2 * pango-utils.c: Utilities for internal functions and modules
4 * Copyright (C) 2000 Red Hat Software
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.
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.
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.
29 #include "pango-font.h"
30 #include "pango-features.h"
31 #include "pango-impl-utils.h"
33 #include <glib/gstdio.h>
35 #ifndef HAVE_FLOCKFILE
36 # define flockfile(f) (void)1
37 # define funlockfile(f) (void)1
38 # define getc_unlocked(f) getc(f)
39 #endif /* !HAVE_FLOCKFILE */
43 #include <sys/types.h>
55 gboolean visible; /* Do we want/need this? */
58 static GHashTable *pango_aliases_ht = NULL;
63 * This is similar to the macro %PANGO_VERSION except that
64 * it returns the encoded version of Pango available at run-time,
65 * as opposed to the version available at compile-time.
67 * A version number can be encoded into an integer using
68 * PANGO_VERSION_ENCODE().
70 * Returns: The encoded version of Pango library
71 * available at run time.
82 * pango_version_string:
84 * This is similar to the macro %PANGO_VERSION_STRING except that
85 * it returns the version of Pango available at run-time, as opposed to
86 * the version available at compile-time.
88 * Returns: A string containing the version of Pango library
89 * available at run time.
90 * The returned string is owned by Pango and should not be modified
96 pango_version_string (void)
98 return PANGO_VERSION_STRING;
102 * pango_version_check:
103 * @required_major: the required major version.
104 * @required_minor: the required minor version.
105 * @required_micro: the required major version.
107 * Checks that the Pango library in use is compatible with the
108 * given version. Generally you would pass in the constants
109 * %PANGO_VERSION_MAJOR, %PANGO_VERSION_MINOR, %PANGO_VERSION_MICRO
110 * as the three arguments to this function; that produces
111 * a check that the library in use at run-time is compatible with
112 * the version of Pango the application or module was compiled against.
114 * Compatibility is defined by two things: first the version
115 * of the running library is newer than the version
116 * @required_major.required_minor.@required_micro. Second
117 * the running library must be binary compatible with the
118 * version @required_major.required_minor.@required_micro
119 * (same major version.)
121 * For compile-time version checking use PANGO_VERSION_CHECK().
123 * Return value: %NULL if the Pango library is compatible with the
124 * given version, or a string describing the version mismatch.
125 * The returned string is owned by Pango and should not be modified
131 pango_version_check (int required_major,
135 gint pango_effective_micro = 100 * PANGO_VERSION_MINOR + PANGO_VERSION_MICRO;
136 gint required_effective_micro = 100 * required_minor + required_micro;
138 if (required_major < PANGO_VERSION_MAJOR)
139 return "Pango version too new (major mismatch)";
140 if (required_effective_micro < pango_effective_micro - PANGO_BINARY_AGE)
141 return "Pango version too new (micro mismatch)";
142 if (required_effective_micro > pango_effective_micro)
143 return "Pango version too old (micro mismatch)";
151 * Trims leading and trailing whitespace from a string.
153 * Return value: A newly-allocated string that must be freed with g_free()
156 pango_trim_string (const char *str)
160 g_return_val_if_fail (str != NULL, NULL);
162 while (*str && g_ascii_isspace (*str))
166 while (len > 0 && g_ascii_isspace (str[len-1]))
169 return g_strndup (str, len);
173 * pango_split_file_list:
174 * @str: a %G_SEARCHPATH_SEPARATOR separated list of filenames
176 * Splits a %G_SEARCHPATH_SEPARATOR-separated list of files, stripping
177 * white space and substituting ~/ with $HOME/.
179 * Return value: a list of strings to be freed with g_strfreev()
182 pango_split_file_list (const char *str)
188 files = g_strsplit (str, G_SEARCHPATH_SEPARATOR_S, -1);
192 char *file = pango_trim_string (files[i]);
194 /* If the resulting file is empty, skip it */
200 for (j = i + 1; files[j]; j++)
201 files[j - 1] = files[j];
208 /* '~' is a quite normal and common character in file names on
209 * Windows, especially in the 8.3 versions of long file names, which
210 * still occur now and then. Also, few Windows user are aware of the
211 * Unix shell convention that '~' stands for the home directory,
212 * even if they happen to have a home directory.
214 if (file[0] == '~' && file[1] == G_DIR_SEPARATOR)
216 char *tmp = g_strconcat (g_get_home_dir(), file + 1, NULL);
220 else if (file[0] == '~' && file[1] == '\0')
223 file = g_strdup (g_get_home_dir());
237 * @stream: a stdio stream
238 * @str: #GString buffer into which to write the result
240 * Reads an entire line from a file into a buffer. Lines may
241 * be delimited with '\n', '\r', '\n\r', or '\r\n'. The delimiter
242 * is not written into the buffer. Text after a '#' character is treated as
243 * a comment and skipped. '\' can be used to escape a # character.
244 * '\' proceeding a line delimiter combines adjacent lines. A '\' proceeding
245 * any other character is ignored and written into the output buffer
248 * Return value: 0 if the stream was already at an %EOF character, otherwise
249 * the number of lines read (this is useful for maintaining
250 * a line number counter which doesn't combine lines with '\')
253 pango_read_line (FILE *stream, GString *str)
255 gboolean quoted = FALSE;
256 gboolean comment = FALSE;
262 g_string_truncate (str, 0);
268 c = getc_unlocked (stream);
273 g_string_append_c (str, '\\');
287 g_string_append_c (str, '#');
292 int next_c = getc_unlocked (stream);
294 if (!(next_c == EOF ||
295 (c == '\r' && next_c == '\n') ||
296 (c == '\n' && next_c == '\r')))
297 ungetc (next_c, stream);
304 g_string_append_c (str, '\\');
305 g_string_append_c (str, c);
321 int next_c = getc_unlocked (stream);
324 (c == '\r' && next_c == '\n') ||
325 (c == '\n' && next_c == '\r')))
326 ungetc (next_c, stream);
332 g_string_append_c (str, c);
339 funlockfile (stream);
341 return (n_read > 0) ? lines : 0;
346 * @pos: in/out string position
348 * Skips 0 or more characters of white space.
350 * Return value: %FALSE if skipping the white space leaves
351 * the position at a '\0' character.
354 pango_skip_space (const char **pos)
356 const char *p = *pos;
358 while (g_ascii_isspace (*p))
363 return !(*p == '\0');
368 * @pos: in/out string position
369 * @out: a #GString into which to write the result
371 * Scans a word into a #GString buffer. A word consists
372 * of [A-Za-z_] followed by zero or more [A-Za-z_0-9]
373 * Leading white space is skipped.
375 * Return value: %FALSE if a parse error occurred.
378 pango_scan_word (const char **pos, GString *out)
380 const char *p = *pos;
382 while (g_ascii_isspace (*p))
385 if (!((*p >= 'A' && *p <= 'Z') ||
386 (*p >= 'a' && *p <= 'z') ||
390 g_string_truncate (out, 0);
391 g_string_append_c (out, *p);
394 while ((*p >= 'A' && *p <= 'Z') ||
395 (*p >= 'a' && *p <= 'z') ||
396 (*p >= '0' && *p <= '9') ||
399 g_string_append_c (out, *p);
410 * @pos: in/out string position
411 * @out: a #GString into which to write the result
413 * Scans a string into a #GString buffer. The string may either
414 * be a sequence of non-white-space characters, or a quoted
415 * string with '"'. Instead a quoted string, '\"' represents
416 * a literal quote. Leading white space outside of quotes is skipped.
418 * Return value: %FALSE if a parse error occurred.
421 pango_scan_string (const char **pos, GString *out)
423 const char *p = *pos;
425 while (g_ascii_isspace (*p))
428 if (G_UNLIKELY (!*p))
432 gboolean quoted = FALSE;
433 g_string_truncate (out, 0);
458 g_string_append_c (out, c);
473 g_string_append_c (out, *p);
484 g_string_truncate (out, 0);
486 while (*p && !g_ascii_isspace (*p))
488 g_string_append_c (out, *p);
500 * @pos: in/out string position
501 * @out: an int into which to write the result
504 * Leading white space is skipped.
506 * Return value: %FALSE if a parse error occurred.
509 pango_scan_int (const char **pos, int *out)
515 temp = strtol (*pos, &end, 10);
523 if ((long)(*out) != temp)
533 static GHashTable *config_hash = NULL;
536 read_config_file (const char *filename, gboolean enoent_error)
538 GKeyFile *key_file = g_key_file_new();
539 GError *key_file_error = NULL;
541 gsize groups_count = 0;
544 if (!g_key_file_load_from_file(key_file,filename, 0, &key_file_error))
548 if (key_file_error->domain != G_FILE_ERROR || key_file_error->code != G_FILE_ERROR_NOENT || enoent_error)
550 g_warning ("error opening config file '%s': %s\n",
551 filename, key_file_error->message);
553 g_error_free(key_file_error);
555 g_key_file_free(key_file);
559 groups = g_key_file_get_groups (key_file, &groups_count);
560 for (group_index = 0; group_index < groups_count; group_index++)
562 gsize keys_count = 0;
563 const gchar *group = groups[group_index];
564 GError *keys_error = NULL;
567 keys = g_key_file_get_keys(key_file, group, &keys_count, &keys_error);
573 for (key_index = 0; key_index < keys_count; key_index++)
575 const gchar *key = keys[key_index];
576 GError *key_error = NULL;
577 gchar *value = g_key_file_get_value(key_file, group, key, &key_error);
580 g_hash_table_insert (config_hash,
581 g_strdup_printf ("%s/%s", group, key),
586 g_warning ("error getting key '%s/%s' in config file '%s'\n",
587 group, key, filename);
588 g_error_free(key_error);
596 g_warning ("error getting keys in group '%s' of config file '%s'\n",
598 g_error_free(keys_error);
602 g_key_file_free(key_file);
614 config_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
615 (GDestroyNotify)g_free,
616 (GDestroyNotify)g_free);
617 filename = g_build_filename (pango_get_sysconf_subdirectory (),
620 read_config_file (filename, FALSE);
623 home = g_get_home_dir ();
626 filename = g_build_filename (home, ".pangorc", NULL);
627 read_config_file (filename, FALSE);
631 envvar = g_getenv ("PANGO_RC_FILE");
633 read_config_file (envvar, TRUE);
638 * pango_config_key_get:
639 * @key: Key to look up, in the form "SECTION/KEY".
641 * Looks up a key in the Pango config database
642 * (pseudo-win.ini style, read from $sysconfdir/pango/pangorc,
643 * ~/.pangorc, and getenv (PANGO_RC_FILE).)
645 * Return value: the value, if found, otherwise %NULL. The value is a
646 * newly-allocated string and must be freed with g_free().
649 pango_config_key_get (const char *key)
651 g_return_val_if_fail (key != NULL, NULL);
655 return g_strdup (g_hash_table_lookup (config_hash, key));
660 /* DllMain function needed to tuck away the DLL handle */
662 static HMODULE pango_dll;
665 DllMain (HINSTANCE hinstDLL,
671 case DLL_PROCESS_ATTACH:
672 pango_dll = (HMODULE) hinstDLL;
682 * pango_get_sysconf_subdirectory:
684 * On Unix, returns the name of the "pango" subdirectory of SYSCONFDIR
685 * (which is set at compile time). On Windows, returns the etc\pango
686 * subdirectory of the Pango installation directory (which is deduced
687 * at run time from the DLL's location).
689 * Return value: the Pango sysconf directory. The returned string should
692 G_CONST_RETURN char *
693 pango_get_sysconf_subdirectory (void)
696 static gchar *result = NULL;
700 gchar *root = g_win32_get_package_installation_directory_of_module (pango_dll);
701 result = g_build_filename (root, "etc\\pango", NULL);
706 return SYSCONFDIR "/pango";
711 * pango_get_lib_subdirectory:
713 * On Unix, returns the name of the "pango" subdirectory of LIBDIR
714 * (which is set at compile time). On Windows, returns the lib\pango
715 * subdirectory of the Pango installation directory (which is deduced
716 * at run time from the DLL's location).
718 * Return value: the Pango lib directory. The returned string should
721 G_CONST_RETURN char *
722 pango_get_lib_subdirectory (void)
725 static gchar *result = NULL;
729 gchar *root = g_win32_get_package_installation_directory_of_module (pango_dll);
730 /* If we are running against an uninstalled copy of the Pango DLL,
731 * use the compile-time installation prefix.
733 if (g_str_has_suffix (root, "\\.libs"))
734 result = g_strdup (LIBDIR "/pango");
736 result = g_build_filename (root, "lib\\pango", NULL);
741 return LIBDIR "/pango";
747 parse_int (const char *word,
751 long val = strtol (word, &end, 10);
754 if (end != word && *end == '\0' && val >= 0 && val == i)
767 * @type: enum type to parse, eg. %PANGO_TYPE_ELLIPSIZE_MODE.
768 * @str: string to parse. May be %NULL.
769 * @value: integer to store the result in, or %NULL.
770 * @warn: if %TRUE, issue a g_warning() on bad input.
771 * @possible_values: place to store list of possible values on failure, or %NULL.
773 * Parses an enum type and stores the result in @value.
775 * If @str does not match the nick name of any of the possible values for the
776 * enum and is not an integer, %FALSE is returned, a warning is issued
777 * if @warn is %TRUE, and a
778 * string representing the list of possible values is stored in
779 * @possible_values. The list is slash-separated, eg.
780 * "none/start/middle/end". If failed and @possible_values is not %NULL,
781 * returned string should be freed using g_free().
783 * Return value: %TRUE if @str was successfully parsed.
788 pango_parse_enum (GType type,
792 char **possible_values)
794 GEnumClass *class = NULL;
796 GEnumValue *v = NULL;
798 class = g_type_class_ref (type);
801 v = g_enum_get_value_by_nick (class, str);
805 if (G_LIKELY (value))
808 else if (!parse_int (str, value))
811 if (G_LIKELY (warn || possible_values))
814 GString *s = g_string_new (NULL);
816 for (i = 0, v = g_enum_get_value (class, i); v;
817 i++ , v = g_enum_get_value (class, i))
820 g_string_append_c (s, '/');
821 g_string_append (s, v->value_nick);
825 g_warning ("%s must be one of %s",
826 G_ENUM_CLASS_TYPE_NAME(class),
830 *possible_values = s->str;
832 g_string_free (s, possible_values ? FALSE : TRUE);
836 g_type_class_unref (class);
843 alias_hash (struct PangoAlias *alias)
845 return g_str_hash (alias->alias);
849 alias_equal (struct PangoAlias *alias1,
850 struct PangoAlias *alias2)
852 return g_str_equal (alias1->alias,
858 alias_free (struct PangoAlias *alias)
861 g_free (alias->alias);
863 for (i = 0; i < alias->n_families; i++)
864 g_free (alias->families[i]);
866 g_free (alias->families);
868 g_slice_free (struct PangoAlias, alias);
872 handle_alias_line (GString *line_buffer,
875 GString *tmp_buffer1;
876 GString *tmp_buffer2;
878 struct PangoAlias alias_key;
879 struct PangoAlias *alias;
880 gboolean append = FALSE;
885 tmp_buffer1 = g_string_new (NULL);
886 tmp_buffer2 = g_string_new (NULL);
889 pos = line_buffer->str;
890 if (!pango_skip_space (&pos))
893 if (!pango_scan_string (&pos, tmp_buffer1) ||
894 !pango_skip_space (&pos))
896 *errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
908 *errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
912 if (!pango_scan_string (&pos, tmp_buffer2))
914 *errstring = g_strdup ("Error parsing value string");
917 if (pango_skip_space (&pos))
919 *errstring = g_strdup ("Junk after value string");
923 alias_key.alias = g_ascii_strdown (tmp_buffer1->str, -1);
925 /* Remove any existing values */
926 alias = g_hash_table_lookup (pango_aliases_ht, &alias_key);
930 alias = g_slice_new0 (struct PangoAlias);
931 alias->alias = alias_key.alias;
933 g_hash_table_insert (pango_aliases_ht,
937 g_free (alias_key.alias);
939 new_families = g_strsplit (tmp_buffer2->str, ",", -1);
942 while (new_families[n_new])
945 if (alias->families && append)
947 alias->families = g_realloc (alias->families,
948 sizeof (char *) *(n_new + alias->n_families));
949 for (i = 0; i < n_new; i++)
950 alias->families[alias->n_families + i] = new_families[i];
951 g_free (new_families);
952 alias->n_families += n_new;
956 for (i = 0; i < alias->n_families; i++)
957 g_free (alias->families[i]);
958 g_free (alias->families);
960 alias->families = new_families;
961 alias->n_families = n_new;
966 g_string_free (tmp_buffer1, TRUE);
967 g_string_free (tmp_buffer2, TRUE);
970 #ifdef HAVE_CAIRO_WIN32
972 static const char *builtin_aliases[] = {
973 "courier = \"courier new\"",
974 "\"segoe ui\" = \"segoe ui,meiryo,malgun gothic,microsoft jhenghei,microsoft yahei,gisha,leelawadee,arial unicode ms,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
975 "tahoma = \"tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
976 /* It sucks to use the same GulimChe, MS Gothic, Sylfaen, Kartika,
977 * Latha, Mangal and Raavi fonts for all three of sans, serif and
978 * mono, but it isn't like there would be much choice. For most
979 * non-Latin scripts that Windows includes any font at all for, it
980 * has ony one. One solution is to install the free DejaVu fonts
981 * that are popular on Linux. They are listed here first.
983 "sans = \"dejavu sans,tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
984 "sans-serif = \"dejavu sans,tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
985 "serif = \"dejavu serif,georgia,angsana new,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
986 "mono = \"dejavu sans mono,courier new,lucida console,courier monothai,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
987 "monospace = \"dejavu sans mono,courier new,lucida console,courier monothai,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\""
991 read_builtin_aliases (void)
994 GString *line_buffer;
995 char *errstring = NULL;
998 line_buffer = g_string_new (NULL);
1000 for (line = 0; line < G_N_ELEMENTS (builtin_aliases) && errstring == NULL; line++)
1002 g_string_assign (line_buffer, builtin_aliases[line]);
1003 handle_alias_line (line_buffer, &errstring);
1008 g_error ("error in built-in aliases:%d: %s\n", line, errstring);
1012 g_string_free (line_buffer, TRUE);
1018 read_alias_file (const char *filename)
1022 GString *line_buffer;
1023 char *errstring = NULL;
1026 file = g_fopen (filename, "r");
1030 line_buffer = g_string_new (NULL);
1032 while (pango_read_line (file, line_buffer) &&
1036 handle_alias_line (line_buffer, &errstring);
1039 if (errstring == NULL && ferror (file))
1040 errstring = g_strdup (g_strerror(errno));
1044 g_warning ("error reading alias file: %s:%d: %s\n", filename, line, errstring);
1048 g_string_free (line_buffer, TRUE);
1054 pango_load_aliases (void)
1059 pango_aliases_ht = g_hash_table_new_full ((GHashFunc)alias_hash,
1060 (GEqualFunc)alias_equal,
1061 (GDestroyNotify)alias_free,
1064 #ifdef HAVE_CAIRO_WIN32
1065 read_builtin_aliases ();
1068 filename = g_strconcat (pango_get_sysconf_subdirectory (),
1069 G_DIR_SEPARATOR_S "pango.aliases",
1071 read_alias_file (filename);
1074 home = g_get_home_dir ();
1077 filename = g_strconcat (home,
1078 G_DIR_SEPARATOR_S ".pango.aliases",
1080 read_alias_file (filename);
1087 * pango_lookup_aliases:
1088 * @fontname: an ascii string
1089 * @families: will be set to an array of font family names.
1090 * this array is owned by pango and should not be freed.
1091 * @n_families: will be set to the length of the @families array.
1093 * Look up all user defined aliases for the alias @fontname.
1094 * The resulting font family names will be stored in @families,
1095 * and the number of families in @n_families.
1098 pango_lookup_aliases (const char *fontname,
1102 struct PangoAlias alias_key;
1103 struct PangoAlias *alias;
1105 if (pango_aliases_ht == NULL)
1106 pango_load_aliases ();
1108 alias_key.alias = g_ascii_strdown (fontname, -1);
1109 alias = g_hash_table_lookup (pango_aliases_ht, &alias_key);
1110 g_free (alias_key.alias);
1114 *families = alias->families;
1115 *n_families = alias->n_families;
1125 * pango_find_base_dir:
1126 * @text: the text to process
1127 * @length: length of @text in bytes (may be -1 if @text is nul-terminated)
1129 * Searches a string the first character that has a strong
1130 * direction, according to the Unicode bidirectional algorithm.
1132 * Return value: The direction corresponding to the first strong character.
1133 * If no such character is found, then %PANGO_DIRECTION_NEUTRAL is returned.
1138 pango_find_base_dir (const gchar *text,
1141 PangoDirection dir = PANGO_DIRECTION_NEUTRAL;
1144 g_return_val_if_fail (text != NULL || length == 0, PANGO_DIRECTION_NEUTRAL);
1147 while ((length < 0 || p < text + length) && *p)
1149 gunichar wc = g_utf8_get_char (p);
1151 dir = pango_unichar_direction (wc);
1153 if (dir != PANGO_DIRECTION_NEUTRAL)
1156 p = g_utf8_next_char (p);
1163 * pango_is_zero_width:
1164 * @ch: a Unicode character
1166 * Checks @ch to see if it is a character that should not be
1167 * normally rendered on the screen. This includes all Unicode characters
1168 * with "ZERO WIDTH" in their name, as well as <firstterm>bidi</firstterm> formatting characters, and
1169 * a few other ones. This is totally different from g_unichar_iszerowidth()
1170 * and is at best misnamed.
1172 * Return value: %TRUE if @ch is a zero-width character, %FALSE otherwise
1177 pango_is_zero_width (gunichar ch)
1179 /* Zero Width characters:
1182 * 034F COMBINING GRAPHEME JOINER
1184 * 200B ZERO WIDTH SPACE
1185 * 200C ZERO WIDTH NON-JOINER
1186 * 200D ZERO WIDTH JOINER
1187 * 200E LEFT-TO-RIGHT MARK
1188 * 200F RIGHT-TO-LEFT MARK
1190 * 2028 LINE SEPARATOR
1192 * 202A LEFT-TO-RIGHT EMBEDDING
1193 * 202B RIGHT-TO-LEFT EMBEDDING
1194 * 202C POP DIRECTIONAL FORMATTING
1195 * 202D LEFT-TO-RIGHT OVERRIDE
1196 * 202E RIGHT-TO-LEFT OVERRIDE
1199 * 2061 FUNCTION APPLICATION
1200 * 2062 INVISIBLE TIMES
1201 * 2063 INVISIBLE SEPARATOR
1203 * FEFF ZERO WIDTH NO-BREAK SPACE
1205 return ((ch & ~(gunichar)0x007F) == 0x2000 && (
1206 (ch >= 0x200B && ch <= 0x200F) ||
1207 (ch >= 0x202A && ch <= 0x202E) ||
1208 (ch >= 0x2060 && ch <= 0x2063) ||
1210 )) || G_UNLIKELY (ch == 0x00AD
1216 * pango_quantize_line_geometry:
1217 * @thickness: pointer to the thickness of a line, in Pango units
1218 * @position: corresponding position
1220 * Quantizes the thickness and position of a line, typically an
1221 * underline or strikethrough, to whole device pixels, that is integer
1222 * multiples of %PANGO_SCALE. The purpose of this function is to avoid
1223 * such lines looking blurry.
1225 * Care is taken to make sure @thickness is at least one pixel when this
1226 * function returns, but returned @position may become zero as a result
1232 pango_quantize_line_geometry (int *thickness,
1235 int thickness_pixels = (*thickness + PANGO_SCALE / 2) / PANGO_SCALE;
1236 if (thickness_pixels == 0)
1237 thickness_pixels = 1;
1239 if (thickness_pixels & 1)
1241 int new_center = ((*position - *thickness / 2) & ~(PANGO_SCALE - 1)) + PANGO_SCALE / 2;
1242 *position = new_center + (PANGO_SCALE * thickness_pixels) / 2;
1246 int new_center = ((*position - *thickness / 2 + PANGO_SCALE / 2) & ~(PANGO_SCALE - 1));
1247 *position = new_center + (PANGO_SCALE * thickness_pixels) / 2;
1250 *thickness = thickness_pixels * PANGO_SCALE;
1254 * pango_units_from_double:
1255 * @d: double floating-point value
1257 * Converts a floating-point number to Pango units: multiplies
1258 * it by %PANGO_SCALE and rounds to nearest integer.
1260 * Return value: the value in Pango units.
1265 pango_units_from_double (double d)
1267 return (int)floor (d * PANGO_SCALE + 0.5);
1271 * pango_units_to_double:
1272 * @i: value in Pango units
1274 * Converts a number in Pango units to floating-point: divides
1275 * it by %PANGO_SCALE.
1277 * Return value: the double value.
1282 pango_units_to_double (int i)
1284 return (double)i / PANGO_SCALE;
1288 * pango_extents_to_pixels:
1289 * @inclusive: rectangle to round to pixels inclusively, or %NULL.
1290 * @nearest: rectangle to round to nearest pixels, or %NULL.
1292 * Converts extents from Pango units to device units, dividing by the
1293 * %PANGO_SCALE factor and performing rounding.
1295 * The @inclusive rectangle is converted by flooring the x/y coordinates and extending
1296 * width/height, such that the final rectangle completely includes the original
1299 * The @nearest rectangle is converted by rounding the coordinates
1300 * of the rectangle to the nearest device unit (pixel).
1302 * The rule to which argument to use is: if you want the resulting device-space
1303 * rectangle to completely contain the original rectangle, pass it in as @inclusive.
1304 * If you want two touching-but-not-overlapping rectangles stay
1305 * touching-but-not-overlapping after rounding to device units, pass them in
1311 pango_extents_to_pixels (PangoRectangle *inclusive,
1312 PangoRectangle *nearest)
1316 int orig_x = inclusive->x;
1317 int orig_y = inclusive->y;
1319 inclusive->x = PANGO_PIXELS_FLOOR (inclusive->x);
1320 inclusive->y = PANGO_PIXELS_FLOOR (inclusive->y);
1322 inclusive->width = PANGO_PIXELS_CEIL (orig_x + inclusive->width ) - inclusive->x;
1323 inclusive->height = PANGO_PIXELS_CEIL (orig_y + inclusive->height) - inclusive->y;
1328 int orig_x = nearest->x;
1329 int orig_y = nearest->y;
1331 nearest->x = PANGO_PIXELS (nearest->x);
1332 nearest->y = PANGO_PIXELS (nearest->y);
1334 nearest->width = PANGO_PIXELS (orig_x + nearest->width ) - nearest->x;
1335 nearest->height = PANGO_PIXELS (orig_y + nearest->height) - nearest->y;
1343 /*********************************************************
1344 * Some internal functions for handling PANGO_ATTR_SHAPE *
1345 ********************************************************/
1348 _pango_shape_shape (const char *text,
1350 PangoRectangle *shape_ink G_GNUC_UNUSED,
1351 PangoRectangle *shape_logical,
1352 PangoGlyphString *glyphs)
1357 pango_glyph_string_set_size (glyphs, n_chars);
1359 for (i=0, p = text; i < n_chars; i++, p = g_utf8_next_char (p))
1361 glyphs->glyphs[i].glyph = PANGO_GLYPH_EMPTY;
1362 glyphs->glyphs[i].geometry.x_offset = 0;
1363 glyphs->glyphs[i].geometry.y_offset = 0;
1364 glyphs->glyphs[i].geometry.width = shape_logical->width;
1365 glyphs->glyphs[i].attr.is_cluster_start = 1;
1367 glyphs->log_clusters[i] = p - text;
1372 _pango_shape_get_extents (gint n_chars,
1373 PangoRectangle *shape_ink,
1374 PangoRectangle *shape_logical,
1375 PangoRectangle *ink_rect,
1376 PangoRectangle *logical_rect)
1382 ink_rect->x = MIN (shape_ink->x, shape_ink->x + shape_logical->width * (n_chars - 1));
1383 ink_rect->width = MAX (shape_ink->width, shape_ink->width + shape_logical->width * (n_chars - 1));
1384 ink_rect->y = shape_ink->y;
1385 ink_rect->height = shape_ink->height;
1389 logical_rect->x = MIN (shape_logical->x, shape_logical->x + shape_logical->width * (n_chars - 1));
1390 logical_rect->width = MAX (shape_logical->width, shape_logical->width + shape_logical->width * (n_chars - 1));
1391 logical_rect->y = shape_logical->y;
1392 logical_rect->height = shape_logical->height;
1401 ink_rect->width = 0;
1402 ink_rect->height = 0;
1407 logical_rect->x = 0;
1408 logical_rect->y = 0;
1409 logical_rect->width = 0;
1410 logical_rect->height = 0;