|
1 /* GRAPHITE2 LICENSING |
|
2 |
|
3 Copyright 2010, SIL International |
|
4 All rights reserved. |
|
5 |
|
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. |
|
10 |
|
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. |
|
15 |
|
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. |
|
21 |
|
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. |
|
26 */ |
|
27 #include "inc/UtfCodec.h" |
|
28 #include <cstring> |
|
29 #include <cstdlib> |
|
30 |
|
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/Bidi.h" |
|
40 #include "graphite2/Segment.h" |
|
41 |
|
42 |
|
43 using namespace graphite2; |
|
44 |
|
45 Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int textDir) |
|
46 : m_freeSlots(NULL), |
|
47 m_freeJustifies(NULL), |
|
48 m_charinfo(new CharInfo[numchars]), |
|
49 m_face(face), |
|
50 m_silf(face->chooseSilf(script)), |
|
51 m_first(NULL), |
|
52 m_last(NULL), |
|
53 m_bufSize(numchars + 10), |
|
54 m_numGlyphs(numchars), |
|
55 m_numCharinfo(numchars), |
|
56 m_passBits(m_silf->aPassBits() ? -1 : 0), |
|
57 m_defaultOriginal(0), |
|
58 m_dir(textDir) |
|
59 { |
|
60 freeSlot(newSlot()); |
|
61 m_bufSize = log_binary(numchars)+1; |
|
62 } |
|
63 |
|
64 Segment::~Segment() |
|
65 { |
|
66 for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i) |
|
67 free(*i); |
|
68 for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j) |
|
69 free(*j); |
|
70 delete[] m_charinfo; |
|
71 } |
|
72 |
|
73 #ifndef GRAPHITE2_NSEGCACHE |
|
74 SegmentScopeState Segment::setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength) |
|
75 { |
|
76 SegmentScopeState state; |
|
77 state.numGlyphsOutsideScope = m_numGlyphs - subLength; |
|
78 state.realFirstSlot = m_first; |
|
79 state.slotBeforeScope = firstSlot->prev(); |
|
80 state.slotAfterScope = lastSlot->next(); |
|
81 state.realLastSlot = m_last; |
|
82 firstSlot->prev(NULL); |
|
83 lastSlot->next(NULL); |
|
84 assert(m_defaultOriginal == 0); |
|
85 m_defaultOriginal = firstSlot->original(); |
|
86 m_numGlyphs = subLength; |
|
87 m_first = firstSlot; |
|
88 m_last = lastSlot; |
|
89 return state; |
|
90 } |
|
91 |
|
92 void Segment::removeScope(SegmentScopeState & state) |
|
93 { |
|
94 m_numGlyphs = state.numGlyphsOutsideScope + m_numGlyphs; |
|
95 if (state.slotBeforeScope) |
|
96 { |
|
97 state.slotBeforeScope->next(m_first); |
|
98 m_first->prev(state.slotBeforeScope); |
|
99 m_first = state.realFirstSlot; |
|
100 } |
|
101 if (state.slotAfterScope) |
|
102 { |
|
103 state.slotAfterScope->prev(m_last); |
|
104 m_last->next(state.slotAfterScope); |
|
105 m_last = state.realLastSlot; |
|
106 } |
|
107 m_defaultOriginal = 0; |
|
108 } |
|
109 |
|
110 #if 0 |
|
111 void Segment::append(const Segment &other) |
|
112 { |
|
113 Rect bbox = other.m_bbox + m_advance; |
|
114 |
|
115 m_slots.insert(m_slots.end(), other.m_slots.begin(), other.m_slots.end()); |
|
116 CharInfo* pNewCharInfo = new CharInfo[m_numCharinfo+other.m_numCharinfo]; //since CharInfo has no constructor, this doesn't do much |
|
117 for (unsigned int i=0 ; i<m_numCharinfo ; ++i) |
|
118 pNewCharInfo[i] = m_charinfo[i]; |
|
119 m_last->next(other.m_first); |
|
120 other.m_last->prev(m_last); |
|
121 m_userAttrs.insert(m_userAttrs.end(), other.m_userAttrs.begin(), other.m_userAttrs.end()); |
|
122 |
|
123 delete[] m_charinfo; |
|
124 m_charinfo = pNewCharInfo; |
|
125 pNewCharInfo += m_numCharinfo ; |
|
126 for (unsigned int i=0 ; i<m_numCharinfo ; ++i) |
|
127 pNewCharInfo[i] = other.m_charinfo[i]; |
|
128 |
|
129 m_numCharinfo += other.m_numCharinfo; |
|
130 m_numGlyphs += other.m_numGlyphs; |
|
131 m_advance = m_advance + other.m_advance; |
|
132 m_bbox = m_bbox.widen(bbox); |
|
133 m_passBits &= other.passBits(); |
|
134 } |
|
135 #endif |
|
136 #endif // GRAPHITE2_NSEGCACHE |
|
137 |
|
138 void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset) |
|
139 { |
|
140 Slot *aSlot = newSlot(); |
|
141 |
|
142 if (!aSlot) return; |
|
143 m_charinfo[id].init(cid); |
|
144 m_charinfo[id].feats(iFeats); |
|
145 m_charinfo[id].base(coffset); |
|
146 const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid); |
|
147 m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0); |
|
148 |
|
149 aSlot->child(NULL); |
|
150 aSlot->setGlyph(this, gid, theGlyph); |
|
151 aSlot->originate(id); |
|
152 aSlot->before(id); |
|
153 aSlot->after(id); |
|
154 if (m_last) m_last->next(aSlot); |
|
155 aSlot->prev(m_last); |
|
156 m_last = aSlot; |
|
157 if (!m_first) m_first = aSlot; |
|
158 if (theGlyph && m_silf->aPassBits()) |
|
159 m_passBits &= theGlyph->attrs()[m_silf->aPassBits()] |
|
160 | (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0); |
|
161 } |
|
162 |
|
163 Slot *Segment::newSlot() |
|
164 { |
|
165 if (!m_freeSlots) |
|
166 { |
|
167 int numUser = m_silf->numUser(); |
|
168 #if !defined GRAPHITE2_NTRACING |
|
169 if (m_face->logger()) ++numUser; |
|
170 #endif |
|
171 Slot *newSlots = grzeroalloc<Slot>(m_bufSize); |
|
172 int16 *newAttrs = grzeroalloc<int16>(numUser * m_bufSize); |
|
173 if (!newSlots || !newAttrs) return NULL; |
|
174 for (size_t i = 0; i < m_bufSize; i++) |
|
175 { |
|
176 newSlots[i].next(newSlots + i + 1); |
|
177 newSlots[i].userAttrs(newAttrs + i * numUser); |
|
178 newSlots[i].setBidiClass(-1); |
|
179 } |
|
180 newSlots[m_bufSize - 1].next(NULL); |
|
181 newSlots[0].next(NULL); |
|
182 m_slots.push_back(newSlots); |
|
183 m_userAttrs.push_back(newAttrs); |
|
184 m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL; |
|
185 return newSlots; |
|
186 } |
|
187 Slot *res = m_freeSlots; |
|
188 m_freeSlots = m_freeSlots->next(); |
|
189 res->next(NULL); |
|
190 return res; |
|
191 } |
|
192 |
|
193 void Segment::freeSlot(Slot *aSlot) |
|
194 { |
|
195 if (m_last == aSlot) m_last = aSlot->prev(); |
|
196 if (m_first == aSlot) m_first = aSlot->next(); |
|
197 if (aSlot->attachedTo()) |
|
198 aSlot->attachedTo()->removeChild(aSlot); |
|
199 while (aSlot->firstChild()) |
|
200 { |
|
201 aSlot->firstChild()->attachTo(NULL); |
|
202 aSlot->removeChild(aSlot->firstChild()); |
|
203 } |
|
204 // reset the slot incase it is reused |
|
205 ::new (aSlot) Slot; |
|
206 memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16)); |
|
207 // Update generation counter for debug |
|
208 #if !defined GRAPHITE2_NTRACING |
|
209 if (m_face->logger()) |
|
210 ++aSlot->userAttrs()[m_silf->numUser()]; |
|
211 #endif |
|
212 // update next pointer |
|
213 if (!m_freeSlots) |
|
214 aSlot->next(NULL); |
|
215 else |
|
216 aSlot->next(m_freeSlots); |
|
217 m_freeSlots = aSlot; |
|
218 } |
|
219 |
|
220 SlotJustify *Segment::newJustify() |
|
221 { |
|
222 if (!m_freeJustifies) |
|
223 { |
|
224 const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels()); |
|
225 byte *justs = grzeroalloc<byte>(justSize * m_bufSize); |
|
226 if (!justs) return NULL; |
|
227 for (int i = m_bufSize - 2; i >= 0; --i) |
|
228 { |
|
229 SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i); |
|
230 SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1)); |
|
231 p->next = next; |
|
232 } |
|
233 m_freeJustifies = (SlotJustify *)justs; |
|
234 m_justifies.push_back(m_freeJustifies); |
|
235 } |
|
236 SlotJustify *res = m_freeJustifies; |
|
237 m_freeJustifies = m_freeJustifies->next; |
|
238 res->next = NULL; |
|
239 return res; |
|
240 } |
|
241 |
|
242 void Segment::freeJustify(SlotJustify *aJustify) |
|
243 { |
|
244 int numJust = m_silf->numJustLevels(); |
|
245 if (m_silf->numJustLevels() <= 0) numJust = 1; |
|
246 aJustify->next = m_freeJustifies; |
|
247 memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16)); |
|
248 m_freeJustifies = aJustify; |
|
249 } |
|
250 |
|
251 #ifndef GRAPHITE2_NSEGCACHE |
|
252 void Segment::splice(size_t offset, size_t length, Slot * const startSlot, |
|
253 Slot * endSlot, const Slot * srcSlot, |
|
254 const size_t numGlyphs) |
|
255 { |
|
256 size_t numChars = length; |
|
257 extendLength(numGlyphs - length); |
|
258 // remove any extra |
|
259 if (numGlyphs < length) |
|
260 { |
|
261 Slot * end = endSlot->next(); |
|
262 do |
|
263 { |
|
264 endSlot = endSlot->prev(); |
|
265 freeSlot(endSlot->next()); |
|
266 } while (numGlyphs < --length); |
|
267 endSlot->next(end); |
|
268 if (end) |
|
269 end->prev(endSlot); |
|
270 } |
|
271 else |
|
272 { |
|
273 // insert extra slots if needed |
|
274 while (numGlyphs > length) |
|
275 { |
|
276 Slot * extra = newSlot(); |
|
277 if (!extra) return; |
|
278 extra->prev(endSlot); |
|
279 extra->next(endSlot->next()); |
|
280 endSlot->next(extra); |
|
281 if (extra->next()) |
|
282 extra->next()->prev(extra); |
|
283 if (m_last == endSlot) |
|
284 m_last = extra; |
|
285 endSlot = extra; |
|
286 ++length; |
|
287 } |
|
288 } |
|
289 |
|
290 endSlot = endSlot->next(); |
|
291 assert(numGlyphs == length); |
|
292 assert(offset + numChars <= m_numCharinfo); |
|
293 Slot * indexmap[eMaxSpliceSize*3]; |
|
294 assert(numGlyphs < sizeof indexmap/sizeof *indexmap); |
|
295 Slot * slot = startSlot; |
|
296 for (uint16 i=0; i < numGlyphs; slot = slot->next(), ++i) |
|
297 indexmap[i] = slot; |
|
298 |
|
299 for (slot = startSlot; slot != endSlot; slot = slot->next(), srcSlot = srcSlot->next()) |
|
300 { |
|
301 slot->set(*srcSlot, offset, m_silf->numUser(), m_silf->numJustLevels(), numChars); |
|
302 if (srcSlot->attachedTo()) slot->attachTo(indexmap[srcSlot->attachedTo()->index()]); |
|
303 if (srcSlot->nextSibling()) slot->m_sibling = indexmap[srcSlot->nextSibling()->index()]; |
|
304 if (srcSlot->firstChild()) slot->m_child = indexmap[srcSlot->firstChild()->index()]; |
|
305 } |
|
306 } |
|
307 #endif // GRAPHITE2_NSEGCACHE |
|
308 |
|
309 void Segment::linkClusters(Slot *s, Slot * end) |
|
310 { |
|
311 end = end->next(); |
|
312 |
|
313 for (; s != end && !s->isBase(); s = s->next()); |
|
314 Slot * ls = s; |
|
315 |
|
316 if (m_dir & 1) |
|
317 { |
|
318 for (; s != end; s = s->next()) |
|
319 { |
|
320 if (!s->isBase()) continue; |
|
321 |
|
322 s->sibling(ls); |
|
323 ls = s; |
|
324 } |
|
325 } |
|
326 else |
|
327 { |
|
328 for (; s != end; s = s->next()) |
|
329 { |
|
330 if (!s->isBase()) continue; |
|
331 |
|
332 ls->sibling(s); |
|
333 ls = s; |
|
334 } |
|
335 } |
|
336 } |
|
337 |
|
338 Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd) |
|
339 { |
|
340 Position currpos(0., 0.); |
|
341 float clusterMin = 0.; |
|
342 Rect bbox; |
|
343 |
|
344 if (!iStart) iStart = m_first; |
|
345 if (!iEnd) iEnd = m_last; |
|
346 |
|
347 if (m_dir & 1) |
|
348 { |
|
349 for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev()) |
|
350 { |
|
351 if (s->isBase()) |
|
352 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x); |
|
353 } |
|
354 } |
|
355 else |
|
356 { |
|
357 for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next()) |
|
358 { |
|
359 if (s->isBase()) |
|
360 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x); |
|
361 } |
|
362 } |
|
363 return currpos; |
|
364 } |
|
365 |
|
366 |
|
367 void Segment::associateChars(int offset, int numChars) |
|
368 { |
|
369 int i = 0, j = 0; |
|
370 CharInfo *c, *cend; |
|
371 for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c) |
|
372 { |
|
373 c->before(-1); |
|
374 c->after(-1); |
|
375 } |
|
376 for (Slot * s = m_first; s; s->index(i++), s = s->next()) |
|
377 { |
|
378 j = s->before(); |
|
379 if (j < 0) continue; |
|
380 |
|
381 for (const int after = s->after(); j <= after; ++j) |
|
382 { |
|
383 c = charinfo(j); |
|
384 if (c->before() == -1 || i < c->before()) c->before(i); |
|
385 if (c->after() < i) c->after(i); |
|
386 } |
|
387 } |
|
388 for (Slot *s = m_first; s; s = s->next()) |
|
389 { |
|
390 int a; |
|
391 for (a = s->after() + 1; a < offset + numChars && charinfo(a)->after() < 0; ++a) |
|
392 { charinfo(a)->after(s->index()); } |
|
393 --a; |
|
394 s->after(a); |
|
395 |
|
396 for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a) |
|
397 { charinfo(a)->before(s->index()); } |
|
398 ++a; |
|
399 s->before(a); |
|
400 } |
|
401 } |
|
402 |
|
403 |
|
404 template <typename utf_iter> |
|
405 inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars) |
|
406 { |
|
407 const Cmap & cmap = face.cmap(); |
|
408 int slotid = 0; |
|
409 |
|
410 const typename utf_iter::codeunit_type * const base = c; |
|
411 for (; n_chars; --n_chars, ++c, ++slotid) |
|
412 { |
|
413 const uint32 usv = *c; |
|
414 uint16 gid = cmap[usv]; |
|
415 if (!gid) gid = face.findPseudo(usv); |
|
416 seg.appendSlot(slotid, usv, gid, fid, c - base); |
|
417 } |
|
418 } |
|
419 |
|
420 |
|
421 bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars) |
|
422 { |
|
423 assert(face); |
|
424 assert(pFeats); |
|
425 if (!m_charinfo) return false; |
|
426 |
|
427 // utf iterator is self recovering so we don't care about the error state of the iterator. |
|
428 switch (enc) |
|
429 { |
|
430 case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break; |
|
431 case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break; |
|
432 case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break; |
|
433 } |
|
434 return true; |
|
435 } |
|
436 |
|
437 void Segment::prepare_pos(const Font * /*font*/) |
|
438 { |
|
439 // copy key changeable metrics into slot (if any); |
|
440 } |
|
441 |
|
442 Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &stack); |
|
443 void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror); |
|
444 void resolveWhitespace(int baseLevel, Slot *s); |
|
445 Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0); |
|
446 |
|
447 void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror) |
|
448 { |
|
449 if (slotCount() == 0) |
|
450 return; |
|
451 |
|
452 Slot *s; |
|
453 int baseLevel = paradir ? 1 : 0; |
|
454 unsigned int bmask = 0; |
|
455 unsigned int ssize = 0; |
|
456 for (s = first(); s; s = s->next()) |
|
457 { |
|
458 if (s->getBidiClass() == -1) |
|
459 { |
|
460 unsigned int bAttr = glyphAttr(s->gid(), aBidi); |
|
461 s->setBidiClass((bAttr <= 22) * bAttr); |
|
462 } |
|
463 bmask |= (1 << s->getBidiClass()); |
|
464 s->setBidiLevel(baseLevel); |
|
465 if (glyphAttr(s->gid(), aMirror) && s->getBidiClass() == 21) |
|
466 ++ssize; |
|
467 } |
|
468 |
|
469 BracketPairStack bstack(ssize); |
|
470 if (bmask & (paradir ? 0x2E7892 : 0x2E789C)) |
|
471 { |
|
472 // O(8N) algorithm, with no working data beyond what is needed for processParens |
|
473 int nextLevel = paradir; |
|
474 int e, i, c; |
|
475 process_bidi(first(), baseLevel, paradir, nextLevel, 0, 0, c = 0, i = 0, e = 0, 1, this, aMirror, bstack); |
|
476 resolveImplicit(first(), this, aMirror); |
|
477 resolveWhitespace(baseLevel, last()); |
|
478 s = resolveOrder(s = first(), baseLevel != 0); |
|
479 if (s) |
|
480 { |
|
481 first(s); last(s->prev()); |
|
482 s->prev()->next(0); s->prev(0); |
|
483 } |
|
484 } |
|
485 else if (!(dir() & 4) && baseLevel && aMirror) |
|
486 { |
|
487 for (s = first(); s; s = s->next()) |
|
488 { |
|
489 unsigned short g = glyphAttr(s->gid(), aMirror); |
|
490 if (g) s->setGlyph(this, g); |
|
491 } |
|
492 } |
|
493 } |
|
494 |