Compare commits

...

14 Commits

Author SHA1 Message Date
Benjamin Otte
f2848737a2 gsk: Add gsk_texture_download() API
Now users can download pixels and make everything slooooooow.
2016-12-22 04:28:11 +01:00
Benjamin Otte
8b7261df40 gdk: Export gdk_cairo_surface_paint_pixbuf() into private header 2016-12-22 04:17:57 +01:00
Benjamin Otte
74e00bddf5 docs: Add GskTexture 2016-12-22 04:17:57 +01:00
Benjamin Otte
2345ffe0e4 gsk: Rename to gsk_texture_download_surface()
I want to reuse the name gsk_texture_download() for downloading the
actual bytes.
2016-12-22 04:17:57 +01:00
Benjamin Otte
67d0fd06b8 gsk: Add gsk_renderer_render_texture()
... and implement it for the Cairo renderer.

It's an API that instructs a renderer to render to a texture.
So far this is mostly meant to be used for testing, but I could imagine
it being useful for rendering DND icons.
2016-12-22 04:17:57 +01:00
Benjamin Otte
9d89e4981b gskcairo: Don't store the viewport in the global struct
Just query it locally.
2016-12-22 04:17:57 +01:00
Benjamin Otte
b1278c3666 gsk: Don't overdraw with transparent
That code doesn't do anything.

And what the code should be doing (clearing the abckground) isn't
necessary as cairo drawing is guaranteed to clear the surface.
2016-12-22 04:17:57 +01:00
Benjamin Otte
04f9fb511f rendernode: Fix typo 2016-12-22 04:17:57 +01:00
Benjamin Otte
f8166f6a4f gsk: Remove nonexisting functions
The function was removed when gsk_render_node_draw() was and
gsk_renderer_realize() was refactored respectively.
2016-12-22 04:17:27 +01:00
Benjamin Otte
52d426d08f tests: Add a simple test to convert rendernode to png
Takes a rendernode file, outputs a PNG. Nothing more.
2016-12-22 04:17:27 +01:00
Benjamin Otte
75510f7123 gsk: Export gsk_render_node_get_bounds()
I'll need it in tests/testsuite soon.
2016-12-22 04:17:27 +01:00
Benjamin Otte
beb48202fc inspector: Add a render node save button
Now we can select buggy nodes, save them to a file, and add that file to
our testsuite.
2016-12-22 04:17:27 +01:00
Benjamin Otte
524c25b727 gsk: Add gsk_render_node_serialize/deserialize()
This does a conversion to/from GBytes and is intended for writing tests.

It's really crude but it works.
And that probably means Alex will (ab)use it for broadway.
2016-12-22 04:17:27 +01:00
Benjamin Otte
8cc77194a3 gsk: Remove spread member from GskShadow
I had originally thought I'd use GskShadow for box-shadow, but didn't in
the end.

So now it's only used for text-shadow and icon-shadow, and those don't
have a spread.
2016-12-22 04:09:07 +01:00
21 changed files with 1444 additions and 58 deletions

View File

@@ -12,6 +12,7 @@ gsk_renderer_unrealize
gsk_renderer_begin_draw_frame
gsk_renderer_end_draw_frame
gsk_renderer_render
gsk_renderer_render_texture
<SUBSECTION Standard>
GSK_IS_RENDERER
GSK_RENDERER
@@ -32,6 +33,8 @@ gsk_render_node_draw
GskScalingFilter
gsk_render_node_set_scaling_filters
gsk_render_node_set_name
gsk_render_node_get_name
gsk_render_node_get_bounds
gsk_color_node_new
gsk_linear_gradient_node_new
gsk_repeating_linear_gradient_node_new
@@ -68,6 +71,22 @@ gsk_render_node_get_type
GSK_TYPE_BLEND_MODE
</SECTION>
<SECTION>
<FILE>GskTexture</FILE>
gsk_texture_ref
gsk_texture_unref
gsk_texture_new_for_data
gsk_texture_new_for_pixbuf
gsk_texture_get_width
gsk_texture_get_height
gsk_texture_download
<SUBSECTION Standard>
GskTexture
gsk_texture_get_type
GSK_TYPE_TEXTURE
GSK_IS_TEXTURE
</SECTION>
<SECTION>
<FILE>GskRoundedRect</FILE>
GskCorner

