Coverage Report

Created: 2026-04-01 06:14

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.26M
{
42
7.26M
  register FriBidiRun *run;
43
44
7.26M
  run = fribidi_malloc (sizeof (FriBidiRun));
45
46
7.26M
  if LIKELY
47
7.26M
    (run)
48
7.26M
    {
49
7.26M
      run->len = run->pos = run->level = run->isolate_level = 0;
50
7.26M
      run->next = run->prev = run->prev_isolate = run->next_isolate = NULL;
51
7.26M
    }
52
7.26M
  return run;
53
7.26M
}
54
55
FriBidiRun *
56
new_run_list (
57
  void
58
)
59
5.46k
{
60
5.46k
  register FriBidiRun *run;
61
62
5.46k
  run = new_run ();
63
64
5.46k
  if LIKELY
65
5.46k
    (run)
66
5.46k
    {
67
5.46k
      run->type = FRIBIDI_TYPE_SENTINEL;
68
5.46k
      run->level = FRIBIDI_SENTINEL;
69
5.46k
      run->pos = FRIBIDI_SENTINEL;
70
5.46k
      run->len = FRIBIDI_SENTINEL;
71
5.46k
      run->next = run->prev = run;
72
5.46k
    }
73
74
5.46k
  return run;
75
5.46k
}
76
77
void
78
free_run_list (
79
  FriBidiRun *run_list
80
)
81
5.46k
{
82
5.46k
  if (!run_list)
83
0
    return;
84
85
5.46k
  fribidi_validate_run_list (run_list);
86
87
5.46k
  {
88
5.46k
    register FriBidiRun *pp;
89
90
5.46k
    pp = run_list;
91
5.46k
    pp->prev->next = NULL;
92
1.29M
    while LIKELY
93
5.46k
      (pp)
94
1.29M
      {
95
1.29M
  register FriBidiRun *p;
96
97
1.29M
  p = pp;
98
1.29M
  pp = pp->next;
99
1.29M
  fribidi_free (p);
100
1.29M
      };
101
5.46k
  }
102
5.46k
}
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
21.1M
  for (i = 0; i < len; i++)
