Subversion Repositories Scribus

Rev

Rev 21218 | Rev 21240 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
3614 cbradney 7
/***************************************************************************
18524 avox 8
                                                  pageitem.cpp  -  description
9
                                                         -------------------
10
        begin                : Sat Apr 7 2001
11
        copyright            : (C) 2001 by Franz Schmid
12
        email                : Franz.Schmid@altmuehlnet.de
3614 cbradney 13
 ***************************************************************************/
14
 
15
/***************************************************************************
16
 *                                                                         *
17
 *   This program is free software; you can redistribute it and/or modify  *
18
 *   it under the terms of the GNU General Public License as published by  *
19
 *   the Free Software Foundation; either version 2 of the License, or     *
20
 *   (at your option) any later version.                                   *
21
 *                                                                         *
22
 ***************************************************************************/
23
 
19067 craig 24
#include "pageitem_textframe.h"
25
 
12269 cbradney 26
#include <QDebug>
9803 fschmid 27
#include <QList>
13951 fschmid 28
#include <QTransform>
12269 cbradney 29
#include <QPalette>
10220 cbradney 30
#include <QPoint>
12269 cbradney 31
#include <QPolygon>
10220 cbradney 32
#include <QRegion>
19067 craig 33
#include <cairo.h>
12269 cbradney 34
#include <cassert>
3614 cbradney 35
 
19495 craig 36
#include "actionmanager.h"
19067 craig 37
#include "appmodes.h"
10532 avox 38
#include "canvas.h"
10220 cbradney 39
#include "commonstrings.h"
3829 cbradney 40
#include "hyphenator.h"
17826 craig 41
#include "marks.h"
42
#include "notesstyles.h"
19067 craig 43
#include "numeration.h"
3614 cbradney 44
#include "pageitem.h"
16943 fschmid 45
#include "pageitem_group.h"
17863 jghali 46
#include "pageitem_noteframe.h"
3614 cbradney 47
#include "prefsmanager.h"
19067 craig 48
#include "scconfig.h"
16736 jghali 49
#include "scpage.h"
10601 mrdocs 50
#include "scpainter.h"
3614 cbradney 51
#include "scpaths.h"
10601 mrdocs 52
#include "scraction.h"
3614 cbradney 53
#include "scribus.h"
10220 cbradney 54
#include "scribusdoc.h"
19093 craig 55
#include "scribusview.h"
3614 cbradney 56
#include "scribusstructs.h"
4145 cbradney 57
#include "selection.h"
21107 craig 58
#include "text/boxes.h"
59
#include "text/screenpainter.h"
21155 jghali 60
#include "text/textshaper.h"
19067 craig 61
#include "ui/guidemanager.h"
20488 jghali 62
#include "ui/marksmanager.h"
3614 cbradney 63
#include "undomanager.h"
64
#include "undostate.h"
20608 jghali 65
#include "units.h"
10601 mrdocs 66
#include "util.h"
10203 cbradney 67
#include "util_math.h"
16736 jghali 68
 
3614 cbradney 69
using namespace std;
70
 
71
PageItem_TextFrame::PageItem_TextFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, QString fill, QString outline)
72
        : PageItem(pa, PageItem::TextFrame, x, y, w, h, w2, fill, outline)
73
{
9816 avox 74
        invalid = true;
75
        firstChar = 0;
8931 cbradney 76
        cursorBiasBackward = false;
3829 cbradney 77
        unicodeTextEditMode = false;
78
        unicodeInputCount = 0;
79
        unicodeInputString = "";
17988 fschmid 80
        m_origAnnotPos = QRectF(xPos(), yPos(), width(), height());
18889 fschmid 81
        verticalAlign = 0;
13148 pierre 82
        connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout()));
3614 cbradney 83
}
84
 
12839 fschmid 85
PageItem_TextFrame::PageItem_TextFrame(const PageItem & p) : PageItem(p)
86
{
87
        invalid = true;
88
        cursorBiasBackward = false;
89
        unicodeTextEditMode = false;
90
        unicodeInputCount = 0;
91
        unicodeInputString = "";
17826 craig 92
        m_notesFramesMap.clear();
17988 fschmid 93
        m_origAnnotPos = QRectF(xPos(), yPos(), width(), height());
18889 fschmid 94
        verticalAlign = 0;
13148 pierre 95
        connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout()));
12839 fschmid 96
}
5184 avox 97
 
10701 avox 98
static QRegion itemShape(PageItem* docItem, double xOffset, double yOffset)
5184 avox 99
{
100
        QRegion res;
13951 fschmid 101
        QTransform pp;
18794 jghali 102
        if (docItem->isGroupChild())
17238 fschmid 103
                pp.translate(docItem->gXpos, docItem->gYpos);
104
        else
105
                pp.translate(docItem->xPos() - xOffset, docItem->yPos() - yOffset);
5184 avox 106
        pp.rotate(docItem->rotation());
107
        if (docItem->textFlowUsesBoundingBox())
108
        {
17038 fschmid 109
                QRectF bb = docItem->getVisualBoundingRect();
18794 jghali 110
                if (docItem->isGroupChild())
17238 fschmid 111
                {
112
                        bb.translate(-docItem->xPos(), -docItem->yPos());
113
                        bb.translate(docItem->gXpos, docItem->gYpos);
114
                }
17132 fschmid 115
                res = QRegion(bb.toRect());
5184 avox 116
        }
8445 fschmid 117
        else if ((docItem->textFlowUsesImageClipping()) && (docItem->imageClip.size() != 0))
5184 avox 118
        {
9803 fschmid 119
                QList<uint> Segs;
10284 fschmid 120
                QPolygon Clip2 = FlattenPath(docItem->imageClip, Segs);
18194 fschmid 121
                res = QRegion(pp.map(Clip2)).intersected(QRegion(pp.map(docItem->Clip)));
5184 avox 122
        }
8445 fschmid 123
        else if ((docItem->textFlowUsesContourLine()) && (docItem->ContourLine.size() != 0))
124
        {
9803 fschmid 125
                QList<uint> Segs;
10284 fschmid 126
                QPolygon Clip2 = FlattenPath(docItem->ContourLine, Segs);
9372 fschmid 127
                res = QRegion(pp.map(Clip2));
8445 fschmid 128
        }
129
        else
17038 fschmid 130
        {
17061 fschmid 131
                if (docItem->isSymbol() || docItem->isGroup())
132
                {
133
                        if (docItem->imageFlippedH())
134
                        {
135
                                pp.translate(docItem->width(), 0);
136
                                pp.scale(-1, 1);
137
                        }
138
                        if (docItem->imageFlippedV())
139
                        {
140
                                pp.translate(0, docItem->height());
141
                                pp.scale(1, -1);
142
                        }
143
                }
17039 fschmid 144
                if ((((docItem->lineColor() != CommonStrings::None) || (!docItem->patternStrokeVal.isEmpty()) || (docItem->GrTypeStroke > 0)) && (docItem->lineWidth() > 1)) || (!docItem->NamedLStyle.isEmpty()))
17038 fschmid 145
                {
17039 fschmid 146
                        QVector<double> m_array;
147
                        QPainterPath ppa;
148
                        QPainterPath result;
149
                        if (docItem->itemType() == PageItem::PolyLine)
150
                                ppa = docItem->PoLine.toQPainterPath(false);
151
                        else
152
                                ppa = docItem->PoLine.toQPainterPath(true);
153
                        if (docItem->NamedLStyle.isEmpty())
17038 fschmid 154
                        {
155
                                QPainterPathStroker stroke;
17039 fschmid 156
                                stroke.setCapStyle(docItem->lineEnd());
157
                                stroke.setJoinStyle(docItem->lineJoin());
17038 fschmid 158
                                stroke.setDashPattern(Qt::SolidLine);
17039 fschmid 159
                                stroke.setWidth(docItem->lineWidth());
17038 fschmid 160
                                result = stroke.createStroke(ppa);
161
                        }
17039 fschmid 162
                        else
163
                        {
164
                                multiLine ml = docItem->doc()->MLineStyles[docItem->NamedLStyle];
165
                                int ind = ml.size()-1;
166
                                if ((ml[ind].Color != CommonStrings::None) && (ml[ind].Width != 0))
167
                                {
168
                                        QPainterPathStroker stroke;
169
                                        stroke.setCapStyle(static_cast<Qt::PenCapStyle>(ml[ind].LineEnd));
170
                                        stroke.setJoinStyle(static_cast<Qt::PenJoinStyle>(ml[ind].LineJoin));
171
                                        stroke.setDashPattern(Qt::SolidLine);
172
                                        stroke.setWidth(ml[ind].Width);
173
                                        result = stroke.createStroke(ppa);
174
                                }
175
                        }
176
                        res = QRegion(pp.map(docItem->Clip));
177
                        QList<QPolygonF> pl = result.toSubpathPolygons();
178
                        for (int b = 0; b < pl.count(); b++)
179
                        {
180
                                res = res.united(QRegion(pp.map(pl[b].toPolygon())));
181
                        }
17038 fschmid 182
                }
17039 fschmid 183
                else
184
                        res = QRegion(pp.map(docItem->Clip));
17038 fschmid 185
        }
5184 avox 186
        return  res;
187
}
188
 
17578 craig 189
QRegion PageItem_TextFrame::calcAvailableRegion()
5184 avox 190
{
16989 jghali 191
        QRegion result(this->Clip);
18794 jghali 192
        if ((!isEmbedded) || (isGroupChild()))
5184 avox 193
        {
16989 jghali 194
                bool invertible(false);
195
                QTransform canvasToLocalMat;
18794 jghali 196
                if (isGroupChild())
17238 fschmid 197
                        canvasToLocalMat.translate(gXpos, gYpos);
198
                else
18032 craig 199
                        canvasToLocalMat.translate(m_xPos, m_yPos);
18022 craig 200
                canvasToLocalMat.rotate(m_rotation);
16989 jghali 201
                canvasToLocalMat = canvasToLocalMat.inverted(&invertible);
202
 
203
                if (!invertible) return QRegion();
204
 
13875 jghali 205
                int LayerLev = m_Doc->layerLevelFromID(LayerID);
7181 cbradney 206
                uint docItemsCount=m_Doc->Items->count();
16729 fschmid 207
                ScPage* Mp=0;
208
                ScPage* Dp=0;
7181 cbradney 209
                PageItem* docItem=0;
210
                int LayerLevItem;
16943 fschmid 211
                QList<PageItem*> thisList;
5184 avox 212
                if (!OnMasterPage.isEmpty())
213
                {
5559 avox 214
                        if ((savedOwnPage == -1) || (savedOwnPage >= signed(m_Doc->Pages->count())))
5375 fschmid 215
                                return result;
7175 fschmid 216
                        Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
217
                        Dp = m_Doc->Pages->at(savedOwnPage);
18794 jghali 218
                        if (isGroupChild())
18610 jghali 219
                                thisList = Parent->asGroupFrame()->groupItemList;
16943 fschmid 220
                        else
221
                                thisList = m_Doc->MasterItems;
222
                        int thisid = thisList.indexOf(this);
9856 fschmid 223
                        for (int a = 0; a < m_Doc->MasterItems.count(); ++a)
5184 avox 224
                        {
7175 fschmid 225
                                docItem = m_Doc->MasterItems.at(a);
17403 jghali 226
                                // #10642 : masterpage items interact only with items placed on same masterpage
227
                                if (docItem->OnMasterPage != OnMasterPage)
228
                                        continue;
16943 fschmid 229
                                int did = m_Doc->MasterItems.indexOf(docItem);
13875 jghali 230
                                LayerLevItem = m_Doc->layerLevelFromID(docItem->LayerID);
16943 fschmid 231
                                if (((did > thisid) && (docItem->LayerID == LayerID)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerID)))
5184 avox 232
                                {
5620 jghali 233
                                        if (docItem->textFlowAroundObject())
16989 jghali 234
                                        {
235
                                                QRegion itemRgn = itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset());
236
                                                result = result.subtracted( canvasToLocalMat.map(itemRgn) );
237
                                        }
5387 avox 238
                                }
239
                        } // for all masterItems
10240 jghali 240
                        // (JG) #6009 : disable possible interaction between master text frames and normal frames
241
                        // which have the text flow option set
242
                        /*if (!m_Doc->masterPageMode())
5184 avox 243
                        {
244
                                for (uint a = 0; a < docItemsCount; ++a)
245
                                {
7175 fschmid 246
                                        docItem = m_Doc->Items->at(a);
247
                                        Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
248
                                        Dp = m_Doc->Pages->at(OwnPage);
5620 jghali 249
                                        if ((docItem->textFlowAroundObject()) && (docItem->OwnPage == OwnPage))
5184 avox 250
                                        {
251
                                                result = result.subtract(itemShape(docItem, m_Doc->view(), Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset()));
252
                                        }
253
                                } // for all docItems
10240 jghali 254
                        } // if (! masterPageMode) */
5387 avox 255
                } // if (!OnMasterPage.isEmpty())
5184 avox 256
                else
257
                {
16943 fschmid 258
                        int thisid = 0;
18794 jghali 259
                        if (isGroupChild())
17238 fschmid 260
                        {
17107 fschmid 261
                                thisid = Parent->asGroupFrame()->groupItemList.indexOf(this);
17238 fschmid 262
                                docItemsCount = Parent->asGroupFrame()->groupItemList.count();
263
                                for (uint a = 0; a < docItemsCount; ++a)
264
                                {
265
                                        docItem = Parent->asGroupFrame()->groupItemList.at(a);
266
                                        int did = Parent->asGroupFrame()->groupItemList.indexOf(docItem);
267
                                        if (did > thisid)
268
                                        {
269
                                                if (docItem->textFlowAroundObject())
270
                                                {
271
                                                        QRegion itemRgn = itemShape(docItem, 0, 0);
272
                                                        result = result.subtracted( canvasToLocalMat.map(itemRgn) );
273
                                                }
274
                                        }
275
                                }
276
                        }
16943 fschmid 277
                        else
17238 fschmid 278
                        {
16943 fschmid 279
                                thisid = m_Doc->Items->indexOf(this);
17238 fschmid 280
                                for (uint a = 0; a < docItemsCount; ++a)
5184 avox 281
                                {
17238 fschmid 282
                                        docItem = m_Doc->Items->at(a);
283
                                        int did = m_Doc->Items->indexOf(docItem);
284
                                        LayerLevItem = m_Doc->layerLevelFromID(docItem->LayerID);
285
                                        if (((did > thisid) && (docItem->LayerID == LayerID)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerID)))
16989 jghali 286
                                        {
17238 fschmid 287
                                                if (docItem->textFlowAroundObject())
288
                                                {
289
                                                        QRegion itemRgn = itemShape(docItem, 0, 0);
290
                                                        result = result.subtracted( canvasToLocalMat.map(itemRgn) );
291
                                                }
16989 jghali 292
                                        }
5387 avox 293
                                }
294
                        } // for all docItems
18524 avox 295
                } // if(OnMasterPage.isEmpty()
5184 avox 296
        } // if(!Embedded)
19983 craig 297
        //else
298
        //      qDebug() << "QRegion empty";
5184 avox 299
        return result;
300
}
301
 
6144 avox 302
void PageItem_TextFrame::setShadow()
303
{
304
        if (OnMasterPage.isEmpty())
305
                return;
18524 avox 306
 
6144 avox 307
        QString newShadow = m_Doc->masterPageMode() ? OnMasterPage : QString::number(OwnPage);
20691 craig 308
        if (newShadow != m_currentShadow) {
309
                if (m_currentShadow == OnMasterPage) {
6366 avox 310
                        // masterpage was edited, clear all shadows
20691 craig 311
                        m_shadows.clear();
6366 avox 312
                }
20691 craig 313
                if (!m_shadows.contains(newShadow)) {
314
                        if (!m_shadows.contains(OnMasterPage)) {
315
                                m_shadows[OnMasterPage] = itemText;
7905 avox 316
//                              const ParagraphStyle& pstyle(shadows[OnMasterPage].paragraphStyle(0));
13085 jghali 317
//                              qDebug() << QString("Pageitem_Textframe: style of master: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
318
//                              qDebug() << QString("Pageitem_Textframe: shadow itemText->%1").arg(OnMasterPage);
6144 avox 319
                        }
7887 avox 320
                        if (newShadow != OnMasterPage) {
20691 craig 321
                                m_shadows[newShadow] = m_shadows[OnMasterPage].copy();
7887 avox 322
//                              const ParagraphStyle& pstyle(shadows[newShadow].paragraphStyle(0));
13085 jghali 323
//                              qDebug() << QString("Pageitem_Textframe: style of shadow copy: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
7887 avox 324
                        }
13085 jghali 325
//                      qDebug() << QString("Pageitem_Textframe: shadow %1<-%2").arg(newShadow).arg(OnMasterPage);
6144 avox 326
                }
20691 craig 327
                itemText = m_shadows[newShadow];
7887 avox 328
//              const ParagraphStyle& pstyle(itemText.paragraphStyle(0));
13085 jghali 329
//              qDebug() << QString("Pageitem_Textframe: style of shadow: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
6144 avox 330
                invalid = true;
20691 craig 331
                m_currentShadow = newShadow;
6144 avox 332
        }
333
}
17790 fschmid 334
/*
17740 jghali 335
static void debugLineLayout(const StoryText& itemText, const LineSpec& line)
336
{
337
        QFile debugFile(QDir::homePath() + "/Desktop/debug_line.csv");
338
        debugFile.open(QIODevice::WriteOnly);
339
 
340
        QTextStream stream(&debugFile);
341
        stream.setRealNumberNotation(QTextStream::FixedNotation);
342
        stream.setRealNumberPrecision(7);
343
 
344
        stream << "xoffset"  << "\t";
345
        stream << "yoffset"  << "\t";
346
        stream << "xadvance" << "\t";
347
        stream << "yadvance" << "\t";
348
        stream << "scaleH"   << "\t";
349
        stream << "scaleV"   << "\t";
350
        stream << "\n";
351
 
21107 craig 352
        for (int zc = line.firstChar; zc < line.lastChar; ++zc)
17740 jghali 353
        {
354
                const ScText* item = itemText.item(zc);
355
 
356
                stream << item->glyph.xoffset  << "\t";
357
                stream << item->glyph.yoffset  << "\t";
358
                stream << item->glyph.xadvance << "\t";
359
                stream << item->glyph.yadvance << "\t";
360
                stream << item->glyph.scaleH   << "\t";
361
                stream << item->glyph.scaleV   << "\t";
362
                stream << "\n";
363
        }
364
 
365
        debugFile.close();
366
}
17826 craig 367
 
5778 avox 368
static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->"))
369
{
10553 fschmid 370
        QString db = QString("%6%1/%2 @ %3: %4--%5 linespa%6: %7 align%8")
5778 avox 371
                   .arg(pstyle.name())
6733 avox 372
                   .arg(pstyle.parent())
5850 tsoots 373
                   .arg( (unsigned long int) &pstyle)
5778 avox 374
                   .arg(pstyle.leftMargin())
375
                   .arg(pstyle.rightMargin())
6805 avox 376
                   .arg(indent)
377
                   .arg(pstyle.lineSpacingMode())
378
                   .arg(pstyle.lineSpacing())
10553 fschmid 379
                   .arg(pstyle.alignment());
13085 jghali 380
        qDebug() << db;
5778 avox 381
        static QString more("  ");
6733 avox 382
        if (pstyle.hasParent())
383
                dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent);
5778 avox 384
}
17826 craig 385
*/
8103 avox 386
static const bool legacy = true;
387
 
10553 fschmid 388
/*
18524 avox 389
static void layoutDropCap(GlyphLayout layout, double curX, double curY, double offsetX, double offsetY, double dropCapDrop)
390
{
6370 avox 391
}
10553 fschmid 392
*/
6370 avox 393
 
7905 avox 394
enum TabStatus {
395
        TabNONE    = 0,
396
        TabLEFT    = TabNONE,
397
        TabRIGHT   = 1,
398
        TabPOINT   = 2,
399
        TabCOMMA   = 3,
400
        TabCENTER  = 4
7313 avox 401
};
6370 avox 402
 
8761 avox 403
 
404
/**
405
fields which describe what type of tab is currently active
406
 */
7313 avox 407
struct TabControl {
21107 craig 408
        bool         active;
409
        int          status;
410
        double       xPos;
411
        QChar        fillChar;
412
        GlyphLayout* tabGlyph;
7313 avox 413
};
414
 
21107 craig 415
struct LineSpec
416
{
417
        qreal x;
418
        qreal y;
419
        qreal width;
420
        qreal ascent;
421
        qreal descent;
422
        qreal colLeft;
423
 
424
        int firstRun;
425
        int lastRun;
426
        qreal naturalWidth;
427
        bool isFirstLine;
428
        qreal height;
429
};
430
 
8761 avox 431
/**
432
fields which describe how the current line is placed into the frame
21107 craig 433
*/
7313 avox 434
struct LineControl {
435
        LineSpec line;
21107 craig 436
        QList<GlyphRun>& glyphRuns;
437
        bool     isEmpty;
7313 avox 438
        int      hyphenCount;
439
        double   colWidth;
8095 avox 440
        double   colGap;
7313 avox 441
        double   colLeft;
442
        double   colRight;
443
        int      column;
444
        bool     startOfCol;
15029 jghali 445
        bool     hasDropCap;
16868 jghali 446
        bool     afterOverflow;
447
        bool     addLine;
448
        bool     recalculateY;
449
        bool     lastInRowLine;
450
        bool     addLeftIndent;
451
        bool     wasFirstInRow;
452
        double   leftIndent;
453
        double   rightMargin;
454
        double   mustLineEnd;
21107 craig 455
        int      restartIndex;  //index of glyph run where line computing should be restarted
456
        int      restartRowIndex;  //index of glyph run where row of text is started
16868 jghali 457
        double   restartX; //starting X position of line if must be restarted
458
        double   rowDesc;
459
 
7313 avox 460
        double   xPos;
461
        double   yPos;
462
        int      breakIndex;
463
        double   breakXPos;
9047 avox 464
 
465
        double   maxShrink;
466
        double   maxStretch;
21107 craig 467
        ScribusDoc *doc;
18524 avox 468
 
8761 avox 469
        /// remember frame dimensions and offsets
21107 craig 470
        LineControl(double w, double h, const MarginStruct& extra, double lCorr, ScribusDoc* d, QList<GlyphRun>& runs, double colwidth, double colgap)
471
                : glyphRuns(runs)
472
                , hasDropCap(false)
473
                , doc(d)
8095 avox 474
        {
475
                insets = extra;
476
                lineCorr = lCorr;
477
                frameWidth = w;
478
                frameHeight = h;
479
                column = 0;
21107 craig 480
                colWidth = colwidth;
481
                colGap = colgap;
482
                hyphenCount = 0;
21119 craig 483
 
484
                isEmpty = true;
485
                colLeft = insets.left() + lineCorr;
486
                colRight = colLeft + colWidth;
487
                startOfCol = true;
488
                afterOverflow = false;
489
                addLine = false;
490
                recalculateY = false;
491
                lastInRowLine = false;
492
                addLeftIndent = false;
493
                wasFirstInRow = false;
494
                leftIndent = 0.0;
495
                rightMargin = 0.0;
496
                mustLineEnd = false;
497
                restartIndex = 0;
498
                restartRowIndex = 0;
499
                restartX = 0.0;
500
                rowDesc = 0.0;
501
                xPos = 0.0;
502
                yPos = 0.0;
503
                breakIndex = -1;
504
                breakXPos = 0.0;
505
                maxShrink = 0.0;
8095 avox 506
        }
18524 avox 507
 
8761 avox 508
        /// move position to next column
21107 craig 509
        void nextColumn(TextLayout &textLayout)
8095 avox 510
        {
511
                startOfCol = true;
19831 craig 512
                colLeft = (colWidth + colGap) * column + insets.left() + lineCorr;
21107 craig 513
                textLayout.addColumn(colLeft, colWidth);
16868 jghali 514
                //now colRight is REAL column right edge
8095 avox 515
                colRight = colLeft + colWidth;
8103 avox 516
                if (legacy)
16868 jghali 517
                        colRight += lineCorr;
8095 avox 518
                xPos = colLeft;
21107 craig 519
                yPos = insets.top() + lineCorr;
21169 jghali 520
                line.colLeft = colLeft;
8095 avox 521
        }
18524 avox 522
 
8095 avox 523
        bool isEndOfCol(double morespace = 0)
524
        {
19831 craig 525
                return yPos + morespace + insets.bottom() + lineCorr > frameHeight;
8095 avox 526
        }
16868 jghali 527
 
8761 avox 528
        /**
529
                init fields for a new line at current position
530
         */
21107 craig 531
        void startLine(int firstRun)
15029 jghali 532
        {
21107 craig 533
                isEmpty = true;
8095 avox 534
                line.x = xPos;
535
                line.y = yPos;
21107 craig 536
                line.firstRun = firstRun;
537
                line.lastRun = 0;
16868 jghali 538
                line.ascent = 0.0;
539
                line.descent = 0.0;
540
                line.width = 0.0;
541
                line.naturalWidth = 0.0;
13211 jghali 542
                line.colLeft = colLeft;
8095 avox 543
                breakIndex = -1;
16868 jghali 544
                breakXPos = 0.0;
545
                maxShrink = 0.0;
546
                maxStretch = 0.0;
547
                leftIndent = 0.0;
548
                rightMargin = 0.0;
549
                rowDesc = 0.0;
8095 avox 550
        }
9047 avox 551
 
18524 avox 552
 
9047 avox 553
        /// called when glyphs are placed on the line
554
        void rememberShrinkStretch(QChar ch, double wide, const ParagraphStyle& style)
555
        {
556
                if (SpecialChars::isExpandingSpace(ch))
557
                        maxShrink += (1 - style.minWordTracking()) * wide;
558
                else
559
                {
560
                        maxShrink += (1 - style.minGlyphExtension()) * wide;
561
                }
562
                maxStretch += (style.maxGlyphExtension() - 1) * wide;
12883 jghali 563
        }
9047 avox 564
 
8761 avox 565
        /// called when a possible break is passed
16868 jghali 566
        void rememberBreak(int index, double pos, double morespace = 0)
8095 avox 567
        {
16868 jghali 568
                if (pos > colRight - morespace)
9047 avox 569
                {
570
                        // only look for the first break behind the right edge
16868 jghali 571
                        //maxShrink = 0;
18524 avox 572
 
9047 avox 573
                        // check if we already have a better break
574
                        if (breakIndex >= 0)
575
                        {
576
                                double oldLooseness = qAbs(colRight - breakXPos);
577
 
578
                                double newLooseness = pos - colRight;
579
                                if (newLooseness >= oldLooseness)
580
                                        return;
581
                        }
582
                }
16868 jghali 583
                breakXPos = pos;
8095 avox 584
                breakIndex = index;
585
        }
21107 craig 586
 
8761 avox 587
        /// called when a mandatory break is found
21107 craig 588
        void breakLine(const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy, int last)
8095 avox 589
        {
590
                breakIndex = last;
591
                breakXPos  = line.x;
21107 craig 592
                for (int i = line.firstRun; i <= breakIndex; i++)
593
                        breakXPos += glyphRuns.at(i).width();
14554 jghali 594
                // #8194, #8717 : update line ascent and descent with sensible values
595
                // so that endOfLine() returns correct result
21107 craig 596
                updateHeightMetrics();
15029 jghali 597
                // #9060 : update line offset too
17303 fschmid 598
        //      updateLineOffset(itemText, style, offsetPolicy);
8095 avox 599
        }
16868 jghali 600
 
8761 avox 601
        /// use the last remembered break to set line width and itemrange
8095 avox 602
        void finishLine(double endX)
603
        {
21107 craig 604
                line.lastRun = breakIndex;
8095 avox 605
                line.naturalWidth = breakXPos - line.x;
606
                line.width = endX - line.x;
9047 avox 607
                maxShrink = maxStretch = 0;
8095 avox 608
        }
16868 jghali 609
 
610
        int restartRow(bool recalcY)
611
        {
612
                if (recalcY)
613
                        yPos++;
614
                recalculateY = recalcY;
615
                xPos = restartX = colLeft;
616
                startLine(restartRowIndex);
617
                addLeftIndent = true;
618
                afterOverflow = false;
21107 craig 619
                return restartRowIndex - 1;
16868 jghali 620
        }
621
 
622
        int restartLine(bool recalcY, bool add)
623
        {
624
                recalculateY = recalcY;
625
                addLine = add;
626
                xPos = restartX;
627
                startLine(restartIndex);
628
                afterOverflow = false;
21107 craig 629
                return restartIndex - 1;
16868 jghali 630
        }
18524 avox 631
 
8095 avox 632
        bool isEndOfLine(double moreSpace = 0)
633
        {
16868 jghali 634
                bool res;
8103 avox 635
                if (legacy)
16868 jghali 636
                        res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight);
8103 avox 637
                else
16868 jghali 638
                        res = ceil(xPos - maxShrink)  + ceil(moreSpace) >= floor(colRight);
639
                return res;
8095 avox 640
        }