View File

@@ -151,7 +151,7 @@ gdk_cairo_region (cairo_t *cr,
}
}
static void
void
gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface,
const GdkPixbuf *pixbuf)
{
@@ -198,7 +198,9 @@ gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface,
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
q[3] = 0xFF;
#else
q[0] = 0xFF;
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];

View File

@@ -343,6 +343,9 @@ void gdk_gl_texture_quads (GdkGLContext *paint_context,
GdkTexturedQuad *quads,
gboolean flip_colors);
void gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface,
const GdkPixbuf *pixbuf);
void gdk_cairo_surface_mark_as_direct (cairo_surface_t *surface,
GdkWindow *window);
cairo_region_t *gdk_cairo_region_from_clip (cairo_t *cr);

View File

@@ -18,8 +18,6 @@ struct _GskCairoRenderer
{
GskRenderer parent_instance;
graphene_rect_t viewport;
#ifdef G_ENABLE_DEBUG
ProfileTimers profile_timers;
#endif
@@ -47,44 +45,16 @@ gsk_cairo_renderer_unrealize (GskRenderer *renderer)
}
static void
gsk_cairo_renderer_render (GskRenderer *renderer,
GskRenderNode *root)
gsk_cairo_renderer_do_render (GskRenderer *renderer,
cairo_t *cr,
GskRenderNode *root)
{
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer);
#ifdef G_ENABLE_DEBUG
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
GskProfiler *profiler;
gint64 cpu_time;
#endif
cairo_t *cr;
cr = gdk_drawing_context_get_cairo_context (context);
g_return_if_fail (cr != NULL);
gsk_renderer_get_viewport (renderer, &self->viewport);
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba (cr, 0, 0, 0, 0);
cairo_paint (cr);
cairo_restore (cr);
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
{
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_rectangle (cr,
self->viewport.origin.x,
self->viewport.origin.y,
self->viewport.size.width,
self->viewport.size.height);
cairo_set_source_rgba (cr, 0, 0, 0.85, 0.5);
cairo_stroke (cr);
cairo_restore (cr);
}
#ifdef G_ENABLE_DEBUG
profiler = gsk_renderer_get_profiler (renderer);
gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
@@ -100,6 +70,62 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
#endif
}
static GskTexture *
gsk_cairo_renderer_render_texture (GskRenderer *renderer,
GskRenderNode *root,
const graphene_rect_t *viewport)
{
GskTexture *texture;
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height));
cr = cairo_create (surface);
cairo_translate (cr, - viewport->origin.x, - viewport->origin.y);
gsk_cairo_renderer_do_render (renderer, cr, root);
cairo_destroy (cr);
texture = gsk_texture_new_for_surface (surface);
cairo_surface_destroy (surface);
return texture;
}
static void
gsk_cairo_renderer_render (GskRenderer *renderer,
GskRenderNode *root)
{
GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer);
graphene_rect_t viewport;
cairo_t *cr;
cr = gdk_drawing_context_get_cairo_context (context);
g_return_if_fail (cr != NULL);
gsk_renderer_get_viewport (renderer, &viewport);
if (GSK_RENDER_MODE_CHECK (GEOMETRY))
{
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_rectangle (cr,
viewport.origin.x,
viewport.origin.y,
viewport.size.width,
viewport.size.height);
cairo_set_source_rgba (cr, 0, 0, 0.85, 0.5);
cairo_stroke (cr);
cairo_restore (cr);
}
gsk_cairo_renderer_do_render (renderer, cr, root);
}
static void
gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
{
@@ -108,6 +134,7 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass)
renderer_class->realize = gsk_cairo_renderer_realize;
renderer_class->unrealize = gsk_cairo_renderer_unrealize;
renderer_class->render = gsk_cairo_renderer_render;
renderer_class->render_texture = gsk_cairo_renderer_render_texture;
}
static void

View File

