Coverage Report

Created: 2023-06-07 07:05

/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
 */