~ubuntu-branches/ubuntu/karmic/pango1.0/karmic-security

« back to all changes in this revision

Viewing changes to pango/glyphstring.c

Tags: upstream-1.15.4
ImportĀ upstreamĀ versionĀ 1.15.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Pango
 
2
 * glyphstring.c:
 
3
 *
 
4
 * Copyright (C) 1999 Red Hat Software
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Library General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Library General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Library General Public
 
17
 * License along with this library; if not, write to the
 
18
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <glib.h>
 
24
#include "pango-glyph.h"
 
25
#include "pango-font.h"
 
26
#include "pango-impl-utils.h"
 
27
 
 
28
/**
 
29
 * pango_glyph_string_new:
 
30
 *
 
31
 * Create a new #PangoGlyphString.
 
32
 *
 
33
 * Return value: the newly allocated #PangoGlyphString, which
 
34
 *               should be freed with pango_glyph_string_free().
 
35
 */
 
36
PangoGlyphString *
 
37
pango_glyph_string_new (void)
 
38
{
 
39
  PangoGlyphString *string = g_slice_new (PangoGlyphString);
 
40
 
 
41
  string->num_glyphs = 0;
 
42
  string->space = 0;
 
43
  string->glyphs = NULL;
 
44
  string->log_clusters = NULL;
 
45
 
 
46
  return string;
 
47
}
 
48
 
 
49
/**
 
50
 * pango_glyph_string_set_size:
 
51
 * @string:    a #PangoGlyphString.
 
52
 * @new_len:   the new length of the string.
 
53
 *
 
54
 * Resize a glyph string to the given length.
 
55
 */
 
56
void
 
57
pango_glyph_string_set_size (PangoGlyphString *string, gint new_len)
 
58
{
 
59
  g_return_if_fail (new_len >= 0);
 
60
 
 
61
  while (new_len > string->space)
 
62
    {
 
63
      if (string->space == 0)
 
64
        string->space = 1;
 
65
      else
 
66
        string->space *= 2;
 
67
 
 
68
      if (string->space < 0)
 
69
        {
 
70
          g_warning ("glyph string length overflows maximum integer size, truncated");
 
71
          new_len = string->space = G_MAXINT - 8;
 
72
        }
 
73
    }
 
74
 
 
75
  string->glyphs = g_realloc (string->glyphs, string->space * sizeof (PangoGlyphInfo));
 
76
  string->log_clusters = g_realloc (string->log_clusters, string->space * sizeof (gint));
 
77
  string->num_glyphs = new_len;
 
78
}
 
79
 
 
80
GType
 
81
pango_glyph_string_get_type (void)
 
82
{
 
83
  static GType our_type = 0;
 
84
 
 
85
  if (our_type == 0)
 
86
    our_type = g_boxed_type_register_static (I_("PangoGlyphString"),
 
87
                                             (GBoxedCopyFunc)pango_glyph_string_copy,
 
88
                                             (GBoxedFreeFunc)pango_glyph_string_free);
 
89
 
 
90
  return our_type;
 
91
}
 
92
 
 
93
/**
 
94
 * pango_glyph_string_copy:
 
95
 * @string: a #PangoGlyphString.
 
96
 *
 
97
 *  Copy a glyph string and associated storage.
 
98
 *
 
99
 * Return value: the newly allocated #PangoGlyphString, which
 
100
 *               should be freed with pango_glyph_string_free().
 
101
 */
 
102
PangoGlyphString *
 
103
pango_glyph_string_copy (PangoGlyphString *string)
 
104
{
 
105
  PangoGlyphString *new_string = g_slice_new (PangoGlyphString);
 
106
 
 
107
  *new_string = *string;
 
108
 
 
109
  new_string->glyphs = g_memdup (string->glyphs,
 
110
                                 string->space * sizeof (PangoGlyphInfo));
 
111
  new_string->log_clusters = g_memdup (string->log_clusters,
 
112
                                       string->space * sizeof (gint));
 
113
 
 
114
  return new_string;
 
115
}
 
116
 
 
117
/**
 
118
 * pango_glyph_string_free:
 
119
 * @string:    a #PangoGlyphString.
 
120
 *
 
121
 * Free a glyph string and associated storage.
 
122
 */
 
123
void
 
124
pango_glyph_string_free (PangoGlyphString *string)
 
125
{
 
126
  g_free (string->glyphs);
 
127
  g_free (string->log_clusters);
 
128
  g_slice_free (PangoGlyphString, string);
 
129
}
 
