Git init
[external/pango1.0.git] / tests / testiter.c
1 /* Pango
2  * testiter.c: Test pangolayoutiter.c
3  *
4  * Copyright (C) 2005 Amit Aronovitch
5  * Copyright (C) 2005 Red Hat, Inc
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #undef G_DISABLE_ASSERT
24 #undef G_LOG_DOMAIN
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <glib.h>
32
33 #include <pango/pangocairo.h>
34
35 #undef VERBOSE
36
37 static void verbose (const char *format, ...) G_GNUC_PRINTF (1, 2);
38 static void
39 verbose (const char *format, ...)
40 {
41 #ifdef VERBOSE
42   va_list vap;
43
44   va_start (vap, format);
45   vfprintf (stderr, format, vap);
46   va_end (vap);
47 #endif
48 }
49
50 #define LAYOUT_WIDTH (80 * PANGO_SCALE)
51
52 /* Note: The test expects that any newline sequence is of length 1
53  * use \n (not \r\n) in the test texts.
54  * I think the iterator itself should support \r\n without trouble,
55  * but there are comments in layout-iter.c suggesting otherwise.
56  */
57 const char *test_texts[] =
58   {
59     /* English with embedded RTL runs (from ancient-hebrew.org) */
60     "The Hebrew word \xd7\x90\xd7\x93\xd7\x9d\xd7\x94 (adamah) is the feminine form of \xd7\x90\xd7\x93\xd7\x9d meaning \"ground\"\n",
61     /* Arabic, with vowel marks (from Sura Al Fatiha) */
62     "\xd8\xa8\xd9\x90\xd8\xb3\xd9\x92\xd9\x85\xd9\x90 \xd8\xa7\xd9\x84\xd9\x84\xd9\x91\xd9\x87\xd9\x90 \xd8\xa7\xd9\x84\xd8\xb1\xd9\x91\xd9\x8e\xd8\xad\xd9\x92\xd9\x85\xd9\x80\xd9\x8e\xd9\x86\xd9\x90 \xd8\xa7\xd9\x84\xd8\xb1\xd9\x91\xd9\x8e\xd8\xad\xd9\x90\xd9\x8a\xd9\x85\xd9\x90\n\xd8\xa7\xd9\x84\xd9\x92\xd8\xad\xd9\x8e\xd9\x85\xd9\x92\xd8\xaf\xd9\x8f \xd9\x84\xd9\x84\xd9\x91\xd9\x87\xd9\x90 \xd8\xb1\xd9\x8e\xd8\xa8\xd9\x91\xd9\x90 \xd8\xa7\xd9\x84\xd9\x92\xd8\xb9\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8e\xd9\x85\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e\n",
63     /* Arabic, with embedded LTR runs (from a Linux guide) */
64     "\xd8\xa7\xd9\x84\xd9\x85\xd8\xaa\xd8\xba\xd9\x8a\xd8\xb1 LC_ALL \xd9\x8a\xd8\xba\xd9\x8a\xd9\x8a\xd8\xb1 \xd9\x83\xd9\x84 \xd8\xa7\xd9\x84\xd9\x85\xd8\xaa\xd8\xba\xd9\x8a\xd8\xb1\xd8\xa7\xd8\xaa \xd8\xa7\xd9\x84\xd8\xaa\xd9\x8a \xd8\xaa\xd8\xa8\xd8\xaf\xd8\xa3 \xd8\xa8\xd8\xa7\xd9\x84\xd8\xb1\xd9\x85\xd8\xb2 LC.",
65     /* Hebrew, with vowel marks (from Genesis) */
66     "\xd7\x91\xd6\xbc\xd6\xb0\xd7\xa8\xd6\xb5\xd7\x90\xd7\xa9\xd7\x81\xd6\xb4\xd7\x99\xd7\xaa, \xd7\x91\xd6\xbc\xd6\xb8\xd7\xa8\xd6\xb8\xd7\x90 \xd7\x90\xd6\xb1\xd7\x9c\xd6\xb9\xd7\x94\xd6\xb4\xd7\x99\xd7\x9d, \xd7\x90\xd6\xb5\xd7\xaa \xd7\x94\xd6\xb7\xd7\xa9\xd6\xbc\xd7\x81\xd6\xb8\xd7\x9e\xd6\xb7\xd7\x99\xd6\xb4\xd7\x9d, \xd7\x95\xd6\xb0\xd7\x90\xd6\xb5\xd7\xaa \xd7\x94\xd6\xb8\xd7\x90\xd6\xb8\xd7\xa8\xd6\xb6\xd7\xa5",
67     /* Hebrew, with embedded LTR runs (from a Linux guide) */
68     "\xd7\x94\xd7\xa7\xd7\x9c\xd7\x93\xd7\x94 \xd7\xa2\xd7\x9c \xd7\xa9\xd7\xa0\xd7\x99 \xd7\x94 SHIFT\xd7\x99\xd7\x9d (\xd7\x99\xd7\x9e\xd7\x99\xd7\x9f \xd7\x95\xd7\xa9\xd7\x9e\xd7\x90\xd7\x9c \xd7\x91\xd7\x99\xd7\x97\xd7\x93) \xd7\x90\xd7\x9e\xd7\x95\xd7\xa8\xd7\x99\xd7\x9d \xd7\x9c\xd7\x94\xd7\x93\xd7\x9c\xd7\x99\xd7\xa7 \xd7\x90\xd7\xaa \xd7\xa0\xd7\x95\xd7\xa8\xd7\xaa \xd7\x94 Scroll Lock , \xd7\x95\xd7\x9c\xd7\x94\xd7\xa2\xd7\x91\xd7\x99\xd7\xa8 \xd7\x90\xd7\x95\xd7\xaa\xd7\xa0\xd7\x95 \xd7\x9c\xd7\x9e\xd7\xa6\xd7\x91 \xd7\x9b\xd7\xaa\xd7\x99\xd7\x91\xd7\x94 \xd7\x91\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa.",
69     /* Different line terminators */
70     "AAAA\nBBBB\nCCCC\n",
71     "DDDD\rEEEE\rFFFF\r",
72     "GGGG\r\nHHHH\r\nIIII\r\n",
73     NULL
74   };
75
76 static void
77 iter_char_test (PangoLayout *layout)
78 {
79   PangoRectangle   extents, run_extents;
80   PangoLayoutIter *iter;
81   PangoLayoutRun  *run;
82   int              num_chars;
83   int              i, index, offset;
84   int              leading_x, trailing_x, x0, x1;
85   gboolean         iter_next_ok, rtl;
86   const char      *text, *ptr;
87
88   text = pango_layout_get_text (layout);
89   num_chars = g_utf8_strlen (text, -1);
90
91   iter = pango_layout_get_iter (layout);
92   iter_next_ok = TRUE;
93
94   for (i = 0 ; i < num_chars; ++i)
95     {
96       gchar *char_str;
97       g_assert (iter_next_ok);
98
99       index = pango_layout_iter_get_index (iter);
100       ptr = text + index;
101       char_str = g_strndup (ptr, g_utf8_next_char (ptr) - ptr);
102       verbose ("i=%d (visual), index = %d '%s':\n",
103                i, index, char_str);
104       g_free (char_str);
105
106       pango_layout_iter_get_char_extents (iter, &extents);
107       verbose ("  char extents: x=%d,y=%d w=%d,h=%d\n",
108                extents.x, extents.y,
109                extents.width, extents.height);
110
111       run = pango_layout_iter_get_run (iter);
112
113       if (run)
114         {
115           /* Get needed data for the GlyphString */
116           pango_layout_iter_get_run_extents(iter, NULL, &run_extents);
117           offset = run->item->offset;
118           rtl = run->item->analysis.level%2;
119           verbose ("  (current run: offset=%d,x=%d,len=%d,rtl=%d)\n",
120                    offset, run_extents.x, run->item->length, rtl);
121
122           /* Calculate expected x result using index_to_x */
123           pango_glyph_string_index_to_x (run->glyphs,
124                                          (char *)(text + offset), run->item->length,
125                                          &run->item->analysis,
126                                          index - offset, FALSE, &leading_x);
127           pango_glyph_string_index_to_x (run->glyphs,
128                                          (char *)(text + offset), run->item->length,
129                                          &run->item->analysis,
130                                          index - offset, TRUE, &trailing_x);
131
132           x0 = run_extents.x + MIN (leading_x, trailing_x);
133           x1 = run_extents.x + MAX (leading_x, trailing_x);
134
135           verbose ("  (index_to_x ind=%d: expected x=%d, width=%d)\n",
136                    index - offset, x0, x1 - x0);
137
138           g_assert (extents.x == x0);
139           g_assert (extents.width == x1 - x0);
140         }
141       else
142         {
143           /* We're on a line terminator */
144         }
145
146       iter_next_ok = pango_layout_iter_next_char (iter);
147       verbose ("more to go? %d\n", iter_next_ok);
148     }
149
150   /* There should be one character position iterator for each character in the
151    * input string */
152   g_assert (!iter_next_ok);
153
154   pango_layout_iter_free (iter);
155 }
156
157 /* char iteration test:
158  *  - Total num of iterations match number of chars
159  *  - GlyphString's index_to_x positions match those returned by the Iter
160  */
161 static void
162 iter_cluster_test (PangoLayout *layout)
163 {
164   PangoRectangle   extents;
165   PangoLayoutIter *iter;
166   int              index;
167   gboolean         iter_next_ok;
168   const char      *text;
169   PangoLayoutLine *last_line = NULL;
170   int              expected_next_x = 0;
171
172   text = pango_layout_get_text (layout);
173
174   iter = pango_layout_get_iter (layout);
175   iter_next_ok = TRUE;
176
177   while (iter_next_ok)
178     {
179       PangoLayoutLine *line = pango_layout_iter_get_line (iter);
180
181       /* Every cluster is part of a run */
182       g_assert (pango_layout_iter_get_run (iter));
183
184       index = pango_layout_iter_get_index (iter);
185
186       pango_layout_iter_get_cluster_extents (iter, NULL, &extents);
187
188       iter_next_ok = pango_layout_iter_next_cluster (iter);
189
190       verbose ("index = %d:\n", index);
191       verbose ("  cluster extents: x=%d,y=%d w=%d,h=%d\n",
192                extents.x, extents.y,
193                extents.width, extents.height);
194       verbose ("more to go? %d\n", iter_next_ok);
195
196       /* All the clusters on a line should be next to each other and occupy
197        * the entire line. They advance linearly from left to right */
198       g_assert (extents.width >= 0);
199
200       if (last_line == line)
201         g_assert (extents.x == expected_next_x);
202
203       expected_next_x = extents.x + extents.width;
204
205       last_line = line;
206     }
207
208   g_assert (!iter_next_ok);
209
210   pango_layout_iter_free (iter);
211 }
212
213 int
214 main (int argc, char *argv[])
215 {
216   const char  **ptext;
217   PangoFontMap *fontmap;
218   PangoContext *context;
219   PangoLayout  *layout;
220
221   g_setenv ("PANGO_RC_FILE", "./pangorc", TRUE);
222
223   fontmap = pango_cairo_font_map_get_default ();
224   context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
225
226   layout = pango_layout_new (context);
227   pango_layout_set_width (layout, LAYOUT_WIDTH);
228
229   for (ptext = test_texts; *ptext != NULL; ++ptext)
230     {
231       verbose ("--------- checking next text ----------\n");
232       verbose (" <%s>\n", *ptext);
233       verbose ( "len=%ld, bytes=%ld\n",
234                 (long)g_utf8_strlen (*ptext, -1), (long)strlen (*ptext));
235
236       pango_layout_set_text (layout, *ptext, -1);
237       iter_char_test (layout);
238       iter_cluster_test (layout);
239     }
240
241   g_object_unref (layout);
242   return 0;
243 }