gdkpango-fb.c 25.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
#include <glib.h>
#include "gdkprivate-fb.h"
#include "gdkpango.h"
#include <dirent.h>
#include <string.h>
#include <stdlib.h>

#include <pango/pango.h>
#include <pango/pango-modules.h>

#include <freetype/freetype.h>
12
#include <freetype/ftglyph.h>
13

14
#if !defined(FREETYPE_MAJOR) || FREETYPE_MAJOR != 2
15
#error "We need Freetype 2.0"
16
17
18
19
#endif

#define PANGO_RENDER_TYPE_FB "PangoRenderTypeFB"

20
21
22
23
24
25
26
#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6))
#define PANGO_PIXELS_26_6(d)				\
  (((d) >= 0) ?						\
   ((d) + PANGO_SCALE_26_6 / 2) / PANGO_SCALE_26_6 :	\
   ((d) - PANGO_SCALE_26_6 / 2) / PANGO_SCALE_26_6)
#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d))

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
typedef struct {
  PangoFontMap parent_instance;

  GPtrArray *all_descs;
  GHashTable *all_fonts;

  int n_fonts;

  double resolution;
} PangoFBFontMap;

typedef struct {
  PangoFontMapClass parent_class;
} PangoFBFontMapClass;

typedef struct {
  PangoFontDescription desc;
  FT_Face ftf;
} PangoFBFontListing;

FT_Library gdk_fb_ft_lib = NULL;

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#define MAX_ALIASES 3

typedef struct {
  PangoFontDescription alias;
  PangoFontDescription descriptions[MAX_ALIASES];
} PangoFBAlias;

