/src/fribidi/lib/fribidi-joining.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
49 | 0 | register FriBidiStrIndex i; |
50 | |
|
51 | 0 | fribidi_assert (jtypes); |
52 | |
|
53 | 0 | MSG (" Join. types: "); |
54 | 0 | for (i = 0; i < len; i++) |
55 | 0 | MSG2 ("%c", fribidi_char_from_joining_type (jtypes[i], |
56 | 0 | !FRIBIDI_LEVEL_IS_RTL |
57 | 0 | (embedding_levels[i]))); |
58 | 0 | MSG ("\n"); |
59 | 0 | } |
60 | | #endif /* DEBUG */ |
61 | | |
62 | | #define FRIBIDI_CONSISTENT_LEVEL(i) \ |
63 | 0 | (FRIBIDI_IS_EXPLICIT_OR_BN (bidi_types[(i)]) \ |
64 | 0 | ? FRIBIDI_SENTINEL \ |
65 | 0 | : embedding_levels[(i)]) |
66 | | |
67 | | #define FRIBIDI_LEVELS_MATCH(i, j) \ |
68 | 0 | ((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 | 0 | { |
80 | 0 | if UNLIKELY |
81 | 0 | (len == 0) return; |
82 | | |
83 | 0 | DBG ("in fribidi_join_arabic"); |
84 | |
|
85 | 0 | fribidi_assert (bidi_types); |
86 | 0 | fribidi_assert (embedding_levels); |
87 | 0 | fribidi_assert (ar_props); |
88 | |
|
89 | 0 | # if DEBUG |
90 | 0 | if UNLIKELY |
91 | 0 | (fribidi_debug_status ()) |
92 | 0 | { |
93 | 0 | print_joining_types (embedding_levels, len, ar_props); |
94 | 0 | } |
95 | 0 | # 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 | 0 | DBG ("Arabic cursive joining"); |
104 | 0 | { |
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 | 0 | register FriBidiStrIndex saved = 0; |
108 | 0 | register FriBidiLevel saved_level = FRIBIDI_SENTINEL; |
109 | 0 | register fribidi_boolean saved_shapes = false; |
110 | 0 | register FriBidiArabicProp saved_joins_following_mask = 0; |
111 | |
|
112 | 0 | register fribidi_boolean joins = false; |
113 | 0 | register FriBidiStrIndex i; |
114 | |
|
115 | 0 | for (i = 0; i < len; i++) |
116 | 0 | if (!FRIBIDI_IS_JOINING_TYPE_G (ar_props[i])) |
117 | 0 | { |
118 | 0 | register fribidi_boolean disjoin = false; |
119 | 0 | register fribidi_boolean shapes = FRIBIDI_ARAB_SHAPES (ar_props[i]); |
120 | 0 | register FriBidiLevel level = FRIBIDI_CONSISTENT_LEVEL (i); |
121 | |
|
122 | 0 | if (joins && !FRIBIDI_LEVELS_MATCH (saved_level, level)) |
123 | 0 | { |
124 | 0 | disjoin = true; |
125 | 0 | joins = false; |
126 | 0 | } |
127 | |
|
128 | 0 | if (!FRIBIDI_IS_JOIN_SKIPPED (ar_props[i])) |
129 | 0 | { |
130 | 0 | register const FriBidiArabicProp joins_preceding_mask = |
131 | 0 | FRIBIDI_JOINS_PRECEDING_MASK (level); |
132 | |
|
133 | 0 | if (!joins) |
134 | 0 | { |
135 | 0 | if (shapes) |
136 | 0 | FRIBIDI_UNSET_BITS (ar_props[i], joins_preceding_mask); |
137 | 0 | } |
138 | 0 | else if (!FRIBIDI_TEST_BITS (ar_props[i], joins_preceding_mask)) |
139 | 0 | { |
140 | 0 | disjoin = true; |
141 | 0 | } |
142 | 0 | else |
143 | 0 | { |
144 | 0 | 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 | 0 | for (j = saved + 1; j < i; j++) |
150 | 0 | FRIBIDI_SET_BITS (ar_props[j], joins_preceding_mask | saved_joins_following_mask); |
151 | 0 | } |
152 | 0 | } |
153 | |
|
154 | 0 | if (disjoin && saved_shapes) |
155 | 0 | FRIBIDI_UNSET_BITS (ar_props[saved], saved_joins_following_mask); |
156 | |
|
157 | 0 | if (!FRIBIDI_IS_JOIN_SKIPPED (ar_props[i])) |
158 | 0 | { |
159 | 0 | saved = i; |
160 | 0 | saved_level = level; |
161 | 0 | saved_shapes = shapes; |
162 | 0 | saved_joins_following_mask = |
163 | 0 | FRIBIDI_JOINS_FOLLOWING_MASK (level); |
164 | 0 | joins = |
165 | 0 | FRIBIDI_TEST_BITS (ar_props[i], saved_joins_following_mask); |
166 | 0 | } |
167 | 0 | } |
168 | 0 | if ((joins) && saved_shapes) |
169 | 0 | FRIBIDI_UNSET_BITS (ar_props[saved], saved_joins_following_mask); |
170 | |
|
171 | 0 | } |
172 | |
|
173 | 0 | # if DEBUG |
174 | 0 | if UNLIKELY |
175 | 0 | (fribidi_debug_status ()) |
176 | 0 | { |
177 | 0 | print_joining_types (embedding_levels, len, ar_props); |
178 | 0 | } |
179 | 0 | # endif /* DEBUG */ |
180 | |
|
181 | 0 | DBG ("leaving fribidi_join_arabic"); |
182 | 0 | } |
183 | | |
184 | | /* Editor directions: |
185 | | * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent |
186 | | */ |