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