~oem-solutions-group/unity-2d/clutter-1.0

« back to all changes in this revision

Viewing changes to clutter/pango/cogl-pango-glyph-cache.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Clutter.
3
 
 *
4
 
 * An OpenGL based 'interactive canvas' library.
5
 
 *
6
 
 * Authored By Matthew Allum  <mallum@openedhand.com>
7
 
 *
8
 
 * Copyright (C) 2008 OpenedHand
9
 
 *
10
 
 * This library is free software; you can redistribute it and/or
11
 
 * modify it under the terms of the GNU Lesser General Public
12
 
 * License as published by the Free Software Foundation; either
13
 
 * version 2 of the License, or (at your option) any later version.
14
 
 *
15
 
 * This library is distributed in the hope that it will be useful,
16
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 
 * Lesser General Public License for more details.
19
 
 *
20
 
 * You should have received a copy of the GNU Lesser General Public
21
 
 * License along with this library. If not, see <http://www.gnu.org/licenses>.
22
 
 */
23
 
 
24
 
#ifdef HAVE_CONFIG_H
25
 
#include "config.h"
26
 
#endif
27
 
 
28
 
#include <glib.h>
29
 
 
30
 
#include "cogl-pango-glyph-cache.h"
31
 
#include "cogl-pango-private.h"
32
 
 
33
 
/* Minimum width/height for each texture */
34
 
#define MIN_TEXTURE_SIZE  256
35
 
/* All glyph with heights within this margin from each other can be
36
 
   put in the same band */
37
 
#define BAND_HEIGHT_ROUND 4
38
 
 
39
 
typedef struct _CoglPangoGlyphCacheKey     CoglPangoGlyphCacheKey;
40
 
typedef struct _CoglPangoGlyphCacheTexture CoglPangoGlyphCacheTexture;
41
 
typedef struct _CoglPangoGlyphCacheBand    CoglPangoGlyphCacheBand;
42
 
 
43
 
struct _CoglPangoGlyphCache
44
 
{
45
 
  /* Hash table to quickly check whether a particular glyph in a
46
 
     particular font is already cached */
47
 
  GHashTable                    *hash_table;
48
 
 
49
 
  /* List of textures */
50
 
  CoglPangoGlyphCacheTexture *textures;
51
 
 
52
 
  /* List of horizontal bands of glyphs */
53
 
  CoglPangoGlyphCacheBand    *bands;
54
 
};
55
 
 
56
 
struct _CoglPangoGlyphCacheKey
57
 
{
58
 
  PangoFont  *font;
59
 
  PangoGlyph  glyph;
60
 
};
61
 
 
62
 
/* Represents one texture that will be used to store glyphs. The
63
 
   texture is divided into horizontal bands which all contain glyphs
64
 
   of approximatly the same height */
65
 
struct _CoglPangoGlyphCacheTexture
66
 
{
67
 
  /* The width and height of the texture which should always be a
68
 
     power of two. This can vary so that glyphs larger than
69
 
     MIN_TEXTURE_SIZE can use a bigger texture */
70
 
  int        texture_size;
71
 
 
72
 
  /* The remaining vertical space not taken up by any bands */
73
 
  int        space_remaining;
74
 
 
75
 
  /* The actual texture */
76
 
  CoglHandle texture;
77
 
 
78
 
  CoglPangoGlyphCacheTexture *next;
79
 
};
80
 
 
81
 
/* Represents one horizontal band of a texture. Each band contains
82
 
   glyphs of a similar height */
83
 
struct _CoglPangoGlyphCacheBand
84
 
{
85
 
  /* The y position of the top of the band */
86
 
  int        top;
87
 
 
88
 
  /* The height of the band */
89
 
  int        height;
90
 
 
91
 
  /* The remaining horizontal space not taken up by any glyphs */
92
 
  int        space_remaining;
93
 
 
94
 
  /* The size of the texture. Needed to calculate texture
95
 
     coordinates */
96
 
  int        texture_size;
97
 
 
98
 
  /* The texture containing this band */
99
 
  CoglHandle texture;
100
 
 
101
 
  CoglPangoGlyphCacheBand *next;
102
 
};
103
 
 
104
 
static void
105
 
cogl_pango_glyph_cache_value_free (CoglPangoGlyphCacheValue *value)
106
 
{
107
 
  cogl_handle_unref (value->texture);
108
 
  g_slice_free (CoglPangoGlyphCacheValue, value);
109
 
}
110
 
 
111
 
static void
112
 
cogl_pango_glyph_cache_key_free (CoglPangoGlyphCacheKey *key)
113
 
{
114
 
  g_object_unref (key->font);
115
 
  g_slice_free (CoglPangoGlyphCacheKey, key);
116
 
}
117
 
 
118
 
static guint
119
 
