1/* FriBidi
2 * fribidi-joining.h - Arabic joining algorithm
3 *
4 * Authors:
5 * Behdad Esfahbod, 2004
6 *
7 * Copyright (C) 2004 Sharif FarsiWeb, Inc
8 * Copyright (C) 2004 Behdad Esfahbod
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library, in a file named COPYING; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA
24 *
25 * For licensing issues, contact <fribidi.license@gmail.com>.
26 */
27
28#include "common.h"
29
30#include <fribidi-joining.h>
31
32#include "bidi-types.h"
33#include "joining-types.h"
34
35#ifdef DEBUG
36/*======================================================================
37 * For debugging, define some functions for printing joining types and
38 * properties.
39 *----------------------------------------------------------------------*/
40
41static void
42print_joining_types (
43 /* input */
44 const FriBidiLevel *embedding_levels,
45 const FriBidiStrIndex len,
46 const FriBidiJoiningType *jtypes
47)
48{
49 register FriBidiStrIndex i;
50
51 fribidi_assert (jtypes);
52
53 MSG (" Join. types: ");
54 for (i = 0; i < len; i++)
55 MSG2 ("%c", fribidi_char_from_joining_type (jtypes[i],
56 !FRIBIDI_LEVEL_IS_RTL
57 (embedding_levels[i])));
58 MSG ("\n");
59}
60#endif /* DEBUG */
61
62#define FRIBIDI_CONSISTENT_LEVEL(i) \
63 (FRIBIDI_IS_EXPLICIT_OR_BN (bidi_types[(i)]) \
64 ? FRIBIDI_SENTINEL \
65 : embedding_levels[(i)])
66
67#define FRIBIDI_LEVELS_MATCH(i, j) \
68 ((i) == (j) || (i) == FRIBIDI_SENTINEL || (j) == FRIBIDI_SENTINEL)
69
70FRIBIDI_ENTRY void
71fribidi_join_arabic (
72 /* input */
73 const FriBidiCharType *bidi_types,
74 const FriBidiStrIndex len,
75 const FriBidiLevel *embedding_levels,
76 /* input and output */
77 FriBidiArabicProp *ar_props
78)
79{
80 if UNLIKELY
81 (len == 0) return;
82
83 DBG ("in fribidi_join_arabic");
84
85 fribidi_assert (bidi_types);
86 fribidi_assert (embedding_levels);
87 fribidi_assert (ar_props);
88
89# if DEBUG
90 if UNLIKELY
91 (fribidi_debug_status ())
92 {
93 print_joining_types (embedding_levels, len, jtypes: ar_props);
94 }
95# endif /* DEBUG */
96
97 /* The joining algorithm turned out very very dirty :(. That's what happens
98 * when you follow the standard which has never been implemented closely
99 * before.
100 */
101
102 /* 8.2 Arabic - Cursive Joining */
103 DBG ("Arabic cursive joining");
104 {
105 /* The following do not need to be initialized as long as joins is
106 * initialized to false. We just do to turn off compiler warnings. */
107 register FriBidiStrIndex saved = 0;
108 register FriBidiLevel saved_level = FRIBIDI_SENTINEL;
109 register fribidi_boolean saved_shapes = false;
110 register FriBidiArabicProp saved_joins_following_mask = 0;
111
112 register fribidi_boolean joins = false;
113 register FriBidiStrIndex i;
114
115 for (i = 0; i < len; i++)
116 if (!FRIBIDI_IS_JOINING_TYPE_G (ar_props[i]))
117 {
118 register fribidi_boolean disjoin = false;
119 register fribidi_boolean shapes = FRIBIDI_ARAB_SHAPES (ar_props[i]);
120 register FriBidiLevel level = FRIBIDI_CONSISTENT_LEVEL (i);
121
122 if (joins && !FRIBIDI_LEVELS_MATCH (saved_level, level))
123 {
124 disjoin = true;
125 joins = false;
126 }
127
128 if (!FRIBIDI_IS_JOIN_SKIPPED (ar_props[i]))
129 {
130 register const FriBidiArabicProp joins_preceding_mask =
131 FRIBIDI_JOINS_PRECEDING_MASK (level);
132
133 if (!joins)
134 {
135 if (shapes)
136 FRIBIDI_UNSET_BITS (ar_props[i], joins_preceding_mask);
137 }
138 else if (!FRIBIDI_TEST_BITS (ar_props[i], joins_preceding_mask))
139 {
140 disjoin = true;
141 }
142 else
143 {
144 register FriBidiStrIndex j;
145 /* This is a FriBidi extension: we set joining properties
146 * for skipped characters in between, so we can put NSMs on tatweel
147 * later if we want. Useful on console for example.
148 */
149 for (j = saved + 1; j < i; j++)
150 FRIBIDI_SET_BITS (ar_props[j], joins_preceding_mask | saved_joins_following_mask);
151 }
152 }
153
154 if (disjoin && saved_shapes)
155 FRIBIDI_UNSET_BITS (ar_props[saved], saved_joins_following_mask);
156
157 if (!FRIBIDI_IS_JOIN_SKIPPED (ar_props[i]))
158 {
159 saved = i;
160 saved_level = level;
161 saved_shapes = shapes;
162 saved_joins_following_mask =
163 FRIBIDI_JOINS_FOLLOWING_MASK (level);
164 joins =
165 FRIBIDI_TEST_BITS (ar_props[i], saved_joins_following_mask);
166 }
167 }
168 if ((joins) && saved_shapes)
169 FRIBIDI_UNSET_BITS (ar_props[saved], saved_joins_following_mask);
170
171 }
172
173# if DEBUG
174 if UNLIKELY
175 (fribidi_debug_status ())
176 {
177 print_joining_types (embedding_levels, len, jtypes: ar_props);
178 }
179# endif /* DEBUG */
180
181 DBG ("leaving fribidi_join_arabic");
182}
183
184/* Editor directions:
185 * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
186 */
187

source code of gtk/subprojects/fribidi/lib/fribidi-joining.c