forked from AuroraMiddleware/gtk
2480e0d575
... and make the icon rendering code use it. This requires moving even more shadow renering code into GSK, but so be it. At least the "shadows not implemented" warning is now gone!
325 lines
12 KiB
C
325 lines
12 KiB
C
/* GTK - The GIMP Toolkit
|
|
* Copyright (C) 2014,2015 Benjamin Otte
|
|
*
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
*
|
|
* 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 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/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gtkrendericonprivate.h"
|
|
|
|
#include "gtkcssimagebuiltinprivate.h"
|
|
#include "gtkcssimagevalueprivate.h"
|
|
#include "gtkcssshadowsvalueprivate.h"
|
|
#include "gtkcssstyleprivate.h"
|
|
#include "gtkcsstransformvalueprivate.h"
|
|
#include "gtksnapshotprivate.h"
|
|
|
|
#include <math.h>
|
|
|
|
void
|
|
gtk_css_style_render_icon (GtkCssStyle *style,
|
|
cairo_t *cr,
|
|
double x,
|
|
double y,
|
|
double width,
|
|
double height,
|
|
GtkCssImageBuiltinType builtin_type)
|
|
{
|
|
const GtkCssValue *shadows;
|
|
graphene_matrix_t graphene_matrix;
|
|
cairo_matrix_t matrix, transform_matrix, saved_matrix;
|
|
GtkCssImage *image;
|
|
|
|
g_return_if_fail (GTK_IS_CSS_STYLE (style));
|
|
g_return_if_fail (cr != NULL);
|
|
|
|
image = _gtk_css_image_value_get_image (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SOURCE));
|
|
if (image == NULL)
|
|
return;
|
|
|
|
cairo_get_matrix (cr, &saved_matrix);
|
|
|
|
shadows = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
|
|
|
|
cairo_translate (cr, x, y);
|
|
|
|
if (gtk_css_transform_value_get_matrix (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM), &graphene_matrix) &&
|
|
graphene_matrix_is_2d (&graphene_matrix))
|
|
{
|
|
graphene_matrix_to_2d (&graphene_matrix,
|
|
&transform_matrix.xx, &transform_matrix.yx,
|
|
&transform_matrix.xy, &transform_matrix.yy,
|
|
&transform_matrix.x0, &transform_matrix.y0);
|
|
/* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
|
|
cairo_matrix_init_translate (&matrix, width / 2, height / 2);
|
|
cairo_matrix_multiply (&matrix, &transform_matrix, &matrix);
|
|
cairo_matrix_translate (&matrix, - width / 2, - height / 2);
|
|
|
|
if (_gtk_css_shadows_value_is_none (shadows))
|
|
{
|
|
cairo_transform (cr, &matrix);
|
|
gtk_css_image_builtin_draw (image, cr, width, height, builtin_type);
|
|
}
|
|
else
|
|
{
|
|
cairo_push_group (cr);
|
|
cairo_transform (cr, &matrix);
|
|
gtk_css_image_builtin_draw (image, cr, width, height, builtin_type);
|
|
cairo_pop_group_to_source (cr);
|
|
_gtk_css_shadows_value_paint_icon (shadows, cr);
|
|
cairo_paint (cr);
|
|
}
|
|
}
|
|
|
|
cairo_set_matrix (cr, &saved_matrix);
|
|
}
|
|
|
|
void
|
|
gtk_css_style_snapshot_icon (GtkCssStyle *style,
|
|
GtkSnapshot *snapshot,
|
|
double width,
|
|
double height,
|
|
GtkCssImageBuiltinType builtin_type)
|
|
{
|
|
const GtkCssValue *shadows_value, *transform;
|
|
graphene_matrix_t transform_matrix;
|
|
GtkCssImage *image;
|
|
GskShadow *shadows;
|
|
gsize n_shadows;
|
|
|
|
g_return_if_fail (GTK_IS_CSS_STYLE (style));
|
|
g_return_if_fail (snapshot != NULL);
|
|
|
|
image = _gtk_css_image_value_get_image (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SOURCE));
|
|
if (image == NULL)
|
|
return;
|
|
|
|
shadows_value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
|
|
transform = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM);
|
|
|
|
if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
|
|
return;
|
|
|
|
shadows = gtk_css_shadows_value_get_shadows (shadows_value, &n_shadows);
|
|
if (shadows)
|
|
gtk_snapshot_push_shadow (snapshot, shadows, n_shadows, "IconShadow<%zu>", n_shadows);
|
|
|
|
if (graphene_matrix_is_identity (&transform_matrix))
|
|
{
|
|
gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
|
|
}
|
|
else
|
|
{
|
|
graphene_matrix_t m1, m2, m3;
|
|
|
|
/* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
|
|
graphene_matrix_init_translate (&m1, &GRAPHENE_POINT3D_INIT (width / 2.0, height / 2.0, 0));
|
|
graphene_matrix_multiply (&transform_matrix, &m1, &m3);
|
|
graphene_matrix_init_translate (&m2, &GRAPHENE_POINT3D_INIT (- width / 2.0, - height / 2.0, 0));
|
|
graphene_matrix_multiply (&m2, &m3, &m1);
|
|
|
|
gtk_snapshot_push_transform (snapshot, &m1, "CSS Icon Transform Container");
|
|
|
|
gtk_css_image_builtin_snapshot (image, snapshot, width, height, builtin_type);
|
|
|
|
gtk_snapshot_pop_and_append (snapshot);
|
|
}
|
|
|
|
if (shadows)
|
|
{
|
|
gtk_snapshot_pop_and_append (snapshot);
|
|
g_free (shadows);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
get_surface_extents (cairo_surface_t *surface,
|
|
GdkRectangle *out_extents)
|
|
{
|
|
cairo_t *cr;
|
|
gboolean result;
|
|
|
|
cr = cairo_create (surface);
|
|
result = gdk_cairo_get_clip_rectangle (cr, out_extents);
|
|
cairo_destroy (cr);
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
gtk_css_style_render_icon_surface (GtkCssStyle *style,
|
|
cairo_t *cr,
|
|
cairo_surface_t *surface,
|
|
double x,
|
|
double y)
|
|
{
|
|
const GtkCssValue *shadows;
|
|
graphene_matrix_t graphene_matrix;
|
|
cairo_matrix_t matrix, transform_matrix, saved_matrix;
|
|
GdkRectangle extents;
|
|
|
|
g_return_if_fail (GTK_IS_CSS_STYLE (style));
|
|
g_return_if_fail (cr != NULL);
|
|
g_return_if_fail (surface != NULL);
|
|
|
|
shadows = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
|
|
|
|
if (!get_surface_extents (surface, &extents))
|
|
{
|
|
/* weird infinite surface, no special magic for you */
|
|
cairo_set_source_surface (cr, surface, x, y);
|
|
_gtk_css_shadows_value_paint_icon (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW), cr);
|
|
cairo_paint (cr);
|
|
return;
|
|
}
|
|
|
|
cairo_get_matrix (cr, &saved_matrix);
|
|
cairo_translate (cr, x + extents.x, y + extents.y);
|
|
|
|
if (gtk_css_transform_value_get_matrix (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM), &graphene_matrix) &&
|
|
graphene_matrix_is_2d (&graphene_matrix))
|
|
{
|
|
cairo_pattern_t *pattern;
|
|
|
|
graphene_matrix_to_2d (&graphene_matrix,
|
|
&transform_matrix.xx, &transform_matrix.yx,
|
|
&transform_matrix.xy, &transform_matrix.yy,
|
|
&transform_matrix.x0, &transform_matrix.y0);
|
|
/* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
|
|
cairo_matrix_init_translate (&matrix, extents.width / 2, extents.height / 2);
|
|
cairo_matrix_multiply (&matrix, &transform_matrix, &matrix);
|
|
cairo_matrix_translate (&matrix, - extents.width / 2, - extents.height / 2);
|
|
if (cairo_matrix_invert (&matrix) != CAIRO_STATUS_SUCCESS)
|
|
{
|
|
g_assert_not_reached ();
|
|
}
|
|
cairo_matrix_translate (&matrix, extents.x, extents.y);
|
|
|
|
pattern = cairo_pattern_create_for_surface (surface);
|
|
cairo_pattern_set_matrix (pattern, &matrix);
|
|
cairo_set_source (cr, pattern);
|
|
cairo_pattern_destroy (pattern);
|
|
|
|
_gtk_css_shadows_value_paint_icon (shadows, cr);
|
|
cairo_paint (cr);
|
|
}
|
|
|
|
cairo_set_matrix (cr, &saved_matrix);
|
|
}
|
|
|
|
void
|
|
gtk_css_style_render_icon_get_extents (GtkCssStyle *style,
|
|
GdkRectangle *extents,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
graphene_matrix_t transform_matrix, translate_matrix, matrix;
|
|
graphene_rect_t bounds;
|
|
GtkBorder border;
|
|
|
|
g_return_if_fail (GTK_IS_CSS_STYLE (style));
|
|
g_return_if_fail (extents != NULL);
|
|
|
|
extents->x = x;
|
|
extents->y = y;
|
|
extents->width = width;
|
|
extents->height = height;
|
|
|
|
if (!gtk_css_transform_value_get_matrix (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM), &transform_matrix))
|
|
return;
|
|
|
|
graphene_matrix_init_translate (&translate_matrix, &GRAPHENE_POINT3D_INIT(x + width / 2.0, y + height / 2.0, 0));
|
|
graphene_matrix_multiply (&transform_matrix, &translate_matrix, &matrix);
|
|
graphene_rect_init (&bounds,
|
|
- width / 2.0, - height / 2.0,
|
|
width, height);
|
|
/* need to round to full pixels */
|
|
graphene_matrix_transform_bounds (&matrix, &bounds, &bounds);
|
|
|
|
_gtk_css_shadows_value_get_extents (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW), &border);
|
|
|
|
extents->x = floorf (bounds.origin.x) - border.left;
|
|
extents->y = floorf (bounds.origin.y) - border.top;
|
|
extents->width = ceilf (bounds.origin.x + bounds.size.width) - extents->x + border.right;
|
|
extents->height = ceilf (bounds.origin.y + bounds.size.height) - extents->y + border.bottom;
|
|
}
|
|
|
|
void
|
|
gtk_css_style_snapshot_icon_texture (GtkCssStyle *style,
|
|
GtkSnapshot *snapshot,
|
|
GskTexture *texture,
|
|
double texture_scale)
|
|
{
|
|
const GtkCssValue *shadows_value, *transform;
|
|
graphene_matrix_t transform_matrix;
|
|
graphene_rect_t bounds;
|
|
double width, height;
|
|
GskShadow *shadows;
|
|
gsize n_shadows;
|
|
|
|
g_return_if_fail (GTK_IS_CSS_STYLE (style));
|
|
g_return_if_fail (snapshot != NULL);
|
|
g_return_if_fail (GSK_IS_TEXTURE (texture));
|
|
g_return_if_fail (texture_scale > 0);
|
|
|
|
shadows_value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_SHADOW);
|
|
transform = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_ICON_TRANSFORM);
|
|
width = gsk_texture_get_width (texture) / texture_scale;
|
|
height = gsk_texture_get_height (texture) / texture_scale;
|
|
|
|
if (!gtk_css_transform_value_get_matrix (transform, &transform_matrix))
|
|
return;
|
|
|
|
shadows = gtk_css_shadows_value_get_shadows (shadows_value, &n_shadows);
|
|
if (shadows)
|
|
gtk_snapshot_push_shadow (snapshot, shadows, n_shadows, "IconShadow<%zu>", n_shadows);
|
|
|
|
if (graphene_matrix_is_identity (&transform_matrix))
|
|
{
|
|
graphene_rect_init (&bounds,
|
|
0, 0,
|
|
gsk_texture_get_width (texture) / texture_scale,
|
|
gsk_texture_get_height (texture) / texture_scale);
|
|
gtk_snapshot_append_texture_node (snapshot, texture, &bounds, "Icon");
|
|
}
|
|
else
|
|
{
|
|
graphene_matrix_t translate, matrix;
|
|
|
|
/* XXX: Implement -gtk-icon-transform-origin instead of hardcoding "50% 50%" here */
|
|
graphene_matrix_init_translate (&translate, &GRAPHENE_POINT3D_INIT (width / 2.0, height / 2.0, 0));
|
|
graphene_matrix_multiply (&transform_matrix, &translate, &matrix);
|
|
graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT(- width / 2.0, - height / 2.0, 0));
|
|
graphene_matrix_scale (&matrix, 1.0 / texture_scale, 1.0 / texture_scale, 1);
|
|
|
|
gtk_snapshot_push_transform (snapshot, &matrix, "Icon Transform");
|
|
|
|
graphene_rect_init (&bounds, 0, 0, gsk_texture_get_width (texture), gsk_texture_get_height (texture));
|
|
gtk_snapshot_append_texture_node (snapshot, texture, &bounds, "Icon");
|
|
|
|
gtk_snapshot_pop_and_append (snapshot);
|
|
}
|
|
|
|
if (shadows)
|
|
{
|
|
gtk_snapshot_pop_and_append (snapshot);
|
|
g_free (shadows);
|
|
}
|
|
}
|