@@ -462,7 +462,7 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *driver,
if (gsk_texture_set_render_data (texture, driver, t, gsk_gl_driver_release_texture))
t->user = texture;
surface = gsk_texture_download (texture);
surface = gsk_texture_download_surface (texture);
gsk_gl_driver_bind_source_texture (driver, t->texture_id);
gsk_gl_driver_init_texture_with_surface (driver,
t->texture_id,

View File

@@ -113,6 +113,15 @@ gsk_renderer_real_unrealize (GskRenderer *self)
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize);
}
static GskTexture *
gsk_renderer_real_render_texture (GskRenderer *self,
GskRenderNode *root,
const graphene_rect_t *viewport)
{
GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render_texture);
return NULL;
}
static GdkDrawingContext *
gsk_renderer_real_begin_draw_frame (GskRenderer *self,
const cairo_region_t *region)
@@ -259,6 +268,7 @@ gsk_renderer_class_init (GskRendererClass *klass)
klass->begin_draw_frame = gsk_renderer_real_begin_draw_frame;
klass->end_draw_frame = gsk_renderer_real_end_draw_frame;
klass->render = gsk_renderer_real_render;
klass->render_texture = gsk_renderer_real_render_texture;
klass->create_cairo_surface = gsk_renderer_real_create_cairo_surface;
gobject_class->constructed = gsk_renderer_constructed;
@@ -606,6 +616,75 @@ gsk_renderer_unrealize (GskRenderer *renderer)
priv->is_realized = FALSE;
}
/**
* gsk_renderer_render_texture:
* @renderer: a realized #GdkRenderer
* @root: a #GskRenderNode
* @viewport: (allow-none): the section to draw or %NULL to use @root's bounds
*
* Renders the scene graph, described by a tree of #GskRenderNode instances,
* to a #GskTexture.
*
* The @renderer will acquire a reference on the #GskRenderNode tree while
* the rendering is in progress, and will make the tree immutable.
*
* If you want to apply any transformations to @root, you should put it into a
* transform node and pass that node instead.
*
* Returns: (transfer full): a #GskTexture with the rendered contents of @root.
*
* Since: 3.90
*/
GskTexture *
gsk_renderer_render_texture (GskRenderer *renderer,
GskRenderNode *root,
const graphene_rect_t *viewport)
{
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
graphene_rect_t real_viewport;
GskTexture *texture;
g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
g_return_val_if_fail (priv->is_realized, NULL);
g_return_val_if_fail (GSK_IS_RENDER_NODE (root), NULL);
g_return_val_if_fail (priv->root_node == NULL, NULL);
priv->root_node = gsk_render_node_ref (root);
if (viewport == NULL)
{
gsk_render_node_get_bounds (root, &real_viewport);
viewport = &real_viewport;
}
#ifdef G_ENABLE_DEBUG
gsk_profiler_reset (priv->profiler);
#endif
texture = GSK_RENDERER_GET_CLASS (renderer)->render_texture (renderer, root, viewport);
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK (RENDERER))
{
GString *buf = g_string_new ("*** Texture stats ***\n\n");
gsk_profiler_append_counters (priv->profiler, buf);
g_string_append_c (buf, '\n');
gsk_profiler_append_timers (priv->profiler, buf);
g_string_append_c (buf, '\n');
g_print ("%s\n***\n\n", buf->str);
g_string_free (buf, TRUE);
}
#endif
g_clear_pointer (&priv->root_node, gsk_render_node_unref);
return texture;
}
/**
* gsk_renderer_render:
* @renderer: a #GskRenderer

View File

@@ -53,9 +53,6 @@ void gsk_renderer_set_scale_factor (GskRenderer
GDK_AVAILABLE_IN_3_90
int gsk_renderer_get_scale_factor (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_90
void gsk_renderer_set_window (GskRenderer *renderer,
GdkWindow *window);
GDK_AVAILABLE_IN_3_90
GdkWindow * gsk_renderer_get_window (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_90
@@ -69,9 +66,9 @@ GDK_AVAILABLE_IN_3_90
void gsk_renderer_unrealize (GskRenderer *renderer);
GDK_AVAILABLE_IN_3_90
GskRenderer * gsk_renderer_create_fallback (GskRenderer *renderer,
const graphene_rect_t *viewport,
cairo_t *cr);
GskTexture * gsk_renderer_render_texture (GskRenderer *renderer,
GskRenderNode *root,
const graphene_rect_t *viewport);
GDK_AVAILABLE_IN_3_90
GdkDrawingContext * gsk_renderer_begin_draw_frame (GskRenderer *renderer,

View File

@@ -42,6 +42,9 @@ struct _GskRendererClass
GError **error);
void (* unrealize) (GskRenderer *renderer);
GskTexture * (* render_texture) (GskRenderer *renderer,
GskRenderNode *root,
const graphene_rect_t *viewport);
GdkDrawingContext * (* begin_draw_frame) (GskRenderer *renderer,
const cairo_region_t *region);
void (* end_draw_frame) (GskRenderer *renderer,

View File

@@ -285,4 +285,54 @@ gsk_render_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
#define GSK_RENDER_NODE_SERIALIZATION_VERSION 0
#define GSK_RENDER_NODE_SERIALIZATION_ID "GskRenderNode"
GBytes *
gsk_render_node_serialize (GskRenderNode *node)
{
GVariant *node_variant, *variant;
GBytes *result;
node_variant = gsk_render_node_serialize_node (node);
variant = g_variant_new ("(suuv)",
GSK_RENDER_NODE_SERIALIZATION_ID,
(guint32) GSK_RENDER_NODE_SERIALIZATION_VERSION,
(guint32) gsk_render_node_get_node_type (node),
node_variant);
result = g_variant_get_data_as_bytes (variant);
g_variant_unref (variant);
return result;
}
GskRenderNode *
gsk_render_node_deserialize (GBytes *bytes)
{
char *id_string;
guint32 version, node_type;
GVariant *variant, *node_variant;
GskRenderNode *node = NULL;
variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
g_variant_get (variant, "(suuv)", &id_string, &version, &node_type, &node_variant);
if (!g_str_equal (id_string, GSK_RENDER_NODE_SERIALIZATION_ID))
goto out;
if (version != GSK_RENDER_NODE_SERIALIZATION_VERSION)
goto out;
node = gsk_render_node_deserialize_node (node_type, node_variant);
out:
g_free (id_string);
g_variant_unref (node_variant);
g_variant_unref (variant);
return node;
}

View File

@@ -47,7 +47,6 @@ struct _GskShadow
GdkRGBA color;
float dx;
float dy;
float spread;
float radius;
};
@@ -167,10 +166,19 @@ void gsk_render_node_set_name (GskRenderNode *
const char *name);
GDK_AVAILABLE_IN_3_90
const char * gsk_render_node_get_name (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
void gsk_render_node_get_bounds (GskRenderNode *node,
graphene_rect_t *frame);
GDK_AVAILABLE_IN_3_90
void gsk_render_node_draw (GskRenderNode *node,
cairo_t *cr);
GDK_AVAILABLE_IN_3_90
GBytes * gsk_render_node_serialize (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes);
G_END_DECLS
#endif /* __GSK_RENDER_NODE_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -34,18 +34,22 @@ struct _GskRenderNodeClass
void (* finalize) (GskRenderNode *node);
void (* draw) (GskRenderNode *node,
cairo_t *cr);
GVariant * (* serialize) (GskRenderNode *node);
GskRenderNode * (* deserialize) (GVariant *variant);
};
GskRenderNode *gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size);
void gsk_render_node_get_bounds (GskRenderNode *node,
graphene_rect_t *frame);
GVariant * gsk_render_node_serialize_node (GskRenderNode *node);
GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVariant *variant);
double gsk_opacity_node_get_opacity (GskRenderNode *node);
const GskRoundedRect * gsk_border_node_peek_outline (GskRenderNode *node);
float gsk_border_node_get_width (GskRenderNode *node, guint i);
const GdkRGBA * gsk_border_node_peek_color (GskRenderNode *node, guint i);
GskRenderNode *gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds, cairo_surface_t *surface);
cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);

View File

@@ -37,6 +37,8 @@
#include "gskdebugprivate.h"
#include "gskrenderer.h"
#include "gdk/gdkinternals.h"
/**
* GskTexture: (ref-func gsk_texture_ref) (unref-func gsk_texture_unref)
*
@@ -135,18 +137,43 @@ gsk_texture_cairo_finalize (GskTexture *texture)
}
static cairo_surface_t *
gsk_texture_cairo_download (GskTexture *texture)
gsk_texture_cairo_download_surface (GskTexture *texture)
{
GskCairoTexture *cairo = (GskCairoTexture *) texture;
return cairo_surface_reference (cairo->surface);
}
static void
gsk_texture_cairo_download (GskTexture *texture,
guchar *data,
gsize stride)
{
GskCairoTexture *cairo = (GskCairoTexture *) texture;
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
texture->width, texture->height,
stride);
cr = cairo_create (surface);
cairo_set_source_surface (cr, cairo->surface, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_finish (surface);
cairo_surface_destroy (surface);
}
static const GskTextureClass GSK_TEXTURE_CLASS_CAIRO = {
"cairo",
sizeof (GskCairoTexture),
gsk_texture_cairo_finalize,
gsk_texture_cairo_download
gsk_texture_cairo_download,
gsk_texture_cairo_download_surface
};
GskTexture *
@@ -208,8 +235,25 @@ gsk_texture_pixbuf_finalize (GskTexture *texture)
g_object_unref (pixbuf->pixbuf);
}
static void
gsk_texture_pixbuf_download (GskTexture *texture,
guchar *data,
gsize stride)
{
GskPixbufTexture *pixbuf = (GskPixbufTexture *) texture;
cairo_surface_t *surface;
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
texture->width, texture->height,
stride);
gdk_cairo_surface_paint_pixbuf (surface, pixbuf->pixbuf);
cairo_surface_finish (surface);
cairo_surface_destroy (surface);
}
static cairo_surface_t *
gsk_texture_pixbuf_download (GskTexture *texture)
gsk_texture_pixbuf_download_surface (GskTexture *texture)
{
GskPixbufTexture *pixbuf = (GskPixbufTexture *) texture;
@@ -220,7 +264,8 @@ static const GskTextureClass GSK_TEXTURE_CLASS_PIXBUF = {
"pixbuf",
sizeof (GskPixbufTexture),
gsk_texture_pixbuf_finalize,
gsk_texture_pixbuf_download
gsk_texture_pixbuf_download,
gsk_texture_pixbuf_download_surface
};
GskTexture *
@@ -276,9 +321,59 @@ gsk_texture_get_height (GskTexture *texture)
}
cairo_surface_t *
gsk_texture_download (GskTexture *texture)
gsk_texture_download_surface (GskTexture *texture)
{
return texture->klass->download (texture);
cairo_surface_t *surface;
if (texture->klass->download_surface)
return texture->klass->download_surface (texture);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
texture->width, texture->height);
gsk_texture_download (texture,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
cairo_surface_mark_dirty (surface);
return surface;
}
/**
* gsk_texture_download:
* @texture: a #GskTexture
* @data: pointer to enough memory to be filled with the
* downloaded data of @texture
* @stride: rowstride in bytes
*
* Downloads the @texture into local memory. This may be
* an expensive operation, as the actual texture data may
* reside on a GPU or on a remote display server.
*
* The data format of the downloaded data is equivalent to
* %CAIRO_FORMAT_ARGB32, so every downloaded pixel requires
* 4 bytes of memory.
*
* Downloading a texture into a Cairo image surface:
* |[<!-- language="C" -->
* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
* gsk_texture_get_width (texture),
* gsk_texture_get_height (texture));
* gsk_texture_download (texture,
* cairo_image_surface_get_data (surface),
* cairo_image_surface_get_stride (surface));
* cairo_surface_mark_dirty (surface);
* ]|
**/
void
gsk_texture_download (GskTexture *texture,
guchar *data,
gsize stride)
{
g_return_if_fail (GSK_IS_TEXTURE (texture));
g_return_if_fail (data != NULL);
g_return_if_fail (stride >= gsk_texture_get_width (texture) * 4);
return texture->klass->download (texture, data, stride);
}
gboolean