18524 avox 641
 
16923 jghali 642
        /// Keep old endOfLine code for reference
643
        /*double endOfLine_old(const QRegion& shape, const QTransform& pf2, double morespace, int Yasc, int Ydesc)
8095 avox 644
        {
13402 jghali 645
                // if we aren't restricted further, we'll end at this maxX:
646
                double maxX = colRight - morespace;
16868 jghali 647
                if (legacy) maxX -= lineCorr;
13402 jghali 648
 
16868 jghali 649
                double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1);
650
                int xPos  = static_cast<int>(ceil(maxX));
13402 jghali 651
 
16921 jghali 652
                QPoint  pt12 (xPos, Yasc);
653
                QPoint  pt22 (xPos, Ydesc);
654
                QRect   pt(pt12,pt22);
18524 avox 655
                QRegion region;
13402 jghali 656
 
657
                double EndX2 = StartX;
16868 jghali 658
                double Interval = 0.25;
13402 jghali 659
                do {
16868 jghali 660
                        int xP = static_cast<int>(ceil(EndX2 + morespace));
661
                        pt.moveTopLeft(QPoint(xP, Yasc));
16921 jghali 662
                        region = QRegion(pf2.mapToPolygon(pt)).subtracted(shape);
663
                        if (!region.isEmpty())
16868 jghali 664
                                break;
13402 jghali 665
                        EndX2 += Interval;
16921 jghali 666
                } while ((EndX2 < maxX) && region.isEmpty());
13402 jghali 667
 
16868 jghali 668
                return qMin(EndX2, maxX);
16923 jghali 669
        }*/
670
 
671
        /// find x position where this line must end
16989 jghali 672
        double endOfLine(const QRegion& shape, double morespace, int yAsc, int yDesc)
16923 jghali 673
        {
674
                // if we aren't restricted further, we'll end at this maxX:
675
                double maxX = colRight - morespace;
676
                if (legacy) maxX -= lineCorr;
677
 
20144 jghali 678
                double StartX = floor(qMax(line.x, qMin(maxX, breakXPos-maxShrink-1))-1);
679
                StartX = qMax(0.0, StartX);
680
 
16923 jghali 681
                int xPos  = static_cast<int>(ceil(maxX));
682
                QPoint  pt12 (xPos, yAsc);
683
                QPoint  pt22 (xPos, yDesc);
684
 
685
                QPolygon p;
16989 jghali 686
                p.append (QPoint (StartX, yAsc));
687
                p.append (QPoint (StartX, yDesc));
688
                p.append (pt12);
689
                p.append (pt22);
16923 jghali 690
                // check if something gets in the way
691
                QRegion lineI = shape.intersected (p.boundingRect());
692
                // if the intersection only has 1 rectangle, then nothing gets in the way
18194 fschmid 693
                if (lineI.rectCount() == 1)
16923 jghali 694
                {
695
                        int   cPos = static_cast<int>(ceil(StartX + morespace));
696
                        QRect cRect (QPoint(cPos, yAsc), QPoint(cPos, yDesc));
18524 avox 697
                        QRegion qr2 = QRegion(cRect).subtracted(shape);
698
                        if (qr2.isEmpty()) // qr2 == 0 <=> cRect subset of shape
16923 jghali 699
                        {
700
                                QRect rect = lineI.rects().at(0);
18524 avox 701
                                double  mx = qMax(rect.left(), rect.right()) /*- pf2.dx()*/;
16989 jghali 702
                                int steps  = static_cast<int>((mx - StartX - morespace - 2) / 0.25);
16923 jghali 703
                                if (steps > 0)
704
                                {
705
                                        StartX += steps * 0.25;
706
                                }
707
                        }
708
                }
709
 
710
                QRect   pt(pt12, pt22);
711
 
712
                double EndX2 = StartX;
713
                double Interval = 0.25;
714
                do {
715
                        int xP = static_cast<int>(ceil(EndX2 + morespace));
716
                        pt.moveTopLeft(QPoint(xP, yAsc));
17044 jghali 717
                        if (!regionContainsRect(shape, pt))
16923 jghali 718
                                break;
719
                        EndX2 += Interval;
17044 jghali 720
                } while ((EndX2 < maxX) && regionContainsRect(shape, pt));
16923 jghali 721
 
722
                /*double oldEndX2 = endOfLine_old(shape, pf2, morespace, yAsc, yDesc);
723
                if (oldEndX2 != qMin(EndX2, maxX))
724
                {
725
                        qDebug() << "Different EndX : " << oldEndX2 << " (old) " << EndX2 << " (new) ";
726
                }*/
727
 
728
                return qMin(EndX2, maxX);
8095 avox 729
        }
18524 avox 730
 
21107 craig 731
        void updateHeightMetrics()
8956 avox 732
        {
21107 craig 733
                line.ascent = line.descent = 0;
734
                // Can happen when inserting a new line at end of text, WTF!
735
                if (line.firstRun >= glyphRuns.length())
736
                        return;
737
                const CharStyle& cStyle(glyphRuns.at(line.firstRun).style());
738
                double scaleV = cStyle.scaleV() / 1000.0;
739
                double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
740
                line.ascent = cStyle.font().ascent(cStyle.fontSize()/10.00) * scaleV + offset;
741
                line.descent = cStyle.font().descent(cStyle.fontSize()/10.00) * scaleV - offset;
8956 avox 742
        }
14554 jghali 743
 
16868 jghali 744
// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!!
17303 fschmid 745
// edit: can't happen as it should only move upwards, and this is covered by the calculations done.
746
//void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy)
747
//{
21107 craig 748
//      if (charsInLine <= 0)
17303 fschmid 749
//              return;
750
//      if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing))
16868 jghali 751
//      {
17303 fschmid 752
//              //FIXME: use glyphs, not chars
21107 craig 753
//              double firstasce = itemText.charStyle(line.firstChar).font().ascent(itemText.charStyle(line.firstChar).fontSize() / 10.0);
17303 fschmid 754
//              double adj (0.0);
755
//              double currasce (this->getLineAscent(itemText));
19927 jghali 756
//              if (offsetPolicy == FLOPRealGlyphHeight)
16868 jghali 757
//              {
17303 fschmid 758
//                      adj = firstasce - currasce;
16868 jghali 759
//              }
19927 jghali 760
//              else if (offsetPolicy == FLOPFontAscent)
16868 jghali 761
//              {
17303 fschmid 762
//                      adj = 0.0;
16868 jghali 763
//              }
19927 jghali 764
//              else if (offsetPolicy == FLOPLineSpacing)
17303 fschmid 765
//              {
766
//                      adj = firstasce - style.lineSpacing();
767
//              }
768
//              line.ascent = currasce;
769
//              line.y -= adj;
770
//              yPos -= adj;
16868 jghali 771
//      }
17303 fschmid 772
//      else if ((!startOfCol) && (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing))
773
//      {
21107 craig 774
//              QChar ch = itemText.text(line.firstChar);
17303 fschmid 775
//              double firstasce = style.lineSpacing();
776
//              double currasce  = getLineHeight(itemText);
777
//              double adj = firstasce - currasce;
21107 craig 778
//              qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstChar).arg(-adj);
17303 fschmid 779
//              line.ascent = currasce;
780
//              line.y -= adj;
781
//              yPos -= adj;
782
//      }
783
//}
15029 jghali 784
 
21107 craig 785
        LineBox* createLineBox()
786
        {
787
                LineBox* result = new LineBox();
788
                result->moveTo(line.x - colLeft, line.y);
789
                result->setWidth(line.width);
790
                result->setAscent(line.ascent);
791
                result->setDescent(line.descent);
792
 
793
                for (int i = line.firstRun; i <= line.lastRun; ++i)
794
                {
795
                        addBox(result, glyphRuns.at(i));
796
                }
797
 
798
                return result;
799
        }
800
 
801
        void addBox(LineBox *lineBox, const GlyphRun& run)
802
        {
803
                Box* result;
804
                if (run.object())
805
                {
806
                        result = new ObjectBox(run);
21218 fschmid 807
                        if (run.hasFlag(ScLayout_DropCap))
808
                                result->setAscent((run.object()->height() - run.object()->lineWidth()) * run.glyphs().first().scaleV - run.glyphs().first().yoffset);
809
                        else
810
                                result->setAscent(run.object()->height() - run.object()->lineWidth());
21107 craig 811
                        result->setDescent(0);
812
                }
813
                else
814
                {
815
                        result = new GlyphBox(run);
816
                        result->setAscent(lineBox->ascent());
817
                        result->setDescent(lineBox->descent());
818
                }
819
                lineBox->addBox(result);
820
        }
821
 
8095 avox 822
private:
823
        double frameWidth;
824
        double frameHeight;
825
        MarginStruct insets;
826
        double lineCorr;
7313 avox 827
};
828
 
21107 craig 829
/**
830
 Clones the tab fill char as often as necssary after all distances are known
831
 */
832
static void fillInTabLeaders(LineControl & current)
833
{
834
        // fill in tab leaders
835
        for(int i = current.line.firstRun; i <= current.line.lastRun; i++)
836
        {
837
                GlyphRun& glyphRun = current.glyphRuns[i];
838
                CharStyle charStyle(glyphRun.style());
839
                if (glyphRun.hasFlag(ScLayout_TabLeaders))
840
                {
841
                        GlyphLayout tglyph = glyphRun.glyphs().last();
842
                        double width = glyphRun.width();
843
                        double wt = charStyle.font().glyphWidth(tglyph.glyph, charStyle.fontSize() * tglyph.scaleV / 10.0);
844
                        int count = static_cast<int>(width / wt);
845
                        glyphRun.glyphs().clear();
846
                        for(int cx = 0; cx < count; ++cx)
847
                        {
848
                                GlyphLayout more = tglyph;
849
                                more.xadvance = width / count;
850
                                glyphRun.glyphs().append(more);
851
                        }
852
                }
853
        }
854
}
855
 
