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