From 448a1f2bbef73c660a678f9c97d760819a1e5f1c Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 22 Apr 2026 13:00:22 -0700 Subject: [PATCH 10/29] Add LINK tag support to the quartz-surface backend --- src/cairo-quartz-surface.c | 67 +++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index fdcfbb071..198c88160 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -48,6 +48,7 @@ #include "cairo-surface-backend-private.h" #include "cairo-surface-clipper-private.h" #include "cairo-recording-surface-private.h" +#include "cairo-tag-attributes-private.h" #include @@ -2190,6 +2191,70 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_quartz_surface_tag (void *abstract_surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes, + const cairo_pattern_t *source, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + const cairo_clip_t *clip) +{ + cairo_link_attrs_t link_attrs; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + int i, num_rects; + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + + /* Currently the only tag we support is "Link" */ + if (strcmp (tag_name, "Link")) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We only process the 'begin' tag, and expect a rect attribute; + using the extents of the drawing operations enclosed by the begin/end + link tags to define the clickable area is not implemented. */ + if (!begin) + return status; + + status = _cairo_tag_parse_link_attributes (attributes, &link_attrs); + if (unlikely (status)) + return status; + + num_rects = _cairo_array_num_elements (&link_attrs.rects); + if (num_rects > 0) { + CFURLRef url = CFURLCreateWithBytes (NULL, + (const UInt8 *) link_attrs.uri, + strlen (link_attrs.uri), + kCFStringEncodingUTF8, + NULL); + + for (i = 0; i < num_rects; i++) { + CGRect link_rect; + cairo_rectangle_t rectf; + + _cairo_array_copy_element (&link_attrs.rects, i, &rectf); + + link_rect = + CGRectMake (rectf.x, + surface->extents.height - rectf.y - rectf.height, + rectf.width, + rectf.height); + + CGPDFContextSetURLForRect (surface->cgContext, url, link_rect); + } + + CFRelease (url); + } + + _cairo_array_fini (&link_attrs.rects); + free (link_attrs.dest); + free (link_attrs.uri); + free (link_attrs.file); + + return status; +} + // XXXtodo implement show_page; need to figure out how to handle begin/end static const cairo_surface_backend_t cairo_quartz_surface_backend = { @@ -2226,7 +2291,7 @@ static const cairo_surface_backend_t cairo_quartz_surface_backend = { NULL, /* has_show_text_glyphs */ NULL, /* show_text_glyphs */ NULL, /* get_supported_mime_types */ - NULL, /* tag */ + _cairo_quartz_surface_tag /* tag */ }; cairo_quartz_surface_t * -- 2.53.0