Subversion Repositories Scribus

Rev

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

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
3614 cbradney 7
/***************************************************************************
8
                          pageitem.cpp  -  description
9
                             -------------------
10
    begin                : Sat Apr 7 2001
11
    copyright            : (C) 2001 by Franz Schmid
12
    email                : Franz.Schmid@altmuehlnet.de
13
 ***************************************************************************/
14
 
15
/***************************************************************************
16
 *                                                                         *
17
 *   This program is free software; you can redistribute it and/or modify  *
18
 *   it under the terms of the GNU General Public License as published by  *
19
 *   the Free Software Foundation; either version 2 of the License, or     *
20
 *   (at your option) any later version.                                   *
21
 *                                                                         *
22
 ***************************************************************************/
23
 
12269 cbradney 24
#include <QDebug>
9803 fschmid 25
#include <QList>
10220 cbradney 26
#include <QMatrix>
12269 cbradney 27
#include <QPalette>
10220 cbradney 28
#include <QPoint>
12269 cbradney 29
#include <QPolygon>
10220 cbradney 30
#include <QRegion>
12269 cbradney 31
#include <cassert>
3614 cbradney 32
 
12269 cbradney 33
 
10532 avox 34
#include "canvas.h"
10220 cbradney 35
#include "commonstrings.h"
36
#include "guidemanager.h"
3829 cbradney 37
#include "hyphenator.h"
3614 cbradney 38
#include "page.h"
39
#include "pageitem.h"
10220 cbradney 40
#include "pageitem_textframe.h"
3614 cbradney 41
#include "prefsmanager.h"
10220 cbradney 42
#include "scconfig.h"
10601 mrdocs 43
#include "scpainter.h"
3614 cbradney 44
#include "scpaths.h"
10601 mrdocs 45
#include "scraction.h"
3614 cbradney 46
#include "scribus.h"
10220 cbradney 47
#include "scribusdoc.h"
3614 cbradney 48
#include "scribusstructs.h"
16342 mrdocs 49
#include "scribusXml.h"
50
#include "serializer.h"
4145 cbradney 51
#include "selection.h"
10220 cbradney 52
#include "text/nlsconfig.h"
3614 cbradney 53
#include "undomanager.h"
54
#include "undostate.h"
10601 mrdocs 55
#include "util.h"
10203 cbradney 56
#include "util_math.h"
12004 fschmid 57
#ifdef HAVE_CAIRO
58
        #include <cairo.h>
59
#endif
3614 cbradney 60
 
61
using namespace std;
62
 
63
PageItem_TextFrame::PageItem_TextFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, QString fill, QString outline)
64
        : PageItem(pa, PageItem::TextFrame, x, y, w, h, w2, fill, outline)
65
{
9816 avox 66
        invalid = true;
67
        firstChar = 0;
8931 cbradney 68
        cursorBiasBackward = false;
3829 cbradney 69
        unicodeTextEditMode = false;
70
        unicodeInputCount = 0;
71
        unicodeInputString = "";
16342 mrdocs 72
        lastUndoAction = NOACTION;
13148 pierre 73
 
74
        connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout()));
3614 cbradney 75
}
76
 
12839 fschmid 77
PageItem_TextFrame::PageItem_TextFrame(const PageItem & p) : PageItem(p)
78
{
79
        invalid = true;
80
        cursorBiasBackward = false;
81
        unicodeTextEditMode = false;
82
        unicodeInputCount = 0;
83
        unicodeInputString = "";
16342 mrdocs 84
        lastUndoAction = NOACTION;
85
 
13148 pierre 86
        connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout()));
12839 fschmid 87
}
5184 avox 88
 
10701 avox 89
static QRegion itemShape(PageItem* docItem, double xOffset, double yOffset)
5184 avox 90
{
91
        QRegion res;
9372 fschmid 92
        QMatrix pp;
5184 avox 93
        pp.translate(docItem->xPos() - xOffset, docItem->yPos() - yOffset);
94
        pp.rotate(docItem->rotation());
95
        if (docItem->textFlowUsesBoundingBox())
96
        {
10284 fschmid 97
                QPolygon tcli(4);
5184 avox 98
                tcli.setPoint(0, QPoint(0,0));
99
                tcli.setPoint(1, QPoint(qRound(docItem->width()), 0));
100
                tcli.setPoint(2, QPoint(qRound(docItem->width()), qRound(docItem->height())));
101
                tcli.setPoint(3, QPoint(0, qRound(docItem->height())));
9372 fschmid 102
                res = QRegion(pp.map(tcli));
5184 avox 103
        }
8445 fschmid 104
        else if ((docItem->textFlowUsesImageClipping()) && (docItem->imageClip.size() != 0))
5184 avox 105
        {
9803 fschmid 106
                QList<uint> Segs;
10284 fschmid 107
                QPolygon Clip2 = FlattenPath(docItem->imageClip, Segs);
9668 fschmid 108
                res = QRegion(pp.map(Clip2)).intersect(QRegion(pp.map(docItem->Clip)));
5184 avox 109
        }
8445 fschmid 110
        else if ((docItem->textFlowUsesContourLine()) && (docItem->ContourLine.size() != 0))
111
        {
9803 fschmid 112
                QList<uint> Segs;
10284 fschmid 113
                QPolygon Clip2 = FlattenPath(docItem->ContourLine, Segs);
9372 fschmid 114
                res = QRegion(pp.map(Clip2));
8445 fschmid 115
        }
116
        else
9372 fschmid 117
                res = QRegion(pp.map(docItem->Clip));
5184 avox 118
        return  res;
119
}
120
 
16988 jghali 121
QRegion PageItem_TextFrame::availableRegion()
5184 avox 122
{
16988 jghali 123
        QRegion result(this->Clip);
5184 avox 124
        if (!isEmbedded)
125
        {
16988 jghali 126
                bool invertible(false);
127
                QMatrix canvasToLocalMat;
128
                canvasToLocalMat.translate(Xpos, Ypos);
129
                canvasToLocalMat.rotate(Rot);
130
                canvasToLocalMat = canvasToLocalMat.inverted(&invertible);
131
 
132
                if (!invertible) return QRegion();
133
 
7181 cbradney 134
                int LayerLev = m_Doc->layerLevelFromNumber(LayerNr);
135
                uint docItemsCount=m_Doc->Items->count();
136
                Page* Mp=0;
137
                Page* Dp=0;
138
                PageItem* docItem=0;
139
                int LayerLevItem;
5184 avox 140
                if (!OnMasterPage.isEmpty())
141
                {
5559 avox 142
                        if ((savedOwnPage == -1) || (savedOwnPage >= signed(m_Doc->Pages->count())))
5375 fschmid 143
                                return result;
7175 fschmid 144
                        Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
145
                        Dp = m_Doc->Pages->at(savedOwnPage);
11310 fschmid 146
                        int currentGroup = -1;
9856 fschmid 147
                        for (int a = 0; a < m_Doc->MasterItems.count(); ++a)
5184 avox 148
                        {
7175 fschmid 149
                                docItem = m_Doc->MasterItems.at(a);
17402 jghali 150
                                // #10642 : masterpage items interact only with items placed on same masterpage
151
                                if (docItem->OnMasterPage != OnMasterPage)
152
                                        continue;
7175 fschmid 153
                                LayerLevItem = m_Doc->layerLevelFromNumber(docItem->LayerNr);
10550 avox 154
                                if (((docItem->ItemNr > ItemNr) && (docItem->LayerNr == LayerNr)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerNr)))
5184 avox 155
                                {
11310 fschmid 156
                                        if (docItem->Groups.count() == 0)
157
                                                currentGroup = -1;
11444 fschmid 158
                                        if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top()))
11310 fschmid 159
                                                continue;
5620 jghali 160
                                        if (docItem->textFlowAroundObject())
16988 jghali 161
                                        {
162
                                                QRegion itemRgn = itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset());
163
                                                result = result.subtracted( canvasToLocalMat.map(itemRgn) );
164
                                        }
11310 fschmid 165
                                        if (docItem->isGroupControl)
166
                                                currentGroup = docItem->Groups.top();
5387 avox 167
                                }
168
                        } // for all masterItems
10240 jghali 169
                        // (JG) #6009 : disable possible interaction between master text frames and normal frames
170
                        // which have the text flow option set
171
                        /*if (!m_Doc->masterPageMode())
5184 avox 172
                        {
173
                                for (uint a = 0; a < docItemsCount; ++a)
174
                                {
7175 fschmid 175
                                        docItem = m_Doc->Items->at(a);
176
                                        Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
177
                                        Dp = m_Doc->Pages->at(OwnPage);
5620 jghali 178
                                        if ((docItem->textFlowAroundObject()) && (docItem->OwnPage == OwnPage))
5184 avox 179
                                        {
180
                                                result = result.subtract(itemShape(docItem, m_Doc->view(), Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset()));
181
                                        }
182
                                } // for all docItems
10240 jghali 183
                        } // if (! masterPageMode) */
5387 avox 184
                } // if (!OnMasterPage.isEmpty())
5184 avox 185
                else
186
                {
11310 fschmid 187
                        int currentGroup = -1;
5184 avox 188
                        for (uint a = 0; a < docItemsCount; ++a)
189
                        {
7175 fschmid 190
                                docItem = m_Doc->Items->at(a);
191
                                LayerLevItem = m_Doc->layerLevelFromNumber(docItem->LayerNr);
10550 avox 192
                                if (((docItem->ItemNr > ItemNr) && (docItem->LayerNr == LayerNr)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerNr)))
5184 avox 193
                                {
11310 fschmid 194
                                        if (docItem->Groups.count() == 0)
195
                                                currentGroup = -1;
11444 fschmid 196
                                        if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top()))
11310 fschmid 197
                                                continue;
198
                                        if (docItem->textFlowAroundObject())
16988 jghali 199
                                        {
200
                                                QRegion itemRgn = itemShape(docItem, 0, 0);
201
                                                result = result.subtracted( canvasToLocalMat.map(itemRgn) );
202
                                        }
11310 fschmid 203
                                        if (docItem->isGroupControl)
204
                                                currentGroup = docItem->Groups.top();
5387 avox 205
                                }
206
                        } // for all docItems
11785 jghali 207
                } // if(OnMasterPage.isEmpty()          
5184 avox 208
        } // if(!Embedded)
209
        return result;
210
}
211
 
6144 avox 212
void PageItem_TextFrame::setShadow()
213
{
214
        if (OnMasterPage.isEmpty())
215
                return;
6366 avox 216
 
6144 avox 217
        QString newShadow = m_Doc->masterPageMode() ? OnMasterPage : QString::number(OwnPage);
218
        if (newShadow != currentShadow) {
6366 avox 219
                if (currentShadow == OnMasterPage) {
220
                        // masterpage was edited, clear all shadows
221
                        shadows.clear();
222
                }
6144 avox 223
                if (!shadows.contains(newShadow)) {
224
                        if (!shadows.contains(OnMasterPage)) {
225
                                shadows[OnMasterPage] = itemText;
7905 avox 226
//                              const ParagraphStyle& pstyle(shadows[OnMasterPage].paragraphStyle(0));
13085 jghali 227
//                              qDebug() << QString("Pageitem_Textframe: style of master: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
228
//                              qDebug() << QString("Pageitem_Textframe: shadow itemText->%1").arg(OnMasterPage);
6144 avox 229
                        }
7887 avox 230
                        if (newShadow != OnMasterPage) {
231
                                shadows[newShadow] = shadows[OnMasterPage].copy();
232
//                              const ParagraphStyle& pstyle(shadows[newShadow].paragraphStyle(0));
13085 jghali 233
//                              qDebug() << QString("Pageitem_Textframe: style of shadow copy: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
7887 avox 234
                        }
13085 jghali 235
//                      qDebug() << QString("Pageitem_Textframe: shadow %1<-%2").arg(newShadow).arg(OnMasterPage);
6144 avox 236
                }
237
                itemText = shadows[newShadow];
7887 avox 238
//              const ParagraphStyle& pstyle(itemText.paragraphStyle(0));
13085 jghali 239
//              qDebug() << QString("Pageitem_Textframe: style of shadow: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
6144 avox 240
                invalid = true;
241
                currentShadow = newShadow;
242
        }
243
}
5291 avox 244
 
