xref: /aosp_15_r20/external/harfbuzz_ng/util/helper-cairo.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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