gfx/graphite2/src/Justifier.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* GRAPHITE2 LICENSING
michael@0 2
michael@0 3 Copyright 2012, SIL International
michael@0 4 All rights reserved.
michael@0 5
michael@0 6 This library is free software; you can redistribute it and/or modify
michael@0 7 it under the terms of the GNU Lesser General Public License as published
michael@0 8 by the Free Software Foundation; either version 2.1 of License, or
michael@0 9 (at your option) any later version.
michael@0 10
michael@0 11 This program is distributed in the hope that it will be useful,
michael@0 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
michael@0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
michael@0 14 Lesser General Public License for more details.
michael@0 15
michael@0 16 You should also have received a copy of the GNU Lesser General Public
michael@0 17 License along with this library in the file named "LICENSE".
michael@0 18 If not, write to the Free Software Foundation, 51 Franklin Street,
michael@0 19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
michael@0 20 internet at http://www.fsf.org/licenses/lgpl.html.
michael@0 21
michael@0 22 Alternatively, the contents of this file may be used under the terms of the
michael@0 23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
michael@0 24 License, as published by the Free Software Foundation, either version 2
michael@0 25 of the License or (at your option) any later version.
michael@0 26 */
michael@0 27
michael@0 28 #include "inc/Segment.h"
michael@0 29 #include "graphite2/Font.h"
michael@0 30 #include "inc/debug.h"
michael@0 31 #include "inc/CharInfo.h"
michael@0 32 #include "inc/Slot.h"
michael@0 33 #include "inc/Main.h"
michael@0 34 #include <math.h>
michael@0 35
michael@0 36 using namespace graphite2;
michael@0 37
michael@0 38 class JustifyTotal {
michael@0 39 public:
michael@0 40 JustifyTotal() : m_numGlyphs(0), m_tStretch(0), m_tShrink(0), m_tStep(0), m_tWeight(0) {}
michael@0 41 void accumulate(Slot *s, Segment *seg, int level);
michael@0 42 int weight() const { return m_tWeight; }
michael@0 43
michael@0 44 CLASS_NEW_DELETE
michael@0 45
michael@0 46 private:
michael@0 47 int m_numGlyphs;
michael@0 48 int m_tStretch;
michael@0 49 int m_tShrink;
michael@0 50 int m_tStep;
michael@0 51 int m_tWeight;
michael@0 52 };
michael@0 53
michael@0 54 void JustifyTotal::accumulate(Slot *s, Segment *seg, int level)
michael@0 55 {
michael@0 56 ++m_numGlyphs;
michael@0 57 m_tStretch += s->getJustify(seg, level, 0);
michael@0 58 m_tShrink += s->getJustify(seg, level, 1);
michael@0 59 m_tStep += s->getJustify(seg, level, 2);
michael@0 60 m_tWeight += s->getJustify(seg, level, 3);
michael@0 61 }
michael@0 62
michael@0 63 float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUSED justFlags flags, Slot *pFirst, Slot *pLast)
michael@0 64 {
michael@0 65 Slot *s, *end;
michael@0 66 float currWidth = 0.0;
michael@0 67 const float scale = font ? font->scale() : 1.0f;
michael@0 68 Position res;
michael@0 69
michael@0 70 if (width < 0 && !(silf()->flags()))
michael@0 71 return width;
michael@0 72
michael@0 73 if (!pFirst) pFirst = pSlot;
michael@0 74 while (!pFirst->isBase()) pFirst = pFirst->attachedTo();
michael@0 75 if (!pLast) pLast = last();
michael@0 76 while (!pLast->isBase()) pLast = pLast->attachedTo();
michael@0 77 const float base = pFirst->origin().x / scale;
michael@0 78 width = width / scale;
michael@0 79 if ((flags & gr_justEndInline) == 0)
michael@0 80 {
michael@0 81 do {
michael@0 82 Rect bbox = theGlyphBBoxTemporary(pLast->glyph());
michael@0 83 if (bbox.bl.x != 0. || bbox.bl.y != 0. || bbox.tr.x != 0. || bbox.tr.y == 0.)
michael@0 84 break;
michael@0 85 pLast = pLast->prev();
michael@0 86 } while (pLast != pFirst);
michael@0 87 }
michael@0 88
michael@0 89 end = pLast->nextSibling();
michael@0 90 pFirst = pFirst->nextSibling();
michael@0 91
michael@0 92 int icount = 0;
michael@0 93 int numLevels = silf()->numJustLevels();
michael@0 94 if (!numLevels)
michael@0 95 {
michael@0 96 for (s = pSlot; s != end; s = s->next())
michael@0 97 {
michael@0 98 CharInfo *c = charinfo(s->before());
michael@0 99 if (isWhitespace(c->unicodeChar()))
michael@0 100 {
michael@0 101 s->setJustify(this, 0, 3, 1);
michael@0 102 s->setJustify(this, 0, 2, 1);
michael@0 103 s->setJustify(this, 0, 0, -1);
michael@0 104 ++icount;
michael@0 105 }
michael@0 106 }
michael@0 107 if (!icount)
michael@0 108 {
michael@0 109 for (s = pSlot; s != end; s = s->nextSibling())
michael@0 110 {
michael@0 111 s->setJustify(this, 0, 3, 1);
michael@0 112 s->setJustify(this, 0, 2, 1);
michael@0 113 s->setJustify(this, 0, 0, -1);
michael@0 114 }
michael@0 115 }
michael@0 116 ++numLevels;
michael@0 117 }
michael@0 118
michael@0 119 JustifyTotal *stats = new JustifyTotal[numLevels];
michael@0 120 if (!stats) return -1.0;
michael@0 121 for (s = pFirst; s != end; s = s->nextSibling())
michael@0 122 {
michael@0 123 float w = s->origin().x / scale + s->advance() - base;
michael@0 124 if (w > currWidth) currWidth = w;
michael@0 125 for (int j = 0; j < numLevels; ++j)
michael@0 126 stats[j].accumulate(s, this, j);
michael@0 127 s->just(0);
michael@0 128 }
michael@0 129
michael@0 130 for (int i = (width < 0.0) ? -1 : numLevels - 1; i >= 0; --i)
michael@0 131 {
michael@0 132 float diff;
michael@0 133 float error = 0.;
michael@0 134 float diffpw;
michael@0 135 int tWeight = stats[i].weight();
michael@0 136
michael@0 137 do {
michael@0 138 error = 0.;
michael@0 139 diff = width - currWidth;
michael@0 140 diffpw = diff / tWeight;
michael@0 141 tWeight = 0;
michael@0 142 for (s = pFirst; s != end; s = s->nextSibling()) // don't include final glyph
michael@0 143 {
michael@0 144 int w = s->getJustify(this, i, 3);
michael@0 145 float pref = diffpw * w + error;
michael@0 146 int step = s->getJustify(this, i, 2);
michael@0 147 if (!step) step = 1; // handle lazy font developers
michael@0 148 if (pref > 0)
michael@0 149 {
michael@0 150 float max = uint16(s->getJustify(this, i, 0));
michael@0 151 if (i == 0) max -= s->just();
michael@0 152 if (pref > max) pref = max;
michael@0 153 else tWeight += w;
michael@0 154 }
michael@0 155 else
michael@0 156 {
michael@0 157 float max = uint16(s->getJustify(this, i, 1));
michael@0 158 if (i == 0) max += s->just();
michael@0 159 if (-pref > max) pref = -max;
michael@0 160 else tWeight += w;
michael@0 161 }
michael@0 162 int actual = step ? int(pref / step) * step : int(pref);
michael@0 163
michael@0 164 if (actual)
michael@0 165 {
michael@0 166 error += diffpw * w - actual;
michael@0 167 if (i == 0)
michael@0 168 s->just(s->just() + actual);
michael@0 169 else
michael@0 170 s->setJustify(this, i, 4, actual);
michael@0 171 }
michael@0 172 }
michael@0 173 currWidth += diff - error;
michael@0 174 } while (i == 0 && int(abs(error)) > 0 && tWeight);
michael@0 175 }
michael@0 176
michael@0 177 Slot *oldFirst = m_first;
michael@0 178 Slot *oldLast = m_last;
michael@0 179 if (silf()->flags() & 1)
michael@0 180 {
michael@0 181 m_first = pSlot = addLineEnd(pSlot);
michael@0 182 m_last = pLast = addLineEnd(end);
michael@0 183 if (!m_first || !m_last) return -1.0;
michael@0 184 }
michael@0 185 else
michael@0 186 {
michael@0 187 m_first = pSlot;
michael@0 188 m_last = pLast;
michael@0 189 }
michael@0 190
michael@0 191 // run justification passes here
michael@0 192 #if !defined GRAPHITE2_NTRACING
michael@0 193 json * const dbgout = m_face->logger();
michael@0 194 if (dbgout)
michael@0 195 *dbgout << json::object
michael@0 196 << "justifies" << objectid(this)
michael@0 197 << "passes" << json::array;
michael@0 198 #endif
michael@0 199
michael@0 200 if (m_silf->justificationPass() != m_silf->positionPass() && (width >= 0. || (silf()->flags() & 1)))
michael@0 201 m_silf->runGraphite(this, m_silf->justificationPass(), m_silf->positionPass());
michael@0 202
michael@0 203 #if !defined GRAPHITE2_NTRACING
michael@0 204 if (dbgout)
michael@0 205 {
michael@0 206 *dbgout << json::item << json::close; // Close up the passes array
michael@0 207 positionSlots(NULL, pSlot, pLast);
michael@0 208 Slot *lEnd = pLast->nextSibling();
michael@0 209 *dbgout << "output" << json::array;
michael@0 210 for(Slot * t = pSlot; t != lEnd; t = t->next())
michael@0 211 *dbgout << dslot(this, t);
michael@0 212 *dbgout << json::close << json::close;
michael@0 213 }
michael@0 214 #endif
michael@0 215
michael@0 216 res = positionSlots(font, pSlot, pLast);
michael@0 217
michael@0 218 if (silf()->flags() & 1)
michael@0 219 {
michael@0 220 delLineEnd(m_first);
michael@0 221 delLineEnd(m_last);
michael@0 222 }
michael@0 223 m_first = oldFirst;
michael@0 224 m_last = oldLast;
michael@0 225 return res.x;
michael@0 226 }
michael@0 227
michael@0 228 Slot *Segment::addLineEnd(Slot *nSlot)
michael@0 229 {
michael@0 230 Slot *eSlot = newSlot();
michael@0 231 if (!eSlot) return NULL;
michael@0 232 const uint16 gid = silf()->endLineGlyphid();
michael@0 233 const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
michael@0 234 eSlot->setGlyph(this, gid, theGlyph);
michael@0 235 if (nSlot)
michael@0 236 {
michael@0 237 eSlot->next(nSlot);
michael@0 238 eSlot->prev(nSlot->prev());
michael@0 239 nSlot->prev(eSlot);
michael@0 240 eSlot->before(nSlot->before());
michael@0 241 if (eSlot->prev())
michael@0 242 eSlot->after(eSlot->prev()->after());
michael@0 243 else
michael@0 244 eSlot->after(nSlot->before());
michael@0 245 }
michael@0 246 else
michael@0 247 {
michael@0 248 nSlot = m_last;
michael@0 249 eSlot->prev(nSlot);
michael@0 250 nSlot->next(eSlot);
michael@0 251 eSlot->after(eSlot->prev()->after());
michael@0 252 eSlot->before(nSlot->after());
michael@0 253 }
michael@0 254 return eSlot;
michael@0 255 }
michael@0 256
michael@0 257 void Segment::delLineEnd(Slot *s)
michael@0 258 {
michael@0 259 Slot *nSlot = s->next();
michael@0 260 if (nSlot)
michael@0 261 {
michael@0 262 nSlot->prev(s->prev());
michael@0 263 if (s->prev())
michael@0 264 s->prev()->next(nSlot);
michael@0 265 }
michael@0 266 else
michael@0 267 s->prev()->next(NULL);
michael@0 268 freeSlot(s);
michael@0 269 }
michael@0 270

mercurial