Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / gfx / graphite2 / src / Segment.cpp
blob62edd4250ffa953fd9cd75f5c5437d4f39daa7ae
1 /* GRAPHITE2 LICENSING
3 Copyright 2010, SIL International
4 All rights reserved.
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should also have received a copy of the GNU Lesser General Public
17 License along with this library in the file named "LICENSE".
18 If not, write to the Free Software Foundation, 51 Franklin Street,
19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20 internet at http://www.fsf.org/licenses/lgpl.html.
22 Alternatively, the contents of this file may be used under the terms of the
23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 License, as published by the Free Software Foundation, either version 2
25 of the License or (at your option) any later version.
27 #include "inc/UtfCodec.h"
28 #include <cstring>
29 #include <cstdlib>
31 #include "inc/bits.h"
32 #include "inc/Segment.h"
33 #include "graphite2/Font.h"
34 #include "inc/CharInfo.h"
35 #include "inc/debug.h"
36 #include "inc/Slot.h"
37 #include "inc/Main.h"
38 #include "inc/CmapCache.h"
39 #include "inc/Collider.h"
40 #include "graphite2/Segment.h"
43 using namespace graphite2;
45 Segment::Segment(size_t numchars, const Face* face, uint32 script, int textDir)
46 : m_freeSlots(NULL),
47 m_freeJustifies(NULL),
48 m_charinfo(new CharInfo[numchars]),
49 m_collisions(NULL),
50 m_face(face),
51 m_silf(face->chooseSilf(script)),
52 m_first(NULL),
53 m_last(NULL),
54 m_bufSize(numchars + 10),
55 m_numGlyphs(numchars),
56 m_numCharinfo(numchars),
57 m_defaultOriginal(0),
58 m_dir(textDir),
59 m_flags(((m_silf->flags() & 0x20) != 0) << 1),
60 m_passBits(m_silf->aPassBits() ? -1 : 0)
62 freeSlot(newSlot());
63 m_bufSize = log_binary(numchars)+1;
66 Segment::~Segment()
68 for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
69 free(*i);
70 for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
71 free(*i);
72 for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
73 free(*i);
74 delete[] m_charinfo;
75 free(m_collisions);
78 void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
80 Slot *aSlot = newSlot();
82 if (!aSlot) return;
83 m_charinfo[id].init(cid);
84 m_charinfo[id].feats(iFeats);
85 m_charinfo[id].base(coffset);
86 const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
87 m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0);
89 aSlot->child(NULL);
90 aSlot->setGlyph(this, gid, theGlyph);
91 aSlot->originate(id);
92 aSlot->before(id);
93 aSlot->after(id);
94 if (m_last) m_last->next(aSlot);
95 aSlot->prev(m_last);
96 m_last = aSlot;
97 if (!m_first) m_first = aSlot;
98 if (theGlyph && m_silf->aPassBits())
99 m_passBits &= theGlyph->attrs()[m_silf->aPassBits()]
100 | (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);
103 Slot *Segment::newSlot()
105 if (!m_freeSlots)
107 // check that the segment doesn't grow indefinintely
108 if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)
109 return NULL;
110 int numUser = m_silf->numUser();
111 #if !defined GRAPHITE2_NTRACING
112 if (m_face->logger()) ++numUser;
113 #endif
114 Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
115 int16 *newAttrs = grzeroalloc<int16>(m_bufSize * numUser);
116 if (!newSlots || !newAttrs)
118 free(newSlots);
119 free(newAttrs);
120 return NULL;
122 for (size_t i = 0; i < m_bufSize; i++)
124 ::new (newSlots + i) Slot(newAttrs + i * numUser);
125 newSlots[i].next(newSlots + i + 1);
127 newSlots[m_bufSize - 1].next(NULL);
128 newSlots[0].next(NULL);
129 m_slots.push_back(newSlots);
130 m_userAttrs.push_back(newAttrs);
131 m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
132 return newSlots;
134 Slot *res = m_freeSlots;
135 m_freeSlots = m_freeSlots->next();
136 res->next(NULL);
137 return res;
140 void Segment::freeSlot(Slot *aSlot)
142 if (aSlot == nullptr) return;
143 if (m_last == aSlot) m_last = aSlot->prev();
144 if (m_first == aSlot) m_first = aSlot->next();
145 if (aSlot->attachedTo())
146 aSlot->attachedTo()->removeChild(aSlot);
147 while (aSlot->firstChild())
149 if (aSlot->firstChild()->attachedTo() == aSlot)
151 aSlot->firstChild()->attachTo(nullptr);
152 aSlot->removeChild(aSlot->firstChild());
154 else
155 aSlot->firstChild(nullptr);
157 // reset the slot incase it is reused
158 ::new (aSlot) Slot(aSlot->userAttrs());
159 memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
160 // Update generation counter for debug
161 #if !defined GRAPHITE2_NTRACING
162 if (m_face->logger())
163 ++aSlot->userAttrs()[m_silf->numUser()];
164 #endif
165 // update next pointer
166 if (!m_freeSlots)
167 aSlot->next(nullptr);
168 else
169 aSlot->next(m_freeSlots);
170 m_freeSlots = aSlot;
173 SlotJustify *Segment::newJustify()
175 if (!m_freeJustifies)
177 const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());
178 byte *justs = grzeroalloc<byte>(justSize * m_bufSize);
179 if (!justs) return NULL;
180 for (ptrdiff_t i = m_bufSize - 2; i >= 0; --i)
182 SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);
183 SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1));
184 p->next = next;
186 m_freeJustifies = (SlotJustify *)justs;
187 m_justifies.push_back(m_freeJustifies);
189 SlotJustify *res = m_freeJustifies;
190 m_freeJustifies = m_freeJustifies->next;
191 res->next = NULL;
192 return res;
195 void Segment::freeJustify(SlotJustify *aJustify)
197 int numJust = m_silf->numJustLevels();
198 if (m_silf->numJustLevels() <= 0) numJust = 1;
199 aJustify->next = m_freeJustifies;
200 memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16));
201 m_freeJustifies = aJustify;
204 // reverse the slots but keep diacritics in their same position after their bases
205 void Segment::reverseSlots()
207 m_dir = m_dir ^ 64; // invert the reverse flag
208 if (m_first == m_last) return; // skip 0 or 1 glyph runs
210 Slot *t = 0;
211 Slot *curr = m_first;
212 Slot *tlast;
213 Slot *tfirst;
214 Slot *out = 0;
216 while (curr && getSlotBidiClass(curr) == 16)
217 curr = curr->next();
218 if (!curr) return;
219 tfirst = curr->prev();
220 tlast = curr;
222 while (curr)
224 if (getSlotBidiClass(curr) == 16)
226 Slot *d = curr->next();
227 while (d && getSlotBidiClass(d) == 16)
228 d = d->next();
230 d = d ? d->prev() : m_last;
231 Slot *p = out->next(); // one after the diacritics. out can't be null
232 if (p)
233 p->prev(d);
234 else
235 tlast = d;
236 t = d->next();
237 d->next(p);
238 curr->prev(out);
239 out->next(curr);
241 else // will always fire first time round the loop
243 if (out)
244 out->prev(curr);
245 t = curr->next();
246 curr->next(out);
247 out = curr;
249 curr = t;
251 out->prev(tfirst);
252 if (tfirst)
253 tfirst->next(out);
254 else
255 m_first = out;
256 m_last = tlast;
259 void Segment::linkClusters(Slot *s, Slot * end)
261 end = end->next();
263 for (; s != end && !s->isBase(); s = s->next());
264 Slot * ls = s;
266 if (m_dir & 1)
268 for (; s != end; s = s->next())
270 if (!s->isBase()) continue;
272 s->sibling(ls);
273 ls = s;
276 else
278 for (; s != end; s = s->next())
280 if (!s->isBase()) continue;
282 ls->sibling(s);
283 ls = s;
288 Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
290 Position currpos(0., 0.);
291 float clusterMin = 0.;
292 Rect bbox;
293 bool reorder = (currdir() != isRtl);
295 if (reorder)
297 Slot *temp;
298 reverseSlots();
299 temp = iStart;
300 iStart = iEnd;
301 iEnd = temp;
303 if (!iStart) iStart = m_first;
304 if (!iEnd) iEnd = m_last;
306 if (!iStart || !iEnd) // only true for empty segments
307 return currpos;
309 if (isRtl)
311 for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
313 if (s->isBase())
314 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
317 else
319 for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
321 if (s->isBase())
322 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
325 if (reorder)
326 reverseSlots();
327 return currpos;
331 void Segment::associateChars(int offset, size_t numChars)
333 int i = 0, j = 0;
334 CharInfo *c, *cend;
335 for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)
337 c->before(-1);
338 c->after(-1);
340 for (Slot * s = m_first; s; s->index(i++), s = s->next())
342 j = s->before();
343 if (j < 0) continue;
345 for (const int after = s->after(); j <= after; ++j)
347 c = charinfo(j);
348 if (c->before() == -1 || i < c->before()) c->before(i);
349 if (c->after() < i) c->after(i);
352 for (Slot *s = m_first; s; s = s->next())
354 int a;
355 for (a = s->after() + 1; a < offset + int(numChars) && charinfo(a)->after() < 0; ++a)
356 { charinfo(a)->after(s->index()); }
357 --a;
358 s->after(a);
360 for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)
361 { charinfo(a)->before(s->index()); }
362 ++a;
363 s->before(a);
368 template <typename utf_iter>
369 inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
371 const Cmap & cmap = face.cmap();
372 int slotid = 0;
374 const typename utf_iter::codeunit_type * const base = c;
375 for (; n_chars; --n_chars, ++c, ++slotid)
377 const uint32 usv = *c;
378 uint16 gid = cmap[usv];
379 if (!gid) gid = face.findPseudo(usv);
380 seg.appendSlot(slotid, usv, gid, fid, c - base);
385 bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
387 assert(face);
388 assert(pFeats);
389 if (!m_charinfo) return false;
391 // utf iterator is self recovering so we don't care about the error state of the iterator.
392 switch (enc)
394 case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
395 case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
396 case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
398 return true;
401 void Segment::doMirror(uint16 aMirror)
403 Slot * s;
404 for (s = m_first; s; s = s->next())
406 unsigned short g = glyphAttr(s->gid(), aMirror);
407 if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
408 s->setGlyph(this, g);
412 bool Segment::initCollisions()
414 m_collisions = grzeroalloc<SlotCollision>(slotCount());
415 if (!m_collisions) return false;
417 for (Slot *p = m_first; p; p = p->next())
418 if (p->index() < slotCount())
419 ::new (collisionInfo(p)) SlotCollision(this, p);
420 else
421 return false;
422 return true;