cogl_pango_glyph_cache_hash_func (gconstpointer key)
120
 
{
121
 
  const CoglPangoGlyphCacheKey *cache_key
122
 
    = (const CoglPangoGlyphCacheKey *) key;
123
 
 
124
 
  /* Generate a number affected by both the font and the glyph
125
 
     number. We can safely directly compare the pointers because the
126
 
     key holds a reference to the font so it is not possible that a
127
 
     different font will have the same memory address */
128
 
  return GPOINTER_TO_UINT (cache_key->font) ^ cache_key->glyph;
129
 
}
130
 
 
131
 
static gboolean
132
 
cogl_pango_glyph_cache_equal_func (gconstpointer a,
133
 
                                      gconstpointer b)
134
 
{
135
 
  const CoglPangoGlyphCacheKey *key_a
136
 
    = (const CoglPangoGlyphCacheKey *) a;
137
 
  const CoglPangoGlyphCacheKey *key_b
138
 
    = (const CoglPangoGlyphCacheKey *) b;
139
 
 
140
 
  /* We can safely directly compare the pointers for the fonts because
141
 
     the key holds a reference to the font so it is not possible that
142
 
     a different font will have the same memory address */
143
 
  return key_a->font == key_b->font
144
 
    && key_a->glyph == key_b->glyph;
145
 
}
146
 
 
147
 
static void
148
 
cogl_pango_glyph_cache_free_textures (CoglPangoGlyphCacheTexture *node)
149
 
{
150
 
  CoglPangoGlyphCacheTexture *next;
151
 
 
152
 
  while (node)
153
 
    {
154
 
      next = node->next;
155
 
      cogl_handle_unref (node->texture);
156
 
      g_slice_free (CoglPangoGlyphCacheTexture, node);
157
 
      node = next;
158
 
    }
159
 
}
160
 
 
161
 
static void
162
 
cogl_pango_glyph_cache_free_bands (CoglPangoGlyphCacheBand *node)
163
 
{
164
 
  CoglPangoGlyphCacheBand *next;
165
 
 
166
 
  while (node)
167
 
    {
168
 
      next = node->next;
169
 
      cogl_handle_unref (node->texture);
170
 
      g_slice_free (CoglPangoGlyphCacheBand, node);
171
 
      node = next;
172
 
    }
173
 
}
174
 
 
175
 
CoglPangoGlyphCache *
176
 
cogl_pango_glyph_cache_new (void)
177
 
{
178
 
  CoglPangoGlyphCache *cache;
179
 
 
180
 
  cache = g_malloc (sizeof (CoglPangoGlyphCache));
181
 
 
182
 
  cache->hash_table = g_hash_table_new_full
183
 
    (cogl_pango_glyph_cache_hash_func,
184
 
     cogl_pango_glyph_cache_equal_func,
185
 
     (GDestroyNotify) cogl_pango_glyph_cache_key_free,
186
 
     (GDestroyNotify) cogl_pango_glyph_cache_value_free);
187
 
 
188
 
  cache->textures = NULL;
189
 
  cache->bands = NULL;
190
 
 
191
 
  return cache;
192
 
}
193
 
 
194
 
void
195
 
cogl_pango_glyph_cache_clear (CoglPangoGlyphCache *cache)
196
 
{
197
 
  cogl_pango_glyph_cache_free_textures (cache->textures);
198
 
  cache->textures = NULL;
199
 
  cogl_pango_glyph_cache_free_bands (cache->bands);
200
 
  cache->bands = NULL;
201
 
 
202
 
  g_hash_table_remove_all (cache->hash_table);
203
 
}
204
 
 
205
 
void
206
 
cogl_pango_glyph_cache_free (CoglPangoGlyphCache *cache)
207
 
{
208
 
  cogl_pango_glyph_cache_clear (cache);
209
 
 
210
 
  g_hash_table_unref (cache->hash_table);
211
 
 
212
 
  g_free (cache);
213
 
}
214
 
 
215
 
CoglPangoGlyphCacheValue *
216
 
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
217
 
                                  PangoFont              *font,
218
 
                                  PangoGlyph              glyph)
219
 
{
220
 
  CoglPangoGlyphCacheKey key;
221
 
 
222
 
  key.font = font;
223
 
  key.glyph = glyph;
224
 
 
225
 
  return (CoglPangoGlyphCacheValue *)
226
 
    g_hash_table_lookup (cache->hash_table, &key);
227
 
}
228
 
 
229
 
CoglPangoGlyphCacheValue *
230
 
cogl_pango_glyph_cache_set (CoglPangoGlyphCache *cache,
231
 
                            PangoFont           *font,
232
 
                            PangoGlyph           glyph,
233
 
                            gconstpointer        pixels,
234
 
                            int                  width,
235
 
                            int                  height,
236
 
                            int                  stride,
237
 
                            int                  draw_x,
238
 
                            int                  draw_y)
