LCOV - code coverage report
Current view: top level - gfx/graphite2/src - Justifier.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 137 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*  GRAPHITE2 LICENSING
       2             : 
       3             :     Copyright 2012, 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             : 
      28             : #include "inc/Segment.h"
      29             : #include "graphite2/Font.h"
      30             : #include "inc/debug.h"
      31             : #include "inc/CharInfo.h"
      32             : #include "inc/Slot.h"
      33             : #include "inc/Main.h"
      34             : #include <cmath>
      35             : 
      36             : using namespace graphite2;
      37             : 
      38             : class JustifyTotal {
      39             : public:
      40           0 :     JustifyTotal() : m_numGlyphs(0), m_tStretch(0), m_tShrink(0), m_tStep(0), m_tWeight(0) {}
      41             :     void accumulate(Slot *s, Segment *seg, int level);
      42           0 :     int weight() const { return m_tWeight; }
      43             : 
      44           0 :     CLASS_NEW_DELETE
      45             : 
      46             : private:
      47             :     int m_numGlyphs;
      48             :     int m_tStretch;
      49             :     int m_tShrink;
      50             :     int m_tStep;
      51             :     int m_tWeight;
      52             : };
      53             : 
      54           0 : void JustifyTotal::accumulate(Slot *s, Segment *seg, int level)
      55             : {
      56           0 :     ++m_numGlyphs;
      57           0 :     m_tStretch += s->getJustify(seg, level, 0);
      58           0 :     m_tShrink += s->getJustify(seg, level, 1);
      59           0 :     m_tStep += s->getJustify(seg, level, 2);
      60           0 :     m_tWeight += s->getJustify(seg, level, 3);
      61           0 : }
      62             : 
      63           0 : float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags jflags, Slot *pFirst, Slot *pLast)
      64             : {
      65             :     Slot *s, *end;
      66           0 :     float currWidth = 0.0;
      67           0 :     const float scale = font ? font->scale() : 1.0f;
      68           0 :     Position res;
      69             : 
      70           0 :     if (width < 0 && !(silf()->flags()))
      71           0 :         return width;
      72             : 
      73           0 :     if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
      74             :     {
      75           0 :         reverseSlots();
      76           0 :         s = pFirst;
      77           0 :         pFirst = pLast;
      78           0 :         pLast = s;
      79             :     }
      80           0 :     if (!pFirst) pFirst = pSlot;
      81           0 :     while (!pFirst->isBase()) pFirst = pFirst->attachedTo();
      82           0 :     if (!pLast) pLast = last();
      83           0 :     while (!pLast->isBase()) pLast = pLast->attachedTo();
      84           0 :     const float base = pFirst->origin().x / scale;
      85           0 :     width = width / scale;
      86           0 :     if ((jflags & gr_justEndInline) == 0)
      87             :     {
      88           0 :         do {
      89           0 :             Rect bbox = theGlyphBBoxTemporary(pLast->glyph());
      90           0 :             if (bbox.bl.x != 0.f || bbox.bl.y != 0.f || bbox.tr.x != 0.f || bbox.tr.y == 0.f)
      91             :                 break;
      92           0 :             pLast = pLast->prev();
      93           0 :         } while (pLast != pFirst);
      94             :     }
      95             : 
      96           0 :     end = pLast->nextSibling();
      97           0 :     pFirst = pFirst->nextSibling();
      98             : 
      99           0 :     int icount = 0;
     100           0 :     int numLevels = silf()->numJustLevels();
     101           0 :     if (!numLevels)
     102             :     {
     103           0 :         for (s = pSlot; s && s != end; s = s->nextSibling())
     104             :         {
     105           0 :             CharInfo *c = charinfo(s->before());
     106           0 :             if (isWhitespace(c->unicodeChar()))
     107             :             {
     108           0 :                 s->setJustify(this, 0, 3, 1);
     109           0 :                 s->setJustify(this, 0, 2, 1);
     110           0 :                 s->setJustify(this, 0, 0, -1);
     111           0 :                 ++icount;
     112             :             }
     113             :         }
     114           0 :         if (!icount)
     115             :         {
     116           0 :             for (s = pSlot; s && s != end; s = s->nextSibling())
     117             :             {
     118           0 :                 s->setJustify(this, 0, 3, 1);
     119           0 :                 s->setJustify(this, 0, 2, 1);
     120           0 :                 s->setJustify(this, 0, 0, -1);
     121             :             }
     122             :         }
     123           0 :         ++numLevels;
     124             :     }
     125             : 
     126           0 :     Vector<JustifyTotal> stats(numLevels);
     127           0 :     for (s = pFirst; s && s != end; s = s->nextSibling())
     128             :     {
     129           0 :         float w = s->origin().x / scale + s->advance() - base;
     130           0 :         if (w > currWidth) currWidth = w;
     131           0 :         for (int j = 0; j < numLevels; ++j)
     132           0 :             stats[j].accumulate(s, this, j);
     133           0 :         s->just(0);
     134             :     }
     135             : 
     136           0 :     for (int i = (width < 0.0f) ? -1 : numLevels - 1; i >= 0; --i)
     137             :     {
     138             :         float diff;
     139           0 :         float error = 0.;
     140             :         float diffpw;
     141           0 :         int tWeight = stats[i].weight();
     142           0 :         if (tWeight == 0) continue;
     143             : 
     144           0 :         do {
     145           0 :             error = 0.;
     146           0 :             diff = width - currWidth;
     147           0 :             diffpw = diff / tWeight;
     148           0 :             tWeight = 0;
     149           0 :             for (s = pFirst; s && s != end; s = s->nextSibling()) // don't include final glyph
     150             :             {
     151           0 :                 int w = s->getJustify(this, i, 3);
     152           0 :                 float pref = diffpw * w + error;
     153           0 :                 int step = s->getJustify(this, i, 2);
     154           0 :                 if (!step) step = 1;        // handle lazy font developers
     155           0 :                 if (pref > 0)
     156             :                 {
     157           0 :                     float max = uint16(s->getJustify(this, i, 0));
     158           0 :                     if (i == 0) max -= s->just();
     159           0 :                     if (pref > max) pref = max;
     160           0 :                     else tWeight += w;
     161             :                 }
     162             :                 else
     163             :                 {
     164           0 :                     float max = uint16(s->getJustify(this, i, 1));
     165           0 :                     if (i == 0) max += s->just();
     166           0 :                     if (-pref > max) pref = -max;
     167           0 :                     else tWeight += w;
     168             :                 }
     169           0 :                 int actual = int(pref / step) * step;
     170             : 
     171           0 :                 if (actual)
     172             :                 {
     173           0 :                     error += diffpw * w - actual;
     174           0 :                     if (i == 0)
     175           0 :                         s->just(s->just() + actual);
     176             :                     else
     177           0 :                         s->setJustify(this, i, 4, actual);
     178             :                 }
     179             :             }
     180           0 :             currWidth += diff - error;
     181           0 :         } while (i == 0 && int(std::abs(error)) > 0 && tWeight);
     182             :     }
     183             : 
     184           0 :     Slot *oldFirst = m_first;
     185           0 :     Slot *oldLast = m_last;
     186           0 :     if (silf()->flags() & 1)
     187             :     {
     188           0 :         m_first = pSlot = addLineEnd(pSlot);
     189           0 :         m_last = pLast = addLineEnd(end);
     190           0 :         if (!m_first || !m_last) return -1.0;
     191             :     }
     192             :     else
     193             :     {
     194           0 :         m_first = pSlot;
     195           0 :         m_last = pLast;
     196             :     }
     197             : 
     198             :     // run justification passes here
     199             : #if !defined GRAPHITE2_NTRACING
     200             :     json * const dbgout = m_face->logger();
     201             :     if (dbgout)
     202             :         *dbgout << json::object
     203             :                     << "justifies"  << objectid(this)
     204             :                     << "passes"     << json::array;
     205             : #endif
     206             : 
     207           0 :     if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0.f || (silf()->flags() & 1)))
     208           0 :         m_silf->runGraphite(this, m_silf->justificationPass(), m_silf->positionPass());
     209             : 
     210             : #if !defined GRAPHITE2_NTRACING
     211             :     if (dbgout)
     212             :     {
     213             :         *dbgout     << json::item << json::close; // Close up the passes array
     214             :         positionSlots(NULL, pSlot, pLast, m_dir);
     215             :         Slot *lEnd = pLast->nextSibling();
     216             :         *dbgout << "output" << json::array;
     217             :         for(Slot * t = pSlot; t != lEnd; t = t->next())
     218             :             *dbgout     << dslot(this, t);
     219             :         *dbgout         << json::close << json::close;
     220             :     }
     221             : #endif
     222             : 
     223           0 :     res = positionSlots(font, pSlot, pLast, m_dir);
     224             : 
     225           0 :     if (silf()->flags() & 1)
     226             :     {
     227           0 :         delLineEnd(m_first);
     228           0 :         delLineEnd(m_last);
     229             :     }
     230           0 :     m_first = oldFirst;
     231           0 :     m_last = oldLast;
     232             : 
     233           0 :     if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
     234           0 :         reverseSlots();
     235           0 :     return res.x;
     236             : }
     237             : 
     238           0 : Slot *Segment::addLineEnd(Slot *nSlot)
     239             : {
     240           0 :     Slot *eSlot = newSlot();
     241           0 :     if (!eSlot) return NULL;
     242           0 :     const uint16 gid = silf()->endLineGlyphid();
     243           0 :     const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
     244           0 :     eSlot->setGlyph(this, gid, theGlyph);
     245           0 :     if (nSlot)
     246             :     {
     247           0 :         eSlot->next(nSlot);
     248           0 :         eSlot->prev(nSlot->prev());
     249           0 :         nSlot->prev(eSlot);
     250           0 :         eSlot->before(nSlot->before());
     251           0 :         if (eSlot->prev())
     252           0 :             eSlot->after(eSlot->prev()->after());
     253             :         else
     254           0 :             eSlot->after(nSlot->before());
     255             :     }
     256             :     else
     257             :     {
     258           0 :         nSlot = m_last;
     259           0 :         eSlot->prev(nSlot);
     260           0 :         nSlot->next(eSlot);
     261           0 :         eSlot->after(eSlot->prev()->after());
     262           0 :         eSlot->before(nSlot->after());
     263             :     }
     264           0 :     return eSlot;
     265             : }
     266             : 
     267           0 : void Segment::delLineEnd(Slot *s)
     268             : {
     269           0 :     Slot *nSlot = s->next();
     270           0 :     if (nSlot)
     271             :     {
     272           0 :         nSlot->prev(s->prev());
     273           0 :         if (s->prev())
     274           0 :             s->prev()->next(nSlot);
     275             :     }
     276             :     else
     277           0 :         s->prev()->next(NULL);
     278           0 :     freeSlot(s);
     279           0 : }
     280             : 

Generated by: LCOV version 1.13