Upload tizen 2.0 beta source
[external/pango1.0.git] / pango / pango-utils.c
1 /* Pango
2  * pango-utils.c: Utilities for internal functions and modules
3  *
4  * Copyright (C) 2000 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 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include <locale.h>
28
29 #include "pango-font.h"
30 #include "pango-features.h"
31 #include "pango-impl-utils.h"
32
33 #include <glib/gstdio.h>
34
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 */
40
41 #ifdef G_OS_WIN32
42
43 #include <sys/types.h>
44
45 #define STRICT
46 #include <windows.h>
47
48 #endif
49
50 struct PangoAlias
51 {
52   char *alias;
53   int n_families;
54   char **families;
55   gboolean visible; /* Do we want/need this? */
56 };
57
58 static GHashTable *pango_aliases_ht = NULL;
59
60 /**
61  * pango_version:
62  *
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.
66  *
67  * A version number can be encoded into an integer using
68  * PANGO_VERSION_ENCODE().
69  *
70  * Returns: The encoded version of Pango library
71  *   available at run time.
72  *
73  * Since: 1.16
74  **/
75 int
76 pango_version (void)
77 {
78   return PANGO_VERSION;
79 }
80
81 /**
82  * pango_version_string:
83  *
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.
87  *
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
91  *   or freed.
92  *
93  * Since: 1.16
94  **/
95 const char *
96 pango_version_string (void)
97 {
98   return PANGO_VERSION_STRING;
99 }
100
101 /**
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.
106  *
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.
113  *
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.)
120  *
121  * For compile-time version checking use PANGO_VERSION_CHECK().
122  *
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
126  *   or freed.
127  *
128  * Since: 1.16
129  **/
130 const gchar*
131 pango_version_check (int required_major,
132                      int required_minor,
133                      int required_micro)
134 {
135   gint pango_effective_micro = 100 * PANGO_VERSION_MINOR + PANGO_VERSION_MICRO;
136   gint required_effective_micro = 100 * required_minor + required_micro;
137
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)";
144   return NULL;
145 }
146
147 /**
148  * pango_trim_string:
149  * @str: a string
150  *
151  * Trims leading and trailing whitespace from a string.
152  *
153  * Return value: A newly-allocated string that must be freed with g_free()
154  **/
155 char *
156 pango_trim_string (const char *str)
157 {
158   int len;
159
160   g_return_val_if_fail (str != NULL, NULL);
161
162   while (*str && g_ascii_isspace (*str))
163     str++;
164
165   len = strlen (str);
166   while (len > 0 && g_ascii_isspace (str[len-1]))
167     len--;
168
169   return g_strndup (str, len);
170 }
171
172 /**
173  * pango_split_file_list:
174  * @str: a %G_SEARCHPATH_SEPARATOR separated list of filenames
175  *
176  * Splits a %G_SEARCHPATH_SEPARATOR-separated list of files, stripping
177  * white space and substituting ~/ with $HOME/.
178  *
179  * Return value: a list of strings to be freed with g_strfreev()
180  **/
181 char **
182 pango_split_file_list (const char *str)
183 {
184   int i = 0;
185   int j;
186   char **files;
187
188   files = g_strsplit (str, G_SEARCHPATH_SEPARATOR_S, -1);
189
190   while (files[i])
191     {
192       char *file = pango_trim_string (files[i]);
193
194       /* If the resulting file is empty, skip it */
195       if (file[0] == '\0')
196         {
197           g_free(file);
198           g_free (files[i]);
199
200           for (j = i + 1; files[j]; j++)
201             files[j - 1] = files[j];
202
203           files[j - 1] = NULL;
204
205           continue;
206         }
207 #ifndef G_OS_WIN32
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.
213        */
214       if (file[0] == '~' && file[1] == G_DIR_SEPARATOR)
215         {
216           char *tmp = g_strconcat (g_get_home_dir(), file + 1, NULL);
217           g_free (file);
218           file = tmp;
219         }
220       else if (file[0] == '~' && file[1] == '\0')
221         {
222           g_free (file);
223           file = g_strdup (g_get_home_dir());
224         }
225 #endif
226       g_free (files[i]);
227       files[i] = file;
228
229       i++;
230     }
231
232   return files;
233 }
234
235 /**
236  * pango_read_line:
237  * @stream: a stdio stream
238  * @str: #GString buffer into which to write the result
239  *
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
246  * unmodified.
247  *
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 '\')
251  **/
252 gint
253 pango_read_line (FILE *stream, GString *str)
254 {
255   gboolean quoted = FALSE;
256   gboolean comment = FALSE;
257   int n_read = 0;
258   int lines = 1;
259
260   flockfile (stream);
261
262   g_string_truncate (str, 0);
263
264   while (1)
265     {
266       int c;
267
268       c = getc_unlocked (stream);
269
270       if (c == EOF)
271         {
272           if (quoted)
273             g_string_append_c (str, '\\');
274
275           goto done;
276         }
277       else
278         n_read++;
279
280       if (quoted)
281         {
282           quoted = FALSE;
283
284           switch (c)
285             {
286             case '#':
287               g_string_append_c (str, '#');
288               break;
289             case '\r':
290             case '\n':
291               {
292                 int next_c = getc_unlocked (stream);
293
294                 if (!(next_c == EOF ||
295                       (c == '\r' && next_c == '\n') ||
296                       (c == '\n' && next_c == '\r')))
297                   ungetc (next_c, stream);
298
299                 lines++;
300
301                 break;
302               }
303             default:
304               g_string_append_c (str, '\\');
305               g_string_append_c (str, c);
306             }
307         }
308       else
309         {
310           switch (c)
311             {
312             case '#':
313               comment = TRUE;
314               break;
315             case '\\':
316               if (!comment)
317                 quoted = TRUE;
318               break;
319             case '\n':
320               {
321                 int next_c = getc_unlocked (stream);
322
323                 if (!(c == EOF ||
324                       (c == '\r' && next_c == '\n') ||
325                       (c == '\n' && next_c == '\r')))
326                   ungetc (next_c, stream);
327
328                 goto done;
329               }
330             default:
331               if (!comment)
332                 g_string_append_c (str, c);
333             }
334         }
335     }
336
337  done:
338
339   funlockfile (stream);
340
341   return (n_read > 0) ? lines : 0;
342 }
343
344 /**
345  * pango_skip_space:
346  * @pos: in/out string position
347  *
348  * Skips 0 or more characters of white space.
349  *
350  * Return value: %FALSE if skipping the white space leaves
351  * the position at a '\0' character.
352  **/
353 gboolean
354 pango_skip_space (const char **pos)
355 {
356   const char *p = *pos;
357
358   while (g_ascii_isspace (*p))
359     p++;
360
361   *pos = p;
362
363   return !(*p == '\0');
364 }
365
366 /**
367  * pango_scan_word:
368  * @pos: in/out string position
369  * @out: a #GString into which to write the result
370  *
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.
374  *
375  * Return value: %FALSE if a parse error occurred.
376  **/
377 gboolean
378 pango_scan_word (const char **pos, GString *out)
379 {
380   const char *p = *pos;
381
382   while (g_ascii_isspace (*p))
383     p++;
384
385   if (!((*p >= 'A' && *p <= 'Z') ||
386         (*p >= 'a' && *p <= 'z') ||
387         *p == '_'))
388     return FALSE;
389
390   g_string_truncate (out, 0);
391   g_string_append_c (out, *p);
392   p++;
393
394   while ((*p >= 'A' && *p <= 'Z') ||
395          (*p >= 'a' && *p <= 'z') ||
396          (*p >= '0' && *p <= '9') ||
397          *p == '_')
398     {
399       g_string_append_c (out, *p);
400       p++;
401     }
402
403   *pos = p;
404
405   return TRUE;
406 }
407
408 /**
409  * pango_scan_string:
410  * @pos: in/out string position
411  * @out: a #GString into which to write the result
412  *
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.
417  *
418  * Return value: %FALSE if a parse error occurred.
419  **/
420 gboolean
421 pango_scan_string (const char **pos, GString *out)
422 {
423   const char *p = *pos;
424
425   while (g_ascii_isspace (*p))
426     p++;
427
428   if (G_UNLIKELY (!*p))
429     return FALSE;
430   else if (*p == '"')
431     {
432       gboolean quoted = FALSE;
433       g_string_truncate (out, 0);
434
435       p++;
436
437       while (TRUE)
438         {
439           if (quoted)
440             {
441               int c = *p;
442
443               switch (c)
444                 {
445                 case '\0':
446                   return FALSE;
447                 case 'n':
448                   c = '\n';
449                   break;
450                 case 't':
451                   c = '\t';
452                   break;
453                 default:
454                   break;
455                 }
456
457               quoted = FALSE;
458               g_string_append_c (out, c);
459             }
460           else
461             {
462               switch (*p)
463                 {
464                 case '\0':
465                   return FALSE;
466                 case '\\':
467                   quoted = TRUE;
468                   break;
469                 case '"':
470                   p++;
471                   goto done;
472                 default:
473                   g_string_append_c (out, *p);
474                   break;
475                 }
476             }
477           p++;
478         }
479     done:
480       ;
481     }
482   else
483     {
484       g_string_truncate (out, 0);
485
486       while (*p && !g_ascii_isspace (*p))
487         {
488           g_string_append_c (out, *p);
489           p++;
490         }
491     }
492
493   *pos = p;
494
495   return TRUE;
496 }
497
498 /**
499  * pango_scan_int:
500  * @pos: in/out string position
501  * @out: an int into which to write the result
502  *
503  * Scans an integer.
504  * Leading white space is skipped.
505  *
506  * Return value: %FALSE if a parse error occurred.
507  **/
508 gboolean
509 pango_scan_int (const char **pos, int *out)
510 {
511   char *end;
512   long temp;
513
514   errno = 0;
515   temp = strtol (*pos, &end, 10);
516   if (errno == ERANGE)
517     {
518       errno = 0;
519       return FALSE;
520     }
521
522   *out = (int)temp;
523   if ((long)(*out) != temp)
524     {
525       return FALSE;
526     }
527
528   *pos = end;
529
530   return TRUE;
531 }
532
533 static GHashTable *config_hash = NULL;
534
535 static void
536 read_config_file (const char *filename, gboolean enoent_error)
537 {
538   GKeyFile *key_file = g_key_file_new();
539   GError *key_file_error = NULL;
540   gchar **groups;
541   gsize groups_count = 0;
542   guint group_index;
543
544   if (!g_key_file_load_from_file(key_file,filename, 0, &key_file_error))
545     {
546       if (key_file_error)
547         {
548           if (key_file_error->domain != G_FILE_ERROR || key_file_error->code != G_FILE_ERROR_NOENT || enoent_error)
549             {
550               g_warning ("error opening config file '%s': %s\n",
551                           filename, key_file_error->message);
552             }
553           g_error_free(key_file_error);
554         }
555       g_key_file_free(key_file);
556       return;
557     }
558
559   groups = g_key_file_get_groups (key_file, &groups_count);
560   for (group_index = 0; group_index < groups_count; group_index++)
561     {
562       gsize keys_count = 0;
563       const gchar *group = groups[group_index];
564       GError *keys_error = NULL;
565       gchar **keys;
566
567       keys = g_key_file_get_keys(key_file, group, &keys_count, &keys_error);
568
569       if (keys)
570         {
571           guint key_index;
572
573           for (key_index = 0; key_index < keys_count; key_index++)
574             {
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);
578               if (value != NULL)
579                 {
580                   g_hash_table_insert (config_hash,
581                                        g_strdup_printf ("%s/%s", group, key),
582                                        value);
583                 }
584               if (key_error)
585                 {
586                   g_warning ("error getting key '%s/%s' in config file '%s'\n",
587                              group, key, filename);
588                   g_error_free(key_error);
589                 }
590             }
591           g_strfreev(keys);
592         }
593
594       if (keys_error)
595         {
596           g_warning ("error getting keys in group '%s' of config file '%s'\n",
597                      filename, group);
598           g_error_free(keys_error);
599         }
600     }
601   g_strfreev(groups);
602   g_key_file_free(key_file);
603 }
604
605 static void
606 read_config (void)
607 {
608   if (!config_hash)
609     {
610       char *filename;
611       const char *home;
612       const char *envvar;
613
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 (),
618                                    "pangorc",
619                                    NULL);
620       read_config_file (filename, FALSE);
621       g_free (filename);
622
623       home = g_get_home_dir ();
624       if (home && *home)
625         {
626           filename = g_build_filename (home, ".pangorc", NULL);
627           read_config_file (filename, FALSE);
628           g_free (filename);
629         }
630
631       envvar = g_getenv ("PANGO_RC_FILE");
632       if (envvar)
633         read_config_file (envvar, TRUE);
634     }
635 }
636
637 /**
638  * pango_config_key_get:
639  * @key: Key to look up, in the form "SECTION/KEY".
640  *
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).)
644  *
645  * Return value: the value, if found, otherwise %NULL. The value is a
646  * newly-allocated string and must be freed with g_free().
647  **/
648 char *
649 pango_config_key_get (const char *key)
650 {
651   g_return_val_if_fail (key != NULL, NULL);
652
653   read_config ();
654
655   return g_strdup (g_hash_table_lookup (config_hash, key));
656 }
657
658 #ifdef G_OS_WIN32
659
660 /* DllMain function needed to tuck away the DLL handle */
661
662 static HMODULE pango_dll;
663
664 BOOL WINAPI
665 DllMain (HINSTANCE hinstDLL,
666          DWORD     fdwReason,
667          LPVOID    lpvReserved)
668 {
669   switch (fdwReason)
670     {
671     case DLL_PROCESS_ATTACH:
672       pango_dll = (HMODULE) hinstDLL;
673       break;
674     }
675
676   return TRUE;
677 }
678
679 #endif
680
681 /**
682  * pango_get_sysconf_subdirectory:
683  *
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).
688  *
689  * Return value: the Pango sysconf directory. The returned string should
690  * not be freed.
691  */
692 G_CONST_RETURN char *
693 pango_get_sysconf_subdirectory (void)
694 {
695 #ifdef G_OS_WIN32
696   static gchar *result = NULL;
697
698   if (result == NULL)
699     {
700       gchar *root = g_win32_get_package_installation_directory_of_module (pango_dll);
701       result = g_build_filename (root, "etc\\pango", NULL);
702       g_free (root);
703     }
704   return result;
705 #else
706   return SYSCONFDIR "/pango";
707 #endif
708 }
709
710 /**
711  * pango_get_lib_subdirectory:
712  *
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).
717  *
718  * Return value: the Pango lib directory. The returned string should
719  * not be freed.
720  */
721 G_CONST_RETURN char *
722 pango_get_lib_subdirectory (void)
723 {
724 #ifdef G_OS_WIN32
725   static gchar *result = NULL;
726
727   if (result == NULL)
728     {
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.
732        */
733       if (g_str_has_suffix (root, "\\.libs"))
734         result = g_strdup (LIBDIR "/pango");
735       else
736         result = g_build_filename (root, "lib\\pango", NULL);
737       g_free (root);
738     }
739   return result;
740 #else
741   return LIBDIR "/pango";
742 #endif
743 }
744
745
746 static gboolean
747 parse_int (const char *word,
748            int        *out)
749 {
750   char *end;
751   long val = strtol (word, &end, 10);
752   int i = val;
753
754   if (end != word && *end == '\0' && val >= 0 && val == i)
755     {
756       if (out)
757         *out = i;
758
759       return TRUE;
760     }
761
762   return FALSE;
763 }
764
765 /**
766  * pango_parse_enum:
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.
772  *
773  * Parses an enum type and stores the result in @value.
774  *
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().
782  *
783  * Return value: %TRUE if @str was successfully parsed.
784  *
785  * Since: 1.16
786  **/
787 gboolean
788 pango_parse_enum (GType       type,
789                   const char *str,
790                   int        *value,
791                   gboolean    warn,
792                   char      **possible_values)
793 {
794   GEnumClass *class = NULL;
795   gboolean ret = TRUE;
796   GEnumValue *v = NULL;
797
798   class = g_type_class_ref (type);
799
800   if (G_LIKELY (str))
801     v = g_enum_get_value_by_nick (class, str);
802
803   if (v)
804     {
805       if (G_LIKELY (value))
806         *value = v->value;
807     }
808   else if (!parse_int (str, value))
809     {
810       ret = FALSE;
811       if (G_LIKELY (warn || possible_values))
812         {
813           int i;
814           GString *s = g_string_new (NULL);
815
816           for (i = 0, v = g_enum_get_value (class, i); v;
817                i++  , v = g_enum_get_value (class, i))
818             {
819               if (i)
820                 g_string_append_c (s, '/');
821               g_string_append (s, v->value_nick);
822             }
823
824           if (warn)
825             g_warning ("%s must be one of %s",
826                        G_ENUM_CLASS_TYPE_NAME(class),
827                        s->str);
828
829           if (possible_values)
830             *possible_values = s->str;
831
832           g_string_free (s, possible_values ? FALSE : TRUE);
833         }
834     }
835
836   g_type_class_unref (class);
837
838   return ret;
839 }
840
841
842 static guint
843 alias_hash (struct PangoAlias *alias)
844 {
845   return g_str_hash (alias->alias);
846 }
847
848 static gboolean
849 alias_equal (struct PangoAlias *alias1,
850              struct PangoAlias *alias2)
851 {
852   return g_str_equal (alias1->alias,
853                       alias2->alias);
854 }
855
856
857 static void
858 alias_free (struct PangoAlias *alias)
859 {
860   int i;
861   g_free (alias->alias);
862
863   for (i = 0; i < alias->n_families; i++)
864     g_free (alias->families[i]);
865
866   g_free (alias->families);
867
868   g_slice_free (struct PangoAlias, alias);
869 }
870
871 static void
872 handle_alias_line (GString  *line_buffer,
873                    char    **errstring)
874 {
875   GString *tmp_buffer1;
876   GString *tmp_buffer2;
877   const char *pos;
878   struct PangoAlias alias_key;
879   struct PangoAlias *alias;
880   gboolean append = FALSE;
881   char **new_families;
882   int n_new;
883   int i;
884
885   tmp_buffer1 = g_string_new (NULL);
886   tmp_buffer2 = g_string_new (NULL);
887
888
889   pos = line_buffer->str;
890   if (!pango_skip_space (&pos))
891     return;
892
893   if (!pango_scan_string (&pos, tmp_buffer1) ||
894       !pango_skip_space (&pos))
895     {
896       *errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
897       goto error;
898     }
899
900   if (*pos == '+')
901     {
902       append = TRUE;
903       pos++;
904     }
905
906   if (*(pos++) != '=')
907     {
908       *errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
909       goto error;
910     }
911
912   if (!pango_scan_string (&pos, tmp_buffer2))
913     {
914       *errstring = g_strdup ("Error parsing value string");
915       goto error;
916     }
917   if (pango_skip_space (&pos))
918     {
919       *errstring = g_strdup ("Junk after value string");
920       goto error;
921     }
922
923   alias_key.alias = g_ascii_strdown (tmp_buffer1->str, -1);
924
925   /* Remove any existing values */
926   alias = g_hash_table_lookup (pango_aliases_ht, &alias_key);
927
928   if (!alias)
929     {
930       alias = g_slice_new0 (struct PangoAlias);
931       alias->alias = alias_key.alias;
932       
933       g_hash_table_insert (pango_aliases_ht,
934                            alias, alias);
935     }
936   else
937     g_free (alias_key.alias);
938
939   new_families = g_strsplit (tmp_buffer2->str, ",", -1);
940
941   n_new = 0;
942   while (new_families[n_new])
943     n_new++;
944
945   if (alias->families && append)
946     {
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;
953     }
954   else
955     {
956       for (i = 0; i < alias->n_families; i++)
957         g_free (alias->families[i]);
958       g_free (alias->families);
959       
960       alias->families = new_families;
961       alias->n_families = n_new;
962     }
963
964  error:
965   
966   g_string_free (tmp_buffer1, TRUE);
967   g_string_free (tmp_buffer2, TRUE);
968 }
969
970 #ifdef HAVE_CAIRO_WIN32
971
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.
982    */
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\""
988 };
989
990 static void
991 read_builtin_aliases (void)
992 {
993
994   GString *line_buffer;
995   char *errstring = NULL;
996   int line;
997
998   line_buffer = g_string_new (NULL);
999
1000   for (line = 0; line < G_N_ELEMENTS (builtin_aliases) && errstring == NULL; line++)
1001     {
1002       g_string_assign (line_buffer, builtin_aliases[line]);
1003       handle_alias_line (line_buffer, &errstring);
1004     }
1005
1006   if (errstring)
1007     {
1008       g_error ("error in built-in aliases:%d: %s\n", line, errstring);
1009       g_free (errstring);
1010     }
1011
1012   g_string_free (line_buffer, TRUE);
1013 }
1014
1015 #endif
1016
1017 static void
1018 read_alias_file (const char *filename)
1019 {
1020   FILE *file;
1021
1022   GString *line_buffer;
1023   char *errstring = NULL;
1024   int line = 0;
1025
1026   file = g_fopen (filename, "r");
1027   if (!file)
1028     return;
1029
1030   line_buffer = g_string_new (NULL);
1031
1032   while (pango_read_line (file, line_buffer) &&
1033          errstring == NULL)
1034     {
1035       line++;
1036       handle_alias_line (line_buffer, &errstring);
1037     }
1038
1039   if (errstring == NULL && ferror (file))
1040     errstring = g_strdup (g_strerror(errno));
1041
1042   if (errstring)
1043     {
1044       g_warning ("error reading alias file: %s:%d: %s\n", filename, line, errstring);
1045       g_free (errstring);
1046     }
1047
1048   g_string_free (line_buffer, TRUE);
1049
1050   fclose (file);
1051 }
1052
1053 static void
1054 pango_load_aliases (void)
1055 {
1056   char *filename;
1057   const char *home;
1058
1059   pango_aliases_ht = g_hash_table_new_full ((GHashFunc)alias_hash,
1060                                             (GEqualFunc)alias_equal,
1061                                             (GDestroyNotify)alias_free,
1062                                             NULL);
1063
1064 #ifdef HAVE_CAIRO_WIN32
1065   read_builtin_aliases ();
1066 #endif
1067
1068   filename = g_strconcat (pango_get_sysconf_subdirectory (),
1069                           G_DIR_SEPARATOR_S "pango.aliases",
1070                           NULL);
1071   read_alias_file (filename);
1072   g_free (filename);
1073
1074   home = g_get_home_dir ();
1075   if (home && *home)
1076     {
1077       filename = g_strconcat (home,
1078                               G_DIR_SEPARATOR_S ".pango.aliases",
1079                               NULL);
1080       read_alias_file (filename);
1081       g_free (filename);
1082     }
1083 }
1084
1085
1086 /**
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.
1092  *
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.
1096  **/
1097 void
1098 pango_lookup_aliases (const char   *fontname,
1099                       char       ***families,
1100                       int          *n_families)
1101 {
1102   struct PangoAlias alias_key;
1103   struct PangoAlias *alias;
1104
1105   if (pango_aliases_ht == NULL)
1106     pango_load_aliases ();
1107
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);
1111
1112   if (alias)
1113     {
1114       *families = alias->families;
1115       *n_families = alias->n_families;
1116     }
1117   else
1118     {
1119       *families = NULL;
1120       *n_families = 0;
1121     }
1122 }
1123
1124 /**
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)
1128  *
1129  * Searches a string the first character that has a strong
1130  * direction, according to the Unicode bidirectional algorithm.
1131  *
1132  * Return value: The direction corresponding to the first strong character.
1133  * If no such character is found, then %PANGO_DIRECTION_NEUTRAL is returned.
1134  *
1135  * Since: 1.4
1136  */
1137 PangoDirection
1138 pango_find_base_dir (const gchar *text,
1139                      gint         length)
1140 {
1141   PangoDirection dir = PANGO_DIRECTION_NEUTRAL;
1142   const gchar *p;
1143
1144   g_return_val_if_fail (text != NULL || length == 0, PANGO_DIRECTION_NEUTRAL);
1145
1146   p = text;
1147   while ((length < 0 || p < text + length) && *p)
1148     {
1149       gunichar wc = g_utf8_get_char (p);
1150
1151       dir = pango_unichar_direction (wc);
1152
1153       if (dir != PANGO_DIRECTION_NEUTRAL)
1154         break;
1155
1156       p = g_utf8_next_char (p);
1157     }
1158
1159   return dir;
1160 }
1161
1162 /**
1163  * pango_is_zero_width:
1164  * @ch: a Unicode character
1165  *
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.
1171  *
1172  * Return value: %TRUE if @ch is a zero-width character, %FALSE otherwise
1173  *
1174  * Since: 1.10
1175  */
1176 gboolean
1177 pango_is_zero_width (gunichar ch)
1178 {
1179 /* Zero Width characters:
1180  *
1181  *  00AD  SOFT HYPHEN
1182  *  034F  COMBINING GRAPHEME JOINER
1183  *
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
1189  *
1190  *  2028  LINE SEPARATOR
1191  *
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
1197  *
1198  *  2060  WORD JOINER
1199  *  2061  FUNCTION APPLICATION
1200  *  2062  INVISIBLE TIMES
1201  *  2063  INVISIBLE SEPARATOR
1202  *
1203  *  FEFF  ZERO WIDTH NO-BREAK SPACE
1204  */
1205   return ((ch & ~(gunichar)0x007F) == 0x2000 && (
1206                 (ch >= 0x200B && ch <= 0x200F) ||
1207                 (ch >= 0x202A && ch <= 0x202E) ||
1208                 (ch >= 0x2060 && ch <= 0x2063) ||
1209                 (ch == 0x2028)
1210          )) || G_UNLIKELY (ch == 0x00AD
1211                         || ch == 0x034F
1212                         || ch == 0xFEFF);
1213 }
1214
1215 /**
1216  * pango_quantize_line_geometry:
1217  * @thickness: pointer to the thickness of a line, in Pango units
1218  * @position: corresponding position
1219  *
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.
1224  *
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
1227  * of rounding.
1228  *
1229  * Since: 1.12
1230  */
1231 void
1232 pango_quantize_line_geometry (int *thickness,
1233                               int *position)
1234 {
1235   int thickness_pixels = (*thickness + PANGO_SCALE / 2) / PANGO_SCALE;
1236   if (thickness_pixels == 0)
1237     thickness_pixels = 1;
1238
1239   if (thickness_pixels & 1)
1240     {
1241       int new_center = ((*position - *thickness / 2) & ~(PANGO_SCALE - 1)) + PANGO_SCALE / 2;
1242       *position = new_center + (PANGO_SCALE * thickness_pixels) / 2;
1243     }
1244   else
1245     {
1246       int new_center = ((*position - *thickness / 2 + PANGO_SCALE / 2) & ~(PANGO_SCALE - 1));
1247       *position = new_center + (PANGO_SCALE * thickness_pixels) / 2;
1248     }
1249
1250   *thickness = thickness_pixels * PANGO_SCALE;
1251 }
1252
1253 /**
1254  * pango_units_from_double:
1255  * @d: double floating-point value
1256  *
1257  * Converts a floating-point number to Pango units: multiplies
1258  * it by %PANGO_SCALE and rounds to nearest integer.
1259  *
1260  * Return value: the value in Pango units.
1261  *
1262  * Since: 1.16
1263  */
1264 int
1265 pango_units_from_double (double d)
1266 {
1267   return (int)floor (d * PANGO_SCALE + 0.5);
1268 }
1269
1270 /**
1271  * pango_units_to_double:
1272  * @i: value in Pango units
1273  *
1274  * Converts a number in Pango units to floating-point: divides
1275  * it by %PANGO_SCALE.
1276  *
1277  * Return value: the double value.
1278  *
1279  * Since: 1.16
1280  */
1281 double
1282 pango_units_to_double (int i)
1283 {
1284   return (double)i / PANGO_SCALE;
1285 }
1286
1287 /**
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.
1291  *
1292  * Converts extents from Pango units to device units, dividing by the
1293  * %PANGO_SCALE factor and performing rounding.
1294  *
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
1297  * rectangle.
1298  *
1299  * The @nearest rectangle is converted by rounding the coordinates
1300  * of the rectangle to the nearest device unit (pixel).
1301  *
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
1306  * as @nearest.
1307  *
1308  * Since: 1.16
1309  **/
1310 void
1311 pango_extents_to_pixels (PangoRectangle *inclusive,
1312                          PangoRectangle *nearest)
1313 {
1314   if (inclusive)
1315     {
1316       int orig_x = inclusive->x;
1317       int orig_y = inclusive->y;
1318
1319       inclusive->x = PANGO_PIXELS_FLOOR (inclusive->x);
1320       inclusive->y = PANGO_PIXELS_FLOOR (inclusive->y);
1321
1322       inclusive->width  = PANGO_PIXELS_CEIL (orig_x + inclusive->width ) - inclusive->x;
1323       inclusive->height = PANGO_PIXELS_CEIL (orig_y + inclusive->height) - inclusive->y;
1324     }
1325
1326   if (nearest)
1327     {
1328       int orig_x = nearest->x;
1329       int orig_y = nearest->y;
1330
1331       nearest->x = PANGO_PIXELS (nearest->x);
1332       nearest->y = PANGO_PIXELS (nearest->y);
1333
1334       nearest->width  = PANGO_PIXELS (orig_x + nearest->width ) - nearest->x;
1335       nearest->height = PANGO_PIXELS (orig_y + nearest->height) - nearest->y;
1336     }
1337 }
1338
1339
1340
1341
1342 \f
1343 /*********************************************************
1344  * Some internal functions for handling PANGO_ATTR_SHAPE *
1345  ********************************************************/
1346
1347 void
1348 _pango_shape_shape (const char       *text,
1349                     gint              n_chars,
1350                     PangoRectangle   *shape_ink G_GNUC_UNUSED,
1351                     PangoRectangle   *shape_logical,
1352                     PangoGlyphString *glyphs)
1353 {
1354   int i;
1355   const char *p;
1356
1357   pango_glyph_string_set_size (glyphs, n_chars);
1358
1359   for (i=0, p = text; i < n_chars; i++, p = g_utf8_next_char (p))
1360     {
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;
1366
1367       glyphs->log_clusters[i] = p - text;
1368     }
1369 }
1370
1371 void
1372 _pango_shape_get_extents (gint              n_chars,
1373                           PangoRectangle   *shape_ink,
1374                           PangoRectangle   *shape_logical,
1375                           PangoRectangle   *ink_rect,
1376                           PangoRectangle   *logical_rect)
1377 {
1378   if (n_chars > 0)
1379     {
1380       if (ink_rect)
1381         {
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;
1386         }
1387       if (logical_rect)
1388         {
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;
1393         }
1394     }
1395   else
1396     {
1397       if (ink_rect)
1398         {
1399           ink_rect->x = 0;
1400           ink_rect->y = 0;
1401           ink_rect->width = 0;
1402           ink_rect->height = 0;
1403         }
1404
1405       if (logical_rect)
1406         {
1407           logical_rect->x = 0;
1408           logical_rect->y = 0;
1409           logical_rect->width = 0;
1410           logical_rect->height = 0;
1411         }
1412     }
1413 }
1414