Subversion Repositories Scribus

Rev

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