view-cairo.cc revision f6496663c2f6849a944e41afcf9511f378477532
1b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod/*
2b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * Copyright © 2011  Google, Inc.
3b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod *
4b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
5b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod *
6b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * Permission is hereby granted, without written agreement and without
7b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
8b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * software and its documentation for any purpose, provided that the
9b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
10b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * all copies of this software.
11b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod *
12b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * DAMAGE.
17b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod *
18b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod *
24b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod * Google Author(s): Behdad Esfahbod
25b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod */
26b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
27b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#include "view-cairo.hh"
28b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
29b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
30b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#ifdef CAIRO_HAS_SVG_SURFACE
31b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#  include <cairo-svg.h>
32b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#endif
33b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#ifdef CAIRO_HAS_PDF_SURFACE
34b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#  include <cairo-pdf.h>
35b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#endif
36b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#ifdef CAIRO_HAS_PS_SURFACE
37b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#  include <cairo-ps.h>
38b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#  if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,6,0)
39b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#    define HAS_EPS 1
40b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
41b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodstatic cairo_surface_t *
42f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod_cairo_eps_surface_create_for_stream (cairo_write_func_t  write_func,
43f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      void               *closure,
44f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      double              width,
45f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      double              height)
46b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
47b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_surface_t *surface;
48b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
49f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  surface = cairo_ps_surface_create_for_stream (write_func, closure, width, height);
50b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_ps_surface_set_eps (surface, TRUE);
51b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
52b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  return surface;
53b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
54b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
55b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#  else
56b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#    undef HAS_EPS
57b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#  endif
58b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#endif
59b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
60b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodstruct line_t {
61b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_glyph_t *glyphs;
62b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  unsigned int num_glyphs;
63b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  char *utf8;
64b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  unsigned int utf8_len;
65b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_text_cluster_t *clusters;
66b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  unsigned int num_clusters;
67b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_text_cluster_flags_t cluster_flags;
68b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
69b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  void finish (void) {
70b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    if (glyphs)
71b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_glyph_free (glyphs);
72b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    if (clusters)
73b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_text_cluster_free (clusters);
74b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    if (utf8)
75b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      g_free (utf8);
76b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
77b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod};
78b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
79b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodvoid
80b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::init (const font_options_t *font_opts)
81b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
82b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  lines = g_array_new (FALSE, FALSE, sizeof (line_t));
8311e51993ab562d4c7460eb7c43d0e97404e628e7Behdad Esfahbod  scale = double (font_size) / hb_face_get_upem (hb_font_get_face (font_opts->get_font ()));
84b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
85b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
86b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodvoid
87b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::consume_line (hb_buffer_t  *buffer,
88b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod			    const char   *text,
89b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod			    unsigned int  text_len)
90b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
91b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  line_t l = {0};
92b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
93b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  l.num_glyphs = hb_buffer_get_length (buffer);
94b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, NULL);
95b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, NULL);
96b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  l.glyphs = cairo_glyph_allocate (l.num_glyphs + 1);
97f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod
98f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod  if (text) {
99f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.utf8 = g_strndup (text, text_len);
100f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.utf8_len = text_len;
101f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.num_clusters = l.num_glyphs ? 1 : 0;
102f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    for (unsigned int i = 1; i < l.num_glyphs; i++)
103f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
104f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	l.num_clusters++;
105f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.clusters = cairo_text_cluster_allocate (l.num_clusters);
106f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod  } else {
107f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.utf8_len = 0;
108f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.num_clusters = 0;
109f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod  }
110b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
111b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if ((l.num_glyphs && !l.glyphs) ||
112b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      (l.utf8_len && !l.utf8) ||
113b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      (l.num_clusters && !l.clusters))
114b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  {
115b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    l.finish ();
116b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    return;
117b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
118b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
119b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  hb_position_t x = 0, y = 0;
120b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  int i;
121b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  for (i = 0; i < (int) l.num_glyphs; i++)
122f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod  {
123f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.glyphs[i].index = hb_glyph[i].codepoint;
124f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.glyphs[i].x = ( hb_position->x_offset + x) * scale;
125f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.glyphs[i].y = (-hb_position->y_offset + y) * scale;
126f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    x +=  hb_position->x_advance;
127f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    y += -hb_position->y_advance;
128f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod
129f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    hb_position++;
130f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod  }
131b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  l.glyphs[i].index = 0;
132b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  l.glyphs[i].x = x;
133b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  l.glyphs[i].y = y;
134b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
135f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod  if (l.num_clusters) {
136f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    memset ((void *) l.clusters, 0, l.num_clusters * sizeof (l.clusters[0]));
137f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    bool backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
138f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
139f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    unsigned int cluster = 0;
140f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    if (!l.num_glyphs)
141f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      goto done;
142f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    l.clusters[cluster].num_glyphs++;
143f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    if (backward) {
144f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      for (i = l.num_glyphs - 2; i >= 0; i--) {
145f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) {
146f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	  g_assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
147f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	  l.clusters[cluster].num_bytes += hb_glyph[i].cluster - hb_glyph[i+1].cluster;
148f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	  cluster++;
149f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	}
150f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	l.clusters[cluster].num_glyphs++;
151b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      }
152f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      l.clusters[cluster].num_bytes += text_len - hb_glyph[0].cluster;
153f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    } else {
154f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      for (i = 1; i < (int) l.num_glyphs; i++) {
155f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) {
156f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	  g_assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
157f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	  l.clusters[cluster].num_bytes += hb_glyph[i].cluster - hb_glyph[i-1].cluster;
158f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	  cluster++;
159f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	}
160f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod	l.clusters[cluster].num_glyphs++;
161b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      }
162f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      l.clusters[cluster].num_bytes += text_len - hb_glyph[i - 1].cluster;
163b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    }
164b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
165b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
16655aeb0490454cc1ba93a42f307ed1230f59dee4bBehdad Esfahboddone:
167b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  g_array_append_val (lines, l);
168b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
169b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
170b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodvoid
171b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::finish (const font_options_t *font_opts)
172b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
173b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  render (font_opts);
174b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
175b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  for (unsigned int i = 0; i < lines->len; i++) {
176b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    line_t &line = g_array_index (lines, line_t, i);
177b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    line.finish ();
178b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
179b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
180b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  g_array_unref (lines);
181b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
182b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
183b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahboddouble
184b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::line_width (unsigned int i)
185b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
186b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  line_t &line = g_array_index (lines, line_t, i);
1877bf6ecd3bfb1ccf5d9ac6fe274efa74b46885feaBehdad Esfahbod  return line.glyphs[line.num_glyphs].x * scale;
188b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
189b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
190b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodvoid
191b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::get_surface_size (cairo_scaled_font_t *scaled_font,
192b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				double *w, double *h)
193b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
194b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_extents_t font_extents;
195b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
196b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_scaled_font_extents (scaled_font, &font_extents);
197b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
198da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod  *h = font_extents.ascent
199da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod     + font_extents.descent
200da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod     + ((int) lines->len - 1) * font_extents.height;
201b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  *w = 0;
202b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  for (unsigned int i = 0; i < lines->len; i++)
203b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    *w = MAX (*w, line_width (i));
204b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
205b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  *w += margin.l + margin.r;
206b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  *h += margin.t + margin.b;
207b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
208b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
209b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodcairo_scaled_font_t *
210b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::create_scaled_font (const font_options_t *font_opts)
211b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
212b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  hb_font_t *font = hb_font_reference (font_opts->get_font ());
213b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
2144274ed7ab6fb03fbf8eaaa43ab06647dc0beed79Behdad Esfahbod  cairo_font_face_t *cairo_face;
2154274ed7ab6fb03fbf8eaaa43ab06647dc0beed79Behdad Esfahbod  FT_Face ft_face = hb_ft_font_get_face (font);
2164274ed7ab6fb03fbf8eaaa43ab06647dc0beed79Behdad Esfahbod  if (!ft_face)
2174274ed7ab6fb03fbf8eaaa43ab06647dc0beed79Behdad Esfahbod    /* This allows us to get some boxes at least... */
218d2b3ab9ecebbf46cb9dac1f09c17379c50ea4575Behdad Esfahbod    cairo_face = cairo_toy_font_face_create ("@cairo:sans",
219da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod					     CAIRO_FONT_SLANT_NORMAL,
220da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod					     CAIRO_FONT_WEIGHT_NORMAL);
2214274ed7ab6fb03fbf8eaaa43ab06647dc0beed79Behdad Esfahbod  else
2224274ed7ab6fb03fbf8eaaa43ab06647dc0beed79Behdad Esfahbod    cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
223b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_matrix_t ctm, font_matrix;
224b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_options_t *font_options;
225b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
226b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_matrix_init_identity (&ctm);
227da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod  cairo_matrix_init_scale (&font_matrix,
22811e51993ab562d4c7460eb7c43d0e97404e628e7Behdad Esfahbod			   font_size, font_size);
229b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  font_options = cairo_font_options_create ();
230b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
231b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
232b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
233da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod  cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
234da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod							       &font_matrix,
235da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod							       &ctm,
236da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod							       font_options);
237b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
238b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_options_destroy (font_options);
239b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_face_destroy (cairo_face);
240b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
241b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  static cairo_user_data_key_t key;
242da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod  if (cairo_scaled_font_set_user_data (scaled_font,
243da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod				       &key,
244da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod				       (void *) font,
245da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod				       (cairo_destroy_func_t) hb_font_destroy))
246b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    hb_font_destroy (font);
247b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
248b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  return scaled_font;
249b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
250b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
251b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodstruct finalize_closure_t {
252b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  void (*callback)(finalize_closure_t *);
253b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_surface_t *surface;
254f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  cairo_write_func_t write_func;
255f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  void *closure;
256b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod};
257b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodstatic cairo_user_data_key_t finalize_closure_key;
258b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
259b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#ifdef CAIRO_HAS_PNG_FUNCTIONS
260b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
261b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodstatic void
262b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodfinalize_png (finalize_closure_t *closure)
263b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
264b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_status_t status;
265f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  status = cairo_surface_write_to_png_stream (closure->surface,
266f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod					      closure->write_func,
267f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod					      closure->closure);
268b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
269f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    fail (FALSE, "Failed to write output: %s",
270f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod	  cairo_status_to_string (status));
271b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
272b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
273b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodstatic cairo_surface_t *
274f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod_cairo_png_surface_create_for_stream (cairo_write_func_t write_func,
275f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      void *closure,
276f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      double width,
277f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      double height,
278f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				      cairo_content_t content)
279b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
280b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_surface_t *surface;
281b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  int w = ceil (width);
282b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  int h = ceil (height);
283b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
284b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  switch (content) {
285b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    case CAIRO_CONTENT_ALPHA:
286b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_A8, w, h);
287b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      break;
288b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    default:
289b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    case CAIRO_CONTENT_COLOR:
290b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, w, h);
291b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      break;
292b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
293b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
294b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      break;
295b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
296b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_status_t status = cairo_surface_status (surface);
297b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
298b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    fail (FALSE, "Failed to create cairo surface: %s",
299b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod	  cairo_status_to_string (status));
300b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
301f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  finalize_closure_t *png_closure = g_new0 (finalize_closure_t, 1);
302f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  png_closure->callback = finalize_png;
303f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  png_closure->surface = surface;
304f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  png_closure->write_func = write_func;
305f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  png_closure->closure = closure;
306b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
307da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod  if (cairo_surface_set_user_data (surface,
308da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod				   &finalize_closure_key,
309da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod				   (void *) png_closure,
310da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod				   (cairo_destroy_func_t) g_free))
311b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    g_free ((void *) closure);
312b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
313b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  return surface;
314b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
315b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
316b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod#endif
317b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
318b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodvoid
319b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::render (const font_options_t *font_opts)
320b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
321b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_scaled_font_t *scaled_font = create_scaled_font (font_opts);
322b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  double w, h;
323b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  get_surface_size (scaled_font, &w, &h);
324b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_t *cr = create_context (w, h);
325b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_set_scaled_font (cr, scaled_font);
326b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_scaled_font_destroy (scaled_font);
327b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
328b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  draw (cr);
329b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
330b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  finalize_closure_t *closure = (finalize_closure_t *)
331b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				cairo_surface_get_user_data (cairo_get_target (cr),
332b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod							     &finalize_closure_key);
333b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (closure)
334b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    closure->callback (closure);
335b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
336b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_status_t status = cairo_status (cr);
337b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (status != CAIRO_STATUS_SUCCESS)
338b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    fail (FALSE, "Failed: %s",
339b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod	  cairo_status_to_string (status));
340b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_destroy (cr);
341b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
342b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
343f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbodstatic cairo_status_t
344f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbodstdio_write_func (void                *closure,
345f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod		  const unsigned char *data,
346f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod		  unsigned int         size)
347f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod{
348f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  FILE *fp = (FILE *) closure;
349f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod
350f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  while (size) {
351f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    size_t ret = fwrite (data, 1, size, fp);
352f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    size -= ret;
353f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    data += ret;
354f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    if (size && ferror (fp))
355f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod      fail (FALSE, "Failed to write output: %s", strerror (errno));
356f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  }
357f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod
358f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  return CAIRO_STATUS_SUCCESS;
359f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod}
360f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod
361b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodcairo_t *
362b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::create_context (double w, double h)
363b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
364f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  cairo_surface_t *(*constructor) (cairo_write_func_t write_func,
365f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				   void *closure,
366b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				   double width,
367b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				   double height) = NULL;
368f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  cairo_surface_t *(*constructor2) (cairo_write_func_t write_func,
369f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod				    void *closure,
370b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				    double width,
371b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				    double height,
372b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod				    cairo_content_t content) = NULL;
373b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
374b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  const char *extension = output_format;
375b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (!extension)
376b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    extension = "png";
377b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (0)
378b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    ;
379b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #ifdef CAIRO_HAS_PNG_FUNCTIONS
380b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    else if (0 == strcasecmp (extension, "png"))
381f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod      constructor2 = _cairo_png_surface_create_for_stream;
382b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #endif
383b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #ifdef CAIRO_HAS_SVG_SURFACE
384b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    else if (0 == strcasecmp (extension, "svg"))
385f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod      constructor = cairo_svg_surface_create_for_stream;
386b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #endif
387b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #ifdef CAIRO_HAS_PDF_SURFACE
388b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    else if (0 == strcasecmp (extension, "pdf"))
389f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod      constructor = cairo_pdf_surface_create_for_stream;
390b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #endif
391b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #ifdef CAIRO_HAS_PS_SURFACE
392b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    else if (0 == strcasecmp (extension, "ps"))
393f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod      constructor = cairo_ps_surface_create_for_stream;
394b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod   #ifdef HAS_EPS
395b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    else if (0 == strcasecmp (extension, "eps"))
396f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod      constructor = _cairo_eps_surface_create_for_stream;
397b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod   #endif
398b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  #endif
399b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
400b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
401b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  unsigned int fr, fg, fb, fa, br, bg, bb, ba;
402b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  br = bg = bb = ba = 255;
403b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  sscanf (back + (*back=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba);
404b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  fr = fg = fb = 0; fa = 255;
405b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  sscanf (fore + (*fore=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa);
406b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
407b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_content_t content;
408b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (!annotate && ba == 255 && br == bg && bg == bb && fr == fg && fg == fb)
409b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    content = CAIRO_CONTENT_ALPHA;
410b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  else if (ba == 255)
411b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    content = CAIRO_CONTENT_COLOR;
412b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  else
413b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    content = CAIRO_CONTENT_COLOR_ALPHA;
414b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
415b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_surface_t *surface;
416f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod  FILE *f = get_file_handle ();
417b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  if (constructor)
418f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    surface = constructor (stdio_write_func, f, w, h);
419b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  else if (constructor2)
420f7e2ef74f856ee13d6fd6cf3f1e04bc162203bc2Behdad Esfahbod    surface = constructor2 (stdio_write_func, f, w, h, content);
421b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  else
422b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    fail (FALSE, "Unknown output format `%s'", extension);
423b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
424b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_t *cr = cairo_create (surface);
425b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  content = cairo_surface_get_content (surface);
426b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
427b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  switch (content) {
428b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    case CAIRO_CONTENT_ALPHA:
429b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
430b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 1., 1., br / 255.);
431b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_paint (cr);
432da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 1., 1.,
433da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod			     (fr / 255.) * (fa / 255.) + (br / 255) * (1 - (fa / 255.)));
434b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      break;
435b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    default:
436b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    case CAIRO_CONTENT_COLOR:
437b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    case CAIRO_CONTENT_COLOR_ALPHA:
438b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
439b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.);
440b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_paint (cr);
441b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
442b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.);
443b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      break;
444b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
445b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
446b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_surface_destroy (surface);
447b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  return cr;
448b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
449b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
450b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodvoid
451b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbodview_cairo_t::draw (cairo_t *cr)
452b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod{
453b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_save (cr);
454b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
455b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_extents_t font_extents;
456b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_font_extents (cr, &font_extents);
457b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_translate (cr, margin.l, margin.t);
458b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  for (unsigned int i = 0; i < lines->len; i++)
459b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  {
460b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    line_t &l = g_array_index (lines, line_t, i);
461b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
462b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    if (i)
463b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_translate (cr, 0, line_space);
464b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
465b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    cairo_translate (cr, 0, font_extents.ascent);
466b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
467b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    if (annotate) {
468b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_save (cr);
469b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
470b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      /* Draw actual glyph origins */
471b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_source_rgba (cr, 1., 0., 0., .5);
472b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_line_width (cr, 5);
473b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
474b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      for (unsigned i = 0; i < l.num_glyphs; i++) {
475b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod	cairo_move_to (cr, l.glyphs[i].x, l.glyphs[i].y);
476b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod	cairo_rel_line_to (cr, 0, 0);
477b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      }
478b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_stroke (cr);
479b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
480b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_restore (cr);
481b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    }
482b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
483b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    if (cairo_surface_get_type (cairo_get_target (cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
484da4a2a1426ee3aa9d9678ec12c9ba4dfcba0bcf8Behdad Esfahbod      /* cairo_show_glyphs() doesn't support subpixel positioning */
485b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_glyph_path (cr, l.glyphs, l.num_glyphs);
486b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_fill (cr);
487f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    } else if (l.num_clusters)
488b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod      cairo_show_text_glyphs (cr,
489b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod			      l.utf8, l.utf8_len,
490b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod			      l.glyphs, l.num_glyphs,
491b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod			      l.clusters, l.num_clusters,
492b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod			      l.cluster_flags);
493f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod    else
494f6496663c2f6849a944e41afcf9511f378477532Behdad Esfahbod      cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
495b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
496b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod    cairo_translate (cr, 0, font_extents.height - font_extents.ascent);
497b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  }
498b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod
499b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod  cairo_restore (cr);
500b9b10ad78b1f977494a3a42b58f8040fe16505a3Behdad Esfahbod}
501