Subversion Repositories Scribus

Rev

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