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
20using namespace graphite2;
21
22Segment::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
43Segment::~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
55void 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
80Slot *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
117void 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
150SlotJustify *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
172void 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
182void 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
236void 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
265Position 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
308void 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
345template <typename utf_iter>
346inline 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
362bool 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
378void 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
389bool 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