view-cairo.cc revision 422558142aabb996d8ad1848df7ea4d5a8ade98a
1/*
2 * Copyright © 2011  Google, Inc.
3 *
4 *  This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
27#include "view-cairo.hh"
28
29void
30view_cairo_t::init (const font_options_t *font_opts)
31{
32  lines = g_array_new (FALSE, FALSE, sizeof (helper_cairo_line_t));
33  scale = double (font_size) / hb_face_get_upem (hb_font_get_face (font_opts->get_font ()));
34}
35
36void
37view_cairo_t::consume_line (hb_buffer_t  *buffer,
38			    const char   *text,
39			    unsigned int  text_len)
40{
41  helper_cairo_line_t l;
42  helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale);
43  g_array_append_val (lines, l);
44}
45
46void
47view_cairo_t::finish (const font_options_t *font_opts)
48{
49  render (font_opts);
50
51  for (unsigned int i = 0; i < lines->len; i++) {
52    helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i);
53    line.finish ();
54  }
55  g_array_unref (lines);
56}
57
58void
59view_cairo_t::get_surface_size (cairo_scaled_font_t *scaled_font,
60				double *w, double *h)
61{
62  cairo_font_extents_t font_extents;
63
64  cairo_scaled_font_extents (scaled_font, &font_extents);
65
66  *h = font_extents.ascent
67     + font_extents.descent
68     + ((int) lines->len - 1) * (font_extents.height + line_space);
69  *w = 0;
70  for (unsigned int i = 0; i < lines->len; i++) {
71    helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i);
72    double line_width = line.get_width ();
73    *w = MAX (*w, line_width);
74  }
75
76  *w += margin.l + margin.r;
77  *h += margin.t + margin.b;
78}
79
80void
81view_cairo_t::render (const font_options_t *font_opts)
82{
83  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts, font_size);
84  double w, h;
85  get_surface_size (scaled_font, &w, &h);
86  cairo_t *cr = helper_cairo_create_context (w, h, this, this);
87  cairo_set_scaled_font (cr, scaled_font);
88  cairo_scaled_font_destroy (scaled_font);
89
90  draw (cr);
91
92  helper_cairo_destroy_context (cr);
93}
94
95void
96view_cairo_t::draw (cairo_t *cr)
97{
98  cairo_save (cr);
99
100  cairo_font_extents_t font_extents;
101  cairo_font_extents (cr, &font_extents);
102  cairo_translate (cr, margin.l, margin.t);
103  for (unsigned int i = 0; i < lines->len; i++)
104  {
105    helper_cairo_line_t &l = g_array_index (lines, helper_cairo_line_t, i);
106
107    if (i)
108      cairo_translate (cr, 0, line_space);
109
110    cairo_translate (cr, 0, font_extents.ascent);
111
112    if (annotate) {
113      cairo_save (cr);
114
115      /* Draw actual glyph origins */
116      cairo_set_source_rgba (cr, 1., 0., 0., .5);
117      cairo_set_line_width (cr, 5);
118      cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
119      for (unsigned i = 0; i < l.num_glyphs; i++) {
120	cairo_move_to (cr, l.glyphs[i].x, l.glyphs[i].y);
121	cairo_rel_line_to (cr, 0, 0);
122      }
123      cairo_stroke (cr);
124
125      cairo_restore (cr);
126    }
127
128    if (cairo_surface_get_type (cairo_get_target (cr)) == CAIRO_SURFACE_TYPE_IMAGE) {
129      /* cairo_show_glyphs() doesn't support subpixel positioning */
130      cairo_glyph_path (cr, l.glyphs, l.num_glyphs);
131      cairo_fill (cr);
132    } else if (l.num_clusters)
133      cairo_show_text_glyphs (cr,
134			      l.utf8, l.utf8_len,
135			      l.glyphs, l.num_glyphs,
136			      l.clusters, l.num_clusters,
137			      l.cluster_flags);
138    else
139      cairo_show_glyphs (cr, l.glyphs, l.num_glyphs);
140
141    cairo_translate (cr, 0, font_extents.height - font_extents.ascent);
142  }
143
144  cairo_restore (cr);
145}
146