gfx/graphite2/src/Segment.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/graphite2/src/Segment.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,494 @@
     1.4 +/*  GRAPHITE2 LICENSING
     1.5 +
     1.6 +    Copyright 2010, SIL International
     1.7 +    All rights reserved.
     1.8 +
     1.9 +    This library is free software; you can redistribute it and/or modify
    1.10 +    it under the terms of the GNU Lesser General Public License as published
    1.11 +    by the Free Software Foundation; either version 2.1 of License, or
    1.12 +    (at your option) any later version.
    1.13 +
    1.14 +    This program is distributed in the hope that it will be useful,
    1.15 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.17 +    Lesser General Public License for more details.
    1.18 +
    1.19 +    You should also have received a copy of the GNU Lesser General Public
    1.20 +    License along with this library in the file named "LICENSE".
    1.21 +    If not, write to the Free Software Foundation, 51 Franklin Street, 
    1.22 +    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 
    1.23 +    internet at http://www.fsf.org/licenses/lgpl.html.
    1.24 +
    1.25 +Alternatively, the contents of this file may be used under the terms of the
    1.26 +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
    1.27 +License, as published by the Free Software Foundation, either version 2
    1.28 +of the License or (at your option) any later version.
    1.29 +*/
    1.30 +#include "inc/UtfCodec.h"
    1.31 +#include <cstring>
    1.32 +#include <cstdlib>
    1.33 +
    1.34 +#include "inc/bits.h"
    1.35 +#include "inc/Segment.h"
    1.36 +#include "graphite2/Font.h"
    1.37 +#include "inc/CharInfo.h"
    1.38 +#include "inc/debug.h"
    1.39 +#include "inc/Slot.h"
    1.40 +#include "inc/Main.h"
    1.41 +#include "inc/CmapCache.h"
    1.42 +#include "inc/Bidi.h"
    1.43 +#include "graphite2/Segment.h"
    1.44 +
    1.45 +
    1.46 +using namespace graphite2;
    1.47 +
    1.48 +Segment::Segment(unsigned int numchars, const Face* face, uint32 script, int textDir)
    1.49 +: m_freeSlots(NULL),
    1.50 +  m_freeJustifies(NULL),
    1.51 +  m_charinfo(new CharInfo[numchars]),
    1.52 +  m_face(face),
    1.53 +  m_silf(face->chooseSilf(script)),
    1.54 +  m_first(NULL),
    1.55 +  m_last(NULL),
    1.56 +  m_bufSize(numchars + 10),
    1.57 +  m_numGlyphs(numchars),
    1.58 +  m_numCharinfo(numchars),
    1.59 +  m_passBits(m_silf->aPassBits() ? -1 : 0),
    1.60 +  m_defaultOriginal(0),
    1.61 +  m_dir(textDir)
    1.62 +{
    1.63 +    freeSlot(newSlot());
    1.64 +    m_bufSize = log_binary(numchars)+1;
    1.65 +}
    1.66 +
    1.67 +Segment::~Segment()
    1.68 +{
    1.69 +    for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
    1.70 +        free(*i);
    1.71 +    for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j)
    1.72 +        free(*j);
    1.73 +    delete[] m_charinfo;
    1.74 +}
    1.75 +
    1.76 +#ifndef GRAPHITE2_NSEGCACHE
    1.77 +SegmentScopeState Segment::setScope(Slot * firstSlot, Slot * lastSlot, size_t subLength)
    1.78 +{
    1.79 +    SegmentScopeState state;
    1.80 +    state.numGlyphsOutsideScope = m_numGlyphs - subLength;
    1.81 +    state.realFirstSlot = m_first;
    1.82 +    state.slotBeforeScope = firstSlot->prev();
    1.83 +    state.slotAfterScope = lastSlot->next();
    1.84 +    state.realLastSlot = m_last;
    1.85 +    firstSlot->prev(NULL);
    1.86 +    lastSlot->next(NULL);
    1.87 +    assert(m_defaultOriginal == 0);
    1.88 +    m_defaultOriginal = firstSlot->original();
    1.89 +    m_numGlyphs = subLength;
    1.90 +    m_first = firstSlot;
    1.91 +    m_last = lastSlot;
    1.92 +    return state;
    1.93 +}
    1.94 +
    1.95 +void Segment::removeScope(SegmentScopeState & state)
    1.96 +{
    1.97 +    m_numGlyphs = state.numGlyphsOutsideScope + m_numGlyphs;
    1.98 +    if (state.slotBeforeScope)
    1.99 +    {
   1.100 +        state.slotBeforeScope->next(m_first);
   1.101 +        m_first->prev(state.slotBeforeScope);
   1.102 +        m_first = state.realFirstSlot;
   1.103 +    }
   1.104 +    if (state.slotAfterScope)
   1.105 +    {
   1.106 +        state.slotAfterScope->prev(m_last);
   1.107 +        m_last->next(state.slotAfterScope);
   1.108 +        m_last = state.realLastSlot;
   1.109 +    }
   1.110 +    m_defaultOriginal = 0;
   1.111 +}
   1.112 +
   1.113 +#if 0
   1.114 +void Segment::append(const Segment &other)
   1.115 +{
   1.116 +    Rect bbox = other.m_bbox + m_advance;
   1.117 +
   1.118 +    m_slots.insert(m_slots.end(), other.m_slots.begin(), other.m_slots.end());
   1.119 +    CharInfo* pNewCharInfo = new CharInfo[m_numCharinfo+other.m_numCharinfo];       //since CharInfo has no constructor, this doesn't do much
   1.120 +    for (unsigned int i=0 ; i<m_numCharinfo ; ++i)
   1.121 +    pNewCharInfo[i] = m_charinfo[i];
   1.122 +    m_last->next(other.m_first);
   1.123 +    other.m_last->prev(m_last);
   1.124 +    m_userAttrs.insert(m_userAttrs.end(), other.m_userAttrs.begin(), other.m_userAttrs.end());
   1.125 +    
   1.126 +    delete[] m_charinfo;
   1.127 +    m_charinfo = pNewCharInfo;
   1.128 +    pNewCharInfo += m_numCharinfo ;
   1.129 +    for (unsigned int i=0 ; i<m_numCharinfo ; ++i)
   1.130 +        pNewCharInfo[i] = other.m_charinfo[i];
   1.131 + 
   1.132 +    m_numCharinfo += other.m_numCharinfo;
   1.133 +    m_numGlyphs += other.m_numGlyphs;
   1.134 +    m_advance = m_advance + other.m_advance;
   1.135 +    m_bbox = m_bbox.widen(bbox);
   1.136 +    m_passBits &= other.passBits();
   1.137 +}
   1.138 +#endif
   1.139 +#endif // GRAPHITE2_NSEGCACHE
   1.140 +
   1.141 +void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
   1.142 +{
   1.143 +    Slot *aSlot = newSlot();
   1.144 +    
   1.145 +    if (!aSlot) return;
   1.146 +    m_charinfo[id].init(cid);
   1.147 +    m_charinfo[id].feats(iFeats);
   1.148 +    m_charinfo[id].base(coffset);
   1.149 +    const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
   1.150 +    m_charinfo[id].breakWeight(theGlyph ? theGlyph->attrs()[m_silf->aBreak()] : 0);
   1.151 +    
   1.152 +    aSlot->child(NULL);
   1.153 +    aSlot->setGlyph(this, gid, theGlyph);
   1.154 +    aSlot->originate(id);
   1.155 +    aSlot->before(id);
   1.156 +    aSlot->after(id);
   1.157 +    if (m_last) m_last->next(aSlot);
   1.158 +    aSlot->prev(m_last);
   1.159 +    m_last = aSlot;
   1.160 +    if (!m_first) m_first = aSlot;
   1.161 +    if (theGlyph && m_silf->aPassBits())
   1.162 +        m_passBits &= theGlyph->attrs()[m_silf->aPassBits()] 
   1.163 +                    | (m_silf->numPasses() > 16 ? (theGlyph->attrs()[m_silf->aPassBits() + 1] << 16) : 0);
   1.164 +}
   1.165 +
   1.166 +Slot *Segment::newSlot()
   1.167 +{
   1.168 +    if (!m_freeSlots)
   1.169 +    {
   1.170 +        int numUser = m_silf->numUser();
   1.171 +#if !defined GRAPHITE2_NTRACING
   1.172 +        if (m_face->logger()) ++numUser;
   1.173 +#endif
   1.174 +        Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
   1.175 +        int16 *newAttrs = grzeroalloc<int16>(numUser * m_bufSize);
   1.176 +        if (!newSlots || !newAttrs) return NULL;
   1.177 +        for (size_t i = 0; i < m_bufSize; i++)
   1.178 +        {
   1.179 +            newSlots[i].next(newSlots + i + 1);
   1.180 +            newSlots[i].userAttrs(newAttrs + i * numUser);
   1.181 +            newSlots[i].setBidiClass(-1);
   1.182 +        }
   1.183 +        newSlots[m_bufSize - 1].next(NULL);
   1.184 +        newSlots[0].next(NULL);
   1.185 +        m_slots.push_back(newSlots);
   1.186 +        m_userAttrs.push_back(newAttrs);
   1.187 +        m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
   1.188 +        return newSlots;
   1.189 +    }
   1.190 +    Slot *res = m_freeSlots;
   1.191 +    m_freeSlots = m_freeSlots->next();
   1.192 +    res->next(NULL);
   1.193 +    return res;
   1.194 +}
   1.195 +
   1.196 +void Segment::freeSlot(Slot *aSlot)
   1.197 +{
   1.198 +    if (m_last == aSlot) m_last = aSlot->prev();
   1.199 +    if (m_first == aSlot) m_first = aSlot->next();
   1.200 +    if (aSlot->attachedTo())
   1.201 +        aSlot->attachedTo()->removeChild(aSlot);
   1.202 +    while (aSlot->firstChild())
   1.203 +    {
   1.204 +        aSlot->firstChild()->attachTo(NULL);
   1.205 +        aSlot->removeChild(aSlot->firstChild());
   1.206 +    }
   1.207 +    // reset the slot incase it is reused
   1.208 +    ::new (aSlot) Slot;
   1.209 +    memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
   1.210 +    // Update generation counter for debug
   1.211 +#if !defined GRAPHITE2_NTRACING
   1.212 +    if (m_face->logger())
   1.213 +        ++aSlot->userAttrs()[m_silf->numUser()];
   1.214 +#endif
   1.215 +    // update next pointer
   1.216 +    if (!m_freeSlots)
   1.217 +        aSlot->next(NULL);
   1.218 +    else
   1.219 +        aSlot->next(m_freeSlots);
   1.220 +    m_freeSlots = aSlot;
   1.221 +}
   1.222 +
   1.223 +SlotJustify *Segment::newJustify()
   1.224 +{
   1.225 +    if (!m_freeJustifies)
   1.226 +    {
   1.227 +        const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());
   1.228 +        byte *justs = grzeroalloc<byte>(justSize * m_bufSize);
   1.229 +        if (!justs) return NULL;
   1.230 +        for (int i = m_bufSize - 2; i >= 0; --i)
   1.231 +        {
   1.232 +            SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);
   1.233 +            SlotJustify *next = reinterpret_cast<SlotJustify *>(justs + justSize * (i + 1));
   1.234 +            p->next = next;
   1.235 +        }
   1.236 +        m_freeJustifies = (SlotJustify *)justs;
   1.237 +        m_justifies.push_back(m_freeJustifies);
   1.238 +    }
   1.239 +    SlotJustify *res = m_freeJustifies;
   1.240 +    m_freeJustifies = m_freeJustifies->next;
   1.241 +    res->next = NULL;
   1.242 +    return res;
   1.243 +}
   1.244 +
   1.245 +void Segment::freeJustify(SlotJustify *aJustify)
   1.246 +{
   1.247 +    int numJust = m_silf->numJustLevels();
   1.248 +    if (m_silf->numJustLevels() <= 0) numJust = 1;
   1.249 +    aJustify->next = m_freeJustifies;
   1.250 +    memset(aJustify->values, 0, numJust*SlotJustify::NUMJUSTPARAMS*sizeof(int16));
   1.251 +    m_freeJustifies = aJustify;
   1.252 +}
   1.253 +
   1.254 +#ifndef GRAPHITE2_NSEGCACHE
   1.255 +void Segment::splice(size_t offset, size_t length, Slot * const startSlot,
   1.256 +                       Slot * endSlot, const Slot * srcSlot,
   1.257 +                       const size_t numGlyphs)
   1.258 +{
   1.259 +    size_t numChars = length;
   1.260 +    extendLength(numGlyphs - length);
   1.261 +    // remove any extra
   1.262 +    if (numGlyphs < length)
   1.263 +    {
   1.264 +        Slot * end = endSlot->next();
   1.265 +        do
   1.266 +        {
   1.267 +            endSlot = endSlot->prev();
   1.268 +            freeSlot(endSlot->next());
   1.269 +        } while (numGlyphs < --length);
   1.270 +        endSlot->next(end);
   1.271 +        if (end)
   1.272 +            end->prev(endSlot);
   1.273 +    }
   1.274 +    else
   1.275 +    {
   1.276 +        // insert extra slots if needed
   1.277 +        while (numGlyphs > length)
   1.278 +        {
   1.279 +            Slot * extra = newSlot();
   1.280 +            if (!extra) return;
   1.281 +            extra->prev(endSlot);
   1.282 +            extra->next(endSlot->next());
   1.283 +            endSlot->next(extra);
   1.284 +            if (extra->next())
   1.285 +                extra->next()->prev(extra);
   1.286 +            if (m_last == endSlot)
   1.287 +                m_last = extra;
   1.288 +            endSlot = extra;
   1.289 +            ++length;
   1.290 +        }
   1.291 +    }
   1.292 +
   1.293 +    endSlot = endSlot->next();
   1.294 +    assert(numGlyphs == length);
   1.295 +    assert(offset + numChars <= m_numCharinfo);
   1.296 +    Slot * indexmap[eMaxSpliceSize*3];
   1.297 +    assert(numGlyphs < sizeof indexmap/sizeof *indexmap);
   1.298 +    Slot * slot = startSlot;
   1.299 +    for (uint16 i=0; i < numGlyphs; slot = slot->next(), ++i)
   1.300 +        indexmap[i] = slot;
   1.301 +
   1.302 +    for (slot = startSlot; slot != endSlot; slot = slot->next(), srcSlot = srcSlot->next())
   1.303 +    {
   1.304 +        slot->set(*srcSlot, offset, m_silf->numUser(), m_silf->numJustLevels(), numChars);
   1.305 +        if (srcSlot->attachedTo())  slot->attachTo(indexmap[srcSlot->attachedTo()->index()]);
   1.306 +        if (srcSlot->nextSibling()) slot->m_sibling = indexmap[srcSlot->nextSibling()->index()];
   1.307 +        if (srcSlot->firstChild())  slot->m_child = indexmap[srcSlot->firstChild()->index()];
   1.308 +    }
   1.309 +}
   1.310 +#endif // GRAPHITE2_NSEGCACHE
   1.311 +
   1.312 +void Segment::linkClusters(Slot *s, Slot * end)
   1.313 +{
   1.314 +    end = end->next();
   1.315 +
   1.316 +    for (; s != end && !s->isBase(); s = s->next());
   1.317 +    Slot * ls = s;
   1.318 +
   1.319 +    if (m_dir & 1)
   1.320 +    {
   1.321 +        for (; s != end; s = s->next())
   1.322 +        {
   1.323 +            if (!s->isBase())   continue;
   1.324 +
   1.325 +            s->sibling(ls);
   1.326 +            ls = s;
   1.327 +        }
   1.328 +    }
   1.329 +    else
   1.330 +    {
   1.331 +        for (; s != end; s = s->next())
   1.332 +        {
   1.333 +            if (!s->isBase())   continue;
   1.334 +
   1.335 +            ls->sibling(s);
   1.336 +            ls = s;
   1.337 +        }
   1.338 +    }
   1.339 +}
   1.340 +
   1.341 +Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
   1.342 +{
   1.343 +    Position currpos(0., 0.);
   1.344 +    float clusterMin = 0.;
   1.345 +    Rect bbox;
   1.346 +
   1.347 +    if (!iStart)    iStart = m_first;
   1.348 +    if (!iEnd)      iEnd   = m_last;
   1.349 +
   1.350 +    if (m_dir & 1)
   1.351 +    {
   1.352 +        for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
   1.353 +        {
   1.354 +            if (s->isBase())
   1.355 +                currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x);
   1.356 +        }
   1.357 +    }
   1.358 +    else
   1.359 +    {
   1.360 +        for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
   1.361 +        {
   1.362 +            if (s->isBase())
   1.363 +                currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x);
   1.364 +        }
   1.365 +    }
   1.366 +    return currpos;
   1.367 +}
   1.368 +
   1.369 +
   1.370 +void Segment::associateChars(int offset, int numChars)
   1.371 +{
   1.372 +    int i = 0, j = 0;
   1.373 +    CharInfo *c, *cend;
   1.374 +    for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)
   1.375 +    {
   1.376 +        c->before(-1);
   1.377 +        c->after(-1);
   1.378 +    }
   1.379 +    for (Slot * s = m_first; s; s->index(i++), s = s->next())
   1.380 +    {
   1.381 +        j = s->before();
   1.382 +        if (j < 0)  continue;
   1.383 +
   1.384 +        for (const int after = s->after(); j <= after; ++j)
   1.385 +        {
   1.386 +            c = charinfo(j);
   1.387 +            if (c->before() == -1 || i < c->before())   c->before(i);
   1.388 +            if (c->after() < i)                         c->after(i);
   1.389 +        }
   1.390 +    }
   1.391 +    for (Slot *s = m_first; s; s = s->next())
   1.392 +    {
   1.393 +        int a;
   1.394 +        for (a = s->after() + 1; a < offset + numChars && charinfo(a)->after() < 0; ++a)
   1.395 +        { charinfo(a)->after(s->index()); }
   1.396 +        --a;
   1.397 +        s->after(a);
   1.398 +
   1.399 +        for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)
   1.400 +        { charinfo(a)->before(s->index()); }
   1.401 +        ++a;
   1.402 +        s->before(a);
   1.403 +    }
   1.404 +}
   1.405 +
   1.406 +
   1.407 +template <typename utf_iter>
   1.408 +inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
   1.409 +{
   1.410 +    const Cmap    & cmap = face.cmap();
   1.411 +    int slotid = 0;
   1.412 +
   1.413 +    const typename utf_iter::codeunit_type * const base = c;
   1.414 +    for (; n_chars; --n_chars, ++c, ++slotid)
   1.415 +    {
   1.416 +        const uint32 usv = *c;
   1.417 +        uint16 gid = cmap[usv];
   1.418 +        if (!gid)   gid = face.findPseudo(usv);
   1.419 +        seg.appendSlot(slotid, usv, gid, fid, c - base);
   1.420 +    }
   1.421 +}
   1.422 +
   1.423 +
   1.424 +bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
   1.425 +{
   1.426 +    assert(face);
   1.427 +    assert(pFeats);
   1.428 +    if (!m_charinfo) return false;
   1.429 +
   1.430 +    // utf iterator is self recovering so we don't care about the error state of the iterator.
   1.431 +    switch (enc)
   1.432 +    {
   1.433 +    case gr_utf8:   process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
   1.434 +    case gr_utf16:  process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
   1.435 +    case gr_utf32:  process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
   1.436 +    }
   1.437 +    return true;
   1.438 +}
   1.439 +
   1.440 +void Segment::prepare_pos(const Font * /*font*/)
   1.441 +{
   1.442 +    // copy key changeable metrics into slot (if any);
   1.443 +}
   1.444 +
   1.445 +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);
   1.446 +void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror);
   1.447 +void resolveWhitespace(int baseLevel, Slot *s);
   1.448 +Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0);
   1.449 +
   1.450 +void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
   1.451 +{
   1.452 +    if (slotCount() == 0)
   1.453 +        return;
   1.454 +
   1.455 +    Slot *s;
   1.456 +    int baseLevel = paradir ? 1 : 0;
   1.457 +    unsigned int bmask = 0;
   1.458 +    unsigned int ssize = 0;
   1.459 +    for (s = first(); s; s = s->next())
   1.460 +    {
   1.461 +        if (s->getBidiClass() == -1)
   1.462 +        {
   1.463 +            unsigned int bAttr = glyphAttr(s->gid(), aBidi);
   1.464 +            s->setBidiClass((bAttr <= 22) * bAttr);
   1.465 +        }
   1.466 +        bmask |= (1 << s->getBidiClass());
   1.467 +        s->setBidiLevel(baseLevel);
   1.468 +        if (glyphAttr(s->gid(), aMirror) && s->getBidiClass() == 21)
   1.469 +            ++ssize;
   1.470 +    }
   1.471 +
   1.472 +    BracketPairStack bstack(ssize);
   1.473 +    if (bmask & (paradir ? 0x2E7892 : 0x2E789C))
   1.474 +    {
   1.475 +        // O(8N) algorithm, with no working data beyond what is needed for processParens
   1.476 +        int nextLevel = paradir;
   1.477 +        int e, i, c;
   1.478 +        process_bidi(first(), baseLevel, paradir, nextLevel, 0, 0, c = 0, i = 0, e = 0, 1, this, aMirror, bstack);
   1.479 +        resolveImplicit(first(), this, aMirror);
   1.480 +        resolveWhitespace(baseLevel, last());
   1.481 +        s = resolveOrder(s = first(), baseLevel != 0);
   1.482 +        if (s)
   1.483 +        {
   1.484 +            first(s); last(s->prev());
   1.485 +            s->prev()->next(0); s->prev(0);
   1.486 +        }
   1.487 +    }
   1.488 +    else if (!(dir() & 4) && baseLevel && aMirror)
   1.489 +    {
   1.490 +        for (s = first(); s; s = s->next())
   1.491 +        {
   1.492 +            unsigned short g = glyphAttr(s->gid(), aMirror);
   1.493 +            if (g) s->setGlyph(this, g);
   1.494 +        }
   1.495 +    }
   1.496 +}
   1.497 +

mercurial