gfx/graphite2/src/Segment.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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.
    26 */
    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/Bidi.h"
    40 #include "graphite2/Segment.h"
    43 using namespace graphite2;
    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 }
    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 }
    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 }
    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 }
   110 #if 0
   111 void Segment::append(const Segment &other)
   112 {
   113     Rect bbox = other.m_bbox + m_advance;
   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());
   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];
   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
   138 void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
   139 {
   140     Slot *aSlot = newSlot();
   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);
   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 }
   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 }
   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 }
   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 }
   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 }
   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     }
   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;
   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
   309 void Segment::linkClusters(Slot *s, Slot * end)
   310 {
   311     end = end->next();
   313     for (; s != end && !s->isBase(); s = s->next());
   314     Slot * ls = s;
   316     if (m_dir & 1)
   317     {
   318         for (; s != end; s = s->next())
   319         {
   320             if (!s->isBase())   continue;
   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;
   332             ls->sibling(s);
   333             ls = s;
   334         }
   335     }
   336 }
   338 Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
   339 {
   340     Position currpos(0., 0.);
   341     float clusterMin = 0.;
   342     Rect bbox;
   344     if (!iStart)    iStart = m_first;
   345     if (!iEnd)      iEnd   = m_last;
   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 }
   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;
   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);
   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 }
   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;
   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 }
   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;
   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 }
   437 void Segment::prepare_pos(const Font * /*font*/)
   438 {
   439     // copy key changeable metrics into slot (if any);
   440 }
   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);
   447 void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
   448 {
   449     if (slotCount() == 0)
   450         return;
   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     }
   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 }

mercurial