856
 
18524 avox 857
static bool checkCJK(QChar ch) {
16876 jghali 858
        unsigned int code = ch.unicode();
19851 craig 859
        if (    (0x2E80 < code && code < 0x2EFF)   ||  // CJK Radicals Supplement
860
                (0x3000 < code && code < 0x303F)   ||  // CJK Symbols and Punctuation
861
                (0x3040 < code && code <= 0x30FF)  ||  // Hiragana, Katakana
862
                (0x31C0 < code && code < 0x31EF)   ||  // CJK Strokes
863
                (0x3200 < code && code < 0x32FF)   ||  // Enclosed CJK Letters and Months
864
                (0x3300 < code && code < 0x33FF)   ||  // CJK Compatibility
865
                (0x3400 < code && code < 0x4DBF)   ||  // CJK Unified Ideographs Extension A
866
                (0x4E00 < code && code < 0x9FFF)   ||  // CJK Unified Ideographs
867
                (0xF900 < code && code < 0xFAFF)   ||  // CJK Compatibility Ideographs
868
                (0xFE30 < code && code < 0xFE4F)   ||  // CJK Compatibility Forms
869
                (0x20000 < code && code < 0x2A6DF) ||  // CJK Unified Ideographs Extension B
870
                (0x2A700 < code && code < 0x2B73F) ||  // CJK Unified Ideographs Extension C
871
                (0x2B740 < code && code < 0x2B81F) ||  // CJK Unified Ideographs Extension D
872
                (0x2F800 < code && code < 0x2FA1F) ||  // CJK Compatibility Ideographs Supplement
873
                (0xFF01 < code && code < 0xFF0F)   ||
874
                (0xFF1A < code && code < 0xFF20)   ||
875
                (0xFF58 < code && code < 0xFFDC)   ||
16876 jghali 876
                (code == 0x3000) ||
877
                (code == 0x3002) ||
878
                (code == 0x201C) ||
879
                (code == 0x201D))
18524 avox 880
                return true;
16876 jghali 881
        else
18524 avox 882
                return false;
16876 jghali 883
}
7313 avox 884
 
18524 avox 885
static bool allowedCJKBreakAfter(QChar ch) {
19851 craig 886
        unsigned int code[] = {0x201C, 0x300C, 0xFF08, 0xFF3B, 0xFF5B, 0xFF5F, 0xFF62, 0xFF0D, 0};
16876 jghali 887
        for (int i = 0; code[i]; ++i)
888
                if (code[i] == ch.unicode())
18524 avox 889
                        return false;
890
        return true;
16876 jghali 891
}
8095 avox 892
 
18524 avox 893
static int allowedCJKBreakBefore(QChar ch) {
16876 jghali 894
        unsigned int code[] =
19851 craig 895
         {0x201D, 0x3001, 0x3002, 0x300D, 0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A,
16876 jghali 896
          0xFF1B, 0xFF1F, 0xFF3D, 0xFF5D, 0xFF60, 0xFF63, 0xFF64, 0};
897
        for (int i = 0; code[i]; ++i)
898
                if (code[i] == ch.unicode())
18524 avox 899
                        return false;
900
        return true;
16876 jghali 901
}
902
 
18524 avox 903
static bool implicitBreak(QChar f, QChar s) {
904
        if (checkCJK(f) && checkCJK(s)) {
905
                return allowedCJKBreakAfter(f) && allowedCJKBreakBefore(s);
16876 jghali 906
        } else
18524 avox 907
                return false;
16876 jghali 908
}
909
 