239
 
{
240
 
  int                       band_height;
241
 
  CoglPangoGlyphCacheBand  *band;
242
 
  CoglPangoGlyphCacheKey   *key;
243
 
  CoglPangoGlyphCacheValue *value;
244
 
 
245
 
  /* Reserve an extra pixel gap around the glyph so that it can pull
246
 
     in blank pixels when linear filtering is enabled */
247
 
  width++;
248
 
  height++;
249
 
 
250
 
  /* Round the height up to the nearest multiple of
251
 
     BAND_HEIGHT_ROUND */
252
 
  band_height = (height + BAND_HEIGHT_ROUND - 1) & ~(BAND_HEIGHT_ROUND - 1);
253
 
 
254
 
  /* Look for a band with the same height and enough width available */
255
 
  for (band = cache->bands;
256
 
       band && (band->height != band_height || band->space_remaining < width);
257
 
       band = band->next);
258
 
  if (band == NULL)
259
 
    {
260
 
      CoglPangoGlyphCacheTexture *texture;
261
 
 
262
 
      /* Look for a texture with enough vertical space left for a band
263
 
         with this height */
264
 
      for (texture = cache->textures;
265
 
           texture && (texture->space_remaining < band_height
266
 
                       || texture->texture_size < width);
267
 
           texture = texture->next);
268
 
      if (texture == NULL)
269
 
        {
270
 
          guchar *clear_data;
271
 
 
272
 
          /* Allocate a new texture that is the nearest power of two
273
 
             greater than the band height or the minimum size,
274
 
             whichever is lower */
275
 
          texture = g_slice_new (CoglPangoGlyphCacheTexture);
276
 
 
277
 
          texture->texture_size = MIN_TEXTURE_SIZE;
278
 
          while (texture->texture_size < band_height ||
279
 
                 texture->texture_size < width)
280
 
            {
281
 
              texture->texture_size *= 2;
282
 
            }
283
 
 
284
 
          /* Allocate an empty buffer to clear the texture */
285
 
          clear_data =
286
 
            g_malloc0 (texture->texture_size * texture->texture_size);
287
 
 
288
 
          texture->texture =
289
 
            cogl_texture_new_from_data (texture->texture_size,
290
 
                                        texture->texture_size,
291
 
                                        COGL_TEXTURE_NONE,
292
 
                                        COGL_PIXEL_FORMAT_A_8,
293
 
                                        COGL_PIXEL_FORMAT_A_8,
294
 
                                        texture->texture_size,
295
 
                                        clear_data);
296
 
 
297
 
          g_free (clear_data);
298
 
 
299
 
          texture->space_remaining = texture->texture_size;
300
 
          texture->next = cache->textures;
301
 
          cache->textures = texture;
302
 
        }
303
 
 
304
 
      band = g_slice_new (CoglPangoGlyphCacheBand);
305
 
      band->top = texture->texture_size - texture->space_remaining;
306
 
      band->height = band_height;
307
 
      band->space_remaining = texture->texture_size;
308
 
      band->texture = cogl_handle_ref (texture->texture);
309
 
      band->texture_size = texture->texture_size;
310
 
      band->next = cache->bands;
311
 
      cache->bands = band;
312
 
      texture->space_remaining -= band_height;
313
 
    }
314
 
 
315
 
  band->space_remaining -= width;
316
 
 
317
 
  width--;
318
 
  height--;
319
 
 
320
 
  cogl_texture_set_region (band->texture,
321
 
                           0, 0,
322
 
                           band->space_remaining,
323
 
                           band->top,
324
 
                           width, height,
325
 
                           width, height,
326
 
                           COGL_PIXEL_FORMAT_A_8,
327
 
                           stride,
328
 
                           pixels);
329
 
 
330
 
  key = g_slice_new (CoglPangoGlyphCacheKey);
331
 
  key->font = g_object_ref (font);
332
 
  key->glyph = glyph;
333
 
 
334
 
  value = g_slice_new (CoglPangoGlyphCacheValue);
335
 
  value->texture = cogl_handle_ref (band->texture);
336
 
  value->tx1 = (float)(band->space_remaining)
337
 
             / band->texture_size;
338
 
  value->tx2 = (float)(band->space_remaining + width)
339
 
             / band->texture_size;
340
 
  value->ty1 = (float)(band->top)
341
 
             / band->texture_size;
342
 
  value->ty2 = (float)(band->top + height)
343
 
             / band->texture_size;
344
 
  value->draw_x = draw_x;
345
 
  value->draw_y = draw_y;
346
 
  value->draw_width = width;
347
 
  value->draw_height = height;
348
 
 
349
 
  g_hash_table_insert (cache->hash_table, key, value);
350
 
 
351
 
  return value;
352
 
}