17739 jghali 245
static void debugLineLayout(const StoryText& itemText, const LineSpec& line)
246
{
247
        QFile debugFile(QDir::homePath() + "/Desktop/debug_line.csv");
248
        debugFile.open(QIODevice::WriteOnly);
249
 
250
        QTextStream stream(&debugFile);
251
        stream.setRealNumberNotation(QTextStream::FixedNotation);
252
        stream.setRealNumberPrecision(7);
253
 
254
        stream << "xoffset"  << "\t";
255
        stream << "yoffset"  << "\t";
256
        stream << "xadvance" << "\t";
257
        stream << "yadvance" << "\t";
258
        stream << "scaleH"   << "\t";
259
        stream << "scaleV"   << "\t";
260
        stream << "\n";
261
 
262
        for (int zc = line.firstItem; zc < line.lastItem; ++zc)
263
        {
264
                const ScText* item = itemText.item(zc);
265
 
266
                stream << item->glyph.xoffset  << "\t";
267
                stream << item->glyph.yoffset  << "\t";
268
                stream << item->glyph.xadvance << "\t";
269
                stream << item->glyph.yadvance << "\t";
270
                stream << item->glyph.scaleH   << "\t";
271
                stream << item->glyph.scaleV   << "\t";
272
                stream << "\n";
273
        }
274
 
275
        debugFile.close();
276
}
277
 
5778 avox 278
static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->"))
279
{
10553 fschmid 280
        QString db = QString("%6%1/%2 @ %3: %4--%5 linespa%6: %7 align%8")
5778 avox 281
                   .arg(pstyle.name())
6733 avox 282
                   .arg(pstyle.parent())
5850 tsoots 283
                   .arg( (unsigned long int) &pstyle)
5778 avox 284
                   .arg(pstyle.leftMargin())
285
                   .arg(pstyle.rightMargin())
6805 avox 286
                   .arg(indent)
287
                   .arg(pstyle.lineSpacingMode())
288
                   .arg(pstyle.lineSpacing())
10553 fschmid 289
                   .arg(pstyle.alignment());
13085 jghali 290
        qDebug() << db;
5778 avox 291
        static QString more("  ");
6733 avox 292
        if (pstyle.hasParent())
293
                dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent);
5778 avox 294
}
295
 
8103 avox 296
static const bool legacy = true;
297
 
10553 fschmid 298
/*
7313 avox 299
static void layoutDropCap(GlyphLayout layout, double curX, double curY, double offsetX, double offsetY, double dropCapDrop)
300
{      
6370 avox 301
}
10553 fschmid 302
*/
6370 avox 303
 
8761 avox 304
/**
305
 Clones the tab fill char as often as necssary after all distances are known
306
 */
7905 avox 307
static void fillInTabLeaders(StoryText & itemText, LineSpec & curLine)
308
{
309
        // fill in tab leaders
310
        double xPos = curLine.x;
13178 jghali 311
        for (int ti= curLine.firstItem; ti <= curLine.lastItem; ++ti)
7905 avox 312
        {
313
                ScText * hl = itemText.item(ti);
9737 jghali 314
                if (hl->ch == SpecialChars::TAB)
7905 avox 315
                {
316
                        GlyphLayout * tglyph = hl->glyph.more;
317
 
318
                        if (!tglyph)
319
                                continue;
320
 
321
                        const CharStyle & charStyle(itemText.charStyle(ti));
322
                        double wt   = charStyle.font().glyphWidth(tglyph->glyph, charStyle.fontSize() * tglyph->scaleV / 10.0);
323
                        double len  = hl->glyph.xadvance;
324
                        int count   = static_cast<int>(len / wt);
325
                        double sPos = -len;
326
                        tglyph->xoffset = sPos;
13085 jghali 327
//                      qDebug() << QString("tab leaders: %1 %2 width=%3 count=%4").arg(sPos).arg(curLine.y).arg(wt).arg(count);
7905 avox 328
                        for (int cx = 1; cx < count; ++cx)
329
                        {
330
                                // clone fillchar
331
                                tglyph->grow();
332
                                *(tglyph->more) = *tglyph;
333
                                tglyph->more->more = NULL;
334
                                tglyph = tglyph->more;
335
                                tglyph->xoffset =  sPos + wt * cx;
336
                        }
337
                }
338
                xPos += hl->glyph.wide();
339
        }
340
}
341
 
342
 
7887 avox 343
 
7905 avox 344
enum TabStatus {
345
        TabNONE    = 0,
346
        TabLEFT    = TabNONE,
347
        TabRIGHT   = 1,
348
        TabPOINT   = 2,
349
        TabCOMMA   = 3,
350
        TabCENTER  = 4
7313 avox 351
};
6370 avox 352
 
8761 avox 353
 
354
/**
355
fields which describe what type of tab is currently active
356
 */
7313 avox 357
struct TabControl {
358
        bool   active;
7905 avox 359
        int    status;
7313 avox 360
        int    charIndex;
361
        double xPos;
7905 avox 362
        QChar  fillChar;
7313 avox 363
};
364
 
8761 avox 365
/**
366
fields which describe how the current line is placed into the frame
367
 */
7313 avox 368
struct LineControl {
369
        LineSpec line;
370
        int      itemsInLine;
371
        int      hyphenCount;
372
        double   colWidth;
8095 avox 373
        double   colGap;
7313 avox 374
        double   colLeft;
375
        double   colRight;
376
        int      column;
377
        bool     startOfCol;
15028 jghali 378
        bool     hasDropCap;
16867 jghali 379
        bool     afterOverflow;
380
        bool     addLine;
381
        bool     recalculateY;
382
        bool     lastInRowLine;
383
        bool     addLeftIndent;
384
        bool     wasFirstInRow;
385
        double   leftIndent;
386
        double   rightMargin;
387
        double   mustLineEnd;
388
        int      restartIndex;  //index of char where line computing should be restarted
389
        int      restartRowIndex;  //index of char where row of text is started
390
        double   restartX; //starting X position of line if must be restarted
391
        double   rowDesc;
392
 
7313 avox 393
        double   ascend;
394
        double   descend;
395
        double   width;
396
        double   xPos;
397
        double   yPos;
398
        int      breakIndex;
399
        double   breakXPos;
9047 avox 400
 
401
        double   maxShrink;
402
        double   maxStretch;
8095 avox 403
 
404
 
8761 avox 405
        /// remember frame dimensions and offsets
8095 avox 406
        void init(double w, double h, const MarginStruct& extra, double lCorr)
407
        {
408
                insets = extra;
409
                lineCorr = lCorr;
410
                frameWidth = w;
411
                frameHeight = h;
15055 jghali 412
                hasDropCap = false;
8095 avox 413
        }
414
 
8761 avox 415
        /// start at column 0
8095 avox 416
        void initColumns(double width, double gap)
417
        {
418
                column = 0;
419
                colWidth = width;
420
                colGap = gap;
421
        }
422
 
8761 avox 423
        /// move position to next column
16867 jghali 424
        void nextColumn(double asce = 0.0)
8095 avox 425
        {
426
                startOfCol = true;
427
                colLeft = (colWidth + colGap) * column + insets.Left + lineCorr;
16867 jghali 428
                //now colRight is REAL column right edge
8095 avox 429
                colRight = colLeft + colWidth;
8103 avox 430
                if (legacy)
16867 jghali 431
                        colRight += lineCorr;
8095 avox 432
                xPos = colLeft;
16867 jghali 433
                yPos = asce + insets.Top + lineCorr;
8095 avox 434
        }
435
 
436
        bool isEndOfCol(double morespace = 0)
437
        {
438
                return yPos + morespace + insets.Bottom + lineCorr > frameHeight;
439
        }
16867 jghali 440
 
8761 avox 441
        /**
442
                init fields for a new line at current position
443
         */
8095 avox 444
        void startLine(int first)
15028 jghali 445
        {      
8095 avox 446
                itemsInLine = 0;
447
                line.x = xPos;
448
                line.y = yPos;
449
                line.firstItem = first;
16867 jghali 450
                line.lastItem = 0;
451
                line.ascent = 0.0;
452
                line.descent = 0.0;
453
                line.width = 0.0;
454
                line.naturalWidth = 0.0;
13211 jghali 455
                line.colLeft = colLeft;
8095 avox 456
                breakIndex = -1;
16867 jghali 457
                breakXPos = 0.0;
458
                maxShrink = 0.0;
459
                maxStretch = 0.0;
460
                width = 0.0;
461
                leftIndent = 0.0;
462
                rightMargin = 0.0;
463
                rowDesc = 0.0;
8095 avox 464
        }
465
 
9047 avox 466
 
467
        /// called when glyphs are placed on the line
468
        void rememberShrinkStretch(QChar ch, double wide, const ParagraphStyle& style)
469
        {
470
                if (SpecialChars::isExpandingSpace(ch))
471
                        maxShrink += (1 - style.minWordTracking()) * wide;
472
                else
473
                {
474
                        maxShrink += (1 - style.minGlyphExtension()) * wide;
475
                }
476
                maxStretch += (style.maxGlyphExtension() - 1) * wide;
12883 jghali 477
        }
9047 avox 478
 
8761 avox 479
        /// called when a possible break is passed
16867 jghali 480
        void rememberBreak(int index, double pos, double morespace = 0)
8095 avox 481
        {
16867 jghali 482
                if (pos > colRight - morespace)
9047 avox 483
                {
484
                        // only look for the first break behind the right edge
16867 jghali 485
                        //maxShrink = 0;
9047 avox 486
 
487
                        // check if we already have a better break
488
                        if (breakIndex >= 0)
489
                        {
490
                                double oldLooseness = qAbs(colRight - breakXPos);
491
 
492
                                double newLooseness = pos - colRight;
493
                                if (newLooseness >= oldLooseness)
494
                                        return;
495
                        }
496
                }
16867 jghali 497
                breakXPos = pos;
8095 avox 498
                breakIndex = index;
499
        }
500
 
8761 avox 501
        /// called when a mandatory break is found
15028 jghali 502
        void breakLine(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy, int last)
8095 avox 503
        {
504
                breakIndex = last;
505
                breakXPos  = line.x;
506
                for (int j = line.firstItem; j <= last; ++j)
507
                        if ( (itemText.item(j)->effects() & ScStyle_SuppressSpace) == 0)
508
                                breakXPos += itemText.item(j)->glyph.wide();
14553 jghali 509
                // #8194, #8717 : update line ascent and descent with sensible values
510
                // so that endOfLine() returns correct result
511
                updateHeightMetrics(itemText);
15028 jghali 512
                // #9060 : update line offset too
16867 jghali 513
                //updateLineOffset(itemText, style, offsetPolicy);
8095 avox 514
        }
16867 jghali 515
 
8761 avox 516
        /// use the last remembered break to set line width and itemrange
8095 avox 517
        void finishLine(double endX)
518
        {
519
                line.lastItem = breakIndex;
520
                line.naturalWidth = breakXPos - line.x;
521
                line.width = endX - line.x;
9047 avox 522
                maxShrink = maxStretch = 0;
8095 avox 523
        }
16867 jghali 524
 
525
        int restartRow(bool recalcY)
526
        {
527
                if (recalcY)
528
                        yPos++;
529
                recalculateY = recalcY;
530
                xPos = restartX = colLeft;
531
                startLine(restartRowIndex);
532
                addLeftIndent = true;
533
                afterOverflow = false;
534
                return restartRowIndex -1;
535
        }
536
 
537
        int restartLine(bool recalcY, bool add)
538
        {
539
                recalculateY = recalcY;
540
                addLine = add;
541
                xPos = restartX;
542
                startLine(restartIndex);
543
                afterOverflow = false;
544
                return restartIndex -1;
545
        }
546
 
8095 avox 547
        bool isEndOfLine(double moreSpace = 0)
548
        {
16867 jghali 549
                bool res;
8103 avox 550
                if (legacy)
16867 jghali 551
                        res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight);
8103 avox 552
                else
16867 jghali 553
                        res = ceil(xPos - maxShrink)  + ceil(moreSpace) >= floor(colRight);
554
                return res;
8095 avox 555
        }
16867 jghali 556
 
16924 jghali 557
        /// Keep old endOfLine code for reference
558
        /*double endOfLine_old(const QRegion& shape, const QMatrix& pf2, double morespace, int Yasc, int Ydesc)
8095 avox 559
        {
13402 jghali 560
                // if we aren't restricted further, we'll end at this maxX:
561
                double maxX = colRight - morespace;
16867 jghali 562
                if (legacy) maxX -= lineCorr;
13402 jghali 563
 
17287 malex 564
                double StartX = floor(qMax((double)line.x, qMin(maxX,breakXPos-maxShrink-1))-1);
16867 jghali 565
                int xPos  = static_cast<int>(ceil(maxX));
13402 jghali 566
 
16920 jghali 567
                QPoint  pt12 (xPos, Yasc);
568
                QPoint  pt22 (xPos, Ydesc);
569
                QRect   pt(pt12,pt22);
570
                QRegion region;
13402 jghali 571
 
572
                double EndX2 = StartX;
16867 jghali 573
                double Interval = 0.25;
13402 jghali 574
                do {
16867 jghali 575
                        int xP = static_cast<int>(ceil(EndX2 + morespace));
576
                        pt.moveTopLeft(QPoint(xP, Yasc));
16920 jghali 577
                        region = QRegion(pf2.mapToPolygon(pt)).subtracted(shape);
578
                        if (!region.isEmpty())
16867 jghali 579
                                break;
13402 jghali 580
                        EndX2 += Interval;
16920 jghali 581
                } while ((EndX2 < maxX) && region.isEmpty());
13402 jghali 582
 
16867 jghali 583
                return qMin(EndX2, maxX);
16924 jghali 584
        }*/
585
 
586
        /// find x position where this line must end
16988 jghali 587
        double endOfLine(const QRegion& shape, double morespace, int yAsc, int yDesc)
16924 jghali 588
        {
589
                // if we aren't restricted further, we'll end at this maxX:
590
                double maxX = colRight - morespace;
591
                if (legacy) maxX -= lineCorr;
592
 
17299 malex 593
                double StartX = floor(qMax((double)line.x, qMin(maxX,breakXPos-maxShrink-1))-1);
16924 jghali 594
                int xPos  = static_cast<int>(ceil(maxX));
595
 
596
                QPoint  pt12 (xPos, yAsc);
597
                QPoint  pt22 (xPos, yDesc);
598
 
599
                QPolygon p;
16988 jghali 600
                p.append (QPoint (StartX, yAsc));
601
                p.append (QPoint (StartX, yDesc));
602
                p.append (pt12);
603
                p.append (pt22);
16924 jghali 604
                // check if something gets in the way
605
                QRegion lineI = shape.intersected (p.boundingRect());
606
                // if the intersection only has 1 rectangle, then nothing gets in the way
607
                if (lineI.numRects() == 1)
608
                {
609
                        int   cPos = static_cast<int>(ceil(StartX + morespace));
610
                        QRect cRect (QPoint(cPos, yAsc), QPoint(cPos, yDesc));
16988 jghali 611
                        if (QRegion(cRect).subtracted(shape).isEmpty())
16924 jghali 612
                        {
613
                                QRect rect = lineI.rects().at(0);
16988 jghali 614
                                double  mx = qMax(rect.left(), rect.right()) /*- pf2.dx()*/;
16924 jghali 615
                                int steps  = static_cast<int>((mx - StartX - morespace - 2) / 0.25);
616
                                if (steps > 0)
617
                                {
618
                                        StartX += steps * 0.25;
619
                                }
620
                        }
621
                }
622
 
623
                QRect   pt(pt12, pt22);
624
 
625
                double EndX2 = StartX;
626
                double Interval = 0.25;
627
                do {
628
                        int xP = static_cast<int>(ceil(EndX2 + morespace));
629
                        pt.moveTopLeft(QPoint(xP, yAsc));
17043 jghali 630
                        if (!regionContainsRect(shape, pt))
16924 jghali 631
                                break;
632
                        EndX2 += Interval;
17043 jghali 633
                } while ((EndX2 < maxX) && regionContainsRect(shape, pt));
16924 jghali 634
 
635
                /*double oldEndX2 = endOfLine_old(shape, pf2, morespace, yAsc, yDesc);
636
                if (oldEndX2 != qMin(EndX2, maxX))
637
                {
638
                        qDebug() << "Different EndX : " << oldEndX2 << " (old) " << EndX2 << " (new) ";
639
                }*/
640
 
641
                return qMin(EndX2, maxX);
8095 avox 642
        }
16867 jghali 643
 
8956 avox 644
        double getLineAscent(const StoryText& itemText)
645
        {
646
                double result = 0;
16654 jghali 647
                QChar  firstChar = itemText.text(line.firstItem);
648
                const CharStyle& fcStyle(itemText.charStyle(line.firstItem));
649
                if ((firstChar == SpecialChars::PARSEP) || (firstChar == SpecialChars::LINEBREAK))
650
                        result = fcStyle.font().ascent(fcStyle.fontSize() / 10.0);
8956 avox 651
                else if (itemText.object(line.firstItem) != 0)
16654 jghali 652
                        result = qMax(result, (itemText.object(line.firstItem)->gHeight + itemText.object(line.firstItem)->lineWidth()) * (fcStyle.scaleV() / 1000.0));
653
                else if ((firstChar == SpecialChars::PAGENUMBER) || (firstChar == SpecialChars::PAGECOUNT))
654
                        result = fcStyle.font().realCharAscent('8', fcStyle.fontSize() / 10.0);
8956 avox 655
                else //if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap == 0)
16654 jghali 656
                        result = fcStyle.font().realCharAscent(firstChar, fcStyle.fontSize() / 10.0);
8956 avox 657
                for (int zc = 0; zc < itemsInLine; ++zc)
658
                {
659
                        QChar ch = itemText.text(line.firstItem + zc);
11713 fschmid 660
                        if ((ch == SpecialChars::PAGENUMBER) || (ch == SpecialChars::PAGECOUNT))
8956 avox 661
                                ch = '8'; // should have highest ascender even in oldstyle
662
                        const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
663
                        if ((ch == SpecialChars::TAB) || (ch == QChar(10))
664
                                || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN)
665
                                || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::LINEBREAK)
666
                                || (ch == SpecialChars::FRAMEBREAK) || (ch.isSpace()))
667
                                continue;
668
                        double asce;
669
                        if (itemText.object(line.firstItem + zc) != 0)
670
                                asce = itemText.object(line.firstItem + zc)->gHeight + itemText.object(line.firstItem + zc)->lineWidth() * (cStyle.scaleV() / 1000.0);
671
                        else //if (itemText.charStyle(current.line.firstItem + zc).effects() & ScStyle_DropCap == 0)
672
                                asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0);
13085 jghali 673
                        //      qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
10394 cbradney 674
                        result = qMax(result, asce);
8956 avox 675
                }
676
                return result;
677
        }
14553 jghali 678
 
679
        double getLineDescent(const StoryText& itemText)
680
        {
681
                double result = 0;
16654 jghali 682
                QChar  firstChar = itemText.text(line.firstItem);
683
                const CharStyle& fcStyle(itemText.charStyle(line.firstItem));
684
                if ((firstChar == SpecialChars::PARSEP) || (firstChar == SpecialChars::LINEBREAK))
685
                        result = fcStyle.font().descent(fcStyle.fontSize() / 10.0);
14553 jghali 686
                else if (itemText.object(line.firstItem) != 0)
687
                        result = 0.0;
16654 jghali 688
                else if ((firstChar == SpecialChars::PAGENUMBER) || (firstChar == SpecialChars::PAGECOUNT))
689
                        result = fcStyle.font().realCharDescent('8', fcStyle.fontSize() / 10.0);
14553 jghali 690
                else //if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap == 0)
16654 jghali 691
                        result = fcStyle.font().realCharDescent(firstChar, fcStyle.fontSize() / 10.0);
14553 jghali 692
                for (int zc = 0; zc < itemsInLine; ++zc)
693
                {
694
                        QChar ch = itemText.text(line.firstItem + zc);
695
                        if ((ch == SpecialChars::PAGENUMBER) || (ch == SpecialChars::PAGECOUNT))
696
                                ch = '8'; // should have highest ascender even in oldstyle
697
                        const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
698
                        if ((ch == SpecialChars::TAB) || (ch == QChar(10))
699
                                || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN)
700
                                || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::LINEBREAK)
701
                                || (ch == SpecialChars::FRAMEBREAK) || (ch.isSpace()))
702
                                continue;
703
                        double desc;
704
                        if (itemText.object(line.firstItem + zc) != 0)
705
                                desc = 0.0;
706
                        else //if (itemText.charStyle(current.line.firstItem + zc).effects() & ScStyle_DropCap == 0)
707
                                desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0);
708
                        //      qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
709
                        result = qMax(result, desc);
710
                }
711
                return result;
712
        }
8956 avox 713
 
714
        double getLineHeight(const StoryText& itemText)
715
        {
716
                double result = 0;
717
                if (itemText.object(line.firstItem) != 0)
10394 cbradney 718
                        result = qMax(result, (itemText.object(line.firstItem)->gHeight + itemText.object(line.firstItem)->lineWidth()) * (itemText.charStyle(line.firstItem).scaleV() / 1000.0));
8956 avox 719
                else //if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap == 0)
720
                        result = itemText.charStyle(line.firstItem).font().height(itemText.charStyle(line.firstItem).fontSize() / 10.0);
721
                for (int zc = 0; zc < itemsInLine; ++zc)
722
                {
723
                        QChar ch = itemText.text(line.firstItem+zc);
724
                        if ((ch == SpecialChars::TAB) || (ch == QChar(10))
725
                                || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN)
726
                                || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::FRAMEBREAK)
727
                                || (ch == SpecialChars::LINEBREAK) || (ch.isSpace()))
728
                                continue;
729
                        double asce;
730
                        if (itemText.object(line.firstItem+zc) != 0)
731
                                asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0);
732
                        else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0)
733
                                asce = itemText.charStyle(line.firstItem+zc).font().height(itemText.charStyle(line.firstItem+zc).fontSize() / 10.0);
13085 jghali 734
                        //      qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
10394 cbradney 735
                        result = qMax(result, asce);
8956 avox 736
                }
737
                return result;
738
        }
14553 jghali 739
 
740
        void updateHeightMetrics(const StoryText& itemText)
741
        {
742
                double asce, desc;
743
                line.ascent  = 0;
744
                line.descent = 0;
745
                for (int zc = 0; zc < itemsInLine; ++zc)
746
                {
747
                        QChar ch = itemText.text(line.firstItem+zc);
748
                        if ((ch == SpecialChars::TAB) || (ch == QChar(10))
749
                                || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN)
750
                                || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::FRAMEBREAK)
751
                                || (ch == SpecialChars::LINEBREAK) || (ch.isSpace()))
752
                                continue;
753
                        const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
16867 jghali 754
                        double scaleV = cStyle.scaleV() / 1000.0;
755
                        double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
756
 
14553 jghali 757
                        if (itemText.object(line.firstItem+zc) != 0)
758
                        {
16867 jghali 759
                                asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset;
14553 jghali 760
                                desc = 0.0;
761
                        }
762
                        else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0)
763
                        {
16867 jghali 764
                                asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset;
765
                                desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset;
14553 jghali 766
                        }
767
                        //      qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result);
17287 malex 768
                        line.ascent  = qMax((double)line.ascent, asce);
769
                        line.descent = qMax((double)line.descent, desc);
14553 jghali 770
                }
771
        }
8956 avox 772
 
16867 jghali 773
// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!!
774
//
775
//      void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy)
776
//      {
777
//              if (itemsInLine <= 0)
778
//                      return;
779
//              if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing))
780
//              {
781
//                      //FIXME: use glyphs, not chars
782
//                      double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0);
783
//                      double adj (0.0);
784
//                      double currasce (this->getLineAscent(itemText));
785
//                      if( offsetPolicy == FLOPRealGlyphHeight )
786
//                      {
787
//                              adj = firstasce - currasce;
788
//                      }
789
//                      else if( offsetPolicy == FLOPFontAscent )
790
//                      {
791
//                              adj = 0.0;
792
//                      }
793
//                      else if( offsetPolicy == FLOPLineSpacing )
794
//                      {
795
//                              adj = firstasce - style.lineSpacing();
796
//                      }
797
//                      line.ascent = currasce;
798
//                      line.y -= adj;
799
//                      yPos -= adj;
800
//              }
801
//              else if ((!startOfCol) && (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing))
802
//              {
803
//                      QChar ch = itemText.text(line.firstItem);
804
//                      double firstasce = style.lineSpacing();
805
//                      double currasce  = getLineHeight(itemText);                                             
806
//                      double adj = firstasce - currasce;
15028 jghali 807
//                      qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj);
16867 jghali 808
//                      line.ascent = currasce;
809
//                      line.y -= adj;
810
//                      yPos -= adj;
811
//              }
812
//      }
15028 jghali 813
 
8095 avox 814
private:
815
        double frameWidth;
816
        double frameHeight;
817
        MarginStruct insets;
818
        double lineCorr;
7313 avox 819
};
820
 
8761 avox 821
/// called when line length is known and line is to be justified
8095 avox 822
static void justifyLine(StoryText& itemText, LineSpec& line)
823
{
8761 avox 824
 
9047 avox 825
        double glyphNatural = 0;
826
        double spaceNatural = 0;
827
        double glyphExtension;
828
        double spaceExtension;
829
 
830
        const ParagraphStyle& style(itemText.paragraphStyle(line.firstItem));
831
 
832
        // measure natural widths for glyphs and spaces
9054 avox 833
        for (int sof = line.firstItem; sof <= line.lastItem; ++sof)
8095 avox 834
        {
9047 avox 835
                if (!SpecialChars::isExpandingSpace(itemText.text(sof)))
836
                {
837
                        glyphNatural += itemText.item(sof)->glyph.wide();
838
                }
839
                else if ( (itemText.item(sof)->effects() & ScStyle_SuppressSpace) == 0)
840
                {
841
                        spaceNatural += itemText.item(sof)->glyph.wide();
842
                }
8095 avox 843
        }
9047 avox 844
 
845
        // decision: prio 1: stretch glyph;  prio 2: stretch spaces
846
 
847
        if (line.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0)
848
        {
849
                glyphExtension = style.minGlyphExtension() - 1;
850
                spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural  - 1;
851
        }
852
        else if (line.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0)
853
        {
854
                spaceExtension = 0;
855
                glyphExtension = (line.width - spaceNatural) / glyphNatural  - 1;
856
        }
8095 avox 857
        else
9047 avox 858
        {
859
                glyphExtension = style.maxGlyphExtension() - 1;
860
                if (spaceNatural > 0)
861
                        spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural  - 1;
862
                else
863
                        spaceExtension = 0;
864
        }
8095 avox 865
 
9047 avox 866
        double glyphScale = 1 + glyphExtension;
867
 
868
/*
13085 jghali 869
        qDebug() << QString("justify: line = %7 natural = %1 + %2 = %3 (%4); spaces + %5%%; min=%8; glyphs + %6%%; min=%9")
9047 avox 870
                   .arg(spaceNatural).arg(glyphNatural).arg(spaceNatural+glyphNatural).arg(line.naturalWidth)
871
                   .arg(spaceExtension).arg(glyphExtension).arg(line.width)
13085 jghali 872
                   .arg(style.minWordTracking()).arg(style.minGlyphExtension());
9047 avox 873
        */
874
 
16867 jghali 875
        int startItem = line.firstItem;
876
        if (itemText.item(startItem)->effects() & ScStyle_DropCap)
877
                startItem++;
9047 avox 878
        // distribute whitespace on spaces and glyphs
16867 jghali 879
        for (int yof = startItem; yof <= line.lastItem; ++yof)
8095 avox 880
        {
9047 avox 881
                double wide = itemText.item(yof)->glyph.wide();
882
                if (!SpecialChars::isExpandingSpace(itemText.text(yof)))
8095 avox 883
                {
9047 avox 884
                        itemText.item(yof)->glyph.last()->xadvance += wide * glyphExtension;
885
                        GlyphLayout* glyph = &(itemText.item(yof)->glyph);
886
                        while (glyph)
887
                        {
888
                                glyph->xoffset *= glyphScale;
889
                                glyph->scaleH *= glyphScale;
890
                                glyph = glyph->more;
891
                        }
8095 avox 892
                }
9047 avox 893
                else if ((itemText.item(yof)->effects() & ScStyle_SuppressSpace) == 0)
894
                {
895
                        itemText.item(yof)->glyph.last()->xadvance += wide * spaceExtension;
896
                }
8095 avox 897
        }
898
}
899
 
900
 
9047 avox 901
/// called when linelength is known and line is not justified
902
static void indentLine(StoryText& itemText, LineSpec& line, double leftIndent)
8095 avox 903
{
9047 avox 904
        if (line.naturalWidth > line.width)
905
        {
906
                justifyLine(itemText, line);
907
        }
908
        if (leftIndent > 0)
909
        {
910
                line.x += leftIndent;
911
                line.width -= leftIndent;
912
        }
8095 avox 913
}
914
 
16912 jghali 915
//defined but not used
16867 jghali 916
///// calculate how much the first char should stick out to the left
917
//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line)
918
//{
919
//      int b = line.firstItem;
920
//      while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace))
921
//                 ++b;
8095 avox 922
 
16867 jghali 923
//      double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
924
//      QChar chr = itemText.text(b);
925
//      double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
926
//      if (QString("'´`").indexOf(chr) >= 0
927
//              || chr == QChar(0x2018) // quote 6
928
//              || chr == QChar(0x2019) // quote 9
929
//              || chr == QChar(0x201a) // lower quote 9
930
//              || chr == QChar(0x201b) // upper reversed 9 6
931
//              || chr == QChar(0x2039) // single guillemet <
932
//              || chr == QChar(0x203a) // single guillemet >
933
//              )
934
//              leftCorr *= -0.7;
935
//      else if (QString("\"").indexOf(chr) >= 0
936
//                       || chr == QChar(0x00ab) // guillemet <<
937
//                       || chr == QChar(0x00bb) // guillemet >>
938
//                       || chr == QChar(0x201c) // quote 66
939
//                       || chr == QChar(0x201d) // quote 99
940
//                       || chr == QChar(0x201e) // lower quote 99
941
//                       || chr == QChar(0x201f) // upper reversed 99
942
//                       ) 
943
//              leftCorr *= -0.5;
944
//      else {
945
//              leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
946
//              leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
947
//      }
948
//      return leftCorr;
949
//}
8095 avox 950
 
8761 avox 951
/// calculate how much the last char should stick out to the right
8095 avox 952
static double opticalRightMargin(const StoryText& itemText, const LineSpec& line)
953
{
954
        int b = line.lastItem;
955
        while (b > line.firstItem &&
8177 avox 956
                   (SpecialChars::isBreakingSpace(itemText.text(b)) || SpecialChars::isBreak(itemText.text(b)))
8095 avox 957
                   )
958
                --b;
959
        if (b >= line.firstItem)
960
        {
961
                double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
962
                QChar chr = (itemText.item(b)->effects() & ScStyle_SmartHyphenVisible) ?
963
                        QChar('-') : itemText.text(b);
964
                double rightCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
10517 cbradney 965
                if (QString("-,.`´'~").indexOf(chr) >= 0
8095 avox 966
                        || chr == QChar(0x2018)
967
                        || chr == QChar(0x2019)
968
                        || chr == QChar(0x201a)
969
                        || chr == QChar(0x201b)
970
                        || chr == QChar(0x2039)
971
                        || chr == QChar(0x203a)
8761 avox 972
                        || chr == QChar(0x2032) // PRIME
8095 avox 973
                        )
974
                        rightCorr *= 0.7;
10517 cbradney 975
                else if (QString(";:\"").indexOf(chr) >= 0
8095 avox 976
                                 || chr == QChar(0x00ab)
977
                                 || chr == QChar(0x00bb)
978
                                 || chr == QChar(0x201c)
979
                                 || chr == QChar(0x201d)
980
                                 || chr == QChar(0x201e)
981
                                 || chr == QChar(0x201f)
8761 avox 982
                                 || chr == QChar(0x2013) // EN DASH
983
                                 || chr == QChar(0x2033) // double prime
8095 avox 984
                                 )
985
                        rightCorr *= 0.5;
986
                else {
987
                        rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0);
988
                        rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.'));
989
                }
990
                return rightCorr;
991
        }
992
        return 0.0;
993
}
994
 
16988 jghali 995
static double findRealOverflowEnd(const QRegion& shape, QRect pt, double maxX)
16867 jghali 996
{
17043 jghali 997
        while (!regionContainsRect(shape, pt) && pt.right() < maxX)
16867 jghali 998
                pt.translate(1, 0);
999
        if (pt.right() >= maxX)
1000
                return maxX;
16988 jghali 1001
        return pt.left() + 0.5;
16867 jghali 1002
}
8095 avox 1003
 
5362 avox 1004
void PageItem_TextFrame::layout()
3614 cbradney 1005
{
13045 jghali 1006
//      qDebug()<<"==Layout==" << itemName() ;
13034 pierre 1007
//      printBacktrace(24);
16638 jghali 1008
        if (BackBox != NULL && BackBox->invalid) {
5732 avox 1009
//              qDebug("textframe: len=%d, going back", itemText.length());
16638 jghali 1010
                // Why that invalid = false here? Calling prevInChain->layout() does
1011
                // not ensure that this box will be layouted
1012
                // invalid = false;
8060 avox 1013
                PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox);
16542 jghali 1014
                while (prevInChain && prevInChain->invalid)
1015
                {
1016
                        if (!prevInChain->BackBox || !prevInChain->BackBox->invalid)
1017
                                break;
1018
                        prevInChain = dynamic_cast<PageItem_TextFrame*>(prevInChain->BackBox);
1019
                }
1020
                if (prevInChain && prevInChain->invalid)
1021
                        prevInChain->layout();
16107 jghali 1022
                // #9592 : warning, BackBox->layout() may not layout BackBox next box
1023
                if (!invalid)
1024
                        return;
5362 avox 1025
        }
6370 avox 1026
        else if (!invalid && OnMasterPage.isEmpty()) {
13085 jghali 1027
//              qDebug() << QString("textframe: len=%1, invalid=%2 OnMasterPage=%3: no relayout").arg(itemText.length()).arg(invalid).arg(OnMasterPage);
5732 avox 1028
                return;
1029
        }
16638 jghali 1030
        if (invalid && BackBox == NULL)
8334 avox 1031
                firstChar = 0;
1032
 
13085 jghali 1033
//      qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame());
5362 avox 1034
        QPoint pt1, pt2;
16867 jghali 1035
        QRect pt;
7969 avox 1036
        double chs, chsd = 0;
8095 avox 1037
        double oldCurY, EndX, OFs, wide, kernVal;
7313 avox 1038
        QString chstr;
5362 avox 1039
        ScText *hl;
17741 jghali 1040
        PageItem_TextFrame* nextFrame;
6805 avox 1041
        ParagraphStyle style;
17741 jghali 1042
        int opticalMargins = ParagraphStyle::OM_None;
5362 avox 1043
 
1044
        bool outs = false;
1045
        bool goNoRoom = false;
1046
        bool goNextColumn = false;
7905 avox 1047
 
1048
        TabControl tabs;
1049
        tabs.active    = false;     // RTab
1050
        tabs.status    = TabNONE;   // TabCode
1051
        tabs.charIndex = -1;        // StartRT
1052
        tabs.xPos      = 0;         // RTabX
1053
 
9803 fschmid 1054
        QList<ParagraphStyle::TabRecord> tTabValues;
7905 avox 1055
        tTabValues.clear();
1056
 
5362 avox 1057
        bool DropCmode = false;
16912 jghali 1058
        double desc=0, asce=0, realAsce=0, realDesc = 0;
16867 jghali 1059
        double maxDY=0, maxDX=0;
6370 avox 1060
        double DropCapDrop = 0;
11776 jghali 1061
        int    DropLines = 0;
1062
        int    DropLinesCount = 0;
5362 avox 1063
 
6144 avox 1064
        itemText.clearLines();
8095 avox 1065
 
1066
        double lineCorr = 0;
1067
        if (lineColor() != CommonStrings::None)
1068
                lineCorr = m_lineWidth / 2.0;
1069
 
1070
        // TODO: refactor this into PageItem
1071
        MarginStruct extra;
1072
        extra.Top = TExtra;
1073
        extra.Left = Extra;
1074
        extra.Right = RExtra;
1075
        extra.Bottom = BExtra;
1076
 
1077
        LineControl current;
1078
        current.init(Width, Height, extra, lineCorr);
1079
        current.initColumns(columnWidth(), ColGap);
1080
        current.hyphenCount = 0;
16867 jghali 1081
 
1082
        //hold Y position of last computed line of text (with glyphs descent)
1083
        //for moving next line if glyphs are higher than that
1084
        double lastLineY = 0;
1085
 
5778 avox 1086
        // dump styles
1087
/*     
1088
        for (int i=0; i < itemText.nrOfParagraphs(); ++i) {
1089
                const ParagraphStyle& pstyle(itemText.paragraphStyle(itemText.endOfParagraph(i)));
13085 jghali 1090
                qDebug("par %d:", i);
5778 avox 1091
                dumpIt(pstyle);
1092
        }
13085 jghali 1093
        qDebug() << "default:";
5778 avox 1094
        dumpIt(itemText.defaultStyle());
16988 jghali 1095
*/
5778 avox 1096
 
6144 avox 1097
        setShadow();
5732 avox 1098
        if ((itemText.length() != 0)) // || (NextBox != 0))
8095 avox 1099
        {
5408 avox 1100
                // determine layout area
16988 jghali 1101
                QRegion cl = availableRegion();
14383 jghali 1102
                if (cl.isEmpty())
1103
                {
1104
                        MaxChars = firstInFrame();
1105
                        goto NoRoom;
1106
                }
5362 avox 1107
 
16988 jghali 1108
                if (imageFlippedH() || imageFlippedV())
5362 avox 1109
                {
16988 jghali 1110
                        QMatrix matrix;
1111
                        if (imageFlippedH())
1112
                        {
1113
                                matrix.translate(Width, 0);
1114
                                matrix.scale(-1, 1);
1115
                        }
1116
                        if (imageFlippedV())
1117
                        {
1118
                                matrix.translate(0, Height);
1119
                                matrix.scale(1, -1);
1120
                        }
1121
                        cl = matrix.map(cl);
5362 avox 1122
                }
5408 avox 1123
 
16867 jghali 1124
                current.nextColumn();
1125
                lastLineY = extra.Top;
8095 avox 1126
 
5559 avox 1127
                // find start of first line
7887 avox 1128
                if (firstInFrame() < itemText.length())
5362 avox 1129
                {
7887 avox 1130
                        hl = itemText.item(firstInFrame());
1131
                        style = itemText.paragraphStyle(firstInFrame());
8956 avox 1132
                        if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
1133
                        {
1134
                                style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0));
13085 jghali 1135
//                              qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing());
8956 avox 1136
                        }
11768 jghali 1137
                        else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1138
                                style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid);
8956 avox 1139
 
13085 jghali 1140
//                      qDebug() << QString("style @0: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin())
1141
//                                 .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()?style.parent()->name():"");
6805 avox 1142
                        if (style.hasDropCap())
3614 cbradney 1143
                        {
8062 avox 1144
                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
6805 avox 1145
                                        chs = qRound(m_Doc->typographicSettings.valueBaseGrid  * style.dropCapLines() * 10);
5362 avox 1146
                                else
6805 avox 1147
                                        chs = qRound(style.lineSpacing() * style.dropCapLines() * 10);
3614 cbradney 1148
                        }
6370 avox 1149
                        else
5691 avox 1150
                                chs = hl->fontSize();
16867 jghali 1151
                        desc = -hl->font().descent(chs / 10.0);
8095 avox 1152
                        current.yPos = extra.Top + lineCorr;
13085 jghali 1153
//                      qDebug() << QString("first line at y=%1").arg(current.yPos);
5362 avox 1154
                }
6370 avox 1155
                else // empty itemText:
5362 avox 1156
                {
16867 jghali 1157
                        desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0);
16912 jghali 1158
                        current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top + lineCorr - desc;
5362 avox 1159
                }
8095 avox 1160
                current.startLine(firstInFrame());
16867 jghali 1161
 
5362 avox 1162
                outs = false;
1163
                OFs = 0;
1164
                MaxChars = 0;
16867 jghali 1165
                double realEnd = 0;
1166
                current.restartIndex = current.restartRowIndex = firstInFrame();
1167
                current.afterOverflow = false;
1168
                current.addLine = false;
1169
                current.recalculateY = true;
1170
                current.lastInRowLine = false;
1171
                current.addLeftIndent = true;
1172
                current.wasFirstInRow = false;
1173
                current.leftIndent = 0;
1174
                current.rightMargin = 0.0;
1175
                current.mustLineEnd = current.colRight;
1176
                current.restartX = 0;
17253 fschmid 1177
                int lastStat = 0, curStat = 0;
16867 jghali 1178
 
5721 avox 1179
                for (int a = firstInFrame(); a < itemText.length(); ++a)
5362 avox 1180
                {
5721 avox 1181
                        hl = itemText.item(a);
17253 fschmid 1182
                        curStat = SpecialChars::getCJKAttr(hl->ch);
8060 avox 1183
                        if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP)
1184
                                style = itemText.paragraphStyle(a);
8095 avox 1185
                        if (current.itemsInLine == 0)
8060 avox 1186
                                opticalMargins = style.opticalMargins();
1187
 
12782 jghali 1188
                        const CharStyle& charStyle =  (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle());
16867 jghali 1189
                        chstr = ExpandToken(a);
16912 jghali 1190
                        double hlcsize10 = charStyle.fontSize() / 10.0;
16867 jghali 1191
                        double scaleV = charStyle.scaleV() / 1000.0;
1192
                        double scaleH = charStyle.scaleH() / 1000.0;
1193
                        double offset = hlcsize10 * (charStyle.baselineOffset() / 1000.0);
5721 avox 1194
 
6144 avox 1195
                        if (chstr.isEmpty())
8861 cbradney 1196
                                chstr = SpecialChars::ZWNBSPACE;
8956 avox 1197
                        if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
16867 jghali 1198
                                style.setLineSpacing(charStyle.font().height(hlcsize10));
11768 jghali 1199
                        else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1200
                                style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid);
5408 avox 1201
                        // find out about par gap and dropcap
5721 avox 1202
                        if (a == firstInFrame())
3614 cbradney 1203
                        {
8814 cbradney 1204
                                if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP)
5362 avox 1205
                                {
7313 avox 1206
                                        if (chstr[0] != SpecialChars::PARSEP)
5362 avox 1207
                                        {
5721 avox 1208
                                                DropCmode = style.hasDropCap();
5362 avox 1209
                                                if (DropCmode)
5721 avox 1210
                                                        DropLines = style.dropCapLines();
5362 avox 1211
                                        }
1212
                                        else
1213
                                                DropCmode = false;
1214
                                }
3614 cbradney 1215
                        }
8814 cbradney 1216
 
6370 avox 1217
                        {  // local block for 'fl'
5691 avox 1218
                                StyleFlag fl = hl->effects();
1219
                                fl &= ~ScStyle_DropCap;
1220
                                fl &= ~ScStyle_SmartHyphenVisible;
1221
                                hl->setEffects(fl);
1222
                        }
8814 cbradney 1223
 
8150 avox 1224
                        // No space at begin of line, 
1225
                        if (legacy)
3614 cbradney 1226
                        {
8150 avox 1227
                                // unless at begin of par (eeks)
9737 jghali 1228
                                if ( (current.itemsInLine == 0) && (SpecialChars::isBreakingSpace(hl->ch))
8177 avox 1229
                                         && (a > 0 && ! SpecialChars::isBreak(itemText.text(a-1)))
1230
                                         && ! (a > 0 && SpecialChars::isBreakingSpace(itemText.text(a-1))
8150 avox 1231
                                                   && (itemText.charStyle(a-1).effects() & ScStyle_SuppressSpace) != ScStyle_SuppressSpace))
1232
                                {
1233
                                        hl->setEffects(hl->effects() | ScStyle_SuppressSpace);
1234
                                        hl->glyph.xadvance = 0;
1235
                                        continue;
1236
                                }
1237
                                else
1238
                                        hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace);
5362 avox 1239
                        }
8150 avox 1240
                        else // from 134 on use NBSPACE for this effect
1241
                        {
12477 jghali 1242
                                if ( current.itemsInLine == 0 && (SpecialChars::isBreakingSpace(hl->ch) || hl->ch.isSpace()))
8150 avox 1243
                                {
1244
                                        hl->setEffects(hl->effects() | ScStyle_SuppressSpace);
1245
                                        hl->glyph.xadvance = 0;
1246
                                        continue;
1247
                                }
1248
                                else
1249
                                        hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace);
1250
                        }
8095 avox 1251
                        if (current.itemsInLine == 0)