8761 avox 910
/// called when line length is known and line is to be justified
21107 craig 911
static void justifyLine(const ParagraphStyle& style, LineControl& curr)
8095 avox 912
{
18524 avox 913
 
9047 avox 914
        double glyphNatural = 0;
915
        double spaceNatural = 0;
916
        double glyphExtension;
917
        double spaceExtension;
16876 jghali 918
        int spaceInsertion = 0;
919
        double imSpace = -1;
9047 avox 920
 
21107 craig 921
        for (int i = curr.line.firstRun; i <= curr.line.lastRun; ++i)
8095 avox 922
        {
21107 craig 923
                GlyphRun glyphrun = curr.glyphRuns[i];
924
                if (!glyphrun.hasFlag(ScLayout_ExpandingSpace))
9047 avox 925
                {
21107 craig 926
                        glyphNatural += glyphrun.width();
9047 avox 927
                }
21107 craig 928
                else if ( !glyphrun.hasFlag(ScLayout_SuppressSpace) )
9047 avox 929
                {
21107 craig 930
                        spaceNatural += glyphrun.width();
931
                        if (imSpace < 0.0 || imSpace > glyphrun.width())
932
                                imSpace = glyphrun.width();
9047 avox 933
                }
21107 craig 934
                if (i != curr.line.firstRun && glyphrun.hasFlag(ScLayout_ImplicitSpace))
935
                {
16876 jghali 936
                        spaceInsertion += 1;
937
                }
8095 avox 938
        }
9047 avox 939
 
16876 jghali 940
        imSpace /= 2;
941
 
942
        // decision: prio 1: stretch glyph;  prio 2: insert spaces;  prio 3: stretch spaces
18524 avox 943
 
21107 craig 944
        if (curr.line.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0)
9047 avox 945
        {
946
                glyphExtension = style.minGlyphExtension() - 1;
21107 craig 947
                spaceExtension = (curr.line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural  - 1;
16876 jghali 948
                imSpace = 0;
9047 avox 949
        }
21107 craig 950
        else if (curr.line.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0)
9047 avox 951
        {
952
                spaceExtension = 0;
21107 craig 953
                glyphExtension = (curr.line.width - spaceNatural) / glyphNatural  - 1;
16876 jghali 954
                imSpace = 0;
9047 avox 955
        }
8095 avox 956
        else
9047 avox 957
        {
958
                glyphExtension = style.maxGlyphExtension() - 1;
16876 jghali 959
                if (spaceInsertion) {
21107 craig 960
                        double remaining = curr.line.width - glyphNatural * (1 + glyphExtension) - spaceNatural;
16876 jghali 961
                        if (imSpace > 0) {
962
                                if (remaining / spaceInsertion < imSpace) {
963
                                        imSpace = remaining / spaceInsertion;
964
                                        spaceExtension = 0;
965
                                } else {
966
                                        spaceExtension = (remaining + spaceNatural) / (spaceNatural + spaceInsertion * imSpace) - 1;
967
                                        imSpace *= spaceExtension + 1;
968
                                }
969
                        } else {
970
                                imSpace = remaining / spaceInsertion;
971
                                spaceExtension = 0;
972
                        }
973
                } else {
974
                        if (spaceNatural > 0)
21107 craig 975
                                spaceExtension = (curr.line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural  - 1;
16876 jghali 976
                        else
977
                                spaceExtension = 0;
978
                }
9047 avox 979
        }
18524 avox 980
 
9047 avox 981
        double glyphScale = 1 + glyphExtension;
18524 avox 982
 
9047 avox 983
/*
13085 jghali 984
        qDebug() << QString("justify: line = %7 natural = %1 + %2 = %3 (%4); spaces + %5%%; min=%8; glyphs + %6%%; min=%9")
9047 avox 985
                   .arg(spaceNatural).arg(glyphNatural).arg(spaceNatural+glyphNatural).arg(line.naturalWidth)
986
                   .arg(spaceExtension).arg(glyphExtension).arg(line.width)
13085 jghali 987
                   .arg(style.minWordTracking()).arg(style.minGlyphExtension());
9047 avox 988
        */
18524 avox 989
 
21107 craig 990
        int startItem = curr.line.firstRun;
991
        if (curr.glyphRuns[startItem].hasFlag(ScLayout_DropCap))
16868 jghali 992
                startItem++;
9047 avox 993
        // distribute whitespace on spaces and glyphs
21107 craig 994
        for (int i = startItem; i <= curr.line.lastRun; ++i)
8095 avox 995
        {
21107 craig 996
                GlyphRun& glyphrun = curr.glyphRuns[i];
997
                double wide = glyphrun.width();
998
                if (!glyphrun.hasFlag(ScLayout_ExpandingSpace))
999
                {
1000
                        for (int j = 0; j < glyphrun.glyphs().count(); ++j)
9047 avox 1001
                        {
21107 craig 1002
                                GlyphLayout& glyph = glyphrun.glyphs()[j];
1003
                                glyph.xoffset *= glyphScale;
1004
                                glyph.scaleH *= glyphScale;
9047 avox 1005
                        }
8095 avox 1006
                }
21107 craig 1007
                else if (!glyphrun.hasFlag(ScLayout_SuppressSpace))
9047 avox 1008
                {
21107 craig 1009
                        GlyphLayout& glyph = glyphrun.glyphs().last();
21160 jghali 1010
                        glyph.xadvance += (wide * spaceExtension) / glyph.scaleH;
9047 avox 1011
                }
21135 jghali 1012
                if (i != curr.line.firstRun && glyphrun.hasFlag(ScLayout_ImplicitSpace))
1013
                {
1014
                        GlyphRun& lastRun = curr.glyphRuns[i - 1];
1015
                        lastRun.glyphs().last().xadvance += imSpace;
1016
                }
8095 avox 1017
        }
1018
}
1019
 
1020
 
9047 avox 1021
/// called when linelength is known and line is not justified
21107 craig 1022
static void indentLine(const ParagraphStyle& style, LineControl& curr, double leftIndent)
8095 avox 1023
{
21107 craig 1024
        if (curr.line.naturalWidth > curr.line.width)
9047 avox 1025
        {
21107 craig 1026
                justifyLine(style, curr);
9047 avox 1027
        }
1028
        if (leftIndent > 0)
1029
        {
21107 craig 1030
                curr.line.x += leftIndent;
1031
                curr.line.width -= leftIndent;
9047 avox 1032
        }
8095 avox 1033
}
1034
 
16868 jghali 1035
//defined but not used
1036
///// calculate how much the first char should stick out to the left
1037
//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line)
1038
//{
21107 craig 1039
//      int b = line.firstChar;
1040
//      while (b < line.lastChar && (itemText.flags(b) & ScLayout_SuppressSpace))
16868 jghali 1041
//                 ++b;
18524 avox 1042
//
16868 jghali 1043
//      double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
1044
//      QChar chr = itemText.text(b);
1045
//      double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
1046
//      if (QString("'´`").indexOf(chr) >= 0
1047
//              || chr == QChar(0x2018) // quote 6
1048
//              || chr == QChar(0x2019) // quote 9
1049
//              || chr == QChar(0x201a) // lower quote 9
1050
//              || chr == QChar(0x201b) // upper reversed 9 6
1051
//              || chr == QChar(0x2039) // single guillemet <
1052
//              || chr == QChar(0x203a) // single guillemet >
1053
//              )
1054
//              leftCorr *= -0.7;
1055
//      else if (QString("\"").indexOf(chr) >= 0
1056
//                       || chr == QChar(0x00ab) // guillemet <<
1057
//                       || chr == QChar(0x00bb) // guillemet >>
1058
//                       || chr == QChar(0x201c) // quote 66
1059
//                       || chr == QChar(0x201d) // quote 99
1060
//                       || chr == QChar(0x201e) // lower quote 99
1061
//                       || chr == QChar(0x201f) // upper reversed 99
18524 avox 1062
//                       )
16868 jghali 1063
//              leftCorr *= -0.5;
1064
//      else {
1065
//              leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
1066
//              leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
1067
////                            double leftCorr2 = itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0, chr);
1068
////                            leftCorr2 -= itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0);
1069
////                            leftCorr = qMin(leftCorr, leftCorr2);
1070
//      }
1071
//      return leftCorr;
1072
//}
8095 avox 1073
 
8761 avox 1074
/// calculate how much the last char should stick out to the right
21107 craig 1075
static double opticalRightMargin(const StoryText& itemText, const QList<GlyphRun> runs, const LineSpec& line)
8095 avox 1076
{
21107 craig 1077
        int b = line.lastRun;
1078
        while (b > line.firstRun &&
1079
                   (SpecialChars::isBreakingSpace(itemText.text(runs[b].firstChar())) ||
1080
                        SpecialChars::isBreak(itemText.text(runs[b].firstChar())))
8095 avox 1081
                   )
1082
                --b;
21107 craig 1083
        if (b >= line.firstRun)
8095 avox 1084
        {
21107 craig 1085
                const CharStyle& chStyle(runs[b].style());
17757 jghali 1086
                double chs = chStyle.fontSize() * (chStyle.scaleH() / 1000.0);
21107 craig 1087
                QChar chr = runs[b].hasFlag(ScLayout_SoftHyphenVisible) ?
1088
                        QChar('-') : itemText.text(runs[b].firstChar());
17757 jghali 1089
                double rightCorr = chStyle.font().realCharWidth(chr, chs / 10.0);
10517 cbradney 1090
                if (QString("-,.`´'~").indexOf(chr) >= 0
8095 avox 1091
                        || chr == QChar(0x2018)
1092
                        || chr == QChar(0x2019)
1093
                        || chr == QChar(0x201a)
1094
                        || chr == QChar(0x201b)
1095
                        || chr == QChar(0x2039)
1096
                        || chr == QChar(0x203a)
8761 avox 1097
                        || chr == QChar(0x2032) // PRIME
8095 avox 1098
                        )
1099
                        rightCorr *= 0.7;
10517 cbradney 1100
                else if (QString(";:\"").indexOf(chr) >= 0
8095 avox 1101
                                 || chr == QChar(0x00ab)
1102
                                 || chr == QChar(0x00bb)
1103
                                 || chr == QChar(0x201c)
1104
                                 || chr == QChar(0x201d)
1105
                                 || chr == QChar(0x201e)
1106
                                 || chr == QChar(0x201f)
8761 avox 1107
                                 || chr == QChar(0x2013) // EN DASH
1108
                                 || chr == QChar(0x2033) // double prime
8095 avox 1109
                                 )
1110
                        rightCorr *= 0.5;
1111
                else {
17757 jghali 1112
                        rightCorr = chStyle.font().charWidth(chr, chs / 10.0);
1113
                        rightCorr -= chStyle.font().charWidth(chr, chs / 10.0, QChar('.'));
8095 avox 1114
                }
1115
                return rightCorr;
1116
        }
1117
        return 0.0;
1118
}
1119
 
16989 jghali 1120
static double findRealOverflowEnd(const QRegion& shape, QRect pt, double maxX)
16868 jghali 1121
{
17044 jghali 1122
        while (!regionContainsRect(shape, pt) && pt.right() < maxX)
16868 jghali 1123
                pt.translate(1, 0);
1124
        if (pt.right() >= maxX)
1125
                return maxX;
16989 jghali 1126
        return pt.left() + 0.5;
16868 jghali 1127
}
1128
 
16840 jghali 1129
static double adjustToBaselineGrid (const LineControl &control, PageItem *item, int OwnPage)
1130
{
1131
        double by = item->yPos();
1132
        if (OwnPage != -1)
1133
                by = by - item->doc()->Pages->at(OwnPage)->yOffset();
1134
        int ol1 = qRound((by + control.yPos - item->doc()->guidesPrefs().offsetBaselineGrid) * 10000.0);
1135
        int ol2 = static_cast<int>(ol1 / item->doc()->guidesPrefs().valueBaselineGrid);
1136
//                                              qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil(  ol2 / 10000.0 ) * item->doc()->typographicSettings.valueBaselineGrid + item->doc()->typographicSettings.offsetBaselineGrid - by);
8095 avox 1137
 
16840 jghali 1138
        return ceil(  ol2 / 10000.0 ) * item->doc()->guidesPrefs().valueBaselineGrid + item->doc()->guidesPrefs().offsetBaselineGrid - by;
1139
}
8761 avox 1140
 
16840 jghali 1141
static double nextAutoTab (const LineControl &current, PageItem *item)
1142
{
1143
        double dtw = item->doc()->itemToolPrefs().textTabWidth;
1144
        if (current.xPos == current.colLeft)
1145
                return current.colLeft + dtw;
1146
        double res = current.colLeft + ceil ((current.xPos - current.colLeft) / dtw) * dtw;
1147
        if (res == current.xPos) res += dtw;
1148
        return res;
1149
}
8761 avox 1150
 
17826 craig 1151
//cezaryece: I remove static statement as this function is used also by PageItem_NoteFrame
1152
double calculateLineSpacing (const ParagraphStyle &style, PageItem *item)
16840 jghali 1153
{
1154
        if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
17223 jghali 1155
        {
1156
                double autoLS = static_cast<double>(item->doc()->typographicPrefs().autoLineSpacing) / 100.0;
1157
                return (style.charStyle().font().height(style.charStyle().fontSize() / 10.0) * autoLS);
1158
        }
16840 jghali 1159
        if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1160
                return item->doc()->guidesPrefs().valueBaselineGrid;
1161
        return style.lineSpacing();
1162
}
1163
 
1164
 
1165
// This assumes that layout() ran on the previous page and set the incomplete* vars
1166
// It also clears the incomplete* vars, and changes the starting position for this frame
1167
// The incomplete* vars are used to ensure that we don't run into an endless loop
1168
// This setup won't cause any problems, as the only way for the starting position to change
1169
// back is if the previous frame's layout() runs again, but if it does, it also sets the
1170
// incomplete* vars for us
1171
bool PageItem_TextFrame::moveLinesFromPreviousFrame ()
1172
{
1173
        PageItem_TextFrame* prev = dynamic_cast<PageItem_TextFrame*>(BackBox);
1174
        if (!prev) return false;
1175
        if (!prev->incompleteLines) return false;   // no incomplete lines - nothing to do
18987 avox 1176
        int pos = textLayout.endOfFrame()-1;
16840 jghali 1177
        QChar lastChar = itemText.text (pos);
1178
        // qDebug()<<"pos is"<<pos<<", length is"<<itemText.length()<<", incomplete is "<<prev->incompleteLines;
1179
        if ((pos != itemText.length()-1) && (!SpecialChars::isBreak (lastChar, true)))
1180
                return false;  // the paragraph isn't ending yet
18987 avox 1181
        int lines = textLayout.lines();  // lines added to the current frame
16840 jghali 1182
 
1183
        ParagraphStyle style = itemText.paragraphStyle (pos);
1184
        int need = style.keepLinesEnd () + 1;
1185
        int prevneed = style.keepLinesStart () + 1;
1186
        if (lines >= need) {
1187
                prev->incompleteLines = 0;   // so that further paragraphs don't pull anything
1188
                return false;   // we have enough lines
1189
        }
1190
 
1191
        // too few lines - we need to pull some from the previous page
17039 fschmid 1192
        int pull = need - lines;
16840 jghali 1193
        // if pulling the lines would lead to the original frame having too few, pull the whole paragraph
1194
        if (prev->incompleteLines - pull < prevneed)
1195
                pull = prev->incompleteLines;
1196
        // qDebug()<<"pulling"<<pull<<"lines;
1197
        // Okay, move the starting/ending character
1198
        int startingPos = prev->incompletePositions[prev->incompleteLines - pull];
17039 fschmid 1199
        for (int i = 0; i < pull; ++i)
18987 avox 1200
                prev->textLayout.removeLastLine();
16840 jghali 1201
        firstChar = prev->MaxChars = startingPos;
1202
        // keep the remaining incomplete lines flagged as such
1203
        // this ensures that if pulling one line won't be enough, the subsequent call to layout() will pull more
1204
        prev->incompleteLines -= pull;
1205
 
1206
        return true;
1207
}
1208
 
1209
// called at the end of a frame or column
1210
void PageItem_TextFrame::adjustParagraphEndings ()
1211
{
1212
        // More text to go - let's apply paragraph flowing options - orphans/widows, etc
18987 avox 1213
        int pos = textLayout.endOfFrame() - 1;
16840 jghali 1214
        if (pos >= itemText.length() - 1) return;
1215
 
1216
        ParagraphStyle style = itemText.paragraphStyle (pos);
1217
        int paragraphStart = itemText.prevParagraph (pos) + 1;
1218
        QChar lastChar = itemText.text (pos);
1219
        bool keepWithNext = style.keepWithNext() && (lastChar == SpecialChars::PARSEP);
1220
        if (keepWithNext || (!SpecialChars::isBreak (lastChar, true))) {
1221
                // paragraph continues in the next frame, or needs to be kept with the next one
1222
                // check how many lines are in this frame
18987 avox 1223
                int lineStart = textLayout.startOfLine (pos);
16840 jghali 1224
                incompleteLines = 1;
1225
                incompletePositions.prepend (lineStart);
1226
                while (lineStart > paragraphStart) {
18987 avox 1227
                        lineStart = textLayout.startOfLine (lineStart - 1);
16840 jghali 1228
                        incompleteLines++;
1229
                        incompletePositions.prepend (lineStart);
1230
                }
1231
                int need = style.keepLinesStart () + 1;
1232
                if (style.keepTogether()) need = incompleteLines;
1233
                int pull = 0;
1234
                if (style.keepTogether() || (incompleteLines < need)) pull = incompleteLines;
1235
                // if we need to keep it with the next one, pull one line. Next frame layouting
1236
                // will pull more from us if it proves necessary.
1237
                if (keepWithNext && (!pull)) pull = 1;
1238
 
1239
                if (pull) {
1240
                        // push this paragraph to the next frame
1241
                        for (int i = 0; i < pull; ++i)
18987 avox 1242
                                textLayout.removeLastLine();
21197 jghali 1243
                        MaxChars = incompletePositions[incompleteLines-pull];
16840 jghali 1244
                        incompleteLines = 0;
1245
                        incompletePositions.clear();
1246
                }
1247
        }
1248
}
1249
 
18524 avox 1250
void PageItem_TextFrame::layout()
3614 cbradney 1251
{
13045 jghali 1252
//      qDebug()<<"==Layout==" << itemName() ;
13034 pierre 1253
//      printBacktrace(24);
5732 avox 1254
        if (BackBox != NULL && BackBox->invalid) {
1255
//              qDebug("textframe: len=%d, going back", itemText.length());
16639 jghali 1256
                // Why that invalid = false here? Calling prevInChain->layout() does
1257
                // not ensure that this box will be layouted
1258
                // invalid = false;
8060 avox 1259
                PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox);
16543 jghali 1260
                while (prevInChain && prevInChain->invalid)
1261
                {
1262
                        if (!prevInChain->BackBox || !prevInChain->BackBox->invalid)
1263
                                break;
1264
                        prevInChain = dynamic_cast<PageItem_TextFrame*>(prevInChain->BackBox);
1265
                }
1266
                if (prevInChain && prevInChain->invalid)
1267
                        prevInChain->layout();
16106 jghali 1268
                // #9592 : warning, BackBox->layout() may not layout BackBox next box
1269
                if (!invalid)
1270
                        return;
5362 avox 1271
        }
6370 avox 1272
        else if (!invalid && OnMasterPage.isEmpty()) {
13085 jghali 1273
//              qDebug() << QString("textframe: len=%1, invalid=%2 OnMasterPage=%3: no relayout").arg(itemText.length()).arg(invalid).arg(OnMasterPage);
5732 avox 1274
                return;
1275
        }
8334 avox 1276
        if (invalid && BackBox == NULL)
1277
                firstChar = 0;
18524 avox 1278
 
13085 jghali 1279
//      qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame());
5362 avox 1280
        QPoint pt1, pt2;
16868 jghali 1281
        QRect pt;
7969 avox 1282
        double chs, chsd = 0;
21107 craig 1283
        double EndX, OFs;
6805 avox 1284
        ParagraphStyle style;
17742 jghali 1285
        int opticalMargins = ParagraphStyle::OM_None;
18524 avox 1286
 
5362 avox 1287
        bool outs = false;
1288
        bool goNoRoom = false;
1289
        bool goNextColumn = false;
18524 avox 1290
 
7905 avox 1291
        TabControl tabs;
1292
        tabs.active    = false;     // RTab
1293
        tabs.status    = TabNONE;   // TabCode
21107 craig 1294
        tabs.tabGlyph  = 0;         // was int charIndex ~ StartRT
7905 avox 1295
        tabs.xPos      = 0;         // RTabX
1296
 
9803 fschmid 1297
        QList<ParagraphStyle::TabRecord> tTabValues;
7905 avox 1298
        tTabValues.clear();
18524 avox 1299
 
18047 craig 1300
        bool BulNumMode = false; //when bullet or counter should be inserted
17760 jghali 1301
        bool   DropCmode = false, FlopBaseline = false;
17599 craig 1302
        double desc=0, asce=0, realAsce=0, realDesc = 0, offset = 0;
16868 jghali 1303
        double maxDY=0, maxDX=0;
6370 avox 1304
        double DropCapDrop = 0;
11776 jghali 1305
        int    DropLines = 0;
1306
        int    DropLinesCount = 0;
18524 avox 1307
 
18987 avox 1308
        textLayout.clear();
16840 jghali 1309
        incompleteLines = 0;
1310
        incompletePositions.clear();
8095 avox 1311
 
1312
        double lineCorr = 0;
1313
        if (lineColor() != CommonStrings::None)
1314
                lineCorr = m_lineWidth / 2.0;
18524 avox 1315
 
16868 jghali 1316
        //hold Y position of last computed line of text (with glyphs descent)
1317
        //for moving next line if glyphs are higher than that
1318
        double lastLineY = 0;
18524 avox 1319
 
17826 craig 1320
        QMap<int, Mark*> noteMarksPosMap;  //maping notes marks and its position in text
1321
 
5778 avox 1322
        // dump styles
18524 avox 1323
/*
5778 avox 1324
        for (int i=0; i < itemText.nrOfParagraphs(); ++i) {
1325
                const ParagraphStyle& pstyle(itemText.paragraphStyle(itemText.endOfParagraph(i)));
13085 jghali 1326
                qDebug("par %d:", i);
5778 avox 1327
                dumpIt(pstyle);
1328
        }
13085 jghali 1329
        qDebug() << "default:";
5778 avox 1330
        dumpIt(itemText.defaultStyle());
16989 jghali 1331
*/
18524 avox 1332
 
6144 avox 1333
        setShadow();
17826 craig 1334
        int itLen = itemText.length();
1335
        //fast validate empty frames
1336
        if (itLen == 0 || firstInFrame() == itLen)
8095 avox 1337
        {
17826 craig 1338
                PageItem* next = this;
1339
                while (next != NULL)
1340
                {
1341
                        next->invalid = false;
1342
                        next = next->nextInChain();
1343
                }
21195 fschmid 1344
                // TODO layout() shouldn't delete any frame here, as it breaks any loop
1345
                // over the doc->Items or doc->MasterItems lists when done with indexes
1346
                // see Bug #12685 for an example
17826 craig 1347
                if (!isNoteFrame() && m_Doc->notesChanged() && !m_notesFramesMap.isEmpty())
1348
                { //if notes are used
1349
                        UndoManager::instance()->setUndoEnabled(false);
1350
                        QList<PageItem_NoteFrame*> delList;
1351
                        foreach (PageItem_NoteFrame* nF, m_notesFramesMap.keys())
1352
                        {
1353
                                if (nF->notesList().isEmpty() && !nF->isAutoNoteFrame())
1354
                                        delList.append(nF);
1355
                        }
1356
                        while (!delList.isEmpty())
1357
                                m_Doc->delNoteFrame(delList.takeFirst(), false);
1358
                        UndoManager::instance()->setUndoEnabled(true);
1359
                }
1360
                return;
1361
        }
1362
 
1363
        if ((itLen != 0)) // || (NextBox != 0))
1364
        {
5408 avox 1365
                // determine layout area
17578 craig 1366
                m_availableRegion = calcAvailableRegion();
1367
                if (m_availableRegion.isEmpty())
14384 jghali 1368
                {
1369
                        MaxChars = firstInFrame();
1370
                        goto NoRoom;
1371
                }
18524 avox 1372
 
16989 jghali 1373
                if (imageFlippedH() || imageFlippedV())
5362 avox 1374
                {
16989 jghali 1375
                        QTransform matrix;
1376
                        if (imageFlippedH())
1377
                        {
18095 craig 1378
                                matrix.translate(m_width, 0);
16989 jghali 1379
                                matrix.scale(-1, 1);
1380
                        }
1381
                        if (imageFlippedV())
1382
                        {
18095 craig 1383
                                matrix.translate(0, m_height);
16989 jghali 1384
                                matrix.scale(1, -1);
1385
                        }
17578 craig 1386
                        m_availableRegion = matrix.map(m_availableRegion);
5362 avox 1387
                }
18524 avox 1388
 
21155 jghali 1389
                QList<GlyphRun> glyphRuns;
1390
                TextShaper shaper(this, firstInFrame());
21107 craig 1391
 
1392
                LineControl current(m_width, m_height, m_textDistanceMargins, lineCorr, m_Doc, glyphRuns, columnWidth(), ColGap);
1393
                current.nextColumn(textLayout);
1394
 
19831 craig 1395
                lastLineY = m_textDistanceMargins.top();
8095 avox 1396
 
17223 jghali 1397
                //automatic line spacing factor (calculated once)
1398
                double autoLS = static_cast<double>(m_Doc->typographicPrefs().autoLineSpacing) / 100.0;
1399
 
5559 avox 1400
                // find start of first line
17826 craig 1401
                if (firstInFrame() < itLen)
5362 avox 1402
                {
18524 avox 1403
                        CharStyle cstyle = itemText.charStyle(firstInFrame());
7887 avox 1404
                        style = itemText.paragraphStyle(firstInFrame());
16840 jghali 1405
                        style.setLineSpacing (calculateLineSpacing (style, this));
8956 avox 1406
 
13085 jghali 1407
//                      qDebug() << QString("style @0: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin())
1408
//                                 .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()?style.parent()->name():"");
6805 avox 1409
                        if (style.hasDropCap())
3614 cbradney 1410
                        {
16840 jghali 1411
                                chs = calculateLineSpacing (style, this) * style.dropCapLines() * 10;
3614 cbradney 1412
                        }
18524 avox 1413
                        else
1414
                                chs = cstyle.fontSize();
1415
                        desc = -cstyle.font().descent(chs / 10.0);
19831 craig 1416
                        current.yPos = m_textDistanceMargins.top() + lineCorr;
13085 jghali 1417
//                      qDebug() << QString("first line at y=%1").arg(current.yPos);
5362 avox 1418
                }
6370 avox 1419
                else // empty itemText:
5362 avox 1420
                {
16868 jghali 1421
                        desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0);
19831 craig 1422
                        current.yPos = itemText.defaultStyle().lineSpacing() + m_textDistanceMargins.top() + lineCorr - desc;
5362 avox 1423
                }
21107 craig 1424
                current.startLine(0);
16868 jghali 1425
 
5362 avox 1426
                outs = false;
1427
                OFs = 0;
1428
                MaxChars = 0;
16868 jghali 1429
                double realEnd = 0;
21107 craig 1430
                current.restartIndex = current.restartRowIndex = 0;
16868 jghali 1431
                current.afterOverflow = false;
1432
                current.addLine = false;
1433
                current.recalculateY = true;
1434
                current.lastInRowLine = false;
1435
                current.addLeftIndent = true;
1436
                current.wasFirstInRow = false;
1437
                current.leftIndent = 0;
1438
                current.rightMargin = 0.0;
1439
                current.mustLineEnd = current.colRight;
1440
                current.restartX = 0;
17254 fschmid 1441
                int lastStat = 0, curStat = 0;
17826 craig 1442
 
1443
                //why emit invalidating signals each time text is changed by appling styles?
1444
                //this speed up layouting in case of using notes marks and drop caps
1445
                itemText.blockSignals(true);
17595 craig 1446
                setMaxY(-1);
17599 craig 1447
                double maxYAsc = 0.0, maxYDesc = 0.0;
18482 jghali 1448
                int regionMinY = 0, regionMaxY= 0;
21155 jghali 1449
                double autoLeftIndent = 0.0;
18482 jghali 1450
 
21155 jghali 1451
                for (int i = 0; shaper.hasRun(i); ++i)
21107 craig 1452
                {
21155 jghali 1453
                        GlyphRun newRun = shaper.runAt(i);
1454
                        if (i >= glyphRuns.count())
1455
                                glyphRuns.append(newRun);
1456
                        else
1457
                                glyphRuns[i] = newRun;
1458
 
1459
                        GlyphRun& currentRun = glyphRuns[i];
1460
                        if (currentRun.glyphs().isEmpty())
21107 craig 1461
                                continue;
16868 jghali 1462
 
21107 craig 1463
                        int a = glyphRuns[i].firstChar();
18524 avox 1464
                        bool HasObject = itemText.hasObject(a);
21107 craig 1465
                        PageItem* currentObject = itemText.object(a);
18524 avox 1466
                        bool HasMark = itemText.hasMark(a);
1467
 
21237 jghali 1468
                        const StyleFlag& effects = itemText.charStyle(a).effects();
1469
                        if (effects & ScStyle_UnderlineWords)
21107 craig 1470
                        {
21237 jghali 1471
                                if (itemText.text(a).isSpace())
1472
                                        glyphRuns[i].clearFlag(ScLayout_Underlined);
1473
                                else
1474
                                        glyphRuns[i].setFlag(ScLayout_Underlined);
21107 craig 1475
                        }
1476
 
17826 craig 1477
                        if (HasMark)
1478
                        {
21107 craig 1479
                                Mark* mark = itemText.mark(a);
17826 craig 1480
                                //store mark pointer and position in text
18524 avox 1481
                                if (mark->isType(MARKNoteMasterType))
1482
                                        noteMarksPosMap.insert(a, mark);
21107 craig 1483
                        }
18524 avox 1484
 
18047 craig 1485
                        BulNumMode = false;
1486
                        if (a==0 || itemText.text(a-1) == SpecialChars::PARSEP)
1487
                        {
1488
                                autoLeftIndent = 0.0;
1489
                                style = itemText.paragraphStyle(a);
1490
                                if (style.hasBullet() || style.hasNum())
1491
                                {
1492
                                        BulNumMode = true;
1493
                                }
1494
                        }
21107 craig 1495
 
1496
                        if (current.isEmpty)
18047 craig 1497
                                opticalMargins = style.opticalMargins();
20550 craig 1498
                        //-->#13490
21107 craig 1499
                        if (isNoteFrame() && !HasMark)
20550 craig 1500
                        {
1501
                                StyleFlag s(itemText.charStyle(a).effects());
1502
                                s &= ~ScStyle_Superscript;
1503
                                CharStyle haveSuperscript;
1504
                                haveSuperscript.setFeatures(s.featureList());
1505
                                itemText.applyCharStyle(a, 1, haveSuperscript);
1506
                        }
1507
                        //--<#13490
18524 avox 1508
                        CharStyle charStyle = ((itemText.text(a) != SpecialChars::PARSEP) ? itemText.charStyle(a) : style.charStyle());
17826 craig 1509
 
21107 craig 1510
                        curStat = SpecialChars::getCJKAttr(itemText.text(a));
18047 craig 1511
                        //set style for paragraph effects
1512
                        if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP)
1513
                        {
1514
                                if (style.hasDropCap() || style.hasBullet() || style.hasNum())
1515
                                {
1516
                                        const QString& curParent(style.hasParent() ? style.parent() : style.name());
20269 jghali 1517
                                        CharStyle newStyle(charStyle);
19089 jghali 1518
                                        if (style.peCharStyleName().isEmpty())
18047 craig 1519
                                                newStyle.setParent(m_Doc->paragraphStyle(curParent).charStyle().name());
1520
                                        else if (charStyle.name() != style.peCharStyleName())
1521
                                                newStyle.setParent(m_Doc->charStyle(style.peCharStyleName()).name());
1522
                                        charStyle.setStyle(newStyle);
1523
                                        itemText.setCharStyle(a, 1 , charStyle);
1524
                                }
19089 jghali 1525
                                else if (!style.peCharStyleName().isEmpty())
18047 craig 1526
                                //par effect is cleared but is set dcCharStyleName = clear drop cap char style
1527
                                {
1528
                                        const QString& curParent(style.hasParent() ? style.parent() : style.name());
1529
                                        charStyle.eraseCharStyle(m_Doc->charStyle(style.peCharStyleName()));
1530
                                        charStyle.setParent(m_Doc->paragraphStyle(curParent).charStyle().name());
1531
                                        itemText.setCharStyle(a, 1,charStyle);
1532
                                }
1533
                        }
1534
 
16868 jghali 1535
                        double hlcsize10 = charStyle.fontSize() / 10.0;
1536
                        double scaleV = charStyle.scaleV() / 1000.0;
1537
                        double scaleH = charStyle.scaleH() / 1000.0;
17826 craig 1538
                        double offset = hlcsize10 * (charStyle.baselineOffset() / 1000.0);
16840 jghali 1539
                        style.setLineSpacing (calculateLineSpacing (style, this));
17760 jghali 1540
                        FlopBaseline = (current.startOfCol && firstLineOffset() == FLOPBaselineGrid);
1541
 
5408 avox 1542
                        // find out about par gap and dropcap
5721 avox 1543
                        if (a == firstInFrame())
3614 cbradney 1544
                        {
8814 cbradney 1545
                                if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP)
5362 avox 1546
                                {
21107 craig 1547
                                        if (itemText.text(a) != SpecialChars::PARSEP)
5362 avox 1548
                                        {
5721 avox 1549
                                                DropCmode = style.hasDropCap();
5362 avox 1550
                                                if (DropCmode)
5721 avox 1551
                                                        DropLines = style.dropCapLines();
5362 avox 1552
                                        }
1553
                                        else
1554
                                                DropCmode = false;
20632 fschmid 1555
                                        current.line.isFirstLine = true;
5362 avox 1556
                                }
3614 cbradney 1557
                        }
8814 cbradney 1558
 
17757 jghali 1559
                        const ScFace font = charStyle.font();
1560
 
21107 craig 1561
                        glyphRuns[i].clearFlag(ScLayout_DropCap);
1562
                        glyphRuns[i].clearFlag(ScLayout_SoftHyphenVisible);
8814 cbradney 1563
 
18524 avox 1564
                        // No space at begin of line,
8150 avox 1565
                        if (legacy)
3614 cbradney 1566
                        {
8150 avox 1567
                                // unless at begin of par (eeks)
21107 craig 1568
                                if ( (current.isEmpty) && (SpecialChars::isBreakingSpace(itemText.text(a)))
8177 avox 1569
                                         && (a > 0 && ! SpecialChars::isBreak(itemText.text(a-1)))
18524 avox 1570
                                         && ! (a > 0 && SpecialChars::isBreakingSpace(itemText.text(a-1))
21107 craig 1571
                                                   && (!glyphRuns[i - 1].hasFlag(ScLayout_SuppressSpace))))
8150 avox 1572
                                {
21107 craig 1573
                                        glyphRuns[i].setFlag(ScLayout_SuppressSpace);
1574
                                        glyphRuns[i].glyphs().first().xadvance = 0;
8150 avox 1575
                                        continue;
1576
                                }
1577
                                else
21150 jghali 1578
                                        glyphRuns[i].clearFlag(ScLayout_SuppressSpace);
5362 avox 1579
                        }
8150 avox 1580
                        else // from 134 on use NBSPACE for this effect
1581
                        {
21107 craig 1582
                                if ( current.isEmpty && (SpecialChars::isBreakingSpace(itemText.text(a)) || itemText.text(a).isSpace()))
8150 avox 1583
                                {
21107 craig 1584
                                        glyphRuns[i].setFlag(ScLayout_SuppressSpace);
1585
                                        glyphRuns[i].glyphs()[0].xadvance = 0;
8150 avox 1586
                                        continue;
1587
                                }
1588
                                else
21150 jghali 1589
                                        glyphRuns[i].clearFlag(ScLayout_SuppressSpace);
8150 avox 1590
                        }
21107 craig 1591
                        if (current.isEmpty)
5362 avox 1592
                        {
18524 avox 1593
                                if (style.rightMargin() == 0)
3614 cbradney 1594
                                {
16868 jghali 1595
                                        //addLine = true;
1596
                                        current.rightMargin = 0.0;
1597
                                }
1598
                                else
1599
                                {
1600
                                        if (current.lastInRowLine)
1601
                                                current.rightMargin = style.rightMargin();
1602
                                        else
1603
                                                current.rightMargin = 0.0;
1604
                                }
1605
                                current.breakIndex = -1;
1606
                                if (current.startOfCol && !current.afterOverflow && current.recalculateY)
19831 craig 1607
                                        current.yPos = qMax(current.yPos, m_textDistanceMargins.top());
16868 jghali 1608
                                // more about par gap and dropcaps
1609
                                if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol))