127
21.1M
    {
128
21.1M
      register FriBidiCharType char_type = bidi_types[i];
129
21.1M
      register FriBidiBracketType bracket_type = FRIBIDI_NO_BRACKET;
130
21.1M
      if (bracket_types)
131
21.1M
        bracket_type = bracket_types[i];
132
      
133
21.1M
      if (char_type != last->type
134
19.2M
          || bracket_type != FRIBIDI_NO_BRACKET /* Always separate bracket into single char runs! */
135
15.8M
          || last->bracket_type != FRIBIDI_NO_BRACKET
136
15.8M
          || FRIBIDI_IS_ISOLATE(char_type)
137
21.1M
          )
138
6.89M
  {
139
6.89M
    run = new_run ();
140
6.89M
    if UNLIKELY
141
6.89M
      (!run) break;
142
6.89M
    run->type = char_type;
143
6.89M
    run->pos = i;
144
6.89M
    last->len = run->pos - last->pos;
145
6.89M
    last->next = run;
146
6.89M
    run->prev = last;
147
6.89M
          run->bracket_type = bracket_type;
148
6.89M
    last = run;
149
6.89M
  }
150
21.1M
    }
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.63k
{
197
2.63k
  register FriBidiRun *p = base, *q, *r, *s, *t;
198
2.63k
  register FriBidiStrIndex pos = 0, pos2;
199
2.63k
  fribidi_boolean status = false;
200
201
2.63k
  fribidi_validate_run_list (base);
202
2.63k
  fribidi_validate_run_list (over);
203
204
2.63k
  for_run_list (q, over)
205
289k
  {
206
289k
    if UNLIKELY
207
289k
      (!q->len || q->pos < pos) continue;
208
288k
    pos = q->pos;
209
1.75M
    while (p->next->type != FRIBIDI_TYPE_SENTINEL && p->next->pos <= pos)
210
1.46M
      p = p->next;
211
    /* now p is the element that q must be inserted 'in'. */
212
288k
    pos2 = pos + q->len;
213
288k
    r = p;
214
307k
    while (r->next->type != FRIBIDI_TYPE_SENTINEL && r->next->pos < pos2)
215
18.5k
      r = r->next;
216
288k
    if (preserve_length)
217
179k
      r->len += q->len;
218
    /* now r is the last element that q affects. */
219
288k
    if LIKELY
220
288k
      (p == r)
221
285k
      {
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
285k
  if (p->pos + p->len > pos2)
226
256k
    {
227
256k
      r = new_run ();
228
256k
      if UNLIKELY
229
256k
        (!r) goto out;
230
256k
      p->next->prev = r;
231
256k
      r->next = p->next;
232
256k
      r->level = p->level;
233
256k
      r->isolate_level = p->isolate_level;
234
256k
      r->type = p->type;
235
256k
      r->len = p->pos + p->len - pos2;
236
256k
      r->pos = pos2;
237
256k
    }
238
28.4k
  else
239
28.4k
    r = r->next;
240
241
285k
  if LIKELY
242
285k
    (p->pos + p->len >= pos)
243
285k
    {
244
      /* first part needed? */
245
285k
      if (p->pos < pos)
246
        /* cut the end of p. */
247
268k
        p->len = pos - p->pos;
248
16.5k
      else
249
16.5k
        {
250
16.5k
    t = p;
251
16.5k
    p = p->prev;
252
16.5k
    fribidi_free (t);
253
16.5k
        }
254
285k
    }
255
285k
      }
256
3.70k
    else
257
3.70k
      {
258
3.70k
  if LIKELY
259
3.70k
    (p->pos + p->len >= pos)
260
3.70k
    {
261
      /* p needed? */
262
3.70k
      if (p->pos < pos)
263
        /* cut the end of p. */
264
1.52k
        p->len = pos - p->pos;
265
2.17k
      else
266
2.17k
        p = p->prev;
267
3.70k
    }
268
269
  /* r needed? */
270
3.70k
  if (r->pos + r->len > pos2)
271
2.26k
    {
272
      /* cut the beginning of r. */
273
2.26k
      r->len = r->pos + r->len - pos2;
274
2.26k
      r->pos = pos2;
275
2.26k
    }
276
1.43k
  else
277
1.43k
    r = r->next;
278
279
  /* remove the elements between p and r. */
280
22.1k
  for (s = p->next; s != r;)
281
18.4k
    {
282
18.4k
      t = s;
283
18.4k
      s = s->next;
284
18.4k
      fribidi_free (t);
285
18.4k
    }
286
3.70k
      }
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
288k
    t = q;
291
288k
    q = q->prev;
292
288k
    delete_node (t);
293
288k
    p->next = t;
294
288k
    t->prev = p;
295
288k
    t->next = r;
296
288k
    r->prev = t;
297
288k
  }
298
2.63k
  status = true;
299
300
2.63k
  fribidi_validate_run_list (base);
301
302
2.63k
out:
303
2.63k
  free_run_list (over);
304
305
2.63k
  return status;
306
2.63k
}
307
308
#ifdef DEBUG
309
310
void
311
fribidi_validate_run_list (
312
  FriBidiRun *run_list    /* input run list */
313
)
314
15.1k
{
315
15.1k
  register FriBidiRun *q;
316
317
15.1k
  fribidi_assert (run_list);
318
15.1k
  fribidi_assert (run_list->next);
319
15.1k
  fribidi_assert (run_list->next->prev == run_list);
320
15.1k
  fribidi_assert (run_list->type == FRIBIDI_TYPE_SENTINEL);
321
15.1k
  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.1k
}
328
329
#endif /* !DEBUG */
330
331
/* Editor directions:
332
 * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
333
 */