• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Tehreer / SheenBidi / 29262635967

13 Jul 2026 03:32PM UTC coverage: 96.182% (+0.1%) from 96.086%
29262635967

push

github

mta452
[test] Add uniform run iterator tests

4157 of 4322 relevant lines covered (96.18%)

433341.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.0
/Source/API/SBText.c
1
/*
2
 * Copyright (C) 2025-2026 Muhammad Tayyab Akram
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
#include <API/SBBase.h>
18

19
#if SB_TEXT_API_SUPPORTED
20

21
#include <stddef.h>
22

23
#include <API/SBAssert.h>
24
#include <API/SBAttributeRegistry.h>
25
#include <API/SBTextConfig.h>
26
#include <API/SBTextIterators.h>
27
#include <Core/Object.h>
28
#include <Text/AttributeManager.h>
29
#include <Text/BidiTypesBuffer.h>
30
#include <Text/TextAnalysis.h>
31
#include <Text/TextBuffer.h>
32

33
#include "SBText.h"
34

35
/* =========================================================================
36
 * Text Implementation
37
 * ========================================================================= */
38

39
SBTextRef SBTextCreate(const void *string, SBUInteger length, SBStringEncoding encoding,
17✔
40
    SBTextConfigRef config)
41
{
42
    SBMutableTextRef text = SBTextCreateMutable(encoding, config);
17✔
43

44
    if (text) {
17✔
45
        SBTextAppendCodeUnits(text, string, length);
17✔
46
        text->isMutable = SBFalse;
17✔
47
    }
48

49
    return text;
17✔
50
}
51

52
SBTextRef SBTextCreateCopy(SBTextRef text)
2✔
53
{
54
    SBMutableTextRef copy = SBTextCreateMutableCopy(text);
2✔
55

56
    if (copy) {
2✔
57
        copy->isMutable = SBFalse;
2✔
58
    }
59

60
    return copy;
2✔
61
}
62

63
SBStringEncoding SBTextGetEncoding(SBTextRef text)
7✔
64
{
65
    return text->buffer.encoding;
7✔
66
}
67

68
SBAttributeRegistryRef SBTextGetAttributeRegistry(SBTextRef text)
13✔
69
{
70
    return text->attributeRegistry;
13✔
71
}
72

73
SBUInteger SBTextGetLength(SBTextRef text)
24✔
74
{
75
    return TextBufferGetLength((TextBufferRef)&text->buffer);
24✔
76
}
77

78
void SBTextGetCodeUnits(SBTextRef text, SBUInteger index, SBUInteger length, void *buffer)
10✔
79
{
80
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
10✔
81

82
    SBAssert(isRangeValid);
10✔
83

84
    TextBufferGetCodeUnits((TextBufferRef)&text->buffer, index, length, buffer);
10✔
85
}
10✔
86

87
void SBTextGetBidiTypes(SBTextRef text, SBUInteger index, SBUInteger length, SBBidiType *buffer)
2✔
88
{
89
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
2✔
90

91
    SBAssert(isRangeValid);
2✔
92

93
    BidiTypesBufferGetBidiTypes((BidiTypesBufferRef)&text->bidiTypes, index, length, buffer);
2✔
94
}
2✔
95

96
void SBTextGetScripts(SBTextRef text, SBUInteger index, SBUInteger length, SBScript *buffer)
2✔
97
{
98
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
2✔
99

100
    SBAssert(isRangeValid && !text->isEditing);
2✔
101

102
    TextAnalysisGetScripts((TextAnalysisRef)&text->analysis, index, length, buffer);
2✔
103
}
2✔
104

105
void SBTextGetResolvedLevels(SBTextRef text, SBUInteger index, SBUInteger length, SBLevel *buffer)
2✔
106
{
107
    SBBoolean isRangeValid = SBUIntegerVerifyRange(text->buffer.codeUnits.count, index, length);
2✔
108

109
    SBAssert(isRangeValid && !text->isEditing);
2✔
110

111
    TextAnalysisGetResolvedLevels((TextAnalysisRef)&text->analysis, index, length, buffer);
2✔
112
}
2✔
113