1610
                                {
1611
                                        if (!current.afterOverflow && current.recalculateY && !current.startOfCol)
1612
                                                current.yPos += style.gapBefore();
6370 avox 1613
                                        DropCapDrop = 0;
21107 craig 1614
                                        if (itemText.text(a) != SpecialChars::PARSEP)
5721 avox 1615
                                                DropCmode = style.hasDropCap();
5362 avox 1616
                                        else
1617
                                                DropCmode = false;
16868 jghali 1618
                                        if (DropCmode && !current.afterOverflow)
5362 avox 1619
                                        {
5721 avox 1620
                                                DropLines = style.dropCapLines();
16840 jghali 1621
                                                DropCapDrop = calculateLineSpacing (style, this) * (DropLines - 1);
13085 jghali 1622
//                                              qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop);
5362 avox 1623
                                        }
20632 fschmid 1624
                                        current.line.isFirstLine = true;
3614 cbradney 1625
                                }
5362 avox 1626
                        }
16868 jghali 1627
                        // find charsize factors
5362 avox 1628
                        if (DropCmode)
1629
                        {
18047 craig 1630
//                              DropCapDrop = calculateLineSpacing (style, this) * (DropLines - 1);
17140 jghali 1631
 
11767 jghali 1632
                                // FIXME : we should ensure that fonts are loaded before calls to layout()
1633
                                // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap()
1634
                                // ScFace::ascent() can be called safely afterwards
17826 craig 1635
 
18524 avox 1636
                                //text height, width, ascent and descent should be calculated for whole text provided by ScText in current position
17826 craig 1637
                                //and that may be more than one char (variable text for example)
1638
                                double realCharHeight = 0.0, realCharAscent = 0.0;
21107 craig 1639
                                foreach (GlyphLayout gl, glyphRuns[i].glyphs()) {
1640
                                        GlyphMetrics gm = font.glyphBBox(gl.glyph);
1641
                                        realCharHeight = qMax(realCharHeight, gm.ascent + gm.descent);
1642
                                        realCharAscent = qMax(realCharAscent, gm.ascent);
17826 craig 1643
                                }
18524 avox 1644
                                double fontAscent = font.ascent(style.charStyle().fontSize() / 10.0);
14929 jghali 1645
                                if (realCharHeight == 0.0)
17757 jghali 1646
                                        realCharHeight = font.height(style.charStyle().fontSize() / 10.0);
14929 jghali 1647
                                if (realCharAscent == 0.0)
1648
                                        realCharAscent = fontAscent;
16840 jghali 1649
                                chsd = (10 * ((DropCapDrop + fontAscent) / realCharHeight));
1650
                                chs  = (10 * ((DropCapDrop + fontAscent) / realCharAscent));
21107 craig 1651
                                glyphRuns[i].setFlag(ScLayout_DropCap);
21142 fschmid 1652
//                              glyphRuns[i].glyphs().first().yoffset += DropCapDrop;
17826 craig 1653
                                if (HasObject)
17199 fschmid 1654
                                {
18524 avox 1655
                                        chs = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
1656
                                        chsd = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
17199 fschmid 1657
                                }
5362 avox 1658
                        }