130
 
 
131
/**
 
132
 * pango_glyph_string_extents_range:
 
133
 * @glyphs:   a #PangoGlyphString
 
134
 * @start:    start index
 
135
 * @end:      end index (the range is the set of bytes with
 
136
              indices such that start <= index < end)
 
137
 * @font:     a #PangoFont
 
138
 * @ink_rect: rectangle used to store the extents of the glyph string range as drawn
 
139
 *            or %NULL to indicate that the result is not needed.
 
140
 * @logical_rect: rectangle used to store the logical extents of the glyph string range
 
141
 *            or %NULL to indicate that the result is not needed.
 
142
 *
 
143
 * Computes the extents of a sub-portion of a glyph string. The extents are
 
144
 * relative to the start of the glyph string range (the origin of their
 
145
 * coordinate system is at the start of the range, not at the start of the entire
 
146
 * glyph string).
 
147
 **/
 
148
void
 
149
pango_glyph_string_extents_range (PangoGlyphString *glyphs,
 
150
                                  int               start,
 
151
                                  int               end,
 
152
                                  PangoFont        *font,
 
153
                                  PangoRectangle   *ink_rect,
 
154
                                  PangoRectangle   *logical_rect)
 
155
{
 
156
  int x_pos = 0;
 
157
  int i;
 
158
 
 
159
  /* Note that the handling of empty rectangles for ink
 
160
   * and logical rectangles is different. A zero-height ink
 
161
   * rectangle makes no contribution to the overall ink rect,
 
162
   * while a zero-height logical rect still reserves horizontal
 
163
   * width. Also, we may return zero-width, positive height
 
164
   * logical rectangles, while we'll never do that for the
 
165
   * ink rect.
 
166
   */
 
167
  g_return_if_fail (start <= end);
 
168
 
 
169
  if (G_UNLIKELY (!ink_rect && !logical_rect))
 
170
    return;
 
171
 
 
172
  if (ink_rect)
 
173
    {
 
174
      ink_rect->x = 0;
 
175
      ink_rect->y = 0;
 
176
      ink_rect->width = 0;
 
177
      ink_rect->height = 0;
 
178
    }
 
179
 
 
180
  if (logical_rect)
 
181
    {
 
182
      logical_rect->x = 0;
 
183
      logical_rect->y = 0;
 
184
      logical_rect->width = 0;
 
185
      logical_rect->height = 0;
 
186
    }
 
187
 
 
188
  for (i = start; i < end; i++)
 
189
    {
 
190
      PangoRectangle glyph_ink;
 
191
      PangoRectangle glyph_logical;
 
192
 
 
193
      PangoGlyphGeometry *geometry = &glyphs->glyphs[i].geometry;
 
194
 
 
195
      pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
 
196
                                    ink_rect ? &glyph_ink : NULL,
 
197
                                    logical_rect ? &glyph_logical : NULL);
 
198
 
 
199
      if (ink_rect && glyph_ink.width != 0 && glyph_ink.height != 0)
 
200
        {
 
201
          if (ink_rect->width == 0 || ink_rect->height == 0)
 
202
            {
 
203
              ink_rect->x = x_pos + glyph_ink.x + geometry->x_offset;
 
204
              ink_rect->width = glyph_ink.width;
 
205
              ink_rect->y = glyph_ink.y + geometry->y_offset;
 
206
              ink_rect->height = glyph_ink.height;
 
207
            }
 
208
          else
 
209
            {
 
210
              int new_x, new_y;
 
211
 
 
212
              new_x = MIN (ink_rect->x, x_pos + glyph_ink.x + geometry->x_offset);
 
213
              ink_rect->width = MAX (ink_rect->x + ink_rect->width,
 
214
                                     x_pos + glyph_ink.x + glyph_ink.width + geometry->x_offset) - new_x;
 
215
              ink_rect->x = new_x;
 
216
 
 
217
              new_y = MIN (ink_rect->y, glyph_ink.y + geometry->y_offset);
 
218
              ink_rect->height = MAX (ink_rect->y + ink_rect->height,
 
219
                                      glyph_ink.y + glyph_ink.height + geometry->y_offset) - new_y;
 
220
              ink_rect->y = new_y;
 
221
            }
 
222
        }
 
223
 
 
224
      if (logical_rect)
 
225
        {
 
226
          logical_rect->width += geometry->width;
 
227
 
 
228
          if (i == start)
 
229
            {
 
230
              logical_rect->y = glyph_logical.y;
 
231
              logical_rect->height = glyph_logical.height;
 
232
            }
 
233
          else
 
234
            {
 
235
              int new_y = MIN (logical_rect->y, glyph_logical.y);
 
236
              logical_rect->height = MAX (logical_rect->y + logical_rect->height,
 
237
                                          glyph_logical.y + glyph_logical.height) - new_y;
 
238
              logical_rect->y = new_y;
 
239
            }
 
240
        }
 
241
 
 
242
      x_pos += geometry->width;
 
243
    }
 
244
}
 