114
void SBTextGetCodeUnitParagraphInfo(SBTextRef text, SBUInteger index,
17✔
115
    SBParagraphInfo *paragraphInfo)
116
{
117
    SBBoolean isValidIndex = index < text->buffer.codeUnits.count;
17✔
118

119
    SBAssert(isValidIndex && !text->isEditing);
17✔
120

121
    TextAnalysisGetCodeUnitParagraphInfo((TextAnalysisRef)&text->analysis, index, paragraphInfo);
17✔
122
}
17✔
123

124
SBParagraphIteratorRef SBTextCreateParagraphIterator(SBTextRef text)
2✔
125
{
126
    return SBParagraphIteratorCreate(text);
2✔
127
}
128

129
SBLogicalRunIteratorRef SBTextCreateLogicalRunIterator(SBTextRef text)
1✔
130
{
131
    return SBLogicalRunIteratorCreate(text);
1✔
132
}
133

134
SBScriptRunIteratorRef SBTextCreateScriptRunIterator(SBTextRef text)
1✔
135
{
136
    return SBScriptRunIteratorCreate(text);
1✔
137
}
138

139
SBAttributeRunIteratorRef SBTextCreateAttributeRunIterator(SBTextRef text)
26✔
140
{
141
    return SBAttributeRunIteratorCreate(text);
26✔
142
}
143

144
SBUniformRunIteratorRef SBTextCreateUniformRunIterator(SBTextRef text)
16✔
145
{
146
    return SBUniformRunIteratorCreate(text);
16✔
147
}
148

149
SBVisualRunIteratorRef SBTextCreateVisualRunIterator(SBTextRef text,
×
150
    SBUInteger index, SBUInteger length)
151
{
152
    SBVisualRunIteratorRef iterator = SBVisualRunIteratorCreate(text);
×
153

154
    if (iterator) {
×
155
        SBVisualRunIteratorReset(iterator, index, length);
×
156
    }
157

158
    return iterator;
×
159
}
160

161
SBTextRef SBTextRetain(SBTextRef text)
107✔
162
{
163
    return ObjectRetain((ObjectRef)text);
107✔
164
}
165

166
void SBTextRelease(SBTextRef text)
304✔
167
{
168
    ObjectRelease((ObjectRef)text);
304✔
169
}
304✔
170

171
/* =========================================================================
172
 * Mutable Text Implementation
173
 * ========================================================================= */
174

175
static void FinalizeMutableText(ObjectRef object)
197✔
176
{
177
    SBMutableTextRef text = object;
197✔
178

179
    AttributeManagerFinalize(&text->attributeManager);
197✔
180
    TextAnalysisFinalize(&text->analysis);
197✔
181
    BidiTypesBufferFinalize(&text->bidiTypes);
197✔
182
    TextBufferFinalize(&text->buffer);
197✔
183

184
    if (text->attributeRegistry) {
197✔
185
        SBAttributeRegistryRelease(text->attributeRegistry);
142✔
186
    }
187
}
197✔
188

189
SB_INTERNAL SBMutableTextRef SBTextCreateMutableWithParameters(SBStringEncoding encoding,
197✔
190
    SBAttributeRegistryRef attributeRegistry, SBLevel baseLevel,
191
    const SBParagraphUserInfoCallbacks *userInfoCallbacks,
192
    SBParagraphUserInfoProviderCallback userInfoProvider, void *userInfoProviderContext)
193
{
194
    const SBUInteger size = sizeof(SBText);
197✔
195
    void *pointer = NULL;
197✔
196
    SBMutableTextRef text;
197

198
    text = ObjectCreate(&size, 1, &pointer, FinalizeMutableText);
197✔
199

200
    if (text) {
197✔
201
        if (attributeRegistry) {
197✔
202
            attributeRegistry = SBAttributeRegistryRetain(attributeRegistry);
142✔
203
        }
204

205
        text->isMutable = SBTrue;
197✔
206
        text->isEditing = SBFalse;
197✔
207
        text->attributeRegistry = attributeRegistry;
197✔
208

209
        TextBufferInitialize(&text->buffer, encoding);
197✔
210
        BidiTypesBufferInitialize(&text->bidiTypes);
197✔
211
        TextAnalysisInitialize(&text->analysis, text, baseLevel, userInfoCallbacks,
197✔
212
            userInfoProvider, userInfoProviderContext);
213
        AttributeManagerInitialize(&text->attributeManager, &text->analysis, attributeRegistry);
197✔
214
    }
215

216
    return text;
197✔
217
}
218

