Coverage Report

Created: 2025-07-23 06:45

/src/fribidi/lib/fribidi-arabic.c
Line
Count
Source (jump to first uncovered line)
1
/* fribidi-arabic.c - Arabic shaping
2
 *
3
 * Copyright (C) 2005  Behdad Esfahbod
4
 *
5
 * This file is part of GNU FriBidi.
6
 * 
7
 * GNU FriBidi is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public License
9
 * as published by the Free Software Foundation; either version 2.1
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * GNU FriBidi is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with GNU FriBidi; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
 * 
21
 * For licensing issues, contact <fribidi.license@gmail.com> or write to
22
 * Sharif FarsiWeb, Inc., PO Box 13445-389, Tehran, Iran.
23
 *
24
 * Author(s):
25
 *   Behdad Esfahbod, 2005
26
 */
27
28
#include "common.h"
29
30
#ifdef HAVE_CONFIG_H
31
# include <config.h>
32
#endif
33
34
#ifdef HAVE_STDLIB_H
35
# include <stdlib.h>
36
#endif
37
38
39
#include <fribidi-arabic.h>
40
#include <fribidi-unicode.h>
41
42
43
typedef struct _PairMap {
44
  FriBidiChar pair[2], to;
45
} PairMap;
46
47
48
0
#define FRIBIDI_ACCESS_SHAPE_TABLE(table,min,max,x,shape) (table), (min), (max)
49
# define FRIBIDI_ACCESS_SHAPE_TABLE_REAL(table,min,max,x,shape) \
50
0
  (((x)<(min)||(x)>(max))?(x):(table)[(x)-(min)][(shape)])
51
52
#include "arabic-shaping.tab.i"
53
#include "arabic-misc.tab.i"
54
55
56
static void
57
fribidi_shape_arabic_joining (
58
  /* input */
59
  const FriBidiChar table[][4],
60
  FriBidiChar min,
61
  FriBidiChar max,
62
  const FriBidiStrIndex len,
63
  const FriBidiArabicProp *ar_props,
64
  /* input and output */
65
  FriBidiChar *str
66
)
67
0
{
68
0
  register FriBidiStrIndex i;
69
70
0
  for (i = 0; i < len; i++)
71
0
    if (FRIBIDI_ARAB_SHAPES(ar_props[i]))
72
0
      str[i] = FRIBIDI_ACCESS_SHAPE_TABLE_REAL (table, min, max, str[i], FRIBIDI_JOIN_SHAPE (ar_props[i]));
73
0
}
74
75
76
77
static int
78
comp_PairMap (const void *pa, const void *pb)
79
0
{
80
0
  PairMap *a = (PairMap *)pa;
81
0
  PairMap *b = (PairMap *)pb;
82
83
0
  if (a->pair[0] != b->pair[0])
84
0
    return a->pair[0] < b->pair[0] ? -1 : +1;
85
0
  else
86
0
    return a->pair[1] < b->pair[1] ? -1 :
87
0
           a->pair[1] > b->pair[1] ? +1 :
88
0
     0;
89
0
}
90
91
static void *
92
fribidi_bsearch (const void *key, const void *base,
93
                 unsigned int nmemb, unsigned int size,
94
                 int (*compar)(const void *_key, const void *_item))
95
0
{
96
0
  int min = 0, max = (int) nmemb - 1;
97
0
  while (min <= max)
98
0
  {
99
0
    int mid = ((unsigned int) min + (unsigned int) max) / 2;
100
0
    const void *p = (const void *) (((const char *) base) + (mid * size));
101
0
    int c = compar (key, p);
102
0
    if (c < 0)
103
0
      max = mid - 1;
104
0
    else if (c > 0)
105
0
      min = mid + 1;
106
0
    else
107
0
      return (void *) p;
108
0
  }
109
0
  return NULL;
110
0
}
111
112
static FriBidiChar
113
find_pair_match (const PairMap *table, int size, FriBidiChar first, FriBidiChar second)
114
0
{
115
0
  PairMap *match;
116
0
  PairMap x;
117
0
  x.pair[0] = first;
118
0
  x.pair[1] = second;
119
0
  x.to = 0;
120
0
  match = fribidi_bsearch (&x, table, size, sizeof (table[0]), comp_PairMap);
121
0
  return match ? match->to : 0;
122
0
}
123
124
#define PAIR_MATCH(table,len,first,second) \
125
0
  ((first)<(table[0].pair[0])||(first)>(table[len-1].pair[0])?0: \
126
0
   find_pair_match(table, len, first, second))
127
128
static void
129
fribidi_shape_arabic_ligature (
130
  /* input */
131
  const PairMap *table,
132
  int size,
133
  const FriBidiLevel *embedding_levels,
134
  const FriBidiStrIndex len,
135
  /* input and output */
136
  FriBidiArabicProp *ar_props,
137
  FriBidiChar *str
138
)
139
0
{
140
  /* TODO: This doesn't form ligatures for even-level Arabic text.
141
   * no big problem though. */
142
0
  register FriBidiStrIndex i;
143
144
0
  for (i = 0; i < len - 1; i++) {
145
0
    register FriBidiChar c;
146
0
    if (FRIBIDI_LEVEL_IS_RTL(embedding_levels[i]) &&
147
0
  embedding_levels[i] == embedding_levels[i+1] &&
148
0
  (c = PAIR_MATCH(table, size, str[i], str[i+1])))
149
0
      {
150
0
  str[i] = FRIBIDI_CHAR_FILL;
151
0
  FRIBIDI_SET_BITS(ar_props[i], FRIBIDI_MASK_LIGATURED);
152
0
  str[i+1] = c;
153
0
      }
154
0
  }
155
0
}
156
157
#define DO_LIGATURING(table, levels, len, ar_props, str) \
158
0
  fribidi_shape_arabic_ligature ((table), sizeof(table)/sizeof((table)[0]), levels, len, ar_props, str)
159
160
#define DO_SHAPING(tablemacro, len, ar_props, str) \
161
0
  fribidi_shape_arabic_joining (tablemacro(,), len, ar_props, str);
162
  
163
164
165
166
FRIBIDI_ENTRY void
167
fribidi_shape_arabic (
168
  /* input */
169
  FriBidiFlags flags,
170
  const FriBidiLevel *embedding_levels,
171
  const FriBidiStrIndex len,
172
  /* input and output */
173
  FriBidiArabicProp *ar_props,
174
  FriBidiChar *str
175
)
176
0
{
177
0
  DBG ("in fribidi_shape_arabic");
178
179
0
  if UNLIKELY
180
0
    (len == 0 || !str) return;
181
182
0
  DBG ("in fribidi_shape");
183
184
0
  fribidi_assert (ar_props);
185
186
0
  if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_PRES))
187
0
    {
188
0
      DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_PRES, len, ar_props, str);
189
0
    }
190
191
0
  if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_LIGA))
192
0
    {
193
0
      DO_LIGATURING (mandatory_liga_table, embedding_levels, len, ar_props, str);
194
0
    }
195
196
0
  if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_CONSOLE))
197
0
    {
198
0
      DO_LIGATURING (console_liga_table, embedding_levels, len, ar_props, str);
199
0
      DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_NSM, len, ar_props, str);
200
0
    }
201
0
}
202
203
/* Editor directions:
204
 * Local Variables:
205
 *   mode: c
206
 *   c-basic-offset: 2
207
 *   indent-tabs-mode: t
208
 *   tab-width: 8
209
 * End:
210
 * vim: textwidth=78: autoindent: cindent: shiftwidth=2: tabstop=8:
211
 */