Subversion Repositories Scribus

Rev

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

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