5362 avox 1252
                        {
16867 jghali 1253
                                if (style.rightMargin() == 0)
3614 cbradney 1254
                                {
16867 jghali 1255
                                        //addLine = true;
1256
                                        current.rightMargin = 0.0;
1257
                                }
1258
                                else
1259
                                {
1260
                                        if (current.lastInRowLine)
1261
                                                current.rightMargin = style.rightMargin();
1262
                                        else
1263
                                                current.rightMargin = 0.0;
1264
                                }
1265
                                current.breakIndex = -1;
1266
                                if (current.startOfCol && !current.afterOverflow && current.recalculateY)
17084 jghali 1267
                                        current.yPos = qMax(current.yPos, extra.Top);
16867 jghali 1268
                                // more about par gap and dropcaps
1269
                                if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol))
1270
                                {
1271
                                        if (!current.afterOverflow && current.recalculateY && !current.startOfCol)
1272
                                                current.yPos += style.gapBefore();
6370 avox 1273
                                        DropCapDrop = 0;
7313 avox 1274
                                        if (chstr[0] != SpecialChars::PARSEP)
5721 avox 1275
                                                DropCmode = style.hasDropCap();
5362 avox 1276
                                        else
1277
                                                DropCmode = false;
16867 jghali 1278
                                        if (DropCmode && !current.afterOverflow)
5362 avox 1279
                                        {
5721 avox 1280
                                                DropLines = style.dropCapLines();
8062 avox 1281
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
17139 jghali 1282
                                                        DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines - 1);
1283
                                                else if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
1284
                                                        DropCapDrop = style.lineSpacing() * (DropLines - 1);
5362 avox 1285
                                                else
17139 jghali 1286
                                                        DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines - 1);
5362 avox 1287
                                        }
3614 cbradney 1288
                                }
5362 avox 1289
                        }
16867 jghali 1290
                        // find charsize factors
5362 avox 1291
                        if (DropCmode)
1292
                        {
17139 jghali 1293
                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1294
                                        DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines - 1);
1295
                                else if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
1296
                                        DropCapDrop = style.lineSpacing() * (DropLines - 1);
1297
                                else
1298
                                        DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines - 1);
1299
 
11767 jghali 1300
                                // FIXME : we should ensure that fonts are loaded before calls to layout()
1301
                                // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap()
1302
                                // ScFace::ascent() can be called safely afterwards
1303
                                double realCharHeight = charStyle.font().realCharHeight(chstr[0], 1);
1304
                                double realCharAscent = charStyle.font().realCharAscent(chstr[0], 1);
16867 jghali 1305
                                double fontAscent     = charStyle.font().ascent(hlcsize10);
14928 jghali 1306
                                if (realCharHeight == 0.0)
16867 jghali 1307
                                        realCharHeight = charStyle.font().height(hlcsize10);
14928 jghali 1308
                                if (realCharAscent == 0.0)
1309
                                        realCharAscent = fontAscent;
8062 avox 1310
                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
6370 avox 1311
                                {
11767 jghali 1312
                                        chsd = (10 * ((m_Doc->typographicSettings.valueBaseGrid * (DropLines-1) + fontAscent) / realCharHeight));
1313
                                        chs  = (10 * ((m_Doc->typographicSettings.valueBaseGrid * (DropLines-1) + fontAscent) / realCharAscent));
3614 cbradney 1314
                                }
17139 jghali 1315
                                else if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
1316
                                {
1317
                                        chsd = (10 * ((style.lineSpacing() * (DropLines-1) + fontAscent) / realCharHeight));
1318
                                        chs  = (10 * ((style.lineSpacing() * (DropLines-1) + fontAscent) / realCharAscent));
1319
                                }
5362 avox 1320
                                else
3614 cbradney 1321
                                {
17139 jghali 1322
                                        double currasce = charStyle.font().height(hlcsize10);
1323
                                        chsd = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharHeight));
1324
                                        chs  = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharAscent));
5362 avox 1325
                                }
5691 avox 1326
                                hl->setEffects(hl->effects() | ScStyle_DropCap);
6370 avox 1327
                                hl->glyph.yoffset -= DropCapDrop;
5362 avox 1328
                        }
5408 avox 1329
                        else // ! dropCapMode
5362 avox 1330
                        {
9737 jghali 1331
                                if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
8177 avox 1332
                                        chs = qRound((hl->embedded.getItem()->gHeight + hl->embedded.getItem()->lineWidth()) * 10);
5362 avox 1333
                                else
6144 avox 1334
                                        chs = charStyle.fontSize();
5362 avox 1335
                        }
16867 jghali 1336
                        // set StartOfLine (and find tracking?)
8098 avox 1337
                        if (current.itemsInLine == 0)
1338
                        {
1339
                                itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine);
1340
                                kernVal = 0;
1341
                        }
1342
                        else
1343
                        {
1344
                                kernVal = 0; // chs * charStyle.tracking() / 10000.0;
1345
                                itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine);
1346
                        }
6144 avox 1347
                        hl->glyph.yadvance = 0;
5980 avox 1348
                        oldCurY = layoutGlyphs(*hl, chstr, hl->glyph);
16867 jghali 1349
                        // find out width, ascent and descent of char
9737 jghali 1350
                        if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
14418 jghali 1351
                        {
8177 avox 1352
                                wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth();
14425 jghali 1353
                                hl->glyph.xadvance = wide * hl->glyph.scaleH;
14418 jghali 1354
                        }
5362 avox 1355
                        else
1356
                        {
6354 avox 1357
                                wide = hl->glyph.wide();
8814 cbradney 1358
                                // apply kerning
6354 avox 1359
                                if (a+1 < itemText.length())
1360
                                {
1361
                                        uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1));
7356 avox 1362
                                        double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH;
1363
                                        wide += kern;
1364
                                        hl->glyph.xadvance += kern;
17253 fschmid 1365
                // change xadvance, xoffset according to JIS X4051
1366
                                        ScText *hl2 = itemText.item(a+1);
1367
                                        int nextStat = SpecialChars::getCJKAttr(hl2->ch);
1368
                                        int prevStat;
1369
                                        if(curStat != 0){       // current char is CJK
1370
                                                if(nextStat == 0 && !SpecialChars::isBreakingSpace(hl2->ch)){
1371
                                                        switch(curStat & SpecialChars::CJK_CHAR_MASK){
1372
                                                        case SpecialChars::CJK_KANJI:
1373
                                                        case SpecialChars::CJK_KANA:
1374
                                                        case SpecialChars::CJK_NOTOP:
19989 jghali 1375
                                                                kern = charStyle.fontSize() / 10 / 4;
17253 fschmid 1376
                                                                wide += kern;
1377
                                                                hl->glyph.xadvance += kern;
1378
                                                        }
1379
                                                } else {        // next char is CJK, too
1380
                                                        switch(curStat & SpecialChars::CJK_CHAR_MASK){
1381
                                                        case SpecialChars::CJK_FENCE_END:
1382
                                                                switch(nextStat & SpecialChars::CJK_CHAR_MASK){
1383
                                                                case SpecialChars::CJK_FENCE_BEGIN:
1384
                                                                case SpecialChars::CJK_FENCE_END:
1385
                                                                case SpecialChars::CJK_COMMA:
1386
                                                                case SpecialChars::CJK_PERIOD:
1387
                                                                case SpecialChars::CJK_MIDPOINT:
19989 jghali 1388
                                                                        kern = -charStyle.fontSize() / 10 / 2;
17253 fschmid 1389
                                                                        wide += kern;
1390
                                                                        hl->glyph.xadvance += kern;
1391
                                                                }
1392
                                                                break;
1393
                                                        case SpecialChars::CJK_COMMA:
1394
                                                        case SpecialChars::CJK_PERIOD:
1395
                                                                switch(nextStat & SpecialChars::CJK_CHAR_MASK){
1396
                                                                case SpecialChars::CJK_FENCE_BEGIN:
1397
                                                                case SpecialChars::CJK_FENCE_END:
19989 jghali 1398
                                                                        kern = -charStyle.fontSize() / 10 / 2;
17253 fschmid 1399
                                                                        wide += kern;
1400
                                                                        hl->glyph.xadvance += kern;
1401
                                                                }
1402
                                                                break;
1403
                                                        case SpecialChars::CJK_MIDPOINT:
1404
                                                                switch(nextStat & SpecialChars::CJK_CHAR_MASK){
1405
                                                                case SpecialChars::CJK_FENCE_BEGIN:
19989 jghali 1406
                                                                        kern = -charStyle.fontSize() / 10 / 2;
17253 fschmid 1407
                                                                        wide += kern;
1408
                                                                        hl->glyph.xadvance += kern;
1409
                                                                }
1410
                                                                break;
1411
                                                        case SpecialChars::CJK_FENCE_BEGIN:
1412
                                                                if(a == current.line.firstItem){ // first char of the line
1413
                                                                        prevStat = SpecialChars::CJK_FENCE_BEGIN;
1414
                                                                } else {
1415
                                                                        hl2 = itemText.item(a-1);
1416
                                                                        prevStat = SpecialChars::getCJKAttr(hl2->ch) & SpecialChars::CJK_CHAR_MASK;
1417
                                                                }
1418
                                                                if(prevStat == SpecialChars::CJK_FENCE_BEGIN){
19989 jghali 1419
                                                                        kern = -charStyle.fontSize() / 10 / 2;
17253 fschmid 1420
                                                                        wide += kern;
1421
                                                                        hl->glyph.xadvance += kern;
1422
                                                                        hl->glyph.xoffset += kern;
1423
                                                                }
1424
                                                                break;
1425
                                                        }
1426
 
1427
                                                }
1428
                                        } else {        // current char is not CJK
1429
                                                if(nextStat != 0 && !SpecialChars::isBreakingSpace(hl->ch)){
1430
                                                        switch(nextStat & SpecialChars::CJK_CHAR_MASK){
1431
                                                        case SpecialChars::CJK_KANJI:
1432
                                                        case SpecialChars::CJK_KANA:
1433
                                                        case SpecialChars::CJK_NOTOP:
19989 jghali 1434
                                                                kern = charStyle.fontSize() / 10 / 4;
17253 fschmid 1435
                                                                wide += kern;
1436
                                                                hl->glyph.xadvance += kern;
1437
                                                        }
1438
                                                }
1439
                                        }
6354 avox 1440
                                }
5362 avox 1441
                        }
1442
                        if (DropCmode)
1443
                        {
5408 avox 1444
                                // drop caps are wider...
9737 jghali 1445
                                if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
5362 avox 1446
                                {
14928 jghali 1447
                                        double itemHeight = hl->embedded.getItem()->gHeight + hl->embedded.getItem()->lineWidth();
1448
                                        if (itemHeight == 0)
1449
                                                itemHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0);
8177 avox 1450
                                        wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth();
8062 avox 1451
                                        if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
16867 jghali 1452
                                                realAsce = m_Doc->typographicSettings.valueBaseGrid * DropLines;
5362 avox 1453
                                        else
3614 cbradney 1454
                                        {
5721 avox 1455
                                                if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
16867 jghali 1456
                                                        realAsce = style.lineSpacing() * DropLines;
5362 avox 1457
                                                else
16867 jghali 1458
                                                        realAsce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines;
3614 cbradney 1459
                                        }
6144 avox 1460
                                        hl->glyph.scaleH /= hl->glyph.scaleV;
16867 jghali 1461
                                        hl->glyph.scaleV = (realAsce / itemHeight);
6144 avox 1462
                                        hl->glyph.scaleH *= hl->glyph.scaleV;
5362 avox 1463
                                }
1464
                                else
1465
                                {
16867 jghali 1466
                                        double realCharHeight = charStyle.font().realCharHeight(chstr[0], hlcsize10);
14928 jghali 1467
                                        if (realCharHeight == 0)
1468
                                                realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0);
