12-quartz-named-destination.patch (6599B)
1 # HG changeset patch 2 # User Jonathan Kew <jkew@mozilla.com> 3 # Date 1628081557 0 4 # Wed Aug 04 12:52:37 2021 +0000 5 # Node ID 2635200eb5ec6f6eff1ecd0fad1ef029f0b994af 6 # Parent 99c4916f4a924ede94aee9044fe3f753d2e2be2d 7 Bug 1892913 - patch 14 - Add cairo-quartz-surface named-destination support from bug 1722300 patch 3. 8 9 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c 10 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c 11 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c 12 @@ -2192,24 +2192,13 @@ static cairo_status_t 13 } 14 15 static cairo_int_status_t 16 -_cairo_quartz_surface_tag (void *abstract_surface, 17 - cairo_bool_t begin, 18 - const char *tag_name, 19 - const char *attributes, 20 - const cairo_pattern_t *source, 21 - const cairo_stroke_style_t *style, 22 - const cairo_matrix_t *ctm, 23 - const cairo_matrix_t *ctm_inverse, 24 - const cairo_clip_t *clip) 25 +_cairo_quartz_surface_link (cairo_quartz_surface_t *surface, 26 + cairo_bool_t begin, 27 + const char *attributes) 28 { 29 cairo_link_attrs_t link_attrs; 30 cairo_int_status_t status = CAIRO_STATUS_SUCCESS; 31 int i, num_rects; 32 - cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 33 - 34 - /* Currently the only tag we support is "Link" */ 35 - if (strcmp (tag_name, "Link")) 36 - return CAIRO_INT_STATUS_UNSUPPORTED; 37 38 /* We only process the 'begin' tag, and expect a rect attribute; 39 using the extents of the drawing operations enclosed by the begin/end 40 @@ -2223,11 +2212,24 @@ static cairo_int_status_t 41 42 num_rects = _cairo_array_num_elements (&link_attrs.rects); 43 if (num_rects > 0) { 44 - CFURLRef url = CFURLCreateWithBytes (NULL, 45 - (const UInt8 *) link_attrs.uri, 46 - strlen (link_attrs.uri), 47 - kCFStringEncodingUTF8, 48 - NULL); 49 + /* Create either a named destination or a URL, depending which is present 50 + in the link attributes. */ 51 + CFURLRef url = NULL; 52 + CFStringRef name = NULL; 53 + if (link_attrs.uri && *link_attrs.uri) 54 + url = CFURLCreateWithBytes (NULL, 55 + (const UInt8 *) link_attrs.uri, 56 + strlen (link_attrs.uri), 57 + kCFStringEncodingUTF8, 58 + NULL); 59 + else if (link_attrs.dest && *link_attrs.dest) 60 + name = CFStringCreateWithBytes (kCFAllocatorDefault, 61 + (const UInt8 *) link_attrs.dest, 62 + strlen (link_attrs.dest), 63 + kCFStringEncodingUTF8, 64 + FALSE); 65 + else /* silently ignore link that doesn't have a usable target */ 66 + goto cleanup; 67 68 for (i = 0; i < num_rects; i++) { 69 CGRect link_rect; 70 @@ -2241,12 +2243,19 @@ static cairo_int_status_t 71 rectf.width, 72 rectf.height); 73 74 - CGPDFContextSetURLForRect (surface->cgContext, url, link_rect); 75 + if (url) 76 + CGPDFContextSetURLForRect (surface->cgContext, url, link_rect); 77 + else 78 + CGPDFContextSetDestinationForRect (surface->cgContext, name, link_rect); 79 } 80 81 - CFRelease (url); 82 + if (url) 83 + CFRelease (url); 84 + else 85 + CFRelease (name); 86 } 87 88 +cleanup: 89 _cairo_array_fini (&link_attrs.rects); 90 free (link_attrs.dest); 91 free (link_attrs.uri); 92 @@ -2255,6 +2264,74 @@ static cairo_int_status_t 93 return status; 94 } 95 96 +static cairo_int_status_t 97 +_cairo_quartz_surface_dest (cairo_quartz_surface_t *surface, 98 + cairo_bool_t begin, 99 + const char *attributes) 100 +{ 101 + cairo_dest_attrs_t dest_attrs; 102 + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; 103 + double x = 0, y = 0; 104 + 105 + /* We only process the 'begin' tag, and expect 'x' and 'y' attributes. */ 106 + if (!begin) 107 + return status; 108 + 109 + status = _cairo_tag_parse_dest_attributes (attributes, &dest_attrs); 110 + if (unlikely (status)) 111 + return status; 112 + 113 + if (unlikely (!dest_attrs.name || !strlen (dest_attrs.name))) 114 + goto cleanup; 115 + 116 + CFStringRef name = CFStringCreateWithBytes (kCFAllocatorDefault, 117 + (const UInt8 *) dest_attrs.name, 118 + strlen (dest_attrs.name), 119 + kCFStringEncodingUTF8, 120 + FALSE); 121 + 122 + if (dest_attrs.x_valid) 123 + x = dest_attrs.x; 124 + if (dest_attrs.y_valid) 125 + y = dest_attrs.y; 126 + 127 + CGPDFContextAddDestinationAtPoint (surface->cgContext, 128 + name, 129 + CGPointMake (x, surface->extents.height - y)); 130 + CFRelease (name); 131 + 132 +cleanup: 133 + free (dest_attrs.name); 134 + 135 + return status; 136 +} 137 + 138 +static cairo_int_status_t 139 +_cairo_quartz_surface_tag (void *abstract_surface, 140 + cairo_bool_t begin, 141 + const char *tag_name, 142 + const char *attributes, 143 + const cairo_pattern_t *source, 144 + const cairo_stroke_style_t *style, 145 + const cairo_matrix_t *ctm, 146 + const cairo_matrix_t *ctm_inverse, 147 + const cairo_clip_t *clip) 148 +{ 149 + cairo_link_attrs_t link_attrs; 150 + int i, num_rects; 151 + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; 152 + 153 + /* Currently the only tags we support are CAIRO_TAG_LINK and CAIRO_TAG_DEST */ 154 + if (!strcmp (tag_name, CAIRO_TAG_LINK)) 155 + return _cairo_quartz_surface_link (surface, begin, attributes); 156 + 157 + if (!strcmp (tag_name, CAIRO_TAG_DEST)) 158 + return _cairo_quartz_surface_dest (surface, begin, attributes); 159 + 160 + /* Unknown tag names are silently ignored here. */ 161 + return CAIRO_INT_STATUS_SUCCESS; 162 +} 163 + 164 // XXXtodo implement show_page; need to figure out how to handle begin/end 165 166 static const cairo_surface_backend_t cairo_quartz_surface_backend = {