helper-cairo.cc revision 52e7b1424a3613122e9ca30879298df42733acda
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);
538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad 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
638b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodcairo_scaled_font_t *
648b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_create_scaled_font (const font_options_t *font_opts,
658b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				 double font_size)
668b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
678b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_font_t *font = hb_font_reference (font_opts->get_font ());
688b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
698b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_face_t *cairo_face;
708b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  FT_Face ft_face = hb_ft_font_get_face (font);
718b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (!ft_face)
728b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    /* This allows us to get some boxes at least... */
738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    cairo_face = cairo_toy_font_face_create ("@cairo:sans",
748b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					     CAIRO_FONT_SLANT_NORMAL,
758b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					     CAIRO_FONT_WEIGHT_NORMAL);
768b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else
778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_matrix_t ctm, font_matrix;
798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_t *font_options;
808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
818b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_matrix_init_identity (&ctm);
828b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_matrix_init_scale (&font_matrix,
838b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			   font_size, font_size);
848b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  font_options = cairo_font_options_create ();
858b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
868b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
878b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
888b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
898b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							       &font_matrix,
908b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							       &ctm,
918b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							       font_options);
928b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
938b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_options_destroy (font_options);
948b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_font_face_destroy (cairo_face);
958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  static cairo_user_data_key_t key;
978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (cairo_scaled_font_set_user_data (scaled_font,
988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				       &key,
998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				       (void *) font,
1008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				       (cairo_destroy_func_t) hb_font_destroy))
1018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    hb_font_destroy (font);
1028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return scaled_font;
1048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
1058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstruct finalize_closure_t {
1088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  void (*callback)(finalize_closure_t *);
1098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
1108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_write_func_t write_func;
1118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  void *closure;
1128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod};
1138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_user_data_key_t finalize_closure_key;
1148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
11552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
11652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstatic void
11752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodfinalize_ansi (finalize_closure_t *closure)
11852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
11952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  cairo_status_t status;
12052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  status = helper_cairo_surface_write_to_ansi_stream (closure->surface,
12152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod						      closure->write_func,
12252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod						      closure->closure);
12352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
12452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    fail (FALSE, "Failed to write output: %s",
12552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  cairo_status_to_string (status));
12652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod}
12752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
12852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstatic cairo_surface_t *
12952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod_cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func,
13052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       void *closure,
13152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       double width,
13252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       double height,
13352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				       cairo_content_t content)
13452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
13552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  cairo_surface_t *surface;
13652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  int w = ceil (width);
13752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  int h = ceil (height);
13852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
13952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  switch (content) {
14052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    case CAIRO_CONTENT_ALPHA:
14152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
14252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      break;
14352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    default:
14452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    case CAIRO_CONTENT_COLOR:
14552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
14652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      break;
14752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
14852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
14952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      break;
15052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
15152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  cairo_status_t status = cairo_surface_status (surface);
15252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
15352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    fail (FALSE, "Failed to create cairo surface: %s",
15452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  cairo_status_to_string (status));
15552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
15652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  finalize_closure_t *ansi_closure = g_new0 (finalize_closure_t, 1);
15752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->callback = finalize_ansi;
15852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->surface = surface;
15952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->write_func = write_func;
16052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ansi_closure->closure = closure;
16152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
16252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (cairo_surface_set_user_data (surface,
16352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				   &finalize_closure_key,
16452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				   (void *) ansi_closure,
16552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod				   (cairo_destroy_func_t) g_free))
16652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    g_free ((void *) closure);
16752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
16852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  return surface;
16952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod}
17052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
17152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
1728b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#ifdef CAIRO_HAS_PNG_FUNCTIONS
1738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1748b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic void
1758b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodfinalize_png (finalize_closure_t *closure)
1768b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
1778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_status_t status;
1788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  status = cairo_surface_write_to_png_stream (closure->surface,
1798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					      closure->write_func,
1808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod					      closure->closure);
1818b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
1828b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    fail (FALSE, "Failed to write output: %s",
1838b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cairo_status_to_string (status));
1848b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
1858b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1868b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_surface_t *
1878b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod_cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
1888b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      void *closure,
1898b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      double width,
1908b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      double height,
1918b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				      cairo_content_t content)
1928b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
1938b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
1948b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  int w = ceil (width);
1958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  int h = ceil (height);
1968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
1978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  switch (content) {
1988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_ALPHA:
1998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
2008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
2018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    default:
2028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR:
2038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
2048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
2058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
2068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
2078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
2088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
2098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_status_t status = cairo_surface_status (surface);
2108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
2118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    fail (FALSE, "Failed to create cairo surface: %s",
2128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cairo_status_to_string (status));
2138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  finalize_closure_t *png_closure = g_new0 (finalize_closure_t, 1);
2158b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->callback = finalize_png;
2168b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->surface = surface;
2178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->write_func = write_func;
2188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  png_closure->closure = closure;
2198b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (cairo_surface_set_user_data (surface,
2218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   &finalize_closure_key,
2228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   (void *) png_closure,
2238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   (cairo_destroy_func_t) g_free))
2248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    g_free ((void *) closure);
2258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2268b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return surface;
2278b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
2288b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod#endif
2308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstatic cairo_status_t
2328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodstdio_write_func (void                *closure,
2338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod		  const unsigned char *data,
2348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod		  unsigned int         size)
2358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
2368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  FILE *fp = (FILE *) closure;
2378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  while (size) {
2398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    size_t ret = fwrite (data, 1, size, fp);
2408b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    size -= ret;
2418b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    data += ret;
2428b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    if (size && ferror (fp))
2438b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      fail (FALSE, "Failed to write output: %s", strerror (errno));
2448b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
2458b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return CAIRO_STATUS_SUCCESS;
2478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
2488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodcairo_t *
2508b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_create_context (double w, double h,
2518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			     view_options_t *view_opts,
2528b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			     output_options_t *out_opts)
2538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
2548b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
2558b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   void *closure,
2568b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   double width,
2578b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				   double height) = NULL;
2588b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
2598b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    void *closure,
2608b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    double width,
2618b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    double height,
2628b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				    cairo_content_t content) = NULL;
2638b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2648b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  const char *extension = out_opts->output_format;
26552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (!extension) {
26652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#if HAVE_ISATTY
26752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    if (isatty (fileno (out_opts->get_file_handle ())))
26852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      extension = "ansi";
26952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    else
27052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#endif
27152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      extension = "png";
27252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
2738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (0)
2748b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    ;
27552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    else if (0 == strcasecmp (extension, "ansi"))
27652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      constructor2 = _cairo_ansi_surface_create_for_stream;
2778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_PNG_FUNCTIONS
2788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "png"))
2798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor2 = _cairo_png_surface_create_for_stream;
2808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
2818b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_SVG_SURFACE
2828b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "svg"))
2838b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = cairo_svg_surface_create_for_stream;
2848b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
2858b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_PDF_SURFACE
2868b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "pdf"))
2878b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = cairo_pdf_surface_create_for_stream;
2888b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
2898b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #ifdef CAIRO_HAS_PS_SURFACE
2908b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "ps"))
2918b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = cairo_ps_surface_create_for_stream;
2928b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod   #ifdef HAS_EPS
2938b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    else if (0 == strcasecmp (extension, "eps"))
2948b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      constructor = _cairo_eps_surface_create_for_stream;
2958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod   #endif
2968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  #endif
2978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
2998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  unsigned int fr, fg, fb, fa, br, bg, bb, ba;
3008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  br = bg = bb = ba = 255;
3018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  sscanf (view_opts->back + (*view_opts->back=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
3028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  fr = fg = fb = 0; fa = 255;
3038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  sscanf (view_opts->fore + (*view_opts->fore=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
3048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_content_t content;
3068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (!view_opts->annotate && ba == 255 && br == bg && bg == bb && fr == fg && fg == fb)
3078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    content = CAIRO_CONTENT_ALPHA;
3088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else if (ba == 255)
3098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    content = CAIRO_CONTENT_COLOR;
3108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else
3118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    content = CAIRO_CONTENT_COLOR_ALPHA;
3128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_t *surface;
3148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  FILE *f = out_opts->get_file_handle ();
3158b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (constructor)
3168b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    surface = constructor (stdio_write_func, f, w, h);
3178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else if (constructor2)
3188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    surface = constructor2 (stdio_write_func, f, w, h, content);
3198b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  else
3208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    fail (FALSE, "Unknown output format `%s'", extension);
3218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_t *cr = cairo_create (surface);
3238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  content = cairo_surface_get_content (surface);
3248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3258b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  switch (content) {
3268b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_ALPHA:
3278b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3288b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 1., 1., br / 255.);
3298b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_paint (cr);
3308b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 1., 1.,
3318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			     (fr / 255.) * (fa / 255.) + (br / 255) * (1 - (fa / 255.)));
3328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
3338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    default:
3348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR:
3358b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
3368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
3388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_paint (cr);
3398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
3408b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
3418b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      break;
3428b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
3438b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3448b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_surface_destroy (surface);
3458b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  return cr;
3468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
3478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodvoid
3498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_destroy_context (cairo_t *cr)
3508b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
3518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  finalize_closure_t *closure = (finalize_closure_t *)
3528b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod				cairo_surface_get_user_data (cairo_get_target (cr),
3538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod							     &finalize_closure_key);
3548b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (closure)
3558b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    closure->callback (closure);
3568b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3578b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_status_t status = cairo_status (cr);
3588b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
3598b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    fail (FALSE, "Failed: %s",
3608b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cairo_status_to_string (status));
3618b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  cairo_destroy (cr);
3628b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
3638b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3648b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3658b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodvoid
3668b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbodhelper_cairo_line_from_buffer (helper_cairo_line_t *l,
3678b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			       hb_buffer_t         *buffer,
3688b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			       const char          *text,
3698b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod			       unsigned int         text_len,
37095cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod			       double               scale,
37195cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod			       hb_bool_t            utf8_clusters)
3728b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod{
3738b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  memset (l, 0, sizeof (*l));
3748b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3758b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->num_glyphs = hb_buffer_get_length (buffer);
3768b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, NULL);
3778b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, NULL);
3788b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs = cairo_glyph_allocate (l->num_glyphs + 1);
3798b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3808b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (text) {
3818b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->utf8 = g_strndup (text, text_len);
3828b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->utf8_len = text_len;
3838b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->num_clusters = l->num_glyphs ? 1 : 0;
3848b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    for (unsigned int i = 1; i < l->num_glyphs; i++)
3858b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
3868b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	l->num_clusters++;
3878b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->clusters = cairo_text_cluster_allocate (l->num_clusters);
3888b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
3898b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3908b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if ((l->num_glyphs && !l->glyphs) ||
3918b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      (l->utf8_len && !l->utf8) ||
3928b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      (l->num_clusters && !l->clusters))
3938b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  {
3948b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->finish ();
3958b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    return;
3968b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
3978b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
3988b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  hb_position_t x = 0, y = 0;
3998b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  int i;
4008b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  for (i = 0; i < (int) l->num_glyphs; i++)
4018b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  {
4028b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->glyphs[i].index = hb_glyph[i].codepoint;
4038b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->glyphs[i].x = ( hb_position->x_offset + x) * scale;
4048b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->glyphs[i].y = (-hb_position->y_offset + y) * scale;
4058b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    x +=  hb_position->x_advance;
4068b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    y += -hb_position->y_advance;
4078b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4088b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    hb_position++;
4098b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
4108b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs[i].index = -1;
4118b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs[i].x = x * scale;
4128b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  l->glyphs[i].y = y * scale;
4138b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod
4148b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  if (l->num_clusters) {
4158b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    memset ((void *) l->clusters, 0, l->num_clusters * sizeof (l->clusters[0]));
416088c1e27c0fc0cdef999cf1f567e4d5eb2cfb2e4Behdad Esfahbod    hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
4178b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
4188b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    unsigned int cluster = 0;
41995cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod    const char *start = l->utf8, *end = start;
4208b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    l->clusters[cluster].num_glyphs++;
4218b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    if (backward) {
4228b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      for (i = l->num_glyphs - 2; i >= 0; i--) {
4238b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) {
4248b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  g_assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
42595cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  if (utf8_clusters)
42695cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
42795cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  else
42895cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i+1].cluster);
42995cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  l->clusters[cluster].num_bytes = end - start;
43095cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  start = end;
4318b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cluster++;
4328b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	}
4338b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	l->clusters[cluster].num_glyphs++;
4348b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      }
43595cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod      l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
4368b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    } else {
4378b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      for (i = 1; i < (int) l->num_glyphs; i++) {
4388b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) {
4398b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  g_assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
44095cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  if (utf8_clusters)
44195cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
44295cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  else
44395cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	    end = g_utf8_offset_to_pointer (start, hb_glyph[i].cluster - hb_glyph[i-1].cluster);
44495cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  l->clusters[cluster].num_bytes = end - start;
44595cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod	  start = end;
4468b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	  cluster++;
4478b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	}
4488b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod	l->clusters[cluster].num_glyphs++;
4498b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod      }
45095cefdf96efe43a44133aa8a186155cf4e63e2b7Behdad Esfahbod      l->clusters[cluster].num_bytes = l->utf8 + text_len - start;
4518b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod    }
4528b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod  }
4538b8b19056decaf09e4e0ccd9412ee1aeb30f4de7Behdad Esfahbod}
454