16867 jghali 1469
                                        wide = (charStyle.font().realCharWidth(chstr[0], chsd / 10.0) * scaleH) + (1 - scaleH); //dropcaps are to close to next glyphs if glyphs are hard scaled
1470
                                        realAsce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0) * scaleV + offset;
1471
                                        asce = charStyle.font().ascent(hlcsize10);
1472
                                        // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]);
6144 avox 1473
                                        hl->glyph.scaleH /= hl->glyph.scaleV;
16867 jghali 1474
                                        hl->glyph.scaleV = (realAsce / realCharHeight);
6144 avox 1475
                                        hl->glyph.scaleH *= hl->glyph.scaleV;
16867 jghali 1476
                                        hl->glyph.xoffset -= 0.5; //drop caps are always to far from column left edge
5362 avox 1477
                                }
6370 avox 1478
                                hl->glyph.xadvance = wide;
16867 jghali 1479
                                desc = realDesc =0;
5362 avox 1480
                        }
8814 cbradney 1481
                        else // !DropCMode
5362 avox 1482
                        {
9737 jghali 1483
                                if (SpecialChars::isExpandingSpace(hl->ch))
8900 cbradney 1484
                                {
8931 cbradney 1485
                                        double wordtracking = charStyle.wordTracking();
8900 cbradney 1486
                                        hl->glyph.xadvance *= wordtracking;
1487
                                        wide *= wordtracking;
1488
                                }
5408 avox 1489
                                // find ascent / descent
9737 jghali 1490
                                if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem()))
16867 jghali 1491
                                        desc = realDesc = 0;
5362 avox 1492
                                else
1493
                                {
16867 jghali 1494
                                        desc = -charStyle.font().descent(hlcsize10);
1495
                                        realDesc = charStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset;
9737 jghali 1496
                                        current.rememberShrinkStretch(hl->ch, wide, style);
5362 avox 1497
                                }
6144 avox 1498
                                asce = charStyle.font().ascent(hlcsize10);
16867 jghali 1499
                                realAsce = charStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset;
5362 avox 1500
                        }
16867 jghali 1501
 
1502
                        //check for Y position at beginning of line
1503
                        if (current.itemsInLine == 0 && !current.afterOverflow)
5362 avox 1504
                        {
16867 jghali 1505
                                if (current.recalculateY)
5362 avox 1506
                                {
16867 jghali 1507
                                        //if top of column Y position depends on first line offset
1508
                                        if (current.startOfCol)
3614 cbradney 1509
                                        {
16867 jghali 1510
                                                lastLineY = qMax(lastLineY, extra.Top + lineCorr);
1511
                                                if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
3614 cbradney 1512
                                                {
16867 jghali 1513
                                                        if (firstLineOffset() == FLOPRealGlyphHeight)
1514
                                                        {
1515
                                                                if (DropCmode)
1516
                                                                        current.yPos += asce;
1517
                                                                else
1518
                                                                        current.yPos += realAsce;
1519
                                                        }
1520
                                                        else if (firstLineOffset() == FLOPLineSpacing)
1521
                                                                current.yPos += style.lineSpacing();
3614 cbradney 1522
                                                        else
16867 jghali 1523
                                                                current.yPos += asce;
3614 cbradney 1524
                                                }
16867 jghali 1525
                                                else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1526
                                                {
1527
                                                        if (current.yPos <= lastLineY)
1528
                                                                current.yPos = lastLineY +1;
16985 jghali 1529
                                                        double by = Ypos;
16867 jghali 1530
                                                        if (OwnPage != -1)
1531
                                                                by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset();
1532
                                                        int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0);
1533
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid);
1534
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by;
1535
                                                }
3614 cbradney 1536
                                        }
16867 jghali 1537
                                        else
3614 cbradney 1538
                                        {
16867 jghali 1539
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
1540
                                                {
1541
                                                        current.yPos += m_Doc->typographicSettings.valueBaseGrid;
16985 jghali 1542
                                                        double by = Ypos;
16867 jghali 1543
                                                        if (OwnPage != -1)
1544
                                                                by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset();
1545
                                                        int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0);
1546
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid);
1547
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by;
1548
                                                }
1549
                                                else
1550
                                                        current.yPos += style.lineSpacing();
3614 cbradney 1551
                                        }
16867 jghali 1552
                                        if (DropCmode)
1553
                                                current.yPos += DropCapDrop;
5362 avox 1554
                                }
16867 jghali 1555
                                //set left indentation
1556
                                current.leftIndent = 0.0;
1557
                                if (current.addLeftIndent && (maxDX == 0 || DropCmode))
5362 avox 1558
                                {
16867 jghali 1559
                                        current.leftIndent = style.leftMargin();
1560
                                        if (current.hasDropCap)
1561
                                                current.leftIndent = 0;
1562
                                        if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP)))
1563
                                                current.leftIndent += style.firstIndent();
1564
                                        current.addLeftIndent = false;
5362 avox 1565
                                }
1566
                        }
16867 jghali 1567
                        current.recalculateY = true;
1568
                        int maxYAsc = 0, maxYDesc = 0;
1569
                        if (current.startOfCol)
5362 avox 1570
                        {
16867 jghali 1571
                                //qMax is used for glyphs shifted or vertically scalled above ascent or below descent
1572
                                double addAsce = qMax(realAsce, asce);
1573
                                if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
5362 avox 1574
                                {
16867 jghali 1575
                                        if (firstLineOffset() == FLOPRealGlyphHeight)
1576
                                                addAsce = realAsce;
1577
                                        else if (firstLineOffset() == FLOPLineSpacing)
1578
                                                addAsce = style.lineSpacing();
5362 avox 1579
                                }
16867 jghali 1580
                                maxYAsc = static_cast<int>(floor(current.yPos - addAsce));
1581
                        }
1582
                        else
1583
                                maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce)));
16912 jghali 1584
                        //fix for glyphs with negative realAsce value
1585
                        maxYAsc = qMax(maxYAsc, 0);
16867 jghali 1586
                        maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc)));
1587
 
1588
                        if (current.itemsInLine == 0 && !current.afterOverflow)
1589
                        {
1590
                                //start a new line
1591
                                goNoRoom = false;
1592
 
1593
                                // find line`s start
1594
                                pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc);
1595
                                pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc);
1596
                                pt = QRect(pt1, pt2);
1597
                                realEnd = 0;
1598
                                //check if there is overflow at start of line, if so jump behind it and check again
1599
                                double Xpos, Xend;
1600
                                bool done = false;
1601
                                bool newColumn = false;
17372 jghali 1602
 
1603
                                //FIX ME - that should be paragraph style`s properties
1604
                                //if set then indent is add to possible line start point (after overflow)
1605
                                //if not then indent is calculated from column left edge
1606
                                //if you dont agree that adding indent to overflow should be default behaviour 
1607
                                //then change it to false
1608
                                bool addIndent2overflow = false; // should be addIndent2Overflow = style.addIndent2Overlow();
1609
                                bool addFirstIndent2overflow = true; // should be addFirstIndent2Overflow = style.addFirstIndent2Overlow();
1610
                                //if first line indent is negative and left indent should not be added to overflow
1611
                                //then dont add first line ident either
1612
                                if ((style.firstIndent() < 0) && !addIndent2overflow)
1613
                                        addFirstIndent2overflow = false;
1614
 
16867 jghali 1615
                                while (!done)
5362 avox 1616
                                {
17372 jghali 1617
                                        Xpos = current.xPos + (addIndent2overflow ? 0 : current.leftIndent);
16867 jghali 1618
                                        Xend = current.xPos + current.leftIndent;
1619
                                        //check if in indent any overflow occurs
1620
                                        while (Xpos <= Xend && Xpos < current.colRight)
3614 cbradney 1621
                                        {
17372 jghali 1622
                                                pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc));
17043 jghali 1623
                                                if (!regionContainsRect(cl, pt))
16867 jghali 1624
                                                {
16988 jghali 1625
                                                        Xpos = current.xPos = realEnd = findRealOverflowEnd(cl, pt, current.colRight);
17372 jghali 1626
                                                        Xend = current.xPos + (addIndent2overflow ? current.leftIndent : 0);
1627
                                                        //for first paragraph`s line - move it back if first line offset should not be add
1628
                                                        if ( addFirstIndent2overflow && (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))))
1629
                                                                Xend += style.firstIndent();
16867 jghali 1630
                                                }
1631
                                                else
1632
                                                        Xpos++;
1633
                                        }
1634
                                        current.xPos = Xend;
1635
                                        done = true;
17372 jghali 1636
                                        if (current.isEndOfLine((style.minGlyphExtension() * wide) + current.rightMargin))
16867 jghali 1637
                                        {
5408 avox 1638
                                                // new line
16867 jghali 1639
                                                current.xPos = qMax(current.colLeft, maxDX);
8062 avox 1640
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
3614 cbradney 1641
                                                {
17084 jghali 1642
                                                        current.yPos++;
5362 avox 1643
                                                        double by = Ypos;
1644
                                                        if (OwnPage != -1)
1645
                                                                by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset();
8095 avox 1646
                                                        int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0);
5362 avox 1647
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid);
8095 avox 1648
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by;
5362 avox 1649
                                                }
17084 jghali 1650
                                                else if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
1651
                                                        current.yPos += (current.startOfCol ? 1 : style.lineSpacing());
1652
                                                else
1653
                                                        current.yPos++;
16867 jghali 1654
                                                lastLineY = maxYAsc +1;
1655
                                                if (current.startOfCol)
5362 avox 1656
                                                {
16867 jghali 1657
                                                        //qMax is used for glyphs shifted or vertically scalled above ascent or below descent
1658
                                                        double addAsce = qMax(realAsce, asce);
1659
                                                        if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
3614 cbradney 1660
                                                        {
16867 jghali 1661
                                                                if (firstLineOffset() == FLOPRealGlyphHeight)
1662
                                                                        addAsce = realAsce;
1663
                                                                else if (firstLineOffset() == FLOPLineSpacing)
1664
                                                                        addAsce = style.lineSpacing();
3614 cbradney 1665
                                                        }
16867 jghali 1666
                                                        maxYAsc = static_cast<int>(floor(current.yPos - addAsce));
3614 cbradney 1667
                                                }
16867 jghali 1668
                                                else
1669
                                                        maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce)));
1670
                                                maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc)));
1671
 
1672
                                                pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc));
1673
                                                done = false;
5362 avox 1674
                                        }
16867 jghali 1675
                                        if (current.isEndOfCol(realDesc))
1676
                                        {
1677
                                                current.column++;
1678
                                                if (current.column < Cols)
1679
                                                {
1680
                                                        newColumn = true;
1681
                                                        break;
1682
                                                }
1683
                                                else
1684
                                                {
1685
                                                        MaxChars = a;
1686
                                                        goto NoRoom;
1687
                                                }
1688
                                        }
5362 avox 1689
                                }
16867 jghali 1690
                                if (newColumn)
5362 avox 1691
                                {
16867 jghali 1692
                                        current.nextColumn();
1693
                                        current.mustLineEnd = current.colRight;
1694
                                        current.restartX = current.xPos;
1695
                                        lastLineY = current.yPos;
1696
                                        current.rowDesc = 0;
1697
                                        a--;
1698
                                        current.recalculateY = true;
1699
                                        current.addLeftIndent = true;
1700
                                        continue;
5362 avox 1701
                                }
16867 jghali 1702
                                current.line.x = current.restartX = current.xPos;
1703
                                current.line.y = current.yPos;
1704
                        }
1705
 
1706
                        //check if line must start at new Y position due to current glyph height or previous line descent
