tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }