Compare commits

..

9 Commits

Author SHA1 Message Date
Emmanuele Bassi 2855ea43a3 trashmonitor: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:28:38 +01:00
Emmanuele Bassi 2a9296f54e calendar: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:28:22 +01:00
Emmanuele Bassi 4c77a466af calendar: Remove unused field and translatable string
Since the switch to child widgets, GtkCalendar has stopped using the
"year_before" field, and does not need to compute whether the year
should be displayed before the month depending on the locale.
2023-06-28 15:27:10 +01:00
Emmanuele Bassi 91c7fc9cc5 colorswatch: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:26:45 +01:00
Emmanuele Bassi 595e2e6001 coloreditor: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:26:18 +01:00
Emmanuele Bassi 31e16ed7ba checkbutton: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:25:59 +01:00
Emmanuele Bassi 2925ba2228 button: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:25:37 +01:00
Emmanuele Bassi 40f6f11cae box: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:25:06 +01:00
Emmanuele Bassi f92dd63401 aboutdialog: Replace internal 1-bit fields with bool
Single bit fields cannot be used by address, and will overflow when
set to values that are bigger than one bit; the behaviour (if not the
size) of the C99 bool type is better defined.
2023-06-28 15:22:07 +01:00
96 changed files with 933 additions and 10207 deletions
+3 -26
View File
@@ -20,28 +20,16 @@ Overview of Changes in 4.11.4, xx-xx-xxxx
* GtkWindow:
- Clear the resize cursors to avoid artifacts
* GtkFileDialog:
- Always set initial-folder
* GtkDropDown:
- Update on expression changes
* Accessibility:
- Improvements all over the place: GtkButton, GtkPasswordEntry,
GtkFontChooserDialog, GtkColorChooserDialog, GtkShortcutsWindow,
GtkMenuButton, GtkAboutDialog, GtkFileChooserDialog, GtkStackSidebar,
GtkStackSwitcher, GtkMediaControls, GtkColorDialogButton, GtkDropDown,
GtkInfoBar, GtkNotebook, GtkPrintUnixDialog, GtkModelButton
GtkMediaControls, GtkColorDialogButton, GtkDropDown, GtkInfoBar,
GtkNotebook, GtkPrintUnixDialog, GtkModelButton
- Make name computation follow the ARIA spec more closely
- Adapt name computation for the common 'nested button' scenario
- Change many containers to use `generic` instead of `group`
- Use `generic` as the default role
- Use `application` instead of `window` for windows
- Add properties for accessible names of not directly exposed
widgets in GtkListView, GtkGridView and GtkColumnView
* DND:
- Fix criticals when drops are rejected
* X11:
- Fix regressions in GLX setup
@@ -54,30 +42,19 @@ Overview of Changes in 4.11.4, xx-xx-xxxx
- Do less work on clipped away nodes
- Redo image uploading
- Support different image depths and formats
- Add a pipeline cache
* Demos:
- gtk4-demo: Improve window sizing
- gtk4-demo: Improve focus behavior
- gtk4-demo: Add many missing a11y properties
* Tools:
- gtk4-builder-tool: Make render an alias screenshot
`
* Inspector:
- Show more information in the a11y tab
- Add an accessibility overlay with warnings and recommendations
- Limit the width of the a11y tab
* Build:
- Require GLib 2.76
- Make asan builds work again
* Translation updates:
Brazilian Portuguese
Catalan
Czech
Georgian
Overview of Changes in 4.11.3, 05-06-2023
-6
View File
@@ -335,9 +335,6 @@
<file>paintable_symbolic.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>path_fill.c</file>
<file>path_maze.c</file>
<file>path_text.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
<file>printing.c</file>
@@ -423,9 +420,6 @@
<gresource prefix="/fontrendering">
<file>fontrendering.ui</file>
</gresource>
<gresource prefix="/path_text">
<file>path_text.ui</file>
</gresource>
<gresource prefix="/org/gtk/Demo4">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>
+7 -19
View File
@@ -162,39 +162,27 @@ click_done (GtkGesture *gesture)
gtk_widget_insert_after (item, canvas, last_child);
}
/* GtkSettings treats `GTK_THEME=foo:dark` as theme name `foo`, variant `dark`,
* and our embedded CSS files let `foo-dark` work as an alias for `foo:dark`. */
static gboolean
has_dark_suffix (const char *theme)
{
return g_str_has_suffix (theme, ":dark") ||
g_str_has_suffix (theme, "-dark");
}
/* So we can make a good guess whether the current theme is dark by checking for
* either: it is suffixed `[:-]dark`, or Settings:…prefer-dark-theme is TRUE. */
static gboolean
theme_is_dark (void)
{
const char *env_theme;
GtkSettings *settings;
char *theme;
gboolean prefer_dark;
gboolean dark;
/* Like GtkSettings, 1st see if theme is overridden by environment variable */
env_theme = g_getenv ("GTK_THEME");
if (env_theme != NULL)
return has_dark_suffix (env_theme);
/* If not, test Settings:…theme-name in the same way OR :…prefer-dark-theme */
settings = gtk_settings_get_default ();
g_object_get (settings,
"gtk-theme-name", &theme,
"gtk-application-prefer-dark-theme", &prefer_dark,
NULL);
dark = prefer_dark || has_dark_suffix (theme);
if ((strcmp (theme, "Adwaita") == 0 && prefer_dark) || strcmp (theme, "HighContrastInverse") == 0)
dark = TRUE;
else
dark = FALSE;
g_free (theme);
return dark;
}
+11 -4
View File
@@ -72,9 +72,6 @@ demos = files([
'paintable_symbolic.c',
'panes.c',
'password_entry.c',
'path_fill.c',
'path_maze.c',
'path_text.c',
'peg_solitaire.c',
'pickers.c',
'printing.c',
@@ -161,7 +158,17 @@ demos_h = custom_target('gtk4 demo header',
command: [ find_program('geninclude.py'), '@OUTPUT@', '@INPUT@' ],
)
if can_use_objcopy_for_resources
objcopy_supports_add_symbol = false
objcopy = find_program('objcopy', required : false)
if objcopy.found()
objcopy_supports_add_symbol = run_command(objcopy, '--help', check: false).stdout().contains('--add-symbol')
endif
ld = find_program('ld', required : false)
if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
glib_compile_resources = find_program('glib-compile-resources')
# Create the resource blob
gtkdemo_gresource = custom_target('gtkdemo.gresource',
input : 'demo.gresource.xml',
-321
View File
@@ -1,321 +0,0 @@
/* Path/Fill
*
* This demo shows how to use PangoCairo to draw text with more than
* just a single color.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#define GTK_TYPE_PATH_PAINTABLE (gtk_path_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathPaintable, gtk_path_paintable, GTK, PATH_PAINTABLE, GObject)
struct _GtkPathPaintable
{
GObject parent_instance;
int width;
int height;
GskPath *path;
GdkPaintable *background;
};
struct _GtkPathPaintableClass
{
GObjectClass parent_class;
};
static int
gtk_path_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return MAX (gdk_paintable_get_intrinsic_width (self->background), self->width);
else
return self->width;
}
static int
gtk_path_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return MAX (gdk_paintable_get_intrinsic_height (self->background), self->height);
else
return self->height;
}
static void
gtk_path_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
#if 0
gtk_snapshot_push_fill (snapshot, self->path, GSK_FILL_RULE_WINDING);
#else
GskStroke *stroke = gsk_stroke_new (4.0);
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
gsk_stroke_free (stroke);
#endif
if (self->background)
{
gdk_paintable_snapshot (self->background, snapshot, width, height);
}
else
{
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
(GskColorStop[8]) {
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
},
8);
}
gtk_snapshot_pop (snapshot);
}
static GdkPaintableFlags
gtk_path_paintable_get_flags (GdkPaintable *paintable)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return gdk_paintable_get_flags (self->background);
else
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
}
static void
gtk_path_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->get_intrinsic_width = gtk_path_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_path_paintable_get_intrinsic_height;
iface->snapshot = gtk_path_paintable_snapshot;
iface->get_flags = gtk_path_paintable_get_flags;
}
/* When defining the GType, we need to implement the GdkPaintable interface */
G_DEFINE_TYPE_WITH_CODE (GtkPathPaintable, gtk_path_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_path_paintable_paintable_init))
/* Here's the boilerplate for the GObject declaration.
* We need to disconnect the signals here that we set up elsewhere
*/
static void
gtk_path_paintable_dispose (GObject *object)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (object);
if (self->background)
{
g_signal_handlers_disconnect_by_func (self->background, gdk_paintable_invalidate_contents, self);
g_signal_handlers_disconnect_by_func (self->background, gdk_paintable_invalidate_size, self);
g_clear_object (&self->background);
}
G_OBJECT_CLASS (gtk_path_paintable_parent_class)->dispose (object);
}
static void
gtk_path_paintable_class_init (GtkPathPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_path_paintable_dispose;
}
static void
gtk_path_paintable_init (GtkPathPaintable *self)
{
}
/* And finally, we add a simple constructor.
* It is declared in the header so that the other examples
* can use it.
*/
GdkPaintable *
gtk_path_paintable_new (GskPath *path,
GdkPaintable *background,
int width,
int height)
{
GtkPathPaintable *self;
self = g_object_new (GTK_TYPE_PATH_PAINTABLE, NULL);
self->path = path;
self->background = background;
if (self->background)
{
g_object_ref (self->background);
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
}
self->width = width;
self->height = height;
return GDK_PAINTABLE (self);
}
void
gtk_path_paintable_set_path (GtkPathPaintable *self,
GskPath *path)
{
g_clear_pointer (&self->path, gsk_path_unref);
self->path = gsk_path_ref (path);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
static GskPath *
create_hexagon (GtkWidget *widget)
{
GskPathBuilder *builder;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, 120, 0);
gsk_path_builder_line_to (builder, 360, 0);
gsk_path_builder_line_to (builder, 480, 208);
gsk_path_builder_line_to (builder, 360, 416);
gsk_path_builder_line_to (builder, 120, 416);
gsk_path_builder_line_to (builder, 0, 208);
gsk_path_builder_close (builder);
return gsk_path_builder_free_to_path (builder);
}
static GskPath *
create_path_from_text (GtkWidget *widget)
{
cairo_surface_t *surface;
cairo_t *cr;
cairo_path_t *path;
PangoLayout *layout;
PangoFontDescription *desc;
GskPath *result;
surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
cr = cairo_create (surface);
layout = gtk_widget_create_pango_layout (widget, "Pango power!\nPango power!\nPango power!");
desc = pango_font_description_from_string ("sans bold 36");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_cairo_layout_path (cr, layout);
path = cairo_copy_path_flat (cr);
result = gsk_path_new_from_cairo (path);
cairo_path_destroy (path);
g_object_unref (layout);
cairo_destroy (cr);
cairo_surface_destroy (surface);
return result;
}
static gboolean
update_path (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer measure)
{
float progress = gdk_frame_clock_get_frame_time (frame_clock) % (60 * G_USEC_PER_SEC) / (float) (30 * G_USEC_PER_SEC);
GskPathBuilder *builder;
GskPath *path;
graphene_point_t pos;
graphene_vec2_t tangent;
builder = gsk_path_builder_new ();
gsk_path_measure_add_segment (measure,
builder,
progress > 1 ? (progress - 1) * gsk_path_measure_get_length (measure) : 0.0,
(progress < 1 ? progress : 1.0) * gsk_path_measure_get_length (measure));
gsk_path_measure_get_point (measure,
(progress > 1 ? (progress - 1) : progress) * gsk_path_measure_get_length (measure),
&pos,
&tangent);
gsk_path_builder_move_to (builder, pos.x + 5 * graphene_vec2_get_x (&tangent), pos.y + 5 * graphene_vec2_get_y (&tangent));
gsk_path_builder_line_to (builder, pos.x + 3 * graphene_vec2_get_y (&tangent), pos.y + 3 * graphene_vec2_get_x (&tangent));
gsk_path_builder_line_to (builder, pos.x - 3 * graphene_vec2_get_y (&tangent), pos.y - 3 * graphene_vec2_get_x (&tangent));
gsk_path_builder_close (builder);
path = gsk_path_builder_free_to_path (builder);
gtk_path_paintable_set_path (GTK_PATH_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget))),
path);
gsk_path_unref (path);
return G_SOURCE_CONTINUE;
}
GtkWidget *
do_path_fill (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *picture;
GdkPaintable *paintable;
GtkMediaStream *stream;
GskPath *path;
graphene_rect_t bounds;
GskPathMeasure *measure;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Path Fill");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
#if 0
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
#else
stream = gtk_nuclear_media_stream_new ();
#endif
gtk_media_stream_play (stream);
gtk_media_stream_set_loop (stream, TRUE);
path = create_hexagon (window);
path = create_path_from_text (window);
gsk_path_get_bounds (path, &bounds);
paintable = gtk_path_paintable_new (path,
GDK_PAINTABLE (stream),
bounds.origin.x + bounds.size.width,
bounds.origin.y + bounds.size.height);
picture = gtk_picture_new_for_paintable (paintable);
measure = gsk_path_measure_new (path);
gtk_widget_add_tick_callback (picture, update_path, measure, (GDestroyNotify) gsk_path_measure_unref);
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_CONTAIN);
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
g_object_unref (paintable);
gtk_window_set_child (GTK_WINDOW (window), picture);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
-338
View File
@@ -1,338 +0,0 @@
/* Path/Maze
*
* This demo shows how to use a GskPath to create a maze and use
* gsk_path_measure_get_closest_point() to check the mouse stays
* on the path.
*
* It also shows off the performance of GskPath (or not) as this
* is a rather complex path.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#define MAZE_GRID_SIZE 20
#define MAZE_STROKE_SIZE_ACTIVE (MAZE_GRID_SIZE - 4)
#define MAZE_STROKE_SIZE_INACTIVE (MAZE_GRID_SIZE - 12)
#define MAZE_WIDTH 31
#define MAZE_HEIGHT 21
#define GTK_TYPE_MAZE (gtk_maze_get_type ())
G_DECLARE_FINAL_TYPE (GtkMaze, gtk_maze, GTK, MAZE, GtkWidget)
struct _GtkMaze
{
GtkWidget parent_instance;
int width;
int height;
GskPath *path;
GskPathMeasure *measure;
GdkPaintable *background;
gboolean active;
};
struct _GtkMazeClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GtkMaze, gtk_maze, GTK_TYPE_WIDGET)
static void
gtk_maze_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkMaze *self = GTK_MAZE (widget);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = self->width;
else
*minimum = *natural = self->height;
}
static void
gtk_maze_snapshot (GtkWidget *widget,
GdkSnapshot *snapshot)
{
GtkMaze *self = GTK_MAZE (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
GskStroke *stroke;
stroke = gsk_stroke_new (MAZE_STROKE_SIZE_INACTIVE);
if (self->active)
gsk_stroke_set_line_width (stroke, MAZE_STROKE_SIZE_ACTIVE);
gsk_stroke_set_line_join (stroke, GSK_LINE_JOIN_ROUND);
gsk_stroke_set_line_cap (stroke, GSK_LINE_CAP_ROUND);
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
gsk_stroke_free (stroke);
if (self->background)
{
gdk_paintable_snapshot (self->background, snapshot, width, height);
}
else
{
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
(GskColorStop[8]) {
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
},
8);
}
gtk_snapshot_pop (snapshot);
}
static void
gtk_maze_dispose (GObject *object)
{
GtkMaze *self = GTK_MAZE (object);
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
if (self->background)
{
g_signal_handlers_disconnect_matched (self->background, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
g_clear_object (&self->background);
}
G_OBJECT_CLASS (gtk_maze_parent_class)->dispose (object);
}
static void
gtk_maze_class_init (GtkMazeClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_maze_dispose;
widget_class->measure = gtk_maze_measure;
widget_class->snapshot = gtk_maze_snapshot;
}
static void
pointer_motion (GtkEventControllerMotion *controller,
double x,
double y,
GtkMaze *self)
{
if (!self->active)
return;
if (gsk_path_measure_get_closest_point (self->measure, &GRAPHENE_POINT_INIT (x, y), NULL) <= MAZE_STROKE_SIZE_ACTIVE / 2.0f)
return;
self->active = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_leave (GtkEventControllerMotion *controller,
GtkMaze *self)
{
if (!self->active)
{
self->active = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
gtk_maze_init (GtkMaze *self)
{
GtkEventController *controller;
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
self->active = TRUE;
}
static void
gtk_maze_set_path (GtkMaze *self,
GskPath *path)
{
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
self->path = gsk_path_ref (path);
self->measure = gsk_path_measure_new (path);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
GtkWidget *
gtk_maze_new (GskPath *path,
GdkPaintable *background,
int width,
int height)
{
GtkMaze *self;
self = g_object_new (GTK_TYPE_MAZE, NULL);
gtk_maze_set_path (self, path);
gsk_path_unref (path);
self->background = background;
if (self->background)
{
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gtk_widget_queue_draw), self);
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gtk_widget_queue_resize), self);
}
self->width = width;
self->height = height;
return GTK_WIDGET (self);
}
static void
add_point_to_maze (GtkBitset *maze,
GskPathBuilder *builder,
guint x,
guint y)
{
gboolean set[4] = { FALSE, FALSE, FALSE, FALSE };
guint dir;
gtk_bitset_add (maze, y * MAZE_WIDTH + x);
while (TRUE)
{
set[0] = set[0] || x == 0 || gtk_bitset_contains (maze, y * MAZE_WIDTH + x - 1);
set[1] = set[1] || y == 0 || gtk_bitset_contains (maze, (y - 1) * MAZE_WIDTH + x);
set[2] = set[2] || x + 1 == MAZE_WIDTH || gtk_bitset_contains (maze, y * MAZE_WIDTH + x + 1);
set[3] = set[3] || y + 1 == MAZE_HEIGHT || gtk_bitset_contains (maze, (y + 1) * MAZE_WIDTH + x);
if (set[0] && set[1] && set[2] && set[3])
return;
do
{
dir = g_random_int_range (0, 4);
}
while (set[dir]);
switch (dir)
{
case 0:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x - 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x - 1, y);
break;
case 1:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y - 0.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x, y - 1);
break;
case 2:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x + 1.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x + 1, y);
break;
case 3:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 1.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x, y + 1);
break;
default:
g_assert_not_reached ();
break;
}
}
}
static GskPath *
create_path_for_maze (GtkWidget *widget)
{
GskPathBuilder *builder;
GtkBitset *maze;
builder = gsk_path_builder_new ();
maze = gtk_bitset_new_empty ();
/* make sure the outer lines are unreachable:
* Set the full range, then remove the center again. */
gtk_bitset_add_range (maze, 0, MAZE_WIDTH * MAZE_HEIGHT);
gtk_bitset_remove_rectangle (maze, MAZE_WIDTH + 1, MAZE_WIDTH - 2, MAZE_HEIGHT - 2, MAZE_WIDTH);
/* Fill the maze */
add_point_to_maze (maze, builder, MAZE_WIDTH / 2, MAZE_HEIGHT / 2);
/* Add start and stop lines */
gsk_path_builder_move_to (builder, 1.5 * MAZE_GRID_SIZE, -0.5 * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, 1.5 * MAZE_GRID_SIZE, 1.5 * MAZE_GRID_SIZE);
gsk_path_builder_move_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT - 1.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT + 0.5) * MAZE_GRID_SIZE);
gtk_bitset_unref (maze);
return gsk_path_builder_free_to_path (builder);
}
GtkWidget *
do_path_maze (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *maze;
GtkMediaStream *stream;
GskPath *path;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Follow the maze with the mouse");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
#if 0
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
#else
stream = gtk_nuclear_media_stream_new ();
#endif
gtk_media_stream_play (stream);
gtk_media_stream_set_loop (stream, TRUE);
path = create_path_for_maze (window);
maze = gtk_maze_new (path,
GDK_PAINTABLE (stream),
MAZE_WIDTH * MAZE_GRID_SIZE,
MAZE_HEIGHT * MAZE_GRID_SIZE);
gtk_window_set_child (GTK_WINDOW (window), maze);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
-580
View File
@@ -1,580 +0,0 @@
/* Path/Text
*
* This demo shows how to use GskPath to animate a path along another path.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#define GTK_TYPE_PATH_WIDGET (gtk_path_widget_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathWidget, gtk_path_widget, GTK, PATH_WIDGET, GtkWidget)
#define POINT_SIZE 8
enum {
PROP_0,
PROP_TEXT,
PROP_EDITABLE,
N_PROPS
};
struct _GtkPathWidget
{
GtkWidget parent_instance;
char *text;
gboolean editable;
graphene_point_t points[4];
guint active_point;
float line_closest;
GskPath *line_path;
GskPathMeasure *line_measure;
GskPath *text_path;
GdkPaintable *background;
};
struct _GtkPathWidgetClass
{
GtkWidgetClass parent_class;
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkPathWidget, gtk_path_widget, GTK_TYPE_WIDGET)
static GskPath *
create_path_from_text (GtkWidget *widget,
const char *text)
{
cairo_surface_t *surface;
cairo_t *cr;
cairo_path_t *path;
PangoLayout *layout;
PangoFontDescription *desc;
GskPath *result;
surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
cr = cairo_create (surface);
layout = gtk_widget_create_pango_layout (widget, text);
desc = pango_font_description_from_string ("sans bold 36");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
cairo_move_to (cr, 0, - pango_layout_get_baseline (layout) / (double) PANGO_SCALE);
pango_cairo_layout_path (cr, layout);
path = cairo_copy_path_flat (cr);
result = gsk_path_new_from_cairo (path);
cairo_path_destroy (path);
g_object_unref (layout);
cairo_destroy (cr);
cairo_surface_destroy (surface);
return result;
}
typedef struct
{
GskPathMeasure *measure;
GskPathBuilder *builder;
double scale;
} GtkPathTransform;
static void
gtk_path_transform_point (GskPathMeasure *measure,
const graphene_point_t *pt,
float scale,
graphene_point_t *res)
{
graphene_vec2_t tangent;
gsk_path_measure_get_point (measure, pt->x * scale, res, &tangent);
res->x -= pt->y * scale * graphene_vec2_get_y (&tangent);
res->y += pt->y * scale * graphene_vec2_get_x (&tangent);
}
static gboolean
gtk_path_transform_op (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
gpointer data)
{
GtkPathTransform *transform = data;
switch (op)
{
case GSK_PATH_MOVE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[0], transform->scale, &res);
gsk_path_builder_move_to (transform->builder, res.x, res.y);
}
break;
case GSK_PATH_LINE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[1], transform->scale, &res);
gsk_path_builder_line_to (transform->builder, res.x, res.y);
}
break;
case GSK_PATH_CURVE:
{
graphene_point_t res[3];
gtk_path_transform_point (transform->measure, &pts[1], transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &pts[3], transform->scale, &res[2]);
gsk_path_builder_curve_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
}
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (transform->builder);
break;
default:
g_assert_not_reached();
return FALSE;
}
return TRUE;
}
static GskPath *
gtk_path_transform (GskPathMeasure *measure,
GskPath *path)
{
GtkPathTransform transform = { measure, gsk_path_builder_new () };
graphene_rect_t bounds;
gsk_path_get_bounds (path, &bounds);
if (bounds.origin.x + bounds.size.width > 0)
transform.scale = gsk_path_measure_get_length (measure) / (bounds.origin.x + bounds.size.width);
else
transform.scale = 1.0f;
gsk_path_foreach (path, GSK_PATH_FOREACH_ALLOW_CURVES, gtk_path_transform_op, &transform);
return gsk_path_builder_free_to_path (transform.builder);
}
static void
gtk_path_widget_clear_text_path (GtkPathWidget *self)
{
g_clear_pointer (&self->text_path, gsk_path_unref);
}
static void
gtk_path_widget_clear_paths (GtkPathWidget *self)
{
gtk_path_widget_clear_text_path (self);
g_clear_pointer (&self->line_path, gsk_path_unref);
g_clear_pointer (&self->line_measure, gsk_path_measure_unref);
}
static void
gtk_path_widget_create_text_path (GtkPathWidget *self)
{
GskPath *path;
gtk_path_widget_clear_text_path (self);
if (self->line_measure == NULL)
return;
path = create_path_from_text (GTK_WIDGET (self), self->text);
self->text_path = gtk_path_transform (self->line_measure, path);
gsk_path_unref (path);
}
static void
gtk_path_widget_create_paths (GtkPathWidget *self)
{
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
GskPathBuilder *builder;
gtk_path_widget_clear_paths (self);
if (width <= 0 || height <= 0)
return;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder,
self->points[0].x * width, self->points[0].y * height);
gsk_path_builder_curve_to (builder,
self->points[1].x * width, self->points[1].y * height,
self->points[2].x * width, self->points[2].y * height,
self->points[3].x * width, self->points[3].y * height);
self->line_path = gsk_path_builder_free_to_path (builder);
self->line_measure = gsk_path_measure_new (self->line_path);
gtk_path_widget_create_text_path (self);
}
static void
gtk_path_widget_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
GTK_WIDGET_CLASS (gtk_path_widget_parent_class)->size_allocate (widget, width, height, baseline);
gtk_path_widget_create_paths (self);
}
static void
gtk_path_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkPathWidget *self = GTK_PATH_WIDGET (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
GskPath *path;
GskStroke *stroke;
gsize i;
/* frosted glass the background */
gtk_snapshot_push_blur (snapshot, 100);
gdk_paintable_snapshot (self->background, snapshot, width, height);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 0.6 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
/* draw the text */
if (self->text_path)
{
gtk_snapshot_push_fill (snapshot, self->text_path, GSK_FILL_RULE_WINDING);
gdk_paintable_snapshot (self->background, snapshot, width, height);
/* ... with an emboss effect */
stroke = gsk_stroke_new (2.0);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT(1, 1));
gtk_snapshot_push_stroke (snapshot, self->text_path, stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 0.2 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gsk_stroke_free (stroke);
gtk_snapshot_pop (snapshot);
gtk_snapshot_pop (snapshot);
}
if (self->editable && self->line_path)
{
GskPathBuilder *builder;
/* draw the control line */
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, self->line_path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
/* draw the points */
builder = gsk_path_builder_new ();
for (i = 0; i < 4; i++)
{
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), POINT_SIZE);
}
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 1, 1, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
stroke = gsk_stroke_new (1.0);
gtk_snapshot_push_stroke (snapshot, path, stroke);
gsk_stroke_free (stroke);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
if (self->line_closest >= 0)
{
GskPathBuilder *builder;
graphene_point_t closest;
builder = gsk_path_builder_new ();
gsk_path_measure_get_point (self->line_measure, self->line_closest, &closest, NULL);
gsk_path_builder_add_circle (builder, &closest, POINT_SIZE);
path = gsk_path_builder_free_to_path (builder);
gtk_snapshot_push_fill (snapshot, path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 0, 0, 1, 1 }, &GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
gsk_path_unref (path);
}
}
static void
gtk_path_widget_set_text (GtkPathWidget *self,
const char *text)
{
if (g_strcmp0 (self->text, text) == 0)
return;
g_free (self->text);
self->text = g_strdup (text);
gtk_path_widget_create_paths (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEXT]);
}
static void
gtk_path_widget_set_editable (GtkPathWidget *self,
gboolean editable)
{
if (self->editable == editable)
return;
self->editable = editable;
gtk_widget_queue_draw (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EDITABLE]);
}
static void
gtk_path_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
switch (prop_id)
{
case PROP_TEXT:
gtk_path_widget_set_text (self, g_value_get_string (value));
break;
case PROP_EDITABLE:
gtk_path_widget_set_editable (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
switch (prop_id)
{
case PROP_TEXT:
g_value_set_string (value, self->text);
break;
case PROP_EDITABLE:
g_value_set_boolean (value, self->editable);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_path_widget_dispose (GObject *object)
{
GtkPathWidget *self = GTK_PATH_WIDGET (object);
gtk_path_widget_clear_paths (self);
G_OBJECT_CLASS (gtk_path_widget_parent_class)->dispose (object);
}
static void
gtk_path_widget_class_init (GtkPathWidgetClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_path_widget_dispose;
object_class->set_property = gtk_path_widget_set_property;
object_class->get_property = gtk_path_widget_get_property;
widget_class->size_allocate = gtk_path_widget_allocate;
widget_class->snapshot = gtk_path_widget_snapshot;
properties[PROP_TEXT] =
g_param_spec_string ("text",
"text",
"Text transformed along a path",
NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_EDITABLE] =
g_param_spec_boolean ("editable",
"editable",
"If the path can be edited by the user",
FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
drag_begin (GtkGestureDrag *gesture,
double x,
double y,
GtkPathWidget *self)
{
graphene_point_t mouse = GRAPHENE_POINT_INIT (x, y);
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
gsize i;
for (i = 0; i < 4; i++)
{
if (graphene_point_distance (&GRAPHENE_POINT_INIT (self->points[i].x * width, self->points[i].y * height), &mouse, NULL, NULL) <= POINT_SIZE)
{
self->active_point = i;
break;
}
}
if (i == 4)
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
return;
}
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
GtkPathWidget *self)
{
double width = gtk_widget_get_width (GTK_WIDGET (self));
double height = gtk_widget_get_height (GTK_WIDGET (self));
double start_x, start_y;
gtk_gesture_drag_get_start_point (drag, &start_x, &start_y);
self->points[self->active_point] = GRAPHENE_POINT_INIT ((start_x + offset_x) / width,
(start_y + offset_y) / height);
self->points[self->active_point].x = CLAMP (self->points[self->active_point].x, 0, 1);
self->points[self->active_point].y = CLAMP (self->points[self->active_point].y, 0, 1);
gtk_path_widget_create_paths (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_motion (GtkEventControllerMotion *controller,
double x,
double y,
GtkPathWidget *self)
{
gsk_path_measure_get_closest_point_full (self->line_measure,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&self->line_closest,
NULL, NULL, NULL);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_leave (GtkEventControllerMotion *controller,
GtkPathWidget *self)
{
self->line_closest = -1;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
gtk_path_widget_init (GtkPathWidget *self)
{
GtkEventController *controller;
controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_update), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
g_signal_connect (controller, "enter", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
self->line_closest = -1;
self->points[0] = GRAPHENE_POINT_INIT (0.1, 0.9);
self->points[1] = GRAPHENE_POINT_INIT (0.3, 0.1);
self->points[2] = GRAPHENE_POINT_INIT (0.7, 0.1);
self->points[3] = GRAPHENE_POINT_INIT (0.9, 0.9);
self->background = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
gtk_path_widget_set_text (self, "It's almost working");
}
GtkWidget *
gtk_path_widget_new (void)
{
GtkPathWidget *self;
self = g_object_new (GTK_TYPE_PATH_WIDGET, NULL);
return GTK_WIDGET (self);
}
GtkWidget *
do_path_text (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_PATH_WIDGET);
builder = gtk_builder_new_from_resource ("/path_text/path_text.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
-38
View File
@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Text along a Path</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child type="end">
<object class="GtkToggleButton" id="edit-toggle">
<property name="icon-name">document-edit-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkRevealer">
<property name="reveal-child" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
<child>
<object class="GtkEntry" id="text">
<property name="text">Through the looking glass</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPathWidget" id="view">
<property name="editable" bind-source="edit-toggle" bind-property="active" bind-flags="sync-create"></property>
<property name="text" bind-source="text" bind-property="text" bind-flags="sync-create"></property>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</child>
</object>
</child>
</object>
</interface>
+11 -1
View File
@@ -1,6 +1,16 @@
# demos/widget-factory
if can_use_objcopy_for_resources
objcopy_supports_add_symbol = false
objcopy = find_program('objcopy', required : false)
if objcopy.found()
objcopy_supports_add_symbol = run_command(objcopy, '--help', check: false).stdout().contains('--add-symbol')
endif
ld = find_program('ld', required : false)
if not meson.is_cross_build() and build_machine.cpu_family() != 'arm' and build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
glib_compile_resources = find_program('glib-compile-resources')
# Create the resource blob
widgetfactory_gresource = custom_target('widgetfactory.gresource',
input : 'widget-factory.gresource.xml',
+5 -10
View File
@@ -16,7 +16,6 @@ SYNOPSIS
| **gtk4-builder-tool** enumerate [OPTIONS...] <FILE>
| **gtk4-builder-tool** simplify [OPTIONS...] <FILE>
| **gtk4-builder-tool** preview [OPTIONS...] <FILE>
| **gtk4-builder-tool** render [OPTIONS...] <FILE>
| **gtk4-builder-tool** screenshot [OPTIONS...] <FILE>
DESCRIPTION
@@ -70,11 +69,12 @@ file to use.
Load style information from the given CSS file.
Render
^^^^^^
Screenshot
^^^^^^^^^^
The ``render`` command saves a rendering of the UI definition file as a png image
or node file. The name of the file to write can be specified as a second FILE argument.
The ``screenshot`` command saves a rendering of the UI definition file
as a png image or node file. The name of the file to write can be specified as
a second FILE argument.
This command accepts options to specify the ID of the toplevel object and a CSS
file to use.
@@ -96,11 +96,6 @@ file to use.
Overwrite an existing file.
Screenshot
^^^^^^^^^^
The ``screenshot`` command is an alias for ``render``.
Simplification
^^^^^^^^^^^^^^
-4
View File
@@ -100,10 +100,6 @@ struct _GdkDisplay
VkDevice vk_device;
VkQueue vk_queue;
uint32_t vk_queue_family_index;
VkPipelineCache vk_pipeline_cache;
gsize vk_pipeline_cache_size;
char *vk_pipeline_cache_etag;
guint vk_save_pipeline_cache_source;
guint vulkan_refcount;
#endif /* GDK_RENDERING_VULKAN */
-222
View File
@@ -931,216 +931,6 @@ gdk_vulkan_context_get_queue_family_index (GdkVulkanContext *context)
return gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context))->vk_queue_family_index;
}
static char *
gdk_vulkan_get_pipeline_cache_dirname (void)
{
return g_build_filename (g_get_user_cache_dir (), "gtk-4.0", "vulkan-pipeline-cache", NULL);
}
static GFile *
gdk_vulkan_get_pipeline_cache_file (GdkDisplay *display)
{
VkPhysicalDeviceProperties props;
char *dirname, *basename, *path;
GFile *result;
vkGetPhysicalDeviceProperties (display->vk_physical_device, &props);
dirname = gdk_vulkan_get_pipeline_cache_dirname ();
basename = g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
"-%02x%02x%02x%02x%02x%02x.%u",
props.pipelineCacheUUID[0], props.pipelineCacheUUID[1],
props.pipelineCacheUUID[2], props.pipelineCacheUUID[3],
props.pipelineCacheUUID[4], props.pipelineCacheUUID[5],
props.pipelineCacheUUID[6], props.pipelineCacheUUID[7],
props.pipelineCacheUUID[8], props.pipelineCacheUUID[9],
props.pipelineCacheUUID[10], props.pipelineCacheUUID[11],
props.pipelineCacheUUID[12], props.pipelineCacheUUID[13],
props.pipelineCacheUUID[14], props.pipelineCacheUUID[15],
props.driverVersion);
path = g_build_filename (dirname, basename, NULL);
result = g_file_new_for_path (path);
g_free (path);
g_free (basename);
g_free (dirname);
return result;
}
static VkPipelineCache
gdk_display_load_pipeline_cache (GdkDisplay *display)
{
GError *error = NULL;
VkPipelineCache result;
GFile *cache_file;
char *etag, *data;
gsize size;
cache_file = gdk_vulkan_get_pipeline_cache_file (display);
if (!g_file_load_contents (cache_file, NULL, &data, &size, &etag, &error))
{
GDK_DEBUG (VULKAN, "failed to load Vulkan pipeline cache file '%s': %s\n",
g_file_peek_path (cache_file), error->message);
g_object_unref (cache_file);
g_clear_error (&error);
return VK_NULL_HANDLE;
}
if (GDK_VK_CHECK (vkCreatePipelineCache, display->vk_device,
&(VkPipelineCacheCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
.initialDataSize = size,
.pInitialData = data,
},
NULL,
&result) != VK_SUCCESS)
result = VK_NULL_HANDLE;
g_free (data);
g_free (display->vk_pipeline_cache_etag);
display->vk_pipeline_cache_etag = etag;
display->vk_pipeline_cache_size = size;
return result;
}
static gboolean
gdk_vulkan_save_pipeline_cache (GdkDisplay *display)
{
GError *error = NULL;
VkDevice device;
VkPipelineCache cache;
GFile *file;
char *path;
size_t size;
char *data, *etag;
device = display->vk_device;
cache = display->vk_pipeline_cache;
GDK_VK_CHECK (vkGetPipelineCacheData, device, cache, &size, NULL);
if (size == 0)
return TRUE;
if (size == display->vk_pipeline_cache_size)
{
GDK_DEBUG (VULKAN, "pipeline cache size (%zu bytes) unchanged, skipping save", size);
return TRUE;
}
data = g_malloc (size);
if (GDK_VK_CHECK (vkGetPipelineCacheData, device, cache, &size, data) != VK_SUCCESS)
{
g_free (data);
return FALSE;
}
path = gdk_vulkan_get_pipeline_cache_dirname ();
if (g_mkdir_with_parents (path, 0755) != 0)
{
g_warning_once ("Failed to create pipeline cache directory");
g_free (path);
return FALSE;
}
g_free (path);
file = gdk_vulkan_get_pipeline_cache_file (display);
GDK_DEBUG (VULKAN, "Saving pipeline cache to %s", g_file_peek_path (file));
if (!g_file_replace_contents (file,
data,
size,
display->vk_pipeline_cache_etag,
FALSE,
0,
&etag,
NULL,
&error))
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG))
{
VkPipelineCache new_cache;
GDK_DEBUG (VULKAN, "Pipeline cache file modified, merging into current");
new_cache = gdk_display_load_pipeline_cache (display);
if (new_cache)
{
GDK_VK_CHECK (vkMergePipelineCaches, device, cache, 1, &new_cache);
vkDestroyPipelineCache (device, new_cache, NULL);
}
else
{
g_clear_pointer (&display->vk_pipeline_cache_etag, g_free);
}
g_clear_error (&error);
g_object_unref (file);
/* try again */
return gdk_vulkan_save_pipeline_cache (display);
}
g_warning ("Failed to save pipeline cache: %s", error->message);
g_clear_error (&error);
g_object_unref (file);
return FALSE;
}
g_object_unref (file);
g_free (display->vk_pipeline_cache_etag);
display->vk_pipeline_cache_etag = etag;
return TRUE;
}
static gboolean
gdk_vulkan_save_pipeline_cache_cb (gpointer data)
{
GdkDisplay *display = data;
gdk_vulkan_save_pipeline_cache (display);
display->vk_save_pipeline_cache_source = 0;
return G_SOURCE_REMOVE;
}
void
gdk_vulkan_context_pipeline_cache_updated (GdkVulkanContext *self)
{
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self));
g_clear_handle_id (&display->vk_save_pipeline_cache_source, g_source_remove);
display->vk_save_pipeline_cache_source = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE - 10,
10, /* random choice that is not now */
gdk_vulkan_save_pipeline_cache_cb,
display,
NULL);
}
static void
gdk_display_create_pipeline_cache (GdkDisplay *display)
{
display->vk_pipeline_cache = gdk_display_load_pipeline_cache (display);
GDK_VK_CHECK (vkCreatePipelineCache, display->vk_device,
&(VkPipelineCacheCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
},
NULL,
&display->vk_pipeline_cache);
}
VkPipelineCache
gdk_vulkan_context_get_pipeline_cache (GdkVulkanContext *self)
{
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (self), NULL);
return gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self))->vk_pipeline_cache;
}
/**
* gdk_vulkan_context_get_image_format:
* @context: a `GdkVulkanContext`
@@ -1591,8 +1381,6 @@ gdk_display_create_vulkan_instance (GdkDisplay *display,
return FALSE;
}
gdk_display_create_pipeline_cache (display);
return TRUE;
}
@@ -1621,16 +1409,6 @@ gdk_display_unref_vulkan (GdkDisplay *display)
if (display->vulkan_refcount > 0)
return;
if (display->vk_save_pipeline_cache_source)
{
gdk_vulkan_save_pipeline_cache_cb (display);
g_assert (display->vk_save_pipeline_cache_source == 0);
}
vkDestroyPipelineCache (display->vk_device, display->vk_pipeline_cache, NULL);
display->vk_device = VK_NULL_HANDLE;
g_clear_pointer (&display->vk_pipeline_cache_etag, g_free);
display->vk_pipeline_cache_size = 0;
vkDestroyDevice (display->vk_device, NULL);
display->vk_device = VK_NULL_HANDLE;
if (display->vk_debug_callback != VK_NULL_HANDLE)
-3
View File
@@ -73,9 +73,6 @@ gboolean gdk_display_ref_vulkan (GdkDisp
GError **error);
void gdk_display_unref_vulkan (GdkDisplay *display);
VkPipelineCache gdk_vulkan_context_get_pipeline_cache (GdkVulkanContext *self);
void gdk_vulkan_context_pipeline_cache_updated (GdkVulkanContext *self);
GdkMemoryFormat gdk_vulkan_context_get_offscreen_format (GdkVulkanContext *context,
GdkMemoryDepth depth);
-4
View File
@@ -271,8 +271,6 @@ collect_reused_child_nodes (GskRenderer *renderer,
case GSK_CROSS_FADE_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
default:
@@ -861,8 +859,6 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
case GSK_CROSS_FADE_NODE:
case GSK_BLUR_NODE:
case GSK_GL_SHADER_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
default:
break; /* Fallback */
}
+4 -4
View File
@@ -165,7 +165,7 @@ void half_to_float4 (const guint16 h[4], float f[4]) __attribute__((ifunc ("reso
void float_to_half (const float *f, guint16 *h, int n) __attribute__((ifunc ("resolve_float_to_half")));
void half_to_float (const guint16 *h, float *f, int n) __attribute__((ifunc ("resolve_half_to_float")));
static void * __attribute__ ((no_sanitize_address))
static void *
resolve_float_to_half4 (void)
{
__builtin_cpu_init ();
@@ -175,7 +175,7 @@ resolve_float_to_half4 (void)
return float_to_half4_c;
}
static void * __attribute__ ((no_sanitize_address))
static void *
resolve_half_to_float4 (void)
{
__builtin_cpu_init ();
@@ -185,7 +185,7 @@ resolve_half_to_float4 (void)
return half_to_float4_c;
}
static void * __attribute__ ((no_sanitize_address))
static void *
resolve_float_to_half (void)
{
__builtin_cpu_init ();
@@ -195,7 +195,7 @@ resolve_float_to_half (void)
return float_to_half_c;
}
static void * __attribute__ ((no_sanitize_address))
static void *
resolve_half_to_float (void)
{
__builtin_cpu_init ();
+5 -9
View File
@@ -686,21 +686,17 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
const GskTextureKey *key,
guint texture_id)
{
GskTextureKey *k;
g_assert (GSK_IS_GL_DRIVER (self));
g_assert (key != NULL);
g_assert (texture_id > 0);
g_assert (g_hash_table_contains (self->textures, GUINT_TO_POINTER (texture_id)));
if (!g_hash_table_contains (self->key_to_texture_id, key))
{
GskTextureKey *k;
k = g_memdup (key, sizeof *key);
k = g_memdup (key, sizeof *key);
g_assert (!g_hash_table_contains (self->texture_id_to_key, GUINT_TO_POINTER (texture_id)));
g_hash_table_insert (self->key_to_texture_id, k, GUINT_TO_POINTER (texture_id));
g_hash_table_insert (self->texture_id_to_key, GUINT_TO_POINTER (texture_id), k);
}
g_hash_table_insert (self->key_to_texture_id, k, GUINT_TO_POINTER (texture_id));
g_hash_table_insert (self->texture_id_to_key, GUINT_TO_POINTER (texture_id), k);
}
/**
-14
View File
@@ -254,8 +254,6 @@ node_supports_2d_transform (const GskRenderNode *node)
case GSK_BLEND_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
return TRUE;
case GSK_SHADOW_NODE:
@@ -310,8 +308,6 @@ node_supports_transform (const GskRenderNode *node)
case GSK_BLEND_NODE:
case GSK_BLUR_NODE:
case GSK_MASK_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
return TRUE;
case GSK_SHADOW_NODE:
@@ -807,8 +803,6 @@ gsk_gl_render_job_untransform_bounds (GskGLRenderJob *job,
out_rect->origin.x -= job->offset_x;
out_rect->origin.y -= job->offset_y;
gsk_transform_unref (transform);
}
static inline void
@@ -4117,14 +4111,6 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_FILL_NODE:
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_STROKE_NODE:
gsk_gl_render_job_visit_as_fallback (job, node);
break;
case GSK_NOT_A_RENDER_NODE:
default:
g_assert_not_reached ();
+1 -5
View File
@@ -20,15 +20,11 @@
#define __GSK_H_INSIDE__
#include <gsk/gskenums.h>
#include <gsk/gskglshader.h>
#include <gsk/gskpath.h>
#include <gsk/gskpathbuilder.h>
#include <gsk/gskpathmeasure.h>
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>
#include <gsk/gskroundedrect.h>
#include <gsk/gskstroke.h>
#include <gsk/gsktransform.h>
#include <gsk/gskglshader.h>
#include <gsk/gskcairorenderer.h>
-99
View File
@@ -42,8 +42,6 @@
* @GSK_REPEAT_NODE: A node that repeats the child's contents
* @GSK_CLIP_NODE: A node that clips its child to a rectangular area
* @GSK_ROUNDED_CLIP_NODE: A node that clips its child to a rounded rectangle
* @GSK_FILL_NODE: A node that fills a path
* @GSK_STROKE_NODE: A node that strokes a path
* @GSK_SHADOW_NODE: A node that draws a shadow below its child
* @GSK_BLEND_NODE: A node that blends two children together
* @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
@@ -76,8 +74,6 @@ typedef enum {
GSK_REPEAT_NODE,
GSK_CLIP_NODE,
GSK_ROUNDED_CLIP_NODE,
GSK_FILL_NODE,
GSK_STROKE_NODE,
GSK_SHADOW_NODE,
GSK_BLEND_NODE,
GSK_CROSS_FADE_NODE,
@@ -174,101 +170,6 @@ typedef enum {
GSK_CORNER_BOTTOM_LEFT
} GskCorner;
/**
* GskFillRule:
* @GSK_FILL_RULE_WINDING: If the path crosses the ray from
* left-to-right, counts +1. If the path crosses the ray
* from right to left, counts -1. (Left and right are determined
* from the perspective of looking along the ray from the starting
* point.) If the total count is non-zero, the point will be filled.
* @GSK_FILL_RULE_EVEN_ODD: Counts the total number of
* intersections, without regard to the orientation of the contour. If
* the total number of intersections is odd, the point will be
* filled.
*
* #GskFillRule is used to select how paths are filled, for example in
* gsk_fill_node_new(). Whether or not a point is included in the fill is
* determined by taking a ray from that point to infinity and looking
* at intersections with the path. The ray can be in any direction,
* as long as it doesn't pass through the end point of a segment
* or have a tricky intersection such as intersecting tangent to the path.
* (Note that filling is not actually implemented in this way. This
* is just a description of the rule that is applied.)
*
* New entries may be added in future versions.
**/
typedef enum {
GSK_FILL_RULE_WINDING,
GSK_FILL_RULE_EVEN_ODD
} GskFillRule;
/**
* GskLineCap:
* @GSK_LINE_CAP_BUTT: Start and stop the line exactly at the start
* and end point
* @GSK_LINE_CAP_ROUND: Use a round ending, the center of the circle
* is the start or end point.
* @GSK_LINE_CAP_SQUARE: use squared ending, the center of the square
* is the start or end point.
*
* Specifies how to render the start and end points of contours or
* dashes when stroking.
*
* The default line cap style is %GSK_LINE_CAP_BUTT.
*/
typedef enum {
GSK_LINE_CAP_BUTT,
GSK_LINE_CAP_ROUND,
GSK_LINE_CAP_SQUARE
} GskLineCap;
/**
* GskLineJoin:
* @GSK_LINE_JOIN_MITER: Use a sharp, angled corner
* @GSK_LINE_JOIN_MITER_CLIP: Use a sharp, angled corner, at a distance
* @GSK_LINE_JOIN_ROUND: Use a round join, the center of the circle is
* the joint point
* @GSK_LINE_JOIN_BEVEL: Use a cut-off join, the join is cut off at half
* the line width from the joint point
*
* Specifies how to render the junction of two lines when stroking.
*
* See gsk_stroke_set_miter_limit() for details on the difference between
* @GSK_LINE_JOIN_MITER and @GSK_LINE_JOIN_MITER_CLIP.
*
* The default line join style is %GSK_LINE_JOIN_MITER.
**/
typedef enum {
GSK_LINE_JOIN_MITER,
GSK_LINE_JOIN_MITER_CLIP,
GSK_LINE_JOIN_ROUND,
GSK_LINE_JOIN_BEVEL
} GskLineJoin;
/**
* GskPathOperation:
* @GSK_PATH_MOVE: A move-to operation, with 1 point describing the
* target point.
* @GSK_PATH_LINE: A line-to operation, with 2 points describing the
* start and end point of a straight line.
* @GSK_PATH_CLOSE: A close operation ending the current contour with
* a line back to the starting point. Two points describe the start
* and end of the line.
* @GSK_PATH_CURVE: A curve-to operation describing a cubic Bézier curve
* with 4 points describing the start point, the two control points
* and the end point of the curve.
*
* Path operations can be used to approximate a #GskPath.
*
* More values may be added in the future.
**/
typedef enum {
GSK_PATH_MOVE,
GSK_PATH_CLOSE,
GSK_PATH_LINE,
GSK_PATH_CURVE,
} GskPathOperation;
/**
* GskSerializationError:
* @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be identified
-2819
View File
File diff suppressed because it is too large Load Diff
-108
View File
@@ -1,108 +0,0 @@
/*
* Copyright © 2020 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 __GSK_PATH_H__
#define __GSK_PATH_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
/**
* GskPathForeachFlags:
* @GSK_PATH_FOREACH_ALLOW_CURVES: Allow emission of %GSK_PATH_CURVE
* operations.
*
* Flags that can be passed to gsk_path_foreach() to enable additional
* features.
*
* By default, gsk_path_foreach() will only emit a path with all operations
* flattened to straight lines to allow for maximum compatibility. The only
* operations emitted will be %GSK_PATH_MOVE, %GSK_PATH_LINE and %GSK_PATH_CLOSE.
*/
typedef enum
{
GSK_PATH_FOREACH_ALLOW_CURVES = (1 << 0)
} GskPathForeachFlags;
/**
* GskPathForeachFunc:
* @op: The operation to perform
* @pts: The points of the operation
* @n_pts: The number of points
* @user_data: The user data provided with the function
*
* Prototype of the callback to iterate throught the operations of
* a path.
*
* Returns: %TRUE to continue evaluating the path, %FALSE to
* immediately abort and not call the function again.
*/
typedef gboolean (* GskPathForeachFunc) (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
gpointer user_data);
#define GSK_TYPE_PATH (gsk_path_get_type ())
GDK_AVAILABLE_IN_ALL
GType gsk_path_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_new_from_cairo (const cairo_path_t *path);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_ref (GskPath *self);
GDK_AVAILABLE_IN_ALL
void gsk_path_unref (GskPath *self);
GDK_AVAILABLE_IN_ALL
void gsk_path_print (GskPath *self,
GString *string);
GDK_AVAILABLE_IN_ALL
char * gsk_path_to_string (GskPath *self);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_parse (const char *string);
GDK_AVAILABLE_IN_ALL
void gsk_path_to_cairo (GskPath *self,
cairo_t *cr);
GDK_AVAILABLE_IN_ALL
gboolean gsk_path_is_empty (GskPath *self);
GDK_AVAILABLE_IN_ALL
gboolean gsk_path_get_bounds (GskPath *self,
graphene_rect_t *bounds);
GDK_AVAILABLE_IN_ALL
gboolean gsk_path_foreach (GskPath *self,
GskPathForeachFlags flags,
GskPathForeachFunc func,
gpointer user_data);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPath, gsk_path_unref)
G_END_DECLS
#endif /* __GSK_PATH_H__ */
-753
View File
@@ -1,753 +0,0 @@
/*
* Copyright © 2020 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 "gskpathbuilder.h"
#include "gskpathprivate.h"
/**
* SECTION:gskpathbuilder
* @Title: Building paths
* @Short_description: Building paths of lines and curves
* @See_also: #GskPath, #GskPathMeasure
*
* This section describes how to construct #GskPath structures.
*
* A path is constructed like this:
*
* |[<!-- language="C" -->
* GskPath *
* construct_path (void)
* {
* GskPathBuilder *builder;
*
* builder = gsk_path_builder_new ();
*
* // add contours to the path here
*
* return gsk_path_builder_free_to_path (builder);
* ]|
*
* Adding contours to the path can be done in two ways.
* The easiest option is to use the `gsk_path_builder_add_*` group
* of functions that add predefined contours to the current path,
* either common shapes like gsk_path_builder_add_circle()
* or by adding from other paths like gsk_path_builder_add_path().
*
* The other option is to define each line and curve manually with
* the `gsk_path_builder_*_to` group of functions. You start with
* a call to gsk_path_builder_move_to() to set the starting point
* and then use multiple calls to any of the drawing functions to
* move the pen along the plane. Once you are done, you can call
* gsk_path_builder_close() to close the path by connecting it
* back with a line to the starting point.
* This is similar for how paths are drawn in Cairo.
*/
/**
* GskPathBuilder:
*
* A #GskPathBuilder struct is an opaque struct. It is meant to
* not be kept around and only be used to create new #GskPath
* objects.
*/
struct _GskPathBuilder
{
int ref_count;
GSList *contours; /* (reverse) list of already recorded contours */
GskPathFlags flags; /* flags for the current path */
graphene_point_t current_point; /* the point all drawing ops start from */
GArray *ops; /* operations for current contour - size == 0 means no current contour */
GArray *points; /* points for the operations */
};
G_DEFINE_BOXED_TYPE (GskPathBuilder,
gsk_path_builder,
gsk_path_builder_ref,
gsk_path_builder_unref)
/**
* gsk_path_builder_new:
*
* Create a new #GskPathBuilder object. The resulting builder
* would create an empty #GskPath. Use addition functions to add
* types to it.
*
* Returns: a new #GskPathBuilder
**/
GskPathBuilder *
gsk_path_builder_new (void)
{
GskPathBuilder *self;
self = g_slice_new0 (GskPathBuilder);
self->ref_count = 1;
self->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
self->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
/* Be explicit here */
self->current_point = GRAPHENE_POINT_INIT (0, 0);
return self;
}
/**
* gsk_path_builder_ref:
* @self: a #GskPathBuilder
*
* Acquires a reference on the given builder.
*
* This function is intended primarily for bindings. #GskPathBuilder objects
* should not be kept around.
*
* Returns: (transfer none): the given #GskPathBuilder with
* its reference count increased
*/
GskPathBuilder *
gsk_path_builder_ref (GskPathBuilder *self)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (self->ref_count > 0, NULL);
self->ref_count += 1;
return self;
}
static void
gsk_path_builder_ensure_current (GskPathBuilder *self)
{
if (self->ops->len != 0)
return;
self->flags = GSK_PATH_FLAT;
g_array_append_vals (self->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
g_array_append_val (self->points, self->current_point);
}
static void
gsk_path_builder_append_current (GskPathBuilder *self,
GskPathOperation op,
gsize n_points,
const graphene_point_t *points)
{
gsk_path_builder_ensure_current (self);
g_array_append_vals (self->ops, &(GskStandardOperation) { op, self->points->len - 1 }, 1);
g_array_append_vals (self->points, points, n_points);
self->current_point = points[n_points - 1];
}
static void
gsk_path_builder_end_current (GskPathBuilder *self)
{
GskContour *contour;
if (self->ops->len == 0)
return;
contour = gsk_standard_contour_new (self->flags,
(GskStandardOperation *) self->ops->data,
self->ops->len,
(graphene_point_t *) self->points->data,
self->points->len);
g_array_set_size (self->ops, 0);
g_array_set_size (self->points, 0);
/* do this at the end to avoid inflooping when add_contour calls back here */
gsk_path_builder_add_contour (self, contour);
}
static void
gsk_path_builder_clear (GskPathBuilder *self)
{
gsk_path_builder_end_current (self);
g_slist_free_full (self->contours, g_free);
self->contours = NULL;
}
/**
* gsk_path_builder_unref:
* @self: a #GskPathBuilder
*
* Releases a reference on the given builder.
*/
void
gsk_path_builder_unref (GskPathBuilder *self)
{
g_return_if_fail (self != NULL);
g_return_if_fail (self->ref_count > 0);
self->ref_count -= 1;
if (self->ref_count > 0)
return;
gsk_path_builder_clear (self);
g_array_unref (self->ops);
g_array_unref (self->points);
g_slice_free (GskPathBuilder, self);
}
/**
* gsk_path_builder_free_to_path: (skip)
* @self: a #GskPathBuilder
*
* Creates a new #GskPath from the current state of the
* given builder, and frees the @builder instance.
*
* Returns: (transfer full): the newly created #GskPath
* with all the contours added to the builder
*/
GskPath *
gsk_path_builder_free_to_path (GskPathBuilder *self)
{
GskPath *res;
g_return_val_if_fail (self != NULL, NULL);
res = gsk_path_builder_to_path (self);
gsk_path_builder_unref (self);
return res;
}
/**
* gsk_path_builder_to_path:
* @self: a #GskPathBuilder
*
* Creates a new #GskPath from the given builder.
*
* The given #GskPathBuilder is reset once this function returns;
* you cannot call this function multiple times on the same builder instance.
*
* This function is intended primarily for bindings. C code should use
* gsk_path_builder_free_to_path().
*
* Returns: (transfer full): the newly created #GskPath
* with all the contours added to the builder
*/
GskPath *
gsk_path_builder_to_path (GskPathBuilder *self)
{
GskPath *path;
g_return_val_if_fail (self != NULL, NULL);
gsk_path_builder_end_current (self);
self->contours = g_slist_reverse (self->contours);
path = gsk_path_new_from_contours (self->contours);
gsk_path_builder_clear (self);
return path;
}
void
gsk_path_builder_add_contour (GskPathBuilder *self,
GskContour *contour)
{
gsk_path_builder_end_current (self);
self->contours = g_slist_prepend (self->contours, contour);
}
/**
* gsk_path_builder_get_current_point:
* @self: a #GskPathBuilder
*
* Gets the current point. The current point is used for relative
* drawing commands and updated after every operation.
*
* When the builder is created, the default current point is set to (0, 0).
*
* Returns: (transfer none): The current point
**/
const graphene_point_t *
gsk_path_builder_get_current_point (GskPathBuilder *self)
{
g_return_val_if_fail (self != NULL, NULL);
return &self->current_point;
}
/**
* gsk_path_builder_add_path:
* @self: a #GskPathBuilder
* @path: (transfer none): the path to append
*
* Appends all of @path to the builder.
**/
void
gsk_path_builder_add_path (GskPathBuilder *self,
GskPath *path)
{
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
for (i = 0; i < gsk_path_get_n_contours (path); i++)
{
const GskContour *contour = gsk_path_get_contour (path, i);
gsk_path_builder_add_contour (self, gsk_contour_dup (contour));
}
}
/**
* gsk_path_builder_add_rect:
* @self: A #GskPathBuilder
* @rect: The rectangle to create a path for
*
* Adds @rect as a new contour to the path built by the builder.
*
* If the width or height of the rectangle is negative, the start
* point will be on the right or bottom, respectively.
*
* If the the width or height are 0, the path will be a closed
* horizontal or vertical line. If both are 0, it'll be a closed dot.
**/
void
gsk_path_builder_add_rect (GskPathBuilder *self,
const graphene_rect_t *rect)
{
GskContour *contour;
g_return_if_fail (self != NULL);
contour = gsk_rect_contour_new (rect);
gsk_path_builder_add_contour (self, contour);
gsk_contour_get_start_end (contour, NULL, &self->current_point);
}
/**
* gsk_path_builder_add_circle:
* @self: a #GskPathBuilder
* @center: the center of the circle
* @radius: the radius of the circle
*
* Adds a circle with the @center and @radius.
**/
void
gsk_path_builder_add_circle (GskPathBuilder *self,
const graphene_point_t *center,
float radius)
{
GskContour *contour;
g_return_if_fail (self != NULL);
g_return_if_fail (center != NULL);
g_return_if_fail (radius > 0);
contour = gsk_circle_contour_new (center, radius, 0, 360);
gsk_path_builder_add_contour (self, contour);
}
/**
* gsk_path_builder_move_to:
* @self: a #GskPathBuilder
* @x: x coordinate
* @y: y coordinate
*
* Starts a new contour by placing the pen at @x, @y.
*
* If gsk_path_builder_move_to() is called twice in succession, the first
* call will result in a contour made up of a single point. The second call
* will start a new contour.
**/
void
gsk_path_builder_move_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
gsk_path_builder_end_current (self);
self->current_point = GRAPHENE_POINT_INIT(x, y);
gsk_path_builder_ensure_current (self);
}
/**
* gsk_path_builder_rel_move_to:
* @self: a #GskPathBuilder
* @x: x offset
* @y: y offset
*
* Starts a new contour by placing the pen at @x, @y relative to the current
* point.
*
* This is the relative version of gsk_path_builder_move_to().
**/
void
gsk_path_builder_rel_move_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
gsk_path_builder_move_to (self,
self->current_point.x + x,
self->current_point.y + y);
}
/**
* gsk_path_builder_line_to:
* @self: a #GskPathBuilder
* @x: x coordinate
* @y: y coordinate
*
* Draws a line from the current point to @x, @y and makes it the new current
* point.
**/
void
gsk_path_builder_line_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
/* skip the line if it goes to the same point */
if (graphene_point_equal (&self->current_point,
&GRAPHENE_POINT_INIT (x, y)))
return;
gsk_path_builder_append_current (self,
GSK_PATH_LINE,
1, (graphene_point_t[1]) {
GRAPHENE_POINT_INIT (x, y)
});
}
/**
* gsk_path_builder_rel_line_to:
* @self: a #GskPathBuilder
* @x: x offset
* @y: y offset
*
* Draws a line from the current point to a point offset to it by @x, @y
* and makes it the new current point.
*
* This is the relative version of gsk_path_builder_line_to().
**/
void
gsk_path_builder_rel_line_to (GskPathBuilder *self,
float x,
float y)
{
g_return_if_fail (self != NULL);
gsk_path_builder_line_to (self,
self->current_point.x + x,
self->current_point.y + y);
}
/**
* gsk_path_builder_curve_to:
* @self: a #GskPathBuilder
* @x1: x coordinate of first control point
* @y1: y coordinate of first control point
* @x2: x coordinate of second control point
* @y2: y coordinate of second control point
* @x3: x coordinate of the end of the curve
* @y3: y coordinate of the end of the curve
*
* Adds a [cubic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
* from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
* points.
*
* After this, @x3, @y3 will be the new current point.
**/
void
gsk_path_builder_curve_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3)
{
g_return_if_fail (self != NULL);
self->flags &= ~GSK_PATH_FLAT;
gsk_path_builder_append_current (self,
GSK_PATH_CURVE,
3, (graphene_point_t[3]) {
GRAPHENE_POINT_INIT (x1, y1),
GRAPHENE_POINT_INIT (x2, y2),
GRAPHENE_POINT_INIT (x3, y3)
});
}
/**
* gsk_path_builder_rel_curve_to:
* @self: a #GskPathBuilder
* @x1: x offset of first control point
* @y1: y offset of first control point
* @x2: x offset of second control point
* @y2: y offset of second control point
* @x3: x offset of the end of the curve
* @y3: y offset of the end of the curve
*
* Adds a [cubic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
* from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
* points. All coordinates are given relative to the current point.
*
* This is the relative version of gsk_path_builder_curve_to().
**/
void
gsk_path_builder_rel_curve_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3)
{
g_return_if_fail (self != NULL);
gsk_path_builder_curve_to (self,
self->current_point.x + x1,
self->current_point.y + y1,
self->current_point.x + x2,
self->current_point.y + y2,
self->current_point.x + x3,
self->current_point.y + y3);
}
/**
* gsk_path_builder_close:
* @self: a #GskPathBuilder
*
* Ends the current contour with a line back to the start point.
*
* Note that this is different from calling gsk_path_builder_line_to()
* with the start point in that the contour will be closed. A closed
* contour behaves different from an open one when stroking its start
* and end point are considered connected, so they will be joined
* via the line join, and not ended with line caps.
**/
void
gsk_path_builder_close (GskPathBuilder *self)
{
g_return_if_fail (self != NULL);
if (self->ops->len == 0)
return;
self->flags |= GSK_PATH_CLOSED;
gsk_path_builder_append_current (self,
GSK_PATH_CLOSE,
1, (graphene_point_t[1]) {
g_array_index (self->points, graphene_point_t, 0)
});
gsk_path_builder_end_current (self);
}
static void
arc_segment (GskPathBuilder *builder,
double cx,
double cy,
double rx,
double ry,
double sin_phi,
double cos_phi,
double sin_th0,
double cos_th0,
double sin_th1,
double cos_th1,
double t)
{
double x1, y1, x2, y2, x3, y3;
x1 = rx * (cos_th0 - t * sin_th0);
y1 = ry * (sin_th0 + t * cos_th0);
x3 = rx * cos_th1;
y3 = ry * sin_th1;
x2 = x3 + rx * (t * sin_th1);
y2 = y3 + ry * (-t * cos_th1);
gsk_path_builder_curve_to (builder,
cx + cos_phi * x1 - sin_phi * y1,
cy + sin_phi * x1 + cos_phi * y1,
cx + cos_phi * x2 - sin_phi * y2,
cy + sin_phi * x2 + cos_phi * y2,
cx + cos_phi * x3 - sin_phi * y3,
cy + sin_phi * x3 + cos_phi * y3);
}
#ifndef HAVE_SINCOS
static inline void
sincos (double angle,
double *y,
double *x)
{
*x = cos (angle);
*y = sin (angle);
}
#endif
void
gsk_path_builder_svg_arc_to (GskPathBuilder *builder,
float rx,
float ry,
float x_axis_rotation,
gboolean large_arc,
gboolean positive_sweep,
float x,
float y)
{
graphene_point_t *current;
double x1, y1, x2, y2;
double phi, sin_phi, cos_phi;
double mid_x, mid_y;
double lambda;
double d;
double k;
double x1_, y1_;
double cx_, cy_;
double cx, cy;
double ux, uy, u_len;
double cos_theta1, theta1;
double vx, vy, v_len;
double dp_uv;
double cos_delta_theta, delta_theta;
int i, n_segs;
double d_theta, theta;
double sin_th0, cos_th0;
double sin_th1, cos_th1;
double th_half;
double t;
if (builder->points->len > 0)
{
current = &g_array_index (builder->points, graphene_point_t, builder->points->len - 1);
x1 = current->x;
y1 = current->y;
}
else
{
x1 = 0;
y1 = 0;
}
x2 = x;
y2 = y;
phi = x_axis_rotation * M_PI / 180.0;
sincos (phi, &sin_phi, &cos_phi);
rx = fabs (rx);
ry = fabs (ry);
mid_x = (x1 - x2) / 2;
mid_y = (y1 - y2) / 2;
x1_ = cos_phi * mid_x + sin_phi * mid_y;
y1_ = - sin_phi * mid_x + cos_phi * mid_y;
lambda = (x1_ / rx) * (x1_ / rx) + (y1_ / ry) * (y1_ / ry);
if (lambda > 1)
{
lambda = sqrt (lambda);
rx *= lambda;
ry *= lambda;
}
d = (rx * y1_) * (rx * y1_) + (ry * x1_) * (ry * x1_);
if (d == 0)
return;
k = sqrt (fabs ((rx * ry) * (rx * ry) / d - 1.0));
if (positive_sweep == large_arc)
k = -k;
cx_ = k * rx * y1_ / ry;
cy_ = -k * ry * x1_ / rx;
cx = cos_phi * cx_ - sin_phi * cy_ + (x1 + x2) / 2;
cy = sin_phi * cx_ + cos_phi * cy_ + (y1 + y2) / 2;
ux = (x1_ - cx_) / rx;
uy = (y1_ - cy_) / ry;
u_len = sqrt (ux * ux + uy * uy);
if (u_len == 0)
return;
cos_theta1 = CLAMP (ux / u_len, -1, 1);
theta1 = acos (cos_theta1);
if (uy < 0)
theta1 = - theta1;
vx = (- x1_ - cx_) / rx;
vy = (- y1_ - cy_) / ry;
v_len = sqrt (vx * vx + vy * vy);
if (v_len == 0)
return;
dp_uv = ux * vx + uy * vy;
cos_delta_theta = CLAMP (dp_uv / (u_len * v_len), -1, 1);
delta_theta = acos (cos_delta_theta);
if (ux * vy - uy * vx < 0)
delta_theta = - delta_theta;
if (positive_sweep && delta_theta < 0)
delta_theta += 2 * M_PI;
else if (!positive_sweep && delta_theta > 0)
delta_theta -= 2 * M_PI;
n_segs = ceil (fabs (delta_theta / (M_PI_2 + 0.001)));
d_theta = delta_theta / n_segs;
theta = theta1;
sincos (theta1, &sin_th1, &cos_th1);
th_half = d_theta / 2;
t = (8.0 / 3.0) * sin (th_half / 2) * sin (th_half / 2) / sin (th_half);
for (i = 0; i < n_segs; i++)
{
theta = theta1;
theta1 = theta + d_theta;
sin_th0 = sin_th1;
cos_th0 = cos_th1;
sincos (theta1, &sin_th1, &cos_th1);
arc_segment (builder,
cx, cy, rx, ry,
sin_phi, cos_phi,
sin_th0, cos_th0,
sin_th1, cos_th1,
t);
}
}
-101
View File
@@ -1,101 +0,0 @@
/*
* Copyright © 2020 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 __GSK_PATH_BUILDER_H__
#define __GSK_PATH_BUILDER_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
GDK_AVAILABLE_IN_ALL
GType gsk_path_builder_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskPathBuilder * gsk_path_builder_new (void);
GDK_AVAILABLE_IN_ALL
GskPathBuilder * gsk_path_builder_ref (GskPathBuilder *self);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_unref (GskPathBuilder *self);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_builder_free_to_path (GskPathBuilder *self) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_ALL
GskPath * gsk_path_builder_to_path (GskPathBuilder *self) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_ALL
const graphene_point_t *gsk_path_builder_get_current_point (GskPathBuilder *self);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_add_path (GskPathBuilder *self,
GskPath *path);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_add_rect (GskPathBuilder *self,
const graphene_rect_t *rect);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_add_circle (GskPathBuilder *self,
const graphene_point_t *center,
float radius);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_move_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_rel_move_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_line_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_rel_line_to (GskPathBuilder *self,
float x,
float y);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_curve_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_rel_curve_to (GskPathBuilder *self,
float x1,
float y1,
float x2,
float y2,
float x3,
float y3);
GDK_AVAILABLE_IN_ALL
void gsk_path_builder_close (GskPathBuilder *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathBuilder, gsk_path_builder_unref)
G_END_DECLS
#endif /* __GSK_PATH_BUILDER_H__ */
-477
View File
@@ -1,477 +0,0 @@
/*
* Copyright © 2020 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 "gskpathmeasure.h"
#include "gskpathprivate.h"
/**
* SECTION:gskpathmeasure
* @Title: PathMeasure
* @Short_description: Measuring operations on paths
* @See_also: #GskPath
*
* #GskPathMeasure is an object that allows measuring operations on #GskPaths.
* These operations are useful when implementing animations.
*/
typedef struct _GskContourMeasure GskContourMeasure;
struct _GskContourMeasure
{
float length;
gpointer contour_data;
};
struct _GskPathMeasure
{
/*< private >*/
guint ref_count;
GskPath *path;
float tolerance;
float length;
gsize n_contours;
GskContourMeasure measures[];
};
/**
* GskPathMeasure:
*
* A #GskPathMeasure struct is a reference counted struct
* and should be treated as opaque.
*/
G_DEFINE_BOXED_TYPE (GskPathMeasure, gsk_path_measure,
gsk_path_measure_ref,
gsk_path_measure_unref)
/**
* gsk_path_measure_new:
* @path: the path to measure
*
* Creates a measure object for the given @path.
*
* Returns: a new #GskPathMeasure representing @path
**/
GskPathMeasure *
gsk_path_measure_new (GskPath *path)
{
return gsk_path_measure_new_with_tolerance (path, GSK_PATH_TOLERANCE_DEFAULT);
}
/**
* gsk_path_measure_new_with_tolerance:
* @path: the path to measure
* @tolerance: the tolerance for measuring operations
*
* Creates a measure object for the given @path and @tolerance.
*
* Returns: a new #GskPathMeasure representing @path
**/
GskPathMeasure *
gsk_path_measure_new_with_tolerance (GskPath *path,
float tolerance)
{
GskPathMeasure *self;
gsize i, n_contours;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (tolerance > 0, NULL);
n_contours = gsk_path_get_n_contours (path);
self = g_malloc0 (sizeof (GskPathMeasure) + n_contours * sizeof (GskContourMeasure));
self->ref_count = 1;
self->path = gsk_path_ref (path);
self->tolerance = tolerance;
self->n_contours = n_contours;
for (i = 0; i < n_contours; i++)
{
self->measures[i].contour_data = gsk_contour_init_measure (path, i,
self->tolerance,
&self->measures[i].length);
self->length += self->measures[i].length;
}
return self;
}
/**
* gsk_path_measure_ref:
* @self: a #GskPathMeasure
*
* Increases the reference count of a #GskPathMeasure by one.
*
* Returns: the passed in #GskPathMeasure.
**/
GskPathMeasure *
gsk_path_measure_ref (GskPathMeasure *self)
{
g_return_val_if_fail (self != NULL, NULL);
self->ref_count++;
return self;
}
/**
* gsk_path_measure_unref:
* @self: a #GskPathMeasure
*
* Decreases the reference count of a #GskPathMeasure by one.
* If the resulting reference count is zero, frees the path_measure.
**/
void
gsk_path_measure_unref (GskPathMeasure *self)
{
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (self->ref_count > 0);
self->ref_count--;
if (self->ref_count > 0)
return;
for (i = 0; i < self->n_contours; i++)
{
gsk_contour_free_measure (self->path, i, self->measures[i].contour_data);
}
gsk_path_unref (self->path);
g_free (self);
}
/**
* gsk_path_measure_get_length:
* @self: a #GskPathMeasure
*
* Gets the length of the path being measured.
*
* The length is cached, so this function does not do any work.
*
* Returns: The length of the path measured by @self
**/
float
gsk_path_measure_get_length (GskPathMeasure *self)
{
g_return_val_if_fail (self != NULL, 0);
return self->length;
}
static float
gsk_path_measure_clamp_distance (GskPathMeasure *self,
float distance)
{
if (isnan (distance))
return 0;
return CLAMP (distance, 0, self->length);
}
/**
* gsk_path_measure_get_point:
* @self: a #GskPathMeasure
* @distance: distance into the path
* @pos: (out caller-allocates) (optional): The coordinates
* of the position at @distance
* @tangent: (out caller-allocates) (optional): The tangent
* to the position at @distance
*
* Calculates the coordinates and tangent of the point @distance
* units into the path. The value will be clamped to the length
* of the path.
*
* If the point is a discontinuous edge in the path, the returned
* point and tangent will describe the line starting at that point
* going forward.
*
* If @self describes an empty path, the returned point will be
* set to `(0, 0)` and the tangent will be the x axis or `(1, 0)`.
**/
void
gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
graphene_point_t *pos,
graphene_vec2_t *tangent)
{
gsize i;
g_return_if_fail (self != NULL);
if (pos == NULL && tangent == NULL)
return;
distance = gsk_path_measure_clamp_distance (self, distance);
for (i = 0; i < self->n_contours; i++)
{
if (distance < self->measures[i].length)
break;
distance -= self->measures[i].length;
}
/* weird corner cases */
if (i == self->n_contours)
{
/* the empty path goes here */
if (self->n_contours == 0)
{
if (pos)
graphene_point_init (pos, 0.f, 0.f);
if (tangent)
graphene_vec2_init (tangent, 1.f, 0.f);
return;
}
/* rounding errors can make this happen */
i = self->n_contours - 1;
distance = self->measures[i].length;
}
gsk_contour_get_point (self->path,
i,
self->measures[i].contour_data,
distance,
pos,
tangent);
}
/**
* gsk_path_measure_get_closest_point:
* @self: a #GskPathMeasure
* @point: the point to fond the closest point to
* @out_pos: (out caller-allocates) (optional): return location
* for the closest point
*
* Gets the point on the path that is closest to @point.
*
* If the path being measured is empty, return 0 and set
* @out_pos to (0, 0).
*
* This is a simpler and slower version of
* gsk_path_measure_get_closest_point_full(). Use that one if you
* need more control.
*
* Returns: The offset into the path of the closest point
**/
float
gsk_path_measure_get_closest_point (GskPathMeasure *self,
const graphene_point_t *point,
graphene_point_t *out_pos)
{
float result;
g_return_val_if_fail (self != NULL, 0.0f);
if (gsk_path_measure_get_closest_point_full (self,
point,
INFINITY,
&result,
out_pos,
NULL,
NULL))
return result;
if (out_pos)
*out_pos = GRAPHENE_POINT_INIT (0, 0);
return 0;
}
/**
* gsk_path_measure_get_closest_point_full:
* @self: a #GskPathMeasure
* @point: the point to fond the closest point to
* @threshold: The maximum allowed distance between the path and @point.
* Use INFINITY to look for any point.
* @out_distance: (out caller-allocates) (optional): The
* distance between the found closest point on the path and the given
* @point.
* @out_pos: (out caller-allocates) (optional): return location
* for the closest point
* @out_offset: (out caller-allocates) (optional): The offset into
* the path of the found point
* @out_tangent: (out caller-allocates) (optional): return location for
* the tangent at the closest point
*
* Gets the point on the path that is closest to @point. If no point on
* path is closer to @point than @threshold, return %FALSE.
*
* Returns: %TRUE if a point was found, %FALSE otherwise.
**/
gboolean
gsk_path_measure_get_closest_point_full (GskPathMeasure *self,
const graphene_point_t *point,
float threshold,
float *out_distance,
graphene_point_t *out_pos,
float *out_offset,
graphene_vec2_t *out_tangent)
{
gboolean result;
gsize i;
float distance, length;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (point != NULL, FALSE);
result = FALSE;
length = 0;
for (i = 0; i < self->n_contours; i++)
{
if (gsk_contour_get_closest_point (self->path,
i,
self->measures[i].contour_data,
self->tolerance,
point,
threshold,
&distance,
out_pos,
out_offset,
out_tangent))
{
result = TRUE;
if (out_offset)
*out_offset += length;
if (distance < self->tolerance)
break;
threshold = distance - self->tolerance;
}
length += self->measures[i].length;
}
if (result && out_distance)
*out_distance = distance;
return result;
}
/**
* gsk_path_measure_in_fill:
* @self: a #GskPathMeasure
* @point: the point to test
* @fill_rule: the fill rule to follow
*
* Returns whether the given point is inside the area that would be
* affected if the path of @self was filled according to @fill_rule.
*
* Returns: %TRUE if @point is inside
*/
gboolean
gsk_path_measure_in_fill (GskPathMeasure *self,
const graphene_point_t *point,
GskFillRule fill_rule)
{
int winding = 0;
gboolean on_edge = FALSE;
int i;
for (i = 0; i < self->n_contours; i++)
{
winding += gsk_contour_get_winding (gsk_path_get_contour (self->path, i),
self->measures[i].contour_data,
point,
&on_edge);
if (on_edge)
return TRUE;
}
switch (fill_rule)
{
case GSK_FILL_RULE_EVEN_ODD:
return winding & 1;
case GSK_FILL_RULE_WINDING:
return winding != 0;
default:
g_assert_not_reached ();
}
}
/**
* gsk_path_measure_add_segment:
* @self: a #GskPathMeasure
* @builder: the builder to add the segment to
* @start: start distance into the path
* @end: end distance into the path
*
* Adds to @builder the segment of @path inbetween @start and @end.
*
* The distances are given relative to the length of @self's path,
* from 0 for the beginning of the path to
* gsk_path_measure_get_length() for the end of the path. The values
* will be clamped to that range.
*
* If @start >= @end after clamping, no path will be added.
**/
void
gsk_path_measure_add_segment (GskPathMeasure *self,
GskPathBuilder *builder,
float start,
float end)
{
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (builder != NULL);
start = gsk_path_measure_clamp_distance (self, start);
end = gsk_path_measure_clamp_distance (self, end);
if (start >= end)
return;
for (i = 0; i < self->n_contours; i++)
{
if (self->measures[i].length < start)
{
start -= self->measures[i].length;
end -= self->measures[i].length;
}
else if (start > 0 || end < self->measures[i].length)
{
float len = MIN (end, self->measures[i].length);
gsk_contour_add_segment (gsk_path_get_contour (self->path, i),
builder,
self->measures[i].contour_data,
start,
len);
end -= len;
start = 0;
if (end <= 0)
break;
}
else
{
end -= self->measures[i].length;
gsk_path_builder_add_contour (builder, gsk_contour_dup (gsk_path_get_contour (self->path, i)));
}
}
}
-81
View File
@@ -1,81 +0,0 @@
/*
* Copyright © 2020 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 __GSK_PATH_MEASURE_H__
#define __GSK_PATH_MEASURE_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gskpath.h>
G_BEGIN_DECLS
#define GSK_TYPE_PATH_MEASURE (gsk_path_measure_get_type ())
GDK_AVAILABLE_IN_ALL
GType gsk_path_measure_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskPathMeasure * gsk_path_measure_new (GskPath *path);
GDK_AVAILABLE_IN_ALL
GskPathMeasure * gsk_path_measure_new_with_tolerance (GskPath *path,
float tolerance);
GDK_AVAILABLE_IN_ALL
GskPathMeasure * gsk_path_measure_ref (GskPathMeasure *self);
GDK_AVAILABLE_IN_ALL
void gsk_path_measure_unref (GskPathMeasure *self);
GDK_AVAILABLE_IN_ALL
float gsk_path_measure_get_length (GskPathMeasure *self);
GDK_AVAILABLE_IN_ALL
void gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
graphene_point_t *pos,
graphene_vec2_t *tangent);
GDK_AVAILABLE_IN_ALL
float gsk_path_measure_get_closest_point (GskPathMeasure *self,
const graphene_point_t *point,
graphene_point_t *out_pos);
GDK_AVAILABLE_IN_ALL
gboolean gsk_path_measure_get_closest_point_full (GskPathMeasure *self,
const graphene_point_t *point,
float threshold,
float *out_distance,
graphene_point_t *out_pos,
float *out_offset,
graphene_vec2_t *out_tangent);
GDK_AVAILABLE_IN_ALL
void gsk_path_measure_add_segment (GskPathMeasure *self,
GskPathBuilder *builder,
float start,
float end);
GDK_AVAILABLE_IN_ALL
gboolean gsk_path_measure_in_fill (GskPathMeasure *self,
const graphene_point_t *point,
GskFillRule fill_rule);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPathMeasure, gsk_path_measure_unref)
G_END_DECLS
#endif /* __GSK_PATH_MEASURE_H__ */
-121
View File
@@ -1,121 +0,0 @@
/*
* Copyright © 2020 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 __GSK_PATH_PRIVATE_H__
#define __GSK_PATH_PRIVATE_H__
#include "gskpath.h"
G_BEGIN_DECLS
/* Same as Skia, so looks like a good value. ¯\_(ツ)_/¯ */
#define GSK_PATH_TOLERANCE_DEFAULT (0.5)
typedef enum
{
GSK_PATH_FLAT,
GSK_PATH_CLOSED
} GskPathFlags;
typedef struct _GskContour GskContour;
typedef struct _GskContourClass GskContourClass;
typedef struct _GskStandardOperation GskStandardOperation;
struct _GskStandardOperation {
GskPathOperation op;
gsize point; /* index into points array of the start point (last point of previous op) */
};
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
float radius,
float start_angle,
float end_angle);
GskContour * gsk_standard_contour_new (GskPathFlags flags,
const GskStandardOperation *ops,
gsize n_ops,
const graphene_point_t *points,
gsize n_points);
GskPath * gsk_path_new_from_contours (const GSList *contours);
gsize gsk_path_get_n_contours (GskPath *path);
const GskContour * gsk_path_get_contour (GskPath *path,
gsize i);
gboolean gsk_path_foreach_with_tolerance (GskPath *self,
GskPathForeachFlags flags,
double tolerance,
GskPathForeachFunc func,
gpointer user_data);
GskContour * gsk_contour_dup (const GskContour *src);
gpointer gsk_contour_init_measure (GskPath *path,
gsize i,
float tolerance,
float *out_length);
void gsk_contour_free_measure (GskPath *path,
gsize i,
gpointer data);
void gsk_contour_get_start_end (const GskContour *self,
graphene_point_t *start,
graphene_point_t *end);
void gsk_contour_get_point (GskPath *path,
gsize i,
gpointer measure_data,
float distance,
graphene_point_t *pos,
graphene_vec2_t *tangent);
gboolean gsk_contour_get_closest_point (GskPath *path,
gsize i,
gpointer measure_data,
float tolerance,
const graphene_point_t *point,
float threshold,
float *out_distance,
graphene_point_t *out_pos,
float *out_offset,
graphene_vec2_t *out_tangent);
int gsk_contour_get_winding (const GskContour *self,
gpointer measure_data,
const graphene_point_t *point,
gboolean *on_edge);
void gsk_contour_add_segment (const GskContour *self,
GskPathBuilder *builder,
gpointer measure_data,
float start,
float end);
void gsk_path_builder_add_contour (GskPathBuilder *builder,
GskContour *contour);
void gsk_path_builder_svg_arc_to (GskPathBuilder *builder,
float rx,
float ry,
float x_axis_rotation,
gboolean large_arc,
gboolean positive_sweep,
float x,
float y);
G_END_DECLS
#endif /* __GSK_PATH_PRIVATE_H__ */
-30
View File
@@ -158,8 +158,6 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_REPEAT_NODE (gsk_repeat_node_get_type())
#define GSK_TYPE_CLIP_NODE (gsk_clip_node_get_type())
#define GSK_TYPE_ROUNDED_CLIP_NODE (gsk_rounded_clip_node_get_type())
#define GSK_TYPE_FILL_NODE (gsk_fill_node_get_type())
#define GSK_TYPE_STROKE_NODE (gsk_stroke_node_get_type())
#define GSK_TYPE_SHADOW_NODE (gsk_shadow_node_get_type())
#define GSK_TYPE_BLEND_NODE (gsk_blend_node_get_type())
#define GSK_TYPE_CROSS_FADE_NODE (gsk_cross_fade_node_get_type())
@@ -188,8 +186,6 @@ typedef struct _GskColorMatrixNode GskColorMatrixNode;
typedef struct _GskRepeatNode GskRepeatNode;
typedef struct _GskClipNode GskClipNode;
typedef struct _GskRoundedClipNode GskRoundedClipNode;
typedef struct _GskFillNode GskFillNode;
typedef struct _GskStrokeNode GskStrokeNode;
typedef struct _GskShadowNode GskShadowNode;
typedef struct _GskBlendNode GskBlendNode;
typedef struct _GskCrossFadeNode GskCrossFadeNode;
@@ -463,32 +459,6 @@ GskRenderNode * gsk_rounded_clip_node_get_child (const GskRender
GDK_AVAILABLE_IN_ALL
const GskRoundedRect * gsk_rounded_clip_node_get_clip (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
GType gsk_fill_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_fill_node_new (GskRenderNode *child,
GskPath *path,
GskFillRule fill_rule);
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_fill_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_fill_node_get_path (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GskFillRule gsk_fill_node_get_fill_rule (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_stroke_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_stroke_node_new (GskRenderNode *child,
GskPath *path,
const GskStroke *stroke);
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_stroke_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GskPath * gsk_stroke_node_get_path (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
const GskStroke * gsk_stroke_node_get_stroke (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_shadow_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
-378
View File
@@ -25,10 +25,8 @@
#include "gskdebugprivate.h"
#include "gskdiffprivate.h"
#include "gl/gskglrenderer.h"
#include "gskpath.h"
#include "gskrendererprivate.h"
#include "gskroundedrectprivate.h"
#include "gskstrokeprivate.h"
#include "gsktransformprivate.h"
#include "gdk/gdktextureprivate.h"
@@ -4372,368 +4370,6 @@ gsk_rounded_clip_node_get_clip (const GskRenderNode *node)
return &self->clip;
}
/* }}} */
/* {{{ GSK_FILL_NODE */
struct _GskFillNode
{
GskRenderNode render_node;
GskRenderNode *child;
GskPath *path;
GskFillRule fill_rule;
};
static void
gsk_fill_node_finalize (GskRenderNode *node)
{
GskFillNode *self = (GskFillNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_FILL_NODE));
gsk_render_node_unref (self->child);
gsk_path_unref (self->path);
parent_class->finalize (node);
}
static void
gsk_fill_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskFillNode *self = (GskFillNode *) node;
cairo_save (cr);
switch (self->fill_rule)
{
case GSK_FILL_RULE_WINDING:
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
break;
case GSK_FILL_RULE_EVEN_ODD:
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
break;
default:
g_assert_not_reached ();
break;
}
gsk_path_to_cairo (self->path, cr);
cairo_clip (cr);
gsk_render_node_draw (self->child, cr);
cairo_restore (cr);
}
static void
gsk_fill_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskFillNode *self1 = (GskFillNode *) node1;
GskFillNode *self2 = (GskFillNode *) node2;
if (self1->path == self2->path)
{
cairo_region_t *sub;
cairo_rectangle_int_t clip_rect;
graphene_rect_t rect;
sub = cairo_region_create();
gsk_render_node_diff (self1->child, self2->child, sub);
graphene_rect_union (&node1->bounds, &node2->bounds, &rect);
rectangle_init_from_graphene (&clip_rect, &rect);
cairo_region_intersect_rectangle (sub, &clip_rect);
cairo_region_union (region, sub);
cairo_region_destroy (sub);
}
else
{
gsk_render_node_diff_impossible (node1, node2, region);
}
}
static void
gsk_fill_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_FILL_NODE;
node_class->finalize = gsk_fill_node_finalize;
node_class->draw = gsk_fill_node_draw;
node_class->diff = gsk_fill_node_diff;
}
/**
* gsk_fill_node_new:
* @child: The node to fill the area with
* @path: The path describing the area to fill
* @fill_rule: The fill rule to use
*
* Creates a #GskRenderNode that will fill the @child in the area
* given by @path and @fill_rule.
*
* Returns: (transfer none) (type GskFillNode): A new #GskRenderNode
*/
GskRenderNode *
gsk_fill_node_new (GskRenderNode *child,
GskPath *path,
GskFillRule fill_rule)
{
GskFillNode *self;
GskRenderNode *node;
graphene_rect_t path_bounds;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (path != NULL, NULL);
self = gsk_render_node_alloc (GSK_FILL_NODE);
node = (GskRenderNode *) self;
self->child = gsk_render_node_ref (child);
self->path = gsk_path_ref (path);
self->fill_rule = fill_rule;
if (gsk_path_get_bounds (path, &path_bounds))
graphene_rect_intersection (&path_bounds, &child->bounds, &node->bounds);
else
graphene_rect_init_from_rect (&node->bounds, graphene_rect_zero ());
return node;
}
/**
* gsk_fill_node_get_child:
* @node: (type GskFillNode): a fill #GskRenderNode
*
* Gets the child node that is getting drawn by the given @node.
*
* Returns: (transfer none): The child that is getting drawn
**/
GskRenderNode *
gsk_fill_node_get_child (GskRenderNode *node)
{
GskFillNode *self = (GskFillNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL);
return self->child;
}
/**
* gsk_fill_node_get_path:
* @node: (type GskFillNode): a fill #GskRenderNode
*
* Retrievs the path used to describe the area filled with the contents of
* the @node.
*
* Returns: (transfer none): a #GskPath
*/
GskPath *
gsk_fill_node_get_path (GskRenderNode *node)
{
GskFillNode *self = (GskFillNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), NULL);
return self->path;
}
/**
* gsk_fill_node_get_fill_rule:
* @node: (type GskFillNode): a fill #GskRenderNode
*
* Retrievs the fill rule used to determine how the path is filled.
*
* Returns: a #GskFillRule
*/
GskFillRule
gsk_fill_node_get_fill_rule (GskRenderNode *node)
{
GskFillNode *self = (GskFillNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_FILL_NODE), GSK_FILL_RULE_WINDING);
return self->fill_rule;
}
/* }}} */
/* {{{ GSK_STROKE_NODE */
struct _GskStrokeNode
{
GskRenderNode render_node;
GskRenderNode *child;
GskPath *path;
GskStroke stroke;
};
static void
gsk_stroke_node_finalize (GskRenderNode *node)
{
GskStrokeNode *self = (GskStrokeNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_STROKE_NODE));
gsk_render_node_unref (self->child);
gsk_path_unref (self->path);
gsk_stroke_clear (&self->stroke);
parent_class->finalize (node);
}
static void
gsk_stroke_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskStrokeNode *self = (GskStrokeNode *) node;
cairo_save (cr);
gsk_cairo_rectangle (cr, &self->child->bounds);
cairo_clip (cr);
cairo_push_group (cr);
gsk_render_node_draw (self->child, cr);
cairo_pop_group_to_source (cr);
gsk_stroke_to_cairo (&self->stroke, cr);
gsk_path_to_cairo (self->path, cr);
cairo_stroke (cr);
cairo_restore (cr);
}
static void
gsk_stroke_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskStrokeNode *self1 = (GskStrokeNode *) node1;
GskStrokeNode *self2 = (GskStrokeNode *) node2;
if (self1->path == self2->path &&
gsk_stroke_equal (&self1->stroke, &self2->stroke))
{
cairo_region_t *sub;
sub = cairo_region_create();
gsk_render_node_diff (self1->child, self2->child, sub);
cairo_region_union (region, sub);
cairo_region_destroy (sub);
}
else
{
gsk_render_node_diff_impossible (node1, node2, region);
}
}
static void
gsk_stroke_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_STROKE_NODE;
node_class->finalize = gsk_stroke_node_finalize;
node_class->draw = gsk_stroke_node_draw;
node_class->diff = gsk_stroke_node_diff;
}
/**
* gsk_stroke_node_new:
* @child: The node to stroke the area with
* @path: (transfer none): The path describing the area to stroke
* @stroke: (transfer none): The stroke attributes to use
*
* Creates a #GskRenderNode that will stroke the @child along the given
* @path using the attributes defined in @stroke.
*
* Returns: (transfer none) (type GskStrokeNode): A new #GskRenderNode
*/
GskRenderNode *
gsk_stroke_node_new (GskRenderNode *child,
GskPath *path,
const GskStroke *stroke)
{
GskStrokeNode *self;
GskRenderNode *node;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (stroke != NULL, NULL);
self = gsk_render_node_alloc (GSK_STROKE_NODE);
node = (GskRenderNode *) self;
self->child = gsk_render_node_ref (child);
self->path = gsk_path_ref (path);
gsk_stroke_init_copy (&self->stroke, stroke);
/* XXX: Figure out a way to compute bounds from the path */
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
return node;
}
/**
* gsk_stroke_node_get_child:
* @node: (type GskStrokeNode): a stroke #GskRenderNode
*
* Gets the child node that is getting drawn by the given @node.
*
* Returns: (transfer none): The child that is getting drawn
**/
GskRenderNode *
gsk_stroke_node_get_child (GskRenderNode *node)
{
GskStrokeNode *self = (GskStrokeNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_STROKE_NODE), NULL);
return self->child;
}
/**
* gsk_stroke_node_get_path:
* @node: (type GskStrokeNode): a stroke #GskRenderNode
*
* Retrievs the path that will be stroked with the contents of
* the @node.
*
* Returns: (transfer none): a #GskPath
*/
GskPath *
gsk_stroke_node_get_path (GskRenderNode *node)
{
GskStrokeNode *self = (GskStrokeNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_STROKE_NODE), NULL);
return self->path;
}
/**
* gsk_stroke_node_get_stroke:
* @node: (type GskStrokeNode): a stroke #GskRenderNode
*
* Retrievs the stroke attributes used in this @node.
*
* Returns: a #GskStroke
*/
const GskStroke *
gsk_stroke_node_get_stroke (GskRenderNode *node)
{
GskStrokeNode *self = (GskStrokeNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_STROKE_NODE), NULL);
return &self->stroke;
}
/* }}} */
/* {{{ GSK_SHADOW_NODE */
@@ -6067,8 +5703,6 @@ gsk_mask_node_draw (GskRenderNode *node,
cairo_clip (cr);
cairo_mask (cr, mask_pattern);
cairo_pattern_destroy (mask_pattern);
}
static void
@@ -6587,8 +6221,6 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_color_matrix_node, GSK_COLOR_MATRIX_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeat_node, GSK_REPEAT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_clip_node, GSK_CLIP_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_rounded_clip_node, GSK_ROUNDED_CLIP_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_fill_node, GSK_FILL_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_stroke_node, GSK_STROKE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_shadow_node, GSK_SHADOW_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE)
@@ -6737,16 +6369,6 @@ gsk_render_node_init_types_once (void)
sizeof (GskDebugNode),
gsk_debug_node_class_init);
gsk_render_node_types[GSK_DEBUG_NODE] = node_type;
node_type = gsk_render_node_type_register_static (I_("GskFillNode"),
sizeof (GskFillNode),
gsk_fill_node_class_init);
gsk_render_node_types[GSK_FILL_NODE] = node_type;
node_type = gsk_render_node_type_register_static (I_("GskStrokeNode"),
sizeof (GskStrokeNode),
gsk_stroke_node_class_init);
gsk_render_node_types[GSK_STROKE_NODE] = node_type;
}
static void
+4 -377
View File
@@ -23,13 +23,9 @@
#include "gskrendernodeparserprivate.h"
#include "gskpath.h"
#include "gskpathbuilder.h"
#include "gskroundedrectprivate.h"
#include "gskrendernodeprivate.h"
#include "gskstroke.h"
#include "gsktransformprivate.h"
#include "gskenumtypes.h"
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdktextureprivate.h"
@@ -1163,26 +1159,6 @@ create_default_render_node (void)
return gsk_color_node_new (&GDK_RGBA("FF00CC"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
}
static GskPath *
create_default_path (void)
{
GskPathBuilder *builder;
guint i;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, 25, 0);
for (i = 1; i < 5; i++)
{
gsk_path_builder_line_to (builder,
sin (i * G_PI * 0.8) * 25 + 25,
-cos (i * G_PI * 0.8) * 25 + 25);
}
gsk_path_builder_close (builder);
return gsk_path_builder_free_to_path (builder);
}
static GskRenderNode *
parse_color_node (GtkCssParser *parser,
Context *context)
@@ -2106,215 +2082,6 @@ parse_rounded_clip_node (GtkCssParser *parser,
return result;
}
static gboolean
parse_path (GtkCssParser *parser,
Context *context,
gpointer out_path)
{
GskPath *path;
char *str = NULL;
if (!parse_string (parser, context, &str))
return FALSE;
path = gsk_path_parse (str);
g_free (str);
if (path == NULL)
{
gtk_css_parser_error_value (parser, "Invalid path");
return FALSE;
}
*((GskPath **) out_path) = path;
return TRUE;
}
static void
clear_path (gpointer inout_path)
{
g_clear_pointer ((GskPath **) inout_path, gsk_path_unref);
}
static gboolean
parse_dash (GtkCssParser *parser,
Context *context,
gpointer out_dash)
{
GArray *dash;
double d;
/* because CSS does this, too */
if (gtk_css_parser_try_ident (parser, "none"))
{
*((GArray **) out_dash) = NULL;
return TRUE;
}
dash = g_array_new (FALSE, FALSE, sizeof (float));
do {
if (!gtk_css_parser_consume_number (parser, &d))
{
g_array_free (dash, TRUE);
return FALSE;
}
g_array_append_vals (dash, (float[1]) { d }, 1);
} while (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNLESS_NUMBER) ||
gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNLESS_INTEGER));
*((GArray **) out_dash) = dash;
return TRUE;
}
static void
clear_dash (gpointer inout_array)
{
g_clear_pointer ((GArray **) inout_array, g_array_unref);
}
static gboolean
parse_enum (GtkCssParser *parser,
GType type,
gpointer out_value)
{
GEnumClass *class;
GEnumValue *v;
char *enum_name;
enum_name = gtk_css_parser_consume_ident (parser);
if (enum_name == NULL)
return FALSE;
class = g_type_class_ref (type);
v = g_enum_get_value_by_nick (class, enum_name);
if (v == NULL)
{
gtk_css_parser_error_value (parser, "Unknown value \"%s\" for enum \"%s\"",
enum_name, g_type_name (type));
g_free (enum_name);
g_type_class_unref (class);
return FALSE;
}
*(int*)out_value = v->value;
g_free (enum_name);
g_type_class_unref (class);
gtk_css_parser_consume_token (parser);
return TRUE;
}
static gboolean
parse_fill_rule (GtkCssParser *parser,
Context *context,
gpointer out_rule)
{
return parse_enum (parser, GSK_TYPE_FILL_RULE, out_rule);
}
static GskRenderNode *
parse_fill_node (GtkCssParser *parser,
Context *context)
{
GskRenderNode *child = NULL;
GskPath *path = NULL;
int rule = GSK_FILL_RULE_WINDING;
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
{ "path", parse_path, clear_path, &path },
{ "fill-rule", parse_fill_rule, NULL, &rule },
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
if (path == NULL)
path = create_default_path ();
result = gsk_fill_node_new (child, path, rule);
gsk_path_unref (path);
gsk_render_node_unref (child);
return result;
}
static gboolean
parse_line_cap (GtkCssParser *parser,
Context *context,
gpointer out)
{
return parse_enum (parser, GSK_TYPE_LINE_CAP, out);
}
static gboolean
parse_line_join (GtkCssParser *parser,
Context *context,
gpointer out)
{
return parse_enum (parser, GSK_TYPE_LINE_JOIN, out);
}
static GskRenderNode *
parse_stroke_node (GtkCssParser *parser,
Context *context)
{
GskRenderNode *child = NULL;
GskPath *path = NULL;
double line_width = 1.0;
int line_cap = GSK_LINE_CAP_BUTT;
int line_join = GSK_LINE_JOIN_MITER;
double miter_limit = 4.0;
GArray *dash = NULL;
double dash_offset = 0.0;
GskStroke *stroke;
const Declaration declarations[] = {
{ "child", parse_node, clear_node, &child },
{ "path", parse_path, clear_path, &path },
{ "line-width", parse_double, NULL, &line_width },
{ "line-cap", parse_line_cap, NULL, &line_cap },
{ "line-join", parse_line_join, NULL, &line_join },
{ "miter-limit", parse_double, NULL, &miter_limit },
{ "dash", parse_dash, clear_dash, &dash },
{ "dash-offset", parse_double, NULL, &dash_offset},
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
if (path == NULL)
path = create_default_path ();
stroke = gsk_stroke_new (line_width);
gsk_stroke_set_line_cap (stroke, line_cap);
gsk_stroke_set_line_join (stroke, line_join);
gsk_stroke_set_miter_limit (stroke, miter_limit);
if (dash)
{
gsk_stroke_set_dash (stroke, (float *) dash->data, dash->len);
g_array_free (dash, TRUE);
}
gsk_stroke_set_dash_offset (stroke, dash_offset);
result = gsk_stroke_node_new (child, path, stroke);
gsk_path_unref (path);
gsk_stroke_free (stroke);
gsk_render_node_unref (child);
return result;
}
static GskRenderNode *
parse_shadow_node (GtkCssParser *parser,
Context *context)
@@ -2397,8 +2164,6 @@ parse_node (GtkCssParser *parser,
{ "repeating-linear-gradient", parse_repeating_linear_gradient_node },
{ "repeating-radial-gradient", parse_repeating_radial_gradient_node },
{ "rounded-clip", parse_rounded_clip_node },
{ "fill", parse_fill_node },
{ "stroke", parse_stroke_node },
{ "shadow", parse_shadow_node },
{ "text", parse_text_node },
{ "texture", parse_texture_node },
@@ -2653,14 +2418,6 @@ printer_init_duplicates_for_node (Printer *printer,
printer_init_duplicates_for_node (printer, gsk_debug_node_get_child (node));
break;
case GSK_FILL_NODE:
printer_init_duplicates_for_node (printer, gsk_fill_node_get_child (node));
break;
case GSK_STROKE_NODE:
printer_init_duplicates_for_node (printer, gsk_stroke_node_get_child (node));
break;
case GSK_BLEND_NODE:
printer_init_duplicates_for_node (printer, gsk_blend_node_get_bottom_child (node));
printer_init_duplicates_for_node (printer, gsk_blend_node_get_top_child (node));
@@ -2720,15 +2477,6 @@ printer_init (Printer *self,
printer_init_duplicates_for_node (self, node);
}
static void
printer_clear (Printer *self)
{
if (self->str)
g_string_free (self->str, TRUE);
g_hash_table_unref (self->named_nodes);
g_hash_table_unref (self->named_textures);
}
#define IDENT_LEVEL 2 /* Spaces per level */
static void
_indent (Printer *self)
@@ -2886,7 +2634,7 @@ append_float_param (Printer *p,
float value,
float default_value)
{
/* Don't approximate-compare here, better be too verbose */
/* Don't approximate-compare here, better be topo verbose */
if (value == default_value)
return;
@@ -3061,11 +2809,8 @@ append_escaping_newlines (GString *str,
len = strcspn (string, "\n");
g_string_append_len (str, string, len);
string += len;
if (*string)
{
g_string_append (str, "\\\n");
string++;
}
g_string_append (str, "\\\n");
string++;
} while (*string);
}
@@ -3264,83 +3009,6 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
pango_glyph_string_free (ascii);
}
static const char *
enum_to_nick (GType type,
int value)
{
GEnumClass *class;
GEnumValue *v;
class = g_type_class_ref (type);
v = g_enum_get_value (class, value);
g_type_class_unref (class);
return v->value_nick;
}
static void
append_enum_param (Printer *p,
const char *param_name,
GType type,
int value)
{
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
g_string_append (p->str, enum_to_nick (type, value));
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static void
append_path_param (Printer *p,
const char *param_name,
GskPath *path)
{
char *str, *s;
_indent (p);
g_string_append (p->str, "path: \"\\\n");
str = gsk_path_to_string (path);
/* Put each command on a new line */
for (s = str; *s; s++)
{
if (*s == ' ' &&
(s[1] == 'M' || s[1] == 'C' || s[1] == 'Z' || s[1] == 'L'))
*s = '\n';
}
append_escaping_newlines (p->str, str);
g_string_append (p->str, "\";\n");
g_free (str);
}
static void
append_dash_param (Printer *p,
const char *param_name,
const float *dash,
gsize n_dash)
{
_indent (p);
g_string_append (p->str, "dash: ");
if (n_dash == 0)
{
g_string_append (p->str, "none");
}
else
{
gsize i;
string_append_double (p->str, dash[0]);
for (i = 1; i < n_dash; i++)
{
g_string_append_c (p->str, ' ');
string_append_double (p->str, dash[i]);
}
}
g_string_append (p->str, ";\n");
}
static void
render_node_print (Printer *p,
GskRenderNode *node)
@@ -3510,42 +3178,6 @@ render_node_print (Printer *p,
append_rounded_rect_param (p, "clip", gsk_rounded_clip_node_get_clip (node));
append_node_param (p, "child", gsk_rounded_clip_node_get_child (node));
end_node (p);
}
break;
case GSK_FILL_NODE:
{
start_node (p, "fill", node_name);
append_node_param (p, "child", gsk_fill_node_get_child (node));
append_path_param (p, "path", gsk_fill_node_get_path (node));
append_enum_param (p, "fill-rule", GSK_TYPE_FILL_RULE, gsk_fill_node_get_fill_rule (node));
end_node (p);
}
break;
case GSK_STROKE_NODE:
{
const GskStroke *stroke;
const float *dash;
gsize n_dash;
start_node (p, "stroke", node_name);
append_node_param (p, "child", gsk_stroke_node_get_child (node));
append_path_param (p, "path", gsk_stroke_node_get_path (node));
stroke = gsk_stroke_node_get_stroke (node);
append_float_param (p, "line-width", gsk_stroke_get_line_width (stroke), 0.0f);
append_enum_param (p, "line-cap", GSK_TYPE_LINE_CAP, gsk_stroke_get_line_cap (stroke));
append_enum_param (p, "line-join", GSK_TYPE_LINE_JOIN, gsk_stroke_get_line_join (stroke));
append_float_param (p, "miter-limit", gsk_stroke_get_miter_limit (stroke), 4.0f);
dash = gsk_stroke_get_dash (stroke, &n_dash);
if (dash)
append_dash_param (p, "dash", dash, n_dash);
append_float_param (p, "dash-offset", gsk_stroke_get_dash_offset (stroke), 0.0f);
end_node (p);
}
@@ -4054,7 +3686,6 @@ GBytes *
gsk_render_node_serialize (GskRenderNode *node)
{
Printer p;
GBytes *res;
printer_init (&p, node);
@@ -4074,9 +3705,5 @@ gsk_render_node_serialize (GskRenderNode *node)
render_node_print (&p, node);
}
res = g_string_free_to_bytes (g_steal_pointer (&p.str));
printer_clear (&p);
return res;
return g_string_free_to_bytes (p.str);
}
-417
View File
@@ -1,417 +0,0 @@
/*
* Copyright © 2002 University of Southern California
* 2020 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>
* Carl D. Worth <cworth@cworth.org>
*/
#include "config.h"
#include "gsksplineprivate.h"
#include <math.h>
typedef struct
{
graphene_point_t last_point;
float last_progress;
float tolerance;
GskSplineAddPointFunc func;
gpointer user_data;
} GskCubicDecomposition;
static void
gsk_spline_decompose_add_point (GskCubicDecomposition *decomp,
const graphene_point_t *pt,
float progress)
{
if (graphene_point_equal (&decomp->last_point, pt))
return;
decomp->func (&decomp->last_point, pt, decomp->last_progress, decomp->last_progress + progress, decomp->user_data);
decomp->last_point = *pt;
decomp->last_progress += progress;
}
static void
gsk_spline_cubic_get_coefficients (graphene_point_t coeffs[4],
const graphene_point_t pts[4])
{
coeffs[0] = GRAPHENE_POINT_INIT (pts[3].x - 3.0f * pts[2].x + 3.0f * pts[1].x - pts[0].x,
pts[3].y - 3.0f * pts[2].y + 3.0f * pts[1].y - pts[0].y);
coeffs[1] = GRAPHENE_POINT_INIT (3.0f * pts[2].x - 6.0f * pts[1].x + 3.0f * pts[0].x,
3.0f * pts[2].y - 6.0f * pts[1].y + 3.0f * pts[0].y);
coeffs[2] = GRAPHENE_POINT_INIT (3.0f * pts[1].x - 3.0f * pts[0].x,
3.0f * pts[1].y - 3.0f * pts[0].y);
coeffs[3] = pts[0];
}
void
gsk_spline_get_point_cubic (const graphene_point_t pts[4],
float progress,
graphene_point_t *pos,
graphene_vec2_t *tangent)
{
graphene_point_t c[4];
gsk_spline_cubic_get_coefficients (c, pts);
if (pos)
*pos = GRAPHENE_POINT_INIT (((c[0].x * progress + c[1].x) * progress +c[2].x) * progress + c[3].x,
((c[0].y * progress + c[1].y) * progress +c[2].y) * progress + c[3].y);
if (tangent)
{
graphene_vec2_init (tangent,
(3.0f * c[0].x * progress + 2.0f * c[1].x) * progress + c[2].x,
(3.0f * c[0].y * progress + 2.0f * c[1].y) * progress + c[2].y);
graphene_vec2_normalize (tangent, tangent);
}
}
void
gsk_spline_split_cubic (const graphene_point_t pts[4],
graphene_point_t result1[4],
graphene_point_t result2[4],
float progress)
{
graphene_point_t ab, bc, cd;
graphene_point_t abbc, bccd;
graphene_point_t final;
graphene_point_interpolate (&pts[0], &pts[1], progress, &ab);
graphene_point_interpolate (&pts[1], &pts[2], progress, &bc);
graphene_point_interpolate (&pts[2], &pts[3], progress, &cd);
graphene_point_interpolate (&ab, &bc, progress, &abbc);
graphene_point_interpolate (&bc, &cd, progress, &bccd);
graphene_point_interpolate (&abbc, &bccd, progress, &final);
memcpy (result1, (graphene_point_t[4]) { pts[0], ab, abbc, final }, sizeof (graphene_point_t[4]));
memcpy (result2, (graphene_point_t[4]) { final, bccd, cd, pts[3] }, sizeof (graphene_point_t[4]));
}
#if 0
/* Return an upper bound on the error (squared) that could result from
* approximating a spline as a line segment connecting the two endpoints. */
static float
gsk_spline_error_squared (const graphene_point_t pts[4])
{
float bdx, bdy, berr;
float cdx, cdy, cerr;
/* We are going to compute the distance (squared) between each of the the b
* and c control points and the segment a-b. The maximum of these two
* distances will be our approximation error. */
bdx = pts[1].x - pts[0].x;
bdy = pts[1].y - pts[0].y;
cdx = pts[2].x - pts[0].x;
cdy = pts[2].y - pts[0].y;
if (!graphene_point_equal (&pts[0], &pts[3]))
{
float dx, dy, u, v;
/* Intersection point (px):
* px = p1 + u(p2 - p1)
* (p - px) (p2 - p1) = 0
* Thus:
* u = ((p - p1) (p2 - p1)) / p2 - p1²;
*/
dx = pts[3].x - pts[0].x;
dy = pts[3].y - pts[0].y;
v = dx * dx + dy * dy;
u = bdx * dx + bdy * dy;
if (u <= 0)
{
/* bdx -= 0;
* bdy -= 0;
*/
}
else if (u >= v)
{
bdx -= dx;
bdy -= dy;
}
else
{
bdx -= u/v * dx;
bdy -= u/v * dy;
}
u = cdx * dx + cdy * dy;
if (u <= 0)
{
/* cdx -= 0;
* cdy -= 0;
*/
}
else if (u >= v)
{
cdx -= dx;
cdy -= dy;
}
else
{
cdx -= u/v * dx;
cdy -= u/v * dy;
}
}
berr = bdx * bdx + bdy * bdy;
cerr = cdx * cdx + cdy * cdy;
if (berr > cerr)
return berr;
else
return cerr;
}
#endif
/* taken from Skia, including the very descriptive name */
static gboolean
gsk_spline_cubic_too_curvy (const graphene_point_t pts[4],
float tolerance)
{
graphene_point_t p;
graphene_point_interpolate (&pts[0], &pts[3], 1.0f / 3, &p);
if (ABS (p.x - pts[1].x) + ABS (p.y - pts[1].y) > tolerance)
return TRUE;
graphene_point_interpolate (&pts[0], &pts[3], 2.0f / 3, &p);
if (ABS (p.x - pts[2].x) + ABS (p.y - pts[2].y) > tolerance)
return TRUE;
return FALSE;
}
static void
gsk_spline_decompose_into (GskCubicDecomposition *decomp,
const graphene_point_t pts[4],
float progress)
{
graphene_point_t left[4], right[4];
if (!gsk_spline_cubic_too_curvy (pts, decomp->tolerance) || progress < 1 / 1024.f)
{
gsk_spline_decompose_add_point (decomp, &pts[3], progress);
return;
}
gsk_spline_split_cubic (pts, left, right, 0.5);
gsk_spline_decompose_into (decomp, left, progress / 2);
gsk_spline_decompose_into (decomp, right, progress / 2);
}
void
gsk_spline_decompose_cubic (const graphene_point_t pts[4],
float tolerance,
GskSplineAddPointFunc add_point_func,
gpointer user_data)
{
GskCubicDecomposition decomp = { pts[0], 0.0f, tolerance, add_point_func, user_data };
gsk_spline_decompose_into (&decomp, pts, 1.0f);
g_assert (graphene_point_equal (&decomp.last_point, &pts[3]));
g_assert (decomp.last_progress == 1.0f || decomp.last_progress == 0.0f);
}
/* Spline deviation from the circle in radius would be given by:
error = sqrt (x**2 + y**2) - 1
A simpler error function to work with is:
e = x**2 + y**2 - 1
From "Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
Design 8 (1990) 22-41, we learn:
abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
and
abs (error) =~ 1/2 * e
Of course, this error value applies only for the particular spline
approximation that is used in _cairo_gstate_arc_segment.
*/
static float
arc_error_normalized (float angle)
{
return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
}
static float
arc_max_angle_for_tolerance_normalized (float tolerance)
{
float angle, error;
guint i;
/* Use table lookup to reduce search time in most cases. */
struct {
float angle;
float error;
} table[] = {
{ G_PI / 1.0, 0.0185185185185185036127 },
{ G_PI / 2.0, 0.000272567143730179811158 },
{ G_PI / 3.0, 2.38647043651461047433e-05 },
{ G_PI / 4.0, 4.2455377443222443279e-06 },
{ G_PI / 5.0, 1.11281001494389081528e-06 },
{ G_PI / 6.0, 3.72662000942734705475e-07 },
{ G_PI / 7.0, 1.47783685574284411325e-07 },
{ G_PI / 8.0, 6.63240432022601149057e-08 },
{ G_PI / 9.0, 3.2715520137536980553e-08 },
{ G_PI / 10.0, 1.73863223499021216974e-08 },
{ G_PI / 11.0, 9.81410988043554039085e-09 },
};
for (i = 0; i < G_N_ELEMENTS (table); i++)
{
if (table[i].error < tolerance)
return table[i].angle;
}
i++;
do {
angle = G_PI / i++;
error = arc_error_normalized (angle);
} while (error > tolerance);
return angle;
}
static guint
arc_segments_needed (float angle,
float radius,
float tolerance)
{
float max_angle;
/* the error is amplified by at most the length of the
* major axis of the circle; see cairo-pen.c for a more detailed analysis
* of this. */
max_angle = arc_max_angle_for_tolerance_normalized (tolerance / radius);
return ceil (fabs (angle) / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius
R from angle A to angle B. Since we want a symmetric spline that
matches the endpoints of the arc in position and slope, we know
that the spline control points must be:
(R * cos(A), R * sin(A))
(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
(R * cos(B), R * sin(B))
for some value of h.
"Approximation of circular arcs by cubic polynomials", Michael
Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
various values of h along with error analysis for each.
From that paper, a very practical value of h is:
h = 4/3 * R * tan(angle/4)
This value does not give the spline with minimal error, but it does
provide a very good approximation, (6th-order convergence), and the
error expression is quite simple, (see the comment for
_arc_error_normalized).
*/
static gboolean
gsk_spline_decompose_arc_segment (const graphene_point_t *center,
float radius,
float angle_A,
float angle_B,
GskSplineAddCurveFunc curve_func,
gpointer user_data)
{
float r_sin_A, r_cos_A;
float r_sin_B, r_cos_B;
float h;
r_sin_A = radius * sin (angle_A);
r_cos_A = radius * cos (angle_A);
r_sin_B = radius * sin (angle_B);
r_cos_B = radius * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
return curve_func ((graphene_point_t[4]) {
GRAPHENE_POINT_INIT (
center->x + r_cos_A,
center->y + r_sin_A
),
GRAPHENE_POINT_INIT (
center->x + r_cos_A - h * r_sin_A,
center->y + r_sin_A + h * r_cos_A
),
GRAPHENE_POINT_INIT (
center->x + r_cos_B + h * r_sin_B,
center->y + r_sin_B - h * r_cos_B
),
GRAPHENE_POINT_INIT (
center->x + r_cos_B,
center->y + r_sin_B
)
},
user_data);
}
gboolean
gsk_spline_decompose_arc (const graphene_point_t *center,
float radius,
float tolerance,
float start_angle,
float end_angle,
GskSplineAddCurveFunc curve_func,
gpointer user_data)
{
float step = start_angle - end_angle;
guint i, n_segments;
/* Recurse if drawing arc larger than pi */
if (ABS (step) > G_PI)
{
float mid_angle = (start_angle + end_angle) / 2.0;
return gsk_spline_decompose_arc (center, radius, tolerance, start_angle, mid_angle, curve_func, user_data)
&& gsk_spline_decompose_arc (center, radius, tolerance, mid_angle, end_angle, curve_func, user_data);
}
else if (ABS (step) < tolerance)
{
return gsk_spline_decompose_arc_segment (center, radius, start_angle, end_angle, curve_func, user_data);
}
n_segments = arc_segments_needed (ABS (step), radius, tolerance);
step = (end_angle - start_angle) / n_segments;
for (i = 0; i < n_segments - 1; i++, start_angle += step)
{
if (!gsk_spline_decompose_arc_segment (center, radius, start_angle, start_angle + step, curve_func, user_data))
return FALSE;
}
return gsk_spline_decompose_arc_segment (center, radius, start_angle, end_angle, curve_func, user_data);
}
-60
View File
@@ -1,60 +0,0 @@
/*
* Copyright © 2020 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 __GSK_SPLINE_PRIVATE_H__
#define __GSK_SPLINE_PRIVATE_H__
#include "gskpath.h"
G_BEGIN_DECLS
typedef void (* GskSplineAddPointFunc) (const graphene_point_t *from,
const graphene_point_t *to,
float from_progress,
float to_progress,
gpointer user_data);
void gsk_spline_get_point_cubic (const graphene_point_t pts[4],
float progress,
graphene_point_t *pos,
graphene_vec2_t *tangent);
void gsk_spline_split_cubic (const graphene_point_t pts[4],
graphene_point_t result1[4],
graphene_point_t result2[4],
float progress);
void gsk_spline_decompose_cubic (const graphene_point_t pts[4],
float tolerance,
GskSplineAddPointFunc add_point_func,
gpointer user_data);
typedef gboolean (* GskSplineAddCurveFunc) (const graphene_point_t curve[4],
gpointer user_data);
gboolean gsk_spline_decompose_arc (const graphene_point_t *center,
float radius,
float tolerance,
float start_angle,
float end_angle,
GskSplineAddCurveFunc curve_func,
gpointer user_data);
G_END_DECLS
#endif /* __GSK_SPLINE_PRIVATE_H__ */
-441
View File
@@ -1,441 +0,0 @@
/*
* Copyright © 2020 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 "gskstrokeprivate.h"
/**
* SECTION:gskstroke
* @Title: Stroke
* @Short_description: Properties of a stroke operation
* @See_also: #GskPath, gsk_stroke_node_new()
*
* This section describes the #GskStroke structure that is used to
* describe lines and curves that are more complex than simple rectangles.
*
* #GskStroke is an immutable struct. After creation, you cannot change
* the types it represents. Instead, new #GskStroke have to be created.
* The #GskStrokeBuilder structure is meant to help in this endeavor.
*/
/**
* GskStroke:
*
* A #GskStroke struct is an opaque struct that should be copied
* on use.
*/
G_DEFINE_BOXED_TYPE (GskStroke, gsk_stroke,
gsk_stroke_copy,
gsk_stroke_free)
/**
* gsk_stroke_new:
* @line_width: line width of the stroke. Must be > 0
*
* Creates a new #GskStroke with the given @line_width.
*
* Returns: a new #GskStroke
**/
GskStroke *
gsk_stroke_new (float line_width)
{
GskStroke *self;
g_return_val_if_fail (line_width > 0, NULL);
self = g_new0 (GskStroke, 1);
self->line_width = line_width;
self->line_cap = GSK_LINE_CAP_BUTT;
self->line_join = GSK_LINE_JOIN_MITER;
self->miter_limit = 4.f; /* following svg */
return self;
}
/**
* gsk_stroke_copy:
* @other: #GskStroke to copy
*
* Creates a copy of the given @other stroke.
*
* Returns: a new #GskStroke. Use gsk_stroke_free() to free it.
**/
GskStroke *
gsk_stroke_copy (const GskStroke *other)
{
GskStroke *self;
g_return_val_if_fail (other != NULL, NULL);
self = g_new (GskStroke, 1);
gsk_stroke_init_copy (self, other);
return self;
}
/**
* gsk_stroke_free:
* @self: a #GskStroke
*
* Frees a #GskStroke.
**/
void
gsk_stroke_free (GskStroke *self)
{
if (self == NULL)
return;
gsk_stroke_clear (self);
g_free (self);
}
void
gsk_stroke_to_cairo (const GskStroke *self,
cairo_t *cr)
{
cairo_set_line_width (cr, self->line_width);
/* gcc can optimize that to a direct case. This catches later additions to the enum */
switch (self->line_cap)
{
case GSK_LINE_CAP_BUTT:
cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
break;
case GSK_LINE_CAP_ROUND:
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
break;
case GSK_LINE_CAP_SQUARE:
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
break;
default:
g_assert_not_reached ();
break;
}
/* gcc can optimize that to a direct case. This catches later additions to the enum */
switch (self->line_join)
{
case GSK_LINE_JOIN_MITER:
case GSK_LINE_JOIN_MITER_CLIP:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
break;
case GSK_LINE_JOIN_ROUND:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
break;
case GSK_LINE_JOIN_BEVEL:
cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
break;
default:
g_assert_not_reached ();
break;
}
cairo_set_miter_limit (cr, self->miter_limit);
if (self->dash_length)
{
gsize i;
double *dash = g_newa (double, self->n_dash);
for (i = 0; i < self->n_dash; i++)
{
dash[i] = self->dash[i];
}
cairo_set_dash (cr, dash, self->n_dash, self->dash_offset);
}
else
cairo_set_dash (cr, NULL, 0, 0.0);
}
/**
* gsk_stroke_equal:
* @stroke1: the first #GskStroke
* @stroke2: the second #GskStroke
*
* Checks if 2 strokes are identical.
*
* Returns: %TRUE if the 2 strokes are equal, %FALSE otherwise
**/
gboolean
gsk_stroke_equal (gconstpointer stroke1,
gconstpointer stroke2)
{
const GskStroke *self1 = stroke1;
const GskStroke *self2 = stroke2;
return self1->line_width == self2->line_width;
}
/**
* gsk_stroke_set_line_width:
* @self: a #GskStroke
* @line_width: width of the line in pixels
*
* Sets the line width to be used when stroking. The line width
* must be > 0.
**/
void
gsk_stroke_set_line_width (GskStroke *self,
float line_width)
{
g_return_if_fail (self != NULL);
g_return_if_fail (line_width > 0);
self->line_width = line_width;
}
/**
* gsk_stroke_get_line_width:
* @self: a #GskStroke
*
* Gets the line width used.
*
* Returns: The line width
**/
float
gsk_stroke_get_line_width (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 0.0);
return self->line_width;
}
/**
* gsk_stroke_set_line_cap:
* @self: a #GskStroke
* @line_cap: the #GskLineCap
*
* Sets the line cap to be used when stroking.
* See #GskLineCap for details.
**/
void
gsk_stroke_set_line_cap (GskStroke *self,
GskLineCap line_cap)
{
g_return_if_fail (self != NULL);
self->line_cap = line_cap;
}
/**
* gsk_stroke_get_line_cap:
* @self: a #GskStroke
*
* Gets the line cap used. See #GskLineCap for details.
*
* Returns: The line cap
**/
GskLineCap
gsk_stroke_get_line_cap (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 0.0);
return self->line_cap;
}
/**
* gsk_stroke_set_line_join:
* @self: a #GskStroke
* @line_join: The line join to use
*
* Sets the line join to be used when stroking.
* See #GskLineJoin for details.
**/
void
gsk_stroke_set_line_join (GskStroke *self,
GskLineJoin line_join)
{
g_return_if_fail (self != NULL);
self->line_join = line_join;
}
/**
* gsk_stroke_get_line_join:
* @self: a #GskStroke
*
* Gets the line join used. See #GskLineJoin for details.
*
* Returns: The line join
**/
GskLineJoin
gsk_stroke_get_line_join (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 0.0);
return self->line_join;
}
/**
* gsk_stroke_set_miter_limit:
* @self: a #GskStroke
* @limit: the miter limit, must be non-negative
*
* Sets the limit for the distance from the corner where sharp
* turns of joins get cut off. The miter limit is in units of
* line width.
*
* For joins of type %GSK_LINE_JOIN_MITER that exceed the miter
* limit, the join gets rendered as if it was of type
* %GSK_LINE_JOIN_BEVEL. For joins of type %GSK_LINE_JOIN_MITER_CLIP,
* the miter is clipped at a distance of half the miter limit.
*/
void
gsk_stroke_set_miter_limit (GskStroke *self,
float limit)
{
g_return_if_fail (self != NULL);
g_return_if_fail (limit >= 0);
self->miter_limit = limit;
}
/**
* gsk_stroke_get_miter_limit:
* @self: a #GskStroke
*
* Returns the miter limit of a #GskStroke.
*/
float
gsk_stroke_get_miter_limit (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 4.f);
return self->miter_limit;
}
/**
* gsk_stroke_set_dash:
* @self: a #GskStroke
* @dash: (array length=n_dash) (transfer none) (nullable):
* the array of dashes
* @n_dash: number of elements in @dash
*
* Sets the dash pattern to use by this stroke. A dash pattern is specified by
* an array of alternating non-negative values. Each value provides the length
* of alternate "on" and "off" portions of the stroke.
*
* Each "on" segment will have caps applied as if the segment were a separate
* contour. In particular, it is valid to use an "on" length of 0 with
* @GSK_LINE_CAP_ROUND or @GSK_LINE_CAP_SQUARE to draw dots or squares along
* a path.
*
* If @n_dash is 0, if all elements in @dash are 0, or if there are negative
* values in @dash, then dashing is disabled.
*
* If @n_dash is 1, an alternating "on" and "off" pattern with the single
* dash length provided is assumed.
*
* If @n_dash is uneven, the dash array will be used with the first element
* in @dash defining an "on" or "off" in alternating passes through the array.
*
* You can specify a starting offset into the dash with
* @gsk_stroke_set_dash_offset().
**/
void
gsk_stroke_set_dash (GskStroke *self,
const float *dash,
gsize n_dash)
{
float dash_length;
gsize i;
g_return_if_fail (self != NULL);
g_return_if_fail (dash != NULL || n_dash == 0);
dash_length = 0;
for (i = 0; i < n_dash; i++)
{
if (!(dash[i] >= 0)) /* should catch NaN */
{
g_critical ("invalid value in dash array at position %zu", i);
return;
}
dash_length += dash[i];
}
self->dash_length = dash_length;
g_free (self->dash);
self->dash = g_memdup (dash, sizeof (gfloat) * n_dash);
self->n_dash = n_dash;
}
/**
* gsk_stroke_get_dash:
* @self: a #GskStroke
* @n_dash: (out caller-allocates): number of elements
* in the array returned
*
* Gets the dash array in use or %NULL if dashing is disabled.
*
* Returns: (array length=n_dash) (transfer none) (nullable):
* The dash array or %NULL if the dash array is empty.
**/
const float *
gsk_stroke_get_dash (const GskStroke *self,
gsize *n_dash)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (n_dash != NULL, NULL);
*n_dash = self->n_dash;
return self->dash;
}
/**
* gsk_stroke_set_dash_offset:
* @self: a #GskStroke
* @offset: offset into the dash pattern
*
* Sets the offset into the dash pattern set via gsk_stroke_set_dash() where
* dashing should begin.
*
* This is an offset into the length of the path, not an index into the array values of
* the dash array.
**/
void
gsk_stroke_set_dash_offset (GskStroke *self,
float offset)
{
g_return_if_fail (self != NULL);
self->dash_offset = offset;
}
/**
* gsk_stroke_get_dash_offset:
* @self: a #GskStroke
*
* Returns the dash_offset of a #GskStroke.
*/
float
gsk_stroke_get_dash_offset (const GskStroke *self)
{
g_return_val_if_fail (self != NULL, 4.f);
return self->dash_offset;
}
-87
View File
@@ -1,87 +0,0 @@
/*
* Copyright © 2020 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 __GSK_STROKE_H__
#define __GSK_STROKE_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <gsk/gsktypes.h>
G_BEGIN_DECLS
#define GSK_TYPE_STROKE (gsk_stroke_get_type ())
GDK_AVAILABLE_IN_ALL
GType gsk_stroke_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskStroke * gsk_stroke_new (float line_width);
GDK_AVAILABLE_IN_ALL
GskStroke * gsk_stroke_copy (const GskStroke *other);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_free (GskStroke *self);
GDK_AVAILABLE_IN_ALL
gboolean gsk_stroke_equal (gconstpointer stroke1,
gconstpointer stroke2);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_set_line_width (GskStroke *self,
float line_width);
GDK_AVAILABLE_IN_ALL
float gsk_stroke_get_line_width (const GskStroke *self);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_set_line_cap (GskStroke *self,
GskLineCap line_cap);
GDK_AVAILABLE_IN_ALL
GskLineCap gsk_stroke_get_line_cap (const GskStroke *self);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_set_line_join (GskStroke *self,
GskLineJoin line_join);
GDK_AVAILABLE_IN_ALL
GskLineJoin gsk_stroke_get_line_join (const GskStroke *self);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_set_miter_limit (GskStroke *self,
float limit);
GDK_AVAILABLE_IN_ALL
float gsk_stroke_get_miter_limit (const GskStroke *self);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_set_dash (GskStroke *self,
const float *dash,
gsize n_dash);
GDK_AVAILABLE_IN_ALL
const float * gsk_stroke_get_dash (const GskStroke *self,
gsize *n_dash);
GDK_AVAILABLE_IN_ALL
void gsk_stroke_set_dash_offset (GskStroke *self,
float offset);
GDK_AVAILABLE_IN_ALL
float gsk_stroke_get_dash_offset (const GskStroke *self);
G_END_DECLS
#endif /* __GSK_STROKE_H__ */
-63
View File
@@ -1,63 +0,0 @@
/*
* Copyright © 2020 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 __GSK_STROKE_PRIVATE_H__
#define __GSK_STROKE_PRIVATE_H__
#include "gskstroke.h"
G_BEGIN_DECLS
struct _GskStroke
{
float line_width;
GskLineCap line_cap;
GskLineJoin line_join;
float miter_limit;
float *dash;
gsize n_dash;
float dash_length; /* sum of all dashes in the array */
float dash_offset;
};
static inline void
gsk_stroke_init_copy (GskStroke *stroke,
const GskStroke *other)
{
*stroke = *other;
stroke->dash = g_memdup (other->dash, stroke->n_dash * sizeof (float));
}
static inline void
gsk_stroke_clear (GskStroke *stroke)
{
g_clear_pointer (&stroke->dash, g_free);
stroke->n_dash = 0; /* better safe than sorry */
}
void gsk_stroke_to_cairo (const GskStroke *self,
cairo_t *cr);
G_END_DECLS
#endif /* __GSK_STROKE_PRIVATE_H__ */
-4
View File
@@ -25,10 +25,6 @@
#include <gdk/gdk.h>
#include <gsk/gskenums.h>
typedef struct _GskPath GskPath;
typedef struct _GskPathBuilder GskPathBuilder;
typedef struct _GskPathMeasure GskPathMeasure;
typedef struct _GskRenderer GskRenderer;
typedef struct _GskStroke GskStroke;
typedef struct _GskTransform GskTransform;
-11
View File
@@ -26,15 +26,11 @@ gsk_public_sources = files([
'gskdiff.c',
'gskcairorenderer.c',
'gskglshader.c',
'gskpath.c',
'gskpathbuilder.c',
'gskpathmeasure.c',
'gskrenderer.c',
'gskrendernode.c',
'gskrendernodeimpl.c',
'gskrendernodeparser.c',
'gskroundedrect.c',
'gskstroke.c',
'gsktransform.c',
'gl/gskglrenderer.c',
])
@@ -44,7 +40,6 @@ gsk_private_sources = files([
'gskdebug.c',
'gskprivate.c',
'gskprofiler.c',
'gskspline.c',
'gl/gskglattachmentstate.c',
'gl/gskglbuffer.c',
'gl/gskglcommandqueue.c',
@@ -71,13 +66,9 @@ gsk_public_headers = files([
'gskcairorenderer.h',
'gskenums.h',
'gskglshader.h',
'gskpath.h',
'gskpathbuilder.h',
'gskpathmeasure.h',
'gskrenderer.h',
'gskrendernode.h',
'gskroundedrect.h',
'gskstroke.h',
'gsktransform.h',
'gsktypes.h',
])
@@ -112,7 +103,6 @@ gsk_private_vulkan_shaders = []
# on constantly regenerated files.
gsk_private_vulkan_compiled_shaders = []
gsk_private_vulkan_compiled_shaders_deps = []
gsk_private_vulkan_shader_headers = []
if have_vulkan
gsk_private_sources += files([
@@ -207,7 +197,6 @@ libgsk = static_library('gsk',
gsk_private_sources,
gsk_enums,
gskresources,
gsk_private_vulkan_shader_headers,
],
dependencies: gsk_deps,
include_directories: [ confinc, ],
+78 -3
View File
@@ -2,8 +2,6 @@
#include "gskvulkanblendmodepipelineprivate.h"
#include "vulkan/resources/blend-mode.vert.h"
struct _GskVulkanBlendModePipeline
{
GObject parent_instance;
@@ -11,12 +9,89 @@ struct _GskVulkanBlendModePipeline
typedef struct _GskVulkanBlendModeInstance GskVulkanBlendModeInstance;
struct _GskVulkanBlendModeInstance
{
float rect[4];
float top_rect[4];
float bottom_rect[4];
float top_tex_rect[4];
float bottom_tex_rect[4];
guint32 top_tex_id[2];
guint32 bottom_tex_id[2];
guint32 blend_mode;
};
G_DEFINE_TYPE (GskVulkanBlendModePipeline, gsk_vulkan_blend_mode_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_blend_mode_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_blend_mode_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanBlendModeInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = 0,
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, top_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, bottom_rect),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, top_tex_rect),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, bottom_tex_rect),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, top_tex_id),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, bottom_tex_id),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlendModeInstance, blend_mode),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
+54 -5
View File
@@ -2,19 +2,68 @@
#include "gskvulkanblurpipelineprivate.h"
#include "vulkan/resources/blur.vert.h"
struct _GskVulkanBlurPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanBlurInstance GskVulkanBlurInstance;
struct _GskVulkanBlurInstance
{
float rect[4];
float tex_rect[4];
float blur_radius;
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanBlurPipeline, gsk_vulkan_blur_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_blur_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_blur_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanBlurInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = 0,
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, blur_radius),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanBlurInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -56,7 +105,7 @@ gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
const graphene_point_t *offset,
const graphene_rect_t *rect,
const graphene_rect_t *tex_rect,
double radius)
double blur_radius)
{
GskVulkanBlurInstance *instance = (GskVulkanBlurInstance *) data;
@@ -68,7 +117,7 @@ gsk_vulkan_blur_pipeline_collect_vertex_data (GskVulkanBlurPipeline *pipeline,
instance->tex_rect[1] = tex_rect->origin.y;
instance->tex_rect[2] = tex_rect->size.width;
instance->tex_rect[3] = tex_rect->size.height;
instance->radius = radius;
instance->blur_radius = blur_radius;
instance->tex_id[0] = tex_id[0];
instance->tex_id[1] = tex_id[1];
}
+80 -8
View File
@@ -4,19 +4,91 @@
#include "gskroundedrectprivate.h"
#include "vulkan/resources/border.vert.h"
struct _GskVulkanBorderPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanBorderInstance GskVulkanBorderInstance;
struct _GskVulkanBorderInstance
{
float rect[12];
float widths[4];
float colors[16];
};
G_DEFINE_TYPE (GskVulkanBorderPipeline, gsk_vulkan_border_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_border_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_border_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanBorderInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 4 * sizeof (float),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, rect) + 8 * sizeof (float),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, widths),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 4 * sizeof (float),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 8 * sizeof (float),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBorderInstance, colors) + 12 * sizeof (float),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -65,11 +137,11 @@ gsk_vulkan_border_pipeline_collect_vertex_data (GskVulkanBorderPipeline *pipelin
gsk_rounded_rect_to_float (rect, offset, instance->rect);
for (i = 0; i < 4; i++)
{
instance->border_widths[i] = widths[i];
instance->border_colors[4 * i + 0] = colors[i].red;
instance->border_colors[4 * i + 1] = colors[i].green;
instance->border_colors[4 * i + 2] = colors[i].blue;
instance->border_colors[4 * i + 3] = colors[i].alpha;
instance->widths[i] = widths[i];
instance->colors[4 * i + 0] = colors[i].red;
instance->colors[4 * i + 1] = colors[i].green;
instance->colors[4 * i + 2] = colors[i].blue;
instance->colors[4 * i + 3] = colors[i].alpha;
}
}
+72 -4
View File
@@ -2,8 +2,6 @@
#include "gskvulkanboxshadowpipelineprivate.h"
#include "vulkan/resources/inset-shadow.vert.h"
#include "gskroundedrectprivate.h"
struct _GskVulkanBoxShadowPipeline
@@ -11,12 +9,82 @@ struct _GskVulkanBoxShadowPipeline
GObject parent_instance;
};
typedef struct _GskVulkanBoxShadowInstance GskVulkanBoxShadowInstance;
struct _GskVulkanBoxShadowInstance
{
float outline[12];
float color[4];
float offset[2];
float spread;
float blur_radius;
};
G_DEFINE_TYPE (GskVulkanBoxShadowPipeline, gsk_vulkan_box_shadow_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_box_shadow_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_inset_shadow_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanBoxShadowInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 4 * sizeof (float),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, outline) + 8 * sizeof (float),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, color),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, offset),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, spread),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanBoxShadowInstance, blur_radius),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -62,7 +130,7 @@ gsk_vulkan_box_shadow_pipeline_collect_vertex_data (GskVulkanBoxShadowPipeline *
float spread,
float blur_radius)
{
GskVulkanInsetShadowInstance *instance = (GskVulkanInsetShadowInstance *) data;
GskVulkanBoxShadowInstance *instance = (GskVulkanBoxShadowInstance *) data;
gsk_rounded_rect_to_float (outline, offset, instance->outline);
instance->color[0] = color->red;
+38 -3
View File
@@ -2,19 +2,54 @@
#include "gskvulkancolorpipelineprivate.h"
#include "vulkan/resources/color.vert.h"
struct _GskVulkanColorPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanColorInstance GskVulkanColorInstance;
struct _GskVulkanColorInstance
{
float rect[4];
float color[4];
};
G_DEFINE_TYPE (GskVulkanColorPipeline, gsk_vulkan_color_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_color_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_color_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanColorInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = 0,
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanColorInstance, color),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
+47 -5
View File
@@ -2,19 +2,61 @@
#include "gskvulkancolortextpipelineprivate.h"
#include "vulkan/resources/texture.vert.h"
struct _GskVulkanColorTextPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanColorTextInstance GskVulkanColorTextInstance;
struct _GskVulkanColorTextInstance
{
float rect[4];
float tex_rect[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanColorTextPipeline, gsk_vulkan_color_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_color_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_texture_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanColorTextInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanColorTextInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -63,7 +105,7 @@ gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *
guint num_glyphs,
float scale)
{
GskVulkanTextureInstance *instances = (GskVulkanTextureInstance *) data;
GskVulkanColorTextInstance *instances = (GskVulkanColorTextInstance *) data;
int i;
int count = 0;
int x_position = 0;
@@ -79,7 +121,7 @@ gsk_vulkan_color_text_pipeline_collect_vertex_data (GskVulkanColorTextPipeline *
{
double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
double cy = gi->geometry.y_offset / PANGO_SCALE;
GskVulkanTextureInstance *instance = &instances[count];
GskVulkanColorTextInstance *instance = &instances[count];
GskVulkanCachedGlyph *glyph;
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer,
+80 -3
View File
@@ -2,19 +2,96 @@
#include "gskvulkancrossfadepipelineprivate.h"
#include "vulkan/resources/cross-fade.vert.h"
struct _GskVulkanCrossFadePipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
struct _GskVulkanCrossFadeInstance
{
float rect[4];
float start_rect[4];
float end_rect[4];
float start_tex_rect[4];
float end_tex_rect[4];
guint32 start_tex_id[2];
guint32 end_tex_id[2];
float progress;
};
G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_cross_fade_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanCrossFadeInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = 0,
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_rect),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_id),
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_id),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
+78 -4
View File
@@ -2,19 +2,93 @@
#include "gskvulkaneffectpipelineprivate.h"
#include "vulkan/resources/color-matrix.vert.h"
struct _GskVulkanEffectPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanEffectInstance GskVulkanEffectInstance;
struct _GskVulkanEffectInstance
{
float rect[4];
float tex_rect[4];
float color_matrix[16];
float color_offset[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanEffectPipeline, gsk_vulkan_effect_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_effect_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_color_matrix_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanEffectInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = 0,
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 4,
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 8,
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_matrix) + sizeof (float) * 12,
},
{
.location = 6,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, color_offset),
},
{
.location = 7,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanEffectInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -59,7 +133,7 @@ gsk_vulkan_effect_pipeline_collect_vertex_data (GskVulkanEffectPipeline *pipelin
const graphene_matrix_t *color_matrix,
const graphene_vec4_t *color_offset)
{
GskVulkanColorMatrixInstance *instance = (GskVulkanColorMatrixInstance *) data;
GskVulkanEffectInstance *instance = (GskVulkanEffectInstance *) data;
instance->rect[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->y;
+68 -5
View File
@@ -2,19 +2,82 @@
#include "gskvulkanlineargradientpipelineprivate.h"
#include "vulkan/resources/linear.vert.h"
struct _GskVulkanLinearGradientPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanLinearGradientInstance GskVulkanLinearGradientInstance;
struct _GskVulkanLinearGradientInstance
{
float rect[4];
float start[2];
float end[2];
gint32 repeating;
gint32 offset;
gint32 stop_count;
};
G_DEFINE_TYPE (GskVulkanLinearGradientPipeline, gsk_vulkan_linear_gradient_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_linear_gradient_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_linear_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanLinearGradientInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = 0,
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, start),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, end),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32_SINT,
.offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, repeating),
},
{
.location = 4,
.binding = 0,
.format = VK_FORMAT_R32_SINT,
.offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, offset),
},
{
.location = 5,
.binding = 0,
.format = VK_FORMAT_R32_SINT,
.offset = G_STRUCT_OFFSET (GskVulkanLinearGradientInstance, stop_count),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -60,7 +123,7 @@ gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradient
gsize gradient_offset,
gsize n_stops)
{
GskVulkanLinearInstance *instance = (GskVulkanLinearInstance *) data;
GskVulkanLinearGradientInstance *instance = (GskVulkanLinearGradientInstance *) data;
instance->rect[0] = rect->origin.x + offset->x;
instance->rect[1] = rect->origin.y + offset->y;
@@ -71,7 +134,7 @@ gsk_vulkan_linear_gradient_pipeline_collect_vertex_data (GskVulkanLinearGradient
instance->end[0] = end->x + offset->x;
instance->end[1] = end->y + offset->y;
instance->repeating = repeating;
instance->stop_offset = gradient_offset;
instance->offset = gradient_offset;
instance->stop_count = n_stops;
}
+1 -5
View File
@@ -5,8 +5,6 @@
#include "gskvulkanpushconstantsprivate.h"
#include "gskvulkanshaderprivate.h"
#include "gdk/gdkvulkancontextprivate.h"
#include <graphene.h>
typedef struct _GskVulkanPipelinePrivate GskVulkanPipelinePrivate;
@@ -89,7 +87,7 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
priv->vertex_stride = vertex_input_state->pVertexBindingDescriptions[0].stride;
GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
gdk_vulkan_context_get_pipeline_cache (context),
VK_NULL_HANDLE,
1,
&(VkGraphicsPipelineCreateInfo) {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
@@ -162,8 +160,6 @@ gsk_vulkan_pipeline_new (GType pipeline_type,
NULL,
&priv->pipeline);
gdk_vulkan_context_pipeline_cache_updated (context);
return self;
}
+6 -6
View File
@@ -418,12 +418,12 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
{ "texture", 1, gsk_vulkan_color_text_pipeline_new },
{ "texture-clip", 1, gsk_vulkan_color_text_pipeline_new },
{ "texture-clip-rounded", 1, gsk_vulkan_color_text_pipeline_new },
{ "cross-fade", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "cross-fade-clip", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "cross-fade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "blend-mode", 2, gsk_vulkan_blend_mode_pipeline_new },
{ "blend-mode-clip", 2, gsk_vulkan_blend_mode_pipeline_new },
{ "blend-mode-clip-rounded", 2, gsk_vulkan_blend_mode_pipeline_new },
{ "crossfade", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "crossfade-clip", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "crossfade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "blendmode", 2, gsk_vulkan_blend_mode_pipeline_new },
{ "blendmode-clip", 2, gsk_vulkan_blend_mode_pipeline_new },
{ "blendmode-clip-rounded", 2, gsk_vulkan_blend_mode_pipeline_new },
};
g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
-2
View File
@@ -1181,8 +1181,6 @@ static const GskVulkanRenderPassNodeFunc nodes_vtable[] = {
[GSK_GL_SHADER_NODE] = NULL,
[GSK_TEXTURE_SCALE_NODE] = gsk_vulkan_render_pass_add_texture_scale_node,
[GSK_MASK_NODE] = NULL,
[GSK_FILL_NODE] = NULL,
[GSK_STROKE_NODE] = NULL,
};
static void
+54 -5
View File
@@ -2,19 +2,68 @@
#include "gskvulkantextpipelineprivate.h"
#include "vulkan/resources/mask.vert.h"
struct _GskVulkanTextPipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanTextInstance GskVulkanTextInstance;
struct _GskVulkanTextInstance
{
float rect[4];
float tex_rect[4];
float color[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanTextPipeline, gsk_vulkan_text_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_text_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_mask_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanTextInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, color),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanTextInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
@@ -64,7 +113,7 @@ gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
guint num_glyphs,
float scale)
{
GskVulkanMaskInstance *instances = (GskVulkanMaskInstance *) data;
GskVulkanTextInstance *instances = (GskVulkanTextInstance *) data;
int i;
int count = 0;
int x_position = 0;
@@ -80,7 +129,7 @@ gsk_vulkan_text_pipeline_collect_vertex_data (GskVulkanTextPipeline *pipeline,
{
double cx = (x_position + gi->geometry.x_offset) / PANGO_SCALE;
double cy = gi->geometry.y_offset / PANGO_SCALE;
GskVulkanMaskInstance *instance = &instances[count];
GskVulkanTextInstance *instance = &instances[count];
GskVulkanCachedGlyph *glyph;
glyph = gsk_vulkan_renderer_get_cached_glyph (renderer,
+45 -3
View File
@@ -2,19 +2,61 @@
#include "gskvulkantexturepipelineprivate.h"
#include "vulkan/resources/texture.vert.h"
struct _GskVulkanTexturePipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanTextureInstance GskVulkanTextureInstance;
struct _GskVulkanTextureInstance
{
float rect[4];
float tex_rect[4];
guint32 tex_id[2];
};
G_DEFINE_TYPE (GskVulkanTexturePipeline, gsk_vulkan_texture_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_texture_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
return &gsk_vulkan_texture_info;
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanTextureInstance),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}
};
static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
{
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, rect),
},
{
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET (GskVulkanTextureInstance, tex_id),
}
};
static const VkPipelineVertexInputStateCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
.pVertexBindingDescriptions = vertexBindingDescriptions,
.vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
.pVertexAttributeDescriptions = vertexInputAttributeDescription
};
return &info;
}
static void
+14 -12
View File
@@ -3,7 +3,9 @@
#include "clip.vert.glsl"
#include "rounded-rect.glsl"
layout(location = 0) in mat3x4 inRect;
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inCornerWidths;
layout(location = 2) in vec4 inCornerHeights;
layout(location = 3) in vec4 inBorderWidths;
layout(location = 4) in mat4 inBorderColors;
@@ -42,47 +44,47 @@ void main() {
int slice_index = gl_VertexIndex / 6;
int vert_index = gl_VertexIndex % 6;
vec4 corner_widths = max (inRect[1], inBorderWidths.wyyw);
vec4 corner_heights = max (inRect[2], inBorderWidths.xxzz);
vec4 corner_widths = max (inCornerWidths, inBorderWidths.wyyw);
vec4 corner_heights = max (inCornerHeights, inBorderWidths.xxzz);
Rect rect;
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = rect_from_gsk (vec4(inRect[0].xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]));
rect = rect_from_gsk (vec4(inRect.xy, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]));
rect = rect_round_larger (rect);
vert_index = (vert_index + 3) % 6;
break;
case SLICE_TOP:
rect = rect_from_gsk (vec4(inRect[0].x + corner_widths[TOP_LEFT], inRect[0].y, inRect[0].z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]));
rect = rect_from_gsk (vec4(inRect.x + corner_widths[TOP_LEFT], inRect.y, inRect.z - corner_widths[TOP_LEFT] - corner_widths[TOP_RIGHT], inBorderWidths[TOP]));
rect = rect_round_smaller_larger (rect);
outColor = inBorderColors[TOP];
break;
case SLICE_TOP_RIGHT:
rect = rect_from_gsk (vec4(inRect[0].x + inRect[0].z - corner_widths[TOP_RIGHT], inRect[0].y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]));
rect = rect_from_gsk (vec4(inRect.x + inRect.z - corner_widths[TOP_RIGHT], inRect.y, corner_widths[TOP_RIGHT], corner_heights[TOP_RIGHT]));
rect = rect_round_larger (rect);
break;
case SLICE_RIGHT:
rect = rect_from_gsk (vec4(inRect[0].x + inRect[0].z - inBorderWidths[RIGHT], inRect[0].y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect[0].w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]));
rect = rect_from_gsk (vec4(inRect.x + inRect.z - inBorderWidths[RIGHT], inRect.y + corner_heights[TOP_RIGHT], inBorderWidths[RIGHT], inRect.w - corner_heights[TOP_RIGHT] - corner_heights[BOTTOM_RIGHT]));
rect = rect_round_larger_smaller (rect);
outColor = inBorderColors[RIGHT];
break;
case SLICE_BOTTOM_RIGHT:
rect = rect_from_gsk (vec4(inRect[0].x + inRect[0].z - corner_widths[BOTTOM_RIGHT], inRect[0].y + inRect[0].w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]));
rect = rect_from_gsk (vec4(inRect.x + inRect.z - corner_widths[BOTTOM_RIGHT], inRect.y + inRect.w - corner_heights[BOTTOM_RIGHT], corner_widths[BOTTOM_RIGHT], corner_heights[BOTTOM_RIGHT]));
rect = rect_round_larger (rect);
break;
case SLICE_BOTTOM:
rect = rect_from_gsk (vec4(inRect[0].x + corner_widths[BOTTOM_LEFT], inRect[0].y + inRect[0].w - inBorderWidths[BOTTOM], inRect[0].z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]));
rect = rect_from_gsk (vec4(inRect.x + corner_widths[BOTTOM_LEFT], inRect.y + inRect.w - inBorderWidths[BOTTOM], inRect.z - corner_widths[BOTTOM_LEFT] - corner_widths[BOTTOM_RIGHT], inBorderWidths[BOTTOM]));
rect = rect_round_smaller_larger (rect);
break;
case SLICE_BOTTOM_LEFT:
rect = rect_from_gsk (vec4(inRect[0].x, inRect[0].y + inRect[0].w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]));
rect = rect_from_gsk (vec4(inRect.x, inRect.y + inRect.w - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], corner_heights[BOTTOM_LEFT]));
vert_index = (vert_index + 3) % 6;
rect = rect_round_larger (rect);
break;
case SLICE_LEFT:
rect = rect_from_gsk (vec4(inRect[0].x, inRect[0].y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect[0].w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]));
rect = rect_from_gsk (vec4(inRect.x, inRect.y + corner_heights[TOP_LEFT], inBorderWidths[LEFT], inRect.w - corner_heights[TOP_LEFT] - corner_heights[BOTTOM_LEFT]));
rect = rect_round_larger_smaller (rect);
break;
}
@@ -97,7 +99,7 @@ void main() {
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
outColor = inBorderColors[((gl_VertexIndex / 3 + 15) / 4) % 4];
outPos = pos;
outRect = RoundedRect(inRect[0].xyxy + vec4(0,0,inRect[0].zw), inRect[1], inRect[2]);
outRect = RoundedRect(inRect.xyxy + vec4(0,0,inRect.zw), inCornerWidths, inCornerHeights);
outRect = rounded_rect_scale (outRect, push.scale);
outBorderWidths = inBorderWidths * push.scale.yxyx;
}
-192
View File
@@ -1,192 +0,0 @@
#!/usr/bin/env python3
import sys
import re
import os
name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
var_name = "gsk_vulkan_" + name.replace('-', '_')
struct_name = "GskVulkan" + name.title().replace('-', '') + "Instance"
lines = open (sys.argv[1]).readlines()
matches = []
for line in lines:
match = re.search("^layout\(location = ([0-9]+)\) in ([a-z0-9]+) ([a-zA-Z0-9]+);$", line)
if not match:
if re.search("layout.*\sin\s.*", line):
raise Exception("Failed to parse file")
continue;
if not match.group(3).startswith('in'):
raise Exception("Variable doesn't start with 'in'")
matches.append({ 'name': ''.join('_' + char.lower() if char.isupper() else char for char in match.group(3))[3:],
'location': int(match.group(1)),
'type': match.group(2) })
print(
f'''#pragma once
typedef struct _{struct_name} {struct_name};
struct _{struct_name} {{''')
expected = 0;
for match in matches:
if expected != int(match['location']):
raise Exception(f"Should be layout location {expected} but is {match['location']}")
match match['type']:
case "float":
print(f" float {match['name']};")
expected += 1
case "int":
print(f" gint32 {match['name']};")
expected += 1
case "uint":
print(f" guint32 {match['name']};")
expected += 1
case "uvec2":
print(f" guint32 {match['name']}[2];")
expected += 1
case "vec2":
print(f" float {match['name']}[2];")
expected += 1
case "vec4":
print(f" float {match['name']}[4];")
expected += 1
case "mat3x4":
print(f" float {match['name']}[12];")
expected += 3
case "mat4":
print(f" float {match['name']}[16];")
expected += 4
case _:
raise Exception(f"Don't know what a {match['type']} is")
print(
'''};
''')
print(
f'''static const VkPipelineVertexInputStateCreateInfo {var_name}_info = {{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[1]) {{
{{
.binding = 0,
.stride = sizeof ({struct_name}),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
}}
}},
.vertexAttributeDescriptionCount = {expected},
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[{expected}]) {{''')
for match in matches:
match match['type']:
case "float":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},''')
case "int":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32_SINT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},''')
case "uint":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32_UINT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},''')
case "uvec2":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32G32_UINT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},''')
case "vec2":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},''')
case "vec4":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},''')
case "mat3x4":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},
{{
.location = {int(match['location']) + 1},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 4,
}},
{{
.location = {int(match['location']) + 2},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 8,
}},''')
case "mat4":
print(
f''' {{
.location = {match['location']},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
}},
{{
.location = {int(match['location']) + 1},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 4,
}},
{{
.location = {int(match['location']) + 2},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 8,
}},
{{
.location = {int(match['location']) + 3},
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 12,
}},''')
case _:
raise Exception(f"Don't know what a {match['type']} is")
print(" },")
print("};")
+7 -5
View File
@@ -2,7 +2,9 @@
#include "clip.vert.glsl"
layout(location = 0) in mat3x4 inOutline;
layout(location = 0) in vec4 inOutline;
layout(location = 1) in vec4 inOutlineCornerWidths;
layout(location = 2) in vec4 inOutlineCornerHeights;
layout(location = 3) in vec4 inColor;
layout(location = 4) in vec2 inOffset;
layout(location = 5) in float inSpread;
@@ -24,15 +26,15 @@ vec2 offsets[6] = { vec2(0.0, 0.0),
vec2(1.0, 1.0) };
void main() {
vec4 rect = clip (inOutline[0]);
vec4 rect = clip (inOutline);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
outOutline = inOutline[0];
outOutlineCornerWidths = inOutline[1];
outOutlineCornerHeights = inOutline[2];
outOutline = inOutline;
outOutlineCornerWidths = inOutlineCornerWidths;
outOutlineCornerHeights = inOutlineCornerHeights;
outColor = inColor;
outOffset = inOffset;
outSpread = inSpread;
+4 -15
View File
@@ -12,12 +12,12 @@ gsk_private_vulkan_include_shaders = [
]
gsk_private_vulkan_fragment_shaders = [
'blend-mode.frag',
'blendmode.frag',
'blur.frag',
'border.frag',
'color.frag',
'color-matrix.frag',
'cross-fade.frag',
'crossfade.frag',
'inset-shadow.frag',
'linear.frag',
'mask.frag',
@@ -26,12 +26,12 @@ gsk_private_vulkan_fragment_shaders = [
]
gsk_private_vulkan_vertex_shaders = [
'blend-mode.vert',
'blendmode.vert',
'blur.vert',
'border.vert',
'color.vert',
'color-matrix.vert',
'cross-fade.vert',
'crossfade.vert',
'inset-shadow.vert',
'linear.vert',
'mask.vert',
@@ -90,14 +90,3 @@ foreach shader: gsk_private_vulkan_shaders
endif
gsk_private_vulkan_compiled_shaders += files(spv_shader, clip_spv_shader, clip_rounded_spv_shader)
endforeach
foreach shader: gsk_private_vulkan_vertex_shaders
shader_header = configure_file(output: '@0@.h'.format(shader),
input: shader,
command: [
find_program('generate-header.py'),
'@INPUT@',
],
capture: true)
gsk_private_vulkan_shader_headers += shader_header
endforeach
+8 -6
View File
@@ -2,7 +2,9 @@
#include "clip.vert.glsl"
layout(location = 0) in mat3x4 inOutline;
layout(location = 0) in vec4 inOutline;
layout(location = 1) in vec4 inOutlineCornerWidths;
layout(location = 2) in vec4 inOutlineCornerHeights;
layout(location = 3) in vec4 inColor;
layout(location = 4) in vec2 inOffset;
layout(location = 5) in float inSpread;
@@ -29,19 +31,19 @@ float radius_pixels(float radius) {
}
void main() {
vec4 rect = inOutline[0];
vec4 rect = inOutline;
float spread = inSpread + radius_pixels(inBlurRadius);
rect += vec4(inOffset - spread, vec2(2 * spread));
clip (inOutline[0]);
clip (inOutline);
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
gl_Position = push.mvp * vec4 (push.scale * pos, 0.0, 1.0);
outPos = pos;
outOutline = inOutline[0];
outOutlineCornerWidths = inOutline[1];
outOutlineCornerHeights = inOutline[2];
outOutline = inOutline;
outOutlineCornerWidths = inOutlineCornerWidths;
outOutlineCornerHeights = inOutlineCornerHeights;
outColor = inColor;
outOffset = inOffset;
outSpread = inSpread;
+10 -11
View File
@@ -197,9 +197,8 @@ struct _GtkAboutDialog
GtkLicense license_type;
guint hovering_over_link : 1;
guint wrap_license : 1;
guint in_child_changed : 1;
bool hovering_over_link;
bool wrap_license;
};
struct _GtkAboutDialogClass
@@ -724,8 +723,8 @@ gtk_about_dialog_init (GtkAboutDialog *about)
about->documenters = NULL;
about->artists = NULL;
about->hovering_over_link = FALSE;
about->wrap_license = FALSE;
about->hovering_over_link = false;
about->wrap_license = false;
about->license_type = GTK_LICENSE_UNKNOWN;
@@ -1305,11 +1304,11 @@ gtk_about_dialog_set_wrap_license (GtkAboutDialog *about,
{
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
wrap_license = wrap_license != FALSE;
bool wrap = !!wrap_license;
if (about->wrap_license != wrap_license)
if (about->wrap_license != wrap)
{
about->wrap_license = wrap_license;
about->wrap_license = wrap;
g_object_notify_by_pspec (G_OBJECT (about), props[PROP_WRAP_LICENSE]);
}
@@ -1780,7 +1779,7 @@ set_cursor_if_appropriate (GtkAboutDialog *about,
{
GSList *tags = NULL, *tagp = NULL;
GtkTextIter iter;
gboolean hovering_over_link = FALSE;
bool hovering_over_link = false;
gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
@@ -1792,7 +1791,7 @@ set_cursor_if_appropriate (GtkAboutDialog *about,
if (uri != NULL)
{
hovering_over_link = TRUE;
hovering_over_link = true;
break;
}
}
@@ -2273,7 +2272,7 @@ gtk_about_dialog_set_license_type (GtkAboutDialog *about,
g_free (about->license);
about->license = g_string_free (str, FALSE);
about->wrap_license = TRUE;
about->wrap_license = true;
license_string = g_strdup_printf ("<span size=\"small\">%s</span>",
about->license);
+7 -6
View File
@@ -86,10 +86,12 @@ enum {
typedef struct
{
gint16 spacing;
gint16 spacing;
guint homogeneous : 1;
guint baseline_pos : 2;
bool homogeneous;
/* GtkBaselinePosition */
guint baseline_pos : 2;
} GtkBoxPrivate;
static GParamSpec *props[LAST_PROP] = { NULL, };
@@ -369,14 +371,13 @@ void
gtk_box_set_homogeneous (GtkBox *box,
gboolean homogeneous)
{
bool is_homogeneous = !!homogeneous;
GtkBoxLayout *box_layout;
g_return_if_fail (GTK_IS_BOX (box));
homogeneous = !!homogeneous;
box_layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (box)));
if (homogeneous == gtk_box_layout_get_homogeneous (box_layout))
if (is_homogeneous == gtk_box_layout_get_homogeneous (box_layout))
return;
gtk_box_layout_set_homogeneous (box_layout, homogeneous);
+22 -23
View File
@@ -83,18 +83,19 @@
struct _GtkButtonPrivate
{
GtkWidget *child;
GtkWidget *child;
GtkActionHelper *action_helper;
GtkActionHelper *action_helper;
GtkGesture *gesture;
GtkGesture *gesture;
guint activate_timeout;
guint activate_timeout;
guint button_down : 1;
guint use_underline : 1;
guint child_type : 2;
guint can_shrink : 1;
bool button_down;
bool use_underline;
bool can_shrink;
guint child_type : 2;
};
enum {
@@ -353,7 +354,7 @@ click_pressed_cb (GtkGestureClick *gesture,
gtk_widget_grab_focus (widget);
if (!priv->activate_timeout)
priv->button_down = TRUE;
priv->button_down = true;
}
static void
@@ -444,8 +445,8 @@ gtk_button_init (GtkButton *button)
gtk_widget_set_focusable (GTK_WIDGET (button), TRUE);
gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
priv->button_down = FALSE;
priv->use_underline = FALSE;
priv->button_down = false;
priv->use_underline = false;
priv->child_type = WIDGET_CHILD;
priv->gesture = gtk_gesture_click_new ();
@@ -772,7 +773,7 @@ gtk_button_do_release (GtkButton *button,
if (priv->button_down)
{
priv->button_down = FALSE;
priv->button_down = false;
if (priv->activate_timeout)
return;
@@ -811,7 +812,7 @@ gtk_real_button_activate (GtkButton *button)
gdk_source_set_static_name_by_id (priv->activate_timeout, "[gtk] button_activate_timeout");
gtk_widget_add_css_class (GTK_WIDGET (button), "keyboard-activating");
priv->button_down = TRUE;
priv->button_down = true;
}
}
@@ -826,7 +827,7 @@ gtk_button_finish_activate (GtkButton *button,
g_source_remove (priv->activate_timeout);
priv->activate_timeout = 0;
priv->button_down = FALSE;
priv->button_down = false;
if (do_it)
g_signal_emit (button, button_signals[CLICKED], 0);
@@ -918,20 +919,19 @@ gtk_button_set_use_underline (GtkButton *button,
gboolean use_underline)
{
GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
bool underline = !!use_underline;
g_return_if_fail (GTK_IS_BUTTON (button));
use_underline = use_underline != FALSE;
if (use_underline != priv->use_underline)
if (underline != priv->use_underline)
{
if (priv->child_type == LABEL_CHILD)
{
gtk_label_set_use_underline (GTK_LABEL (priv->child), use_underline);
gtk_label_set_use_underline (GTK_LABEL (priv->child), underline);
gtk_label_set_mnemonic_widget (GTK_LABEL (priv->child), GTK_WIDGET (button));
}
priv->use_underline = use_underline;
priv->use_underline = underline;
g_object_notify_by_pspec (G_OBJECT (button), props[PROP_USE_UNDERLINE]);
}
}
@@ -1118,14 +1118,13 @@ gtk_button_set_can_shrink (GtkButton *button,
gboolean can_shrink)
{
GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
bool shrink = !!can_shrink;
g_return_if_fail (GTK_IS_BUTTON (button));
can_shrink = !!can_shrink;
if (priv->can_shrink != can_shrink)
if (priv->can_shrink != shrink)
{
priv->can_shrink = can_shrink;
priv->can_shrink = shrink;
switch (priv->child_type)
{
+25 -41
View File
@@ -202,10 +202,9 @@ struct _GtkCalendar
{
GtkWidget widget;
guint show_week_numbers : 1;
guint show_heading : 1;
guint show_day_names : 1;
guint year_before : 1;
bool show_week_numbers;
bool show_heading;
bool show_day_names;
GtkWidget *header_box;
GtkWidget *year_label;
@@ -219,14 +218,14 @@ struct _GtkCalendar
GDateTime *date;
int day_month[6][7];
int day[6][7];
int day_month[6][7];
int day[6][7];
int num_marked_dates;
int marked_date[31];
int num_marked_dates;
int marked_date[31];
int focus_row;
int focus_col;
int focus_row;
int focus_col;
int week_start;
};
@@ -547,7 +546,6 @@ gtk_calendar_init (GtkCalendar *calendar)
char buffer[255];
time_t tmp_time;
#endif
char *year_before;
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
union { unsigned int word; char *string; } langinfo;
int week_1stday = 0;
@@ -775,12 +773,12 @@ gtk_calendar_init (GtkCalendar *calendar)
gtk_widget_set_vexpand (calendar->grid, TRUE);
gtk_widget_set_parent (calendar->grid, GTK_WIDGET (calendar));
for (i=0;i<31;i++)
for (i = 0; i < 31; i++)
calendar->marked_date[i] = FALSE;
calendar->num_marked_dates = 0;
calendar->show_heading = TRUE;
calendar->show_day_names = TRUE;
calendar->show_heading = true;
calendar->show_day_names = true;
calendar->focus_row = -1;
calendar->focus_col = -1;
@@ -791,24 +789,6 @@ gtk_calendar_init (GtkCalendar *calendar)
g_signal_connect (target, "drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (target));
calendar->year_before = 0;
/* Translate to calendar:YM if you want years to be displayed
* before months; otherwise translate to calendar:MY.
* Do *not* translate it to anything else, if it
* it isn't calendar:YM or calendar:MY it will not work.
*
* Note that the ordering described here is logical order, which is
* further influenced by BIDI ordering. Thus, if you have a default
* text direction of RTL and specify "calendar:YM", then the year
* will appear to the right of the month.
*/
year_before = _("calendar:MY");
if (strcmp (year_before, "calendar:YM") == 0)
calendar->year_before = 1;
else if (strcmp (year_before, "calendar:MY") != 0)
g_warning ("Whoever translated calendar:MY did so wrongly.");
gtk_orientable_set_orientation (GTK_ORIENTABLE (gtk_widget_get_layout_manager (GTK_WIDGET (calendar))),
GTK_ORIENTATION_VERTICAL);
@@ -1657,17 +1637,18 @@ void
gtk_calendar_set_show_week_numbers (GtkCalendar *self,
gboolean value)
{
bool show_week_numbers = !!value;
int i;
g_return_if_fail (GTK_IS_CALENDAR (self));
if (self->show_week_numbers == value)
if (self->show_week_numbers == show_week_numbers)
return;
self->show_week_numbers = value;
self->show_week_numbers = show_week_numbers;
for (i = 0; i < 6; i ++)
gtk_widget_set_visible (self->week_number_labels[i], value);
gtk_widget_set_visible (self->week_number_labels[i], show_week_numbers);
g_object_notify (G_OBJECT (self), "show-week-numbers");
}
@@ -1706,14 +1687,16 @@ void
gtk_calendar_set_show_heading (GtkCalendar *self,
gboolean value)
{
bool show_heading = !!value;
g_return_if_fail (GTK_IS_CALENDAR (self));
if (self->show_heading == value)
if (self->show_heading == show_heading)
return;
self->show_heading = value;
self->show_heading = show_heading;
gtk_widget_set_visible (self->header_box, value);
gtk_widget_set_visible (self->header_box, show_heading);
g_object_notify (G_OBJECT (self), "show-heading");
}
@@ -1748,17 +1731,18 @@ void
gtk_calendar_set_show_day_names (GtkCalendar *self,
gboolean value)
{
bool show_day_names = !!value;
int i;
g_return_if_fail (GTK_IS_CALENDAR (self));
if (self->show_day_names == value)
if (self->show_day_names == show_day_names)
return;
self->show_day_names = value;
self->show_day_names = show_day_names;
for (i = 0; i < 7; i ++)
gtk_widget_set_visible (self->day_name_labels[i], value);
gtk_widget_set_visible (self->day_name_labels[i], show_day_names);
g_object_notify (G_OBJECT (self), "show-day-names");
}
+16 -17
View File
@@ -103,10 +103,11 @@ typedef struct {
GtkWidget *indicator_widget;
GtkWidget *child;
guint inconsistent: 1;
guint active: 1;
guint use_underline: 1;
guint child_type: 1;
bool inconsistent;
bool active;
bool use_underline;
guint child_type : 1;
GtkCheckButton *group_next;
GtkCheckButton *group_prev;
@@ -790,13 +791,13 @@ gtk_check_button_set_inconsistent (GtkCheckButton *check_button,
gboolean inconsistent)
{
GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (check_button);
bool is_inconsistent = !!inconsistent;
g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button));
inconsistent = !!inconsistent;
if (priv->inconsistent != inconsistent)
if (priv->inconsistent != is_inconsistent)
{
priv->inconsistent = inconsistent;
priv->inconsistent = is_inconsistent;
if (inconsistent)
{
@@ -863,15 +864,14 @@ gtk_check_button_set_active (GtkCheckButton *self,
gboolean setting)
{
GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);
bool is_active = !!setting;
g_return_if_fail (GTK_IS_CHECK_BUTTON (self));
setting = !!setting;
if (setting == priv->active)
if (is_active == priv->active)
return;
if (setting)
if (is_active)
{
gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED, FALSE);
gtk_widget_set_state_flags (priv->indicator_widget, GTK_STATE_FLAG_CHECKED, FALSE);
@@ -882,7 +882,7 @@ gtk_check_button_set_active (GtkCheckButton *self,
gtk_widget_unset_state_flags (priv->indicator_widget, GTK_STATE_FLAG_CHECKED);
}
if (setting && (priv->group_prev || priv->group_next))
if (is_active && (priv->group_prev || priv->group_next))
{
GtkCheckButton *group_first = NULL;
GtkCheckButton *iter;
@@ -897,7 +897,7 @@ gtk_check_button_set_active (GtkCheckButton *self,
/* ... and the next code block will set this one to active */
}
priv->active = setting;
priv->active = is_active;
update_accessible_state (self);
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]);
g_signal_emit (self, signals[TOGGLED], 0);
@@ -1095,15 +1095,14 @@ gtk_check_button_set_use_underline (GtkCheckButton *self,
gboolean setting)
{
GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);
bool use_underline = !!setting;
g_return_if_fail (GTK_IS_CHECK_BUTTON (self));
setting = !!setting;
if (setting == priv->use_underline)
if (use_underline == priv->use_underline)
return;
priv->use_underline = setting;
priv->use_underline = use_underline;
if (priv->child_type == LABEL_CHILD && priv->child != NULL)
gtk_label_set_use_underline (GTK_LABEL (priv->child), priv->use_underline);
+8 -8
View File
@@ -76,8 +76,8 @@ struct _GtkColorEditor
int popup_position;
guint text_changed : 1;
guint use_alpha : 1;
bool text_changed;
bool use_alpha;
};
struct _GtkColorEditorClass
@@ -118,7 +118,7 @@ entry_set_rgba (GtkColorEditor *editor,
scale_round (color->green, 255),
scale_round (color->blue, 255));
gtk_editable_set_text (GTK_EDITABLE (editor->entry), text);
editor->text_changed = FALSE;
editor->text_changed = false;
g_free (text);
}
@@ -139,7 +139,7 @@ entry_apply (GtkWidget *entry,
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), &color);
}
editor->text_changed = FALSE;
editor->text_changed = false;
g_free (text);
}
@@ -158,7 +158,7 @@ entry_text_changed (GtkWidget *entry,
GParamSpec *pspec,
GtkColorEditor *editor)
{
editor->text_changed = TRUE;
editor->text_changed = true;
}
static void
@@ -409,7 +409,7 @@ gtk_color_editor_init (GtkColorEditor *editor)
{
GtkEventController *controller;
editor->use_alpha = TRUE;
editor->use_alpha = true;
g_type_ensure (GTK_TYPE_COLOR_SCALE);
g_type_ensure (GTK_TYPE_COLOR_PLANE);
@@ -489,7 +489,7 @@ gtk_color_editor_get_property (GObject *object,
static void
gtk_color_editor_set_use_alpha (GtkColorEditor *editor,
gboolean use_alpha)
bool use_alpha)
{
if (editor->use_alpha != use_alpha)
{
@@ -573,7 +573,7 @@ gtk_color_editor_class_init (GtkColorEditorClass *class)
* @component: the component to edit, "h", "sv" or "a"
*
* Opens the edit popup for one of the color components.
*/
*/
gtk_widget_class_install_action (widget_class, "color.edit", "s", popup_edit);
}
+18 -11
View File
@@ -55,10 +55,11 @@ struct _GtkColorSwatch
GdkRGBA color;
char *icon;
guint has_color : 1;
guint use_alpha : 1;
guint selectable : 1;
guint has_menu : 1;
bool has_color;
bool use_alpha;
bool has_menu;
bool selectable;
GtkWidget *overlay_widget;
@@ -549,9 +550,9 @@ gtk_color_swatch_init (GtkColorSwatch *swatch)
GtkEventController *controller;
GtkGesture *gesture;
swatch->use_alpha = TRUE;
swatch->selectable = TRUE;
swatch->has_menu = TRUE;
swatch->use_alpha = true;
swatch->selectable = true;
swatch->has_menu = true;
swatch->color.red = 0.75;
swatch->color.green = 0.25;
swatch->color.blue = 0.25;
@@ -610,7 +611,7 @@ void
gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
const GdkRGBA *color)
{
swatch->has_color = TRUE;
swatch->has_color = true;
swatch->color = *color;
if (swatch->source)
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (swatch->source), GTK_PHASE_CAPTURE);
@@ -711,21 +712,27 @@ gtk_color_swatch_set_can_drag (GtkColorSwatch *swatch,
void
gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
gboolean use_alpha)
gboolean value)
{
bool use_alpha = !!value;
if (use_alpha == swatch->use_alpha)
return;
swatch->use_alpha = use_alpha;
gtk_widget_queue_draw (GTK_WIDGET (swatch));
}
void
gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
gboolean selectable)
gboolean value)
{
bool selectable = !!value;
if (selectable == swatch->selectable)
return;
swatch->selectable = selectable;
update_accessible_properties (swatch);
g_object_notify (G_OBJECT (swatch), "selectable");
}
+3 -90
View File
@@ -44,7 +44,6 @@
#include "gtkbuilderprivate.h"
#include "gtkstringlist.h"
#include "gtkbox.h"
#include "gtktypebuiltins.h"
/**
* GtkDropDown:
@@ -105,8 +104,6 @@ struct _GtkDropDown
{
GtkWidget parent_instance;
gboolean uses_default_factory;
gboolean uses_default_list_factory;
GtkListItemFactory *factory;
GtkListItemFactory *list_factory;
GtkListItemFactory *header_factory;
@@ -127,8 +124,6 @@ struct _GtkDropDown
GtkWidget *search_entry;
GtkExpression *expression;
GtkStringFilterMatchMode search_match_mode;
guint enable_search : 1;
guint show_arrow : 1;
@@ -151,7 +146,6 @@ enum
PROP_ENABLE_SEARCH,
PROP_EXPRESSION,
PROP_SHOW_ARROW,
PROP_SEARCH_MATCH_MODE,
N_PROPS
};
@@ -285,7 +279,7 @@ update_filter (GtkDropDown *self)
if (self->expression)
{
filter = GTK_FILTER (gtk_string_filter_new (gtk_expression_ref (self->expression)));
gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter), self->search_match_mode);
gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter), GTK_STRING_FILTER_MATCH_MODE_PREFIX);
}
else
filter = GTK_FILTER (gtk_every_filter_new ());
@@ -394,10 +388,6 @@ gtk_drop_down_get_property (GObject *object,
case PROP_SHOW_ARROW:
g_value_set_boolean (value, gtk_drop_down_get_show_arrow (self));
break;
case PROP_SEARCH_MATCH_MODE:
g_value_set_enum (value, gtk_drop_down_get_search_match_mode (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -446,11 +436,6 @@ gtk_drop_down_set_property (GObject *object,
case PROP_SHOW_ARROW:
gtk_drop_down_set_show_arrow (self, g_value_get_boolean (value));
break;
case PROP_SEARCH_MATCH_MODE:
gtk_drop_down_set_search_match_mode (self, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -656,20 +641,7 @@ gtk_drop_down_class_init (GtkDropDownClass *klass)
g_param_spec_boolean ("show-arrow", NULL, NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GtkDropDown:search-match-mode: (attributes org.gtk.Property.get=gtk_drop_down_get_search_match_mode org.gtk.Property.set=gtk_drop_down_set_search_match_mode)
*
* The match mode for the search filter.
*
* Since: 4.12
*/
properties[PROP_SEARCH_MATCH_MODE] =
g_param_spec_enum ("search-match-mode", NULL, NULL,
GTK_TYPE_STRING_FILTER_MATCH_MODE,
GTK_STRING_FILTER_MATCH_MODE_PREFIX,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
/**
@@ -822,10 +794,6 @@ set_default_factory (GtkDropDown *self)
g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item), self);
gtk_drop_down_set_factory (self, factory);
self->uses_default_factory = TRUE;
if (self->uses_default_list_factory)
gtk_drop_down_set_list_factory (self, NULL);
g_object_unref (factory);
}
@@ -841,8 +809,6 @@ gtk_drop_down_init (GtkDropDown *self)
self->show_arrow = gtk_widget_get_visible (self->arrow);
set_default_factory (self);
self->search_match_mode = GTK_STRING_FILTER_MATCH_MODE_PREFIX;
}
/**
@@ -1006,12 +972,7 @@ gtk_drop_down_set_factory (GtkDropDown *self,
gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (self->button_item), factory);
if (self->list_factory == NULL)
{
gtk_list_view_set_factory (GTK_LIST_VIEW (self->popup_list), factory);
self->uses_default_list_factory = TRUE;
}
self->uses_default_factory = factory != NULL;
gtk_list_view_set_factory (GTK_LIST_VIEW (self->popup_list), factory);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
}
@@ -1096,8 +1057,6 @@ gtk_drop_down_set_list_factory (GtkDropDown *self,
else
gtk_list_view_set_factory (GTK_LIST_VIEW (self->popup_list), self->factory);
self->uses_default_list_factory = factory != NULL;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LIST_FACTORY]);
}
@@ -1235,9 +1194,6 @@ gtk_drop_down_set_expression (GtkDropDown *self,
if (self->expression)
gtk_expression_ref (self->expression);
if (self->uses_default_factory)
set_default_factory (self);
update_filter (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPRESSION]);
@@ -1304,46 +1260,3 @@ gtk_drop_down_get_show_arrow (GtkDropDown *self)
return self->show_arrow;
}
/**
* gtk_drop_down_set_search_match_mode: (attributes org.gtk.Method.set_property=search-match-mode)
* @self: a `GtkDropDown`
* @search_match_mode: the new match mode
*
* Sets the match mode for the search filter.
*
* Since: 4.12
*/
void
gtk_drop_down_set_search_match_mode (GtkDropDown *self,
GtkStringFilterMatchMode search_match_mode)
{
g_return_if_fail (GTK_IS_DROP_DOWN (self));
if (self->search_match_mode == search_match_mode)
return;
self->search_match_mode = search_match_mode;
update_filter (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_MATCH_MODE]);
}
/**
* gtk_drop_down_get_search_match_mode: (attributes org.gtk.Method.get_property=search-match-mode)
* @self: a `GtkDropDown`
*
* Returns the match mode that the search filter is using.
*
* Returns: the match mode of the search filter
*
* Since: 4.12
*/
GtkStringFilterMatchMode
gtk_drop_down_get_search_match_mode (GtkDropDown *self)
{
g_return_val_if_fail (GTK_IS_DROP_DOWN (self), GTK_STRING_FILTER_MATCH_MODE_PREFIX);
return self->search_match_mode;
}
-9
View File
@@ -21,7 +21,6 @@
#include <gtk/gtkwidget.h>
#include <gtk/gtkexpression.h>
#include "gtk/gtkstringfilter.h"
G_BEGIN_DECLS
@@ -84,19 +83,11 @@ void gtk_drop_down_set_enable_search (GtkDropDown
gboolean enable_search);
GDK_AVAILABLE_IN_ALL
gboolean gtk_drop_down_get_enable_search (GtkDropDown *self);
GDK_AVAILABLE_IN_4_6
void gtk_drop_down_set_show_arrow (GtkDropDown *self,
gboolean show_arrow);
GDK_AVAILABLE_IN_4_6
gboolean gtk_drop_down_get_show_arrow (GtkDropDown *self);
GDK_AVAILABLE_IN_4_12
void gtk_drop_down_set_search_match_mode (GtkDropDown *self,
GtkStringFilterMatchMode search_match_mode);
GDK_AVAILABLE_IN_4_12
GtkStringFilterMatchMode
gtk_drop_down_get_search_match_mode (GtkDropDown *self);
G_END_DECLS
+7 -14
View File
@@ -507,19 +507,13 @@ gtk_drop_target_handle_crossing (GtkEventController *controller,
graphene_point_init (&self->coords, x, y);
gtk_drop_target_start_drop (self, crossing->drop);
/* start_drop ends w/ thaw_notify, where handler may reject, so recheck */
if (self->drop != NULL)
g_signal_emit (self, signals[ENTER], 0, x, y, &preferred);
else
preferred = 0;
if (!gdk_drag_action_is_unique (preferred))
{
g_critical ("Handler for GtkDropTarget::enter on %s %p did not return a unique preferred action",
G_OBJECT_TYPE_NAME (widget), widget);
preferred = make_action_unique (preferred);
}
g_signal_emit (self, signals[ENTER], 0, x, y, &preferred);
if (!gdk_drag_action_is_unique (preferred))
{
g_critical ("Handler for GtkDropTarget::enter on %s %p did not return a unique preferred action",
G_OBJECT_TYPE_NAME (widget), widget);
preferred = make_action_unique (preferred);
}
if (preferred &&
gtk_drop_status (self->drop, self->actions, preferred))
{
@@ -539,7 +533,6 @@ gtk_drop_target_handle_crossing (GtkEventController *controller,
g_signal_emit (self, signals[LEAVE], 0);
if (!self->dropping)
gtk_drop_target_end_drop (self);
gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
}
}
+1 -1
View File
@@ -181,7 +181,7 @@ gtk_image_class_init (GtkImageClass *class)
/**
* GtkImage:file: (attributes org.gtk.Property.set=gtk_image_set_from_file)
*
* The `GFile` to display.
* The `GFile to display.
*/
image_props[PROP_FILE] =
g_param_spec_string ("file", NULL, NULL,
-138
View File
@@ -30,7 +30,6 @@
#include "gsk/gskrendernodeprivate.h"
#include "gsk/gskroundedrectprivate.h"
#include "gsk/gskstrokeprivate.h"
#include "gtk/gskpangoprivate.h"
@@ -106,14 +105,6 @@ struct _GtkSnapshotState {
struct {
GskRoundedRect bounds;
} rounded_clip;
struct {
GskPath *path;
GskFillRule fill_rule;
} fill;
struct {
GskPath *path;
GskStroke stroke;
} stroke;
struct {
gsize n_shadows;
GskShadow *shadows;
@@ -1105,135 +1096,6 @@ gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot,
gsk_rounded_rect_scale_affine (&state->data.rounded_clip.bounds, bounds, scale_x, scale_y, dx, dy);
}
static GskRenderNode *
gtk_snapshot_collect_fill (GtkSnapshot *snapshot,
GtkSnapshotState *state,
GskRenderNode **nodes,
guint n_nodes)
{
GskRenderNode *node, *fill_node;
node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
if (node == NULL)
return NULL;
fill_node = gsk_fill_node_new (node,
state->data.fill.path,
state->data.fill.fill_rule);
if (fill_node->bounds.size.width == 0 ||
fill_node->bounds.size.height == 0)
{
gsk_render_node_unref (node);
gsk_render_node_unref (fill_node);
return NULL;
}
gsk_render_node_unref (node);
return fill_node;
}
static void
gtk_snapshot_clear_fill (GtkSnapshotState *state)
{
gsk_path_unref (state->data.fill.path);
}
/**
* gtk_snapshot_push_fill:
* @snapshot: a #GtkSnapshot
* @path: The path describing the area to fill
* @fill_rule: The fill rule to use
*
* Fills the area given by @path and @fill_rule with an image and discards everything
* outside of it.
*
* The image is recorded until the next call to gtk_snapshot_pop().
*/
void
gtk_snapshot_push_fill (GtkSnapshot *snapshot,
GskPath *path,
GskFillRule fill_rule)
{
GtkSnapshotState *state;
/* FIXME: Is it worth calling ensure_affine() and transforming the path here? */
gtk_snapshot_ensure_identity (snapshot);
state = gtk_snapshot_push_state (snapshot,
gtk_snapshot_get_current_state (snapshot)->transform,
gtk_snapshot_collect_fill,
gtk_snapshot_clear_fill);
state->data.fill.path = gsk_path_ref (path);
state->data.fill.fill_rule = fill_rule;
}
static GskRenderNode *
gtk_snapshot_collect_stroke (GtkSnapshot *snapshot,
GtkSnapshotState *state,
GskRenderNode **nodes,
guint n_nodes)
{
GskRenderNode *node, *stroke_node;
node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
if (node == NULL)
return NULL;
stroke_node = gsk_stroke_node_new (node,
state->data.stroke.path,
&state->data.stroke.stroke);
if (stroke_node->bounds.size.width == 0 ||
stroke_node->bounds.size.height == 0)
{
gsk_render_node_unref (node);
gsk_render_node_unref (stroke_node);
return NULL;
}
gsk_render_node_unref (node);
return stroke_node;
}
static void
gtk_snapshot_clear_stroke (GtkSnapshotState *state)
{
gsk_path_unref (state->data.stroke.path);
gsk_stroke_clear (&state->data.stroke.stroke);
}
/**
* gtk_snapshot_push_stroke:
* @snapshot: a #GtkSnapshot
* @path: The path to stroke
* @stroke: The stroke attributes
*
* Strokes the given @path with the attributes given by @stroke and the
* image being recorded until the next call to gtk_snapshot_pop().
*/
void
gtk_snapshot_push_stroke (GtkSnapshot *snapshot,
GskPath *path,
const GskStroke *stroke)
{
GtkSnapshotState *state;
/* FIXME: Is it worth calling ensure_affine() and transforming the path here? */
gtk_snapshot_ensure_identity (snapshot);
state = gtk_snapshot_push_state (snapshot,
gtk_snapshot_get_current_state (snapshot)->transform,
gtk_snapshot_collect_stroke,
gtk_snapshot_clear_stroke);
state->data.stroke.path = gsk_path_ref (path);
gsk_stroke_init_copy (&state->data.stroke.stroke, stroke);
}
static GskRenderNode *
gtk_snapshot_collect_shadow (GtkSnapshot *snapshot,
GtkSnapshotState *state,
-8
View File
@@ -88,14 +88,6 @@ GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot,
const GskRoundedRect *bounds);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_fill (GtkSnapshot *snapshot,
GskPath *path,
GskFillRule fill_rule);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_stroke (GtkSnapshot *snapshot,
GskPath *path,
const GskStroke *stroke);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_shadow (GtkSnapshot *snapshot,
const GskShadow *shadow,
gsize n_shadows);
+10 -10
View File
@@ -33,10 +33,10 @@ struct _GtkTrashMonitor
GFileMonitor *file_monitor;
gulong file_monitor_changed_id;
gboolean pending;
bool pending;
int timeout_id;
guint has_trash : 1;
bool has_trash;
};
struct _GtkTrashMonitorClass
@@ -104,14 +104,14 @@ _gtk_trash_monitor_class_init (GtkTrashMonitorClass *class)
/* Updates the internal has_trash flag and emits the "trash-state-changed" signal */
static void
update_has_trash_and_notify (GtkTrashMonitor *monitor,
gboolean has_trash)
bool has_trash)
{
if (monitor->has_trash == !!has_trash)
if (monitor->has_trash == has_trash)
return;
monitor->has_trash = !!has_trash;
monitor->has_trash = has_trash;
g_signal_emit (monitor, signals[TRASH_STATE_CHANGED], 0);
g_signal_emit (monitor, signals[TRASH_STATE_CHANGED], 0);
}
/* Use G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT since we only want to know whether the
@@ -127,7 +127,7 @@ trash_query_info_cb (GObject *source,
GtkTrashMonitor *monitor = GTK_TRASH_MONITOR (user_data);
GFileInfo *info;
guint32 item_count;
gboolean has_trash = FALSE;
bool has_trash = false;
info = g_file_query_info_finish (G_FILE (source), result, NULL);
@@ -155,7 +155,7 @@ recompute_trash_state_cb (gpointer data)
monitor->timeout_id = 0;
if (monitor->pending)
{
monitor->pending = FALSE;
monitor->pending = false;
recompute_trash_state (monitor);
}
@@ -173,7 +173,7 @@ recompute_trash_state (GtkTrashMonitor *monitor)
*/
if (monitor->timeout_id > 0)
{
monitor->pending = TRUE;
monitor->pending = true;
return;
}
@@ -213,7 +213,7 @@ _gtk_trash_monitor_init (GtkTrashMonitor *monitor)
file = g_file_new_for_uri ("trash:///");
monitor->file_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
monitor->pending = FALSE;
monitor->pending = false;
monitor->timeout_id = 0;
g_object_unref (file);
+3 -60
View File
@@ -298,12 +298,6 @@ create_list_model_for_render_node (GskRenderNode *node)
case GSK_ROUNDED_CLIP_NODE:
return create_render_node_list_model ((GskRenderNode *[1]) { gsk_rounded_clip_node_get_child (node) }, 1);
case GSK_FILL_NODE:
return create_render_node_list_model ((GskRenderNode *[1]) { gsk_fill_node_get_child (node) }, 1);
case GSK_STROKE_NODE:
return create_render_node_list_model ((GskRenderNode *[1]) { gsk_stroke_node_get_child (node) }, 1);
case GSK_SHADOW_NODE:
return create_render_node_list_model ((GskRenderNode *[1]) { gsk_shadow_node_get_child (node) }, 1);
@@ -431,10 +425,6 @@ node_type_name (GskRenderNodeType type)
return "Clip";
case GSK_ROUNDED_CLIP_NODE:
return "Rounded Clip";
case GSK_FILL_NODE:
return "Fill";
case GSK_STROKE_NODE:
return "Stroke";
case GSK_SHADOW_NODE:
return "Shadow";
case GSK_BLEND_NODE:
@@ -476,8 +466,6 @@ node_name (GskRenderNode *node)
case GSK_REPEAT_NODE:
case GSK_CLIP_NODE:
case GSK_ROUNDED_CLIP_NODE:
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_MASK_NODE:
@@ -906,20 +894,6 @@ add_float_row (GListStore *store,
g_free (text);
}
static const char *
enum_to_nick (GType type,
int value)
{
GEnumClass *class;
GEnumValue *v;
class = g_type_class_ref (type);
v = g_enum_get_value (class, value);
g_type_class_unref (class);
return v->value_nick;
}
static void
populate_render_node_properties (GListStore *store,
GskRenderNode *node)
@@ -1159,7 +1133,9 @@ populate_render_node_properties (GListStore *store,
case GSK_BLEND_NODE:
{
GskBlendMode mode = gsk_blend_node_get_blend_mode (node);
add_text_row (store, "Blendmode", enum_to_nick (GSK_TYPE_BLEND_MODE, mode));
tmp = g_enum_to_string (GSK_TYPE_BLEND_MODE, mode);
add_text_row (store, "Blendmode", tmp);
g_free (tmp);
}
break;
@@ -1401,39 +1377,6 @@ populate_render_node_properties (GListStore *store,
}
break;
case GSK_FILL_NODE:
{
GskPath *path = gsk_fill_node_get_path (node);
GskFillRule fill_rule = gsk_fill_node_get_fill_rule (node);
tmp = gsk_path_to_string (path);
add_text_row (store, "Path", tmp);
g_free (tmp);
add_text_row (store, "Fill rule", enum_to_nick (GSK_TYPE_FILL_RULE, fill_rule));
}
break;
case GSK_STROKE_NODE:
{
GskPath *path = gsk_stroke_node_get_path (node);
const GskStroke *stroke = gsk_stroke_node_get_stroke (node);
GskLineCap line_cap = gsk_stroke_get_line_cap (stroke);
GskLineJoin line_join = gsk_stroke_get_line_join (stroke);
tmp = gsk_path_to_string (path);
add_text_row (store, "Path", tmp);
g_free (tmp);
tmp = g_strdup_printf ("%.2f", gsk_stroke_get_line_width (stroke));
add_text_row (store, "Line width", tmp);
g_free (tmp);
add_text_row (store, "Line cap", enum_to_nick (GSK_TYPE_LINE_CAP, line_cap));
add_text_row (store, "Line join", enum_to_nick (GSK_TYPE_LINE_JOIN, line_join));
}
break;
case GSK_CONTAINER_NODE:
tmp = g_strdup_printf ("%d", gsk_container_node_get_n_children (node));
add_text_row (store, "Children", tmp);
+11 -1
View File
@@ -758,7 +758,17 @@ if not fs.exists('theme/Default/Default-light.css')
endif
if can_use_objcopy_for_resources
objcopy_supports_add_symbol = false
objcopy = find_program('objcopy', required : false)
if objcopy.found()
objcopy_supports_add_symbol = run_command(objcopy, '--help', check: false).stdout().contains('--add-symbol')
endif
ld = find_program('ld', required : false)
if not meson.is_cross_build() and build_machine.cpu_family() == 'x86_64' and build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found()
glib_compile_resources = find_program('glib-compile-resources')
# Create the resource blob
gtk_gresource = custom_target('gtk.gresource',
input : gtk_gresources_xml,
-1
View File
@@ -8,4 +8,3 @@ leak:libgio-2.0.so
leak:libcairo.so
leak:libpixman-1.so
leak:librsvg-2.so
leak:libxkbcommon.so
-21
View File
@@ -737,27 +737,6 @@ endif
build_gir = gir.found() and (get_option('introspection').enabled() or
(get_option('introspection').allowed() and get_option('gtk_doc')))
# Resource building
glib_compile_resources = find_program('glib-compile-resources')
objcopy_supports_add_symbol = false
objcopy = find_program('objcopy', required : false)
if objcopy.found()
objcopy_supports_add_symbol = run_command(objcopy, '--help', check: false).stdout().contains('--add-symbol')
endif
ld_is_bfd = false
ld = find_program('ld', required : false)
if ld.found()
ld_is_bfd = run_command(ld, '--version', check: false).stdout().contains('GNU ld')
endif
if not meson.is_cross_build() and build_machine.cpu_family() == 'x86_64' and build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found() and ld_is_bfd
can_use_objcopy_for_resources = true
else
can_use_objcopy_for_resources = false
endif
project_build_root = meson.current_build_dir()
gen_visibility_macros = find_program('build-aux/meson/gen-visibility-macros.py')
+2 -10
View File
@@ -298,12 +298,8 @@ main (int argc, char **argv)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
GskTransform *transform;
transform = gsk_transform_scale (NULL, -1, 1);
node2 = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
node2 = gsk_transform_node_new (node, gsk_transform_scale (NULL, -1, 1));
save_node (node2, node_file, "-flipped.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
@@ -408,12 +404,8 @@ main (int argc, char **argv)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
GskTransform *transform;
transform = gsk_transform_rotate (NULL, 90);
node2 = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
node2 = gsk_transform_node_new (node, gsk_transform_rotate (NULL, 90));
save_node (node2, node_file, "-rotated.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
-2
View File
@@ -355,8 +355,6 @@ foreach test : node_parser_tests
endforeach
tests = [
['path'],
['path-special-cases'],
['transform'],
['shader'],
]
-319
View File
@@ -1,319 +0,0 @@
/*
* Copyright © 2020 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 <gtk/gtk.h>
/* testcases from path_parser.rs in librsvg */
static void
test_rsvg_parse (void)
{
struct {
const char *in;
const char *out;
} tests[] = {
{ "", "" },
// numbers
{ "M 10 20", "M 10 20" },
{ "M -10 -20", "M -10 -20" },
{ "M .10 0.20", "M 0.1 0.2" },
{ "M -.10 -0.20", "M -0.1 -0.2" },
{ "M-.10-0.20", "M -0.1 -0.2" },
{ "M10.5.50", "M 10.5 0.5" },
{ "M.10.20", "M 0.1 0.2" },
{ "M .10E1 .20e-4", "M 1 2e-05" },
{ "M-.10E1-.20", "M -1 -0.2" },
{ "M10.10E2 -0.20e3", "M 1010 -200" },
{ "M-10.10E2-0.20e-3", "M -1010 -0.0002" },
{ "M1e2.5", "M 100 0.5" },
{ "M1e-2.5", "M 0.01 0.5" },
{ "M1e+2.5", "M 100 0.5" },
// bogus numbers
{ "M+", NULL },
{ "M-", NULL },
{ "M+x", NULL },
{ "M10e", NULL },
{ "M10ex", NULL },
{ "M10e-", NULL },
{ "M10e+x", NULL },
// numbers with comma
{ "M 10, 20", "M 10 20" },
{ "M -10,-20", "M -10 -20" },
{ "M.10 , 0.20", "M 0.1 0.2" },
{ "M -.10, -0.20 ", "M -0.1 -0.2" },
{ "M-.10-0.20", "M -0.1 -0.2" },
{ "M.10.20", "M 0.1 0.2" },
{ "M .10E1,.20e-4", "M 1 2e-05" },
{ "M-.10E-2,-.20", "M -0.001 -0.2" },
{ "M10.10E2,-0.20e3", "M 1010 -200" },
{ "M-10.10E2,-0.20e-3", "M -1010 -0.0002" },
// single moveto
{ "M 10 20 ", "M 10 20" },
{ "M10,20 ", "M 10 20" },
{ "M10 20 ", "M 10 20" },
{ " M10,20 ", "M 10 20" },
// relative moveto
{ "m10 20", "M 10 20" },
// absolute moveto with implicit lineto
{ "M10 20 30 40", "M 10 20 L 30 40" },
{ "M10,20,30,40", "M 10 20 L 30 40" },
{ "M.1-2,3E2-4", "M 0.1 -2 L 300 -4" },
// relative moveto with implicit lineto
{ "m10 20 30 40", "M 10 20 L 40 60" },
// relative moveto with relative lineto sequence
{ "m 46,447 l 0,0.5 -1,0 -1,0 0,1 0,12",
"M 46 447 L 46 447.5 L 45 447.5 L 44 447.5 L 44 448.5 L 44 460.5" },
// absolute moveto with implicit linetos
{ "M10,20 30,40,50 60", "M 10 20 L 30 40 L 50 60" },
// relative moveto with implicit linetos
{ "m10 20 30 40 50 60", "M 10 20 L 40 60 L 90 120" },
// absolute moveto moveto
{ "M10 20 M 30 40", "M 10 20 M 30 40" },
// relative moveto moveto
{ "m10 20 m 30 40", "M 10 20 M 40 60" },
// relative moveto lineto moveto
{ "m10 20 30 40 m 50 60", "M 10 20 L 40 60 M 90 120" },
// absolute moveto lineto
{ "M10 20 L30,40", "M 10 20 L 30 40" },
// relative moveto lineto
{ "m10 20 l30,40", "M 10 20 L 40 60" },
// relative moveto lineto lineto abs lineto
{ "m10 20 30 40l30,40,50 60L200,300",
"M 10 20 L 40 60 L 70 100 L 120 160 L 200 300" },
// horizontal lineto
{ "M10 20 H30", "M 10 20 L 30 20" },
{ "M 10 20 H 30 40", "M 10 20 L 30 20 L 40 20" },
{ "M10 20 H30,40-50", "M 10 20 L 30 20 L 40 20 L -50 20" },
{ "m10 20 h30,40-50", "M 10 20 L 40 20 L 80 20 L 30 20" },
// vertical lineto
{ "M10 20 V30", "M 10 20 L 10 30" },
{ "M10 20 V30 40", "M 10 20 L 10 30 L 10 40" },
{ "M10 20 V30,40-50", "M 10 20 L 10 30 L 10 40 L 10 -50" },
{ "m10 20 v30,40-50", "M 10 20 L 10 50 L 10 90 L 10 40" },
// curveto
{ "M10 20 C 30,40 50 60-70,80", "M 10 20 C 30 40, 50 60, -70 80" },
{ "M10 20 C 30,40 50 60-70,80,90 100,110 120,130,140",
"M 10 20 C 30 40, 50 60, -70 80 C 90 100, 110 120, 130 140" },
{ "m10 20 c 30,40 50 60-70,80,90 100,110 120,130,140",
"M 10 20 C 40 60, 60 80, -60 100 C 30 200, 50 220, 70 240" },
{ "m10 20 c 30,40 50 60-70,80 90 100,110 120,130,140",
"M 10 20 C 40 60, 60 80, -60 100 C 30 200, 50 220, 70 240" },
// smooth curveto
{ "M10 20 S 30,40-50,60", "M 10 20 C 10 20, 30 40, -50 60" },
{ "M10 20 S 30,40 50 60-70,80,90 100",
"M 10 20 C 10 20, 30 40, 50 60 C 70 80, -70 80, 90 100" },
// quadratic curveto
{ "M10 20 Q30 40 50 60", "M 10 20 C 23.3333333 33.3333333, 36.6666667 46.6666667, 50 60" },
{ "M10 20 Q30 40 50 60,70,80-90 100",
"M 10 20 C 23.3333333 33.3333333, 36.6666667 46.6666667, 50 60 C 63.3333333 73.3333333, 16.6666667 86.6666667, -90 100" },
{ "m10 20 q 30,40 50 60-70,80 90 100",
"M 10 20 C 30 46.6666667, 46.6666667 66.6666667, 60 80 C 13.3333333 133.3333333, 43.3333333 166.6666667, 150 180" },
// smooth quadratic curveto
{ "M10 20 T30 40", "M 10 20 C 10 20, 16.6666667 26.6666667, 30 40" },
{ "M10 20 Q30 40 50 60 T70 80",
"M 10 20 C 23.3333333 33.3333333, 36.6666667 46.6666667, 50 60 C 63.3333333 73.3333333, 70 80, 70 80" },
{ "m10 20 q 30,40 50 60t-70,80",
"M 10 20 C 30 46.6666667, 46.6666667 66.6666667, 60 80 C 73.3333333 93.3333333, 50 120, -10 160" },
// elliptical arc. Exact numbers depend on too much math, so just verify
// that these parse successfully
{ "M 1 3 A 1 2 3 00 6 7", "path" },
{ "M 1 2 A 1 2 3 016 7", "path" },
{ "M 1 2 A 1 2 3 10,6 7", "path" },
{ "M 1 2 A 1 2 3 1,1 6 7", "path" },
{ "M 1 2 A 1 2 3 1 1 6 7", "path" },
{ "M 1 2 A 1 2 3 1 16 7", "path" },
// close path
{ "M10 20 Z", "M 10 20 Z" },
{ "m10 20 30 40 m 50 60 70 80 90 100z", "M 10 20 L 40 60 M 90 120 L 160 200 L 250 300 Z" },
// must start with moveto
{ " L10 20", NULL },
// moveto args
{ "M", NULL },
{ "M,", NULL },
{ "M10", NULL },
{ "M10,", NULL },
{ "M10x", NULL },
{ "M10,x", NULL },
{ "M10-20,", NULL },
{ "M10-20-30", NULL },
{ "M10-20-30 x", NULL },
// closepath args
{ "M10-20z10", NULL },
{ "M10-20z,", NULL },
// lineto args
{ "M10-20L10", NULL },
{ "M 10,10 L 20,20,30", NULL },
{ "M 10,10 L 20,20,", NULL },
// horizontal lineto args
{ "M10-20H", NULL },
{ "M10-20H,", NULL },
{ "M10-20H30,", NULL },
// vertical lineto args
{ "M10-20v", NULL },
{ "M10-20v,", NULL },
{ "M10-20v30,", NULL },
// curveto args
{ "M10-20C1", NULL },
{ "M10-20C1,", NULL },
{ "M10-20C1 2", NULL },
{ "M10-20C1,2,", NULL },
{ "M10-20C1 2 3", NULL },
{ "M10-20C1,2,3", NULL },
{ "M10-20C1,2,3,", NULL },
{ "M10-20C1 2 3 4", NULL },
{ "M10-20C1,2,3,4", NULL },
{ "M10-20C1,2,3,4,", NULL },
{ "M10-20C1 2 3 4 5", NULL },
{ "M10-20C1,2,3,4,5", NULL },
{ "M10-20C1,2,3,4,5,", NULL },
{ "M10-20C1,2,3,4,5,6,", NULL },
// smooth curveto args
{ "M10-20S1", NULL },
{ "M10-20S1,", NULL },
{ "M10-20S1 2", NULL },
{ "M10-20S1,2,", NULL },
{ "M10-20S1 2 3", NULL },
{ "M10-20S1,2,3,", NULL },
{ "M10-20S1,2,3,4,", NULL },
// quadratic curveto args
{ "M10-20Q1", NULL },
{ "M10-20Q1,", NULL },
{ "M10-20Q1 2", NULL },
{ "M10-20Q1,2,", NULL },
{ "M10-20Q1 2 3", NULL },
{ "M10-20Q1,2,3", NULL },
{ "M10-20Q1,2,3,", NULL },
{ "M10 20 Q30 40 50 60,", NULL },
// smooth quadratic curveto args
{ "M10-20T1", NULL },
{ "M10-20T1,", NULL },
{ "M10 20 T 30 40,", NULL },
// elliptical arc args
{ "M10-20A1", NULL },
{ "M10-20A1,", NULL },
{ "M10-20A1 2", NULL },
{ "M10-20A1 2,", NULL },
{ "M10-20A1 2 3", NULL },
{ "M10-20A1 2 3,", NULL },
{ "M10-20A1 2 3 4", NULL },
{ "M10-20A1 2 3 1", NULL },
{ "M10-20A1 2 3,1,", NULL },
{ "M10-20A1 2 3 1 5", NULL },
{ "M10-20A1 2 3 1 1", NULL },
{ "M10-20A1 2 3,1,1,", NULL },
{ "M10-20A1 2 3 1 1 6", NULL },
{ "M10-20A1 2 3,1,1,6,", NULL },
{ "M 1 2 A 1 2 3 1.0 0.0 6 7", NULL },
{ "M10-20A1 2 3,1,1,6,7,", NULL },
// misc
{ "M.. 1,0 0,100000", NULL },
{ "M 10 20,M 10 20", NULL },
{ "M 10 20, M 10 20", NULL },
{ "M 10 20, M 10 20", NULL },
{ "M 10 20, ", NULL },
};
int i;
for (i = 0; i < G_N_ELEMENTS (tests); i++)
{
GskPath *path;
char *string;
char *string2;
if (g_test_verbose ())
g_print ("%d: %s\n", i, tests[i].in);
path = gsk_path_parse (tests[i].in);
if (tests[i].out)
{
g_assert_nonnull (path);
string = gsk_path_to_string (path);
gsk_path_unref (path);
if (strcmp (tests[i].out, "path") != 0)
{
/* Preferred, but doesn't work, because
* gsk_path_print() prints numbers with
* insane accuracy */
/* g_assert_cmpstr (tests[i].out, ==, string); */
path = gsk_path_parse (tests[i].out);
g_assert_nonnull (path);
string2 = gsk_path_to_string (path);
gsk_path_unref (path);
g_assert_cmpstr (string, ==, string2);
}
path = gsk_path_parse (string);
g_assert_nonnull (path);
string2 = gsk_path_to_string (path);
gsk_path_unref (path);
g_assert_cmpstr (string, ==, string2);
g_free (string);
g_free (string2);
}
else
g_assert_null (path);
}
}
/* Test that circles and rectangles serialize as expected and can be
* round-tripped through strings.
*/
static void
test_serialize_custom_contours (void)
{
GskPathBuilder *builder;
GskPath *path;
GskPath *path1;
char *string;
char *string1;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (100, 100), 50);
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (111, 222, 333, 444));
path = gsk_path_builder_free_to_path (builder);
string = gsk_path_to_string (path);
g_assert_cmpstr ("M 150 100 A 50 50 0 0 0 50 100 A 50 50 0 0 0 150 100 z M 111 222 h 333 v 444 h -333 z", ==, string);
path1 = gsk_path_parse (string);
string1 = gsk_path_to_string (path1);
g_assert_cmpstr (string, ==, string1);
g_free (string);
g_free (string1);
gsk_path_unref (path);
gsk_path_unref (path1);
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/path/rsvg-parse", test_rsvg_parse);
g_test_add_func ("/path/serialize-custom-contours", test_serialize_custom_contours);
return g_test_run ();
}
-1073
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -371,11 +371,11 @@ do_screenshot (int *argc,
exit (1);
}
g_set_prgname ("gtk4-builder-tool render");
g_set_prgname ("gtk4-builder-tool screenshot");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Render a .ui file to an image."));
g_option_context_set_summary (context, _("Take a screenshot of the file."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
@@ -394,7 +394,7 @@ do_screenshot (int *argc,
if (g_strv_length (filenames) > 2)
{
g_printerr (_("Can only render a single .ui file to a single output file\n"));
g_printerr (_("Can only screenshot a single .ui file and a single output file\n"));
exit (1);
}
+2 -4
View File
@@ -34,7 +34,7 @@ static void G_GNUC_NORETURN
usage (void)
{
g_print (_("Usage:\n"
" gtk4-builder-tool [COMMAND] [OPTION…] FILE\n"
" gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
"\n"
"Perform various tasks on GtkBuilder .ui files.\n"
"\n"
@@ -43,7 +43,6 @@ usage (void)
" simplify Simplify the file\n"
" enumerate List all named objects\n"
" preview Preview the file\n"
" render Take a screenshot of the file\n"
" screenshot Take a screenshot of the file\n"
"\n"));
exit (1);
@@ -135,8 +134,7 @@ main (int argc, const char *argv[])
do_enumerate (&argc, &argv);
else if (strcmp (argv[0], "preview") == 0)
do_preview (&argc, &argv);
else if (strcmp (argv[0], "render") == 0 ||
strcmp (argv[0], "screenshot") == 0)
else if (strcmp (argv[0], "screenshot") == 0)
do_screenshot (&argc, &argv);
else
usage ();