Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/graphite/src/Segment.cpp
9902 views
1
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later
2
// Copyright 2010, SIL International, All rights reserved.
3
4
#include "inc/UtfCodec.h"
5
#include <cstring>
6
#include <cstdlib>
7
8
#include "inc/bits.h"
9
#include "inc/Segment.h"
10
#include "graphite2/Font.h"
11
#include "inc/CharInfo.h"
12
#include "inc/debug.h"
13
#include "inc/Slot.h"
14
#include "inc/Main.h"
15
#include "inc/CmapCache.h"
16
#include "inc/Collider.h"
17
#include "graphite2/Segment.h"
18
19
20
using namespace graphite2;
21
22
Segment::Segment(size_t numchars, const Face* face, uint32 script, int textDir)
23
: m_freeSlots(NULL),
24
m_freeJustifies(NULL),
25
m_charinfo(new CharInfo[numchars]),
26
m_collisions(NULL),
27
m_face(face),
28
m_silf(face->chooseSilf(script)),
29
m_first(NULL),
30
m_last(NULL),
31
m_bufSize(numchars + 10),
32
m_numGlyphs(numchars),
33
m_numCharinfo(numchars),
34
m_defaultOriginal(0),
35
m_dir(textDir),
36
m_flags(((m_silf->flags() & 0x20) != 0) << 1),
37
m_passBits(m_silf->aPassBits() ? -1 : 0)
38
{
39
freeSlot(newSlot());
40
m_bufSize = log_binary(numchars)+1;
41
}
42
43
Segment::~Segment()
44
{
45
for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
46
free(*i);
47
for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
48
free(*i);
49
for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
50
free(*i);
51
delete[] m_charinfo;
52
free(m_collisions);
53
}
54
55
void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
56
{
57
Slot *aSlot = newSlot();
58
59
if (!aSlot) return;
60
m_charinfo[id].init(cid);
61
m_charinfo[id].feats(iFeats);
62
m_charinfo[id].base(coffset);
63
const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
64
m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0);
65
66
aSlot->child(NULL);
67
aSlot->setGlyph(this, gid, theGlyph);
68
aSlot->originate(id);
69
aSlot->before(id);
70
aSlot->after(id);
71
if (m_last) m_last->next(aSlot);
72
aSlot->prev(m_last);
73
m_last = aSlot;
74
if (!m_first) m_first = aSlot;
75
if (theGlyph && m_silf->aPassBits())
76
m_passBits &= theGlyph->attrs()[m_silf->aPassBits()]
77
| (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);
78
}
79
80
Slot *Segment::newSlot()
81
{
82
if (!m_freeSlots)
83
{
84
// check that the segment doesn't grow indefinintely
85
if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)
86
return NULL;
87
int numUser = m_silf->numUser();
88
#if !defined GRAPHITE2_NTRACING
89
if (m_face->logger()) ++numUser;
90
#endif
91
Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
92
int16 *newAttrs = grzeroalloc<int16>(m_bufSize * numUser);
93
if (!newSlots || !newAttrs)
94
{
95
free(newSlots);
96
free(newAttrs);
97
return NULL;
98
}
99
for (size_t i = 0; i < m_bufSize; i++)
100
{
101
::new (newSlots + i) Slot(newAttrs + i * numUser);
102
newSlots[i].next(newSlots + i + 1);
103
}
104
newSlots[m_bufSize - 1].next(NULL);
105
newSlots[0].next(NULL);
106
m_slots.push_back(newSlots);
107
m_userAttrs.push_back(newAttrs);
108
m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
109
return newSlots;
110
}
111
Slot *res = m_freeSlots;
112
m_freeSlots = m_freeSlots->next();
113
res->next(NULL);
114
return res;
115
}
116
117
void Segment::freeSlot(Slot *aSlot)
118
{
119
if (aSlot == nullptr) return;
120
if (m_last == aSlot) m_last = aSlot->prev();
121
if (m_first == aSlot) m_first = aSlot->next();
122
if (aSlot->attachedTo())
123
aSlot->attachedTo()->removeChild(aSlot);
124
while (aSlot->firstChild())
125
{
126
if (aSlot->firstChild()->attachedTo() == aSlot)
127
{
128
aSlot->firstChild()->attachTo(nullptr);
129
aSlot->removeChild(aSlot->firstChild());
130
}
131
else
132
aSlot->firstChild(nullptr);
133
}
134
// reset the slot incase it is reused
135
::new (aSlot) Slot(aSlot->userAttrs());
136
memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
137
// Update generation counter for debug
138
#if !defined GRAPHITE2_NTRACING
139
if (m_face->logger())
140
++aSlot->userAttrs()[m_silf->numUser()];
141
#endif
142
// update next pointer
143
if (!m_freeSlots)
144
aSlot->next(nullptr);
145
else
146
aSlot->next(m_freeSlots);
147
m_freeSlots = aSlot;
148
}
149
150
SlotJustify *Segment::newJustify()
151
{
152
if (!m_freeJustifies)
153
{
154
const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());
155
byte *justs = grzeroalloc<byte>(justSize * m_bufSize);
156
if (!justs) return NULL;
157
for (ptrdiff_t i = m_bufSize - 2; i >= 0; --i)
158
{
159
SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);
160
SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1));
161
p->next = next;
162
}
163
m_freeJustifies = (SlotJustify *)justs;
164
m_justifies.push_back(m_freeJustifies);
165
}
166
SlotJustify *res = m_freeJustifies;
167
m_freeJustifies = m_freeJustifies->next;
168
res->next = NULL;
169
return res;
170
}
171
172
void Segment::freeJustify(SlotJustify *aJustify)
173
{
174
int numJust = m_silf->numJustLevels();
175
if (m_silf->numJustLevels() <= 0) numJust = 1;
176
aJustify->next = m_freeJustifies;
177
memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16));
178
m_freeJustifies = aJustify;
179
}
180
181
// reverse the slots but keep diacritics in their same position after their bases
182
void Segment::reverseSlots()
183
{
184
m_dir = m_dir ^ 64; // invert the reverse flag
185
if (m_first == m_last) return; // skip 0 or 1 glyph runs
186
187
Slot *t = 0;
188
Slot *curr = m_first;
189
Slot *tlast;
190
Slot *tfirst;
191
Slot *out = 0;
192
193
while (curr && getSlotBidiClass(curr) == 16)
194
curr = curr->next();
195
if (!curr) return;
196
tfirst = curr->prev();
197
tlast = curr;
198
199
while (curr)
200
{
201
if (getSlotBidiClass(curr) == 16)
202
{
203
Slot *d = curr->next();
204
while (d && getSlotBidiClass(d) == 16)
205
d = d->next();
206
207
d = d ? d->prev() : m_last;
208
Slot *p = out->next(); // one after the diacritics. out can't be null
209
if (p)
210
p->prev(d);
211
else
212
tlast = d;
213
t = d->next();
214
d->next(p);
215
curr->prev(out);
216
out->next(curr);
217
}
218
else // will always fire first time round the loop
219
{
220
if (out)
221
out->prev(curr);
222
t = curr->next();
223
curr->next(out);
224
out = curr;
225
}
226
curr = t;
227
}
228
out->prev(tfirst);
229
if (tfirst)
230
tfirst->next(out);
231
else
232
m_first = out;
233
m_last = tlast;
234
}
235
236
void Segment::linkClusters(Slot *s, Slot * end)
237
{
238
end = end->next();
239
240
for (; s != end && !s->isBase(); s = s->next());
241
Slot * ls = s;
242
243
if (m_dir & 1)
244
{
245
for (; s != end; s = s->next())
246
{
247
if (!s->isBase()) continue;
248
249
s->sibling(ls);
250
ls = s;
251
}
252
}
253
else
254
{
255
for (; s != end; s = s->next())
256
{
257
if (!s->isBase()) continue;
258
259
ls->sibling(s);
260
ls = s;
261
}
262
}
263
}
264
265
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
266
{
267
Position currpos(0., 0.);
268
float clusterMin = 0.;
269
Rect bbox;
270
bool reorder = (currdir() != isRtl);
271
272
if (reorder)
273
{
274
Slot *temp;
275
reverseSlots();
276
temp = iStart;
277
iStart = iEnd;
278
iEnd = temp;
279
}
280
if (!iStart) iStart = m_first;
281
if (!iEnd) iEnd = m_last;
282
283
if (!iStart || !iEnd) // only true for empty segments
284
return currpos;
285
286
if (isRtl)
287
{
288
for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
289
{
290
if (s->isBase())
291
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
292
}
293
}
294
else
295
{
296
for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
297
{
298
if (s->isBase())
299
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
300
}
301
}
302
if (reorder)
303
reverseSlots();
304
return currpos;
305
}
306
307
308
void Segment::associateChars(int offset, size_t numChars)
309
{
310
int i = 0, j = 0;
311
CharInfo *c, *cend;
312
for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)
313
{
314
c->before(-1);
315
c->after(-1);
316
}
317
for (Slot * s = m_first; s; s->index(i++), s = s->next())
318
{
319
j = s->before();
320
if (j < 0) continue;
321
322
for (const int after = s->after(); j <= after; ++j)
323
{
324
c = charinfo(j);
325
if (c->before() == -1 || i < c->before()) c->before(i);
326
if (c->after() < i) c->after(i);
327
}
328
}
329
for (Slot *s = m_first; s; s = s->next())
330
{
331
int a;
332
for (a = s->after() + 1; a < offset + int(numChars) && charinfo(a)->after() < 0; ++a)
333
{ charinfo(a)->after(s->index()); }
334
--a;
335
s->after(a);
336
337
for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)
338
{ charinfo(a)->before(s->index()); }
339
++a;
340
s->before(a);
341
}
342
}
343
344
345
template <typename utf_iter>
346
inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
347
{
348
const Cmap & cmap = face.cmap();
349
int slotid = 0;
350
351
const typename utf_iter::codeunit_type * const base = c;
352
for (; n_chars; --n_chars, ++c, ++slotid)
353
{
354
const uint32 usv = *c;
355
uint16 gid = cmap[usv];
356
if (!gid) gid = face.findPseudo(usv);
357
seg.appendSlot(slotid, usv, gid, fid, c - base);
358
}
359
}
360
361
362
bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
363
{
364
assert(face);
365
assert(pFeats);
366
if (!m_charinfo) return false;
367
368
// utf iterator is self recovering so we don't care about the error state of the iterator.
369
switch (enc)
370
{
371
case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
372
case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
373
case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
374
}
375
return true;
376
}
377
378
void Segment::doMirror(uint16 aMirror)
379
{
380
Slot * s;
381
for (s = m_first; s; s = s->next())
382
{
383
unsigned short g = glyphAttr(s->gid(), aMirror);
384
if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
385
s->setGlyph(this, g);
386
}
387
}
388
389
bool Segment::initCollisions()
390
{
391
m_collisions = grzeroalloc<SlotCollision>(slotCount());
392
if (!m_collisions) return false;
393
394
for (Slot *p = m_first; p; p = p->next())
395
if (p->index() < slotCount())
396
::new (collisionInfo(p)) SlotCollision(this, p);
397
else
398
return false;
399
return true;
400
}
401
402