View File

@@ -52,6 +52,11 @@ int gsk_texture_get_width (GskTexture
GDK_AVAILABLE_IN_3_90
int gsk_texture_get_height (GskTexture *texture);
GDK_AVAILABLE_IN_3_90
void gsk_texture_download (GskTexture *texture,
guchar *data,
gsize stride);
G_END_DECLS
#endif /* __GSK_TEXTURE_H__ */

View File

@@ -30,14 +30,17 @@ struct _GskTextureClass {
gsize size;
void (* finalize) (GskTexture *texture);
cairo_surface_t * (* download) (GskTexture *texture);
void (* download) (GskTexture *texture,
guchar *data,
gsize stride);
cairo_surface_t * (* download_surface) (GskTexture *texture);
};
gpointer gsk_texture_new (const GskTextureClass *klass,
int width,
int height);
GskTexture * gsk_texture_new_for_surface (cairo_surface_t *surface);
cairo_surface_t * gsk_texture_download (GskTexture *texture);
cairo_surface_t * gsk_texture_download_surface (GskTexture *texture);
gboolean gsk_texture_set_render_data (GskTexture *self,
gpointer key,

View File

@@ -281,7 +281,7 @@ gsk_vulkan_renderer_ref_texture_image (GskVulkanRenderer *self,
if (data)
return g_object_ref (data->image);
surface = gsk_texture_download (texture);
surface = gsk_texture_download_surface (texture);
image = gsk_vulkan_image_new_from_data (uploader,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_width (surface),

View File

@@ -631,7 +631,6 @@ gtk_css_shadow_value_get_shadow (const GtkCssValue *value,
shadow->color = *_gtk_css_rgba_value_get_rgba (value->color);
shadow->dx = _gtk_css_number_value_get (value->hoffset, 0);
shadow->dy = _gtk_css_number_value_get (value->voffset, 0);
shadow->spread = _gtk_css_number_value_get (value->spread, 0);
shadow->radius = _gtk_css_number_value_get (value->radius, 0);
}

View File

@@ -21,8 +21,10 @@
#include "recorder.h"
#include <gtk/gtkbox.h>
#include <gtk/gtkfilechooserdialog.h>
#include <gtk/gtklabel.h>
#include <gtk/gtklistbox.h>
#include <gtk/gtkmessagedialog.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktreeview.h>
@@ -43,6 +45,7 @@ struct _GtkInspectorRecorderPrivate
GtkWidget *recordings_list;
GtkWidget *render_node_view;
GtkWidget *render_node_tree;
GtkWidget *render_node_save_button;
GtkWidget *node_property_tree;
GtkTreeModel *render_node_properties;
@@ -219,14 +222,92 @@ render_node_list_selection_changed (GtkTreeSelection *selection,
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
{
gtk_widget_set_sensitive (priv->render_node_save_button, FALSE);
return;
}
gtk_widget_set_sensitive (priv->render_node_save_button, TRUE);
node = gtk_tree_model_render_node_get_node_from_iter (GTK_TREE_MODEL_RENDER_NODE (priv->render_node_model), &iter);
gtk_render_node_view_set_render_node (GTK_RENDER_NODE_VIEW (priv->render_node_view), node);
populate_render_node_properties (GTK_LIST_STORE (priv->render_node_properties), node);
}
static void
render_node_save_response (GtkWidget *dialog,
gint response,
GskRenderNode *node)
{
gtk_widget_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GBytes *bytes = gsk_render_node_serialize (node);
GError *error = NULL;
if (!g_file_replace_contents (gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)),
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
NULL,
FALSE,
0,
NULL,
NULL,
&error))
{
GtkWidget *message_dialog;
message_dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_window_get_transient_for (GTK_WINDOW (dialog))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
_("Saving RenderNode failed"));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message_dialog),
"%s", error->message);
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (message_dialog);
g_error_free (error);
}
g_bytes_unref (bytes);
}
gtk_widget_destroy (dialog);
}
static void
render_node_save (GtkButton *button,
GtkInspectorRecorder *recorder)
{
GtkInspectorRecorderPrivate *priv = gtk_inspector_recorder_get_instance_private (recorder);
GskRenderNode *node;
GtkTreeIter iter;
GtkWidget *dialog;
char *filename;
if (!gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->render_node_tree)), NULL, &iter))
return;
node = gtk_tree_model_render_node_get_node_from_iter (GTK_TREE_MODEL_RENDER_NODE (priv->render_node_model), &iter);
dialog = gtk_file_chooser_dialog_new ("",
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (recorder))),
GTK_FILE_CHOOSER_ACTION_SAVE,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_ACCEPT,
NULL);
filename = g_strdup_printf ("%s.node", gsk_render_node_get_name (node) ? gsk_render_node_get_name (node)
: node_type_name (gsk_render_node_get_node_type (node)));
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename);
g_free (filename);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
g_signal_connect (dialog, "response", G_CALLBACK (render_node_save_response), node);
gtk_widget_show (dialog);
}
static char *
format_timespan (gint64 timespan)
{
@@ -394,11 +475,13 @@ gtk_inspector_recorder_class_init (GtkInspectorRecorderClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorRecorder, recordings_list);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorRecorder, render_node_view);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorRecorder, render_node_tree);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorRecorder, render_node_save_button);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorRecorder, node_property_tree);
gtk_widget_class_bind_template_callback (widget_class, recordings_clear_all);
gtk_widget_class_bind_template_callback (widget_class, recordings_list_row_selected);
gtk_widget_class_bind_template_callback (widget_class, render_node_list_selection_changed);
gtk_widget_class_bind_template_callback (widget_class, render_node_save);
}
static void