219
SBMutableTextRef SBTextCreateMutable(SBStringEncoding encoding, SBTextConfigRef config)
192✔
220
{
221
    SBMutableTextRef text = SBTextCreateMutableWithParameters(encoding,
384✔
222
        config->attributeRegistry, config->baseLevel, &config->userInfoCallbacks,
192✔
223
        config->userInfoProvider, config->userInfoProviderContext);
224

225
    if (text) {
226
        /* TODO: Apply default attributes */
227
    }
228

229
    return text;
192✔
230
}
231

232
SBMutableTextRef SBTextCreateMutableCopy(SBTextRef text)
5✔
233
{
234
    SBMutableTextRef copy = SBTextCreateMutableWithParameters(text->buffer.encoding,
10✔
235
        text->attributeRegistry, text->analysis.baseLevel, &text->analysis.userInfoCallbacks,
5✔
236
        text->analysis.userInfoProvider, text->analysis.userInfoProviderContext);
5✔
237

238
    if (copy) {
5✔
239
        TextBufferCopyCodeUnits(&copy->buffer, &text->buffer);
5✔
240
        BidiTypesBufferCopyBidiTypes(&copy->bidiTypes, &text->bidiTypes);
5✔
241
        TextAnalysisCopyParagraphs(&copy->analysis, &text->analysis);
5✔
242
        TextAnalysisFlush(&copy->analysis, &copy->buffer, &copy->bidiTypes);
5✔
243

244
        /* Copy attributes */
245
        AttributeManagerCopyAttributes(&copy->attributeManager, &text->attributeManager);
5✔
246
    }
247

248
    return copy;
5✔
249
}
250

251
void SBTextBeginEditing(SBMutableTextRef text)
5✔
252
{
253
    SBAssert(text->isMutable);
5✔
254

255
    if (!text->isMutable) {
5✔
256
        return;
×
257
    }
258

259
    text->isEditing = SBTrue;
5✔
260
}
261

262
void SBTextEndEditing(SBMutableTextRef text)
5✔
263
{
264
    SBAssert(text->isMutable);
5✔
265

266
    if (!text->isMutable) {
5✔
267
        return;
×
268
    }
269

270
    TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
5✔
271
    text->isEditing = SBFalse;
5✔
272
}
273

