Compare commits

...

10 Commits

Author SHA1 Message Date
Matthias Clasen 4ced8d1803 Add a simple example 2021-04-01 08:01:01 -04:00
Matthias Clasen 14b1873e5a Implement dashed and dotted underlines
This is implementing rendering dashed and dotted lines, using
a private attribute that can be added to PangoItems after layout.

This is currently using a linear gradient for dashes and a repeat
node for dots.
2021-04-01 07:59:57 -04:00
Matthias Clasen b5df1299ec gsk: Add another test
Compare clipped repeat nodes. Must skip cairo here
since it blurred the child by scaling after rendering.

Also skip the gl renderer, since it hasn't been fixed
for this yet. ngl passes this test.
2021-03-31 16:49:31 -04:00
Matthias Clasen 6f62107656 testsuite: Rename next to ngl
Use specific names for renderers in the gsk tests.
Otherwise the tests may use the wrong renderer, or
the same renderer twice.
2021-03-31 14:59:43 -04:00
Matthias Clasen f9457af128 ngl: Fix offscreen rendering with transforms
There was confusion here about the handling of the
modelview transform. The modelview transform we are
getting is already set up for rendering the node
we are given, so keep it - except for possible adding
an extra scale on top when the texture would otherwise
be too big.
2021-03-31 14:36:24 -04:00
Matthias Clasen 94f0a4ef2c ngl: Be explicit about offscreen clipping
Explicitly set all the input arguments.
This makes it clearer what is going on.
2021-03-31 14:34:16 -04:00
Matthias Clasen 53e75936cb ngl: Add sonme comments
The GskNglRenderOffscreen struct is a mix of in and
out arguments. Better annotate that a little bit.
2021-03-31 14:32:47 -04:00
Anders Jonsson 6c95fc7e87 Update Swedish translation 2021-03-30 17:13:11 +00:00
Matthias Clasen f4cc9a47ad Merge branch 'docs' into 'master'
docs: Cover corner-case of @line_number = total lines in buffer

