]> Pileus Git - ~andy/gtk/blob - modules/linux-fb/basic.c
:get_property): remove g_value_init calls, as they are no longer needed.
[~andy/gtk] / modules / linux-fb / basic.c
1 /* Pango
2  * basic.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 Lesser 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  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser 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 <glib.h>
23 #include <gconvert.h>
24 #include <pango/pango.h>
25 #include <pango/pango-utils.h>
26 #include "gdkprivate-fb.h"
27 #include <string.h>
28
29 typedef struct _CharCache CharCache;
30
31 struct _CharCache 
32 {
33 };
34
35 static PangoEngineRange basic_ranges[] = {
36   /* Language characters */
37   { 0x0000, 0x02af, "*" },
38   { 0x02b0, 0x02ff, "" },
39   { 0x0380, 0x058f, "*" },
40   { 0x0591, 0x05f4, "*" }, /* Hebrew */
41   { 0x060c, 0x06f9, "" }, /* Arabic */
42   { 0x0e01, 0x0e5b, "" },  /* Thai */
43   { 0x10a0, 0x10ff, "*" }, /* Georgian */
44   { 0x1200, 0x16ff, "*" }, /* Ethiopic,Cherokee,Canadian,Ogham,Runic */
45   { 0x1e00, 0x1fff, "*" },
46   { 0x2000, 0x9fff, "*" },
47   { 0xac00, 0xd7a3, "kr" },
48   { 0xf900, 0xfa0b, "kr" },
49   { 0xff00, 0xffe3, "*" }
50 };
51
52 static PangoEngineInfo script_engines[] = {
53   {
54     "BasicScriptEngineFB",
55     PANGO_ENGINE_TYPE_SHAPE,
56     "PangoRenderTypeFB",
57     basic_ranges, G_N_ELEMENTS(basic_ranges)
58   }
59 };
60
61 static gint n_script_engines = G_N_ELEMENTS (script_engines);
62
63 /*
64  * FB window system script engine portion
65  */
66
67 static CharCache *
68 char_cache_new (void)
69 {
70   CharCache *result;
71
72   result = g_new0 (CharCache, 1);
73
74   return result;
75 }
76
77 static void
78 char_cache_free (CharCache *cache)
79 {
80   g_free (cache);
81 }
82
83 PangoGlyph 
84 find_char (CharCache *cache, PangoFont *font, gunichar wc, const char *input)
85 {
86   return FT_Get_Char_Index(PANGO_FB_FONT(font)->ftf, wc);
87 }
88
89 static void
90 set_glyph (PangoFont *font, PangoGlyphString *glyphs, int i, int offset, PangoGlyph glyph)
91 {
92   PangoRectangle logical_rect;
93
94   glyphs->glyphs[i].glyph = glyph;
95   
96   glyphs->glyphs[i].geometry.x_offset = 0;
97   glyphs->glyphs[i].geometry.y_offset = 0;
98
99   glyphs->log_clusters[i] = offset;
100
101   pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
102   glyphs->glyphs[i].geometry.width = logical_rect.width;
103 }
104
105
106 static void
107 swap_range (PangoGlyphString *glyphs, int start, int end)
108 {
109   int i, j;
110   
111   for (i = start, j = end - 1; i < j; i++, j--)
112     {
113       PangoGlyphInfo glyph_info;
114       gint log_cluster;
115       
116       glyph_info = glyphs->glyphs[i];
117       glyphs->glyphs[i] = glyphs->glyphs[j];
118       glyphs->glyphs[j] = glyph_info;
119       
120       log_cluster = glyphs->log_clusters[i];
121       glyphs->log_clusters[i] = glyphs->log_clusters[j];
122       glyphs->log_clusters[j] = log_cluster;
123     }
124 }
125
126 static PangoGlyph
127 pango_fb_get_unknown_glyph(PangoFont *font)
128 {
129   return FT_Get_Char_Index (PANGO_FB_FONT (font)->ftf, '~');
130 }
131
132 static CharCache *
133 get_char_cache (PangoFont *font)
134 {
135   GQuark cache_id = g_quark_from_string ("basic-char-cache");
136   
137   CharCache *cache = g_object_get_qdata (G_OBJECT (font), cache_id);
138   if (!cache)
139     {
140       cache = char_cache_new ();
141       g_object_set_qdata_full (G_OBJECT (font), cache_id, 
142                                cache, (GDestroyNotify)char_cache_free);
143     }
144
145   return cache;
146 }
147
148 static void 
149 basic_engine_shape (PangoFont        *font,
150                     const char       *text,
151                     gint              length,
152                     PangoAnalysis    *analysis,
153                     PangoGlyphString *glyphs)
154 {
155   int n_chars;
156   int i;
157   const char *p;
158
159   CharCache *cache;
160
161   g_return_if_fail (font != NULL);
162   g_return_if_fail (text != NULL);
163   g_return_if_fail (length >= 0);
164   g_return_if_fail (analysis != NULL);
165
166   cache = get_char_cache (font);
167
168   n_chars = g_utf8_strlen (text, length);
169   pango_glyph_string_set_size (glyphs, n_chars);
170
171   p = text;
172   for (i=0; i < n_chars; i++)
173     {
174       gunichar wc;
175       gunichar mirrored_ch;
176       PangoGlyph index;
177       char buf[6];
178       const char *input;
179
180       wc = g_utf8_get_char (p);
181
182       input = p;
183       if (analysis->level % 2)
184         if (pango_get_mirror_char (wc, &mirrored_ch))
185           {
186             wc = mirrored_ch;
187             
188             g_unichar_to_utf8 (wc, buf);
189             input = buf;
190           }
191
192       if (wc == 0x200B || wc == 0x200E || wc == 0x200F) /* Zero-width characters */
193         {
194           set_glyph (font, glyphs, i, p - text, 0);
195         }
196       else
197         {
198           index = find_char (cache, font, wc, input);
199           if (index)
200             {
201               set_glyph (font, glyphs, i, p - text, index);
202               
203               if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
204                 {
205                   if (i > 0)
206                     {
207                       PangoRectangle logical_rect, ink_rect;
208                       
209                       glyphs->glyphs[i].geometry.width = MAX (glyphs->glyphs[i-1].geometry.width,
210                                                               glyphs->glyphs[i].geometry.width);
211                       glyphs->glyphs[i-1].geometry.width = 0;
212                       glyphs->log_clusters[i] = glyphs->log_clusters[i-1];
213
214                       /* Some heuristics to try to guess how overstrike glyphs are
215                        * done and compensate
216                        */
217                       pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect);
218                       if (logical_rect.width == 0 && ink_rect.x == 0)
219                         glyphs->glyphs[i].geometry.x_offset = (glyphs->glyphs[i].geometry.width - ink_rect.width) / 2;
220                     }
221                 }
222             }
223           else
224             set_glyph (font, glyphs, i, p - text, pango_fb_get_unknown_glyph (font));
225         }
226       
227       p = g_utf8_next_char (p);
228     }
229
230   /* Simple bidi support... may have separate modules later */
231
232   if (analysis->level % 2)
233     {
234       int start, end;
235
236       /* Swap all glyphs */
237       swap_range (glyphs, 0, n_chars);
238       
239       /* Now reorder glyphs within each cluster back to LTR */
240       for (start=0; start<n_chars;)
241         {
242           end = start;
243           while (end < n_chars &&
244                  glyphs->log_clusters[end] == glyphs->log_clusters[start])
245             end++;
246           
247           swap_range (glyphs, start, end);
248           start = end;
249         }
250     }
251 }
252
253 static PangoCoverage *
254 basic_engine_get_coverage (PangoFont  *font,
255                            const char *lang)
256 {
257   CharCache *cache = get_char_cache (font);
258   PangoCoverage *result = pango_coverage_new ();
259   gunichar wc;
260
261   for (wc = 0; wc < 65536; wc++)
262     {
263       char buf[6];
264
265       g_unichar_to_utf8 (wc, buf);
266       if (find_char (cache, font, wc, buf))
267         pango_coverage_set (result, wc, PANGO_COVERAGE_EXACT);
268     }
269
270   return result;
271 }
272
273 static PangoEngine *
274 basic_engine_fb_new ()
275 {
276   PangoEngineShape *result;
277   
278   result = g_new (PangoEngineShape, 1);
279
280   result->engine.id = "BasicScriptEngineFB";
281   result->engine.type = PANGO_ENGINE_TYPE_LANG;
282   result->engine.length = sizeof (result);
283   result->script_shape = basic_engine_shape;
284   result->get_coverage = basic_engine_get_coverage;
285
286   return (PangoEngine *)result;
287 }
288
289 /* The following three functions provide the public module API for
290  * Pango
291  */
292 #ifdef MODULE_PREFIX
293 #define MODULE_ENTRY(func) _pango_basic_##func
294 #else
295 #define MODULE_ENTRY(func) func
296 #endif
297
298 void 
299 MODULE_ENTRY(script_engine_list) (PangoEngineInfo **engines, gint *n_engines)
300 {
301   *engines = script_engines;
302   *n_engines = n_script_engines;
303 }
304
305 PangoEngine *
306 MODULE_ENTRY(script_engine_load) (const char *id)
307 {
308   if (!strcmp (id, "BasicScriptEngineFB"))
309     return basic_engine_fb_new ();
310   else
311     return NULL;
312 }
313
314 void 
315 MODULE_ENTRY(script_engine_unload) (PangoEngine *engine)
316 {
317 }
318