274
void SBTextAppendCodeUnits(SBMutableTextRef text,
185✔
275
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
276
{
277
    SBAssert(text->isMutable);
185✔
278

279
    if (!text->isMutable) {
185✔
280
        return;
×
281
    }
282

283
    SBTextInsertCodeUnits(text, text->buffer.codeUnits.count, codeUnitBuffer, codeUnitCount);
185✔
284
}
285

286
void SBTextInsertCodeUnits(SBMutableTextRef text, SBUInteger index,
219✔
287
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
288
{
289
    SBAssert(text->isMutable && index <= text->buffer.codeUnits.count);
219✔
290

291
    if (!text->isMutable) {
219✔
292
        return;
×
293
    }
294

295
    if (codeUnitCount > 0) {
219✔
296
        /* Splice into the raw code-unit storage */
297
        TextBufferInsertCodeUnits(&text->buffer, index, codeUnitBuffer, codeUnitCount);
209✔
298

299
        /* Re-derive bidi types immediately; paragraph boundaries need them as input */
300
        BidiTypesBufferReplaceRange(&text->bidiTypes, &text->buffer, index, 0, codeUnitCount);
209✔
301

302
        /* Re-derive paragraph boundaries; scripts/levels stay deferred */
303
        TextAnalysisReplaceRange(&text->analysis, &text->buffer, &text->bidiTypes, index, 0, codeUnitCount);
209✔
304

305
        /* Reserve attribute manager space */
306
        AttributeManagerReserveRange(&text->attributeManager, index, codeUnitCount);
209✔
307

308
        /* Perform immediate analysis if not in batch editing mode */
309
        if (!text->isEditing) {
209✔
310
            TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
201✔
311
        }
312
    }
313
}
314

315
void SBTextDeleteCodeUnits(SBMutableTextRef text, SBUInteger index, SBUInteger length)
17✔
316
{
317
    SBUInteger rangeEnd = index + length;
17✔
318
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
17✔
319

320
    SBAssert(text->isMutable && isRangeValid);
17✔
321

322
    if (!text->isMutable) {
17✔
323
        return;
×
324
    }
325

326
    if (length > 0) {
17✔
327
        TextBufferDeleteCodeUnits(&text->buffer, index, length);
16✔
328
        BidiTypesBufferReplaceRange(&text->bidiTypes, &text->buffer, index, length, 0);
16✔
329
        TextAnalysisReplaceRange(&text->analysis, &text->buffer, &text->bidiTypes, index, length, 0);
16✔
330
        AttributeManagerRemoveRange(&text->attributeManager, index, length);
16✔
331

332
        if (!text->isEditing) {
16✔
333
            /* Perform immediate analysis if not in batch editing mode */
334
            TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
15✔
335
        }
336
    }
337
}
338

339
void SBTextSetCodeUnits(SBMutableTextRef text,
3✔
340
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
341
{
342
    SBAssert(text->isMutable);
3✔
343

344
    if (!text->isMutable) {
3✔
345
        return;
×
346
    }
347

348
    SBTextReplaceCodeUnits(text, 0, text->buffer.codeUnits.count, codeUnitBuffer, codeUnitCount);
3✔
349
}
350

351
void SBTextReplaceCodeUnits(SBMutableTextRef text, SBUInteger index, SBUInteger length,
28✔
352
    const void *codeUnitBuffer, SBUInteger codeUnitCount)
353
{
354
    SBUInteger rangeEnd = index + length;
28✔
355
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
28✔
356

357
    SBAssert(text->isMutable && isRangeValid);
28✔
358

359
    if (!text->isMutable) {
28✔
360
        return;
×
361
    }
362

363
    if (length > 0 || codeUnitCount > 0) {
28✔
364
        TextBufferReplaceCodeUnits(&text->buffer, index, length, codeUnitBuffer, codeUnitCount);
26✔
365
        BidiTypesBufferReplaceRange(&text->bidiTypes, &text->buffer, index, length, codeUnitCount);
26✔
366
        TextAnalysisReplaceRange(&text->analysis, &text->buffer, &text->bidiTypes, index, length, codeUnitCount);
26✔
367
        AttributeManagerReplaceRange(&text->attributeManager, index, length, codeUnitCount);
26✔
368

369
        if (!text->isEditing) {
26✔
370
            /* Perform immediate analysis if not in batch editing mode */
371
            TextAnalysisFlush(&text->analysis, &text->buffer, &text->bidiTypes);
25✔
372
        }
373
    }
374
}
375

376
void SBTextSetAttribute(SBMutableTextRef text, SBUInteger index, SBUInteger length,
117✔
377
    SBAttributeID attributeID, const void *attributeValue)
378
{
379
    SBUInteger rangeEnd = index + length;
117✔
380
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
117✔
381

382
    SBAssert(text->isMutable && isRangeValid);
117✔
383

384
    if (!text->isMutable) {
117✔
385
        return;
×
386
    }
387

388
    if (length > 0) {
117✔
389
        AttributeManagerSetAttribute(&text->attributeManager,
114✔
390
            index, length, attributeID, attributeValue);
391
    }
392
}
393

394
void SBTextRemoveAttribute(SBMutableTextRef text, SBUInteger index, SBUInteger length,
15✔
395
    SBAttributeID attributeID)
396
{
397
    SBUInteger rangeEnd = index + length;
15✔
398
    SBBoolean isRangeValid = (rangeEnd <= text->buffer.codeUnits.count && index <= rangeEnd);
15✔
399

400
    SBAssert(text->isMutable && isRangeValid);
15✔
401

402
    if (!text->isMutable) {
15✔
403
        return;
×
404
    }
405

406
    if (length > 0) {
15✔
407
        AttributeManagerRemoveAttribute(&text->attributeManager, index, length, attributeID);
13✔
408
    }
409
}
410

411
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc