Upload tizen 2.0 beta source
[external/pango1.0.git] / pango / pango-gravity.c
1 /* Pango
2  * pango-gravity.c: Gravity routines
3  *
4  * Copyright (C) 2006, 2007 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
24 #include "pango-gravity.h"
25
26 #include <math.h>
27
28 /**
29  * pango_gravity_to_rotation:
30  * @gravity: gravity to query
31  *
32  * Converts a #PangoGravity value to its natural rotation in radians.
33  * @gravity should not be %PANGO_GRAVITY_AUTO.
34  *
35  * Note that pango_matrix_rotate() takes angle in degrees, not radians.
36  * So, to call pango_matrix_rotate() with the output of this function
37  * you should multiply it by (180. / G_PI).
38  *
39  * Return value: the rotation value corresponding to @gravity.
40  *
41  * Since: 1.16
42  */
43 double
44 pango_gravity_to_rotation (PangoGravity gravity)
45 {
46   double rotation;
47
48   g_return_val_if_fail (gravity != PANGO_GRAVITY_AUTO, 0);
49
50   switch (gravity)
51     {
52       default:
53       case PANGO_GRAVITY_AUTO: /* shut gcc up */
54       case PANGO_GRAVITY_SOUTH: rotation =  0;          break;
55       case PANGO_GRAVITY_NORTH: rotation =  G_PI;       break;
56       case PANGO_GRAVITY_EAST:  rotation = -G_PI_2;     break;
57       case PANGO_GRAVITY_WEST:  rotation = +G_PI_2;     break;
58     }
59
60   return rotation;
61 }
62
63 /**
64  * pango_gravity_get_for_matrix:
65  * @matrix: a #PangoMatrix
66  *
67  * Finds the gravity that best matches the rotation component
68  * in a #PangoMatrix.
69  *
70  * Return value: the gravity of @matrix, which will never be
71  * %PANGO_GRAVITY_AUTO, or %PANGO_GRAVITY_SOUTH if @matrix is %NULL
72  *
73  * Since: 1.16
74  */
75 PangoGravity
76 pango_gravity_get_for_matrix (const PangoMatrix *matrix)
77 {
78   PangoGravity gravity;
79   double x;
80   double y;
81
82   if (!matrix)
83     return PANGO_GRAVITY_SOUTH;
84
85   x = matrix->xy;
86   y = matrix->yy;
87
88   if (fabs (x) > fabs (y))
89     gravity = x > 0 ? PANGO_GRAVITY_WEST : PANGO_GRAVITY_EAST;
90   else
91     gravity = y < 0 ? PANGO_GRAVITY_NORTH : PANGO_GRAVITY_SOUTH;
92
93   return gravity;
94 }
95
96
97
98 typedef enum
99 {
100   PANGO_VERTICAL_DIRECTION_NONE,
101   PANGO_VERTICAL_DIRECTION_TTB,
102   PANGO_VERTICAL_DIRECTION_BTT
103 } PangoVerticalDirection;
104
105 typedef struct {
106   /* PangoDirection */
107   guint8 horiz_dir;             /* Orientation in horizontal context */
108
109   /* PangoVerticalDirection */
110   guint8 vert_dir;              /* Orientation in vertical context */
111
112   /* PangoGravity */
113   guint8 preferred_gravity;     /* Preferred context gravity */
114
115   /* gboolean */
116   guint8 wide;                  /* Whether script is mostly wide.
117                                  * Wide characters are upright (ie.
118                                  * not rotated) in foreign context */
119 } PangoScriptProperties;
120
121 #define NONE PANGO_VERTICAL_DIRECTION_NONE
122 #define TTB  PANGO_VERTICAL_DIRECTION_TTB
123 #define BTT  PANGO_VERTICAL_DIRECTION_BTT
124
125 #define LTR  PANGO_DIRECTION_LTR
126 #define RTL  PANGO_DIRECTION_RTL
127 #define WEAK PANGO_DIRECTION_WEAK_LTR
128
129 #define S PANGO_GRAVITY_SOUTH
130 #define E PANGO_GRAVITY_EAST
131 #define N PANGO_GRAVITY_NORTH
132 #define W PANGO_GRAVITY_WEST
133
134 const PangoScriptProperties script_properties[] =
135   {                             /* ISO 15924 code */
136       {LTR, NONE, S, FALSE},    /* Zyyy */
137       {LTR, NONE, S, FALSE},    /* Qaai */
138       {RTL, NONE, S, FALSE},    /* Arab */
139       {LTR, NONE, S, FALSE},    /* Armn */
140       {LTR, NONE, S, FALSE},    /* Beng */
141       {LTR, TTB,  E, TRUE },    /* Bopo */
142       {LTR, NONE, S, FALSE},    /* Cher */
143       {LTR, NONE, S, FALSE},    /* Qaac */
144       {LTR, NONE, S, FALSE},    /* Cyrl (Cyrs) */
145       {LTR, NONE, S, FALSE},    /* Dsrt */
146       {LTR, NONE, S, FALSE},    /* Deva */
147       {LTR, NONE, S, FALSE},    /* Ethi */
148       {LTR, NONE, S, FALSE},    /* Geor (Geon, Geoa) */
149       {LTR, NONE, S, FALSE},    /* Goth */
150       {LTR, NONE, S, FALSE},    /* Grek */
151       {LTR, NONE, S, FALSE},    /* Gujr */
152       {LTR, NONE, S, FALSE},    /* Guru */
153       {LTR, TTB,  E, TRUE },    /* Hani */
154       {LTR, TTB,  E, TRUE },    /* Hang */
155       {RTL, NONE, S, FALSE},    /* Hebr */
156       {LTR, TTB,  E, TRUE },    /* Hira */
157       {LTR, NONE, S, FALSE},    /* Knda */
158       {LTR, TTB,  E, TRUE },    /* Kana */
159       {LTR, NONE, S, FALSE},    /* Khmr */
160       {LTR, NONE, S, FALSE},    /* Laoo */
161       {LTR, NONE, S, FALSE},    /* Latn (Latf, Latg) */
162       {LTR, NONE, S, FALSE},    /* Mlym */
163       {WEAK,TTB,  W, FALSE},    /* Mong */
164       {LTR, NONE, S, FALSE},    /* Mymr */
165       {LTR, BTT,  W, FALSE},    /* Ogam */
166       {LTR, NONE, S, FALSE},    /* Ital */
167       {LTR, NONE, S, FALSE},    /* Orya */
168       {LTR, NONE, S, FALSE},    /* Runr */
169       {LTR, NONE, S, FALSE},    /* Sinh */
170       {RTL, NONE, S, FALSE},    /* Syrc (Syrj, Syrn, Syre) */
171       {LTR, NONE, S, FALSE},    /* Taml */
172       {LTR, NONE, S, FALSE},    /* Telu */
173       {RTL, NONE, S, FALSE},    /* Thaa */
174       {LTR, NONE, S, FALSE},    /* Thai */
175       {LTR, NONE, S, FALSE},    /* Tibt */
176       {LTR, NONE, S, FALSE},    /* Cans */
177       {LTR, TTB,  S, TRUE },    /* Yiii */
178       {LTR, NONE, S, FALSE},    /* Tglg */
179       {LTR, NONE, S, FALSE},    /* Hano */
180       {LTR, NONE, S, FALSE},    /* Buhd */
181       {LTR, NONE, S, FALSE},    /* Tagb */
182
183       /* Unicode-4.0 additions */
184       {LTR, NONE, S, FALSE},    /* Brai */
185       {LTR, NONE, S, FALSE},    /* Cprt */
186       {LTR, NONE, S, FALSE},    /* Limb */
187       {LTR, NONE, S, FALSE},    /* Osma */
188       {LTR, NONE, S, FALSE},    /* Shaw */
189       {LTR, NONE, S, FALSE},    /* Linb */
190       {LTR, NONE, S, FALSE},    /* Tale */
191       {LTR, NONE, S, FALSE},    /* Ugar */
192
193       /* Unicode-4.1 additions */
194       {LTR, NONE, S, FALSE},    /* Talu */
195       {LTR, NONE, S, FALSE},    /* Bugi */
196       {LTR, NONE, S, FALSE},    /* Glag */
197       {LTR, NONE, S, FALSE},    /* Tfng */
198       {LTR, NONE, S, FALSE},    /* Sylo */
199       {LTR, NONE, S, FALSE},    /* Xpeo */
200       {LTR, NONE, S, FALSE},    /* Khar */
201
202       /* Unicode-5.0 additions */
203       {LTR, NONE, S, FALSE},    /* Zzzz */
204       {LTR, NONE, S, FALSE},    /* Bali */
205       {LTR, NONE, S, FALSE},    /* Xsux */
206       {RTL, NONE, S, FALSE},    /* Phnx */
207       {LTR, NONE, S, FALSE},    /* Phag */
208       {RTL, NONE, S, FALSE}     /* Nkoo */
209 };
210
211 #undef NONE
212 #undef TTB
213 #undef BTT
214
215 #undef LTR
216 #undef RTL
217 #undef WEAK
218
219 #undef S
220 #undef E
221 #undef N
222 #undef W
223
224 static PangoScriptProperties
225 get_script_properties (PangoScript script)
226 {
227   g_return_val_if_fail (script >= 0, script_properties[0]);
228
229   if ((guint)script >= G_N_ELEMENTS (script_properties))
230     return script_properties[0];
231
232   return script_properties[script];
233 }
234
235 /**
236  * pango_gravity_get_for_script:
237  * @script: #PangoScript to query
238  * @base_gravity: base gravity of the paragraph
239  * @hint: orientation hint
240  *
241  * Based on the script, base gravity, and hint, returns actual gravity
242  * to use in laying out a single #PangoItem.
243  *
244  * If @base_gravity is %PANGO_GRAVITY_AUTO, it is first replaced with the
245  * preferred gravity of @script.  To get the preferred gravity of a script,
246  * pass %PANGO_GRAVITY_AUTO and %PANGO_GRAVITY_HINT_STRONG in.
247  *
248  * Return value: resolved gravity suitable to use for a run of text
249  * with @script.
250  *
251  * Since: 1.16
252  */
253 PangoGravity
254 pango_gravity_get_for_script (PangoScript      script,
255                               PangoGravity     base_gravity,
256                               PangoGravityHint hint)
257 {
258   PangoScriptProperties props = get_script_properties (script);
259   gboolean vertical;
260
261
262   if (G_UNLIKELY (base_gravity == PANGO_GRAVITY_AUTO))
263     base_gravity = props.preferred_gravity;
264
265   vertical = PANGO_GRAVITY_IS_VERTICAL (base_gravity);
266
267   return pango_gravity_get_for_script_and_width (script, props.wide,
268                                                  base_gravity, hint);
269 }
270
271 /**
272  * pango_gravity_get_for_script_and_width:
273  * @script: #PangoScript to query
274  * @wide: %TRUE for wide characters as returned by g_unichar_iswide()
275  * @base_gravity: base gravity of the paragraph
276  * @hint: orientation hint
277  *
278  * Based on the script, East Asian width, base gravity, and hint,
279  * returns actual gravity to use in laying out a single character
280  * or #PangoItem.
281  *
282  * This function is similar to pango_gravity_get_for_script() except
283  * that this function makes a distinction between narrow/half-width and
284  * wide/full-width characters also.  Wide/full-width characters always
285  * stand <emph>upright</emph>, that is, they always take the base gravity,
286  * whereas narrow/full-width characters are always rotated in vertical
287  * context.
288  *
289  * If @base_gravity is %PANGO_GRAVITY_AUTO, it is first replaced with the
290  * preferred gravity of @script.
291  *
292  * Return value: resolved gravity suitable to use for a run of text
293  * with @script and @wide.
294  *
295  * Since: 1.26
296  */
297 PangoGravity
298 pango_gravity_get_for_script_and_width (PangoScript        script,
299                                         gboolean           wide,
300                                         PangoGravity       base_gravity,
301                                         PangoGravityHint   hint)
302 {
303   PangoScriptProperties props = get_script_properties (script);
304   gboolean vertical;
305
306
307   if (G_UNLIKELY (base_gravity == PANGO_GRAVITY_AUTO))
308     base_gravity = props.preferred_gravity;
309
310   vertical = PANGO_GRAVITY_IS_VERTICAL (base_gravity);
311
312   /* Everything is designed such that a system with no vertical support
313    * renders everything correctly horizontally.  So, if not in a vertical
314    * gravity, base and resolved gravities are always the same.
315    *
316    * Wide characters are always upright.
317    */
318   if (G_LIKELY (!vertical || wide))
319     return base_gravity;
320
321   /* If here, we have a narrow character in a vertical gravity setting.
322    * Resolve depending on the hint.
323    */
324   switch (hint)
325     {
326     default:
327     case PANGO_GRAVITY_HINT_NATURAL:
328       if (props.vert_dir == PANGO_VERTICAL_DIRECTION_NONE)
329         return PANGO_GRAVITY_SOUTH;
330       if ((base_gravity   == PANGO_GRAVITY_EAST) ^
331           (props.vert_dir == PANGO_VERTICAL_DIRECTION_BTT))
332         return PANGO_GRAVITY_SOUTH;
333       else
334         return PANGO_GRAVITY_NORTH;
335
336     case PANGO_GRAVITY_HINT_STRONG:
337       return base_gravity;
338
339     case PANGO_GRAVITY_HINT_LINE:
340       if ((base_gravity    == PANGO_GRAVITY_EAST) ^
341           (props.horiz_dir == PANGO_DIRECTION_RTL))
342         return PANGO_GRAVITY_SOUTH;
343       else
344         return PANGO_GRAVITY_NORTH;
345     }
346 }