1707
                        if (!SpecialChars::isBreak(hl->ch, true)
1708
                                && !SpecialChars::isBreakingSpace(hl->ch)
1709
                                && !SpecialChars::isExpandingSpace(hl->ch)
1710
                                && hl->ch != SpecialChars::TAB)
1711
                        {
1712
                                double diff = 0;
1713
                                if (current.startOfCol || DropCmode)
16981 jghali 1714
                                        diff = realAsce - (current.yPos - lastLineY);
17081 jghali 1715
                                else if (style.lineSpacingMode() != ParagraphStyle::FixedLineSpacing)
16867 jghali 1716
                                        diff = charStyle.font().realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY);
1717
                                if (diff >= 1 || (!DropCmode && diff > 0))
5362 avox 1718
                                {
16867 jghali 1719
                                        if (current.hasDropCap && DropLinesCount == 0)
1720
                                        {
1721
                                                current.hasDropCap = false;
1722
                                                current.yPos = maxDY;
1723
                                                maxDX = 0;
1724
                                        }
1725
                                        int linesDrop = 0;
17081 jghali 1726
                                        if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
16867 jghali 1727
                                        {
17084 jghali 1728
                                                linesDrop = ceil(diff / m_Doc->typographicSettings.valueBaseGrid);
17081 jghali 1729
                                                current.yPos += m_Doc->typographicSettings.valueBaseGrid * linesDrop;
16867 jghali 1730
                                        }
1731
                                        else /*if (current.startOfCol)*/
1732
                                        {
1733
                                                //FIX ME - that is ugly hack I must made, because simply expression
1734
                                                //current.yPos += diff; stop working, dont know why (compiler bug?)
1735
                                                float YPOS = (float) current.yPos + (float) diff + 0.01;
1736
                                                current.yPos = (double) YPOS;
1737
                                                if (current.hasDropCap && diff > DropCapDrop)
1738
                                                {
1739
                                                        current.hasDropCap = false;
1740
                                                }
1741
                                        }
1742
                                        if (current.hasDropCap && linesDrop > 0 && DropLinesCount > 1)
1743
                                        {
1744
                                                DropLinesCount += linesDrop;
1745
                                                if (DropLinesCount >= DropLines)
1746
                                                {
1747
                                                        current.hasDropCap = false;
1748
                                                        maxDX = 0;
1749
                                                        maxDY = 0;
1750
                                                }
1751
                                        }
1752
                                        a = current.restartRow(false);
1753
                                        continue;
3614 cbradney 1754
                                }
5362 avox 1755
                        }
5408 avox 1756
                        // right tab stuff
7905 avox 1757
                        if (tabs.active)
5362 avox 1758
                        {
9737 jghali 1759
                                if (((hl->ch == '.') && (tabs.status == TabPOINT)) || ((hl->ch == ',') && (tabs.status == TabCOMMA)) || (hl->ch == SpecialChars::TAB))
5362 avox 1760
                                {
7905 avox 1761
                                        tabs.active = false;
1762
                                        tabs.status = TabNONE;
3614 cbradney 1763
                                }
1764
                        }
5408 avox 1765
                        // tab positioning
9737 jghali 1766
                        if (hl->ch == SpecialChars::TAB)
3614 cbradney 1767
                        {
5362 avox 1768
                                wide = 1;
7905 avox 1769
                                if (tabs.active)
1770
                                        tabs.active = false;
1771
                                else // ???
3614 cbradney 1772
                                {
8095 avox 1773
                                        tabs.xPos = current.xPos;
5721 avox 1774
                                        tTabValues = style.tabValues();
5362 avox 1775
                                        if (tTabValues.isEmpty())
3614 cbradney 1776
                                        {
8095 avox 1777
                                                if ((current.xPos - current.colLeft) != 0)
3614 cbradney 1778
                                                {
8095 avox 1779
                                                        if (current.xPos == current.colLeft + ceil((current.xPos-current.colLeft) / m_Doc->toolSettings.dTabWidth) * m_Doc->toolSettings.dTabWidth)
1780
                                                                current.xPos += m_Doc->toolSettings.dTabWidth;
5362 avox 1781
                                                        else
8095 avox 1782
                                                                current.xPos = current.colLeft + ceil((current.xPos-current.colLeft) / m_Doc->toolSettings.dTabWidth) * m_Doc->toolSettings.dTabWidth;
3614 cbradney 1783
                                                }
5362 avox 1784
                                                else
8095 avox 1785
                                                        current.xPos = current.colLeft + m_Doc->toolSettings.dTabWidth;
7905 avox 1786
                                                tabs.status = TabNONE;
1787
                                                tabs.active = false;
3614 cbradney 1788
                                        }
5362 avox 1789
                                        else
1790
                                        {
8095 avox 1791
                                                double tCurX = current.xPos - current.colLeft;
5362 avox 1792
                                                double oCurX = tCurX + wide;
1793
                                                for (int yg = static_cast<int>(tTabValues.count()-1); yg > -1; yg--)
1794
                                                {
13406 jghali 1795
                                                        if (oCurX < tTabValues.at(yg).tabPosition)
5362 avox 1796
                                                        {
13406 jghali 1797
                                                                tabs.status = static_cast<int>(tTabValues.at(yg).tabType);
1798
                                                                tCurX = tTabValues.at(yg).tabPosition;
1799
                                                                tabs.fillChar = tTabValues.at(yg).tabFillChar;
5362 avox 1800
                                                        }
1801
                                                }
7905 avox 1802
                                                tabs.active = (tabs.status != TabLEFT);
5362 avox 1803
                                                if (tCurX == oCurX-wide)
8095 avox 1804
                                                        current.xPos = current.colLeft + ceil((current.xPos-current.colLeft) / m_Doc->toolSettings.dTabWidth) * m_Doc->toolSettings.dTabWidth;
5362 avox 1805
                                                else
8095 avox 1806
                                                        current.xPos = current.colLeft + tCurX;
7905 avox 1807
 
1808
                                                // remember fill char
1809
                                                if (!tabs.fillChar.isNull()) {
13945 jghali 1810
                                                        hl->glyph.growWithTabLayout();
1811
                                                        TabLayout * tglyph = dynamic_cast<TabLayout*>(hl->glyph.more);
1812
                                                        if (tglyph)
1813
                                                        {
1814
                                                                tglyph->fillChar = tabs.fillChar;
1815
                                                                tglyph->glyph    = charStyle.font().char2CMap(tabs.fillChar);
1816
                                                                tglyph->yoffset  = hl->glyph.yoffset;
1817
                                                                tglyph->scaleV   = tglyph->scaleH = chs / charStyle.fontSize();
1818
                                                                tglyph->xadvance = 0;
1819
                                                        }
7905 avox 1820
                                                }
5362 avox 1821
                                        }
12084 jghali 1822
                                        current.xPos -= (legacy ? 1.0 : 0.0);
1823
                                        hl->glyph.xadvance = current.xPos + wide + kernVal - tabs.xPos;
8095 avox 1824
//                                      wide = current.xPos - RTabX;
7905 avox 1825
                                        tabs.charIndex = a;
3614 cbradney 1826
                                }
5362 avox 1827
                        }
1828
 
5408 avox 1829
                        // remember y pos
5362 avox 1830
                        if (DropCmode)
7313 avox 1831
                                hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0);
8095 avox 1832
 
8103 avox 1833
                        // remember x pos
1834
                        double breakPos = current.xPos;
8095 avox 1835
 
7905 avox 1836
                        if (!tabs.active) // normal case
5362 avox 1837
                        {
8095 avox 1838
                                current.xPos += wide+kernVal;
5362 avox 1839
                        }
7905 avox 1840
                        else if (tabs.active && tabs.status == TabCENTER)       // center tab
5362 avox 1841
                        {
8095 avox 1842
                                current.xPos += (wide+kernVal) / 2;
8562 jghali 1843
                                current.xPos = qMax(current.xPos, current.colLeft);
5362 avox 1844
                        }
7905 avox 1845
                        else // other tabs.active                       
5362 avox 1846
                        {
8562 jghali 1847
                                current.xPos = qMax(current.xPos, current.colLeft);
16867 jghali 1848
                        }
1849
                        // remember possible break
1850
                        if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB))
5362 avox 1851
                        {
16867 jghali 1852
                                if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) )
3614 cbradney 1853
                                {
16867 jghali 1854
                                        current.rememberBreak(a, breakPos, style.rightMargin());
3614 cbradney 1855
                                }
16867 jghali 1856
                        }
17253 fschmid 1857
                        // CJK break
1858
                        if(a > current.line.firstItem){ // not the first char
1859
                                if( (lastStat == 0) && (curStat == 0)){ // both non-CJK
1860
                                        // do nothing
1861
                                } else {
1862
                                        // non-CJK char does not have CJK_NOBREAK_AFTER/CJK_NOBREAK_BEFORE
1863
                                        if((lastStat & SpecialChars::CJK_NOBREAK_AFTER) == 0 &&
1864
                                           (curStat & SpecialChars::CJK_NOBREAK_BEFORE) == 0){
1865
                                                current.rememberBreak(a-1, breakPos, style.rightMargin());
1866
                                        }
1867
                                }
1868
 
1869
                        }
1870
                        lastStat = curStat;
16867 jghali 1871
                        //check against space before PARSEP
1872
                        /*if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP))
1873
                        {
1874
                                a++;
1875
                                hl = itemText.item(a);
1876
                        }*/
1877
 
1878
                        // test if end of line reached
1879
                        double overflowWidth = 0.0;
1880
                        double hyphWidth = 0.0;
1881
                        bool inOverflow = false;
1882
                        if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN)
1883
                                hyphWidth = charStyle.font().charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0);
1884
                        if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(hl->ch, Cols > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd)
1885
                        {
1886
                                //end of row reached - right column, end of column, break char or line must end
1887
                                if (current.itemsInLine == 0 && !current.afterOverflow && !SpecialChars::isBreak(hl->ch, Cols > 1))
3614 cbradney 1888
                                {
16867 jghali 1889
                                        //no glyphs in line, so start new row
1890
                                        if (SpecialChars::isBreak(hl->ch, Cols > 1))
1891
                                                current.restartRowIndex = a +1;
1892
                                        a = current.restartRow(true);
1893
                                        inOverflow = false;
1894
                                        outs = false;
1895
                                        continue;
3614 cbradney 1896
                                }
16867 jghali 1897
                                //there we have some glyphs
17086 jghali 1898
                                if (current.breakIndex < 0)
1899
                                {
1900
                                        //force break
1901
                                        if (!SpecialChars::isBreak(hl->ch, Cols > 1))
1902
                                        {
1903
                                                //force line end at previouse glyph
1904
                                                a--;
1905
                                                current.mustLineEnd = current.line.x;
1906
                                        }
1907
                                        current.breakLine(itemText, style, firstLineOffset(),a);
1908
                                }
16867 jghali 1909
                                if (!current.addLine && !current.lastInRowLine && current.afterOverflow)
1910
                                {
1911
                                        //we reach right edge of column
1912
                                        //if we are after overflow area we have to go back and try to insert text before it
1913
                                        //if we have some text here - insert text WITHOUT right margin
1914
                                        //if there is no place for text - insert text WITH right margin and end line
1915
                                        current.lastInRowLine = false;
17086 jghali 1916
                                        if (current.line.firstItem == current.restartIndex)
16867 jghali 1917
                                                current.lastInRowLine = true;
1918
                                        if (current.hasDropCap && DropLinesCount == 0 && current.restartIndex == current.restartRowIndex)
1919
                                        {
1920
                                                current.hasDropCap = false;
1921
                                                maxDX = 0;
1922
                                                current.yPos = maxDY;
1923
                                        }
1924
                                        a = current.restartLine(false,true);