245
 
 
246
/**
 
247
 * pango_glyph_string_extents:
 
248
 * @glyphs:   a #PangoGlyphString
 
249
 * @font:     a #PangoFont
 
250
 * @ink_rect: rectangle used to store the extents of the glyph string as drawn
 
251
 *            or %NULL to indicate that the result is not needed.
 
252
 * @logical_rect: rectangle used to store the logical extents of the glyph string
 
253
 *            or %NULL to indicate that the result is not needed.
 
254
 *
 
255
 * Compute the logical and ink extents of a glyph string. See the documentation
 
256
 * for pango_font_get_glyph_extents() for details about the interpretation
 
257
 * of the rectangles.
 
258
 */
 
259
void
 
260
pango_glyph_string_extents (PangoGlyphString *glyphs,
 
261
                            PangoFont        *font,
 
262
                            PangoRectangle   *ink_rect,
 
263
                            PangoRectangle   *logical_rect)
 
264
{
 
265
  pango_glyph_string_extents_range (glyphs, 0, glyphs->num_glyphs,
 
266
                                    font, ink_rect, logical_rect);
 
267
}
 
268
 
 
269
/**
 
270
 * pango_glyph_string_get_width:
 
271
 * @glyphs:   a #PangoGlyphString
 
272
 *
 
273
 * Computes the logical width of the glyph string as can also be computed
 
274
 * using pango_glyph_string_extents().  However, since this only computes the
 
275
 * width, it's much faster.  This is in fact only a convenience function that
 
276
 * computes the sum of geometry.width for each glyph in the @glyphs.
 
277
 *
 
278
 * Return value: the logical width of the glyph string.
 
279
 *
 
280
 * Since: 1.14
 
281
 */
 
282
int
 
283
pango_glyph_string_get_width (PangoGlyphString *glyphs)
 
284
{
 
285
  int i;
 
286
  int width = 0;
 
287
 
 
288
  for (i = 0; i < glyphs->num_glyphs; i++)
 
289
    width += glyphs->glyphs[i].geometry.width;
 
290
 
 
291
  return width;
 
292
}
 
293
 
 
294
/**
 
295
 * pango_glyph_string_get_logical_widths:
 
296
 * @glyphs: a #PangoGlyphString
 
297
 * @text: the text corresponding to the glyphs
 
298
 * @length: the length of @text, in bytes
 
299
 * @embedding_level: the embedding level of the string
 
300
 * @logical_widths: an array whose length is g_utf8_strlen (text, length)
 
301
 *                  to be filled in with the resulting character widths.
 
302
 *
 
303
 * Given a #PangoGlyphString resulting from pango_shape() and the corresponding
 
304
 * text, determine the screen width corresponding to each character. When
 
305
 * multiple characters compose a single cluster, the width of the entire
 
306
 * cluster is divided equally among the characters.
 
307
 **/
 
308
void
 
309
pango_glyph_string_get_logical_widths (PangoGlyphString *glyphs,
 
310
                                       const char       *text,
 
311
                                       int               length,
 
312
                                       int               embedding_level,
 
313
                                       int              *logical_widths)
 
314
{
 
315
  int i, j;
 
316
  int last_cluster = 0;
 
317
  int width = 0;
 
318
  int last_cluster_width = 0;
 
319
  const char *p = text;         /* Points to start of current cluster */
 
320
 
 
321
  for (i=0; i<=glyphs->num_glyphs; i++)
 
322
    {
 
323
      int glyph_index = (embedding_level % 2 == 0) ? i : glyphs->num_glyphs - i - 1;
 
324
 
 
325
      /* If this glyph belongs to a new cluster, or we're at the end, find
 
326
       * the start of the next cluster, and assign the widths for this cluster.
 
327
       */
 
328
      if (i == glyphs->num_glyphs || p != text + glyphs->log_clusters[glyph_index])
 
329
        {
 
330
          int next_cluster = last_cluster;
 
331
 
 
332
          if (i < glyphs->num_glyphs)
 
333
            {
 
334
              while (p < text + glyphs->log_clusters[glyph_index])
 
335
                {
 
336
                  next_cluster++;
 
337
                  p = g_utf8_next_char (p);
 
338
                }
 
339
            }
 
340
          else
 
341
            {
 
342
              while (p < text + length)
 
343
                {
 
344
                  next_cluster++;
 
345
                  p = g_utf8_next_char (p);
 
346
                }
 
347
            }
 
348
 
 
349
          for (j = last_cluster; j < next_cluster; j++)
 
350
            logical_widths[j] = (width - last_cluster_width) / (next_cluster - last_cluster);
 
351
 
 
352
          last_cluster = next_cluster;
 
353
          last_cluster_width = width;
 
354
        }
 
355
 
 
356
      if (i < glyphs->num_glyphs)
 
357
        width += glyphs->glyphs[glyph_index].geometry.width;
 
358
    }
 
359
}
 
360