1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2011 Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker *
4*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker *
6*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker *
12*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker *
18*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker *
24*2d1272b8SAndroid Build Coastguard Worker * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker */
26*2d1272b8SAndroid Build Coastguard Worker
27*2d1272b8SAndroid Build Coastguard Worker #ifndef HELPER_CAIRO_HH
28*2d1272b8SAndroid Build Coastguard Worker #define HELPER_CAIRO_HH
29*2d1272b8SAndroid Build Coastguard Worker
30*2d1272b8SAndroid Build Coastguard Worker #include "view-options.hh"
31*2d1272b8SAndroid Build Coastguard Worker #include "output-options.hh"
32*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_CAIRO_FT
33*2d1272b8SAndroid Build Coastguard Worker # include "helper-cairo-ft.hh"
34*2d1272b8SAndroid Build Coastguard Worker #endif
35*2d1272b8SAndroid Build Coastguard Worker
36*2d1272b8SAndroid Build Coastguard Worker #include <cairo.h>
37*2d1272b8SAndroid Build Coastguard Worker #include <hb.h>
38*2d1272b8SAndroid Build Coastguard Worker #include <hb-cairo.h>
39*2d1272b8SAndroid Build Coastguard Worker
40*2d1272b8SAndroid Build Coastguard Worker #include "helper-cairo-ansi.hh"
41*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SVG_SURFACE
42*2d1272b8SAndroid Build Coastguard Worker # include <cairo-svg.h>
43*2d1272b8SAndroid Build Coastguard Worker #endif
44*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PDF_SURFACE
45*2d1272b8SAndroid Build Coastguard Worker # include <cairo-pdf.h>
46*2d1272b8SAndroid Build Coastguard Worker #endif
47*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PS_SURFACE
48*2d1272b8SAndroid Build Coastguard Worker # include <cairo-ps.h>
49*2d1272b8SAndroid Build Coastguard Worker # if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,6,0)
50*2d1272b8SAndroid Build Coastguard Worker # define HAS_EPS 1
51*2d1272b8SAndroid Build Coastguard Worker
52*2d1272b8SAndroid Build Coastguard Worker static cairo_surface_t *
_cairo_eps_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width,double height)53*2d1272b8SAndroid Build Coastguard Worker _cairo_eps_surface_create_for_stream (cairo_write_func_t write_func,
54*2d1272b8SAndroid Build Coastguard Worker void *closure,
55*2d1272b8SAndroid Build Coastguard Worker double width,
56*2d1272b8SAndroid Build Coastguard Worker double height)
57*2d1272b8SAndroid Build Coastguard Worker {
58*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *surface;
59*2d1272b8SAndroid Build Coastguard Worker
60*2d1272b8SAndroid Build Coastguard Worker surface = cairo_ps_surface_create_for_stream (write_func, closure, width, height);
61*2d1272b8SAndroid Build Coastguard Worker cairo_ps_surface_set_eps (surface, true);
62*2d1272b8SAndroid Build Coastguard Worker
63*2d1272b8SAndroid Build Coastguard Worker return surface;
64*2d1272b8SAndroid Build Coastguard Worker }
65*2d1272b8SAndroid Build Coastguard Worker
66*2d1272b8SAndroid Build Coastguard Worker # else
67*2d1272b8SAndroid Build Coastguard Worker # undef HAS_EPS
68*2d1272b8SAndroid Build Coastguard Worker # endif
69*2d1272b8SAndroid Build Coastguard Worker #endif
70*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SCRIPT_SURFACE
71*2d1272b8SAndroid Build Coastguard Worker # include <cairo-script.h>
72*2d1272b8SAndroid Build Coastguard Worker #endif
73*2d1272b8SAndroid Build Coastguard Worker
74*2d1272b8SAndroid Build Coastguard Worker static inline bool
helper_cairo_use_hb_draw(const font_options_t * font_opts)75*2d1272b8SAndroid Build Coastguard Worker helper_cairo_use_hb_draw (const font_options_t *font_opts)
76*2d1272b8SAndroid Build Coastguard Worker {
77*2d1272b8SAndroid Build Coastguard Worker const char *env = getenv ("HB_DRAW");
78*2d1272b8SAndroid Build Coastguard Worker if (!env)
79*2d1272b8SAndroid Build Coastguard Worker /* Older cairo had a bug in rendering COLRv0 fonts in
80*2d1272b8SAndroid Build Coastguard Worker * right-to-left direction as well as clipping issue
81*2d1272b8SAndroid Build Coastguard Worker * with user-fonts.
82*2d1272b8SAndroid Build Coastguard Worker *
83*2d1272b8SAndroid Build Coastguard Worker * https://github.com/harfbuzz/harfbuzz/issues/4051 */
84*2d1272b8SAndroid Build Coastguard Worker return cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 5);
85*2d1272b8SAndroid Build Coastguard Worker
86*2d1272b8SAndroid Build Coastguard Worker return atoi (env);
87*2d1272b8SAndroid Build Coastguard Worker }
88*2d1272b8SAndroid Build Coastguard Worker
89*2d1272b8SAndroid Build Coastguard Worker static inline cairo_scaled_font_t *
helper_cairo_create_scaled_font(const font_options_t * font_opts,const view_options_t * view_opts)90*2d1272b8SAndroid Build Coastguard Worker helper_cairo_create_scaled_font (const font_options_t *font_opts,
91*2d1272b8SAndroid Build Coastguard Worker const view_options_t *view_opts)
92*2d1272b8SAndroid Build Coastguard Worker {
93*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font = font_opts->font;
94*2d1272b8SAndroid Build Coastguard Worker bool use_hb_draw = true;
95*2d1272b8SAndroid Build Coastguard Worker
96*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_CAIRO_FT
97*2d1272b8SAndroid Build Coastguard Worker use_hb_draw = helper_cairo_use_hb_draw (font_opts);
98*2d1272b8SAndroid Build Coastguard Worker #endif
99*2d1272b8SAndroid Build Coastguard Worker
100*2d1272b8SAndroid Build Coastguard Worker
101*2d1272b8SAndroid Build Coastguard Worker cairo_font_face_t *cairo_face = nullptr;
102*2d1272b8SAndroid Build Coastguard Worker if (use_hb_draw)
103*2d1272b8SAndroid Build Coastguard Worker {
104*2d1272b8SAndroid Build Coastguard Worker cairo_face = hb_cairo_font_face_create_for_font (font);
105*2d1272b8SAndroid Build Coastguard Worker hb_cairo_font_face_set_scale_factor (cairo_face, 1 << font_opts->subpixel_bits);
106*2d1272b8SAndroid Build Coastguard Worker }
107*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_CAIRO_FT
108*2d1272b8SAndroid Build Coastguard Worker else
109*2d1272b8SAndroid Build Coastguard Worker cairo_face = helper_cairo_create_ft_font_face (font_opts);
110*2d1272b8SAndroid Build Coastguard Worker #endif
111*2d1272b8SAndroid Build Coastguard Worker
112*2d1272b8SAndroid Build Coastguard Worker cairo_matrix_t ctm, font_matrix;
113*2d1272b8SAndroid Build Coastguard Worker cairo_font_options_t *font_options;
114*2d1272b8SAndroid Build Coastguard Worker
115*2d1272b8SAndroid Build Coastguard Worker cairo_matrix_init_identity (&ctm);
116*2d1272b8SAndroid Build Coastguard Worker cairo_matrix_init_scale (&font_matrix,
117*2d1272b8SAndroid Build Coastguard Worker font_opts->font_size_x,
118*2d1272b8SAndroid Build Coastguard Worker font_opts->font_size_y);
119*2d1272b8SAndroid Build Coastguard Worker if (!use_hb_draw)
120*2d1272b8SAndroid Build Coastguard Worker font_matrix.xy = -font_opts->slant * font_opts->font_size_x;
121*2d1272b8SAndroid Build Coastguard Worker
122*2d1272b8SAndroid Build Coastguard Worker font_options = cairo_font_options_create ();
123*2d1272b8SAndroid Build Coastguard Worker cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
124*2d1272b8SAndroid Build Coastguard Worker cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
125*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_COLOR_PALETTE_DEFAULT
126*2d1272b8SAndroid Build Coastguard Worker cairo_font_options_set_color_palette (font_options, view_opts->palette);
127*2d1272b8SAndroid Build Coastguard Worker #endif
128*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
129*2d1272b8SAndroid Build Coastguard Worker if (view_opts->custom_palette)
130*2d1272b8SAndroid Build Coastguard Worker {
131*2d1272b8SAndroid Build Coastguard Worker char **entries = g_strsplit (view_opts->custom_palette, ",", -1);
132*2d1272b8SAndroid Build Coastguard Worker unsigned idx = 0;
133*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; entries[i]; i++)
134*2d1272b8SAndroid Build Coastguard Worker {
135*2d1272b8SAndroid Build Coastguard Worker const char *p = strchr (entries[i], '=');
136*2d1272b8SAndroid Build Coastguard Worker if (!p)
137*2d1272b8SAndroid Build Coastguard Worker p = entries[i];
138*2d1272b8SAndroid Build Coastguard Worker else
139*2d1272b8SAndroid Build Coastguard Worker {
140*2d1272b8SAndroid Build Coastguard Worker sscanf (entries[i], "%u", &idx);
141*2d1272b8SAndroid Build Coastguard Worker p++;
142*2d1272b8SAndroid Build Coastguard Worker }
143*2d1272b8SAndroid Build Coastguard Worker
144*2d1272b8SAndroid Build Coastguard Worker unsigned fr, fg, fb, fa;
145*2d1272b8SAndroid Build Coastguard Worker fr = fg = fb = fa = 0;
146*2d1272b8SAndroid Build Coastguard Worker if (parse_color (p, fr, fg,fb, fa))
147*2d1272b8SAndroid Build Coastguard Worker cairo_font_options_set_custom_palette_color (font_options, idx, fr / 255., fg / 255., fb / 255., fa / 255.);
148*2d1272b8SAndroid Build Coastguard Worker
149*2d1272b8SAndroid Build Coastguard Worker idx++;
150*2d1272b8SAndroid Build Coastguard Worker }
151*2d1272b8SAndroid Build Coastguard Worker g_strfreev (entries);
152*2d1272b8SAndroid Build Coastguard Worker }
153*2d1272b8SAndroid Build Coastguard Worker #endif
154*2d1272b8SAndroid Build Coastguard Worker
155*2d1272b8SAndroid Build Coastguard Worker cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
156*2d1272b8SAndroid Build Coastguard Worker &font_matrix,
157*2d1272b8SAndroid Build Coastguard Worker &ctm,
158*2d1272b8SAndroid Build Coastguard Worker font_options);
159*2d1272b8SAndroid Build Coastguard Worker
160*2d1272b8SAndroid Build Coastguard Worker cairo_font_options_destroy (font_options);
161*2d1272b8SAndroid Build Coastguard Worker cairo_font_face_destroy (cairo_face);
162*2d1272b8SAndroid Build Coastguard Worker
163*2d1272b8SAndroid Build Coastguard Worker return scaled_font;
164*2d1272b8SAndroid Build Coastguard Worker }
165*2d1272b8SAndroid Build Coastguard Worker
166*2d1272b8SAndroid Build Coastguard Worker static inline bool
helper_cairo_scaled_font_has_color(cairo_scaled_font_t * scaled_font)167*2d1272b8SAndroid Build Coastguard Worker helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font)
168*2d1272b8SAndroid Build Coastguard Worker {
169*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font = hb_cairo_font_face_get_font (cairo_scaled_font_get_font_face (scaled_font));
170*2d1272b8SAndroid Build Coastguard Worker
171*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_CAIRO_FT
172*2d1272b8SAndroid Build Coastguard Worker if (!font)
173*2d1272b8SAndroid Build Coastguard Worker return helper_cairo_ft_scaled_font_has_color (scaled_font);
174*2d1272b8SAndroid Build Coastguard Worker #endif
175*2d1272b8SAndroid Build Coastguard Worker
176*2d1272b8SAndroid Build Coastguard Worker hb_face_t *face = hb_font_get_face (font);
177*2d1272b8SAndroid Build Coastguard Worker
178*2d1272b8SAndroid Build Coastguard Worker return hb_ot_color_has_png (face) ||
179*2d1272b8SAndroid Build Coastguard Worker hb_ot_color_has_layers (face) ||
180*2d1272b8SAndroid Build Coastguard Worker hb_ot_color_has_paint (face);
181*2d1272b8SAndroid Build Coastguard Worker }
182*2d1272b8SAndroid Build Coastguard Worker
183*2d1272b8SAndroid Build Coastguard Worker
184*2d1272b8SAndroid Build Coastguard Worker enum class image_protocol_t {
185*2d1272b8SAndroid Build Coastguard Worker NONE = 0,
186*2d1272b8SAndroid Build Coastguard Worker ITERM2,
187*2d1272b8SAndroid Build Coastguard Worker KITTY,
188*2d1272b8SAndroid Build Coastguard Worker };
189*2d1272b8SAndroid Build Coastguard Worker
190*2d1272b8SAndroid Build Coastguard Worker struct finalize_closure_t {
191*2d1272b8SAndroid Build Coastguard Worker void (*callback)(finalize_closure_t *);
192*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *surface;
193*2d1272b8SAndroid Build Coastguard Worker cairo_write_func_t write_func;
194*2d1272b8SAndroid Build Coastguard Worker void *closure;
195*2d1272b8SAndroid Build Coastguard Worker image_protocol_t protocol;
196*2d1272b8SAndroid Build Coastguard Worker };
197*2d1272b8SAndroid Build Coastguard Worker static cairo_user_data_key_t finalize_closure_key;
198*2d1272b8SAndroid Build Coastguard Worker
199*2d1272b8SAndroid Build Coastguard Worker
200*2d1272b8SAndroid Build Coastguard Worker static void
finalize_ansi(finalize_closure_t * closure)201*2d1272b8SAndroid Build Coastguard Worker finalize_ansi (finalize_closure_t *closure)
202*2d1272b8SAndroid Build Coastguard Worker {
203*2d1272b8SAndroid Build Coastguard Worker cairo_status_t status;
204*2d1272b8SAndroid Build Coastguard Worker status = helper_cairo_surface_write_to_ansi_stream (closure->surface,
205*2d1272b8SAndroid Build Coastguard Worker closure->write_func,
206*2d1272b8SAndroid Build Coastguard Worker closure->closure);
207*2d1272b8SAndroid Build Coastguard Worker if (status != CAIRO_STATUS_SUCCESS)
208*2d1272b8SAndroid Build Coastguard Worker fail (false, "Failed to write output: %s",
209*2d1272b8SAndroid Build Coastguard Worker cairo_status_to_string (status));
210*2d1272b8SAndroid Build Coastguard Worker }
211*2d1272b8SAndroid Build Coastguard Worker
212*2d1272b8SAndroid Build Coastguard Worker static cairo_surface_t *
_cairo_ansi_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width,double height,cairo_content_t content,image_protocol_t protocol HB_UNUSED)213*2d1272b8SAndroid Build Coastguard Worker _cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func,
214*2d1272b8SAndroid Build Coastguard Worker void *closure,
215*2d1272b8SAndroid Build Coastguard Worker double width,
216*2d1272b8SAndroid Build Coastguard Worker double height,
217*2d1272b8SAndroid Build Coastguard Worker cairo_content_t content,
218*2d1272b8SAndroid Build Coastguard Worker image_protocol_t protocol HB_UNUSED)
219*2d1272b8SAndroid Build Coastguard Worker {
220*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *surface;
221*2d1272b8SAndroid Build Coastguard Worker int w = ceil (width);
222*2d1272b8SAndroid Build Coastguard Worker int h = ceil (height);
223*2d1272b8SAndroid Build Coastguard Worker
224*2d1272b8SAndroid Build Coastguard Worker switch (content) {
225*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_ALPHA:
226*2d1272b8SAndroid Build Coastguard Worker surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
227*2d1272b8SAndroid Build Coastguard Worker break;
228*2d1272b8SAndroid Build Coastguard Worker default:
229*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_COLOR:
230*2d1272b8SAndroid Build Coastguard Worker surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
231*2d1272b8SAndroid Build Coastguard Worker break;
232*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_COLOR_ALPHA:
233*2d1272b8SAndroid Build Coastguard Worker surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
234*2d1272b8SAndroid Build Coastguard Worker break;
235*2d1272b8SAndroid Build Coastguard Worker }
236*2d1272b8SAndroid Build Coastguard Worker cairo_status_t status = cairo_surface_status (surface);
237*2d1272b8SAndroid Build Coastguard Worker if (status != CAIRO_STATUS_SUCCESS)
238*2d1272b8SAndroid Build Coastguard Worker fail (false, "Failed to create cairo surface: %s",
239*2d1272b8SAndroid Build Coastguard Worker cairo_status_to_string (status));
240*2d1272b8SAndroid Build Coastguard Worker
241*2d1272b8SAndroid Build Coastguard Worker finalize_closure_t *ansi_closure = g_new0 (finalize_closure_t, 1);
242*2d1272b8SAndroid Build Coastguard Worker ansi_closure->callback = finalize_ansi;
243*2d1272b8SAndroid Build Coastguard Worker ansi_closure->surface = surface;
244*2d1272b8SAndroid Build Coastguard Worker ansi_closure->write_func = write_func;
245*2d1272b8SAndroid Build Coastguard Worker ansi_closure->closure = closure;
246*2d1272b8SAndroid Build Coastguard Worker
247*2d1272b8SAndroid Build Coastguard Worker if (cairo_surface_set_user_data (surface,
248*2d1272b8SAndroid Build Coastguard Worker &finalize_closure_key,
249*2d1272b8SAndroid Build Coastguard Worker (void *) ansi_closure,
250*2d1272b8SAndroid Build Coastguard Worker (cairo_destroy_func_t) g_free))
251*2d1272b8SAndroid Build Coastguard Worker g_free ((void *) closure);
252*2d1272b8SAndroid Build Coastguard Worker
253*2d1272b8SAndroid Build Coastguard Worker return surface;
254*2d1272b8SAndroid Build Coastguard Worker }
255*2d1272b8SAndroid Build Coastguard Worker
256*2d1272b8SAndroid Build Coastguard Worker
257*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PNG_FUNCTIONS
258*2d1272b8SAndroid Build Coastguard Worker
259*2d1272b8SAndroid Build Coastguard Worker static cairo_status_t
byte_array_write_func(void * closure,const unsigned char * data,unsigned int size)260*2d1272b8SAndroid Build Coastguard Worker byte_array_write_func (void *closure,
261*2d1272b8SAndroid Build Coastguard Worker const unsigned char *data,
262*2d1272b8SAndroid Build Coastguard Worker unsigned int size)
263*2d1272b8SAndroid Build Coastguard Worker {
264*2d1272b8SAndroid Build Coastguard Worker g_byte_array_append ((GByteArray *) closure, data, size);
265*2d1272b8SAndroid Build Coastguard Worker return CAIRO_STATUS_SUCCESS;
266*2d1272b8SAndroid Build Coastguard Worker }
267*2d1272b8SAndroid Build Coastguard Worker
268*2d1272b8SAndroid Build Coastguard Worker static void
finalize_png(finalize_closure_t * closure)269*2d1272b8SAndroid Build Coastguard Worker finalize_png (finalize_closure_t *closure)
270*2d1272b8SAndroid Build Coastguard Worker {
271*2d1272b8SAndroid Build Coastguard Worker cairo_status_t status;
272*2d1272b8SAndroid Build Coastguard Worker GByteArray *bytes = nullptr;
273*2d1272b8SAndroid Build Coastguard Worker GString *string;
274*2d1272b8SAndroid Build Coastguard Worker gchar *base64;
275*2d1272b8SAndroid Build Coastguard Worker size_t base64_len;
276*2d1272b8SAndroid Build Coastguard Worker
277*2d1272b8SAndroid Build Coastguard Worker if (closure->protocol == image_protocol_t::NONE)
278*2d1272b8SAndroid Build Coastguard Worker {
279*2d1272b8SAndroid Build Coastguard Worker status = cairo_surface_write_to_png_stream (closure->surface,
280*2d1272b8SAndroid Build Coastguard Worker closure->write_func,
281*2d1272b8SAndroid Build Coastguard Worker closure->closure);
282*2d1272b8SAndroid Build Coastguard Worker }
283*2d1272b8SAndroid Build Coastguard Worker else
284*2d1272b8SAndroid Build Coastguard Worker {
285*2d1272b8SAndroid Build Coastguard Worker bytes = g_byte_array_new ();
286*2d1272b8SAndroid Build Coastguard Worker status = cairo_surface_write_to_png_stream (closure->surface,
287*2d1272b8SAndroid Build Coastguard Worker byte_array_write_func,
288*2d1272b8SAndroid Build Coastguard Worker bytes);
289*2d1272b8SAndroid Build Coastguard Worker }
290*2d1272b8SAndroid Build Coastguard Worker
291*2d1272b8SAndroid Build Coastguard Worker if (status != CAIRO_STATUS_SUCCESS)
292*2d1272b8SAndroid Build Coastguard Worker fail (false, "Failed to write output: %s",
293*2d1272b8SAndroid Build Coastguard Worker cairo_status_to_string (status));
294*2d1272b8SAndroid Build Coastguard Worker
295*2d1272b8SAndroid Build Coastguard Worker if (closure->protocol == image_protocol_t::NONE)
296*2d1272b8SAndroid Build Coastguard Worker return;
297*2d1272b8SAndroid Build Coastguard Worker
298*2d1272b8SAndroid Build Coastguard Worker base64 = g_base64_encode (bytes->data, bytes->len);
299*2d1272b8SAndroid Build Coastguard Worker base64_len = strlen (base64);
300*2d1272b8SAndroid Build Coastguard Worker
301*2d1272b8SAndroid Build Coastguard Worker string = g_string_new (NULL);
302*2d1272b8SAndroid Build Coastguard Worker if (closure->protocol == image_protocol_t::ITERM2)
303*2d1272b8SAndroid Build Coastguard Worker {
304*2d1272b8SAndroid Build Coastguard Worker /* https://iterm2.com/documentation-images.html */
305*2d1272b8SAndroid Build Coastguard Worker g_string_printf (string, "\033]1337;File=inline=1;size=%zu:%s\a\n",
306*2d1272b8SAndroid Build Coastguard Worker base64_len, base64);
307*2d1272b8SAndroid Build Coastguard Worker }
308*2d1272b8SAndroid Build Coastguard Worker else if (closure->protocol == image_protocol_t::KITTY)
309*2d1272b8SAndroid Build Coastguard Worker {
310*2d1272b8SAndroid Build Coastguard Worker #define CHUNK_SIZE 4096
311*2d1272b8SAndroid Build Coastguard Worker /* https://sw.kovidgoyal.net/kitty/graphics-protocol.html */
312*2d1272b8SAndroid Build Coastguard Worker for (size_t pos = 0; pos < base64_len; pos += CHUNK_SIZE)
313*2d1272b8SAndroid Build Coastguard Worker {
314*2d1272b8SAndroid Build Coastguard Worker size_t len = base64_len - pos;
315*2d1272b8SAndroid Build Coastguard Worker
316*2d1272b8SAndroid Build Coastguard Worker if (pos == 0)
317*2d1272b8SAndroid Build Coastguard Worker g_string_append (string, "\033_Ga=T,f=100,m=");
318*2d1272b8SAndroid Build Coastguard Worker else
319*2d1272b8SAndroid Build Coastguard Worker g_string_append (string, "\033_Gm=");
320*2d1272b8SAndroid Build Coastguard Worker
321*2d1272b8SAndroid Build Coastguard Worker if (len > CHUNK_SIZE)
322*2d1272b8SAndroid Build Coastguard Worker {
323*2d1272b8SAndroid Build Coastguard Worker g_string_append (string, "1;");
324*2d1272b8SAndroid Build Coastguard Worker g_string_append_len (string, base64 + pos, CHUNK_SIZE);
325*2d1272b8SAndroid Build Coastguard Worker }
326*2d1272b8SAndroid Build Coastguard Worker else
327*2d1272b8SAndroid Build Coastguard Worker {
328*2d1272b8SAndroid Build Coastguard Worker g_string_append (string, "0;");
329*2d1272b8SAndroid Build Coastguard Worker g_string_append_len (string, base64 + pos, len);
330*2d1272b8SAndroid Build Coastguard Worker }
331*2d1272b8SAndroid Build Coastguard Worker
332*2d1272b8SAndroid Build Coastguard Worker g_string_append (string, "\033\\");
333*2d1272b8SAndroid Build Coastguard Worker }
334*2d1272b8SAndroid Build Coastguard Worker g_string_append (string, "\n");
335*2d1272b8SAndroid Build Coastguard Worker #undef CHUNK_SIZE
336*2d1272b8SAndroid Build Coastguard Worker }
337*2d1272b8SAndroid Build Coastguard Worker
338*2d1272b8SAndroid Build Coastguard Worker closure->write_func (closure->closure, (unsigned char *) string->str, string->len);
339*2d1272b8SAndroid Build Coastguard Worker
340*2d1272b8SAndroid Build Coastguard Worker g_byte_array_unref (bytes);
341*2d1272b8SAndroid Build Coastguard Worker g_free (base64);
342*2d1272b8SAndroid Build Coastguard Worker g_string_free (string, TRUE);
343*2d1272b8SAndroid Build Coastguard Worker }
344*2d1272b8SAndroid Build Coastguard Worker
345*2d1272b8SAndroid Build Coastguard Worker static cairo_surface_t *
_cairo_png_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width,double height,cairo_content_t content,image_protocol_t protocol)346*2d1272b8SAndroid Build Coastguard Worker _cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
347*2d1272b8SAndroid Build Coastguard Worker void *closure,
348*2d1272b8SAndroid Build Coastguard Worker double width,
349*2d1272b8SAndroid Build Coastguard Worker double height,
350*2d1272b8SAndroid Build Coastguard Worker cairo_content_t content,
351*2d1272b8SAndroid Build Coastguard Worker image_protocol_t protocol)
352*2d1272b8SAndroid Build Coastguard Worker {
353*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *surface;
354*2d1272b8SAndroid Build Coastguard Worker int w = ceil (width);
355*2d1272b8SAndroid Build Coastguard Worker int h = ceil (height);
356*2d1272b8SAndroid Build Coastguard Worker
357*2d1272b8SAndroid Build Coastguard Worker switch (content) {
358*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_ALPHA:
359*2d1272b8SAndroid Build Coastguard Worker surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
360*2d1272b8SAndroid Build Coastguard Worker break;
361*2d1272b8SAndroid Build Coastguard Worker default:
362*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_COLOR:
363*2d1272b8SAndroid Build Coastguard Worker surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
364*2d1272b8SAndroid Build Coastguard Worker break;
365*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_COLOR_ALPHA:
366*2d1272b8SAndroid Build Coastguard Worker surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
367*2d1272b8SAndroid Build Coastguard Worker break;
368*2d1272b8SAndroid Build Coastguard Worker }
369*2d1272b8SAndroid Build Coastguard Worker cairo_status_t status = cairo_surface_status (surface);
370*2d1272b8SAndroid Build Coastguard Worker if (status != CAIRO_STATUS_SUCCESS)
371*2d1272b8SAndroid Build Coastguard Worker fail (false, "Failed to create cairo surface: %s",
372*2d1272b8SAndroid Build Coastguard Worker cairo_status_to_string (status));
373*2d1272b8SAndroid Build Coastguard Worker
374*2d1272b8SAndroid Build Coastguard Worker finalize_closure_t *png_closure = g_new0 (finalize_closure_t, 1);
375*2d1272b8SAndroid Build Coastguard Worker png_closure->callback = finalize_png;
376*2d1272b8SAndroid Build Coastguard Worker png_closure->surface = surface;
377*2d1272b8SAndroid Build Coastguard Worker png_closure->write_func = write_func;
378*2d1272b8SAndroid Build Coastguard Worker png_closure->closure = closure;
379*2d1272b8SAndroid Build Coastguard Worker png_closure->protocol = protocol;
380*2d1272b8SAndroid Build Coastguard Worker
381*2d1272b8SAndroid Build Coastguard Worker if (cairo_surface_set_user_data (surface,
382*2d1272b8SAndroid Build Coastguard Worker &finalize_closure_key,
383*2d1272b8SAndroid Build Coastguard Worker (void *) png_closure,
384*2d1272b8SAndroid Build Coastguard Worker (cairo_destroy_func_t) g_free))
385*2d1272b8SAndroid Build Coastguard Worker g_free ((void *) closure);
386*2d1272b8SAndroid Build Coastguard Worker
387*2d1272b8SAndroid Build Coastguard Worker return surface;
388*2d1272b8SAndroid Build Coastguard Worker }
389*2d1272b8SAndroid Build Coastguard Worker
390*2d1272b8SAndroid Build Coastguard Worker #endif
391*2d1272b8SAndroid Build Coastguard Worker
392*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SCRIPT_SURFACE
393*2d1272b8SAndroid Build Coastguard Worker
394*2d1272b8SAndroid Build Coastguard Worker static cairo_surface_t *
_cairo_script_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width,double height,cairo_content_t content,image_protocol_t protocol HB_UNUSED)395*2d1272b8SAndroid Build Coastguard Worker _cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
396*2d1272b8SAndroid Build Coastguard Worker void *closure,
397*2d1272b8SAndroid Build Coastguard Worker double width,
398*2d1272b8SAndroid Build Coastguard Worker double height,
399*2d1272b8SAndroid Build Coastguard Worker cairo_content_t content,
400*2d1272b8SAndroid Build Coastguard Worker image_protocol_t protocol HB_UNUSED)
401*2d1272b8SAndroid Build Coastguard Worker {
402*2d1272b8SAndroid Build Coastguard Worker cairo_device_t *script = cairo_script_create_for_stream (write_func, closure);
403*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *surface = cairo_script_surface_create (script, content, width, height);
404*2d1272b8SAndroid Build Coastguard Worker cairo_device_destroy (script);
405*2d1272b8SAndroid Build Coastguard Worker return surface;
406*2d1272b8SAndroid Build Coastguard Worker }
407*2d1272b8SAndroid Build Coastguard Worker
408*2d1272b8SAndroid Build Coastguard Worker #endif
409*2d1272b8SAndroid Build Coastguard Worker
410*2d1272b8SAndroid Build Coastguard Worker static cairo_status_t
stdio_write_func(void * closure,const unsigned char * data,unsigned int size)411*2d1272b8SAndroid Build Coastguard Worker stdio_write_func (void *closure,
412*2d1272b8SAndroid Build Coastguard Worker const unsigned char *data,
413*2d1272b8SAndroid Build Coastguard Worker unsigned int size)
414*2d1272b8SAndroid Build Coastguard Worker {
415*2d1272b8SAndroid Build Coastguard Worker FILE *fp = (FILE *) closure;
416*2d1272b8SAndroid Build Coastguard Worker
417*2d1272b8SAndroid Build Coastguard Worker while (size) {
418*2d1272b8SAndroid Build Coastguard Worker size_t ret = fwrite (data, 1, size, fp);
419*2d1272b8SAndroid Build Coastguard Worker size -= ret;
420*2d1272b8SAndroid Build Coastguard Worker data += ret;
421*2d1272b8SAndroid Build Coastguard Worker if (size && ferror (fp))
422*2d1272b8SAndroid Build Coastguard Worker fail (false, "Failed to write output: %s", strerror (errno));
423*2d1272b8SAndroid Build Coastguard Worker }
424*2d1272b8SAndroid Build Coastguard Worker
425*2d1272b8SAndroid Build Coastguard Worker return CAIRO_STATUS_SUCCESS;
426*2d1272b8SAndroid Build Coastguard Worker }
427*2d1272b8SAndroid Build Coastguard Worker
428*2d1272b8SAndroid Build Coastguard Worker static const char *helper_cairo_supported_formats[] =
429*2d1272b8SAndroid Build Coastguard Worker {
430*2d1272b8SAndroid Build Coastguard Worker "ansi",
431*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PNG_FUNCTIONS
432*2d1272b8SAndroid Build Coastguard Worker "png",
433*2d1272b8SAndroid Build Coastguard Worker #endif
434*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SVG_SURFACE
435*2d1272b8SAndroid Build Coastguard Worker "svg",
436*2d1272b8SAndroid Build Coastguard Worker #endif
437*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PDF_SURFACE
438*2d1272b8SAndroid Build Coastguard Worker "pdf",
439*2d1272b8SAndroid Build Coastguard Worker #endif
440*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PS_SURFACE
441*2d1272b8SAndroid Build Coastguard Worker "ps",
442*2d1272b8SAndroid Build Coastguard Worker #ifdef HAS_EPS
443*2d1272b8SAndroid Build Coastguard Worker "eps",
444*2d1272b8SAndroid Build Coastguard Worker #endif
445*2d1272b8SAndroid Build Coastguard Worker #endif
446*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SCRIPT_SURFACE
447*2d1272b8SAndroid Build Coastguard Worker "script",
448*2d1272b8SAndroid Build Coastguard Worker #endif
449*2d1272b8SAndroid Build Coastguard Worker nullptr
450*2d1272b8SAndroid Build Coastguard Worker };
451*2d1272b8SAndroid Build Coastguard Worker
452*2d1272b8SAndroid Build Coastguard Worker template <typename view_options_t,
453*2d1272b8SAndroid Build Coastguard Worker typename output_options_type>
454*2d1272b8SAndroid Build Coastguard Worker static inline cairo_t *
helper_cairo_create_context(double w,double h,view_options_t * view_opts,output_options_type * out_opts,cairo_content_t content)455*2d1272b8SAndroid Build Coastguard Worker helper_cairo_create_context (double w, double h,
456*2d1272b8SAndroid Build Coastguard Worker view_options_t *view_opts,
457*2d1272b8SAndroid Build Coastguard Worker output_options_type *out_opts,
458*2d1272b8SAndroid Build Coastguard Worker cairo_content_t content)
459*2d1272b8SAndroid Build Coastguard Worker {
460*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
461*2d1272b8SAndroid Build Coastguard Worker void *closure,
462*2d1272b8SAndroid Build Coastguard Worker double width,
463*2d1272b8SAndroid Build Coastguard Worker double height) = nullptr;
464*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
465*2d1272b8SAndroid Build Coastguard Worker void *closure,
466*2d1272b8SAndroid Build Coastguard Worker double width,
467*2d1272b8SAndroid Build Coastguard Worker double height,
468*2d1272b8SAndroid Build Coastguard Worker cairo_content_t content,
469*2d1272b8SAndroid Build Coastguard Worker image_protocol_t protocol) = nullptr;
470*2d1272b8SAndroid Build Coastguard Worker
471*2d1272b8SAndroid Build Coastguard Worker image_protocol_t protocol = image_protocol_t::NONE;
472*2d1272b8SAndroid Build Coastguard Worker const char *extension = out_opts->output_format;
473*2d1272b8SAndroid Build Coastguard Worker if (!extension) {
474*2d1272b8SAndroid Build Coastguard Worker #if HAVE_ISATTY
475*2d1272b8SAndroid Build Coastguard Worker if (isatty (fileno (out_opts->out_fp)))
476*2d1272b8SAndroid Build Coastguard Worker {
477*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PNG_FUNCTIONS
478*2d1272b8SAndroid Build Coastguard Worker const char *name;
479*2d1272b8SAndroid Build Coastguard Worker /* https://gitlab.com/gnachman/iterm2/-/issues/7154 */
480*2d1272b8SAndroid Build Coastguard Worker if ((name = getenv ("LC_TERMINAL")) != nullptr &&
481*2d1272b8SAndroid Build Coastguard Worker 0 == g_ascii_strcasecmp (name, "iTerm2"))
482*2d1272b8SAndroid Build Coastguard Worker {
483*2d1272b8SAndroid Build Coastguard Worker extension = "png";
484*2d1272b8SAndroid Build Coastguard Worker protocol = image_protocol_t::ITERM2;
485*2d1272b8SAndroid Build Coastguard Worker }
486*2d1272b8SAndroid Build Coastguard Worker else if ((name = getenv ("TERM_PROGRAM")) != nullptr &&
487*2d1272b8SAndroid Build Coastguard Worker 0 == g_ascii_strcasecmp (name, "WezTerm"))
488*2d1272b8SAndroid Build Coastguard Worker {
489*2d1272b8SAndroid Build Coastguard Worker extension = "png";
490*2d1272b8SAndroid Build Coastguard Worker protocol = image_protocol_t::ITERM2;
491*2d1272b8SAndroid Build Coastguard Worker }
492*2d1272b8SAndroid Build Coastguard Worker else if ((name = getenv ("TERM")) != nullptr &&
493*2d1272b8SAndroid Build Coastguard Worker 0 == g_ascii_strcasecmp (name, "xterm-kitty"))
494*2d1272b8SAndroid Build Coastguard Worker {
495*2d1272b8SAndroid Build Coastguard Worker extension = "png";
496*2d1272b8SAndroid Build Coastguard Worker protocol = image_protocol_t::KITTY;
497*2d1272b8SAndroid Build Coastguard Worker }
498*2d1272b8SAndroid Build Coastguard Worker else
499*2d1272b8SAndroid Build Coastguard Worker extension = "ansi";
500*2d1272b8SAndroid Build Coastguard Worker #else
501*2d1272b8SAndroid Build Coastguard Worker extension = "ansi";
502*2d1272b8SAndroid Build Coastguard Worker #endif
503*2d1272b8SAndroid Build Coastguard Worker }
504*2d1272b8SAndroid Build Coastguard Worker else
505*2d1272b8SAndroid Build Coastguard Worker #endif
506*2d1272b8SAndroid Build Coastguard Worker {
507*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PNG_FUNCTIONS
508*2d1272b8SAndroid Build Coastguard Worker extension = "png";
509*2d1272b8SAndroid Build Coastguard Worker #else
510*2d1272b8SAndroid Build Coastguard Worker extension = "ansi";
511*2d1272b8SAndroid Build Coastguard Worker #endif
512*2d1272b8SAndroid Build Coastguard Worker }
513*2d1272b8SAndroid Build Coastguard Worker }
514*2d1272b8SAndroid Build Coastguard Worker if (0)
515*2d1272b8SAndroid Build Coastguard Worker ;
516*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "ansi"))
517*2d1272b8SAndroid Build Coastguard Worker constructor2 = _cairo_ansi_surface_create_for_stream;
518*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PNG_FUNCTIONS
519*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "png"))
520*2d1272b8SAndroid Build Coastguard Worker constructor2 = _cairo_png_surface_create_for_stream;
521*2d1272b8SAndroid Build Coastguard Worker #endif
522*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SVG_SURFACE
523*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "svg"))
524*2d1272b8SAndroid Build Coastguard Worker constructor = cairo_svg_surface_create_for_stream;
525*2d1272b8SAndroid Build Coastguard Worker #endif
526*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PDF_SURFACE
527*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "pdf"))
528*2d1272b8SAndroid Build Coastguard Worker constructor = cairo_pdf_surface_create_for_stream;
529*2d1272b8SAndroid Build Coastguard Worker #endif
530*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_PS_SURFACE
531*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "ps"))
532*2d1272b8SAndroid Build Coastguard Worker constructor = cairo_ps_surface_create_for_stream;
533*2d1272b8SAndroid Build Coastguard Worker #ifdef HAS_EPS
534*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "eps"))
535*2d1272b8SAndroid Build Coastguard Worker constructor = _cairo_eps_surface_create_for_stream;
536*2d1272b8SAndroid Build Coastguard Worker #endif
537*2d1272b8SAndroid Build Coastguard Worker #ifdef CAIRO_HAS_SCRIPT_SURFACE
538*2d1272b8SAndroid Build Coastguard Worker else if (0 == g_ascii_strcasecmp (extension, "script"))
539*2d1272b8SAndroid Build Coastguard Worker constructor2 = _cairo_script_surface_create_for_stream;
540*2d1272b8SAndroid Build Coastguard Worker #endif
541*2d1272b8SAndroid Build Coastguard Worker #endif
542*2d1272b8SAndroid Build Coastguard Worker
543*2d1272b8SAndroid Build Coastguard Worker
544*2d1272b8SAndroid Build Coastguard Worker unsigned int fr, fg, fb, fa, br, bg, bb, ba;
545*2d1272b8SAndroid Build Coastguard Worker const char *color;
546*2d1272b8SAndroid Build Coastguard Worker br = bg = bb = ba = 255;
547*2d1272b8SAndroid Build Coastguard Worker color = view_opts->back ? view_opts->back : DEFAULT_BACK;
548*2d1272b8SAndroid Build Coastguard Worker parse_color (color, br, bg, bb, ba);
549*2d1272b8SAndroid Build Coastguard Worker fr = fg = fb = 0; fa = 255;
550*2d1272b8SAndroid Build Coastguard Worker color = view_opts->fore ? view_opts->fore : DEFAULT_FORE;
551*2d1272b8SAndroid Build Coastguard Worker parse_color (color, fr, fg, fb, fa);
552*2d1272b8SAndroid Build Coastguard Worker
553*2d1272b8SAndroid Build Coastguard Worker if (content == CAIRO_CONTENT_ALPHA)
554*2d1272b8SAndroid Build Coastguard Worker {
555*2d1272b8SAndroid Build Coastguard Worker if (view_opts->show_extents ||
556*2d1272b8SAndroid Build Coastguard Worker br != bg || bg != bb ||
557*2d1272b8SAndroid Build Coastguard Worker fr != fg || fg != fb)
558*2d1272b8SAndroid Build Coastguard Worker content = CAIRO_CONTENT_COLOR;
559*2d1272b8SAndroid Build Coastguard Worker }
560*2d1272b8SAndroid Build Coastguard Worker if (ba != 255)
561*2d1272b8SAndroid Build Coastguard Worker content = CAIRO_CONTENT_COLOR_ALPHA;
562*2d1272b8SAndroid Build Coastguard Worker
563*2d1272b8SAndroid Build Coastguard Worker cairo_surface_t *surface;
564*2d1272b8SAndroid Build Coastguard Worker FILE *f = out_opts->out_fp;
565*2d1272b8SAndroid Build Coastguard Worker if (constructor)
566*2d1272b8SAndroid Build Coastguard Worker surface = constructor (stdio_write_func, f, w, h);
567*2d1272b8SAndroid Build Coastguard Worker else if (constructor2)
568*2d1272b8SAndroid Build Coastguard Worker surface = constructor2 (stdio_write_func, f, w, h, content, protocol);
569*2d1272b8SAndroid Build Coastguard Worker else
570*2d1272b8SAndroid Build Coastguard Worker fail (false, "Unknown output format `%s'; supported formats are: %s%s",
571*2d1272b8SAndroid Build Coastguard Worker extension,
572*2d1272b8SAndroid Build Coastguard Worker g_strjoinv ("/", const_cast<char**> (helper_cairo_supported_formats)),
573*2d1272b8SAndroid Build Coastguard Worker out_opts->explicit_output_format ? "" :
574*2d1272b8SAndroid Build Coastguard Worker "\nTry setting format using --output-format");
575*2d1272b8SAndroid Build Coastguard Worker
576*2d1272b8SAndroid Build Coastguard Worker cairo_t *cr = cairo_create (surface);
577*2d1272b8SAndroid Build Coastguard Worker content = cairo_surface_get_content (surface);
578*2d1272b8SAndroid Build Coastguard Worker
579*2d1272b8SAndroid Build Coastguard Worker switch (content) {
580*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_ALPHA:
581*2d1272b8SAndroid Build Coastguard Worker cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
582*2d1272b8SAndroid Build Coastguard Worker cairo_set_source_rgba (cr, 1., 1., 1., br / 255.);
583*2d1272b8SAndroid Build Coastguard Worker cairo_paint (cr);
584*2d1272b8SAndroid Build Coastguard Worker cairo_set_source_rgba (cr, 1., 1., 1.,
585*2d1272b8SAndroid Build Coastguard Worker (fr / 255.) * (fa / 255.) + (br / 255) * (1 - (fa / 255.)));
586*2d1272b8SAndroid Build Coastguard Worker break;
587*2d1272b8SAndroid Build Coastguard Worker default:
588*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_COLOR:
589*2d1272b8SAndroid Build Coastguard Worker case CAIRO_CONTENT_COLOR_ALPHA:
590*2d1272b8SAndroid Build Coastguard Worker cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
591*2d1272b8SAndroid Build Coastguard Worker cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
592*2d1272b8SAndroid Build Coastguard Worker cairo_paint (cr);
593*2d1272b8SAndroid Build Coastguard Worker cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
594*2d1272b8SAndroid Build Coastguard Worker break;
595*2d1272b8SAndroid Build Coastguard Worker }
596*2d1272b8SAndroid Build Coastguard Worker
597*2d1272b8SAndroid Build Coastguard Worker cairo_surface_destroy (surface);
598*2d1272b8SAndroid Build Coastguard Worker return cr;
599*2d1272b8SAndroid Build Coastguard Worker }
600*2d1272b8SAndroid Build Coastguard Worker
601*2d1272b8SAndroid Build Coastguard Worker static inline void
helper_cairo_destroy_context(cairo_t * cr)602*2d1272b8SAndroid Build Coastguard Worker helper_cairo_destroy_context (cairo_t *cr)
603*2d1272b8SAndroid Build Coastguard Worker {
604*2d1272b8SAndroid Build Coastguard Worker finalize_closure_t *closure = (finalize_closure_t *)
605*2d1272b8SAndroid Build Coastguard Worker cairo_surface_get_user_data (cairo_get_target (cr),
606*2d1272b8SAndroid Build Coastguard Worker &finalize_closure_key);
607*2d1272b8SAndroid Build Coastguard Worker if (closure)
608*2d1272b8SAndroid Build Coastguard Worker closure->callback (closure);
609*2d1272b8SAndroid Build Coastguard Worker
610*2d1272b8SAndroid Build Coastguard Worker cairo_status_t status = cairo_status (cr);
611*2d1272b8SAndroid Build Coastguard Worker if (status != CAIRO_STATUS_SUCCESS)
612*2d1272b8SAndroid Build Coastguard Worker fail (false, "Failed: %s",
613*2d1272b8SAndroid Build Coastguard Worker cairo_status_to_string (status));
614*2d1272b8SAndroid Build Coastguard Worker cairo_destroy (cr);
615*2d1272b8SAndroid Build Coastguard Worker }
616*2d1272b8SAndroid Build Coastguard Worker
617*2d1272b8SAndroid Build Coastguard Worker
618*2d1272b8SAndroid Build Coastguard Worker struct helper_cairo_line_t {
619*2d1272b8SAndroid Build Coastguard Worker cairo_glyph_t *glyphs = nullptr;
620*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs = 0;
621*2d1272b8SAndroid Build Coastguard Worker char *utf8 = nullptr;
622*2d1272b8SAndroid Build Coastguard Worker unsigned int utf8_len = 0;
623*2d1272b8SAndroid Build Coastguard Worker cairo_text_cluster_t *clusters = nullptr;
624*2d1272b8SAndroid Build Coastguard Worker unsigned int num_clusters = 0;
625*2d1272b8SAndroid Build Coastguard Worker cairo_text_cluster_flags_t cluster_flags = (cairo_text_cluster_flags_t) 0;
626*2d1272b8SAndroid Build Coastguard Worker
helper_cairo_line_thelper_cairo_line_t627*2d1272b8SAndroid Build Coastguard Worker helper_cairo_line_t (const char *utf8_,
628*2d1272b8SAndroid Build Coastguard Worker unsigned utf8_len_,
629*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer,
630*2d1272b8SAndroid Build Coastguard Worker hb_bool_t utf8_clusters,
631*2d1272b8SAndroid Build Coastguard Worker unsigned subpixel_bits) :
632*2d1272b8SAndroid Build Coastguard Worker utf8 (utf8_ ? g_strndup (utf8_, utf8_len_) : nullptr),
633*2d1272b8SAndroid Build Coastguard Worker utf8_len (utf8_len_)
634*2d1272b8SAndroid Build Coastguard Worker {
635*2d1272b8SAndroid Build Coastguard Worker hb_cairo_glyphs_from_buffer (buffer,
636*2d1272b8SAndroid Build Coastguard Worker utf8_clusters,
637*2d1272b8SAndroid Build Coastguard Worker 1 << subpixel_bits, 1 << subpixel_bits,
638*2d1272b8SAndroid Build Coastguard Worker 0., 0.,
639*2d1272b8SAndroid Build Coastguard Worker utf8, utf8_len,
640*2d1272b8SAndroid Build Coastguard Worker &glyphs, &num_glyphs,
641*2d1272b8SAndroid Build Coastguard Worker &clusters, &num_clusters,
642*2d1272b8SAndroid Build Coastguard Worker &cluster_flags);
643*2d1272b8SAndroid Build Coastguard Worker }
644*2d1272b8SAndroid Build Coastguard Worker
finishhelper_cairo_line_t645*2d1272b8SAndroid Build Coastguard Worker void finish ()
646*2d1272b8SAndroid Build Coastguard Worker {
647*2d1272b8SAndroid Build Coastguard Worker if (glyphs)
648*2d1272b8SAndroid Build Coastguard Worker cairo_glyph_free (glyphs);
649*2d1272b8SAndroid Build Coastguard Worker if (clusters)
650*2d1272b8SAndroid Build Coastguard Worker cairo_text_cluster_free (clusters);
651*2d1272b8SAndroid Build Coastguard Worker g_free (utf8);
652*2d1272b8SAndroid Build Coastguard Worker }
653*2d1272b8SAndroid Build Coastguard Worker
get_advancehelper_cairo_line_t654*2d1272b8SAndroid Build Coastguard Worker void get_advance (double *x_advance, double *y_advance)
655*2d1272b8SAndroid Build Coastguard Worker {
656*2d1272b8SAndroid Build Coastguard Worker *x_advance = glyphs[num_glyphs].x;
657*2d1272b8SAndroid Build Coastguard Worker *y_advance = glyphs[num_glyphs].y;
658*2d1272b8SAndroid Build Coastguard Worker }
659*2d1272b8SAndroid Build Coastguard Worker };
660*2d1272b8SAndroid Build Coastguard Worker
661*2d1272b8SAndroid Build Coastguard Worker #endif
662