Segment.cpp (12384B)
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/Collider.h" 40 #include "graphite2/Segment.h" 41 42 43 using namespace graphite2; 44 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) 61 { 62 freeSlot(newSlot()); 63 m_bufSize = log_binary(numchars)+1; 64 } 65 66 Segment::~Segment() 67 { 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); 76 } 77 78 void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset) 79 { 80 Slot *aSlot = newSlot(); 81 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); 88 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); 101 } 102 103 Slot *Segment::newSlot() 104 { 105 if (!m_freeSlots) 106 { 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) 117 { 118 free(newSlots); 119 free(newAttrs); 120 return NULL; 121 } 122 for (size_t i = 0; i < m_bufSize; i++) 123 { 124 ::new (newSlots + i) Slot(newAttrs + i * numUser); 125 newSlots[i].next(newSlots + i + 1); 126 } 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; 133 } 134 Slot *res = m_freeSlots; 135 m_freeSlots = m_freeSlots->next(); 136 res->next(NULL); 137 return res; 138 } 139 140 void Segment::freeSlot(Slot *aSlot) 141 { 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()) 148 { 149 if (aSlot->firstChild()->attachedTo() == aSlot) 150 { 151 aSlot->firstChild()->attachTo(nullptr); 152 aSlot->removeChild(aSlot->firstChild()); 153 } 154 else 155 aSlot->firstChild(nullptr); 156 } 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; 171 } 172 173 SlotJustify *Segment::newJustify() 174 { 175 if (!m_freeJustifies) 176 { 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) 181 { 182 SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i); 183 SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1)); 184 p->next = next; 185 } 186 m_freeJustifies = (SlotJustify *)justs; 187 m_justifies.push_back(m_freeJustifies); 188 } 189 SlotJustify *res = m_freeJustifies; 190 m_freeJustifies = m_freeJustifies->next; 191 res->next = NULL; 192 return res; 193 } 194 195 void Segment::freeJustify(SlotJustify *aJustify) 196 { 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; 202 } 203 204 // reverse the slots but keep diacritics in their same position after their bases 205 void Segment::reverseSlots() 206 { 207 m_dir = m_dir ^ 64; // invert the reverse flag 208 if (m_first == m_last) return; // skip 0 or 1 glyph runs 209 210 Slot *t = 0; 211 Slot *curr = m_first; 212 Slot *tlast; 213 Slot *tfirst; 214 Slot *out = 0; 215 216 while (curr && getSlotBidiClass(curr) == 16) 217 curr = curr->next(); 218 if (!curr) return; 219 tfirst = curr->prev(); 220 tlast = curr; 221 222 while (curr) 223 { 224 if (getSlotBidiClass(curr) == 16) 225 { 226 Slot *d = curr->next(); 227 while (d && getSlotBidiClass(d) == 16) 228 d = d->next(); 229 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); 240 } 241 else // will always fire first time round the loop 242 { 243 if (out) 244 out->prev(curr); 245 t = curr->next(); 246 curr->next(out); 247 out = curr; 248 } 249 curr = t; 250 } 251 out->prev(tfirst); 252 if (tfirst) 253 tfirst->next(out); 254 else 255 m_first = out; 256 m_last = tlast; 257 } 258 259 void Segment::linkClusters(Slot *s, Slot * end) 260 { 261 end = end->next(); 262 263 for (; s != end && !s->isBase(); s = s->next()); 264 Slot * ls = s; 265 266 if (m_dir & 1) 267 { 268 for (; s != end; s = s->next()) 269 { 270 if (!s->isBase()) continue; 271 272 s->sibling(ls); 273 ls = s; 274 } 275 } 276 else 277 { 278 for (; s != end; s = s->next()) 279 { 280 if (!s->isBase()) continue; 281 282 ls->sibling(s); 283 ls = s; 284 } 285 } 286 } 287 288 Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal) 289 { 290 Position currpos(0., 0.); 291 float clusterMin = 0.; 292 Rect bbox; 293 bool reorder = (currdir() != isRtl); 294 295 if (reorder) 296 { 297 Slot *temp; 298 reverseSlots(); 299 temp = iStart; 300 iStart = iEnd; 301 iEnd = temp; 302 } 303 if (!iStart) iStart = m_first; 304 if (!iEnd) iEnd = m_last; 305 306 if (!iStart || !iEnd) // only true for empty segments 307 return currpos; 308 309 if (isRtl) 310 { 311 for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev()) 312 { 313 if (s->isBase()) 314 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal); 315 } 316 } 317 else 318 { 319 for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next()) 320 { 321 if (s->isBase()) 322 currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal); 323 } 324 } 325 if (reorder) 326 reverseSlots(); 327 return currpos; 328 } 329 330 331 void Segment::associateChars(int offset, size_t numChars) 332 { 333 int i = 0, j = 0; 334 CharInfo *c, *cend; 335 for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c) 336 { 337 c->before(-1); 338 c->after(-1); 339 } 340 for (Slot * s = m_first; s; s->index(i++), s = s->next()) 341 { 342 j = s->before(); 343 if (j < 0) continue; 344 345 for (const int after = s->after(); j <= after; ++j) 346 { 347 c = charinfo(j); 348 if (c->before() == -1 || i < c->before()) c->before(i); 349 if (c->after() < i) c->after(i); 350 } 351 } 352 for (Slot *s = m_first; s; s = s->next()) 353 { 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); 359 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); 364 } 365 } 366 367 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) 370 { 371 const Cmap & cmap = face.cmap(); 372 int slotid = 0; 373 374 const typename utf_iter::codeunit_type * const base = c; 375 for (; n_chars; --n_chars, ++c, ++slotid) 376 { 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); 381 } 382 } 383 384 385 bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars) 386 { 387 assert(face); 388 assert(pFeats); 389 if (!m_charinfo) return false; 390 391 // utf iterator is self recovering so we don't care about the error state of the iterator. 392 switch (enc) 393 { 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; 397 } 398 return true; 399 } 400 401 void Segment::doMirror(uint16 aMirror) 402 { 403 Slot * s; 404 for (s = m_first; s; s = s->next()) 405 { 406 unsigned short g = glyphAttr(s->gid(), aMirror); 407 if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1))) 408 s->setGlyph(this, g); 409 } 410 } 411 412 bool Segment::initCollisions() 413 { 414 m_collisions = grzeroalloc<SlotCollision>(slotCount()); 415 if (!m_collisions) return false; 416 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; 423 }