Coverage Report

Created: 2025-07-11 06:25

/src/fribidi/lib/fribidi-run.c
Line
Count
Source (jump to first uncovered line)
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
6.70M
{
42
6.70M
  register FriBidiRun *run;
43
44
6.70M
  run = fribidi_malloc (sizeof (FriBidiRun));
45
46
6.70M
  if LIKELY
47
6.70M
    (run)
48
6.70M
    {
49
6.70M
      run->len = run->pos = run->level = run->isolate_level = 0;
50
6.70M
      run->next = run->prev = run->prev_isolate = run->next_isolate = NULL;
51
6.70M
    }
52
6.70M
  return run;
53
6.70M
}
54
55
FriBidiRun *
56
new_run_list (
57
  void
58
)
59
5.05k
{
60
5.05k
  register FriBidiRun *run;
61
62
5.05k
  run = new_run ();
63
64
5.05k
  if LIKELY
65
5.05k
    (run)
66
5.05k
    {
67
5.05k
      run->type = FRIBIDI_TYPE_SENTINEL;
68
5.05k
      run->level = FRIBIDI_SENTINEL;
69
5.05k
      run->pos = FRIBIDI_SENTINEL;
70
5.05k
      run->len = FRIBIDI_SENTINEL;
71
5.05k
      run->next = run->prev = run;
72
5.05k
    }
73
74
5.05k
  return run;
75
5.05k
}
76
77
void
78
free_run_list (
79
  FriBidiRun *run_list
80
)
81
5.05k
{
82
5.05k
  if (!run_list)
83
0
    return;
84
85
5.05k
  fribidi_validate_run_list (run_list);
86
87
5.05k
  {
88
5.05k
    register FriBidiRun *pp;
89
90
5.05k
    pp = run_list;
91
5.05k
    pp->prev->next = NULL;
92
1.28M
    while LIKELY
93
5.05k
      (pp)
94
1.27M
      {
95
1.27M
  register FriBidiRun *p;
96
97
1.27M
  p = pp;
98
1.27M
  pp = pp->next;
99
1.27M
  fribidi_free (p);
100
1.27M
      };
101
5.05k
  }
102
5.05k
}
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.68k
{
113
1.68k
  FriBidiRun *list, *last;
114
1.68k
  register FriBidiRun *run = NULL;
115
1.68k
  FriBidiStrIndex i;
116
117
1.68k
  fribidi_assert (bidi_types);
118
119
  /* Create the list sentinel */
120
1.68k
  list = new_run_list ();
121
1.68k
  if UNLIKELY
122
1.68k
    (!list) return NULL;
123
1.68k
  last = list;
124
125
  /* Scan over the character types */
126
17.0M
  for (i = 0; i < len; i++)
127
17.0M
    {
128
17.0M
      register FriBidiCharType char_type = bidi_types[i];
129
17.0M
      register FriBidiBracketType bracket_type = FRIBIDI_NO_BRACKET;
130
17.0M
      if (bracket_types)
131
17.0M
        bracket_type = bracket_types[i];
132
      
133
17.0M
      if (char_type != last->type
134
17.0M
          || bracket_type != FRIBIDI_NO_BRACKET /* Always separate bracket into single char runs! */
135
17.0M
          || last->bracket_type != FRIBIDI_NO_BRACKET
136
17.0M
          || FRIBIDI_IS_ISOLATE(char_type)
137
17.0M
          )
138
6.33M
  {
139
6.33M
    run = new_run ();
140
6.33M
    if UNLIKELY
141
6.33M
      (!run) break;
142
6.33M
    run->type = char_type;
143
6.33M
    run->pos = i;
144
6.33M
    last->len = run->pos - last->pos;
145
6.33M
    last->next = run;
146
6.33M
    run->prev = last;
147
6.33M
          run->bracket_type = bracket_type;
148
6.33M
    last = run;
149
6.33M
  }
150
17.0M
    }
151
152
  /* Close the circle */
153
1.68k
  last->len = len - last->pos;
154
1.68k
  last->next = list;
155
1.68k
  list->prev = last;
156
157
1.68k
  if UNLIKELY
158
1.68k
    (!run)
159
0
    {
160
      /* Memory allocation failed */
161
0
      free_run_list (list);
162
0
      return NULL;
163
0
    }
164
165
1.68k
  fribidi_validate_run_list (list);
166
167
1.68k
  return list;
168
1.68k
}
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.45k
{
197
2.45k
  register FriBidiRun *p = base, *q, *r, *s, *t;
198
2.45k
  register FriBidiStrIndex pos = 0, pos2;
199
2.45k
  fribidi_boolean status = false;
200
201
2.45k
  fribidi_validate_run_list (base);
202
2.45k
  fribidi_validate_run_list (over);
203
204
2.45k
  for_run_list (q, over)
205
334k
  {
206
334k
    if UNLIKELY
207
334k
      (!q->len || q->pos < pos) continue;
208
333k
    pos = q->pos;
209
1.87M
    while (p->next->type != FRIBIDI_TYPE_SENTINEL && p->next->pos <= pos)
210
1.54M
      p = p->next;
211
    /* now p is the element that q must be inserted 'in'. */
212
333k
    pos2 = pos + q->len;
213
333k
    r = p;
214
352k
    while (r->next->type != FRIBIDI_TYPE_SENTINEL && r->next->pos < pos2)
215
18.8k
      r = r->next;
216
333k
    if (preserve_length)
217
261k
      r->len += q->len;
218
    /* now r is the last element that q affects. */
219
333k
    if LIKELY
220
333k
      (p == r)
221
329k
      {
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
329k
  if (p->pos + p->len > pos2)
226
294k
    {
227
294k
      r = new_run ();
228
294k
      if UNLIKELY
229
294k
        (!r) goto out;
230
294k
      p->next->prev = r;
231
294k
      r->next = p->next;
232
294k
      r->level = p->level;
233
294k
      r->isolate_level = p->isolate_level;
234
294k
      r->type = p->type;
235
294k
      r->len = p->pos + p->len - pos2;
236
294k
      r->pos = pos2;
237
294k
    }
238
34.8k
  else
239
34.8k
    r = r->next;
240
241
329k
  if LIKELY
242
329k
    (p->pos + p->len >= pos)
243
329k
    {
244
      /* first part needed? */
245
329k
      if (p->pos < pos)
246
        /* cut the end of p. */
247
314k
        p->len = pos - p->pos;
248
15.0k
      else
249
15.0k
        {
250
15.0k
    t = p;
251
15.0k
    p = p->prev;
252
15.0k
    fribidi_free (t);
253
15.0k
        }
254
329k
    }
255
329k
      }
256
3.72k
    else
257
3.72k
      {
258
3.72k
  if LIKELY
259
3.72k
    (p->pos + p->len >= pos)
260
3.72k
    {
261
      /* p needed? */
262
3.72k
      if (p->pos < pos)
263
        /* cut the end of p. */
264
1.56k
        p->len = pos - p->pos;
265
2.16k
      else
266
2.16k
        p = p->prev;
267
3.72k
    }
268
269
  /* r needed? */
270
3.72k
  if (r->pos + r->len > pos2)
271
2.42k
    {
272
      /* cut the beginning of r. */
273
2.42k
      r->len = r->pos + r->len - pos2;
274
2.42k
      r->pos = pos2;
275
2.42k
    }
276
1.30k
  else
277
1.30k
    r = r->next;
278
279
  /* remove the elements between p and r. */
280
22.2k
  for (s = p->next; s != r;)
281
18.5k
    {
282
18.5k
      t = s;
283
18.5k
      s = s->next;
284
18.5k
      fribidi_free (t);
285
18.5k
    }
286
3.72k
      }
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
333k
    t = q;
291
333k
    q = q->prev;
292
333k
    delete_node (t);
293
333k
    p->next = t;
294
333k
    t->prev = p;
295
333k
    t->next = r;
296
333k
    r->prev = t;
297
333k
  }
298
2.45k
  status = true;
299
300
2.45k
  fribidi_validate_run_list (base);
301
302
2.45k
out:
303
2.45k
  free_run_list (over);
304
305
2.45k
  return status;
306
2.45k
}
307
308
#ifdef DEBUG
309
310
void
311
fribidi_validate_run_list (
312
  FriBidiRun *run_list    /* input run list */
313
)
314
14.0k
{
315
14.0k
  register FriBidiRun *q;
316
317
14.0k
  fribidi_assert (run_list);
318
14.0k
  fribidi_assert (run_list->next);
319
14.0k
  fribidi_assert (run_list->next->prev == run_list);
320
14.0k
  fribidi_assert (run_list->type == FRIBIDI_TYPE_SENTINEL);
321
14.0k
  for_run_list (q, run_list)
322
11.4M
  {
323
11.4M
    fribidi_assert (q->next);
324
11.4M
    fribidi_assert (q->next->prev == q);
325
11.4M
  }
326
14.0k
  fribidi_assert (q == run_list);
327
14.0k
}
328
329
#endif /* !DEBUG */
330
331
/* Editor directions:
332
 * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
333
 */