View File

@@ -33,6 +33,18 @@
<property name="stack">render_stack</property>
</object>
</child>
<child>
<object class="GtkButton" id="render_node_save_button">
<property name="visible">1</property>
<property name="relief">none</property>
<property name="sensitive">0</property>
<property name="icon-name">document-save-as-symbolic</property>
<signal name="clicked" handler="render_node_save"/>
</object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child>
<child>

View File

@@ -27,6 +27,7 @@ fontconfig_programs = testfontchooserdialog
endif
noinst_PROGRAMS = $(TEST_PROGS) \
rendernode \
overlayscroll \
syncscroll \
animated-resizing \
@@ -161,6 +162,7 @@ if USE_X11
noinst_PROGRAMS += testerrors
endif
rendernode_DEPENDENCIES = $(TEST_DEPS)
animated_resizing_DEPENDENCIES = $(TEST_DEPS)
animated_revealing_DEPENDENCIES = $(TEST_DEPS)
flicker_DEPENDENCIES = $(TEST_DEPS)

68
tests/rendernode.c Normal file
View File

@@ -0,0 +1,68 @@
#include <gtk/gtk.h>
static GOptionEntry options[] = {
{ NULL }
};
int
main(int argc, char **argv)
{
graphene_rect_t bounds;
cairo_surface_t *surface;
GskRenderNode *node;
cairo_t *cr;
GError *error = NULL;
GBytes *bytes;
char *contents;
gsize len;
if (!gtk_init_with_args (&argc, &argv, "NODE-FILE PNG-FILE",
options, NULL, &error))
{
g_printerr ("Option parsing failed: %s\n", error->message);
return 1;
}
if (argc != 3)
{
g_printerr ("Usage: %s [OPTIONS] NODE-FILE PNG-FILE\n", argv[0]);
return 1;
}
if (!g_file_get_contents (argv[1], &contents, &len, &error))
{
g_printerr ("Could not open node file: %s\n", error->message);
return 1;
}
bytes = g_bytes_new_take (contents, len);
node = gsk_render_node_deserialize (bytes);
g_bytes_unref (bytes);
if (node == NULL)
{
g_printerr ("Invalid node file.\n");
return 1;
}
gsk_render_node_get_bounds (node, &bounds);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (bounds.size.width), ceil (bounds.size.height));
cr = cairo_create (surface);
cairo_translate (cr, - bounds.origin.x, - bounds.origin.y);
gsk_render_node_draw (node, cr);
cairo_destroy (cr);
gsk_render_node_unref (node);
if (cairo_surface_write_to_png (surface, argv[2]))
{
cairo_surface_destroy (surface);
g_print ("Failed to save PNG file.\n");
return 1;
}
cairo_surface_destroy (surface);
return 0;
}