Coverage Report

Created: 2025-08-29 06:28

/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.77M
{
42
6.77M
  register FriBidiRun *run;
43
44
6.77M
  run = fribidi_malloc (sizeof (FriBidiRun));
45
46
6.77M
  if LIKELY
47
6.77M
    (run)
48
6.77M
    {
49
6.77M
      run->len = run->pos = run->level = run->isolate_level = 0;
50
6.77M
      run->next = run->prev = run->prev_isolate = run->next_isolate = NULL;
51
6.77M
    }
52
6.77M
  return run;
53
6.77M
}
54
55
FriBidiRun *
56
new_run_list (
57
  void
58
)
59
5.47k
{
60
5.47k
  register FriBidiRun *run;
61
62
5.47k
  run = new_run ();
63
64
5.47k
  if LIKELY
65
5.47k
    (run)
66
5.47k
    {
67
5.47k
      run->type = FRIBIDI_TYPE_SENTINEL;
68
5.47k
      run->level = FRIBIDI_SENTINEL;
69
5.47k
      run->pos = FRIBIDI_SENTINEL;
70
5.47k
      run->len = FRIBIDI_SENTINEL;
71
5.47k
      run->next = run->prev = run;
72
5.47k
    }
73
74
5.47k
  return run;
75
5.47k
}
76
77
void
78
free_run_list (
79
  FriBidiRun *run_list
80
)
81
5.47k
{
82
5.47k
  if (!run_list)
83
0
    return;
84
85
5.47k
  fribidi_validate_run_list (run_list);
86
87
5.47k
  {
88
5.47k
    register FriBidiRun *pp;
89
90
5.47k
    pp = run_list;
91
5.47k
    pp->prev->next = NULL;
92
1.19M
    while LIKELY
93
5.47k
      (pp)
94
1.18M
      {
95
1.18M
  register FriBidiRun *p;
96
97
1.18M
  p = pp;
98
1.18M
  pp = pp->next;
99
1.18M
  fribidi_free (p);
100
1.18M
      };
101
5.47k
  }
102
5.47k
}
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.82k
{
113
1.82k
  FriBidiRun *list, *last;
114
1.82k
  register FriBidiRun *run = NULL;
115
1.82k
  FriBidiStrIndex i;
116
117
1.82k
  fribidi_assert (bidi_types);
118
119
  /* Create the list sentinel */
120
1.82k
  list = new_run_list ();
121
1.82k
  if UNLIKELY
122
1.82k
    (!list) return NULL;
123
1.82k
  last = list;
124
125
  /* Scan over the character types */
126
18.3M
  for (i = 0; i < len; i++)
127
18.2M
    {
128
18.2M
      register FriBidiCharType char_type = bidi_types[i];
129
18.2M
      register FriBidiBracketType bracket_type = FRIBIDI_NO_BRACKET;
130
18.2M
      if (bracket_types)
131
18.2M
        bracket_type = bracket_types[i];
132
      
133
18.2M
      if (char_type != last->type
134
18.2M
          || bracket_type != FRIBIDI_NO_BRACKET /* Always separate bracket into single char runs! */
135
18.2M
          || last->bracket_type != FRIBIDI_NO_BRACKET
136
18.2M
          || FRIBIDI_IS_ISOLATE(char_type)
137
18.2M
          )
138
6.42M
  {
139
6.42M
    run = new_run ();
140
6.42M
    if UNLIKELY
141
6.42M
      (!run) break;
142
6.42M
    run->type = char_type;
143
6.42M
    run->pos = i;
144
6.42M
    last->len = run->pos - last->pos;
145
6.42M
    last->next = run;
146
6.42M
    run->prev = last;
147
6.42M
          run->bracket_type = bracket_type;
148
6.42M
    last = run;
149
6.42M
  }
150
18.2M
    }
151
152
  /* Close the circle */
153
1.82k
  last->len = len - last->pos;
154
1.82k
  last->next = list;
155
1.82k
  list->prev = last;
156
157
1.82k
  if UNLIKELY
158
1.82k
    (!run)
159
0
    {
160
      /* Memory allocation failed */
161
0
      free_run_list (list);
162
0
      return NULL;
163
0
    }
164
165
1.82k
  fribidi_validate_run_list (list);
166
167
1.82k
  return list;
168
1.82k
}
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.58k
{
197
2.58k
  register FriBidiRun *p = base, *q, *r, *s, *t;
198
2.58k
  register FriBidiStrIndex pos = 0, pos2;
199
2.58k
  fribidi_boolean status = false;
200
201
2.58k
  fribidi_validate_run_list (base);
202
2.58k
  fribidi_validate_run_list (over);
203
204
2.58k
  for_run_list (q, over)
205
305k
  {
206
305k
    if UNLIKELY
207
305k
      (!q->len || q->pos < pos) continue;
208
304k
    pos = q->pos;
209
1.70M
    while (p->next->type != FRIBIDI_TYPE_SENTINEL && p->next->pos <= pos)
210
1.40M
      p = p->next;
211
    /* now p is the element that q must be inserted 'in'. */
212
304k
    pos2 = pos + q->len;
213
304k
    r = p;
214
324k
    while (r->next->type != FRIBIDI_TYPE_SENTINEL && r->next->pos < pos2)
215
20.0k
      r = r->next;
216
304k
    if (preserve_length)
217
221k
      r->len += q->len;
218
    /* now r is the last element that q affects. */
219
304k
    if LIKELY
220
304k
      (p == r)
221
300k
      {
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
300k
  if (p->pos + p->len > pos2)
226
265k
    {
227
265k
      r = new_run ();
228
265k
      if UNLIKELY
229
265k
        (!r) goto out;
230
265k
      p->next->prev = r;
231
265k
      r->next = p->next;
232
265k
      r->level = p->level;
233
265k
      r->isolate_level = p->isolate_level;
234
265k
      r->type = p->type;
235
265k
      r->len = p->pos + p->len - pos2;
236
265k
      r->pos = pos2;
237
265k
    }
238
35.3k
  else
239
35.3k
    r = r->next;
240
241
300k
  if LIKELY
242
300k
    (p->pos + p->len >= pos)
243
300k
    {
244
      /* first part needed? */
245
300k
      if (p->pos < pos)
246
        /* cut the end of p. */
247
281k
        p->len = pos - p->pos;
248
19.3k
      else
249
19.3k
        {
250
19.3k
    t = p;
251
19.3k
    p = p->prev;
252
19.3k
    fribidi_free (t);
253
19.3k
        }
254
300k
    }
255
300k
      }
256
3.41k
    else
257
3.41k
      {
258
3.41k
  if LIKELY
259
3.41k
    (p->pos + p->len >= pos)
260
3.41k
    {
261
      /* p needed? */
262
3.41k
      if (p->pos < pos)
263
        /* cut the end of p. */
264
1.29k
        p->len = pos - p->pos;
265
2.12k
      else
266
2.12k
        p = p->prev;
267
3.41k
    }
268
269
  /* r needed? */
270
3.41k
  if (r->pos + r->len > pos2)
271
2.35k
    {
272
      /* cut the beginning of r. */
273
2.35k
      r->len = r->pos + r->len - pos2;
274
2.35k
      r->pos = pos2;
275
2.35k
    }
276
1.06k
  else
277
1.06k
    r = r->next;
278
279
  /* remove the elements between p and r. */
280
23.2k
  for (s = p->next; s != r;)
281
19.8k
    {
282
19.8k
      t = s;
283
19.8k
      s = s->next;
284
19.8k
      fribidi_free (t);
285
19.8k
    }
286
3.41k
      }
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
304k
    t = q;
291
304k
    q = q->prev;
292
304k
    delete_node (t);
293
304k
    p->next = t;
294
304k
    t->prev = p;
295
304k
    t->next = r;
296
304k
    r->prev = t;
297
304k
  }
298
2.58k
  status = true;
299
300
2.58k
  fribidi_validate_run_list (base);
301
302
2.58k
out:
303
2.58k
  free_run_list (over);
304
305
2.58k
  return status;
306
2.58k
}
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
10.9M
  {
323
10.9M
    fribidi_assert (q->next);
324
10.9M
    fribidi_assert (q->next->prev == q);
325
10.9M
  }
326
15.0k
  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
 */