5408 avox 1659
                        else // ! dropCapMode
5362 avox 1660
                        {
17826 craig 1661
                                if (HasObject)
18524 avox 1662
                                        chs = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
5362 avox 1663
                                else
6144 avox 1664
                                        chs = charStyle.fontSize();
5362 avox 1665
                        }
21107 craig 1666
                        // set StartOfLine
1667
                        if (current.isEmpty)
8098 avox 1668
                        {
21107 craig 1669
                                glyphRuns[i].setFlag(ScLayout_StartOfLine);
8098 avox 1670
                        }
1671
                        else
1672
                        {
21107 craig 1673
                                glyphRuns[i].clearFlag(ScLayout_StartOfLine);
8098 avox 1674
                        }
21107 craig 1675
//                      glyphs->yadvance = 0;
18524 avox 1676
 
21107 craig 1677
                        GlyphLayout& firstGlyph = glyphRuns[i].glyphs().first();
1678
                        GlyphLayout& lastGlyph = glyphRuns[i].glyphs().last();
1679
 
21155 jghali 1680
                        // Apply cjk kerning
1681
                        // TODO: cjk spacing and kerning should be done in layoutGlyphs!
1682
                        if (shaper.hasRun(i + 1))
14417 jghali 1683
                        {
21155 jghali 1684
                                GlyphRun nextRun = shaper.runAt(i + 1);
21107 craig 1685
                                // change xadvance, xoffset according to JIS X4051
1686
                                int nextStat = SpecialChars::getCJKAttr(itemText.text(nextRun.firstChar()));
1687
                                if (curStat != 0)
1688
                                {       // current char is CJK
1689
                                        if (nextStat == 0 && !SpecialChars::isBreakingSpace(itemText.text(nextRun.firstChar()))){
1690
                                                switch(curStat & SpecialChars::CJK_CHAR_MASK){
1691
                                                case SpecialChars::CJK_KANJI:
1692
                                                case SpecialChars::CJK_KANA:
1693
                                                case SpecialChars::CJK_NOTOP:
1694
                                                        lastGlyph.xadvance += charStyle.fontSize() / 10 / 4;
1695
                                                }
1696
                                        } else {        // next char is CJK, too
1697
                                                switch(curStat & SpecialChars::CJK_CHAR_MASK){
1698
                                                case SpecialChars::CJK_FENCE_END:
1699
                                                        switch(nextStat & SpecialChars::CJK_CHAR_MASK){
1700
                                                        case SpecialChars::CJK_FENCE_BEGIN:
17254 fschmid 1701
                                                        case SpecialChars::CJK_FENCE_END:
1702
                                                        case SpecialChars::CJK_COMMA:
1703
                                                        case SpecialChars::CJK_PERIOD:
1704
                                                        case SpecialChars::CJK_MIDPOINT:
21107 craig 1705
                                                                lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;
1706
                                                        }
1707
                                                        break;
1708
                                                case SpecialChars::CJK_COMMA:
1709
                                                case SpecialChars::CJK_PERIOD:
1710
                                                        switch(nextStat & SpecialChars::CJK_CHAR_MASK){
17254 fschmid 1711
                                                        case SpecialChars::CJK_FENCE_BEGIN:
21107 craig 1712
                                                        case SpecialChars::CJK_FENCE_END:
1713
                                                                lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;;
17254 fschmid 1714
                                                        }
21107 craig 1715
                                                        break;
1716
                                                case SpecialChars::CJK_MIDPOINT:
17254 fschmid 1717
                                                        switch(nextStat & SpecialChars::CJK_CHAR_MASK){
21107 craig 1718
                                                        case SpecialChars::CJK_FENCE_BEGIN:
1719
                                                                lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;
17254 fschmid 1720
                                                        }
21107 craig 1721
                                                        break;
1722
                                                case SpecialChars::CJK_FENCE_BEGIN:
1723
                                                        int prevStat = 0;
1724
                                                        if (i == current.line.firstRun){ // first char of the line
1725
                                                                prevStat = SpecialChars::CJK_FENCE_BEGIN;
1726
                                                        } else if (i != 0) {
1727
                                                                prevStat = SpecialChars::getCJKAttr(itemText.text(glyphRuns[i - 1].lastChar())) & SpecialChars::CJK_CHAR_MASK;
1728
                                                        }
1729
                                                        if (prevStat == SpecialChars::CJK_FENCE_BEGIN){
1730
                                                                lastGlyph.xadvance -= charStyle.fontSize() / 10 / 2;
1731
                                                                lastGlyph.xoffset -= charStyle.fontSize() / 10 / 2;
1732
                                                        }
1733
                                                        break;
17254 fschmid 1734
                                                }
1735
                                        }
21107 craig 1736
                                } else {        // current char is not CJK
1737
                                        if (nextStat != 0 && !SpecialChars::isBreakingSpace(itemText.text(glyphRuns[i].lastChar()))){
1738
                                                switch(nextStat & SpecialChars::CJK_CHAR_MASK){
1739
                                                case SpecialChars::CJK_KANJI:
1740
                                                case SpecialChars::CJK_KANA:
1741
                                                case SpecialChars::CJK_NOTOP:
1742
                                                        // use the size of the current char instead of the next one
1743
                                                        lastGlyph.xadvance += charStyle.fontSize() / 10 / 4;
1744
                                                }
1745
                                        }
6354 avox 1746
                                }
5362 avox 1747
                        }
21107 craig 1748
 
1749
                        // find out width, ascent and descent of char
1750
                        double wide = glyphRuns[i].width();
1751
 
5362 avox 1752
                        if (DropCmode)
1753
                        {
5408 avox 1754
                                // drop caps are wider...
17826 craig 1755
                                if (HasObject)
5362 avox 1756
                                {
18524 avox 1757
                                        double itemHeight = currentObject->height() + currentObject->lineWidth();
14929 jghali 1758
                                        if (itemHeight == 0)
17757 jghali 1759
                                                itemHeight = font.height(style.charStyle().fontSize() / 10.0);
18524 avox 1760
                                        asce = currentObject->height() + currentObject->lineWidth();
21218 fschmid 1761
                                        wide = currentObject->width() + currentObject->lineWidth();
16868 jghali 1762
                                        realAsce = calculateLineSpacing (style, this) * DropLines;
21107 craig 1763
                                        firstGlyph.scaleH /= firstGlyph.scaleV;
1764
                                        firstGlyph.scaleV = (realAsce / itemHeight);
1765
                                        firstGlyph.scaleH *= firstGlyph.scaleV;
21218 fschmid 1766
                                        wide *= firstGlyph.scaleH;
5362 avox 1767
                                }
1768
                                else
1769
                                {
17826 craig 1770
                                        double realCharHeight = 0.0;
1771
                                        wide = 0.0; realAsce = 0.0;
21107 craig 1772
                                        foreach (GlyphLayout gl, glyphRuns[i].glyphs()) {
1773
                                                GlyphMetrics gm;
1774
                                                gm = font.glyphBBox(gl.glyph, charStyle.fontSize() / 10.0);
1775
                                                realCharHeight = qMax(realCharHeight, gm.ascent + gm.descent);
1776
                                                gm = font.glyphBBox(gl.glyph, chsd / 10.0);
1777
                                                realAsce = qMax(realAsce, gm.ascent + gm.descent);
1778
                                                wide += gm.width;
17826 craig 1779
                                        }
21155 jghali 1780
                                        wide = (wide * scaleH) + (1 - scaleH);
17826 craig 1781
                                        realAsce = realAsce  * scaleV + offset;
14929 jghali 1782
                                        if (realCharHeight == 0)
17757 jghali 1783
                                                realCharHeight = font.height(style.charStyle().fontSize() / 10.0);
1784
                                        asce = font.ascent(hlcsize10);
16868 jghali 1785
                                        // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]);
21107 craig 1786
                                        firstGlyph.scaleH /= firstGlyph.scaleV;
1787
                                        firstGlyph.scaleV = (realAsce / realCharHeight);
1788
                                        firstGlyph.scaleH *= firstGlyph.scaleV;
1789
                                        firstGlyph.xoffset -= 0.5; //drop caps are always to far from column left edge
5362 avox 1790
                                }
21194 jghali 1791
                                // This is to mimic pre-boxes branches in case first character of paragraph is a space
1792
                                // If we don't do this, paragraph offset will not apply correctly to first line
1793
                                if ((firstGlyph.scaleH == 0.0) || (firstGlyph.scaleV == 0.0))
1794
                                {
1795
                                        firstGlyph.scaleH = firstGlyph.scaleV = 1.0;
1796
                                        wide = 0.0;
1797
                                }
21160 jghali 1798
                                firstGlyph.xadvance = wide / firstGlyph.scaleH;
19338 jghali 1799
                                desc = realDesc = 0;
5362 avox 1800
                        }
