Compare commits
7 Commits
gtkdoc-sub
...
wip/matthi
Author | SHA1 | Date | |
---|---|---|---|
|
7ac5d5c11b | ||
|
acf7819b76 | ||
|
3dc257dedd | ||
|
5040e10641 | ||
|
20bc851b77 | ||
|
ca501df049 | ||
|
7e7e59b4f4 |
@@ -45,6 +45,7 @@
|
||||
* @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
|
||||
* @GSK_TEXT_NODE: A node containing a glyph string
|
||||
*
|
||||
* The type of a node determines what the node is rendering.
|
||||
*
|
||||
@@ -69,7 +70,8 @@ typedef enum {
|
||||
GSK_ROUNDED_CLIP_NODE,
|
||||
GSK_SHADOW_NODE,
|
||||
GSK_BLEND_NODE,
|
||||
GSK_CROSS_FADE_NODE
|
||||
GSK_CROSS_FADE_NODE,
|
||||
GSK_TEXT_NODE
|
||||
} GskRenderNodeType;
|
||||
|
||||
/**
|
||||
|
@@ -174,6 +174,15 @@ GskRenderNode * gsk_cross_fade_node_new (GskRenderNode
|
||||
GskRenderNode *end,
|
||||
double progress);
|
||||
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode * gsk_text_node_new (PangoFont *font,
|
||||
PangoGlyphString *glyphs,
|
||||
const GdkRGBA *color,
|
||||
int x_offset,
|
||||
int y_offset,
|
||||
double base_x,
|
||||
double base_y);
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
void gsk_render_node_set_scaling_filters (GskRenderNode *node,
|
||||
GskScalingFilter min_filter,
|
||||
|
@@ -3801,6 +3801,248 @@ gsk_cross_fade_node_get_progress (GskRenderNode *node)
|
||||
return self->progress;
|
||||
}
|
||||
|
||||
/*** GSK_TEXT_NODE ***/
|
||||
|
||||
typedef struct _GskTextNode GskTextNode;
|
||||
|
||||
struct _GskTextNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
PangoFont *font;
|
||||
PangoGlyphString *glyphs;
|
||||
GdkRGBA color;
|
||||
int x_offset;
|
||||
int y_offset;
|
||||
double base_x;
|
||||
double base_y;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_text_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskTextNode *self = (GskTextNode *) node;
|
||||
|
||||
g_object_unref (self->font);
|
||||
pango_glyph_string_free (self->glyphs);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_pango_cairo_font_install (PangoFont *font,
|
||||
cairo_t *cr)
|
||||
{
|
||||
cairo_scaled_font_t *scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
|
||||
|
||||
if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS))
|
||||
return FALSE;
|
||||
|
||||
cairo_set_scaled_font (cr, scaled_font);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifndef STACK_BUFFER_SIZE
|
||||
#define STACK_BUFFER_SIZE (512 * sizeof (int))
|
||||
#endif
|
||||
|
||||
#define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T))
|
||||
|
||||
static void
|
||||
gsk_text_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskTextNode *self = (GskTextNode *) node;
|
||||
int i, count;
|
||||
int x_position = 0;
|
||||
cairo_glyph_t *cairo_glyphs;
|
||||
cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_translate (cr, self->x_offset, self->y_offset);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &self->color);
|
||||
if (!_pango_cairo_font_install (self->font, cr))
|
||||
goto done;
|
||||
|
||||
if (self->glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
|
||||
cairo_glyphs = g_new (cairo_glyph_t, self->glyphs->num_glyphs);
|
||||
else
|
||||
cairo_glyphs = stack_glyphs;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < self->glyphs->num_glyphs; i++)
|
||||
{
|
||||
PangoGlyphInfo *gi = &self->glyphs->glyphs[i];
|
||||
|
||||
if (gi->glyph != PANGO_GLYPH_EMPTY)
|
||||
{
|
||||
double cx = self->base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||
double cy = gi->geometry.y_offset == 0 ? self->base_y : self->base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
|
||||
|
||||
if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
|
||||
{
|
||||
cairo_glyphs[count].index = gi->glyph;
|
||||
cairo_glyphs[count].x = cx;
|
||||
cairo_glyphs[count].y = cy;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
x_position += gi->geometry.width;
|
||||
}
|
||||
|
||||
cairo_show_glyphs (cr, cairo_glyphs, count);
|
||||
|
||||
if (cairo_glyphs != stack_glyphs)
|
||||
g_free (cairo_glyphs);
|
||||
|
||||
done:
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
#define GSK_TEXT_NODE_VARIANT_TYPE "(sddddiidda(uiiii))"
|
||||
|
||||
static GVariant *
|
||||
gsk_text_node_serialize (GskRenderNode *node)
|
||||
{
|
||||
GskTextNode *self = (GskTextNode *) node;
|
||||
GVariant *v;
|
||||
GVariantBuilder builder;
|
||||
int i;
|
||||
PangoFontDescription *desc;
|
||||
char *s;
|
||||
|
||||
desc = pango_font_describe (self->font);
|
||||
s = pango_font_description_to_string (desc);
|
||||
for (i = 0; i < self->glyphs->num_glyphs; i++)
|
||||
{
|
||||
PangoGlyphInfo *glyph = &self->glyphs->glyphs[i];
|
||||
g_variant_builder_add (&builder, "(uiiii)",
|
||||
glyph->glyph,
|
||||
glyph->geometry.width,
|
||||
glyph->geometry.x_offset,
|
||||
glyph->geometry.y_offset,
|
||||
glyph->attr.is_cluster_start);
|
||||
}
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(uiiii)"));
|
||||
v = g_variant_new (GSK_TEXT_NODE_VARIANT_TYPE,
|
||||
s,
|
||||
self->color.red,
|
||||
self->color.green,
|
||||
self->color.blue,
|
||||
self->color.alpha,
|
||||
self->x_offset,
|
||||
self->y_offset,
|
||||
self->base_x,
|
||||
self->base_y,
|
||||
&builder);
|
||||
|
||||
g_free (s);
|
||||
pango_font_description_free (desc);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
gsk_text_node_deserialize (GVariant *variant,
|
||||
GError **error)
|
||||
{
|
||||
PangoFont *font;
|
||||
PangoGlyphString *glyphs;
|
||||
GVariantIter iter;
|
||||
GskRenderNode *result;
|
||||
PangoGlyphInfo glyph;
|
||||
PangoFontDescription *desc;
|
||||
PangoFontMap *fontmap;
|
||||
PangoContext *context;
|
||||
int cluster_start;
|
||||
char *s;
|
||||
GdkRGBA color;
|
||||
int x_offset, y_offset;
|
||||
double base_x, base_y;
|
||||
int i;
|
||||
|
||||
if (!check_variant_type (variant, GSK_TEXT_NODE_VARIANT_TYPE, error))
|
||||
return NULL;
|
||||
|
||||
g_variant_get (variant, "(&sddddiidda(uiiii))",
|
||||
&color.red, &color.green, &color.blue, &color.alpha,
|
||||
&x_offset, &y_offset,
|
||||
&base_x, &base_y,
|
||||
&s, &iter);
|
||||
|
||||
desc = pango_font_description_from_string (s);
|
||||
fontmap = pango_cairo_font_map_get_default ();
|
||||
context = pango_font_map_create_context (fontmap);
|
||||
font = pango_font_map_load_font (fontmap, context, desc);
|
||||
|
||||
glyphs = pango_glyph_string_new ();
|
||||
pango_glyph_string_set_size (glyphs, g_variant_iter_n_children (&iter));
|
||||
i = 0;
|
||||
while (g_variant_iter_next (&iter, "(uiiii)", &glyph.glyph, &glyph.geometry.width, &glyph.geometry.x_offset, &glyph.geometry.y_offset, &cluster_start))
|
||||
{
|
||||
glyph.attr.is_cluster_start = cluster_start;
|
||||
glyphs->glyphs[i] = glyph;
|
||||
i++;
|
||||
}
|
||||
|
||||
result = gsk_text_node_new (font, glyphs, &color, /* FIXME: Avoid copying glyphs */
|
||||
x_offset, y_offset,
|
||||
base_x, base_y);
|
||||
|
||||
pango_glyph_string_free (glyphs);
|
||||
pango_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
g_object_unref (font);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const GskRenderNodeClass GSK_TEXT_NODE_CLASS = {
|
||||
GSK_TEXT_NODE,
|
||||
sizeof (GskTextNode),
|
||||
"GskTextNode",
|
||||
gsk_text_node_finalize,
|
||||
gsk_text_node_draw,
|
||||
gsk_text_node_serialize,
|
||||
gsk_text_node_deserialize
|
||||
};
|
||||
|
||||
GskRenderNode *
|
||||
gsk_text_node_new (PangoFont *font,
|
||||
PangoGlyphString *glyphs,
|
||||
const GdkRGBA *color,
|
||||
int x_offset,
|
||||
int y_offset,
|
||||
double base_x,
|
||||
double base_y)
|
||||
{
|
||||
GskTextNode *self;
|
||||
PangoRectangle ink_rect;
|
||||
|
||||
self = (GskTextNode *) gsk_render_node_new (&GSK_TEXT_NODE_CLASS, 0);
|
||||
|
||||
self->font = g_object_ref (font);
|
||||
self->glyphs = pango_glyph_string_copy (glyphs);
|
||||
self->color = *color;
|
||||
self->x_offset = x_offset;
|
||||
self->y_offset = y_offset;
|
||||
self->base_x = base_x;
|
||||
self->base_y = base_y;
|
||||
|
||||
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
|
||||
pango_extents_to_pixels (&ink_rect, NULL);
|
||||
|
||||
graphene_rect_init (&self->render_node.bounds,
|
||||
x_offset + base_x + ink_rect.x,
|
||||
y_offset + base_y + ink_rect.y,
|
||||
ink_rect.width,
|
||||
ink_rect.height);
|
||||
|
||||
return &self->render_node;
|
||||
}
|
||||
|
||||
static const GskRenderNodeClass *klasses[] = {
|
||||
[GSK_CONTAINER_NODE] = &GSK_CONTAINER_NODE_CLASS,
|
||||
[GSK_CAIRO_NODE] = &GSK_CAIRO_NODE_CLASS,
|
||||
@@ -3818,7 +4060,8 @@ static const GskRenderNodeClass *klasses[] = {
|
||||
[GSK_ROUNDED_CLIP_NODE] = &GSK_ROUNDED_CLIP_NODE_CLASS,
|
||||
[GSK_SHADOW_NODE] = &GSK_SHADOW_NODE_CLASS,
|
||||
[GSK_BLEND_NODE] = &GSK_BLEND_NODE_CLASS,
|
||||
[GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS
|
||||
[GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS,
|
||||
[GSK_TEXT_NODE] = &GSK_TEXT_NODE_CLASS
|
||||
};
|
||||
|
||||
GskRenderNode *
|
||||
|
431
gtk/gskpango.c
Normal file
431
gtk/gskpango.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gsk/gsk.h"
|
||||
#include "gskpango.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
#define GSK_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_PANGO_RENDERER, GskPangoRendererClass))
|
||||
#define GSK_IS_PANGO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_PANGO_RENDERER))
|
||||
#define GSK_PANGO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_PANGO_RENDERER, GskPangoRendererClass))
|
||||
|
||||
struct _GskPangoRenderer
|
||||
{
|
||||
PangoRenderer parent_instance;
|
||||
|
||||
GtkSnapshot *snapshot;
|
||||
const GdkRGBA *fg_color;
|
||||
double x_offset, y_offset;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
/* house-keeping options */
|
||||
gboolean is_cached_renderer;
|
||||
};
|
||||
|
||||
struct _GskPangoRendererClass
|
||||
{
|
||||
PangoRendererClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskPangoRenderer, gsk_pango_renderer, PANGO_TYPE_RENDERER)
|
||||
|
||||
static void
|
||||
get_color (GskPangoRenderer *crenderer,
|
||||
PangoRenderPart part,
|
||||
GdkRGBA *rgba)
|
||||
{
|
||||
PangoColor *color = pango_renderer_get_color ((PangoRenderer *) (crenderer), part);
|
||||
guint16 a = pango_renderer_get_alpha ((PangoRenderer *) (crenderer), part);
|
||||
gdouble red, green, blue, alpha;
|
||||
|
||||
red = crenderer->fg_color->red;
|
||||
green = crenderer->fg_color->green;
|
||||
blue = crenderer->fg_color->blue;
|
||||
alpha = crenderer->fg_color->alpha;
|
||||
|
||||
if (color)
|
||||
{
|
||||
red = color->red / 65535.;
|
||||
green = color->green / 65535.;
|
||||
blue = color->blue / 65535.;
|
||||
alpha = 1.;
|
||||
}
|
||||
|
||||
if (a)
|
||||
alpha = a / 65535.;
|
||||
|
||||
rgba->red = red;
|
||||
rgba->green = green;
|
||||
rgba->blue = blue;
|
||||
rgba->alpha = alpha;
|
||||
}
|
||||
|
||||
static void
|
||||
set_color (GskPangoRenderer *crenderer,
|
||||
PangoRenderPart part,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GdkRGBA rgba = { 0, 0, 0, 1 };
|
||||
|
||||
get_color (crenderer, part, &rgba);
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_show_text_glyphs (PangoRenderer *renderer,
|
||||
const char *text,
|
||||
int text_len,
|
||||
PangoGlyphString *glyphs,
|
||||
cairo_text_cluster_t *clusters,
|
||||
int num_clusters,
|
||||
gboolean backward,
|
||||
PangoFont *font,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
|
||||
double base_x = (double)x / PANGO_SCALE;
|
||||
double base_y = (double)y / PANGO_SCALE;
|
||||
int x_offset, y_offset;
|
||||
GdkRGBA color;
|
||||
GskRenderNode *node;
|
||||
char name[64];
|
||||
|
||||
gtk_snapshot_get_offset (crenderer->snapshot, &x_offset, &y_offset);
|
||||
|
||||
gtk_snapshot_offset (crenderer->snapshot, base_x, base_y);
|
||||
|
||||
get_color (crenderer, PANGO_RENDER_PART_FOREGROUND, &color);
|
||||
|
||||
node = gsk_text_node_new (font, glyphs, &color, x_offset, y_offset, base_x, base_y);
|
||||
snprintf (name, sizeof (name), "Glyphs<%d>", glyphs->num_glyphs);
|
||||
gsk_render_node_set_name (node, name);
|
||||
gtk_snapshot_append_node (crenderer->snapshot, node);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gtk_snapshot_offset (crenderer->snapshot, -base_x, -base_y);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_draw_glyphs (PangoRenderer *renderer,
|
||||
PangoFont *font,
|
||||
PangoGlyphString *glyphs,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
gsk_pango_renderer_show_text_glyphs (renderer, NULL, 0, glyphs, NULL, 0, FALSE, font, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_draw_glyph_item (PangoRenderer *renderer,
|
||||
const char *text,
|
||||
PangoGlyphItem *glyph_item,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
PangoFont *font = glyph_item->item->analysis.font;
|
||||
PangoGlyphString *glyphs = glyph_item->glyphs;
|
||||
|
||||
gsk_pango_renderer_show_text_glyphs (renderer, NULL, 0, glyphs, NULL, 0, FALSE, font, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
|
||||
PangoRenderPart part,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
|
||||
GdkRGBA rgba;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
get_color (crenderer, part, &rgba);
|
||||
|
||||
graphene_rect_init (&bounds,
|
||||
crenderer->x_offset + (double)x / PANGO_SCALE,
|
||||
crenderer->y_offset + (double)y / PANGO_SCALE,
|
||||
(double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
|
||||
|
||||
gtk_snapshot_append_color (crenderer->snapshot, &rgba, &bounds, "DrawRectangle");
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_draw_trapezoid (PangoRenderer *renderer,
|
||||
PangoRenderPart part,
|
||||
double y1_,
|
||||
double x11,
|
||||
double x21,
|
||||
double y2,
|
||||
double x12,
|
||||
double x22)
|
||||
{
|
||||
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
|
||||
cairo_t *cr;
|
||||
gdouble x, y;
|
||||
|
||||
cr = gtk_snapshot_append_cairo (crenderer->snapshot, &crenderer->bounds, "DrawTrapezoid");
|
||||
|
||||
set_color (crenderer, part, cr);
|
||||
|
||||
x = crenderer->x_offset,
|
||||
y = crenderer->y_offset;
|
||||
cairo_user_to_device_distance (cr, &x, &y);
|
||||
cairo_identity_matrix (cr);
|
||||
cairo_translate (cr, x, y);
|
||||
|
||||
cairo_move_to (cr, x11, y1_);
|
||||
cairo_line_to (cr, x21, y1_);
|
||||
cairo_line_to (cr, x22, y2);
|
||||
cairo_line_to (cr, x12, y2);
|
||||
cairo_close_path (cr);
|
||||
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
/* Draws an error underline that looks like one of:
|
||||
* H E H
|
||||
* /\ /\ /\ /\ /\ -
|
||||
* A/ \ / \ / \ A/ \ / \ |
|
||||
* \ \ / \ / /D \ \ / \ |
|
||||
* \ \/ C \/ / \ \/ C \ | height = HEIGHT_SQUARES * square
|
||||
* \ /\ F / \ F /\ \ |
|
||||
* \ / \ / \ / \ \G |
|
||||
* \ / \ / \ / \ / |
|
||||
* \/ \/ \/ \/ -
|
||||
* B B
|
||||
* |---|
|
||||
* unit_width = (HEIGHT_SQUARES - 1) * square
|
||||
*
|
||||
* The x, y, width, height passed in give the desired bounding box;
|
||||
* x/width are adjusted to make the underline a integer number of units
|
||||
* wide.
|
||||
*/
|
||||
#define HEIGHT_SQUARES 2.5
|
||||
|
||||
static void
|
||||
draw_error_underline (cairo_t *cr,
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
double square = height / HEIGHT_SQUARES;
|
||||
double unit_width = (HEIGHT_SQUARES - 1) * square;
|
||||
double double_width = 2 * unit_width;
|
||||
int width_units = (width + unit_width / 2) / unit_width;
|
||||
double y_top, y_bottom;
|
||||
double x_left, x_middle, x_right;
|
||||
int i;
|
||||
|
||||
x += (width - width_units * unit_width) / 2;
|
||||
|
||||
y_top = y;
|
||||
y_bottom = y + height;
|
||||
|
||||
/* Bottom of squiggle */
|
||||
x_middle = x + unit_width;
|
||||
x_right = x + double_width;
|
||||
cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
|
||||
for (i = 0; i < width_units-2; i += 2)
|
||||
{
|
||||
cairo_line_to (cr, x_middle, y_bottom); /* B */
|
||||
cairo_line_to (cr, x_right, y_top + square); /* C */
|
||||
|
||||
x_middle += double_width;
|
||||
x_right += double_width;
|
||||
}
|
||||
cairo_line_to (cr, x_middle, y_bottom); /* B */
|
||||
|
||||
if (i + 1 == width_units)
|
||||
cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
|
||||
else if (i + 2 == width_units) {
|
||||
cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
|
||||
cairo_line_to (cr, x_right, y_top); /* E */
|
||||
}
|
||||
|
||||
/* Top of squiggle */
|
||||
x_left = x_middle - unit_width;
|
||||
for (; i >= 0; i -= 2)
|
||||
{
|
||||
cairo_line_to (cr, x_middle, y_bottom - square); /* F */
|
||||
cairo_line_to (cr, x_left, y_top); /* H */
|
||||
|
||||
x_left -= double_width;
|
||||
x_middle -= double_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_draw_error_underline (PangoRenderer *renderer,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
|
||||
cairo_t *cr;
|
||||
|
||||
cr = gtk_snapshot_append_cairo (crenderer->snapshot, &crenderer->bounds, "DrawTrapezoid");
|
||||
|
||||
set_color (crenderer, PANGO_RENDER_PART_UNDERLINE, cr);
|
||||
|
||||
cairo_new_path (cr);
|
||||
|
||||
draw_error_underline (cr,
|
||||
crenderer->x_offset + (double)x / PANGO_SCALE,
|
||||
crenderer->y_offset + (double)y / PANGO_SCALE,
|
||||
(double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
|
||||
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_draw_shape (PangoRenderer *renderer,
|
||||
PangoAttrShape *attr,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
|
||||
cairo_t *cr;
|
||||
PangoLayout *layout;
|
||||
PangoCairoShapeRendererFunc shape_renderer;
|
||||
gpointer shape_renderer_data;
|
||||
double base_x, base_y;
|
||||
|
||||
cr = gtk_snapshot_append_cairo (crenderer->snapshot, &crenderer->bounds, "DrawShape");
|
||||
|
||||
layout = pango_renderer_get_layout (renderer);
|
||||
if (!layout)
|
||||
return;
|
||||
|
||||
shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout),
|
||||
&shape_renderer_data);
|
||||
|
||||
if (!shape_renderer)
|
||||
return;
|
||||
|
||||
base_x = crenderer->x_offset + (double)x / PANGO_SCALE;
|
||||
base_y = crenderer->y_offset + (double)y / PANGO_SCALE;
|
||||
|
||||
set_color (crenderer, PANGO_RENDER_PART_FOREGROUND, cr);
|
||||
|
||||
cairo_move_to (cr, base_x, base_y);
|
||||
|
||||
shape_renderer (cr, attr, FALSE, shape_renderer_data);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_init (GskPangoRenderer *renderer G_GNUC_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pango_renderer_class_init (GskPangoRendererClass *klass)
|
||||
{
|
||||
PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
|
||||
|
||||
renderer_class->draw_glyphs = gsk_pango_renderer_draw_glyphs;
|
||||
renderer_class->draw_glyph_item = gsk_pango_renderer_draw_glyph_item;
|
||||
renderer_class->draw_rectangle = gsk_pango_renderer_draw_rectangle;
|
||||
renderer_class->draw_trapezoid = gsk_pango_renderer_draw_trapezoid;
|
||||
renderer_class->draw_error_underline = gsk_pango_renderer_draw_error_underline;
|
||||
renderer_class->draw_shape = gsk_pango_renderer_draw_shape;
|
||||
}
|
||||
|
||||
static GskPangoRenderer *cached_renderer = NULL; /* MT-safe */
|
||||
G_LOCK_DEFINE_STATIC (cached_renderer);
|
||||
|
||||
static GskPangoRenderer *
|
||||
acquire_renderer (void)
|
||||
{
|
||||
GskPangoRenderer *renderer;
|
||||
|
||||
if (G_LIKELY (G_TRYLOCK (cached_renderer)))
|
||||
{
|
||||
if (G_UNLIKELY (!cached_renderer))
|
||||
{
|
||||
cached_renderer = g_object_new (GSK_TYPE_PANGO_RENDERER, NULL);
|
||||
cached_renderer->is_cached_renderer = TRUE;
|
||||
}
|
||||
|
||||
renderer = cached_renderer;
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer = g_object_new (GSK_TYPE_PANGO_RENDERER, NULL);
|
||||
}
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
static void
|
||||
release_renderer (GskPangoRenderer *renderer)
|
||||
{
|
||||
if (G_LIKELY (renderer->is_cached_renderer))
|
||||
{
|
||||
renderer->snapshot = NULL;
|
||||
renderer->x_offset = 0.;
|
||||
renderer->y_offset = 0.;
|
||||
|
||||
G_UNLOCK (cached_renderer);
|
||||
}
|
||||
else
|
||||
g_object_unref (renderer);
|
||||
}
|
||||
|
||||
/* convenience wrappers using the default renderer */
|
||||
|
||||
void
|
||||
gsk_pango_show_layout (GtkSnapshot *snapshot,
|
||||
const GdkRGBA *fg_color,
|
||||
PangoLayout *layout)
|
||||
{
|
||||
GskPangoRenderer *crenderer;
|
||||
PangoRectangle ink_rect;
|
||||
|
||||
g_return_if_fail (snapshot != NULL);
|
||||
g_return_if_fail (PANGO_IS_LAYOUT (layout));
|
||||
|
||||
crenderer = acquire_renderer ();
|
||||
|
||||
crenderer->snapshot = snapshot;
|
||||
crenderer->fg_color = fg_color;
|
||||
crenderer->x_offset = crenderer->y_offset = 0;
|
||||
|
||||
pango_layout_get_pixel_extents (layout, &ink_rect, NULL);
|
||||
graphene_rect_init (&crenderer->bounds, ink_rect.x, ink_rect.y, ink_rect.width, ink_rect.height);
|
||||
|
||||
pango_renderer_draw_layout (PANGO_RENDERER (crenderer), layout, 0, 0);
|
||||
|
||||
release_renderer (crenderer);
|
||||
}
|
45
gtk/gskpango.h
Normal file
45
gtk/gskpango.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* GSK - The GTK Scene Kit
|
||||
*
|
||||
* Copyright 2017 Red Hat, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GSK_PANGO_H__
|
||||
#define __GSK_PANGO_H__
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include "gtk/gtksnapshot.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_PANGO_RENDERER (gsk_pango_renderer_get_type ())
|
||||
|
||||
#define GSK_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_PANGO_RENDERER, GskPangoRenderer))
|
||||
#define GSK_IS_PANGO_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_PANGO_RENDERER))
|
||||
|
||||
typedef struct _GskPangoRenderer GskPangoRenderer;
|
||||
typedef struct _GskPangoRendererClass GskPangoRendererClass;
|
||||
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GType gsk_pango_renderer_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
void gsk_pango_show_layout (GtkSnapshot *snapshot,
|
||||
const GdkRGBA *fg_color,
|
||||
PangoLayout *layout);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_PANGO_H__ */
|
@@ -29,6 +29,8 @@
|
||||
|
||||
#include "gsk/gskrendernodeprivate.h"
|
||||
|
||||
#include "gtk/gskpango.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:gtksnapshot
|
||||
@@ -1330,36 +1332,42 @@ gtk_snapshot_render_layout (GtkSnapshot *snapshot,
|
||||
PangoLayout *layout)
|
||||
{
|
||||
const GdkRGBA *fg_color;
|
||||
graphene_rect_t bounds;
|
||||
GtkBorder shadow_extents;
|
||||
PangoRectangle ink_rect;
|
||||
GtkCssValue *shadow;
|
||||
cairo_t *cr;
|
||||
|
||||
g_return_if_fail (snapshot != NULL);
|
||||
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
|
||||
g_return_if_fail (PANGO_IS_LAYOUT (layout));
|
||||
|
||||
fg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR));
|
||||
shadow = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_TEXT_SHADOW);
|
||||
pango_layout_get_pixel_extents (layout, &ink_rect, NULL);
|
||||
_gtk_css_shadows_value_get_extents (shadow, &shadow_extents);
|
||||
graphene_rect_init (&bounds,
|
||||
ink_rect.x - shadow_extents.left,
|
||||
ink_rect.y - shadow_extents.top,
|
||||
ink_rect.width + shadow_extents.left + shadow_extents.right,
|
||||
ink_rect.height + shadow_extents.top + shadow_extents.bottom);
|
||||
|
||||
gtk_snapshot_offset (snapshot, x, y);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &bounds, "Text<%dchars>", pango_layout_get_character_count (layout));
|
||||
fg_color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR));
|
||||
|
||||
_gtk_css_shadows_value_paint_layout (shadow, cr, layout);
|
||||
shadow = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_TEXT_SHADOW);
|
||||
if (!_gtk_css_shadows_value_is_none (shadow))
|
||||
{
|
||||
PangoRectangle ink_rect;
|
||||
graphene_rect_t bounds;
|
||||
GtkBorder shadow_extents = { 0, };
|
||||
cairo_t *cr;
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, fg_color);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
pango_layout_get_pixel_extents (layout, &ink_rect, NULL);
|
||||
_gtk_css_shadows_value_get_extents (shadow, &shadow_extents);
|
||||
graphene_rect_init (&bounds,
|
||||
ink_rect.x - shadow_extents.left,
|
||||
ink_rect.y - shadow_extents.top,
|
||||
ink_rect.width + shadow_extents.left + shadow_extents.right,
|
||||
ink_rect.height + shadow_extents.top + shadow_extents.bottom);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &bounds, "Text<%dchars>", pango_layout_get_character_count (layout));
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, fg_color);
|
||||
|
||||
_gtk_css_shadows_value_paint_layout (shadow, cr, layout);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
gsk_pango_show_layout (snapshot, fg_color, layout);
|
||||
|
||||
cairo_destroy (cr);
|
||||
gtk_snapshot_offset (snapshot, -x, -y);
|
||||
}
|
||||
|
||||
|
@@ -523,6 +523,7 @@ append_node (GtkTreeModelRenderNode *nodemodel,
|
||||
break;
|
||||
|
||||
case GSK_CAIRO_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
|
@@ -181,6 +181,8 @@ node_type_name (GskRenderNodeType type)
|
||||
return "Blend";
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
return "CrossFade";
|
||||
case GSK_TEXT_NODE:
|
||||
return "Text";
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -231,6 +231,7 @@ gtk_public_sources = files([
|
||||
'gtkpagesetup.c',
|
||||
'gtkpaned.c',
|
||||
'gtkpango.c',
|
||||
'gskpango.c',
|
||||
'gtkpapersize.c',
|
||||
'gtkpathbar.c',
|
||||
'gtkplacessidebar.c',
|
||||
|
Reference in New Issue
Block a user