diff options
Diffstat (limited to 'pango2/pango-gravity.c')
-rw-r--r-- | pango2/pango-gravity.c | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/pango2/pango-gravity.c b/pango2/pango-gravity.c new file mode 100644 index 00000000..0e9b4299 --- /dev/null +++ b/pango2/pango-gravity.c @@ -0,0 +1,457 @@ +/* Pango2 + * pango-gravity.c: Gravity routines + * + * Copyright (C) 2006, 2007 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "pango-gravity.h" + +#include <math.h> + +/** + * pango2_gravity_to_rotation: + * @gravity: gravity to query, should not be %PANGO2_GRAVITY_AUTO + * + * Converts a `Pango2Gravity` value to its natural rotation in radians. + * + * Note that [method@Pango2.Matrix.rotate] takes angle in degrees, not radians. + * So, to call [method@Pango2.Matrix,rotate] with the output of this function + * you should multiply it by (180. / G_PI). + * + * Return value: the rotation value corresponding to @gravity. + */ +double +pango2_gravity_to_rotation (Pango2Gravity gravity) +{ + double rotation; + + g_return_val_if_fail (gravity != PANGO2_GRAVITY_AUTO, 0); + + switch (gravity) + { + default: + case PANGO2_GRAVITY_AUTO: /* shut gcc up */ + case PANGO2_GRAVITY_SOUTH: + rotation = 0; + break; + case PANGO2_GRAVITY_NORTH: + rotation = G_PI; + break; + case PANGO2_GRAVITY_EAST: + rotation = -G_PI_2; + break; + case PANGO2_GRAVITY_WEST: + rotation = +G_PI_2; + break; + } + + return rotation; +} + +/** + * pango2_gravity_get_for_matrix: + * @matrix: (nullable): a `Pango2Matrix` + * + * Finds the gravity that best matches the rotation component + * in a `Pango2Matrix`. + * + * Return value: the gravity of @matrix, which will never be + * %PANGO2_GRAVITY_AUTO, or %PANGO2_GRAVITY_SOUTH if @matrix is %NULL + */ +Pango2Gravity +pango2_gravity_get_for_matrix (const Pango2Matrix *matrix) +{ + Pango2Gravity gravity; + double x; + double y; + + if (!matrix) + return PANGO2_GRAVITY_SOUTH; + + x = matrix->xy; + y = matrix->yy; + + if (fabs (x) > fabs (y)) + gravity = x > 0 ? PANGO2_GRAVITY_WEST : PANGO2_GRAVITY_EAST; + else + gravity = y < 0 ? PANGO2_GRAVITY_NORTH : PANGO2_GRAVITY_SOUTH; + + return gravity; +} + + + +typedef enum +{ + PANGO2_VERTICAL_DIRECTION_NONE, + PANGO2_VERTICAL_DIRECTION_TTB, + PANGO2_VERTICAL_DIRECTION_BTT +} Pango2VerticalDirection; + +typedef struct { + /* Pango2Direction */ + guint8 horiz_dir; /* Orientation in horizontal context */ + + /* Pango2VerticalDirection */ + guint8 vert_dir; /* Orientation in vertical context */ + + /* Pango2Gravity */ + guint8 preferred_gravity; /* Preferred context gravity */ + + /* gboolean */ + guint8 wide; /* Whether script is mostly wide. + * Wide characters are upright (ie. + * not rotated) in foreign context */ +} Pango2ScriptProperties; + +#define NONE PANGO2_VERTICAL_DIRECTION_NONE +#define TTB PANGO2_VERTICAL_DIRECTION_TTB +#define BTT PANGO2_VERTICAL_DIRECTION_BTT + +#define LTR PANGO2_DIRECTION_LTR +#define RTL PANGO2_DIRECTION_RTL +#define WEAK PANGO2_DIRECTION_WEAK_LTR + +#define S PANGO2_GRAVITY_SOUTH +#define E PANGO2_GRAVITY_EAST +#define W PANGO2_GRAVITY_WEST + +const Pango2ScriptProperties script_properties[] = + { /* ISO 15924 code */ + {LTR, NONE, S, FALSE}, /* Zyyy */ + {LTR, NONE, S, FALSE}, /* Qaai */ + {RTL, NONE, S, FALSE}, /* Arab */ + {LTR, NONE, S, FALSE}, /* Armn */ + {LTR, NONE, S, FALSE}, /* Beng */ + {LTR, TTB, E, TRUE }, /* Bopo */ + {LTR, NONE, S, FALSE}, /* Cher */ + {LTR, NONE, S, FALSE}, /* Qaac */ + {LTR, NONE, S, FALSE}, /* Cyrl (Cyrs) */ + {LTR, NONE, S, FALSE}, /* Dsrt */ + {LTR, NONE, S, FALSE}, /* Deva */ + {LTR, NONE, S, FALSE}, /* Ethi */ + {LTR, NONE, S, FALSE}, /* Geor (Geon, Geoa) */ + {LTR, NONE, S, FALSE}, /* Goth */ + {LTR, NONE, S, FALSE}, /* Grek */ + {LTR, NONE, S, FALSE}, /* Gujr */ + {LTR, NONE, S, FALSE}, /* Guru */ + {LTR, TTB, E, TRUE }, /* Hani */ + {LTR, TTB, E, TRUE }, /* Hang */ + {RTL, NONE, S, FALSE}, /* Hebr */ + {LTR, TTB, E, TRUE }, /* Hira */ + {LTR, NONE, S, FALSE}, /* Knda */ + {LTR, TTB, E, TRUE }, /* Kana */ + {LTR, NONE, S, FALSE}, /* Khmr */ + {LTR, NONE, S, FALSE}, /* Laoo */ + {LTR, NONE, S, FALSE}, /* Latn (Latf, Latg) */ + {LTR, NONE, S, FALSE}, /* Mlym */ + {WEAK,TTB, W, FALSE}, /* Mong */ + {LTR, NONE, S, FALSE}, /* Mymr */ + {LTR, BTT, W, FALSE}, /* Ogam */ + {LTR, NONE, S, FALSE}, /* Ital */ + {LTR, NONE, S, FALSE}, /* Orya */ + {LTR, NONE, S, FALSE}, /* Runr */ + {LTR, NONE, S, FALSE}, /* Sinh */ + {RTL, NONE, S, FALSE}, /* Syrc (Syrj, Syrn, Syre) */ + {LTR, NONE, S, FALSE}, /* Taml */ + {LTR, NONE, S, FALSE}, /* Telu */ + {RTL, NONE, S, FALSE}, /* Thaa */ + {LTR, NONE, S, FALSE}, /* Thai */ + {LTR, NONE, S, FALSE}, /* Tibt */ + {LTR, NONE, S, FALSE}, /* Cans */ + {LTR, TTB, S, TRUE }, /* Yiii */ + {LTR, NONE, S, FALSE}, /* Tglg */ + {LTR, NONE, S, FALSE}, /* Hano */ + {LTR, NONE, S, FALSE}, /* Buhd */ + {LTR, NONE, S, FALSE}, /* Tagb */ + + /* Unicode-4.0 additions */ + {LTR, NONE, S, FALSE}, /* Brai */ + {RTL, NONE, S, FALSE}, /* Cprt */ + {LTR, NONE, S, FALSE}, /* Limb */ + {LTR, NONE, S, FALSE}, /* Osma */ + {LTR, NONE, S, FALSE}, /* Shaw */ + {LTR, NONE, S, FALSE}, /* Linb */ + {LTR, NONE, S, FALSE}, /* Tale */ + {LTR, NONE, S, FALSE}, /* Ugar */ + + /* Unicode-4.1 additions */ + {LTR, NONE, S, FALSE}, /* Talu */ + {LTR, NONE, S, FALSE}, /* Bugi */ + {LTR, NONE, S, FALSE}, /* Glag */ + {LTR, NONE, S, FALSE}, /* Tfng */ + {LTR, NONE, S, FALSE}, /* Sylo */ + {LTR, NONE, S, FALSE}, /* Xpeo */ + {RTL, NONE, S, FALSE}, /* Khar */ + + /* Unicode-5.0 additions */ + {LTR, NONE, S, FALSE}, /* Zzzz */ + {LTR, NONE, S, FALSE}, /* Bali */ + {LTR, NONE, S, FALSE}, /* Xsux */ + {RTL, NONE, S, FALSE}, /* Phnx */ + {LTR, NONE, S, FALSE}, /* Phag */ + {RTL, NONE, S, FALSE}, /* Nkoo */ + + /* Unicode-5.1 additions */ + {LTR, NONE, S, FALSE}, /* Kali */ + {LTR, NONE, S, FALSE}, /* Lepc */ + {LTR, NONE, S, FALSE}, /* Rjng */ + {LTR, NONE, S, FALSE}, /* Sund */ + {LTR, NONE, S, FALSE}, /* Saur */ + {LTR, NONE, S, FALSE}, /* Cham */ + {LTR, NONE, S, FALSE}, /* Olck */ + {LTR, NONE, S, FALSE}, /* Vaii */ + {LTR, NONE, S, FALSE}, /* Cari */ + {LTR, NONE, S, FALSE}, /* Lyci */ + {RTL, NONE, S, FALSE}, /* Lydi */ + + /* Unicode-5.2 additions */ + {RTL, NONE, S, FALSE}, /* Avst */ + {LTR, NONE, S, FALSE}, /* Bamu */ + {LTR, NONE, S, FALSE}, /* Egyp */ + {RTL, NONE, S, FALSE}, /* Armi */ + {RTL, NONE, S, FALSE}, /* Phli */ + {RTL, NONE, S, FALSE}, /* Prti */ + {LTR, NONE, S, FALSE}, /* Java */ + {LTR, NONE, S, FALSE}, /* Kthi */ + {LTR, NONE, S, FALSE}, /* Lisu */ + {LTR, NONE, S, FALSE}, /* Mtei */ + {RTL, NONE, S, FALSE}, /* Sarb */ + {RTL, NONE, S, FALSE}, /* Orkh */ + {RTL, TTB, S, FALSE}, /* Samr */ + {LTR, NONE, S, FALSE}, /* Lana */ + {LTR, NONE, S, FALSE}, /* Tavt */ + + /* Unicode-6.0 additions */ + {LTR, NONE, S, FALSE}, /* Batk */ + {LTR, NONE, S, FALSE}, /* Brah */ + {RTL, NONE, S, FALSE}, /* Mand */ + + /* Unicode-6.1 additions */ + {LTR, NONE, S, FALSE}, /* Cakm */ + {RTL, NONE, S, FALSE}, /* Merc */ + {RTL, NONE, S, FALSE}, /* Mero */ + {LTR, NONE, S, FALSE}, /* Plrd */ + {LTR, NONE, S, FALSE}, /* Shrd */ + {LTR, NONE, S, FALSE}, /* Sora */ + {LTR, NONE, S, FALSE}, /* Takr */ + + /* Unicode-7.0 additions */ + {LTR, NONE, S, FALSE}, /* Bass */ + {LTR, NONE, S, FALSE}, /* Aghb */ + {LTR, NONE, S, FALSE}, /* Dupl */ + {LTR, NONE, S, FALSE}, /* Elba */ + {LTR, NONE, S, FALSE}, /* Gran */ + {LTR, NONE, S, FALSE}, /* Khoj */ + {LTR, NONE, S, FALSE}, /* Sind */ + {LTR, NONE, S, FALSE}, /* Lina */ + {LTR, NONE, S, FALSE}, /* Mahj */ + {RTL, NONE, S, FALSE}, /* Mani */ + {RTL, NONE, S, FALSE}, /* Mend */ + {LTR, NONE, S, FALSE}, /* Modi */ + {LTR, NONE, S, FALSE}, /* Mroo */ + {RTL, NONE, S, FALSE}, /* Nbat */ + {RTL, NONE, S, FALSE}, /* Narb */ + {LTR, NONE, S, FALSE}, /* Perm */ + {LTR, NONE, S, FALSE}, /* Hmng */ + {RTL, NONE, S, FALSE}, /* Palm */ + {LTR, NONE, S, FALSE}, /* Pauc */ + {RTL, NONE, S, FALSE}, /* Phlp */ + {LTR, NONE, S, FALSE}, /* Sidd */ + {LTR, NONE, S, FALSE}, /* Tirh */ + {LTR, NONE, S, FALSE}, /* Wara */ + + /* Unicode-8.0 additions */ + {LTR, NONE, S, FALSE}, /* Ahom */ + {LTR, NONE, S, FALSE}, /* Hluw */ + {RTL, NONE, S, FALSE}, /* Hatr */ + {LTR, NONE, S, FALSE}, /* Mult */ + {LTR, NONE, S, FALSE}, /* Hung */ + {LTR, NONE, S, FALSE}, /* Sgnw */ + + /* Unicode-9.0 additions */ + {RTL, NONE, S, FALSE}, /* Adlm */ + {LTR, NONE, S, FALSE}, /* Bhks */ + {LTR, NONE, S, FALSE}, /* Marc */ + {LTR, NONE, S, FALSE}, /* Newa */ + {LTR, NONE, S, FALSE}, /* Osge */ + {LTR, NONE, S, FALSE}, /* Tang */ + + /* Unicode-10.0 additions */ + {LTR, NONE, S, FALSE}, /* Gonm */ + {LTR, NONE, S, FALSE}, /* Nshu */ + {LTR, NONE, S, FALSE}, /* Soyo */ + {LTR, NONE, S, FALSE}, /* Zanb */ + + /* Unicode-11.0 additions */ + {LTR, NONE, S, FALSE}, /* Dogr */ + {LTR, NONE, S, FALSE}, /* Gong */ + {RTL, NONE, S, FALSE}, /* Rohg */ + {LTR, NONE, S, FALSE}, /* Maka */ + {LTR, NONE, S, FALSE}, /* Medf */ + {RTL, NONE, S, FALSE}, /* Sogo */ + {RTL, NONE, S, FALSE}, /* Sogd */ + + /* Unicode-12.0 additions */ + {RTL, NONE, S, FALSE}, /* Elym */ + {LTR, NONE, S, FALSE}, /* Nand */ + {LTR, NONE, S, FALSE}, /* Rohg */ + {LTR, NONE, S, FALSE}, /* Wcho */ + + /* Unicode-13.0 additions */ + {RTL, NONE, S, FALSE}, /* Chrs */ + {LTR, NONE, S, FALSE}, /* Diak */ + {LTR, NONE, S, FALSE}, /* Kits */ + {RTL, NONE, S, FALSE}, /* Yezi */ + + {LTR, NONE, S, FALSE}, /* Cpmn */ + {RTL, NONE, S, FALSE}, /* Ougr */ + {LTR, NONE, S, FALSE}, /* Tnsa */ + {LTR, NONE, S, FALSE}, /* Toto */ + {LTR, NONE, S, FALSE}, /* Vith */ +}; + +#undef NONE +#undef TTB +#undef BTT + +#undef LTR +#undef RTL +#undef WEAK + +#undef S +#undef E +#undef N +#undef W + +static Pango2ScriptProperties +get_script_properties (GUnicodeScript script) +{ + g_return_val_if_fail (script >= 0, script_properties[0]); + + if ((guint)script >= G_N_ELEMENTS (script_properties)) + return script_properties[0]; + + return script_properties[script]; +} + +/** + * pango2_gravity_get_for_script: + * @script: `Pango2Script` to query + * @base_gravity: base gravity of the paragraph + * @hint: orientation hint + * + * Returns the gravity to use in laying out a `Pango2Item`. + * + * The gravity is determined based on the script, base gravity, and hint. + * + * If @base_gravity is %PANGO2_GRAVITY_AUTO, it is first replaced with the + * preferred gravity of @script. To get the preferred gravity of a script, + * pass %PANGO2_GRAVITY_AUTO and %PANGO2_GRAVITY_HINT_STRONG in. + * + * Return value: resolved gravity suitable to use for a run of text + * with @script + */ +Pango2Gravity +pango2_gravity_get_for_script (GUnicodeScript script, + Pango2Gravity base_gravity, + Pango2GravityHint hint) +{ + Pango2ScriptProperties props = get_script_properties (script); + + return pango2_gravity_get_for_script_and_width (script, props.wide, + base_gravity, hint); +} + +/** + * pango2_gravity_get_for_script_and_width: + * @script: `Pango2Script` to query + * @wide: %TRUE for wide characters as returned by g_unichar_iswide() + * @base_gravity: base gravity of the paragraph + * @hint: orientation hint + * + * Returns the gravity to use in laying out a single character + * or `Pango2Item`. + * + * The gravity is determined based on the script, East Asian width, + * base gravity, and hint, + * + * This function is similar to [func@Pango2.Gravity.get_for_script] except + * that this function makes a distinction between narrow/half-width and + * wide/full-width characters also. Wide/full-width characters always + * stand *upright*, that is, they always take the base gravity, + * whereas narrow/full-width characters are always rotated in vertical + * context. + * + * If @base_gravity is %PANGO2_GRAVITY_AUTO, it is first replaced with the + * preferred gravity of @script. + * + * Return value: resolved gravity suitable to use for a run of text + * with @script and @wide. + */ +Pango2Gravity +pango2_gravity_get_for_script_and_width (GUnicodeScript script, + gboolean wide, + Pango2Gravity base_gravity, + Pango2GravityHint hint) +{ + Pango2ScriptProperties props = get_script_properties (script); + gboolean vertical; + + if (G_UNLIKELY (base_gravity == PANGO2_GRAVITY_AUTO)) + base_gravity = props.preferred_gravity; + + vertical = PANGO2_GRAVITY_IS_VERTICAL (base_gravity); + + /* Everything is designed such that a system with no vertical support + * renders everything correctly horizontally. So, if not in a vertical + * gravity, base and resolved gravities are always the same. + * + * Wide characters are always upright. + */ + if (G_LIKELY (!vertical || wide)) + return base_gravity; + + /* If here, we have a narrow character in a vertical gravity setting. + * Resolve depending on the hint. + */ + switch (hint) + { + default: + case PANGO2_GRAVITY_HINT_NATURAL: + if (props.vert_dir == PANGO2_VERTICAL_DIRECTION_NONE) + return PANGO2_GRAVITY_SOUTH; + if ((base_gravity == PANGO2_GRAVITY_EAST) ^ + (props.vert_dir == PANGO2_VERTICAL_DIRECTION_BTT)) + return PANGO2_GRAVITY_SOUTH; + else + return PANGO2_GRAVITY_NORTH; + + case PANGO2_GRAVITY_HINT_STRONG: + return base_gravity; + + case PANGO2_GRAVITY_HINT_LINE: + if ((base_gravity == PANGO2_GRAVITY_EAST) ^ + (props.horiz_dir == PANGO2_DIRECTION_RTL)) + return PANGO2_GRAVITY_SOUTH; + else + return PANGO2_GRAVITY_NORTH; + } +} |