See merge request GNOME/gtk!3373
2021-03-30 16:09:34 +00:00
Avinash Sonawane 622bb9186e docs: Cover corner-case of @line_number = total lines in buffer 2021-03-30 17:00:33 +05:30
13 changed files with 1279 additions and 982 deletions
+22 -10
View File
@@ -163,18 +163,29 @@ struct _GskNglRenderJob
typedef struct _GskNglRenderOffscreen
{
/* The bounds to render */
const graphene_rect_t *bounds;
/* Return location for texture coordinates */
struct {
float x;
float y;
float x2;
float y2;
} area;
/* Return location for texture ID */
guint texture_id;
/* Whether to force creating a new texture, even if the
* input already is a texture
*/
guint force_offscreen : 1;
guint reset_clip : 1;
guint do_not_cache : 1;
guint linear_filter : 1;
/* Return location for whether we created a texture */
guint was_offscreen : 1;
} GskNglRenderOffscreen;
@@ -1594,6 +1605,7 @@ gsk_ngl_render_job_visit_rounded_clip_node (GskNglRenderJob *job,
offscreen.bounds = &node->bounds;
offscreen.force_offscreen = TRUE;
offscreen.reset_clip = FALSE;
gsk_ngl_render_job_push_clip (job, &transformed_clip);
if (!gsk_ngl_render_job_visit_node_with_offscreen (job, child, &offscreen))
@@ -3554,8 +3566,8 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job,
float scaled_width;
float scaled_height;
float scale_x = job->scale_x;
float scale_y = job->scale_y;
float downscale_x = 1;
float downscale_y = 1;
g_assert (job->command_queue->max_texture_size > 0);
@@ -3566,17 +3578,17 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job,
{
int max_texture_size = job->command_queue->max_texture_size;
scaled_width = ceilf (offscreen->bounds->size.width * scale_x);
scaled_width = ceilf (offscreen->bounds->size.width * job->scale_x);
if (scaled_width > max_texture_size)
{
scale_x *= (float)max_texture_size / scaled_width;
downscale_x = (float)max_texture_size / scaled_width;
scaled_width = max_texture_size;
}
scaled_height = ceilf (offscreen->bounds->size.height * scale_y);
scaled_height = ceilf (offscreen->bounds->size.height * job->scale_y);
if (scaled_height > max_texture_size)
{
scale_y *= (float)max_texture_size / scaled_height;
downscale_y = (float)max_texture_size / scaled_height;
scaled_height = max_texture_size;
}
}
@@ -3620,10 +3632,9 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job,
gsk_ngl_render_job_set_viewport (job, &viewport, &prev_viewport);
gsk_ngl_render_job_set_projection_from_rect (job, &job->viewport, &prev_projection);
gsk_ngl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_x, scale_y));
if (downscale_x != 1 || downscale_y != 1)
gsk_ngl_render_job_push_modelview (job, gsk_transform_scale (NULL, downscale_x, downscale_y));
prev_alpha = gsk_ngl_render_job_set_alpha (job, 1.0f);
job->offset_x = offset_x;
job->offset_y = offset_y;
prev_fbo = gsk_ngl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
gsk_ngl_command_queue_clear (job->command_queue, 0, &job->viewport);
@@ -3636,7 +3647,8 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job,
if (offscreen->reset_clip)
gsk_ngl_render_job_pop_clip (job);
gsk_ngl_render_job_pop_modelview (job);
if (downscale_x != 1 || downscale_y != 1)
gsk_ngl_render_job_pop_modelview (job);
gsk_ngl_render_job_set_viewport (job, &prev_viewport, NULL);
gsk_ngl_render_job_set_projection (job, &prev_projection);
gsk_ngl_render_job_set_alpha (job, prev_alpha);
+103 -12
View File
@@ -108,23 +108,88 @@ gsk_pango_renderer_draw_glyph_item (PangoRenderer *renderer,
}
static void
gsk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
PangoRenderPart part,
int x,
int y,
int width,
int height)
gsk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
PangoRenderPart part,
int x,
int y,
int width,
int height)
{
GskPangoRenderer *crenderer = (GskPangoRenderer *) (renderer);
GdkRGBA rgba;
double xx, yy, ww, hh;
GtkLineStyle line_style;
xx = (double)x / PANGO_SCALE;
yy = (double)y / PANGO_SCALE;
ww = (double)width / PANGO_SCALE;
hh = (double)height / PANGO_SCALE;
get_color (crenderer, part, &rgba);
gtk_snapshot_append_color (crenderer->snapshot,
&rgba,
&GRAPHENE_RECT_INIT ((double)x / PANGO_SCALE,
(double)y / PANGO_SCALE,
(double)width / PANGO_SCALE,
(double)height / PANGO_SCALE));
if (part == PANGO_RENDER_PART_UNDERLINE ||
part == PANGO_RENDER_PART_STRIKETHROUGH ||
part == PANGO_RENDER_PART_OVERLINE)
line_style = crenderer->line_style;
else
line_style = GTK_LINE_STYLE_SOLID;
switch (line_style)
{
case GTK_LINE_STYLE_SOLID:
gtk_snapshot_append_color (crenderer->snapshot,
&rgba,
&GRAPHENE_RECT_INIT (xx, yy, ww, hh));
break;
case GTK_LINE_STYLE_DOTTED:
{
GskRoundedRect dot;
double d = hh;
graphene_rect_t bounds = GRAPHENE_RECT_INIT (xx, yy, d, d);
graphene_size_t rr = GRAPHENE_SIZE_INIT (d/2, d/2);
GdkRGBA transparent = { 0.f, 0.f, 0.f, 0.f };
gsk_rounded_rect_init (&dot, &bounds, &rr, &rr, &rr, &rr);
gtk_snapshot_push_repeat (crenderer->snapshot,
&GRAPHENE_RECT_INIT (xx, yy, ww, hh),
NULL);
gtk_snapshot_push_rounded_clip (crenderer->snapshot, &dot);
gtk_snapshot_append_color (crenderer->snapshot, &rgba, &bounds);
gtk_snapshot_pop (crenderer->snapshot);
gtk_snapshot_append_color (crenderer->snapshot, &transparent, &GRAPHENE_RECT_INIT (xx + d, yy, 0.5 * d, d));
gtk_snapshot_pop (crenderer->snapshot);
}
break;
case GTK_LINE_STYLE_DASHED:
{
GskColorStop stops[4];
GdkRGBA transparent = { 0.f, 0.f, 0.f, 0.f };
stops[0].offset = 0;
stops[0].color = rgba;
stops[1].offset = 0.66;
stops[1].color = rgba;
stops[2].offset = 0.66;
stops[2].color = transparent;
stops[3].offset = 1;
stops[3].color = transparent;
gtk_snapshot_append_repeating_linear_gradient (
crenderer->snapshot,
&GRAPHENE_RECT_INIT (xx, yy, ww, hh),
&GRAPHENE_POINT_INIT (xx, yy),
&GRAPHENE_POINT_INIT (xx + 9 * MIN (ww, hh), yy),
stops, 4);
}
break;
default:
g_assert_not_reached ();
}
}
static void
@@ -343,6 +408,24 @@ get_item_appearance (PangoItem *item)
return NULL;
}
static GtkLineStyle
get_item_line_style (PangoItem *item)
{
GSList *tmp_list = item->analysis.extra_attrs;
while (tmp_list)
{
PangoAttribute *attr = tmp_list->data;
if (attr->klass->type == gtk_text_attr_line_style_type)
return ((GtkTextAttrLineStyle *)attr)->value;
tmp_list = tmp_list->next;
}
return GTK_LINE_STYLE_SOLID;
}
static void
gsk_pango_renderer_prepare_run (PangoRenderer *renderer,
PangoLayoutRun *run)
@@ -351,9 +434,17 @@ gsk_pango_renderer_prepare_run (PangoRenderer *renderer,
const GdkRGBA *bg_rgba = NULL;
const GdkRGBA *fg_rgba = NULL;
GtkTextAppearance *appearance;
GtkLineStyle line_style;
PANGO_RENDERER_CLASS (gsk_pango_renderer_parent_class)->prepare_run (renderer, run);
line_style = get_item_line_style (run->item);
if (crenderer->line_style != line_style)
{
pango_renderer_part_changed (renderer, PANGO_RENDER_PART_UNDERLINE);
crenderer->line_style = get_item_line_style (run->item);
}
appearance = get_item_appearance (run->item);
if (appearance == NULL)
+3
View File
@@ -21,6 +21,7 @@
#include <pango/pango.h>
#include "gtk/gtksnapshot.h"
#include "gtk/gtktextlayoutprivate.h"
G_BEGIN_DECLS
@@ -68,6 +69,8 @@ struct _GskPangoRenderer
guint is_cached_renderer : 1;
GskPangoShapeHandler shape_handler;
GtkLineStyle line_style;
};
struct _GskPangoRendererClass
+81
View File
@@ -52,6 +52,7 @@
#include "gtkdragsourceprivate.h"
#include "gtkdragicon.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtktextlayoutprivate.h"
#include <math.h>
#include <string.h>
@@ -1259,6 +1260,85 @@ gtk_label_size_allocate (GtkWidget *widget,
}
static void
add_dotted_underline (PangoLayout *layout)
{
const char *text;
char *p;
GSList *l, *ll, *a;
text = pango_layout_get_text (layout);
p = strstr (text, "good");
for (int i = 0; i < pango_layout_get_line_count (layout); i++)
{
PangoLayoutLine *line = pango_layout_get_line (layout, i);
for (l = line->runs, ll = NULL; l; ll = l, l = l->next)
{
PangoGlyphItem *run = l->data;
if (run == NULL)
continue;
if (p != NULL && text + run->item->offset <= p && p + strlen ("good") <= text + run->item->offset + run->item->length)
{
/* Match inside this item */
if (text + run->item->offset < p)
{
PangoGlyphItem *before;
/* split off initial segment */
before = pango_glyph_item_split (run, text, p - (text + run->item->offset));
if (ll)
{
ll->next = g_slist_prepend (l, before);
ll = ll->next;
}
else
{
line->runs = g_slist_prepend (line->runs, before);
ll = line->runs;
}
}
if (p + strlen ("good") < text + run->item->offset + run->item->length)
{
/* split off final segment */
run = pango_glyph_item_split (run, text, strlen ("good"));
if (ll)
ll->next = g_slist_prepend (l, run);
else
line->runs = g_slist_prepend (line->runs, run);
}
for (a = run->item->analysis.extra_attrs; a; a = a->next)
{
PangoAttribute *attr = a->data;
if (attr->klass->type == gtk_text_attr_line_style_type)
break;
}
if (a == NULL)
{
PangoAttribute *attr;
attr = gtk_text_attr_line_style_new (GTK_LINE_STYLE_DOTTED);
run->item->analysis.extra_attrs =
g_slist_prepend (run->item->analysis.extra_attrs, attr);
attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
run->item->analysis.extra_attrs =
g_slist_prepend (run->item->analysis.extra_attrs, attr);
}
return;
}
}
}
}
#define GRAPHENE_RECT_FROM_RECT(_r) (GRAPHENE_RECT_INIT ((_r)->x, (_r)->y, (_r)->width, (_r)->height))
@@ -1280,6 +1360,7 @@ gtk_label_snapshot (GtkWidget *widget,
context = _gtk_widget_get_style_context (widget);
get_layout_location (self, &lx, &ly);
add_dotted_underline (self->layout);
gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout);
info = self->select_info;
+3 -3
View File
@@ -3250,7 +3250,7 @@ gtk_text_buffer_remove_all_tags (GtkTextBuffer *buffer,
* Note characters, not bytes; UTF-8 may encode one character as multiple
* bytes.
*
* If @line_number is greater than the number of lines in the @buffer,
* If @line_number is greater than or equal to the number of lines in the @buffer,
* the end iterator is returned. And if @char_offset is off the
* end of the line, the iterator at the end of the line is returned.
*
@@ -3301,7 +3301,7 @@ gtk_text_buffer_get_iter_at_line_offset (GtkTextBuffer *buffer,
* @byte_index must be the start of a UTF-8 character. Note bytes, not
* characters; UTF-8 may encode one character as multiple bytes.
*
* If @line_number is greater than the number of lines in the @buffer,
* If @line_number is greater than or equal to the number of lines in the @buffer,
* the end iterator is returned. And if @byte_index is off the
* end of the line, the iterator at the end of the line is returned.
*
@@ -3348,7 +3348,7 @@ gtk_text_buffer_get_iter_at_line_index (GtkTextBuffer *buffer,
*
* Initializes @iter to the start of the given line.
*
* If @line_number is greater than the number of lines
* If @line_number is greater than or equal to the number of lines
* in the @buffer, the end iterator is returned.
*
* Returns: whether the exact position has been found
+1 -1
View File
@@ -4052,7 +4052,7 @@ gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
*
* Moves iterator @iter to the start of the line @line_number.
*
* If @line_number is negative or larger than the number of lines
* If @line_number is negative or larger than or equal to the number of lines
* in the buffer, moves @iter to the start of the last line in the buffer.
*/
void
+45
View File
@@ -1512,6 +1512,51 @@ gtk_text_attr_appearance_new (const GtkTextAppearance *appearance)
return (PangoAttribute *)result;
}
static PangoAttribute *
attr_line_style_copy (const PangoAttribute *attr)
{
const GtkTextAttrLineStyle *a = (GtkTextAttrLineStyle *)attr;
return gtk_text_attr_line_style_new (a->value);
}
static void
attr_line_style_destroy (PangoAttribute *attr)
{
g_slice_free (GtkTextAttrLineStyle, (gpointer)attr);
}
static gboolean
attr_line_style_equal (const PangoAttribute *attr1,
const PangoAttribute *attr2)
{
const GtkTextAttrLineStyle *a1 = (GtkTextAttrLineStyle *)attr1;
const GtkTextAttrLineStyle *a2 = (GtkTextAttrLineStyle *)attr2;
return a1->value == a2->value;
}
PangoAttrType gtk_text_attr_line_style_type = 0;
PangoAttribute *
gtk_text_attr_line_style_new (GtkLineStyle style)
{
static PangoAttrClass klass = {
0,
attr_line_style_copy,
attr_line_style_destroy,
attr_line_style_equal
};
GtkTextAttrLineStyle *attr;
if (!klass.type)
klass.type = gtk_text_attr_line_style_type =
pango_attr_type_register (I_("GtkTextAttrLineStyle"));
attr = g_slice_new (GtkTextAttrLineStyle);
pango_attribute_init (&attr->attr, &klass);
attr->value = style;
return (PangoAttribute *)attr;
}
static void
add_generic_attrs (GtkTextLayout *layout,
GtkTextAppearance *appearance,
+15
View File
@@ -219,6 +219,21 @@ struct _GtkTextLineDisplay
#ifdef GTK_COMPILATION
extern G_GNUC_INTERNAL PangoAttrType gtk_text_attr_appearance_type;
typedef enum {
GTK_LINE_STYLE_SOLID,
GTK_LINE_STYLE_DASHED,
GTK_LINE_STYLE_DOTTED
} GtkLineStyle;
typedef struct {
PangoAttribute attr;
GtkLineStyle value;
} GtkTextAttrLineStyle;
extern PangoAttrType gtk_text_attr_line_style_type;
PangoAttribute *gtk_text_attr_line_style_new (GtkLineStyle style);
#endif
GType gtk_text_layout_get_type (void) G_GNUC_CONST;
+970 -953
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -50,7 +50,7 @@ main (int argc, char *argv[])
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
button = gtk_button_new ();
gtk_button_set_label (GTK_BUTTON (button), "hello world");
gtk_button_set_label (GTK_BUTTON (button), "good world");
gtk_widget_set_margin_top (button, 10);
gtk_widget_set_margin_bottom (button, 10);
gtk_widget_set_margin_start (button, 10);
@@ -0,0 +1,32 @@
transform {
child: transform {
child: rounded-clip {
child: container {
repeat {
bounds: 0 0 159 34;
child: container {
color {
bounds: 0 0 10 10;
color: rgb(168,168,168);
}
color {
bounds: 10 0 10 10;
color: rgb(84,84,84);
}
color {
bounds: 0 10 10 10;
color: rgb(84,84,84);
}
color {
bounds: 10 10 10 10;
color: rgb(168,168,168);
}
}
}
}
clip: 0 0 159 34 / 6;
}
transform: scale(4, 4);
}
transform: translate(6, 20);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+3 -2
View File
@@ -76,6 +76,7 @@ compare_render_tests = [
'clip-in-rounded-clip2',
'clip-in-rounded-clip3',
'rounded-clip-in-clip-3d', # not really 3d, but cairo fails it
'clipped-repeat-3d-ngl',
'issue-3615'
]
@@ -89,8 +90,8 @@ informative_render_tests = [
renderers = [
# name exclude term
[ 'opengl', '' ],
[ 'next', '' ],
[ 'gl', '-ngl' ],
[ 'ngl', '' ],
[ 'broadway', '-3d' ],
[ 'cairo', '-3d' ],
]