static PangoFBAlias alias_table[] =
{
  /* sans: */
  {
    {"Sans", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
    {
      {"Arial", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
      {"URW Gothic L", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
    }
  },
  {
67
    {"Sans", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
68
    {
69
70
      {"Arial", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
      {"URW Gothic L", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
71
72
73
74
75
76
77
78
79
80
    }
  },
  {
    {"Sans", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    {
      {"Arial", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
      {"URW Gothic L", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    }
  },
  {
81
    {"Sans", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
82
    {
83
      {"Arial", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
84
85
86
87
88
89
90
91
92
93
94
95
96
      {"URW Gothic L", PANGO_STYLE_OBLIQUE, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    }
  },

  /* serif: */
  {
    {"Serif", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
    {
      {"Times New Roman", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
      {"URW Bookman L", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
    }
  },
  {
97
    {"Serif", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
98
    {
99
100
      {"Times New Roman", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
      {"URW Bookman L", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
101
102
103
104
105
106
107
108
109
110
    }
  },
  {
    {"Serif", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    {
      {"Times New Roman", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
      {"URW Bookman L", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    }
  },
  {
111
    {"Serif", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
112
    {
113
114
      {"Times New Roman", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
      {"URW Bookman L", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
115
116
117
118
119
120
121
122
123
124
125
126
    }
  },
  
  /* monospace: */
  {
    {"Monospace", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
    {
      {"Courier New", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
      {"Courier", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
    }
  },
  {
127
    {"Monospace", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
128
    {
129
130
      {"Courier New", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
      {"Courier", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_NORMAL, PANGO_STRETCH_NORMAL},
131
132
133
134
135
136
137
138
139
140
    }
  },
  {
    {"Monospace", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    {
      {"Courier New", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
      {"Courier", PANGO_STYLE_NORMAL, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
    }
  },
  {
141
    {"Monospace", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
142
    {
143
144
      {"Courier New", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
      {"Courier", PANGO_STYLE_ITALIC, PANGO_VARIANT_NORMAL, PANGO_WEIGHT_BOLD, PANGO_STRETCH_NORMAL},
145
146
147
148
149
    }
  },
};

#define ALIAS_TABLE_LEN (sizeof(alias_table)/sizeof(PangoFBAlias))
150

151
void
152
gdk_fb_font_init (void)
153
{
154
  FT_Init_FreeType (&gdk_fb_ft_lib);
155
156
157
}

void
158
gdk_fb_font_fini (void)
159
{
160
  FT_Done_FreeType (gdk_fb_ft_lib);
161
162
}

163
164
165
166
167
168
169
170
171
172
173
void              pango_fb_font_set_size          (PangoFont                    *font);
static void       pango_fb_font_map_init          (PangoFBFontMap               *fontmap);
static PangoFont *pango_fb_font_map_load_font     (PangoFontMap                 *fontmap,
						   const PangoFontDescription   *desc);
static void       pango_fb_font_map_list_fonts    (PangoFontMap                 *fontmap,
						   const gchar                  *family,
						   PangoFontDescription       ***descs,
						   int                          *n_descs);
static void       pango_fb_font_map_list_families (PangoFontMap                 *fontmap,
						   gchar                      ***families,
						   int                          *n_families);
174

175
176

static void
177
pango_fb_font_map_class_init (PangoFBFontMapClass *class)
178
179
180
181
182
183
184
{
  class->parent_class.load_font = pango_fb_font_map_load_font;
  class->parent_class.list_fonts = pango_fb_font_map_list_fonts;
  class->parent_class.list_families = pango_fb_font_map_list_families;
}

GType
185
pango_fb_font_map_get_type (void)
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
{
  static GType object_type = 0;

  if (!object_type)
    {
      static const GTypeInfo object_info =
      {
        sizeof (PangoFBFontMapClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) pango_fb_font_map_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (PangoFBFontMap),
        0,              /* n_preallocs */
        (GInstanceInitFunc) pango_fb_font_map_init,
      };
      
      object_type = g_type_register_static (PANGO_TYPE_FONT_MAP,
                                            "PangoFBFontMap",
206
207
                                            &object_info,
					    0);
208
209
210
211
212
    }
  
  return object_type;
}

213
214
215
216
217
218
219
220
221
222
223
224
225
static gboolean
pango_font_description_equal_nosize (const PangoFontDescription *d1,
				     const PangoFontDescription *d2)
{
  return
    (g_strcasecmp (d1->family_name, d2->family_name)==0) &&
    d1->style == d2->style &&
    d1->variant == d2->variant &&
    d1->weight == d2->weight &&
    d1->stretch == d2->stretch;
}


226
static PangoFont *
227
228
229
pango_fb_lookup_descr (PangoFontMap *fontmap,
		       const PangoFontDescription *desc,
		       const PangoFontDescription *save_as)
230
231
232
{
  PangoFBFontMap *fbfm = (PangoFBFontMap *)fontmap;
  PangoFBFont *retval;
Elliot Lee's avatar
Elliot Lee committed
233
  PangoFBFontListing *fl = NULL;
234
235
  int i;

236
  retval = g_hash_table_lookup (fbfm->all_fonts, desc);
237

238
  if (retval)
239
    {
240
      g_object_ref (G_OBJECT(retval));
241
      return (PangoFont *)retval;
242
243
    }

244
  for (i = 0; i < fbfm->all_descs->len; i++)
245
    {
246
      fl = g_ptr_array_index (fbfm->all_descs, i);
247

248
      if (pango_font_description_equal_nosize(desc, &fl->desc))
249
250
	break;
    }
251
  
252
  if (i >= fbfm->all_descs->len)
253
254
    return NULL;

255
  retval = (PangoFBFont *)g_object_new (PANGO_TYPE_FB_FONT, NULL);
256

257
258
  retval->desc = *save_as;
  retval->desc.family_name = g_strdup (save_as->family_name);
259
260
  retval->ftf = fl->ftf;

261
  g_hash_table_insert (fbfm->all_fonts, &retval->desc, retval);
262
263
  g_object_ref (G_OBJECT (retval)); /* XXX FIXME: We have to keep the font in the cache
				       forever because I'm too clueless to see
264
				       signals in gobject */
265
266

  return (PangoFont *)retval;
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  
}

static PangoFont *
pango_fb_font_map_load_font (PangoFontMap *fontmap,
			     const PangoFontDescription *desc)
{
  PangoFont *font;
  const PangoFontDescription *descs;
  const PangoFontDescription *alias;
  int i, j;

  font = pango_fb_lookup_descr (fontmap, desc, desc);

  if (font)
    return font;

  for (i=0;i<ALIAS_TABLE_LEN;i++)
    {
      alias = &alias_table[i].alias;
      
      if (pango_font_description_equal_nosize (desc, alias))
	{
	  descs = &alias_table[i].descriptions[0];
	  j = 0;
	  while ((j < MAX_ALIASES) &&
		 (descs[j].family_name != NULL))
	    {
	      font = pango_fb_lookup_descr (fontmap, &descs[j], desc);
	      if (font)
		return font;
	      j++;
	    }
	  return NULL;
	}
    }
  return NULL;
304
305
306
}

static void
307
308
309
310
list_fonts (PangoFBFontMap *fm,
	    const char *family,
	    GPtrArray *descs,
	    const char *dir)
311
312
313
314
{
  DIR *dirh;
  struct dirent *dent;

315
316
  dirh = opendir (dir);
  if (!dirh)
317
318
    return;

319
  while ((dent = readdir (dirh)))
320
321
322
323
324
325
326
327
    {
      PangoFBFontListing *pfd;
      char *ctmp;
      char buf[1024];
      FT_Face ftf;
      FT_Error ec;
      int i = 0, n = 1;

328
329
330
331
332
      ctmp = strrchr (dent->d_name, '.');
      if (!ctmp ||
	  (strcasecmp (ctmp, ".ttf") &&
	   strcasecmp (ctmp, ".pfa") &&
	   strcasecmp (ctmp, ".pfb")))
333
334
	continue;

335
      g_snprintf (buf, sizeof(buf), "%s/%s", dir, dent->d_name);
336

337
      while (i < n)
338
	{
339
340
	  ec = FT_New_Face (gdk_fb_ft_lib, buf, i, &ftf);
	  if (ec)
341
	    break; /* error opening */
342
343
344

	  n = ftf->num_faces;

345
	  if (!ftf->family_name || !ftf->style_name)
346
	    {
347
348
	      g_warning ("No family/style on %s", buf);
	      FT_Done_Face (ftf);
349
	      break;
350
351
	    }

352
	  pfd = g_new0 (PangoFBFontListing, 1);
353
	  /* Now add the item */
354
355
	  if (ftf->family_name[0] == '/')
	    pfd->desc.family_name = g_strdup (ftf->family_name+1);
356
	  else
357
	    pfd->desc.family_name = g_strdup (ftf->family_name);
358
359
360
361
362
363

	  pfd->desc.style = PANGO_STYLE_NORMAL;
	  pfd->desc.variant = PANGO_VARIANT_NORMAL;
	  pfd->desc.weight = PANGO_WEIGHT_NORMAL;
	  pfd->desc.stretch = PANGO_STRETCH_NORMAL;

364
	  if (ftf->style_name)
365
366
	    {
	      char lcstr[512];
367
368
	      strcpy (lcstr, ftf->style_name);
	      g_strdown (lcstr);
369

370
	      if (strstr (lcstr, "italic"))
371
		pfd->desc.style = PANGO_STYLE_ITALIC;
372
	      else if (strstr (lcstr, "oblique"))
373
374
		pfd->desc.style = PANGO_STYLE_OBLIQUE;

375
	      if (strstr (lcstr, "bold"))
376
377
		pfd->desc.weight = PANGO_WEIGHT_BOLD;

378
	      if (strstr (lcstr, "condensed"))
379
		pfd->desc.stretch = PANGO_STRETCH_CONDENSED;
380
	      else if (strstr (lcstr, "expanded"))
381
382
383
384
385
		pfd->desc.stretch = PANGO_STRETCH_EXPANDED;
	    }

	  pfd->ftf = ftf;

386
	  g_ptr_array_add (descs, pfd);
387
388
389
390

	  i++;
	}
    }
391

392
  closedir (dirh);
393
394
395
}

static guint
396
pango_font_description_hash (gconstpointer a)
397
398
399
{
  const PangoFontDescription *fa = a;

400
  return g_str_hash (fa->family_name) ^ (fa->style + fa->weight + fa->stretch + fa->variant + fa->size);
401
402
403
}

static void
404
pango_fb_font_map_init (PangoFBFontMap *fontmap)
405
406
407
408
409
410
411
412
413
414
{
  static const char *font_dirs[] = {
    "/usr/share/fonts/default/TrueType",
    "/usr/share/fonts/default/Type1",
    "/usr/lib/X11/fonts/TrueType",
    "/usr/lib/X11/fonts/Type1",
    NULL
  };
  int i;

415
416
417
418
  fontmap->all_fonts = g_hash_table_new (pango_font_description_hash, (GEqualFunc)pango_font_description_equal);
  fontmap->all_descs = g_ptr_array_new ();
  for (i = 0; font_dirs[i]; i++)
    list_fonts (fontmap, NULL, fontmap->all_descs, font_dirs[i]);
419
420
421
}

static void
422
423
424
425
pango_fb_font_map_list_fonts (PangoFontMap *fontmap,
			      const gchar *family,
			      PangoFontDescription ***descs,
			      int *n_descs)
426
427
428
429
{
  PangoFBFontMap *fbfm = (PangoFBFontMap *)fontmap;
  int i, n;

430
431
  *descs = g_new (PangoFontDescription *, fbfm->all_descs->len + ALIAS_TABLE_LEN);
  *n_descs = fbfm->all_descs->len + ALIAS_TABLE_LEN;
432

433
  for (i = n = 0; i < fbfm->all_descs->len; i++)
434
    {
435
      PangoFontDescription *pfd = g_ptr_array_index (fbfm->all_descs, i);
436

437
438
439
440
441
442
443
444
445
      if (strcasecmp (family, pfd->family_name))
	continue;

      (*descs)[n++] = pango_font_description_copy (pfd);
    }
  for (i = 0; i < ALIAS_TABLE_LEN; i++)
    {
      PangoFontDescription *pfd = &alias_table[i].alias;

446
      if (strcasecmp (family, pfd->family_name))
447
448
	continue;

449
      (*descs)[n++] = pango_font_description_copy (pfd);
450
451
    }
  *n_descs = n;
452
  *descs = g_realloc (*descs, n * sizeof(PangoFontDescription *));
453
454
455
456
457
458
459
460
}

struct famlist {
  gchar **families;
  int last_added;
};

static void
461
add_entry (gpointer key, gpointer value, gpointer data)
462
463
{
  struct famlist *fl = data;
464
  fl->families[fl->last_added++] = g_strdup (key);
465
466
467
}

static void
468
469
470
pango_fb_font_map_list_families (PangoFontMap *fontmap,
				 gchar ***families,
				 int *n_families)
471
472
{
  PangoFBFontMap *fbfm = (PangoFBFontMap *)fontmap;
473
  GHashTable *thash = g_hash_table_new (g_str_hash, g_str_equal);
474
  struct famlist stickittome;
475
476
  gchar *family_name;
  int i;
477

478
479
  /* Use a temporary hashtable to uniqueify the family names. */
  
480
481
  for(i = 0; i < fbfm->all_descs->len; i++)
    {
482
      PangoFBFontListing *fl = g_ptr_array_index (fbfm->all_descs, i);
483
484
      family_name = fl->desc.family_name;
      g_hash_table_insert (thash, family_name, family_name);
485
    }
486
487
488
489
490
491
492
  
  for(i = 0; i < ALIAS_TABLE_LEN; i++)
    {
      family_name = alias_table[i].alias.family_name;
      g_hash_table_insert (thash, family_name, family_name);
    }
  
493
494
  *n_families = g_hash_table_size (thash);
  *families = g_new (gchar *, *n_families);
495
496
497

  stickittome.families = *families;
  stickittome.last_added = 0;
498
499
  g_hash_table_foreach (thash, add_entry, &stickittome);
  g_hash_table_destroy (thash);
500
501
502
}

static PangoFontMap *
503
pango_fb_font_map (void)
504
{
505
  return g_object_new (pango_fb_font_map_get_type (), NULL);
506
507
508
509
510
511
512
513
514
515
}

PangoMap *
pango_fb_get_shaper_map (const char *lang)
{
  static guint engine_type_id = 0;
  static guint render_type_id = 0;
  
  if (engine_type_id == 0)
    {
516
517
      engine_type_id = g_quark_try_string (PANGO_ENGINE_TYPE_SHAPE);
      render_type_id = g_quark_try_string (PANGO_RENDER_TYPE_FB);
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
    }

  if (engine_type_id == 0)
    {
      engine_type_id = g_quark_from_static_string (PANGO_ENGINE_TYPE_SHAPE);
      render_type_id = g_quark_from_static_string (PANGO_RENDER_TYPE_FB);
    }
  
  return pango_find_map (lang, engine_type_id, render_type_id);
}


/*************** Font impl *****************/
#define PANGO_FB_FONT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FB_FONT, PangoFBFontClass))
#define PANGO_FB_IS_FONT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_FB_FONT))
#define PANGO_FB_IS_FONT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FB_FONT))
#define PANGO_FB_FONT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FB_FONT, PangoFBFontClass))

typedef struct _PangoFBFontClass   PangoFBFontClass;
typedef struct _PangoFBMetricsInfo PangoFBMetricsInfo;
typedef struct _PangoFBContextInfo PangoFBContextInfo;

struct _PangoFBMetricsInfo
{
  const char *lang;
  PangoFontMetrics metrics;
};

struct _PangoFBContextInfo
{
};

struct _PangoFBFontClass
{
  PangoFontClass parent_class;
};

555
556
557
static void                  pango_fb_font_class_init        (PangoFBFontClass *class);
static void                  pango_fb_font_init              (PangoFBFont      *font);
static void                  pango_fb_font_finalize          (GObject          *object);
558
559
560

static PangoFontDescription *pango_fb_font_describe          (PangoFont        *font);
static PangoCoverage *       pango_fb_font_get_coverage      (PangoFont        *font,
561
							      const char       *lang);
562
static PangoEngineShape *    pango_fb_font_find_shaper       (PangoFont        *font,
563
564
							      const char       *lang,
							      guint32           ch);
565
static void                  pango_fb_font_get_glyph_extents (PangoFont        *font,
566
567
568
							      PangoGlyph        glyph,
							      PangoRectangle   *ink_rect,
							      PangoRectangle   *logical_rect);
569
static void                  pango_fb_font_get_metrics       (PangoFont        *font,
570
571
							      const gchar      *lang,
							      PangoFontMetrics *metrics);
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594

GType
pango_fb_font_get_type (void)
{
  static GType object_type = 0;

  if (!object_type)
    {
      static const GTypeInfo object_info =
      {
        sizeof (PangoFBFontClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) pango_fb_font_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (PangoFBFont),
        0,              /* n_preallocs */
        (GInstanceInitFunc) pango_fb_font_init,
      };
      
      object_type = g_type_register_static (PANGO_TYPE_FONT,
                                            "PangoFBFont",
595
596
                                            &object_info,
					    0);
597
598
599
600
601
602
603
604
605
    }
  
  return object_type;
}

static void 
pango_fb_font_init (PangoFBFont *font)
{
  font->desc.size = -1;
606
  font->glyph_info = g_hash_table_new (NULL, NULL);
607
608
609
610
611
}

static gboolean
g_free_2(gpointer key, gpointer value, gpointer data)
{
612
  PangoFBGlyphInfo *pgi = value;
613
614
  g_free (pgi->fbd.drawable_data.mem);
  g_free (value);
615
616
617
618
619
620
  return TRUE;
}

static void
pango_fb_font_clear_extent_cache(PangoFBFont *fbf)
{
621
  g_hash_table_foreach_remove (fbf->glyph_info, g_free_2, NULL);
622
623
624
}

PangoFBGlyphInfo *
625
pango_fb_font_get_glyph_info (PangoFont *font, PangoGlyph glyph)
626
627
{
  PangoFBGlyphInfo *pgi;
628
  PangoFBFont *fbf = PANGO_FB_FONT (font);
629
630
631
632
  FT_Bitmap *renderme;
  FT_GlyphSlot g;
  PangoRectangle *my_logical_rect, *my_ink_rect;
  FT_Face ftf;
633
  FT_Error ec;
634
  
635
636
  ftf = fbf->ftf;

637
  pango_fb_font_set_size (font);
638

639
640
  pgi = g_hash_table_lookup (fbf->glyph_info, GUINT_TO_POINTER (glyph));
  if (pgi)
641
642
    return pgi;

643
  pgi = g_new0 (PangoFBGlyphInfo, 1);
644

645
  ec = FT_Load_Glyph (ftf, glyph, FT_LOAD_DEFAULT);
646
647
648

  g = ftf->glyph;

649
  if (g->format != ft_glyph_format_bitmap)
650
651
652
653
654
655
    if ((ec = FT_Render_Glyph(g, ft_render_mode_normal)))
      g_warning ("Glyph render failed: %d", ec);
  
  renderme = &g->bitmap;
  pgi->top = g->bitmap_top;
  pgi->left = g->bitmap_left;
656

657
  pgi->fbd.drawable_data.mem = g_memdup (renderme->buffer, renderme->pitch * renderme->rows);
658
659
660
661
  pgi->fbd.drawable_data.rowstride = renderme->pitch;
  pgi->fbd.drawable_data.width = pgi->fbd.drawable_data.lim_x = renderme->width;
  pgi->fbd.drawable_data.height = pgi->fbd.drawable_data.lim_y = renderme->rows;

662
  switch (renderme->pixel_mode)
663
664
665
666
667
668
669
670
    {
    case ft_pixel_mode_mono:
      pgi->fbd.drawable_data.depth = 1;
      break;
    case ft_pixel_mode_grays:
      pgi->fbd.drawable_data.depth = 78;
      break;
    default:
671
      g_assert_not_reached ();
672
673
674
675
676
677
      break;
    }

  my_ink_rect = &pgi->extents[0];
  my_logical_rect = &pgi->extents[1];

678
679
680
681
682
683
684
685
686
687
  my_ink_rect->x = PANGO_UNITS_26_6 (g->metrics.horiBearingX);
  my_ink_rect->width = PANGO_UNITS_26_6 (g->metrics.width);
  my_ink_rect->y = -PANGO_UNITS_26_6 (g->metrics.horiBearingY);
  my_ink_rect->height = PANGO_UNITS_26_6 (g->metrics.height);
  
  my_logical_rect->x = 0;
  my_logical_rect->width = PANGO_UNITS_26_6 (g->metrics.horiAdvance);
  my_logical_rect->y = -PANGO_UNITS_26_6 (ftf->size->metrics.ascender + 64);
  my_logical_rect->height = PANGO_UNITS_26_6 (ftf->size->metrics.height + 128);
  
688
  g_hash_table_insert (fbf->glyph_info, GUINT_TO_POINTER(glyph), pgi);
689
690

  return pgi;
691
692
}

693
static void pango_fb_font_finalize (GObject         *object)
694
{
695
  PangoFBFont *fbf = PANGO_FB_FONT (object);
696
697

  /* XXX FIXME g_hash_table_remove(ourfontmap, &fbf->desc); */
698
699
700
701
  pango_coverage_unref (fbf->coverage);
  g_free (fbf->desc.family_name);
  pango_fb_font_clear_extent_cache (fbf);
  g_hash_table_destroy (fbf->glyph_info);
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
}

static void
pango_fb_font_class_init (PangoFBFontClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  PangoFontClass *font_class = PANGO_FONT_CLASS (class);
  
  object_class->finalize = pango_fb_font_finalize;
  font_class->describe = pango_fb_font_describe;
  font_class->get_coverage = pango_fb_font_get_coverage;
  font_class->find_shaper = pango_fb_font_find_shaper;
  font_class->get_glyph_extents = pango_fb_font_get_glyph_extents;
  font_class->get_metrics = pango_fb_font_get_metrics;
}

static PangoFontDescription *
719
pango_fb_font_describe (PangoFont *font)
720
{
721
  return pango_font_description_copy (&PANGO_FB_FONT(font)->desc);
722
723
724
725
726
727
728
729
730
731
732
}

static void
free_coverages_foreach (gpointer key,
			gpointer value,
			gpointer data)
{
  pango_coverage_unref (value);
}

static PangoCoverage *
733
734
pango_fb_font_get_coverage (PangoFont        *font,
			    const char       *lang)
735
736
737
738
739
740
{
  int i, n;
  PangoCoverage *retval;
  PangoMap *shape_map;
  GHashTable *coverage_hash;

741
742
  if (PANGO_FB_FONT (font)->coverage)
    return pango_coverage_ref (PANGO_FB_FONT (font)->coverage);
743

744
  shape_map = pango_fb_get_shaper_map (lang);
745
746
747

  coverage_hash = g_hash_table_new (g_str_hash, g_str_equal);

748
749
  retval = pango_coverage_new ();
  n = MIN( 65536, PANGO_FB_FONT (font)->ftf->num_glyphs);
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  for(i = 0; i < n; i++)
    {
      PangoCoverageLevel font_level;
      PangoMapEntry *map_entry;

      map_entry = pango_map_get_entry (shape_map, i);

      if (map_entry->info)
	{
	  PangoCoverage *coverage;
	  coverage = g_hash_table_lookup (coverage_hash, map_entry->info->id);
	  if (!coverage)
	    {
	      PangoEngineShape *engine = (PangoEngineShape *)pango_map_get_engine (shape_map, i);

	      coverage = engine->get_coverage (font, lang);
	      g_hash_table_insert (coverage_hash, map_entry->info->id, coverage);
	    }
	  
	  font_level = pango_coverage_get (coverage, i);
	  if (font_level == PANGO_COVERAGE_EXACT && !map_entry->is_exact)
	    font_level = PANGO_COVERAGE_APPROXIMATE;

	  if (font_level != PANGO_COVERAGE_NONE)
	    pango_coverage_set (retval, i, font_level);
	}
    }

  g_hash_table_foreach (coverage_hash, free_coverages_foreach, NULL);
  g_hash_table_destroy (coverage_hash);

781
  PANGO_FB_FONT (font)->coverage = pango_coverage_ref (retval);
782
783
784
785
786

  return retval;
}

static PangoEngineShape *
787
788
789
pango_fb_font_find_shaper (PangoFont        *font,
			   const char       *lang,
			   guint32           ch)
790
791
792
793
794
795
796
797
{
  PangoMap *shape_map = NULL;

  shape_map = pango_fb_get_shaper_map (lang);
  return (PangoEngineShape *)pango_map_get_engine (shape_map, ch);
}

void
798
pango_fb_font_set_size (PangoFont *font)
799
800
{
  PangoFBFont *fbf = (PangoFBFont *)font;
801
  gint height;
802

803
  if (PANGO_FB_FONT (font)->desc.size != GPOINTER_TO_UINT (fbf->ftf->generic.data))
804
    {
805
806
807
      height = PANGO_FB_FONT (font)->desc.size;
      fbf->ftf->generic.data = GUINT_TO_POINTER (height);
      FT_Set_Char_Size (fbf->ftf, 0, PANGO_PIXELS_26_6 (height), 72, 72);
808
809
810
811
812
813
814
815
816
817
    }
}

static void
pango_fb_font_get_glyph_extents (PangoFont        *font,
				 PangoGlyph        glyph,
				 PangoRectangle   *ink_rect,
				 PangoRectangle   *logical_rect)
{
  PangoFBFont *fbf;
818
819
  PangoRectangle *my_extents;
  PangoFBGlyphInfo *gi;
820

821
  fbf = PANGO_FB_FONT (font);
822

823
  gi = pango_fb_font_get_glyph_info (font, glyph);
824
  my_extents = gi->extents;
825

826
  if (ink_rect)
827
828
    *ink_rect = my_extents[0];

829
  if (logical_rect)
830
831
832
833
    *logical_rect = my_extents[1];
}

static void
834
835
836
pango_fb_font_get_metrics (PangoFont        *font,
			   const gchar      *lang,
			   PangoFontMetrics *metrics)
837
838
839
{
  FT_Face ftf;

840
  ftf = PANGO_FB_FONT (font)->ftf;
841

842
843
  pango_fb_font_set_size (font);

844
  if (metrics)
845
    {
846
847
      metrics->ascent = PANGO_UNITS_26_6 (ftf->size->metrics.ascender);
      metrics->descent = PANGO_UNITS_26_6 (-ftf->size->metrics.descender);
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
    }
}

/* The following array is supposed to contain enough text to tickle all necessary fonts for each
 * of the languages in the following. Yes, it's pretty lame. Not all of the languages
 * in the following have sufficient text to excercise all the accents for the language, and
 * there are obviously many more languages to include as well.
 */
#if 0
LangInfo lang_texts[] = {
  { "ar", "Arabic  السلام عليكم" },
  { "cs", "Czech (česky)  Dobrý den" },
  { "da", "Danish (Dansk)  Hej, Goddag" },
  { "el", "Greek (Ελληνικά) Γειά σας" },
  { "en", "English Hello" },
  { "eo", "Esperanto Saluton" },
  { "es", "Spanish (Español) ¡Hola!" },
  { "et", "Estonian  Tere, Tervist" },
  { "fi", "Finnish (Suomi)  Hei" },
  { "fr", "French (Français)" },
  { "de", "German Grüß Gott" },
  { "iw", "Hebrew   שלום" },
  { "il", "Italiano  Ciao, Buon giorno" },
  { "ja", "Japanese (日本語) こんにちは, コンニチハ" },
  { "ko", "Korean (한글)   안녕하세요, 안녕하십니까" },
  { "mt", "Maltese   Ċaw, Saħħa" },
  { "nl", "Nederlands, Vlaams Hallo, Dag" },
  { "no", "Norwegian (Norsk) Hei, God dag" },
  { "pl", "Polish   Dzień dobry, Hej" },
  { "ru", "Russian (Русский)" },
  { "sk", "Slovak   Dobrý deň" },
  { "sv", "Swedish (Svenska) Hej, Goddag" },
  { "tr", "Turkish (Türkçe) Merhaba" },
  { "zh", "Chinese (中文,普通话,汉语)" }
};
#endif

/******** misc gdk tie-ins **********/
PangoContext *
gdk_pango_context_get (void)
{
  PangoContext *retval;
  static PangoFontMap *font_map = NULL;

892
  if (!font_map)
893
894
    font_map = pango_fb_font_map ();

895
  retval = pango_context_new ();
896
897
898
899
900

  pango_context_add_font_map (retval, font_map);

  return retval;
}