18b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod/*
28b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * Copyright © 2011  Google, Inc.
38b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod *
48b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
58b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod *
68b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * Permission is hereby granted, without written agreement and without
78b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
88b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * software and its documentation for any purpose, provided that the
98b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * all copies of this software.
118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod *
128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
158b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
168b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * DAMAGE.
178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod *
188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
198b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod *
248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod * Google Author(s): Behdad Esfahbod
258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod */
268b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
278b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#include "helper-cairo.hh"
288b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#include <cairo-ft.h>
308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#include <hb-ft.h>
318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include "helper-cairo-ansi.hh"
338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#ifdef CAIRO_HAS_SVG_SURFACE
348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#  include <cairo-svg.h>
358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#endif
368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#ifdef CAIRO_HAS_PDF_SURFACE
378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#  include <cairo-pdf.h>
388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#endif
398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#ifdef CAIRO_HAS_PS_SURFACE
408b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#  include <cairo-ps.h>
418b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#  if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,6,0)
428b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#    define HAS_EPS 1
438b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
448b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_surface_t *
458b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod_cairo_eps_surface_create_for_stream (cairo_write_func_t  write_func,
468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      void               *closure,
478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      double              width,
488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      double              height)
498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
508b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
528b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  surface = cairo_ps_surface_create_for_stream (write_func, closure, width, height);
530594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod  cairo_ps_surface_set_eps (surface, true);
548b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
558b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return surface;
568b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
578b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
588b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#  else
598b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#    undef HAS_EPS
608b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#  endif
618b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#endif
628b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
638656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod
648656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbodstatic FT_Library ft_library;
658656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod
668656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbodstatic inline
678656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbodvoid free_ft_library (void)
688656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod{
698656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod  FT_Done_FreeType (ft_library);
708656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod}
718656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod
728b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodcairo_scaled_font_t *
738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_create_scaled_font (const font_options_t *font_opts,
748b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				 double font_size)
758b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
768b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_font_t *font = hb_font_reference (font_opts->get_font ());
778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_face_t *cairo_face;
798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  FT_Face ft_face = hb_ft_font_get_face (font);
808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (!ft_face)
818656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod  {
828656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod    if (!ft_library)
838656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod    {
848656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod      FT_Init_FreeType (&ft_library);
858656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod#ifdef HAVE_ATEXIT
868656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod      atexit (free_ft_library);
878656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod#endif
888656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod    }
898656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod    FT_New_Face (ft_library,
908656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod		 font_opts->font_file,
918656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod		 font_opts->face_index,
928656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod		 &ft_face);
938656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod  }
948656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod  if (!ft_face)
958656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod  {
968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    /* This allows us to get some boxes at least... */
978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    cairo_face = cairo_toy_font_face_create ("@cairo:sans",
988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					     CAIRO_FONT_SLANT_NORMAL,
998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					     CAIRO_FONT_WEIGHT_NORMAL);
1008656408572c2685f278a3b742ee69c767c29788cBehdad Esfahbod  }
1018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else
1028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
1038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_matrix_t ctm, font_matrix;
1048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_t *font_options;
1058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_matrix_init_identity (&ctm);
1078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_matrix_init_scale (&font_matrix,
1088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			   font_size, font_size);
1098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  font_options = cairo_font_options_create ();
1108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
1128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
1148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							       &font_matrix,
1158b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							       &ctm,
1168b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							       font_options);
1178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_destroy (font_options);
1198b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_face_destroy (cairo_face);
1208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  static cairo_user_data_key_t key;
1228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (cairo_scaled_font_set_user_data (scaled_font,
1238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				       &key,
1248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				       (void *) font,
1258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				       (cairo_destroy_func_t) hb_font_destroy))
1268b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    hb_font_destroy (font);
1278b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1288b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return scaled_font;
1298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
1308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstruct finalize_closure_t {
1338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  void (*callback)(finalize_closure_t *);
1348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
1358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_write_func_t write_func;
1368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  void *closure;
1378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod};
1388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_user_data_key_t finalize_closure_key;
1398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
14052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
14152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstatic void
14252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodfinalize_ansi (finalize_closure_t *closure)
14352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
14452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  cairo_status_t status;
14552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  status = helper_cairo_surface_write_to_ansi_stream (closure->surface,
14652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod						      closure->write_func,
14752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod						      closure->closure);
14852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
1490594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod    fail (false, "Failed to write output: %s",
15052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  cairo_status_to_string (status));
15152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod}
15252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
15352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstatic cairo_surface_t *
15452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod_cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func,
15552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       void *closure,
15652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       double width,
15752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       double height,
15852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       cairo_content_t content)
15952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
16052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  cairo_surface_t *surface;
16152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  int w = ceil (width);
16252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  int h = ceil (height);
16352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
16452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  switch (content) {
16552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    case CAIRO_CONTENT_ALPHA:
16652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
16752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      break;
16852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    default:
16952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    case CAIRO_CONTENT_COLOR:
17052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
17152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      break;
17252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
17352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
17452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      break;
17552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
17652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  cairo_status_t status = cairo_surface_status (surface);
17752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
1780594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod    fail (false, "Failed to create cairo surface: %s",
17952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  cairo_status_to_string (status));
18052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
18152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  finalize_closure_t *ansi_closure = g_new0 (finalize_closure_t, 1);
18252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->callback = finalize_ansi;
18352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->surface = surface;
18452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->write_func = write_func;
18552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->closure = closure;
18652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
18752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (cairo_surface_set_user_data (surface,
18852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				   &finalize_closure_key,
18952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				   (void *) ansi_closure,
19052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				   (cairo_destroy_func_t) g_free))
19152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    g_free ((void *) closure);
19252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
19352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  return surface;
19452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod}
19552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
19652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
1978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#ifdef CAIRO_HAS_PNG_FUNCTIONS
1988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic void
2008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodfinalize_png (finalize_closure_t *closure)
2018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
2028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_status_t status;
2038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  status = cairo_surface_write_to_png_stream (closure->surface,
2048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					      closure->write_func,
2058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					      closure->closure);
2068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
2070594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod    fail (false, "Failed to write output: %s",
2088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cairo_status_to_string (status));
2098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
2108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_surface_t *
2128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod_cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
2138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      void *closure,
2148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      double width,
2158b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      double height,
2168b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      cairo_content_t content)
2178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
2188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
2198b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  int w = ceil (width);
2208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  int h = ceil (height);
2218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  switch (content) {
2238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_ALPHA:
2248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
2258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
2268b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    default:
2278b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR:
2288b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
2298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
2308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
2318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
2328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
2338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
2348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_status_t status = cairo_surface_status (surface);
2358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
2360594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod    fail (false, "Failed to create cairo surface: %s",
2378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cairo_status_to_string (status));
2388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  finalize_closure_t *png_closure = g_new0 (finalize_closure_t, 1);
2408b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->callback = finalize_png;
2418b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->surface = surface;
2428b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->write_func = write_func;
2438b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->closure = closure;
2448b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2458b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (cairo_surface_set_user_data (surface,
2468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   &finalize_closure_key,
2478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   (void *) png_closure,
2488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   (cairo_destroy_func_t) g_free))
2498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    g_free ((void *) closure);
2508b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return surface;
2528b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
2538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2548b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#endif
2558b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2568b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_status_t
2578b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstdio_write_func (void                *closure,
2588b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod		  const unsigned char *data,
2598b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod		  unsigned int         size)
2608b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
2618b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  FILE *fp = (FILE *) closure;
2628b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2638b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  while (size) {
2648b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    size_t ret = fwrite (data, 1, size, fp);
2658b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    size -= ret;
2668b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    data += ret;
2678b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    if (size && ferror (fp))
2680594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod      fail (false, "Failed to write output: %s", strerror (errno));
2698b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
2708b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2718b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return CAIRO_STATUS_SUCCESS;
2728b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
2738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
274ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbodconst char *helper_cairo_supported_formats[] =
275ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod{
276ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod  "ansi",
277f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #ifdef CAIRO_HAS_PNG_FUNCTIONS
278ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod  "png",
279f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #endif
280f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #ifdef CAIRO_HAS_SVG_SURFACE
281ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod  "svg",
282f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #endif
283f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #ifdef CAIRO_HAS_PDF_SURFACE
284ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod  "pdf",
285f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #endif
286f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #ifdef CAIRO_HAS_PS_SURFACE
287ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod  "ps",
288f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod   #ifdef HAS_EPS
289ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod    "eps",
290f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod   #endif
291f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod  #endif
292ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod  NULL
293ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod};
294f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod
2958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodcairo_t *
2968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_create_context (double w, double h,
2978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			     view_options_t *view_opts,
2988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			     output_options_t *out_opts)
2998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
3008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
3018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   void *closure,
3028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   double width,
3038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   double height) = NULL;
3048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
3058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    void *closure,
3068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    double width,
3078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    double height,
3088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    cairo_content_t content) = NULL;
3098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  const char *extension = out_opts->output_format;
31152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (!extension) {
31252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#if HAVE_ISATTY
31352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    if (isatty (fileno (out_opts->get_file_handle ())))
31452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      extension = "ansi";
31552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    else
31652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#endif
317f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod    {
318f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod#ifdef CAIRO_HAS_PNG_FUNCTIONS
31952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      extension = "png";
320f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod#else
321f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod      extension = "ansi";
322f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod#endif
323f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod    }
32452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
3258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (0)
3268b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    ;
32752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    else if (0 == strcasecmp (extension, "ansi"))
32852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      constructor2 = _cairo_ansi_surface_create_for_stream;
3298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_PNG_FUNCTIONS
3308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "png"))
3318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor2 = _cairo_png_surface_create_for_stream;
3328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
3338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_SVG_SURFACE
3348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "svg"))
3358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = cairo_svg_surface_create_for_stream;
3368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
3378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_PDF_SURFACE
3388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "pdf"))
3398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = cairo_pdf_surface_create_for_stream;
3408b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
3418b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_PS_SURFACE
3428b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "ps"))
3438b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = cairo_ps_surface_create_for_stream;
3448b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod   #ifdef HAS_EPS
3458b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "eps"))
3468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = _cairo_eps_surface_create_for_stream;
3478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod   #endif
3488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
3498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3508b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  unsigned int fr, fg, fb, fa, br, bg, bb, ba;
3528f8956a55fff95e5ad529d2f124c9528d1f4f81dBehdad Esfahbod  br = bg = bb = 0; ba = 255;
3538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  sscanf (view_opts->back + (*view_opts->back=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
3548b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  fr = fg = fb = 0; fa = 255;
3558b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  sscanf (view_opts->fore + (*view_opts->fore=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
3568b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3578b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_content_t content;
3588b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (!view_opts->annotate && ba == 255 && br == bg && bg == bb && fr == fg && fg == fb)
3598b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    content = CAIRO_CONTENT_ALPHA;
3608b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else if (ba == 255)
3618b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    content = CAIRO_CONTENT_COLOR;
3628b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else
3638b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    content = CAIRO_CONTENT_COLOR_ALPHA;
3648b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3658b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
3668b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  FILE *f = out_opts->get_file_handle ();
3678b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (constructor)
3688b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    surface = constructor (stdio_write_func, f, w, h);
3698b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else if (constructor2)
3708b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    surface = constructor2 (stdio_write_func, f, w, h, content);
3718b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else
372f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod    fail (false, "Unknown output format `%s'; supported formats are: %s%s",
373ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod	  extension,
374ea5e8a02eb83ad19f3009b0008893f77ce113118Behdad Esfahbod	  g_strjoinv ("/", const_cast<char**> (helper_cairo_supported_formats)),
375f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod	  out_opts->explicit_output_format ? "" :
376f95a87b7b813f588c7910ad4785ee68bb452e864Behdad Esfahbod	  "\nTry setting format using --output-format");
3778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_t *cr = cairo_create (surface);
3798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  content = cairo_surface_get_content (surface);
3808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3818b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  switch (content) {
3828b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_ALPHA:
3838b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3848b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 1., 1., br / 255.);
3858b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_paint (cr);
3868b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 1., 1.,
3878b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			     (fr / 255.) * (fa / 255.) + (br / 255) * (1 - (fa / 255.)));
3888b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
3898b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    default:
3908b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR:
3918b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
3928b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3938b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
3948b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_paint (cr);
3958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
3968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
3978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
3988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
3998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_destroy (surface);
4018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return cr;
4028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
4038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodvoid
4058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_destroy_context (cairo_t *cr)
4068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
4078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  finalize_closure_t *closure = (finalize_closure_t *)
4088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				cairo_surface_get_user_data (cairo_get_target (cr),
4098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							     &finalize_closure_key);
4108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (closure)
4118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    closure->callback (closure);
4128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_status_t status = cairo_status (cr);
4148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
4150594a2448440208efa0acac9a5d8d52d43108289Behdad Esfahbod    fail (false, "Failed: %s",
4168b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cairo_status_to_string (status));
4178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_destroy (cr);
4188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
4198b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodvoid
4228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_line_from_buffer (helper_cairo_line_t *l,
4238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			       hb_buffer_t         *buffer,
4248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			       const char          *text,
4258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			       unsigned int         text_len,
42695cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod			       double               scale,
42795cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod			       hb_bool_t            utf8_clusters)
4288b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
4298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  memset (l, 0, sizeof (*l));
4308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->num_glyphs = hb_buffer_get_length (buffer);
4328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, NULL);
4338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, NULL);
4348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs = cairo_glyph_allocate (l->num_glyphs + 1);
4358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (text) {
4378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->utf8 = g_strndup (text, text_len);
4388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->utf8_len = text_len;
4398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->num_clusters = l->num_glyphs ? 1 : 0;
4408b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    for (unsigned int i = 1; i < l->num_glyphs; i++)
4418b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
4428b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	l->num_clusters++;
4438b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->clusters = cairo_text_cluster_allocate (l->num_clusters);
4448b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
4458b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if ((l->num_glyphs && !l->glyphs) ||
4478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      (l->utf8_len && !l->utf8) ||
4488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      (l->num_clusters && !l->clusters))
4498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  {
4508b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->finish ();
4518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    return;
4528b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
4538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4548b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_position_t x = 0, y = 0;
4558b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  int i;
4568b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  for (i = 0; i < (int) l->num_glyphs; i++)
4578b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  {
4588b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->glyphs[i].index = hb_glyph[i].codepoint;
4598b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->glyphs[i].x = ( hb_position->x_offset + x) * scale;
4608b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->glyphs[i].y = (-hb_position->y_offset + y) * scale;
4618b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    x +=  hb_position->x_advance;
4628b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    y += -hb_position->y_advance;
4638b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4648b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    hb_position++;
4658b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
4668b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs[i].index = -1;
4678b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs[i].x = x * scale;
4688b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs[i].y = y * scale;
4698b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4708b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (l->num_clusters) {
4718b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    memset ((void *) l->clusters, 0, l->num_clusters * sizeof (l->clusters[0]));
472088c1e27c0fc0cdef999cf1f567e4d5eb2cfb2e4Behdad Esfahbod    hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
4738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
4748b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    unsigned int cluster = 0;
475a18280a8ce9128fc9d75f8a367ae8ce0886a9599Behdad Esfahbod    const char *start = l->utf8, *end;
4768b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->clusters[cluster].num_glyphs++;
4778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    if (backward) {
4788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      for (i = l->num_glyphs - 2; i >= 0; i--) {
4798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) {
4808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  g_assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
48195cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  if (utf8_clusters)
48295cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
48395cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  else
48495cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i+1].cluster);
48595cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  l->clusters[cluster].num_bytes = end - start;
48695cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  start = end;
4878b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cluster++;
4888b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	}
4898b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	l->clusters[cluster].num_glyphs++;
4908b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      }
49195cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod      l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
4928b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    } else {
4938b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      for (i = 1; i < (int) l->num_glyphs; i++) {
4948b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) {
4958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  g_assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
49695cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  if (utf8_clusters)
49795cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
49895cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  else
49995cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i-1].cluster);
50095cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  l->clusters[cluster].num_bytes = end - start;
50195cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  start = end;
5028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cluster++;
5038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	}
5048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	l->clusters[cluster].num_glyphs++;
5058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      }
50695cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod      l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
5078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    }
5088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
5098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
510