Path: blob/master/thirdparty/graphite/src/Segment.cpp
9902 views
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later1// Copyright 2010, SIL International, All rights reserved.23#include "inc/UtfCodec.h"4#include <cstring>5#include <cstdlib>67#include "inc/bits.h"8#include "inc/Segment.h"9#include "graphite2/Font.h"10#include "inc/CharInfo.h"11#include "inc/debug.h"12#include "inc/Slot.h"13#include "inc/Main.h"14#include "inc/CmapCache.h"15#include "inc/Collider.h"16#include "graphite2/Segment.h"171819using namespace graphite2;2021Segment::Segment(size_t numchars, const Face* face, uint32 script, int textDir)22: m_freeSlots(NULL),23m_freeJustifies(NULL),24m_charinfo(new CharInfo[numchars]),25m_collisions(NULL),26m_face(face),27m_silf(face->chooseSilf(script)),28m_first(NULL),29m_last(NULL),30m_bufSize(numchars + 10),31m_numGlyphs(numchars),32m_numCharinfo(numchars),33m_defaultOriginal(0),34m_dir(textDir),35m_flags(((m_silf->flags() & 0x20) != 0) << 1),36m_passBits(m_silf->aPassBits() ? -1 : 0)37{38freeSlot(newSlot());39m_bufSize = log_binary(numchars)+1;40}4142Segment::~Segment()43{44for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)45free(*i);46for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)47free(*i);48for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)49free(*i);50delete[] m_charinfo;51free(m_collisions);52}5354void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)55{56Slot *aSlot = newSlot();5758if (!aSlot) return;59m_charinfo[id].init(cid);60m_charinfo[id].feats(iFeats);61m_charinfo[id].base(coffset);62const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);63m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0);6465aSlot->child(NULL);66aSlot->setGlyph(this, gid, theGlyph);67aSlot->originate(id);68aSlot->before(id);69aSlot->after(id);70if (m_last) m_last->next(aSlot);71aSlot->prev(m_last);72m_last = aSlot;73if (!m_first) m_first = aSlot;74if (theGlyph && m_silf->aPassBits())75m_passBits &= theGlyph->attrs()[m_silf->aPassBits()]76| (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);77}7879Slot *Segment::newSlot()80{81if (!m_freeSlots)82{83// check that the segment doesn't grow indefinintely84if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)85return NULL;86int numUser = m_silf->numUser();87#if !defined GRAPHITE2_NTRACING88if (m_face->logger()) ++numUser;89#endif90Slot *newSlots = grzeroalloc<Slot>(m_bufSize);91int16 *newAttrs = grzeroalloc<int16>(m_bufSize * numUser);92if (!newSlots || !newAttrs)93{94free(newSlots);95free(newAttrs);96return NULL;97}98for (size_t i = 0; i < m_bufSize; i++)99{100::new (newSlots + i) Slot(newAttrs + i * numUser);101newSlots[i].next(newSlots + i + 1);102}103newSlots[m_bufSize - 1].next(NULL);104newSlots[0].next(NULL);105m_slots.push_back(newSlots);106m_userAttrs.push_back(newAttrs);107m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;108return newSlots;109}110Slot *res = m_freeSlots;111m_freeSlots = m_freeSlots->next();112res->next(NULL);113return res;114}115116void Segment::freeSlot(Slot *aSlot)117{118if (aSlot == nullptr) return;119if (m_last == aSlot) m_last = aSlot->prev();120if (m_first == aSlot) m_first = aSlot->next();121if (aSlot->attachedTo())122aSlot->attachedTo()->removeChild(aSlot);123while (aSlot->firstChild())124{125if (aSlot->firstChild()->attachedTo() == aSlot)126{127aSlot->firstChild()->attachTo(nullptr);128aSlot->removeChild(aSlot->firstChild());129}130else131aSlot->firstChild(nullptr);132}133// reset the slot incase it is reused134::new (aSlot) Slot(aSlot->userAttrs());135memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));136// Update generation counter for debug137#if !defined GRAPHITE2_NTRACING138if (m_face->logger())139++aSlot->userAttrs()[m_silf->numUser()];140#endif141// update next pointer142if (!m_freeSlots)143aSlot->next(nullptr);144else145aSlot->next(m_freeSlots);146m_freeSlots = aSlot;147}148149SlotJustify *Segment::newJustify()150{151if (!m_freeJustifies)152{153const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());154byte *justs = grzeroalloc<byte>(justSize * m_bufSize);155if (!justs) return NULL;156for (ptrdiff_t i = m_bufSize - 2; i >= 0; --i)157{158SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);159SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1));160p->next = next;161}162m_freeJustifies = (SlotJustify *)justs;163m_justifies.push_back(m_freeJustifies);164}165SlotJustify *res = m_freeJustifies;166m_freeJustifies = m_freeJustifies->next;167res->next = NULL;168return res;169}170171void Segment::freeJustify(SlotJustify *aJustify)172{173int numJust = m_silf->numJustLevels();174if (m_silf->numJustLevels() <= 0) numJust = 1;175aJustify->next = m_freeJustifies;176memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16));177m_freeJustifies = aJustify;178}179180// reverse the slots but keep diacritics in their same position after their bases181void Segment::reverseSlots()182{183m_dir = m_dir ^ 64; // invert the reverse flag184if (m_first == m_last) return; // skip 0 or 1 glyph runs185186Slot *t = 0;187Slot *curr = m_first;188Slot *tlast;189Slot *tfirst;190Slot *out = 0;191192while (curr && getSlotBidiClass(curr) == 16)193curr = curr->next();194if (!curr) return;195tfirst = curr->prev();196tlast = curr;197198while (curr)199{200if (getSlotBidiClass(curr) == 16)201{202Slot *d = curr->next();203while (d && getSlotBidiClass(d) == 16)204d = d->next();205206d = d ? d->prev() : m_last;207Slot *p = out->next(); // one after the diacritics. out can't be null208if (p)209p->prev(d);210else211tlast = d;212t = d->next();213d->next(p);214curr->prev(out);215out->next(curr);216}217else // will always fire first time round the loop218{219if (out)220out->prev(curr);221t = curr->next();222curr->next(out);223out = curr;224}225curr = t;226}227out->prev(tfirst);228if (tfirst)229tfirst->next(out);230else231m_first = out;232m_last = tlast;233}234235void Segment::linkClusters(Slot *s, Slot * end)236{237end = end->next();238239for (; s != end && !s->isBase(); s = s->next());240Slot * ls = s;241242if (m_dir & 1)243{244for (; s != end; s = s->next())245{246if (!s->isBase()) continue;247248s->sibling(ls);249ls = s;250}251}252else253{254for (; s != end; s = s->next())255{256if (!s->isBase()) continue;257258ls->sibling(s);259ls = s;260}261}262}263264Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)265{266Position currpos(0., 0.);267float clusterMin = 0.;268Rect bbox;269bool reorder = (currdir() != isRtl);270271if (reorder)272{273Slot *temp;274reverseSlots();275temp = iStart;276iStart = iEnd;277iEnd = temp;278}279if (!iStart) iStart = m_first;280if (!iEnd) iEnd = m_last;281282if (!iStart || !iEnd) // only true for empty segments283return currpos;284285if (isRtl)286{287for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())288{289if (s->isBase())290currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);291}292}293else294{295for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())296{297if (s->isBase())298currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);299}300}301if (reorder)302reverseSlots();303return currpos;304}305306307void Segment::associateChars(int offset, size_t numChars)308{309int i = 0, j = 0;310CharInfo *c, *cend;311for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)312{313c->before(-1);314c->after(-1);315}316for (Slot * s = m_first; s; s->index(i++), s = s->next())317{318j = s->before();319if (j < 0) continue;320321for (const int after = s->after(); j <= after; ++j)322{323c = charinfo(j);324if (c->before() == -1 || i < c->before()) c->before(i);325if (c->after() < i) c->after(i);326}327}328for (Slot *s = m_first; s; s = s->next())329{330int a;331for (a = s->after() + 1; a < offset + int(numChars) && charinfo(a)->after() < 0; ++a)332{ charinfo(a)->after(s->index()); }333--a;334s->after(a);335336for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)337{ charinfo(a)->before(s->index()); }338++a;339s->before(a);340}341}342343344template <typename utf_iter>345inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)346{347const Cmap & cmap = face.cmap();348int slotid = 0;349350const typename utf_iter::codeunit_type * const base = c;351for (; n_chars; --n_chars, ++c, ++slotid)352{353const uint32 usv = *c;354uint16 gid = cmap[usv];355if (!gid) gid = face.findPseudo(usv);356seg.appendSlot(slotid, usv, gid, fid, c - base);357}358}359360361bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)362{363assert(face);364assert(pFeats);365if (!m_charinfo) return false;366367// utf iterator is self recovering so we don't care about the error state of the iterator.368switch (enc)369{370case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;371case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;372case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;373}374return true;375}376377void Segment::doMirror(uint16 aMirror)378{379Slot * s;380for (s = m_first; s; s = s->next())381{382unsigned short g = glyphAttr(s->gid(), aMirror);383if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))384s->setGlyph(this, g);385}386}387388bool Segment::initCollisions()389{390m_collisions = grzeroalloc<SlotCollision>(slotCount());391if (!m_collisions) return false;392393for (Slot *p = m_first; p; p = p->next())394if (p->index() < slotCount())395::new (collisionInfo(p)) SlotCollision(this, p);396else397return false;398return true;399}400401402