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 | |
41 | static void |
42 | print_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 | |
70 | FRIBIDI_ENTRY void |
71 | fribidi_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 | |