From d8c1db11dd7bc281f85a58a125d6084678a90658 Mon Sep 17 00:00:00 2001 From: Heiko Lewin Date: Fri, 26 Jul 2024 08:18:20 +0200 Subject: [PATCH] Fix cairo_glyph_path() early clipping --- src/cairo-gstate.c | 16 ++-- test/glyph-path.c | 82 ++++++++++++++++++ test/meson.build | 1 + .../reference/glyph-path.image.argb32.ref.png | Bin 0 -> 1473 bytes test/reference/glyph-path.image.rgb24.ref.png | Bin 0 -> 1473 bytes .../glyph-path.image16.rgb24.ref.png | Bin 0 -> 1337 bytes 6 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 test/glyph-path.c create mode 100644 test/reference/glyph-path.image.argb32.ref.png create mode 100644 test/reference/glyph-path.image.rgb24.ref.png create mode 100644 test/reference/glyph-path.image16.rgb24.ref.png diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 46d95f346..274a02a56 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -66,7 +66,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, cairo_text_cluster_flags_t cluster_flags, cairo_glyph_t *transformed_glyphs, int *num_transformed_glyphs, - cairo_text_cluster_t *transformed_clusters); + cairo_text_cluster_t *transformed_clusters, + cairo_bool_t perform_early_clip); static void _cairo_gstate_update_device_transform (cairo_observer_t *observer, @@ -2035,14 +2036,16 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, info->cluster_flags, transformed_glyphs, &num_glyphs, - transformed_clusters); + transformed_clusters, + TRUE); } else { _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs, NULL, 0, 0, transformed_glyphs, &num_glyphs, - NULL); + NULL, + TRUE); } if (num_glyphs == 0) @@ -2144,7 +2147,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, glyphs, num_glyphs, NULL, 0, 0, transformed_glyphs, - &num_glyphs, NULL); + &num_glyphs, NULL, FALSE); status = _cairo_scaled_font_glyph_path (gstate->scaled_font, transformed_glyphs, num_glyphs, @@ -2198,7 +2201,8 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, cairo_text_cluster_flags_t cluster_flags, cairo_glyph_t *transformed_glyphs, int *num_transformed_glyphs, - cairo_text_cluster_t *transformed_clusters) + cairo_text_cluster_t *transformed_clusters, + cairo_bool_t perform_early_clip) { cairo_rectangle_int_t surface_extents; cairo_matrix_t *ctm = &gstate->ctm; @@ -2209,7 +2213,7 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, int i, j, k; drop = TRUE; - if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) { + if (!perform_early_clip || !_cairo_gstate_int_clip_extents (gstate, &surface_extents)) { drop = FALSE; /* unbounded surface */ } else { double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font); diff --git a/test/glyph-path.c b/test/glyph-path.c new file mode 100644 index 000000000..b61f193a1 --- /dev/null +++ b/test/glyph-path.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2024 worldiety GmbH + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * worldiety not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. worldiety makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * WORLDIETY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL WORLDIETY BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Heiko Lewin + */ +#include "cairo-test.h" + +#define WIDTH 128 +#define HEIGHT 64 + + +static cairo_test_status_t +draw(cairo_t *cr, int width, int height) { + cairo_glyph_t *glyphs = NULL; + int num_glyphs = 0; + cairo_path_t *path = NULL, *path2 = NULL; + (void)width; + (void)height; + + /* black on white color */ + cairo_set_source_rgb(cr, 1., 1., 1.); + cairo_paint(cr); + cairo_set_source_rgb(cr, 0, 0, 0); + + + /* translate to some point well outside the surface */ + cairo_translate(cr, -width * 100, 0); + + /* create a simple path to illustrate the correct behaviour */ + cairo_rectangle(cr, 0, 0, width/2.0, 2); + path = cairo_copy_path(cr); + cairo_new_path(cr); + + /* create another path from glyphs - this is broken when clipping to early */ + { + cairo_set_font_size(cr, 32); + cairo_scaled_font_t *sf = cairo_get_scaled_font(cr); + cairo_scaled_font_text_to_glyphs(sf, 0, 0, "Test", 4, &glyphs, &num_glyphs, 0, 0, 0); + cairo_glyph_path(cr, glyphs, num_glyphs); + path2 = cairo_copy_path(cr); + } + + /* translate to a visible point and draw both paths */ + cairo_identity_matrix(cr); + cairo_translate(cr, width/4.0, 48); + + cairo_append_path(cr, path); + cairo_append_path(cr, path2); + cairo_fill(cr); + + cairo_path_destroy(path); + cairo_path_destroy(path2); + free(glyphs); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (glyph_path, + "Tests cairo_glyph_path", + "text, glyph, path", /* keywords */ + "target=raster", /* should be enough */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/test/meson.build b/test/meson.build index b4f799c77..786ac2a84 100644 --- a/test/meson.build +++ b/test/meson.build @@ -154,6 +154,7 @@ test_sources = [ 'font-matrix-translation.c', 'font-options.c', 'glyph-cache-pressure.c', + 'glyph-path.c', 'get-and-set.c', 'get-clip.c', 'get-group-target.c', diff --git a/test/reference/glyph-path.image.argb32.ref.png b/test/reference/glyph-path.image.argb32.ref.png new file mode 100644 index 0000000000000000000000000000000000000000..bf61b6581d2d28407a87482213d79e576675bd27 GIT binary patch literal 1473 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 oV$gjMv1ToaVsst%?A%9)IbnIX>LTx@BjuyK zzvqfjv=L^;N~yDKGFjRUk!jre5AHtC=XstVp5LD5^LZ|Nknk`~BTWDRU_^ooS>?$p zIzmAzrMAuOQyC=K4etVMenWZJ{d@obeD z9u?e6(Im6D(N(Sx&sRYjSizn9XEQ{MQTFn71|ff3q~8&fRq2oHGu-~M_X;(v`a)Q< zmW3QiL-^M`0lh^11J;;x(w>~wU>8x&oXZP*+$A#^l6}B-@np)){I};yOlhNHtI1to zdiuZ~nHuHVdX9#s$%oy6&>O%YMy((SwD11};KVL_j@_ztTuVnPl2vhc0&5?;yr$^4 zJT;#B^xgA$P6LO$1KpS)fY@Ard>afz?u=V_6VCi=R;E3Ni-ehdG68_zrqLykUACJ8 zsgqgwFyAAN0yuv44lpV%(SoMF3m1~KO!q!pdZ{RzB=G0cEHZoEFiO>GZdbi8i$ z-#V8VmNCA;Tkqua_4r#rExeW)+REU^`-23;UR}CYqvi^+OoB=WlD~TYxMVVZt(!4I zhxaPF8y4sxUR_Gb5u!fT%^503d9Mn@UTT zeP;vcR*+X}$Wc(5hk5uv)WCz_&cq4F1@}RMGM&+7!j7iOT!70 zU54gvCw5?T>ZX&o8D&mWq^g!@hFG=!?O+=~9r;{-h_i->Z#=NW9x;gJ=HjXs8-mU1 z0KlM0)S3coED3)~M*zT$YksdKy&_OmJi{+r{E?cW1atrZlsrRFbSHGY-;YJArXiiI zS#GzEOKQkS6G?;LQ`s9;Opk?rJhx!OJQrLniO0{G@)9we>?|B}bPEWXe$&jbC19V_ z)mPg>dZnXQS5MJhCLBB{r0V3PtCn}IBqi7Ul6N2j-#Zjne6{iFOUPYF8+Kv(CwQfX z)Fxml0Uu9phet5utl}N2>(GNGqM?Wettd_*$r#_0xG^R_7Q45UIN=k;{JTw7U>3SG z@LJ!QU?*O57UcBvv3s6abANqce<@*#dIBIIDqr08xwfUxb1GsWCGwS-}*qepz