8814 cbradney 1801
                        else // !DropCMode
5362 avox 1802
                        {
5408 avox 1803
                                // find ascent / descent
17826 craig 1804
                                if (HasObject)
16868 jghali 1805
                                        desc = realDesc = 0;
5362 avox 1806
                                else
1807
                                {
21107 craig 1808
                                        if (itemText.text(a) != SpecialChars::OBJECT)
17826 craig 1809
                                        {
21107 craig 1810
                                                foreach (GlyphLayout gl, glyphRuns[i].glyphs()) {
1811
                                                        GlyphMetrics gm = font.glyphBBox(gl.glyph, hlcsize10);
21174 fschmid 1812
                                                        realDesc = qMax(realDesc, gm.descent * scaleV - offset);
21107 craig 1813
                                                        realAsce = gm.ascent;
1814
                                                }
17826 craig 1815
                                        }
17757 jghali 1816
                                        desc = -font.descent(hlcsize10);
21107 craig 1817
                                        current.rememberShrinkStretch(itemText.text(a), wide, style);
5362 avox 1818
                                }
17826 craig 1819
                                if (HasObject)
17199 fschmid 1820
                                {
18524 avox 1821
                                        asce = currentObject->height() + currentObject->lineWidth();
17199 fschmid 1822
                                        realAsce = asce * scaleV + offset;
1823
                                }
1824
                                else
1825
                                {
17757 jghali 1826
                                        asce = font.ascent(hlcsize10);
18047 craig 1827
                                        if (HasMark && !BulNumMode)
17826 craig 1828
                                                realAsce = asce * scaleV + offset;
1829
                                        else
1830
                                        {
21107 craig 1831
                                                foreach (GlyphLayout gl, glyphRuns[i].glyphs())
1832
                                                        realAsce = qMax(realAsce, font.glyphBBox(gl.glyph, hlcsize10).ascent * scaleV + offset);
17826 craig 1833
                                        }
17199 fschmid 1834
                                }
5362 avox 1835
                        }
18047 craig 1836
//                      if (BulNumMode)
1837
//                              hl->glyph.last()->xadvance += style.parEffectOffset();
16868 jghali 1838
                        //check for Y position at beginning of line
21107 craig 1839
                        if (current.isEmpty && !current.afterOverflow)
5362 avox 1840
                        {
16868 jghali 1841
                                if (current.recalculateY)
5362 avox 1842
                                {
16868 jghali 1843
                                        //if top of column Y position depends on first line offset
1844
                                        if (current.startOfCol)
3614 cbradney 1845
                                        {
19831 craig 1846
                                                lastLineY = qMax(lastLineY, m_textDistanceMargins.top() + lineCorr);
17826 craig 1847
                                                //fix for proper rendering first empty line (only with PARSEP)
21107 craig 1848
                                                if (itemText.text(a) == SpecialChars::PARSEP)
17826 craig 1849
                                                        current.yPos += style.lineSpacing();
17760 jghali 1850
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing || FlopBaseline)
3614 cbradney 1851
                                                {
17760 jghali 1852
                                                        if (current.yPos <= lastLineY)
1853
                                                                current.yPos = lastLineY +1;
18032 craig 1854
                                                        double by = m_yPos;
17760 jghali 1855
                                                        if (OwnPage != -1)
18032 craig 1856
                                                                by = m_yPos - m_Doc->Pages->at(OwnPage)->yOffset();
17760 jghali 1857
                                                        int ol1 = qRound((by + current.yPos - m_Doc->guidesPrefs().offsetBaselineGrid) * 10000.0);
1858
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->guidesPrefs().valueBaselineGrid);
1859
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->guidesPrefs().valueBaselineGrid + m_Doc->guidesPrefs().offsetBaselineGrid - by;
1860
                                                }
1861
                                                else if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
1862
                                                {
16868 jghali 1863
                                                        if (firstLineOffset() == FLOPRealGlyphHeight)
1864
                                                        {
1865
                                                                if (DropCmode)
1866
                                                                        current.yPos += asce;
1867
                                                                else
1868
                                                                        current.yPos += realAsce;
1869
                                                        }
1870
                                                        else if (firstLineOffset() == FLOPLineSpacing)
1871
                                                                current.yPos += style.lineSpacing();
1872
                                                        else
1873
                                                                current.yPos += asce;
3614 cbradney 1874
                                                }
1875
                                        }
16868 jghali 1876
                                        else
1877
                                        {
1878
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1879
                                                {
1880
                                                        current.yPos += m_Doc->guidesPrefs().valueBaselineGrid;
18032 craig 1881
                                                        double by = m_yPos;
16868 jghali 1882
                                                        if (OwnPage != -1)
18032 craig 1883
                                                                by = m_yPos - m_Doc->Pages->at(OwnPage)->yOffset();
16868 jghali 1884
                                                        int ol1 = qRound((by + current.yPos - m_Doc->guidesPrefs().offsetBaselineGrid) * 10000.0);
1885
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->guidesPrefs().valueBaselineGrid);
1886
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->guidesPrefs().valueBaselineGrid + m_Doc->guidesPrefs().offsetBaselineGrid - by;
1887
                                                }
1888
                                                else
1889
                                                        current.yPos += style.lineSpacing();
1890
                                        }
1891
                                        if (DropCmode)
1892
                                                current.yPos += DropCapDrop;
5362 avox 1893
                                }
16868 jghali 1894
                                //set left indentation
1895
                                current.leftIndent = 0.0;
18047 craig 1896
                                if (current.addLeftIndent && (maxDX == 0 || DropCmode || BulNumMode))
5362 avox 1897
                                {
18047 craig 1898
                                        current.leftIndent = style.leftMargin() + autoLeftIndent;
16868 jghali 1899
                                        if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP)))
18047 craig 1900
                                        {
16868 jghali 1901
                                                current.leftIndent += style.firstIndent();
18047 craig 1902
                                                if (BulNumMode || DropCmode)
1903
                                                {
19927 jghali 1904
                                                        if (style.parEffectIndent())
18047 craig 1905
                                                        {
1906
                                                                current.leftIndent -= style.parEffectOffset() + wide;
1907
                                                                if (current.leftIndent < 0.0)
1908
                                                                {
1909
                                                                        autoLeftIndent = abs(current.leftIndent);
1910
                                                                        current.leftIndent = 0.0;
1911
                                                                }
1912
                                                        }
1913
                                                }
1914
                                        }
16868 jghali 1915
                                        current.addLeftIndent = false;
5362 avox 1916
                                }
1917
                        }
16868 jghali 1918
                        current.recalculateY = true;
17599 craig 1919
                        maxYAsc = 0.0, maxYDesc = 0.0;
18047 craig 1920
                        double addAsce = 0.0;
16868 jghali 1921
                        if (current.startOfCol)
5362 avox 1922
                        {
17599 craig 1923
                                if (DropCmode)
1924
                                        addAsce = qMax(realAsce, asce + offset);
1925
                                else
1926
                                        addAsce = asce + offset;
16868 jghali 1927
                                if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
5362 avox 1928
                                {
16868 jghali 1929
                                        if (firstLineOffset() == FLOPRealGlyphHeight)
1930
                                                addAsce = realAsce;
1931
                                        else if (firstLineOffset() == FLOPLineSpacing)
1932
                                                addAsce = style.lineSpacing();
5362 avox 1933
                                }
17595 craig 1934
                                maxYAsc = current.yPos - addAsce;
16868 jghali 1935
                        }
1936
                        else
17599 craig 1937
                                maxYAsc = current.yPos - realAsce;
16913 jghali 1938
                        //fix for glyphs with negative realAsce value
17595 craig 1939
                        maxYAsc = qMax(maxYAsc, 0.0);
17599 craig 1940
                        maxYDesc = current.yPos + realDesc;
16868 jghali 1941
 
18524 avox 1942
                        if (true||style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
1943
                        {
1944
                                regionMinY = static_cast<int>(floor(maxYAsc));
1945
                                regionMaxY = static_cast<int>(floor(maxYDesc));
1946
                        }
1947
                        else // #11727, #11628, etc.
1948
                        {
1949
                                regionMinY = static_cast<int>(qMax(0.0, floor(current.yPos - (asce + offset))));
1950
                                regionMaxY = static_cast<int>(floor(current.yPos + desc));
1951
                        }
18482 jghali 1952
 
21107 craig 1953
                        if (current.isEmpty && !current.afterOverflow)
16868 jghali 1954
                        {
1955
                                //start a new line
1956
                                goNoRoom = false;
1957
 
1958
                                // find line`s start
18482 jghali 1959
                                pt1 = QPoint(static_cast<int>(floor(current.xPos)), regionMinY);
1960
                                pt2 = QPoint(static_cast<int>(floor(current.xPos + (style.minGlyphExtension() * wide))), regionMaxY -1);
16868 jghali 1961
                                pt = QRect(pt1, pt2);
1962
                                realEnd = 0;
1963
                                //check if there is overflow at start of line, if so jump behind it and check again
1964
                                double Xpos, Xend;
1965
                                bool done = false;
1966
                                bool newColumn = false;
18524 avox 1967
 
17215 jghali 1968
                                //FIX ME - that should be paragraph style`s properties
1969
                                //if set then indent is add to possible line start point (after overflow)
1970
                                //if not then indent is calculated from column left edge
21017 craig 1971
                                //if you don't agree that adding indent to overflow should be default behaviour
17215 jghali 1972
                                //then change it to false
1973
                                bool addIndent2overflow = false; // should be addIndent2Overflow = style.addIndent2Overlow();
1974
                                bool addFirstIndent2overflow = true; // should be addFirstIndent2Overflow = style.addFirstIndent2Overlow();
1975
                                //if first line indent is negative and left indent should not be added to overflow
21017 craig 1976
                                //then don't add first line ident either
17215 jghali 1977
                                if ((style.firstIndent() < 0) && !addIndent2overflow)
1978
                                        addFirstIndent2overflow = false;
1979
 
16868 jghali 1980
                                while (!done)
8814 cbradney 1981
                                {
17215 jghali 1982
                                        Xpos = current.xPos + (addIndent2overflow ? 0 : current.leftIndent);
16868 jghali 1983
                                        Xend = current.xPos + current.leftIndent;
1984
                                        //check if in indent any overflow occurs
1985
                                        while (Xpos <= Xend && Xpos < current.colRight)
3614 cbradney 1986
                                        {
18482 jghali 1987
                                                pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)), regionMinY));
17578 craig 1988
                                                if (!regionContainsRect(m_availableRegion, pt))
16868 jghali 1989
                                                {
17578 craig 1990
                                                        Xpos = current.xPos = realEnd = findRealOverflowEnd(m_availableRegion, pt, current.colRight);
17215 jghali 1991
                                                        Xend = current.xPos + (addIndent2overflow ? current.leftIndent : 0);
1992
                                                        //for first paragraph`s line - if first line offset should be added
1993
                                                        if ( addFirstIndent2overflow && (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))))
1994
                                                                Xend += style.firstIndent();
16868 jghali 1995
                                                }
1996
                                                else
1997
                                                        Xpos++;
1998
                                        }
1999
                                        current.xPos = Xend;
2000
                                        done = true;
17215 jghali 2001
                                        if (current.isEndOfLine((style.minGlyphExtension() * wide) + current.rightMargin))
16868 jghali 2002
                                        {
5408 avox 2003
                                                // new line
16868 jghali 2004
                                                current.xPos = qMax(current.colLeft, maxDX);
17760 jghali 2005
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing || FlopBaseline)
5362 avox 2006
                                                {
17085 jghali 2007
                                                        current.yPos++;
18032 craig 2008
                                                        double by = m_yPos;
16868 jghali 2009
                                                        if (OwnPage != -1)
18032 craig 2010
                                                                by = m_yPos - m_Doc->Pages->at(OwnPage)->yOffset();
16868 jghali 2011
                                                        int ol1 = qRound((by + current.yPos - m_Doc->guidesPrefs().offsetBaselineGrid) * 10000.0);
2012
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->guidesPrefs().valueBaselineGrid);
2013
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->guidesPrefs().valueBaselineGrid + m_Doc->guidesPrefs().offsetBaselineGrid - by;
2014
                                                }
17085 jghali 2015
                                                else if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
2016
                                                        current.yPos += (current.startOfCol ? 1 : style.lineSpacing());
2017
                                                else
21188 fschmid 2018
                                                        current.yPos += (current.startOfCol ? 1 : style.lineSpacing());