Coverage Report

Created: 2026-01-17 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fribidi/lib/fribidi-run.c
Line
Count
Source
1
/* FriBidi
2
 * fribidi-run.c - text run data type
3
 *
4
 * Authors:
5
 *   Behdad Esfahbod, 2001, 2002, 2004
6
 *   Dov Grobgeld, 1999, 2000, 2017
7
 *
8
 * Copyright (C) 2004 Sharif FarsiWeb, Inc
9
 * Copyright (C) 2001,2002 Behdad Esfahbod
10
 * Copyright (C) 1999,2000,2017 Dov Grobgeld
11
 * 
12
 * This library is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU Lesser General Public
14
 * License as published by the Free Software Foundation; either
15
 * version 2.1 of the License, or (at your option) any later version.
16
 * 
17
 * This library is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
 * Lesser General Public License for more details.
21
 * 
22
 * You should have received a copy of the GNU Lesser General Public License
23
 * along with this library, in a file named COPYING; if not, write to the
24
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25
 * Boston, MA 02110-1301, USA
26
 * 
27
 * For licensing issues, contact <fribidi.license@gmail.com>.
28
 */
29
30
#include "common.h"
31
32
#include <fribidi-bidi-types.h>
33
34
#include "run.h"
35
#include "bidi-types.h"
36
37
FriBidiRun *
38
new_run (
39
  void
40
)
41
7.25M
{
42
7.25M
  register FriBidiRun *run;
43
44
7.25M
  run = fribidi_malloc (sizeof (FriBidiRun));
45
46
7.25M
  if LIKELY
47
7.25M
    (run)
48
7.25M
    {
49
7.25M
      run->len = run->pos = run->level = run->isolate_level = 0;
50
7.25M
      run->next = run->prev = run->prev_isolate = run->next_isolate = NULL;
51
7.25M
    }
52
7.25M
  return run;
53
7.25M
}
54
55
FriBidiRun *
56
new_run_list (
57
  void
58
)
59
5.43k
{
60
5.43k
  register FriBidiRun *run;
61
62
5.43k
  run = new_run ();
63
64
5.43k
  if LIKELY
65
5.43k
    (run)
66
5.43k
    {
67
5.43k
      run->type = FRIBIDI_TYPE_SENTINEL;
68
5.43k
      run->level = FRIBIDI_SENTINEL;
69
5.43k
      run->pos = FRIBIDI_SENTINEL;
70
5.43k
      run->len = FRIBIDI_SENTINEL;
71
5.43k
      run->next = run->prev = run;
72
5.43k
    }
73
74
5.43k
  return run;
75
5.43k
}
76
77
void
78
free_run_list (
79
  FriBidiRun *run_list
80
)
81
5.43k
{
82
5.43k
  if (!run_list)
83
0
    return;
84
85
5.43k
  fribidi_validate_run_list (run_list);
86
87
5.43k
  {
88
5.43k
    register FriBidiRun *pp;
89
90
5.43k
    pp = run_list;
91
5.43k
    pp->prev->next = NULL;
92
1.27M
    while LIKELY
93
5.43k
      (pp)
94
1.26M
      {
95
1.26M
  register FriBidiRun *p;
96
97
1.26M
  p = pp;
98
1.26M
  pp = pp->next;
99
1.26M
  fribidi_free (p);
100
1.26M
      };
101
5.43k
  }
102
5.43k
}
103
104
105
FriBidiRun *
106
run_list_encode_bidi_types (
107
  /* input */
108
  const FriBidiCharType *bidi_types,
109
  const FriBidiBracketType *bracket_types,
110
  const FriBidiStrIndex len
111
)
112
1.81k
{
113
1.81k
  FriBidiRun *list, *last;
114
1.81k
  register FriBidiRun *run = NULL;
115
1.81k
  FriBidiStrIndex i;
116
117
1.81k
  fribidi_assert (bidi_types);
118
119
  /* Create the list sentinel */
120
1.81k
  list = new_run_list ();
121
1.81k
  if UNLIKELY
122
1.81k
    (!list) return NULL;
123
1.81k
  last = list;
124
125
  /* Scan over the character types */
126
18.5M
  for (i = 0; i < len; i++)
127
18.5M
    {
128
18.5M
      register FriBidiCharType char_type = bidi_types[i];
129
18.5M
      register FriBidiBracketType bracket_type = FRIBIDI_NO_BRACKET;
130
18.5M
      if (bracket_types)
131
18.5M
        bracket_type = bracket_types[i];
132
      
133
18.5M
      if (char_type != last->type
134
16.7M
          || bracket_type != FRIBIDI_NO_BRACKET /* Always separate bracket into single char runs! */
135
13.5M
          || last->bracket_type != FRIBIDI_NO_BRACKET
136
13.4M
          || FRIBIDI_IS_ISOLATE(char_type)
137
18.5M
          )
138
6.88M
  {
139
6.88M
    run = new_run ();
140
6.88M
    if UNLIKELY
141
6.88M
      (!run) break;
142
6.88M
    run->type = char_type;
143
6.88M
    run->pos = i;
144
6.88M
    last->len = run->pos - last->pos;
145
6.88M
    last->next = run;
146
6.88M
    run->prev = last;
147
6.88M
          run->bracket_type = bracket_type;
148
6.88M
    last = run;
149
6.88M
  }
150
18.5M
    }
151
152
  /* Close the circle */
153
1.81k
  last->len = len - last->pos;
154
1.81k
  last->next = list;
155
1.81k
  list->prev = last;
156
157
1.81k
  if UNLIKELY
158
1.81k
    (!run)
159
0
    {
160
      /* Memory allocation failed */
161
0
      free_run_list (list);
162
0
      return NULL;
163
0
    }
164
165
1.81k
  fribidi_validate_run_list (list);
166
167
1.81k
  return list;
168
1.81k
}
169
170
/* override the run list 'base', with the runs in the list 'over', to
171
   reinsert the previously-removed explicit codes (at X9) from
172
   'explicits_list' back into 'type_rl_list' for example. This is used at the
173
   end of I2 to restore the explicit marks, and also to reset the character
174
   types of characters at L1.
175
176
   it is assumed that the 'pos' of the first element in 'base' list is not
177
   more than the 'pos' of the first element of the 'over' list, and the
178
   'pos' of the last element of the 'base' list is not less than the 'pos'
179
   of the last element of the 'over' list. these two conditions are always
180
   satisfied for the two usages mentioned above.
181
182
   Note:
183
     frees the over list.
184
185
   Todo:
186
     use some explanatory names instead of p, q, ...
187
     rewrite comment above to remove references to special usage.
188
*/
189
fribidi_boolean
190
shadow_run_list (
191
  /* input */
192
  FriBidiRun *base,
193
  FriBidiRun *over,
194
  fribidi_boolean preserve_length
195
)
196
2.61k
{
197
2.61k
  register FriBidiRun *p = base, *q, *r, *s, *t;
198
2.61k
  register FriBidiStrIndex pos = 0, pos2;
199
2.61k
  fribidi_boolean status = false;
200
201
2.61k
  fribidi_validate_run_list (base);
202
2.61k
  fribidi_validate_run_list (over);
203
204
2.61k
  for_run_list (q, over)
205
306k
  {
206
306k
    if UNLIKELY
207
306k
      (!q->len || q->pos < pos) continue;
208
305k
    pos = q->pos;
209
1.73M
    while (p->next->type != FRIBIDI_TYPE_SENTINEL && p->next->pos <= pos)
210
1.43M
      p = p->next;
211
    /* now p is the element that q must be inserted 'in'. */
212
305k
    pos2 = pos + q->len;
213
305k
    r = p;
214
324k
    while (r->next->type != FRIBIDI_TYPE_SENTINEL && r->next->pos < pos2)
215
18.7k
      r = r->next;
216
305k
    if (preserve_length)
217
218k
      r->len += q->len;
218
    /* now r is the last element that q affects. */
219
305k
    if LIKELY
220
305k
      (p == r)
221
302k
      {
222
  /* split p into at most 3 intervals, and insert q in the place of
223
     the second interval, set r to be the third part. */
224
  /* third part needed? */
225
302k
  if (p->pos + p->len > pos2)
226
277k
    {
227
277k
      r = new_run ();
228
277k
      if UNLIKELY
229
277k
        (!r) goto out;
230
277k
      p->next->prev = r;
231
277k
      r->next = p->next;
232
277k
      r->level = p->level;
233
277k
      r->isolate_level = p->isolate_level;
234
277k
      r->type = p->type;
235
277k
      r->len = p->pos + p->len - pos2;
236
277k
      r->pos = pos2;
237
277k
    }
238
24.9k
  else
239
24.9k
    r = r->next;
240
241
302k
  if LIKELY
242
302k
    (p->pos + p->len >= pos)
243
302k
    {
244
      /* first part needed? */
245
302k
      if (p->pos < pos)
246
        /* cut the end of p. */
247
281k
        p->len = pos - p->pos;
248
20.5k
      else
249
20.5k
        {
250
20.5k
    t = p;
251
20.5k
    p = p->prev;
252
20.5k
    fribidi_free (t);
253
20.5k
        }
254
302k
    }
255
302k
      }
256
3.31k
    else
257
3.31k
      {
258
3.31k
  if LIKELY
259
3.31k
    (p->pos + p->len >= pos)
260
3.31k
    {
261
      /* p needed? */
262
3.31k
      if (p->pos < pos)
263
        /* cut the end of p. */
264
1.68k
        p->len = pos - p->pos;
265
1.63k
      else
266
1.63k
        p = p->prev;
267
3.31k
    }
268
269
  /* r needed? */
270
3.31k
  if (r->pos + r->len > pos2)
271
2.13k
    {
272
      /* cut the beginning of r. */
273
2.13k
      r->len = r->pos + r->len - pos2;
274
2.13k
      r->pos = pos2;
275
2.13k
    }
276
1.18k
  else
277
1.18k
    r = r->next;
278
279
  /* remove the elements between p and r. */
280
21.5k
  for (s = p->next; s != r;)
281
18.2k
    {
282
18.2k
      t = s;
283
18.2k
      s = s->next;
284
18.2k
      fribidi_free (t);
285
18.2k
    }
286
3.31k
      }
287
    /* before updating the next and prev runs to point to the inserted q,
288
       we must remember the next element of q in the 'over' list.
289
     */
290
305k
    t = q;
291
305k
    q = q->prev;
292
305k
    delete_node (t);
293
305k
    p->next = t;
294
305k
    t->prev = p;
295
305k
    t->next = r;
296
305k
    r->prev = t;
297
305k
  }
298
2.61k
  status = true;
299
300
2.61k
  fribidi_validate_run_list (base);
301
302
2.61k
out:
303
2.61k
  free_run_list (over);
304
305
2.61k
  return status;
306
2.61k
}
307
308
#ifdef DEBUG
309
310
void
311
fribidi_validate_run_list (
312
  FriBidiRun *run_list    /* input run list */
313
)
314
15.0k
{
315
15.0k
  register FriBidiRun *q;
316
317
15.0k
  fribidi_assert (run_list);
318
15.0k
  fribidi_assert (run_list->next);
319
15.0k
  fribidi_assert (run_list->next->prev == run_list);
320
15.0k
  fribidi_assert (run_list->type == FRIBIDI_TYPE_SENTINEL);
321
15.0k
  for_run_list (q, run_list)
322
11.8M
  {
323
11.8M
    fribidi_assert (q->next);
324
11.8M
    fribidi_assert (q->next->prev == q);
325
11.8M
  }
326
  fribidi_assert (q == run_list);
327
15.0k
}
328
329
#endif /* !DEBUG */
330
331
/* Editor directions:
332
 * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
333
 */