Subversion Repositories Scribus

Rev

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