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, should not be %PANGO_GRAVITY_AUTO
31 *
32 * Converts a `PangoGravity` value to its natural rotation in radians.
33 *
34 * Note that [method@Pango.Matrix.rotate] takes angle in degrees, not radians.
35 * So, to call [method@Pango.Matrix,rotate] with the output of this function
36 * you should multiply it by (180. / G_PI).
37 *
38 * Return value: the rotation value corresponding to @gravity.
39 *
40 * Since: 1.16
41 */
42double
43pango_gravity_to_rotation (PangoGravity gravity)
44{
45 double rotation;
46
47 g_return_val_if_fail (gravity != PANGO_GRAVITY_AUTO, 0);
48
49 switch (gravity)
50 {
51 default:
52 case PANGO_GRAVITY_AUTO: /* shut gcc up */
53 case PANGO_GRAVITY_SOUTH: rotation = 0; break;
54 case PANGO_GRAVITY_NORTH: rotation = G_PI; break;
55 case PANGO_GRAVITY_EAST: rotation = -G_PI_2; break;
56 case PANGO_GRAVITY_WEST: rotation = +G_PI_2; break;
57 }
58
59 return rotation;
60}
61
62/**
63 * pango_gravity_get_for_matrix:
64 * @matrix: (nullable): a `PangoMatrix`
65 *
66 * Finds the gravity that best matches the rotation component
67 * in a `PangoMatrix`.
68 *
69 * Return value: the gravity of @matrix, which will never be
70 * %PANGO_GRAVITY_AUTO, or %PANGO_GRAVITY_SOUTH if @matrix is %NULL
71 *
72 * Since: 1.16
73 */
74PangoGravity
75pango_gravity_get_for_matrix (const PangoMatrix *matrix)
76{
77 PangoGravity gravity;
78 double x;
79 double y;
80
81 if (!matrix)
82 return PANGO_GRAVITY_SOUTH;
83
84 x = matrix->xy;
85 y = matrix->yy;
86
87 if (fabs (x: x) > fabs (x: y))
88 gravity = x > 0 ? PANGO_GRAVITY_WEST : PANGO_GRAVITY_EAST;
89 else
90 gravity = y < 0 ? PANGO_GRAVITY_NORTH : PANGO_GRAVITY_SOUTH;
91
92 return gravity;
93}
94
95
96
97typedef enum
98{
99 PANGO_VERTICAL_DIRECTION_NONE,
100 PANGO_VERTICAL_DIRECTION_TTB,
101 PANGO_VERTICAL_DIRECTION_BTT
102} PangoVerticalDirection;
103
104typedef struct {
105 /* PangoDirection */
106 guint8 horiz_dir; /* Orientation in horizontal context */
107
108 /* PangoVerticalDirection */
109 guint8 vert_dir; /* Orientation in vertical context */
110
111 /* PangoGravity */
112 guint8 preferred_gravity; /* Preferred context gravity */
113
114 /* gboolean */
115 guint8 wide; /* Whether script is mostly wide.
116 * Wide characters are upright (ie.
117 * not rotated) in foreign context */
118} PangoScriptProperties;
119
120#define NONE PANGO_VERTICAL_DIRECTION_NONE
121#define TTB PANGO_VERTICAL_DIRECTION_TTB
122#define BTT PANGO_VERTICAL_DIRECTION_BTT
123
124#define LTR PANGO_DIRECTION_LTR
125#define RTL PANGO_DIRECTION_RTL
126#define WEAK PANGO_DIRECTION_WEAK_LTR
127
128#define S PANGO_GRAVITY_SOUTH
129#define E PANGO_GRAVITY_EAST
130#define W PANGO_GRAVITY_WEST
131
132const PangoScriptProperties script_properties[] =
133 { /* ISO 15924 code */
134 {LTR, NONE, S, FALSE}, /* Zyyy */
135 {LTR, NONE, S, FALSE}, /* Qaai */
136 {RTL, NONE, S, FALSE}, /* Arab */
137 {LTR, NONE, S, FALSE}, /* Armn */
138 {LTR, NONE, S, FALSE}, /* Beng */
139 {LTR, TTB, E, TRUE }, /* Bopo */
140 {LTR, NONE, S, FALSE}, /* Cher */
141 {LTR, NONE, S, FALSE}, /* Qaac */
142 {LTR, NONE, S, FALSE}, /* Cyrl (Cyrs) */
143 {LTR, NONE, S, FALSE}, /* Dsrt */
144 {LTR, NONE, S, FALSE}, /* Deva */
145 {LTR, NONE, S, FALSE}, /* Ethi */
146 {LTR, NONE, S, FALSE}, /* Geor (Geon, Geoa) */
147 {LTR, NONE, S, FALSE}, /* Goth */
148 {LTR, NONE, S, FALSE}, /* Grek */
149 {LTR, NONE, S, FALSE}, /* Gujr */
150 {LTR, NONE, S, FALSE}, /* Guru */
151 {LTR, TTB, E, TRUE }, /* Hani */
152 {LTR, TTB, E, TRUE }, /* Hang */
153 {RTL, NONE, S, FALSE}, /* Hebr */
154 {LTR, TTB, E, TRUE }, /* Hira */
155 {LTR, NONE, S, FALSE}, /* Knda */
156 {LTR, TTB, E, TRUE }, /* Kana */
157 {LTR, NONE, S, FALSE}, /* Khmr */
158 {LTR, NONE, S, FALSE}, /* Laoo */
159 {LTR, NONE, S, FALSE}, /* Latn (Latf, Latg) */
160 {LTR, NONE, S, FALSE}, /* Mlym */
161 {WEAK,TTB, W, FALSE}, /* Mong */
162 {LTR, NONE, S, FALSE}, /* Mymr */
163 {LTR, BTT, W, FALSE}, /* Ogam */
164 {LTR, NONE, S, FALSE}, /* Ital */
165 {LTR, NONE, S, FALSE}, /* Orya */
166 {LTR, NONE, S, FALSE}, /* Runr */
167 {LTR, NONE, S, FALSE}, /* Sinh */
168 {RTL, NONE, S, FALSE}, /* Syrc (Syrj, Syrn, Syre) */
169 {LTR, NONE, S, FALSE}, /* Taml */
170 {LTR, NONE, S, FALSE}, /* Telu */
171 {RTL, NONE, S, FALSE}, /* Thaa */
172 {LTR, NONE, S, FALSE}, /* Thai */
173 {LTR, NONE, S, FALSE}, /* Tibt */
174 {LTR, NONE, S, FALSE}, /* Cans */
175 {LTR, TTB, S, TRUE }, /* Yiii */
176 {LTR, NONE, S, FALSE}, /* Tglg */
177 {LTR, NONE, S, FALSE}, /* Hano */
178 {LTR, NONE, S, FALSE}, /* Buhd */
179 {LTR, NONE, S, FALSE}, /* Tagb */
180
181 /* Unicode-4.0 additions */
182 {LTR, NONE, S, FALSE}, /* Brai */
183 {RTL, NONE, S, FALSE}, /* Cprt */
184 {LTR, NONE, S, FALSE}, /* Limb */
185 {LTR, NONE, S, FALSE}, /* Osma */
186 {LTR, NONE, S, FALSE}, /* Shaw */
187 {LTR, NONE, S, FALSE}, /* Linb */
188 {LTR, NONE, S, FALSE}, /* Tale */
189 {LTR, NONE, S, FALSE}, /* Ugar */
190
191 /* Unicode-4.1 additions */
192 {LTR, NONE, S, FALSE}, /* Talu */
193 {LTR, NONE, S, FALSE}, /* Bugi */
194 {LTR, NONE, S, FALSE}, /* Glag */
195 {LTR, NONE, S, FALSE}, /* Tfng */
196 {LTR, NONE, S, FALSE}, /* Sylo */
197 {LTR, NONE, S, FALSE}, /* Xpeo */
198 {RTL, NONE, S, FALSE}, /* Khar */
199
200 /* Unicode-5.0 additions */
201 {LTR, NONE, S, FALSE}, /* Zzzz */
202 {LTR, NONE, S, FALSE}, /* Bali */
203 {LTR, NONE, S, FALSE}, /* Xsux */
204 {RTL, NONE, S, FALSE}, /* Phnx */
205 {LTR, NONE, S, FALSE}, /* Phag */
206 {RTL, NONE, S, FALSE}, /* Nkoo */
207
208 /* Unicode-5.1 additions */
209 {LTR, NONE, S, FALSE}, /* Kali */
210 {LTR, NONE, S, FALSE}, /* Lepc */
211 {LTR, NONE, S, FALSE}, /* Rjng */
212 {LTR, NONE, S, FALSE}, /* Sund */
213 {LTR, NONE, S, FALSE}, /* Saur */
214 {LTR, NONE, S, FALSE}, /* Cham */
215 {LTR, NONE, S, FALSE}, /* Olck */
216 {LTR, NONE, S, FALSE}, /* Vaii */
217 {LTR, NONE, S, FALSE}, /* Cari */
218 {LTR, NONE, S, FALSE}, /* Lyci */
219 {RTL, NONE, S, FALSE}, /* Lydi */
220
221 /* Unicode-5.2 additions */
222 {RTL, NONE, S, FALSE}, /* Avst */
223 {LTR, NONE, S, FALSE}, /* Bamu */
224 {LTR, NONE, S, FALSE}, /* Egyp */
225 {RTL, NONE, S, FALSE}, /* Armi */
226 {RTL, NONE, S, FALSE}, /* Phli */
227 {RTL, NONE, S, FALSE}, /* Prti */
228 {LTR, NONE, S, FALSE}, /* Java */
229 {LTR, NONE, S, FALSE}, /* Kthi */
230 {LTR, NONE, S, FALSE}, /* Lisu */
231 {LTR, NONE, S, FALSE}, /* Mtei */
232 {RTL, NONE, S, FALSE}, /* Sarb */
233 {RTL, NONE, S, FALSE}, /* Orkh */
234 {RTL, TTB, S, FALSE}, /* Samr */
235 {LTR, NONE, S, FALSE}, /* Lana */
236 {LTR, NONE, S, FALSE}, /* Tavt */
237
238 /* Unicode-6.0 additions */
239 {LTR, NONE, S, FALSE}, /* Batk */
240 {LTR, NONE, S, FALSE}, /* Brah */
241 {RTL, NONE, S, FALSE}, /* Mand */
242
243 /* Unicode-6.1 additions */
244 {LTR, NONE, S, FALSE}, /* Cakm */
245 {RTL, NONE, S, FALSE}, /* Merc */
246 {RTL, NONE, S, FALSE}, /* Mero */
247 {LTR, NONE, S, FALSE}, /* Plrd */
248 {LTR, NONE, S, FALSE}, /* Shrd */
249 {LTR, NONE, S, FALSE}, /* Sora */
250 {LTR, NONE, S, FALSE}, /* Takr */
251
252 /* Unicode-7.0 additions */
253 {LTR, NONE, S, FALSE}, /* Bass */
254 {LTR, NONE, S, FALSE}, /* Aghb */
255 {LTR, NONE, S, FALSE}, /* Dupl */
256 {LTR, NONE, S, FALSE}, /* Elba */
257 {LTR, NONE, S, FALSE}, /* Gran */
258 {LTR, NONE, S, FALSE}, /* Khoj */
259 {LTR, NONE, S, FALSE}, /* Sind */
260 {LTR, NONE, S, FALSE}, /* Lina */
261 {LTR, NONE, S, FALSE}, /* Mahj */
262 {RTL, NONE, S, FALSE}, /* Mani */
263 {RTL, NONE, S, FALSE}, /* Mend */
264 {LTR, NONE, S, FALSE}, /* Modi */
265 {LTR, NONE, S, FALSE}, /* Mroo */
266 {RTL, NONE, S, FALSE}, /* Nbat */
267 {RTL, NONE, S, FALSE}, /* Narb */
268 {LTR, NONE, S, FALSE}, /* Perm */
269 {LTR, NONE, S, FALSE}, /* Hmng */
270 {RTL, NONE, S, FALSE}, /* Palm */
271 {LTR, NONE, S, FALSE}, /* Pauc */
272 {RTL, NONE, S, FALSE}, /* Phlp */
273 {LTR, NONE, S, FALSE}, /* Sidd */
274 {LTR, NONE, S, FALSE}, /* Tirh */
275 {LTR, NONE, S, FALSE}, /* Wara */
276
277 /* Unicode-8.0 additions */
278 {LTR, NONE, S, FALSE}, /* Ahom */
279 {LTR, NONE, S, FALSE}, /* Hluw */
280 {RTL, NONE, S, FALSE}, /* Hatr */
281 {LTR, NONE, S, FALSE}, /* Mult */
282 {LTR, NONE, S, FALSE}, /* Hung */
283 {LTR, NONE, S, FALSE}, /* Sgnw */
284
285 /* Unicode-9.0 additions */
286 {RTL, NONE, S, FALSE}, /* Adlm */
287 {LTR, NONE, S, FALSE}, /* Bhks */
288 {LTR, NONE, S, FALSE}, /* Marc */
289 {LTR, NONE, S, FALSE}, /* Newa */
290 {LTR, NONE, S, FALSE}, /* Osge */
291 {LTR, NONE, S, FALSE}, /* Tang */
292
293 /* Unicode-10.0 additions */
294 {LTR, NONE, S, FALSE}, /* Gonm */
295 {LTR, NONE, S, FALSE}, /* Nshu */
296 {LTR, NONE, S, FALSE}, /* Soyo */
297 {LTR, NONE, S, FALSE}, /* Zanb */
298
299 /* Unicode-11.0 additions */
300 {LTR, NONE, S, FALSE}, /* Dogr */
301 {LTR, NONE, S, FALSE}, /* Gong */
302 {RTL, NONE, S, FALSE}, /* Rohg */
303 {LTR, NONE, S, FALSE}, /* Maka */
304 {LTR, NONE, S, FALSE}, /* Medf */
305 {RTL, NONE, S, FALSE}, /* Sogo */
306 {RTL, NONE, S, FALSE}, /* Sogd */
307
308 /* Unicode-12.0 additions */
309 {RTL, NONE, S, FALSE}, /* Elym */
310 {LTR, NONE, S, FALSE}, /* Nand */
311 {LTR, NONE, S, FALSE}, /* Rohg */
312 {LTR, NONE, S, FALSE}, /* Wcho */
313
314 /* Unicode-13.0 additions */
315 {RTL, NONE, S, FALSE}, /* Chrs */
316 {LTR, NONE, S, FALSE}, /* Diak */
317 {LTR, NONE, S, FALSE}, /* Kits */
318 {RTL, NONE, S, FALSE}, /* Yezi */
319
320 {LTR, NONE, S, FALSE}, /* Cpmn */
321 {RTL, NONE, S, FALSE}, /* Ougr */
322 {LTR, NONE, S, FALSE}, /* Tnsa */
323 {LTR, NONE, S, FALSE}, /* Toto */
324 {LTR, NONE, S, FALSE}, /* Vith */
325};
326
327#undef NONE
328#undef TTB
329#undef BTT
330
331#undef LTR
332#undef RTL
333#undef WEAK
334
335#undef S
336#undef E
337#undef N
338#undef W
339
340static PangoScriptProperties
341get_script_properties (PangoScript script)
342{
343 g_return_val_if_fail (script >= 0, script_properties[0]);
344
345 if ((guint)script >= G_N_ELEMENTS (script_properties))
346 return script_properties[0];
347
348 return script_properties[script];
349}
350
351/**
352 * pango_gravity_get_for_script:
353 * @script: `PangoScript` to query
354 * @base_gravity: base gravity of the paragraph
355 * @hint: orientation hint
356 *
357 * Returns the gravity to use in laying out a `PangoItem`.
358 *
359 * The gravity is determined based on the script, base gravity, and hint.
360 *
361 * If @base_gravity is %PANGO_GRAVITY_AUTO, it is first replaced with the
362 * preferred gravity of @script. To get the preferred gravity of a script,
363 * pass %PANGO_GRAVITY_AUTO and %PANGO_GRAVITY_HINT_STRONG in.
364 *
365 * Return value: resolved gravity suitable to use for a run of text
366 * with @script
367 *
368 * Since: 1.16
369 */
370PangoGravity
371pango_gravity_get_for_script (PangoScript script,
372 PangoGravity base_gravity,
373 PangoGravityHint hint)
374{
375 PangoScriptProperties props = get_script_properties (script);
376
377 return pango_gravity_get_for_script_and_width (script, wide: props.wide,
378 base_gravity, hint);
379}
380
381/**
382 * pango_gravity_get_for_script_and_width:
383 * @script: `PangoScript` to query
384 * @wide: %TRUE for wide characters as returned by g_unichar_iswide()
385 * @base_gravity: base gravity of the paragraph
386 * @hint: orientation hint
387 *
388 * Returns the gravity to use in laying out a single character
389 * or `PangoItem`.
390 *
391 * The gravity is determined based on the script, East Asian width,
392 * base gravity, and hint,
393 *
394 * This function is similar to [func@Pango.Gravity.get_for_script] except
395 * that this function makes a distinction between narrow/half-width and
396 * wide/full-width characters also. Wide/full-width characters always
397 * stand *upright*, that is, they always take the base gravity,
398 * whereas narrow/full-width characters are always rotated in vertical
399 * context.
400 *
401 * If @base_gravity is %PANGO_GRAVITY_AUTO, it is first replaced with the
402 * preferred gravity of @script.
403 *
404 * Return value: resolved gravity suitable to use for a run of text
405 * with @script and @wide.
406 *
407 * Since: 1.26
408 */
409PangoGravity
410pango_gravity_get_for_script_and_width (PangoScript script,
411 gboolean wide,
412 PangoGravity base_gravity,
413 PangoGravityHint hint)
414{
415 PangoScriptProperties props = get_script_properties (script);
416 gboolean vertical;
417
418 if (G_UNLIKELY (base_gravity == PANGO_GRAVITY_AUTO))
419 base_gravity = props.preferred_gravity;
420
421 vertical = PANGO_GRAVITY_IS_VERTICAL (base_gravity);
422
423 /* Everything is designed such that a system with no vertical support
424 * renders everything correctly horizontally. So, if not in a vertical
425 * gravity, base and resolved gravities are always the same.
426 *
427 * Wide characters are always upright.
428 */
429 if (G_LIKELY (!vertical || wide))
430 return base_gravity;
431
432 /* If here, we have a narrow character in a vertical gravity setting.
433 * Resolve depending on the hint.
434 */
435 switch (hint)
436 {
437 default:
438 case PANGO_GRAVITY_HINT_NATURAL:
439 if (props.vert_dir == PANGO_VERTICAL_DIRECTION_NONE)
440 return PANGO_GRAVITY_SOUTH;
441 if ((base_gravity == PANGO_GRAVITY_EAST) ^
442 (props.vert_dir == PANGO_VERTICAL_DIRECTION_BTT))
443 return PANGO_GRAVITY_SOUTH;
444 else
445 return PANGO_GRAVITY_NORTH;
446
447 case PANGO_GRAVITY_HINT_STRONG:
448 return base_gravity;
449
450 case PANGO_GRAVITY_HINT_LINE:
451 if ((base_gravity == PANGO_GRAVITY_EAST) ^
452 (props.horiz_dir == PANGO_DIRECTION_RTL))
453 return PANGO_GRAVITY_SOUTH;
454 else
455 return PANGO_GRAVITY_NORTH;
456 }
457}
458

source code of gtk/subprojects/pango/pango/pango-gravity.c