Subversion Repositories Scribus

Rev

Rev 22170 | Rev 22189 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/

/***************************************************************************
                                                  pageitem.cpp  -  description
                                                         -------------------
        begin                : Sat Apr 7 2001
        copyright            : (C) 2001 by Franz Schmid
        email                : Franz.Schmid@altmuehlnet.de
 ***************************************************************************/


/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/


#include "pageitem_textframe.h"

#include <QDebug>
#include <QList>
#include <QTransform>
#include <QPalette>
#include <QPoint>
#include <QPolygon>
#include <QRegion>
#include <cairo.h>
#include <cassert>

#include "actionmanager.h"
#include "appmodes.h"
#include "canvas.h"
#include "commonstrings.h"
#include "hyphenator.h"
#include "marks.h"
#include "notesstyles.h"
#include "numeration.h"
#include "pageitem.h"
#include "pageitem_group.h"
#include "pageitem_noteframe.h"
#include "prefsmanager.h"
#include "scconfig.h"
#include "scpage.h"
#include "scpainter.h"
#include "scpaths.h"
#include "scraction.h"
#include "scribus.h"
#include "scribusdoc.h"
#include "scribusview.h"
#include "scribusstructs.h"
#include "selection.h"
#include "text/boxes.h"
#include "text/screenpainter.h"
#include "text/textshaper.h"
#include "text/shapedtext.h"
#include "text/shapedtextfeed.h"
#include "ui/guidemanager.h"
#include "ui/marksmanager.h"
#include "undomanager.h"
#include "undostate.h"
#include "units.h"
#include "util.h"
#include "util_math.h"



using namespace std;

PageItem_TextFrame::PageItem_TextFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, QString fill, QString outline)
        : PageItem(pa, PageItem::TextFrame, x, y, w, h, w2, fill, outline)
{
        invalid = true;
        firstChar = 0;
        cursorBiasBackward = false;
        unicodeTextEditMode = false;
        unicodeInputCount = 0;
        unicodeInputString = "";
        m_origAnnotPos = QRectF(xPos(), yPos(), width(), height());
        verticalAlign = 0;
        connect(&itemText,SIGNAL(changed(int, int)), this, SLOT(slotInvalidateLayout(int, int)));
}

PageItem_TextFrame::PageItem_TextFrame(const PageItem & p) : PageItem(p)
{
        invalid = true;
        cursorBiasBackward = false;
        unicodeTextEditMode = false;
        unicodeInputCount = 0;
        unicodeInputString = "";
        m_notesFramesMap.clear();
        m_origAnnotPos = QRectF(xPos(), yPos(), width(), height());
        verticalAlign = 0;
        connect(&itemText,SIGNAL(changed(int, int)), this, SLOT(slotInvalidateLayout(int, int)));
}

static QRegion itemShape(PageItem* docItem, double xOffset, double yOffset)
{
        QRegion res;
        QTransform pp;
        if (docItem->isGroupChild())
                pp.translate(docItem->gXpos, docItem->gYpos);
        else
                pp.translate(docItem->xPos() - xOffset, docItem->yPos() - yOffset);
        pp.rotate(docItem->rotation());
        if (docItem->textFlowUsesBoundingBox())
        {
                QRectF bb = docItem->getVisualBoundingRect();
                if (docItem->isGroupChild())
                {
                        bb.translate(-docItem->xPos(), -docItem->yPos());
                        bb.translate(docItem->gXpos, docItem->gYpos);
                }
                res = QRegion(bb.toRect());
        }
        else if ((docItem->textFlowUsesImageClipping()) && (docItem->imageClip.size() != 0))
        {
                QList<uint> Segs;
                QPolygon Clip2 = FlattenPath(docItem->imageClip, Segs);
                res = QRegion(pp.map(Clip2)).intersected(QRegion(pp.map(docItem->Clip)));
        }
        else if ((docItem->textFlowUsesContourLine()) && (docItem->ContourLine.size() != 0))
        {
                QList<uint> Segs;
                QPolygon Clip2 = FlattenPath(docItem->ContourLine, Segs);
                res = QRegion(pp.map(Clip2));
        }
        else
        {
                if (docItem->isSymbol() || docItem->isGroup())
                {
                        if (docItem->imageFlippedH())
                        {
                                pp.translate(docItem->width(), 0);
                                pp.scale(-1, 1);
                        }
                        if (docItem->imageFlippedV())
                        {
                                pp.translate(0, docItem->height());
                                pp.scale(1, -1);
                        }
                }
                if ((((docItem->lineColor() != CommonStrings::None) || (!docItem->patternStrokeVal.isEmpty()) || (docItem->GrTypeStroke > 0)) && (docItem->lineWidth() > 1)) || (!docItem->NamedLStyle.isEmpty()))
                {
                        QVector<double> m_array;
                        QPainterPath ppa;
                        QPainterPath result;
                        if (docItem->itemType() == PageItem::PolyLine)
                                ppa = docItem->PoLine.toQPainterPath(false);
                        else
                                ppa = docItem->PoLine.toQPainterPath(true);
                        if (docItem->NamedLStyle.isEmpty())
                        {
                                QPainterPathStroker stroke;
                                stroke.setCapStyle(docItem->lineEnd());
                                stroke.setJoinStyle(docItem->lineJoin());
                                stroke.setDashPattern(Qt::SolidLine);
                                stroke.setWidth(docItem->lineWidth());
                                result = stroke.createStroke(ppa);
                        }
                        else
                        {
                                multiLine ml = docItem->doc()->MLineStyles[docItem->NamedLStyle];
                                int ind = ml.size()-1;
                                if ((ml[ind].Color != CommonStrings::None) && (ml[ind].Width != 0))
                                {
                                        QPainterPathStroker stroke;
                                        stroke.setCapStyle(static_cast<Qt::PenCapStyle>(ml[ind].LineEnd));
                                        stroke.setJoinStyle(static_cast<Qt::PenJoinStyle>(ml[ind].LineJoin));
                                        stroke.setDashPattern(Qt::SolidLine);
                                        stroke.setWidth(ml[ind].Width);
                                        result = stroke.createStroke(ppa);
                                }
                        }
                        res = QRegion(pp.map(docItem->Clip));
                        QList<QPolygonF> pl = result.toSubpathPolygons();
                        for (int b = 0; b < pl.count(); b++)
                        {
                                res = res.united(QRegion(pp.map(pl[b].toPolygon())));
                        }
                }
                else
                        res = QRegion(pp.map(docItem->Clip));
        }
        return  res;
}

QRegion PageItem_TextFrame::calcAvailableRegion()
{
        QRegion result(this->Clip);
        if ((!isEmbedded) || (isGroupChild()))
        {
                bool invertible(false);
                QTransform canvasToLocalMat;
                if (isGroupChild())
                        canvasToLocalMat.translate(gXpos, gYpos);
                else
                        canvasToLocalMat.translate(m_xPos, m_yPos);
                canvasToLocalMat.rotate(m_rotation);
                canvasToLocalMat = canvasToLocalMat.inverted(&invertible);

                if (!invertible) return QRegion();

                int LayerLev = m_Doc->layerLevelFromID(LayerID);
                int docItemsCount = m_Doc->Items->count();
                ScPage* Mp=0;
                ScPage* Dp=0;
                PageItem* docItem=0;
                int LayerLevItem;
                QList<PageItem*> thisList;
                if (!OnMasterPage.isEmpty())
                {
                        if ((savedOwnPage == -1) || (savedOwnPage >= signed(m_Doc->Pages->count())))
                                return result;
                        Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
                        Dp = m_Doc->Pages->at(savedOwnPage);
                        if (isGroupChild())
                                thisList = Parent->asGroupFrame()->groupItemList;
                        else
                                thisList = m_Doc->MasterItems;
                        int thisid = thisList.indexOf(this);
                        for (int a = 0; a < m_Doc->MasterItems.count(); ++a)
                        {
                                docItem = m_Doc->MasterItems.at(a);
                                // #10642 : masterpage items interact only with items placed on same masterpage
                                if (docItem->OnMasterPage != OnMasterPage)
                                        continue;
                                LayerLevItem = m_Doc->layerLevelFromID(docItem->LayerID);
                                if (((a > thisid) && (docItem->LayerID == LayerID)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerID)))
                                {
                                        if (docItem->textFlowAroundObject())
                                        {
                                                QRegion itemRgn = itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset());
                                                result = result.subtracted( canvasToLocalMat.map(itemRgn) );
                                        }
                                }
                        } // for all masterItems
                        // (JG) #6009 : disable possible interaction between master text frames and normal frames
                        // which have the text flow option set
                        /*if (!m_Doc->masterPageMode())
                        {
                                for (uint a = 0; a < docItemsCount; ++a)
                                {
                                        docItem = m_Doc->Items->at(a);
                                        Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
                                        Dp = m_Doc->Pages->at(OwnPage);
                                        if ((docItem->textFlowAroundObject()) && (docItem->OwnPage == OwnPage))
                                        {
                                                result = result.subtract(itemShape(docItem, m_Doc->view(), Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset()));
                                        }
                                } // for all docItems
                        } // if (! masterPageMode) */

                } // if (!OnMasterPage.isEmpty())
                else
                {
                        int thisid = 0;
                        if (isGroupChild())
                        {
                                thisid = Parent->asGroupFrame()->groupItemList.indexOf(this);
                                docItemsCount = Parent->asGroupFrame()->groupItemList.count();
                                for (int a = thisid + 1; a < docItemsCount; ++a)
                                {
                                        docItem = Parent->asGroupFrame()->groupItemList.at(a);
                                        if (docItem->textFlowAroundObject())
                                        {
                                                QRegion itemRgn = itemShape(docItem, 0, 0);
                                                result = result.subtracted( canvasToLocalMat.map(itemRgn) );
                                        }
                                }
                        }
                        else
                        {
                                thisid = m_Doc->Items->indexOf(this);
                                for (int a = 0; a < docItemsCount; ++a)
                                {
                                        docItem = m_Doc->Items->at(a);
                                        LayerLevItem = m_Doc->layerLevelFromID(docItem->LayerID);
                                        if (((a > thisid) && (docItem->LayerID == LayerID)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerID)))
                                        {
                                                if (docItem->textFlowAroundObject())
                                                {
                                                        QRegion itemRgn = itemShape(docItem, 0, 0);
                                                        result = result.subtracted( canvasToLocalMat.map(itemRgn) );
                                                }
                                        }
                                }
                        } // for all docItems
                } // if(OnMasterPage.isEmpty()
        } // if(!Embedded)
        //else
        //      qDebug() << "QRegion empty";
        return result;
}

void PageItem_TextFrame::setShadow()
{
        if (OnMasterPage.isEmpty())
                return;

        QString newShadow = m_Doc->masterPageMode() ? OnMasterPage : QString::number(OwnPage);
        if (newShadow != m_currentShadow) {
                if (m_currentShadow == OnMasterPage) {
                        // masterpage was edited, clear all shadows
                        m_shadows.clear();
                }
                if (!m_shadows.contains(newShadow)) {
                        if (!m_shadows.contains(OnMasterPage)) {
                                m_shadows[OnMasterPage] = itemText;
//                              const ParagraphStyle& pstyle(shadows[OnMasterPage].paragraphStyle(0));
//                              qDebug() << QString("Pageitem_Textframe: style of master: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
//                              qDebug() << QString("Pageitem_Textframe: shadow itemText->%1").arg(OnMasterPage);
                        }
                        if (newShadow != OnMasterPage) {
                                m_shadows[newShadow] = m_shadows[OnMasterPage].copy();
//                              const ParagraphStyle& pstyle(shadows[newShadow].paragraphStyle(0));
//                              qDebug() << QString("Pageitem_Textframe: style of shadow copy: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
                        }
//                      qDebug() << QString("Pageitem_Textframe: shadow %1<-%2").arg(newShadow).arg(OnMasterPage);
                }
                itemText = m_shadows[newShadow];
//              const ParagraphStyle& pstyle(itemText.paragraphStyle(0));
//              qDebug() << QString("Pageitem_Textframe: style of shadow: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment());
                invalid = true;
                m_currentShadow = newShadow;
        }
}
/*
static void debugLineLayout(const StoryText& itemText, const LineSpec& line)
{
        QFile debugFile(QDir::homePath() + "/Desktop/debug_line.csv");
        debugFile.open(QIODevice::WriteOnly);

        QTextStream stream(&debugFile);
        stream.setRealNumberNotation(QTextStream::FixedNotation);
        stream.setRealNumberPrecision(7);

        stream << "xoffset"  << "\t";
        stream << "yoffset"  << "\t";
        stream << "xadvance" << "\t";
        stream << "yadvance" << "\t";
        stream << "scaleH"   << "\t";
        stream << "scaleV"   << "\t";
        stream << "\n";

        for (int zc = line.firstChar; zc < line.lastChar; ++zc)
        {
                const ScText* item = itemText.item(zc);

                stream << item->glyph.xoffset  << "\t";
                stream << item->glyph.yoffset  << "\t";
                stream << item->glyph.xadvance << "\t";
                stream << item->glyph.yadvance << "\t";
                stream << item->glyph.scaleH   << "\t";
                stream << item->glyph.scaleV   << "\t";
                stream << "\n";
        }

        debugFile.close();
}

static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->"))
{
        QString db = QString("%6%1/%2 @ %3: %4--%5 linespa%6: %7 align%8")
                   .arg(pstyle.name())
                   .arg(pstyle.parent())
                   .arg( (unsigned long int) &pstyle)
                   .arg(pstyle.leftMargin())
                   .arg(pstyle.rightMargin())
                   .arg(indent)
                   .arg(pstyle.lineSpacingMode())
                   .arg(pstyle.lineSpacing())
                   .arg(pstyle.alignment());
        qDebug() << db;
        static QString more("  ");
        if (pstyle.hasParent())
                dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent);
}
*/

static const bool legacy = true;

/*
static void layoutDropCap(GlyphLayout layout, double curX, double curY, double offsetX, double offsetY, double dropCapDrop)
{
}
*/



enum TabStatus {
        TabNONE    = 0,
        TabLEFT    = TabNONE,
        TabRIGHT   = 1,
        TabPOINT   = 2,
        TabCOMMA   = 3,
        TabCENTER  = 4
};


/**
fields which describe what type of tab is currently active
 */

struct TabControl {
        bool         active;
        int          status;
        double       xPos;
        QChar        fillChar;
        GlyphLayout* tabGlyph;
};

class LineSpec
{
        public:
        LineSpec()
        {
                x = 0.0;
                y = 0.0;
                width  = 0.0;
                height = 0.0;
                ascent = 0.0;
                descent = 0.0;
                colLeft = 0.0;
                firstCluster = 0;
                lastCluster = 0;
                naturalWidth = 0.0;
                isFirstLine = false;
        }

        qreal x;
        qreal y;
        qreal width;
        qreal height;
        qreal ascent;
        qreal descent;
        qreal colLeft;

        int firstCluster;
        int lastCluster;
        qreal naturalWidth;
        bool isFirstLine;
};

/**
fields which describe how the current line is placed into the frame
*/

struct LineControl {
        LineSpec lineData;
        QList<GlyphCluster> glyphs;
        bool     isEmpty;
        int      hyphenCount;
        double   colWidth;
        double   colGap;
        double   colLeft;
        double   colRight;
        int      column;
        bool     startOfCol;
        bool     hasDropCap;
        bool     afterOverflow;
        bool     addLine;
        bool     recalculateY;
        bool     lastInRowLine;
        bool     addLeftIndent;
        bool     wasFirstInRow;
        double   leftIndent;
        double   rightMargin;
        double   mustLineEnd;
        int      restartIndex;  //index of glyph run where line computing should be restarted
        int      restartRowIndex;  //index of glyph run where row of text is started
        double   restartX; //starting X position of line if must be restarted
        double   rowDesc;

        double   xPos;
        double   yPos;
        int      breakIndex;
        double   breakXPos;

        double   maxShrink;
        double   maxStretch;
        ScribusDoc *doc;
        ITextContext* context;

        /// remember frame dimensions and offsets
        LineControl(double w, double h, const MarginStruct& extra, double lCorr, ScribusDoc* d, ITextContext* ctx, double colwidth, double colgap)
                : hasDropCap(false)
                , doc(d), context(ctx)
        {
                insets = extra;
                lineCorr = lCorr;
                frameWidth = w;
                frameHeight = h;
                column = 0;
                colWidth = colwidth;
                colGap = colgap;
                hyphenCount = 0;
                isEmpty = true;
                colLeft = insets.left() + lineCorr;
                colRight = colLeft + colWidth;
                startOfCol = true;
                afterOverflow = false;
                addLine = false;
                recalculateY = false;
                lastInRowLine = false;
                addLeftIndent = false;
                wasFirstInRow = false;
                leftIndent = 0.0;
                rightMargin = 0.0;
                mustLineEnd = false;
                restartIndex = 0;
                restartRowIndex = 0;
                restartX = 0.0;
                rowDesc = 0.0;
                xPos = 0.0;
                yPos = 0.0;
                breakIndex = -1;
                breakXPos = 0.0;
                maxShrink = 0.0;
                maxStretch = 0.0;
        }

        /// move position to next column
        void nextColumn(TextLayout &textLayout)
        {
                startOfCol = true;
                if (textLayout.story()->defaultStyle().direction() == ParagraphStyle::RTL)
                        colLeft = textLayout.frame()->width() - insets.right() - ((colWidth * (column + 1)) + (colGap * column));
                else
                        colLeft = (colWidth + colGap) * column + insets.left() + lineCorr;
                textLayout.addColumn(colLeft, colWidth);
                //now colRight is REAL column right edge
                colRight = colLeft + colWidth;
                if (legacy)
                        colRight += lineCorr;
                xPos = colLeft;
                yPos = insets.top() + lineCorr;
                lineData.colLeft = colLeft;
        }

        bool isEndOfCol(double morespace = 0)
        {
                return yPos + morespace + insets.bottom() + lineCorr > frameHeight;
        }

        /**
                init fields for a new line at current position
         */

        void startLine(int firstCluster)
        {
                glyphs.clear();
                isEmpty = true;
                lineData.x = xPos;
                lineData.y = yPos;
                lineData.firstCluster = firstCluster;
                lineData.lastCluster = 0;
                lineData.ascent = 0.0;
                lineData.descent = 0.0;
                lineData.width  = 0.0;
                lineData.height = 0.0;
                lineData.naturalWidth = 0.0;
                lineData.colLeft = colLeft;
                breakIndex = -1;
                breakXPos = 0.0;
                maxShrink = 0.0;
                maxStretch = 0.0;
                leftIndent = 0.0;
                rightMargin = 0.0;
                rowDesc = 0.0;
        }


        /// called when glyphs are placed on the line
        void rememberShrinkStretch(QChar ch, double wide, const ParagraphStyle& style)
        {
                if (SpecialChars::isExpandingSpace(ch))
                        maxShrink += (1 - style.minWordTracking()) * wide;
                else
                {
                        maxShrink += (1 - style.minGlyphExtension()) * wide;
                }
                maxStretch += (style.maxGlyphExtension() - 1) * wide;
        }

        /// called when a possible break is passed
        void rememberBreak(int index, double pos, double morespace = 0)
        {
                if (pos > colRight - morespace)
                {
                        // only look for the first break behind the right edge
                        //maxShrink = 0;

                        // check if we already have a better break
                        if (breakIndex >= 0)
                        {
                                double oldLooseness = qAbs(colRight - breakXPos);

                                double newLooseness = pos - colRight;
                                if (newLooseness >= oldLooseness)
                                        return;
                        }
                }
                breakXPos = pos;
                breakIndex = index;
        }

        /// called when a mandatory break is found
        void breakLine(int last)
        {
                breakIndex = last;
                breakXPos  = lineData.x;

                for (int i = 0; i <= breakIndex - lineData.firstCluster; i++)
                        breakXPos += glyphs.at(i).width();
                // #8194, #8717 : update line ascent and descent with sensible values
                // so that endOfLine() returns correct result
                updateHeightMetrics();
                // #9060 : update line offset too
        //      updateLineOffset(itemText, style, offsetPolicy);
        }

        /// use the last remembered break to set line width and itemrange
        void finishLine(double endX)
        {
                lineData.lastCluster = breakIndex;
                lineData.naturalWidth = breakXPos - lineData.x;
                lineData.width = endX - lineData.x;
                maxShrink = maxStretch = 0;
        }

        int restartRow(bool recalcY)
        {
                if (recalcY)
                        yPos++;
                recalculateY = recalcY;
                xPos = restartX = colLeft;
                startLine(restartRowIndex);
                addLeftIndent = true;
                afterOverflow = false;
                return restartRowIndex - 1;
        }

        int restartLine(bool recalcY, bool add)
        {
                recalculateY = recalcY;
                addLine = add;
                xPos = restartX;
                startLine(restartIndex);
                afterOverflow = false;
                return restartIndex - 1;
        }

        bool isEndOfLine(double moreSpace = 0)
        {
                bool res;
                if (legacy)
                        res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight);
                else
                        res = ceil(xPos - maxShrink)  + ceil(moreSpace) >= floor(colRight);
                return res;
        }

        /// Keep old endOfLine code for reference
        /*double endOfLine_old(const QRegion& shape, const QTransform& pf2, double morespace, int Yasc, int Ydesc)
        {
                // if we aren't restricted further, we'll end at this maxX:
                double maxX = colRight - morespace;
                if (legacy) maxX -= lineCorr;

                double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1);
                int xPos  = static_cast<int>(ceil(maxX));

                QPoint  pt12 (xPos, Yasc);
                QPoint  pt22 (xPos, Ydesc);
                QRect   pt(pt12,pt22);
                QRegion region;

                double EndX2 = StartX;
                double Interval = 0.25;
                do {
                        int xP = static_cast<int>(ceil(EndX2 + morespace));
                        pt.moveTopLeft(QPoint(xP, Yasc));
                        region = QRegion(pf2.mapToPolygon(pt)).subtracted(shape);
                        if (!region.isEmpty())
                                break;
                        EndX2 += Interval;
                } while ((EndX2 < maxX) && region.isEmpty());

                return qMin(EndX2, maxX);
        }*/


        /// find x position where this line must end
        double endOfLine(const QRegion& shape, double morespace, int yAsc, int yDesc)
        {
                // if we aren't restricted further, we'll end at this maxX:
                double maxX = colRight - morespace;
                if (legacy) maxX -= lineCorr;

                double StartX = floor(qMax(lineData.x, qMin(maxX, breakXPos-maxShrink-1))-1);
                StartX = qMax(0.0, StartX);

                int xPos  = static_cast<int>(ceil(maxX));
                QPoint  pt12 (xPos, yAsc);
                QPoint  pt22 (xPos, yDesc);

                QPolygon p;
                p.append (QPoint (StartX, yAsc));
                p.append (QPoint (StartX, yDesc));
                p.append (pt12);
                p.append (pt22);
                // check if something gets in the way
                QRegion lineI = shape.intersected (p.boundingRect());
                // if the intersection only has 1 rectangle, then nothing gets in the way
                if (lineI.rectCount() == 1)
                {
                        int   cPos = static_cast<int>(ceil(StartX + morespace));
                        QRect cRect (QPoint(cPos, yAsc), QPoint(cPos, yDesc));
                        QRegion qr2 = QRegion(cRect).subtracted(shape);
                        if (qr2.isEmpty()) // qr2 == 0 <=> cRect subset of shape
                        {
                                QRect rect = lineI.rects().at(0);
                                double  mx = qMax(rect.left(), rect.right()) /*- pf2.dx()*/;
                                int steps  = static_cast<int>((mx - StartX - morespace - 2) / 0.25);
                                if (steps > 0)
                                {
                                        StartX += steps * 0.25;
                                }
                        }
                }

                QRect   pt(pt12, pt22);

                double EndX2 = StartX;
                double Interval = 0.25;
                do {
                        int xP = static_cast<int>(ceil(EndX2 + morespace));
                        pt.moveTopLeft(QPoint(xP, yAsc));
                        if (!regionContainsRect(shape, pt))
                                break;
                        EndX2 += Interval;
                } while ((EndX2 < maxX) && regionContainsRect(shape, pt));

                /*double oldEndX2 = endOfLine_old(shape, pf2, morespace, yAsc, yDesc);
                if (oldEndX2 != qMin(EndX2, maxX))
                {
                        qDebug() << "Different EndX : " << oldEndX2 << " (old) " << EndX2 << " (new) ";
                }*/


                return qMin(EndX2, maxX);
        }

        void updateHeightMetrics()
        {
                lineData.ascent = lineData.descent = 0;
                if (glyphs.isEmpty())
                        return;
                const CharStyle& cStyle(glyphs.at(0).style());
                double scaleV = cStyle.scaleV() / 1000.0;
                double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
                lineData.ascent = cStyle.font().ascent(cStyle.fontSize()/10.00) * scaleV + offset;
                lineData.descent = cStyle.font().descent(cStyle.fontSize()/10.00) * scaleV - offset;
        }

// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!!
// edit: can't happen as it should only move upwards, and this is covered by the calculations done.
//void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy)
//{
//      if (charsInLine <= 0)
//              return;
//      if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing))
//      {
//              //FIXME: use glyphs, not chars
//              double firstasce = itemText.charStyle(line.firstChar).font().ascent(itemText.charStyle(line.firstChar).fontSize() / 10.0);
//              double adj (0.0);
//              double currasce (this->getLineAscent(itemText));
//              if (offsetPolicy == FLOPRealGlyphHeight)
//              {
//                      adj = firstasce - currasce;
//              }
//              else if (offsetPolicy == FLOPFontAscent)
//              {
//                      adj = 0.0;
//              }
//              else if (offsetPolicy == FLOPLineSpacing)
//              {
//                      adj = firstasce - style.lineSpacing();
//              }
//              line.ascent = currasce;
//              line.y -= adj;
//              yPos -= adj;
//      }
//      else if ((!startOfCol) && (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing))
//      {
//              QChar ch = itemText.text(line.firstChar);
//              double firstasce = style.lineSpacing();
//              double currasce  = getLineHeight(itemText);
//              double adj = firstasce - currasce;
//              qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstChar).arg(-adj);
//              line.ascent = currasce;
//              line.y -= adj;
//              yPos -= adj;
//      }
//}

        /// called when line length is known and line is to be justified
        void justifyLine(const ParagraphStyle& style)
        {

                double glyphNatural = 0;
                double spaceNatural = 0;
                double glyphExtension;
                double spaceExtension;
                int spaceInsertion = 0;
                double imSpace = -1;
                int trackingInsertion = 0;
                double trackingAmount = 0;

                int glyphsCount = lineData.lastCluster - lineData.firstCluster + 1;

                for (int i = 0; i < glyphsCount; ++i)
                {
                        const GlyphCluster& glyphCluster = glyphs.at(i);
                        if (!glyphCluster.hasFlag(ScLayout_ExpandingSpace))
                        {
                                glyphNatural += glyphCluster.width();
                        }
                        else if (!glyphCluster.hasFlag(ScLayout_SuppressSpace))
                        {
                                spaceNatural += glyphCluster.width();
                                if (imSpace < 0.0 || imSpace > glyphCluster.width())
                                        imSpace = glyphCluster.width();
                        }
                        if (i != 0 && glyphCluster.hasFlag(ScLayout_ImplicitSpace))
                        {
                                spaceInsertion += 1;
                        }
                        if (i != glyphsCount && glyphCluster.hasFlag(ScLayout_JustificationTracking))
                        {
                                trackingInsertion += 1;
                        }
                }

                imSpace /= 2;

                // decision: prio 1: stretch glyph;  prio 2: insert spaces;  prio 3: stretch spaces

                if (lineData.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0)
                {
                        glyphExtension = style.minGlyphExtension() - 1;
                        spaceExtension = (lineData.width - glyphNatural * (1+glyphExtension) ) / spaceNatural  - 1;
                        imSpace = 0;
                }
                else if (lineData.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0)
                {
                        spaceExtension = 0;
                        glyphExtension = (lineData.width - spaceNatural) / glyphNatural  - 1;
                        imSpace = 0;
                }
                else
                {
                        glyphExtension = style.maxGlyphExtension() - 1;
                        if (spaceInsertion) {
                                double remaining = lineData.width - glyphNatural * (1 + glyphExtension) - spaceNatural;
                                if (imSpace > 0) {
                                        if (remaining / spaceInsertion < imSpace) {
                                                imSpace = remaining / spaceInsertion;
                                                spaceExtension = 0;
                                        } else {
                                                spaceExtension = (remaining + spaceNatural) / (spaceNatural + spaceInsertion * imSpace) - 1;
                                                imSpace *= spaceExtension + 1;
                                        }
                                } else {
                                        imSpace = remaining / spaceInsertion;
                                        spaceExtension = 0;
                                }
                        } else {
                                if (spaceNatural > 0)
                                        spaceExtension = (lineData.width - glyphNatural * (1 + glyphExtension)) / spaceNatural - 1;
                                else
                                        spaceExtension = 0;

                                if (trackingInsertion && (spaceExtension == 0.0 || spaceExtension >= 20.0))
                                {
                                        if (spaceExtension == 0.0)
                                        {
                                                double remaining = lineData.width - glyphNatural * (1 + glyphExtension) - spaceNatural;
                                                trackingAmount = remaining / trackingInsertion;
                                        }
                                        else
                                        {
                                                spaceExtension = qMin(20.0, spaceExtension);
                                                double remaining = lineData.width - glyphNatural * (1 + glyphExtension) - spaceNatural;
                                                remaining -= spaceExtension * spaceNatural;
                                                trackingAmount = remaining / trackingInsertion;
                                                if (trackingAmount > imSpace)
                                                {
                                                        trackingAmount = imSpace;
                                                        spaceExtension = (lineData.width - glyphNatural * (1 + glyphExtension) - trackingInsertion * trackingAmount) / spaceNatural - 1;
                                                }
                                        }
                                }
                        }
                }

                double glyphScale = 1 + glyphExtension;
                double naturalWidth = 0;

        /*
                qDebug() << QString("justify: line = %7 natural = %1 + %2 = %3 (%4); spaces + %5%%; min=%8; glyphs + %6%%; min=%9")
                           .arg(spaceNatural).arg(glyphNatural).arg(spaceNatural+glyphNatural).arg(line.naturalWidth)
                           .arg(spaceExtension).arg(glyphExtension).arg(line.width)
                           .arg(style.minWordTracking()).arg(style.minGlyphExtension());
                */


                int startItem = 0;
                if (glyphs[startItem].hasFlag(ScLayout_DropCap))
                {
                        startItem++;
                        naturalWidth += glyphs[startItem].width();
                }
                // distribute whitespace on spaces and glyphs
                for (int i = startItem; i < glyphsCount; ++i)
                {
                        GlyphCluster& glyphCluster = glyphs[i];
                        double wide = glyphCluster.width();
                        if (!glyphCluster.hasFlag(ScLayout_ExpandingSpace))
                        {
                                glyphCluster.setScaleH(glyphCluster.scaleH() * glyphScale);
                                glyphCluster.xoffset *= glyphScale;
                        }
                        else if (!glyphCluster.hasFlag(ScLayout_SuppressSpace))
                        {
                                glyphCluster.extraWidth += (wide * spaceExtension);
                        }
                        if (i != 0 && glyphCluster.hasFlag(ScLayout_ImplicitSpace))
                        {
                                GlyphCluster& lastRun = glyphs[i - 1];
                                lastRun.extraWidth += imSpace;
                        }
                        if (i != glyphsCount && trackingAmount != 0 && glyphCluster.hasFlag(ScLayout_JustificationTracking))
                        {
                                glyphCluster.extraWidth += trackingAmount;
                        }
                        naturalWidth += glyphCluster.width();
                }
                lineData.naturalWidth = naturalWidth;

                if ((style.alignment() == ParagraphStyle::Extended) &&
                        (style.direction() == ParagraphStyle::RTL))
                {
                        double offset = lineData.width - lineData.naturalWidth;
                        if (offset > 1e-6)
                                indentLine(style, offset);
                }
        }

        /// called when linelength is known and line is not justified
        void indentLine(const ParagraphStyle& style, double leftIndent)
        {
                if (lineData.naturalWidth > lineData.width)
                {
                        justifyLine(style);
                }
                if (leftIndent > 0)
                {
                        lineData.x += leftIndent;
                        lineData.width -= leftIndent;
                }
        }

        /**
         Clones the tab fill char as often as necssary after all distances are known
         */

        void fillInTabLeaders()
        {
                // fill in tab leaders
                for (int i = 0; i < glyphs.count(); ++i)
                {
                        GlyphCluster& glyphCluster = glyphs[i];
                        if (glyphCluster.hasFlag(ScLayout_TabLeaders))
                        {
                                const CharStyle& charStyle(glyphCluster.style());
                                GlyphLayout tglyph = glyphCluster.glyphs().last();
                                double width = glyphCluster.width();
                                double wt = charStyle.font().glyphWidth(tglyph.glyph, charStyle.fontSize() * tglyph.scaleV / 10.0);
                                int count = static_cast<int>(width / wt);
                                if (count > 0)
                                        glyphCluster.glyphs().clear();
                                for(int cx = 0; cx < count; ++cx)
                                {
                                        GlyphLayout more = tglyph;
                                        more.xadvance = 0;
                                        if (cx != 0)
                                                more.xoffset = (width / count) * cx;
                                        glyphCluster.append(more);
                                }
                                glyphCluster.glyphs().last().xadvance = width / glyphCluster.scaleH();
                        }
                }
        }


        //defined but not used
        ///// calculate how much the first char should stick out to the left
        //double opticalLeftMargin(const StoryText& itemText)
        //{
        //      int b = line.firstChar;
        //      while (b < line.lastChar && (itemText.flags(b) & ScLayout_SuppressSpace))
        //                 ++b;
        //
        //      double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
        //      QChar chr = itemText.text(b);
        //      double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
        //      if (QString("'´`").indexOf(chr) >= 0
        //              || chr == QChar(0x2018) // quote 6
        //              || chr == QChar(0x2019) // quote 9
        //              || chr == QChar(0x201a) // lower quote 9
        //              || chr == QChar(0x201b) // upper reversed 9 6
        //              || chr == QChar(0x2039) // single guillemet <
        //              || chr == QChar(0x203a) // single guillemet >
        //              )
        //              leftCorr *= -0.7;
        //      else if (QString("\"").indexOf(chr) >= 0
        //                       || chr == QChar(0x00ab) // guillemet <<
        //                       || chr == QChar(0x00bb) // guillemet >>
        //                       || chr == QChar(0x201c) // quote 66
        //                       || chr == QChar(0x201d) // quote 99
        //                       || chr == QChar(0x201e) // lower quote 99
        //                       || chr == QChar(0x201f) // upper reversed 99
        //                       )
        //              leftCorr *= -0.5;
        //      else {
        //              leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
        //              leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
        ////                            double leftCorr2 = itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0, chr);
        ////                            leftCorr2 -= itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0);
        ////                            leftCorr = qMin(leftCorr, leftCorr2);
        //      }
        //      return leftCorr;
        //}

        /// calculate how much the last char should stick out to the right
        double opticalRightMargin(const StoryText& itemText)
        {
                int b = lineData.lastCluster - lineData.firstCluster;
                while (b > 0 &&
                           (SpecialChars::isBreakingSpace(itemText.text(glyphs[b].lastChar())) ||
                                SpecialChars::isBreak(itemText.text(glyphs[b].lastChar())))
                           )
                        --b;
                if (b >= 0)
                {
                        const CharStyle& style = glyphs[b].style();
                        const ScFace& font = style.font();
                        double chs = style.fontSize() * (style.scaleH() / 1000.0);
                        QChar chr = itemText.text(glyphs[b].lastChar());
                        double rightCorr;
                        if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible))
                                rightCorr = font.hyphenWidth(style, chs / 10.0);
                        else
                                rightCorr = font.glyphBBox(font.char2CMap(chr.unicode()), chs / 10.0).width;
                        if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible)
                                || QString("-,.`´'~").indexOf(chr) >= 0
                                || chr == QChar(0x2010)
                                || chr == QChar(0x2018)
                                || chr == QChar(0x2019)
                                || chr == QChar(0x201a)
                                || chr == QChar(0x201b)
                                || chr == QChar(0x2039)
                                || chr == QChar(0x203a)
                                || chr == QChar(0x2032) // PRIME
                                )
                                rightCorr *= 0.7;
                        else if (QString(";:\"").indexOf(chr) >= 0
                                         || chr == QChar(0x00ab)
                                         || chr == QChar(0x00bb)
                                         || chr == QChar(0x201c)
                                         || chr == QChar(0x201d)
                                         || chr == QChar(0x201e)
                                         || chr == QChar(0x201f)
                                         || chr == QChar(0x2013) // EN DASH
                                         || chr == QChar(0x2033) // double prime
                                         )
                                rightCorr *= 0.5;
                        else {
#if 0
                                // FIXME HOST: is the kerning with "." a realy reliable way to check this?
                                rightCorr = chStyle.font().realCharWidth(chr, chs / 10.0);
                                rightCorr -= chStyle.font().charWidth(chr, chs / 10.0, QChar('.'));
#else
                                rightCorr = 0;
#endif
                        }
                        return rightCorr;
                }
                return 0.0;
        }

        LineBox* createLineBox()
        {
                LineBox* result = new LineBox();
                result->moveTo(lineData.x - colLeft, lineData.y - lineData.ascent);
                result->setWidth(lineData.width);
                result->setAscent(lineData.ascent);
                result->setDescent(lineData.descent);
                foreach (const GlyphCluster& run, ShapedTextFeed::putInVisualOrder(glyphs,   0, lineData.lastCluster - lineData.firstCluster + 1))
                {
                        addBox(result, run);
//                      qDebug() << "cluster" << run.firstChar() << ".." << run.lastChar() << "@" << run.visualIndex();
                }
                return result;
        }

        void addBox(LineBox *lineBox, const GlyphCluster& run)
        {
                Box* result;
                if (run.object().getPageItem(doc))
                {
                        result = new ObjectBox(run, context);
                        QRectF bBox = context->getVisualBoundingBox(run.object());
                        if (run.hasFlag(ScLayout_DropCap))
                                result->setAscent(bBox.height() * run.scaleV() - run.yoffset);
                        else
                                result->setAscent(bBox.height());
                        result->setDescent(0);
                }
                else
                {
                        result = new GlyphBox(run);
                        result->setAscent(lineBox->ascent());
                        result->setDescent(lineBox->descent());
                }
                lineBox->addBox(result);
        }

private:
        double frameWidth;
        double frameHeight;
        MarginStruct insets;
        double lineCorr;
};

static bool allowedCJKBreakAfter(QChar ch) {
        unsigned int code[] = {0x201C, 0x300C, 0xFF08, 0xFF3B, 0xFF5B, 0xFF5F, 0xFF62, 0xFF0D, 0};
        for (int i = 0; code[i]; ++i)
                if (code[i] == ch.unicode())
                        return false;
        return true;
}

static int allowedCJKBreakBefore(QChar ch) {
        unsigned int code[] =
         {0x201D, 0x3001, 0x3002, 0x300D, 0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A,
          0xFF1B, 0xFF1F, 0xFF3D, 0xFF5D, 0xFF60, 0xFF63, 0xFF64, 0};
        for (int i = 0; code[i]; ++i)
                if (code[i] == ch.unicode())
                        return false;
        return true;
}

static bool implicitBreak(QChar f, QChar s) {
        if (SpecialChars::isCJK(f.unicode()) && SpecialChars::isCJK(s.unicode())) {
                return allowedCJKBreakAfter(f) && allowedCJKBreakBefore(s);
        } else
                return false;
}

static double findRealOverflowEnd(const QRegion& shape, QRect pt, double maxX)
{
        while (!regionContainsRect(shape, pt) && pt.right() < maxX)
                pt.translate(1, 0);
        if (pt.right() >= maxX)
                return maxX;
        return pt.left() + 0.5;
}

static double adjustToBaselineGrid (const LineControl &control, PageItem *item, int OwnPage)
{
        double by = item->yPos();
        if (OwnPage != -1)
                by = by - item->doc()->Pages->at(OwnPage)->yOffset();
        int ol1 = qRound((by + control.yPos - item->doc()->guidesPrefs().offsetBaselineGrid) * 10000.0);
        int ol2 = static_cast<int>(ol1 / item->doc()->guidesPrefs().valueBaselineGrid);
//                                              qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil(  ol2 / 10000.0 ) * item->doc()->typographicSettings.valueBaselineGrid + item->doc()->typographicSettings.offsetBaselineGrid - by);

        return ceil(  ol2 / 10000.0 ) * item->doc()->guidesPrefs().valueBaselineGrid + item->doc()->guidesPrefs().offsetBaselineGrid - by;
}

static double nextAutoTab (const LineControl &current, PageItem *item)
{
        double dtw = item->doc()->itemToolPrefs().textTabWidth;
        if (current.xPos == current.colLeft)
                return current.colLeft + dtw;
        double res = current.colLeft + ceil ((current.xPos - current.colLeft) / dtw) * dtw;
        if (res == current.xPos) res += dtw;
        return res;
}

//cezaryece: I remove static statement as this function is used also by PageItem_NoteFrame
double calculateLineSpacing (const ParagraphStyle &style, PageItem *item)
{
        if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
        {
                double autoLS = static_cast<double>(item->doc()->typographicPrefs().autoLineSpacing) / 100.0;
                return (style.charStyle().font().height(style.charStyle().fontSize() / 10.0) * autoLS);
        }
        if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
                return item->doc()->guidesPrefs().valueBaselineGrid;
        return style.lineSpacing();
}


// This assumes that layout() ran on the previous page and set the incomplete* vars
// It also clears the incomplete* vars, and changes the starting position for this frame
// The incomplete* vars are used to ensure that we don't run into an endless loop
// This setup won't cause any problems, as the only way for the starting position to change
// back is if the previous frame's layout() runs again, but if it does, it also sets the
// incomplete* vars for us
bool PageItem_TextFrame::moveLinesFromPreviousFrame ()
{
        PageItem_TextFrame* prev = dynamic_cast<PageItem_TextFrame*>(BackBox);
        if (!prev) return false;
        if (!prev->incompleteLines) return false;   // no incomplete lines - nothing to do
        int pos = textLayout.endOfFrame()-1;
        QChar lastChar = itemText.text (pos);
        // qDebug()<<"pos is"<<pos<<", length is"<<itemText.length()<<", incomplete is "<<prev->incompleteLines;
        if ((pos != itemText.length()-1) && (!SpecialChars::isBreak (lastChar, true)))
                return false;  // the paragraph isn't ending yet
        int lines = textLayout.lines();  // lines added to the current frame

        ParagraphStyle style = itemText.paragraphStyle (pos);
        int need = style.keepLinesEnd () + 1;
        int prevneed = style.keepLinesStart () + 1;
        if (lines >= need) {
                prev->incompleteLines = 0;   // so that further paragraphs don't pull anything
                return false;   // we have enough lines
        }

        // too few lines - we need to pull some from the previous page
        int pull = need - lines;
        // if pulling the lines would lead to the original frame having too few, pull the whole paragraph
        if (prev->incompleteLines - pull < prevneed)
                pull = prev->incompleteLines;
        // qDebug()<<"pulling"<<pull<<"lines;
        // Okay, move the starting/ending character
        int startingPos = prev->incompletePositions[prev->incompleteLines - pull];
        for (int i = 0; i < pull; ++i)
                prev->textLayout.removeLastLine();
        firstChar = prev->MaxChars = startingPos;
        // keep the remaining incomplete lines flagged as such
        // this ensures that if pulling one line won't be enough, the subsequent call to layout() will pull more
        prev->incompleteLines -= pull;

        return true;
}

// called at the end of a frame or column
void PageItem_TextFrame::adjustParagraphEndings ()
{
        // More text to go - let's apply paragraph flowing options - orphans/widows, etc
        int pos = textLayout.endOfFrame() - 1;
        if (pos >= itemText.length() - 1) return;

        ParagraphStyle style = itemText.paragraphStyle (pos);
        int paragraphStart = itemText.prevParagraph (pos) + 1;
        QChar lastChar = itemText.text (pos);
        bool keepWithNext = style.keepWithNext() && (lastChar == SpecialChars::PARSEP);
        if (keepWithNext || (!SpecialChars::isBreak (lastChar, true))) {
                // paragraph continues in the next frame, or needs to be kept with the next one
                // check how many lines are in this frame
                int lineStart = textLayout.startOfLine (pos);
                incompleteLines = 1;
                incompletePositions.prepend (lineStart);
                while (lineStart > paragraphStart) {
                        lineStart = textLayout.startOfLine (lineStart - 1);
                        incompleteLines++;
                        incompletePositions.prepend (lineStart);
                }
                int need = style.keepLinesStart () + 1;
                if (style.keepTogether()) need = incompleteLines;
                int pull = 0;
                if (style.keepTogether() || (incompleteLines < need)) pull = incompleteLines;
                // if we need to keep it with the next one, pull one line. Next frame layouting
                // will pull more from us if it proves necessary.
                if (keepWithNext && (!pull)) pull = 1;

                if (pull) {
                        qDebug() << "pulling" << pull << "lines";
                        // push this paragraph to the next frame
                        for (int i = 0; i < pull; ++i)
                                textLayout.removeLastLine();
                        MaxChars = incompletePositions[incompleteLines-pull];
                        incompleteLines = 0;
                        incompletePositions.clear();
                }
        }
}

void PageItem_TextFrame::layout()
{
//      qDebug()<<"==Layout==" << itemName() ;
//      printBacktrace(24);
        if (BackBox != NULL) {
//              qDebug("textframe: len=%d, going back", itemText.length());
                PageItem_TextFrame* firstInvalid = NULL;
                PageItem_TextFrame* prevInChain  = dynamic_cast<PageItem_TextFrame*>(BackBox);
                while (prevInChain)
                {
                        if (prevInChain->invalid)
                                firstInvalid = prevInChain;
                        prevInChain = dynamic_cast<PageItem_TextFrame*>(prevInChain->BackBox);
                }
                PageItem_TextFrame* nextInChain = firstInvalid;
                while (nextInChain && (nextInChain != this))
                {
                        nextInChain->layout();
                        nextInChain = dynamic_cast<PageItem_TextFrame*>(nextInChain->NextBox);
                }
                // #9592 : warning, BackBox->layout() may not layout BackBox next box
                if (!invalid)
                        return;
        }
        else if (!invalid && OnMasterPage.isEmpty()) {
//              qDebug() << QString("textframe: len=%1, invalid=%2 OnMasterPage=%3: no relayout").arg(itemText.length()).arg(invalid).arg(OnMasterPage);
                return;
        }
        if (invalid && BackBox == NULL)
                firstChar = 0;

//      qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(m_xPos).arg(m_yPos).arg(itemText.length()).arg(firstInFrame());
        QPoint pt1, pt2;
        QRect pt;
        double chs, chsd = 0;
        double EndX, OFs;
        ParagraphStyle style;
        int opticalMargins = ParagraphStyle::OM_None;

        bool outs = false;
        bool goNoRoom = false;
        bool goNextColumn = false;

        TabControl tabs;
        tabs.active    = false;     // RTab
        tabs.status    = TabNONE;   // TabCode
        tabs.tabGlyph  = 0;         // was int charIndex ~ StartRT
        tabs.xPos      = 0;         // RTabX

        QList<ParagraphStyle::TabRecord> tTabValues;
        tTabValues.clear();

        bool BulNumMode = false; //when bullet or counter should be inserted
        bool   DropCmode = false, FlopBaseline = false;
        double desc=0, asce=0, realAsce=0, realDesc = 0, offset = 0;
        double maxDY=0, maxDX=0;
        double DropCapDrop = 0;
        int    DropLines = 0;
        int    DropLinesCount = 0;

        textLayout.clear();
        incompleteLines = 0;
        incompletePositions.clear();

        double lineCorr = 0;
        if (lineColor() != CommonStrings::None)
                lineCorr = m_lineWidth / 2.0;

        //hold Y position of last computed line of text (with glyphs descent)
        //for moving next line if glyphs are higher than that
        double lastLineY = 0;

        QMap<int, Mark*> noteMarksPosMap;  //maping notes marks and its position in text

        // dump styles
/*
        for (int i=0; i < itemText.nrOfParagraphs(); ++i) {
                const ParagraphStyle& pstyle(itemText.paragraphStyle(itemText.endOfParagraph(i)));
                qDebug("par %d:", i);
                dumpIt(pstyle);
        }
        qDebug() << "default:";
        dumpIt(itemText.defaultStyle());
*/


        setShadow();
        int itLen = itemText.length();
        //fast validate empty frames
        if (itLen == 0 || firstInFrame() == itLen)
        {
                PageItem_TextFrame * next = this;
                while (next != NULL)
                {
                        next->invalid = false;
                        next->firstChar = itLen;
                        next->MaxChars = itLen;
                        next->textLayout.clear();
                        next = dynamic_cast<PageItem_TextFrame*>(next->nextInChain());
                }
                // TODO layout() shouldn't delete any frame here, as it breaks any loop
                // over the doc->Items or doc->MasterItems lists when done with indexes
                // see Bug #12685 for an example
                if (!isNoteFrame() && m_Doc->notesChanged() && !m_notesFramesMap.isEmpty())
                { //if notes are used
                        UndoManager::instance()->setUndoEnabled(false);
                        QList<PageItem_NoteFrame*> delList;
                        foreach (PageItem_NoteFrame* nF, m_notesFramesMap.keys())
                        {
                                if (nF->notesList().isEmpty() && !nF->isAutoNoteFrame())
                                        delList.append(nF);
                        }
                        while (!delList.isEmpty())
                                m_Doc->delNoteFrame(delList.takeFirst(), false);
                        UndoManager::instance()->setUndoEnabled(true);
                }
                return;
        }

        if ((itLen != 0)) // || (NextBox != 0))
        {
                // determine layout area
                m_availableRegion = calcAvailableRegion();
                if (m_availableRegion.isEmpty())
                {
                        MaxChars = firstInFrame();
                        goto NoRoom;
                }

                if (imageFlippedH() || imageFlippedV())
                {
                        QTransform matrix;
                        if (imageFlippedH())
                        {
                                matrix.translate(m_width, 0);
                                matrix.scale(-1, 1);
                        }
                        if (imageFlippedV())
                        {
                                matrix.translate(0, m_height);
                                matrix.scale(1, -1);
                        }
                        m_availableRegion = matrix.map(m_availableRegion);
                }

                ITextContext* context = this;
                //TextShaper textShaper(this, itemText, firstInFrame());
                ShapedTextFeed shapedText(&itemText, firstInFrame(), context);
               
                QList<GlyphCluster> glyphClusters; // = textShaper.shape();
                // std::sort(glyphClusters.begin(), glyphClusters.end(), logicalGlyphRunComp);

                LineControl current(m_width, m_height, m_textDistanceMargins, lineCorr, m_Doc, context,columnWidth(), ColGap);
                current.nextColumn(textLayout);

                lastLineY = m_textDistanceMargins.top();

                //automatic line spacing factor (calculated once)
                double autoLS = static_cast<double>(context->typographicPrefs().autoLineSpacing) / 100.0;

                // find start of first line
                if (firstInFrame() < itLen)
                {
                        const CharStyle& cstyle = itemText.charStyle(firstInFrame());
                        style = itemText.paragraphStyle(firstInFrame());
                        style.setLineSpacing (calculateLineSpacing (style, this));

//                      qDebug() << QString("style @0: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin())
//                                 .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()?style.parent()->name():"");
                        if (style.hasDropCap())
                        {
                                chs = calculateLineSpacing (style, this) * style.dropCapLines() * 10;
                        }
                        else
                                chs = cstyle.fontSize();
                        desc = -cstyle.font().descent(chs / 10.0);
                        current.yPos = m_textDistanceMargins.top() + lineCorr;
//                      qDebug() << QString("first line at y=%1").arg(current.yPos);

                }
                else // empty itemText:
                {
                        desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0);
                        current.yPos = itemText.defaultStyle().lineSpacing() + m_textDistanceMargins.top() + lineCorr - desc;
                }
                // update Bullet & number list if any.
                updateBulletsNum();

                current.startLine(0);

                outs = false;
                OFs = 0;
                MaxChars = 0;
                double realEnd = 0;
                current.restartIndex = current.restartRowIndex = 0;
                current.afterOverflow = false;
                current.addLine = false;
                current.recalculateY = true;
                current.lastInRowLine = false;
                current.addLeftIndent = true;
                current.wasFirstInRow = false;
                current.leftIndent = 0;
                current.rightMargin = 0.0;
                current.mustLineEnd = current.colRight;
                current.restartX = 0;

                //why emit invalidating signals each time text is changed by appling styles?
                //this speed up layouting in case of using notes marks and drop caps
                itemText.blockSignals(true);
                setMaxY(-1);
                double maxYAsc = 0.0, maxYDesc = 0.0;
                int regionMinY = 0, regionMaxY= 0;

                double autoLeftIndent = 0.0;
                for (int i = 0; shapedText.haveMoreText(i, glyphClusters); ++i)
                {
                        int currentIndex = i - current.lineData.firstCluster;
                        GlyphCluster newRun = glyphClusters[i];
                        if (currentIndex >= current.glyphs.count())
                                current.glyphs.append(newRun);
                        else
                                current.glyphs[currentIndex] = newRun;

                        if (current.glyphs[currentIndex].glyphs().isEmpty())
                                continue;

                        int a = current.glyphs[currentIndex].firstChar();
                        bool HasObject = itemText.hasObject(a);
                        PageItem* currentObject = itemText.object(a).getPageItem(m_Doc);
                        QRectF currentObjectBox = QRectF();
                        if (HasObject)
                                currentObjectBox = currentObject->getVisualBoundingRect();

                        bool HasMark = itemText.hasMark(a);

                        if (HasMark)
                        {
                                Mark* mark = itemText.mark(a);
                                //store mark pointer and position in text
                                if (mark->isType(MARKNoteMasterType))
                                        noteMarksPosMap.insert(a, mark);
                        }

                        BulNumMode = false;
                        if (itemText.isBlockStart(a))
                        {
                                autoLeftIndent = 0.0;
                                style = itemText.paragraphStyle(a);
                                if (style.hasBullet() || style.hasNum())
                                {
                                        BulNumMode = true;
                                }
                        }

                        if (current.isEmpty)
                                opticalMargins = style.opticalMargins();
                        //-->#13490
                        if (isNoteFrame() && !HasMark)
                        {
                                StyleFlag s(itemText.charStyle(a).effects());
                                s &= ~ScStyle_Superscript;
                                CharStyle haveSuperscript;
                                haveSuperscript.setFeatures(s.featureList());
                                itemText.applyCharStyle(a, 1, haveSuperscript);
                        }
                        //--<#13490
                        CharStyle charStyle = ((itemText.text(a) != SpecialChars::PARSEP) ? itemText.charStyle(a) : style.charStyle());

                        //set style for paragraph effects
                        if (itemText.isBlockStart(a))
                        {
                                // FIXME: we should avoid calling setCharStyle() in layout()
                                if (style.hasDropCap() || style.hasBullet() || style.hasNum())
                                {
                                        const QString& curParent(style.hasParent() ? style.parent() : style.name());
                                        CharStyle newStyle(charStyle);
                                        if (style.peCharStyleName().isEmpty())
                                                newStyle.setParent(m_Doc->paragraphStyle(curParent).charStyle().name());
                                        else if (charStyle.name() != style.peCharStyleName())
                                                newStyle.setParent(m_Doc->charStyle(style.peCharStyleName()).name());
                                        charStyle.setStyle(newStyle);
                                        itemText.setCharStyle(a, 1 , charStyle);
                                }
                                else if (!style.peCharStyleName().isEmpty())
                                {
                                        //par effect is cleared but is set dcCharStyleName = clear drop cap char style
                                        if (charStyle.parent() == style.peCharStyleName())
                                        {
                                                const QString& curParent(style.hasParent() ? style.parent() : style.name());
                                                if (m_Doc->charStyles().contains(style.peCharStyleName()))
                                                        charStyle.eraseCharStyle(m_Doc->charStyle(style.peCharStyleName()));
                                                charStyle.setParent(m_Doc->paragraphStyle(curParent).charStyle().name());
                                                itemText.setCharStyle(a, 1,charStyle);
                                        }
                                }
                        }

                        double hlcsize10 = charStyle.fontSize() / 10.0;
                        double scaleV = charStyle.scaleV() / 1000.0;
                        double scaleH = charStyle.scaleH() / 1000.0;
                        double offset = hlcsize10 * (charStyle.baselineOffset() / 1000.0);
                        style.setLineSpacing (calculateLineSpacing (style, this));
                        FlopBaseline = (current.startOfCol && firstLineOffset() == FLOPBaselineGrid);

                        // find out about par gap and dropcap
                        if (a == firstInFrame())
                        {
                                if (itemText.isBlockStart(a))
                                {
                                        if (!itemText.isBlockStart(a+1))
                                        {
                                                DropCmode = style.hasDropCap();
                                                if (DropCmode)
                                                        DropLines = style.dropCapLines();
                                        }
                                        else
                                                DropCmode = false;
                                        current.lineData.isFirstLine = true;
                                }
                        }

                        const ScFace& font = charStyle.font();

                        current.glyphs[currentIndex].clearFlag(ScLayout_DropCap);
                        current.glyphs[currentIndex].clearFlag(ScLayout_SoftHyphenVisible);

                        // No space at begin of line,
                        if (legacy)
                        {
                                // unless at begin of par (eeks)
                                if ( (current.isEmpty) && (SpecialChars::isBreakingSpace(itemText.text(a)))
                                         && (a > 0 && ! SpecialChars::isBreak(itemText.text(a-1)))
                                         && ! (a > 0 && SpecialChars::isBreakingSpace(itemText.text(a-1))
                                                   && (!glyphClusters[i - 1].hasFlag(ScLayout_SuppressSpace))))
                                {
                                        current.glyphs[currentIndex].setFlag(ScLayout_SuppressSpace);
                                        continue;
                                }
                                else
                                        current.glyphs[currentIndex].clearFlag(ScLayout_SuppressSpace);
                        }
                        else // from 134 on use NBSPACE for this effect
                        {
                                if ( current.isEmpty && (SpecialChars::isBreakingSpace(itemText.text(a)) || itemText.text(a).isSpace()))
                                {
                                        current.glyphs[currentIndex].setFlag(ScLayout_SuppressSpace);
                                        continue;
                                }
                                else
                                        current.glyphs[currentIndex].clearFlag(ScLayout_SuppressSpace);
                        }
                        if (current.isEmpty)
                        {
                                if (style.rightMargin() == 0)
                                {
                                        //addLine = true;
                                        current.rightMargin = 0.0;
                                }
                                else
                                {
                                        if (current.lastInRowLine)
                                                current.rightMargin = style.rightMargin();
                                        else
                                                current.rightMargin = 0.0;
                                }
                                current.breakIndex = -1;
                                if (current.startOfCol && !current.afterOverflow && current.recalculateY)
                                        current.yPos = qMax(current.yPos, m_textDistanceMargins.top());
                                // more about par gap and dropcaps
                                if ((a > firstInFrame() && itemText.isBlockStart(a)) || (a == 0 && BackBox == 0 && current.startOfCol))
                                {
                                        if (!current.afterOverflow && current.recalculateY && !current.startOfCol)
                                                current.yPos += style.gapBefore();
                                        DropCapDrop = 0;
                                        if (!itemText.isBlockStart(a+1))
                                                DropCmode = style.hasDropCap();
                                        else
                                                DropCmode = false;
                                        if (DropCmode && !current.afterOverflow)
                                        {
                                                DropLines = style.dropCapLines();
//                                              DropCapDrop = calculateLineSpacing (style, this) * (DropLines - 1);
//                                              qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop);
                                        }
                                        current.lineData.isFirstLine = true;
                                }
                        }
                        // find charsize factors
                        if (DropCmode)
                        {
                                DropCapDrop = calculateLineSpacing (style, this) * (DropLines - 1);

                                //text height, width, ascent and descent should be calculated for whole text provided by ScText in current position
                                //and that may be more than one char (variable text for example)
                                double realCharHeight = 0.0, realCharAscent = 0.0;
                                foreach (const GlyphLayout& gl, current.glyphs[currentIndex].glyphs()) {
                                        GlyphMetrics gm = font.glyphBBox(gl.glyph);
                                        realCharHeight = qMax(realCharHeight, gm.ascent + gm.descent);
                                        realCharAscent = qMax(realCharAscent, gm.ascent);
                                }
                                double fontAscent = font.ascent(style.charStyle().fontSize() / 10.0);
                                if (realCharHeight == 0.0)
                                        realCharHeight = font.height(style.charStyle().fontSize() / 10.0);
                                if (realCharAscent == 0.0)
                                        realCharAscent = fontAscent;
                                chsd = (10 * ((DropCapDrop + fontAscent) / realCharHeight));
                                chs  = (10 * ((DropCapDrop + fontAscent) / realCharAscent));
                                current.glyphs[currentIndex].setFlag(ScLayout_DropCap);
                                if (HasObject)
                                {
                                //      chs = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
                                //      chsd = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
                                        chs = currentObjectBox.height() * 10;
                                        chsd = currentObjectBox.height() * 10;
                                }
                        }
                        else // ! dropCapMode
                        {
                                if (HasObject)
                                        chs = currentObjectBox.height() * 10;
                                //      chs = qRound((currentObject->height() + currentObject->lineWidth()) * 10);
                                else
                                        chs = charStyle.fontSize();
                        }
                        // set StartOfLine
                        if (current.isEmpty)
                                current.glyphs[currentIndex].setFlag(ScLayout_StartOfLine);
                        else
                                current.glyphs[currentIndex].clearFlag(ScLayout_StartOfLine);

                        if (!current.glyphs[currentIndex].hasFlag(ScLayout_StartOfLine))
                        {
                                double tracking = charStyle.fontSize() * charStyle.tracking() / 10000.0;
                                current.glyphs[currentIndex].xoffset += tracking;
                                if (current.glyphs[currentIndex].width() != 0)
                                        current.glyphs[currentIndex].extraWidth += tracking;
                        }

//                      glyphs->yadvance = 0;

                        if (i == current.lineData.firstCluster && current.glyphs[currentIndex].hasFlag(ScLayout_CJKFence))
                        {
                                current.glyphs[currentIndex].extraWidth -= (charStyle.fontSize() / 10 / 2);
                                current.glyphs[currentIndex].xoffset -= (charStyle.fontSize() / 10 / 2);
                        }
                        // find out width, ascent and descent of char
                        double wide = current.glyphs[currentIndex].width();

                        if (DropCmode)
                        {
                                // drop caps are wider...
                                GlyphCluster& glyphCluster = current.glyphs[currentIndex];
                                if (HasObject)
                                {
                                //      double itemHeight = currentObject->height() + currentObject->lineWidth();
                                //      if (itemHeight == 0)
                                //              itemHeight = font.height(style.charStyle().fontSize() / 10.0);
                                //      asce = currentObject->height() + currentObject->lineWidth();
                                //      wide = currentObject->width() + currentObject->lineWidth();
                                        double itemHeight = currentObjectBox.height();
                                        if (itemHeight == 0)
                                                itemHeight = font.height(style.charStyle().fontSize() / 10.0);
                                        asce = currentObjectBox.height();
                                        wide = currentObjectBox.width();
                                        realAsce = calculateLineSpacing (style, this) * DropLines;
                                        glyphCluster.setScaleH(glyphCluster.scaleH() / glyphCluster.scaleV());
                                        glyphCluster.setScaleV(realAsce / itemHeight);
                                        glyphCluster.setScaleH(glyphCluster.scaleH() * glyphCluster.scaleV());
                                        wide *= glyphCluster.scaleH();
                                }
                                else
                                {
                                        double realCharHeight = 0.0;
                                        wide = 0.0; realAsce = 0.0;
                                        foreach (const GlyphLayout& gl, glyphCluster.glyphs()) {
                                                GlyphMetrics gm;
                                                gm = font.glyphBBox(gl.glyph, charStyle.fontSize() / 10.0);
                                                realCharHeight = qMax(realCharHeight, gm.ascent + gm.descent);
                                                gm = font.glyphBBox(gl.glyph, chsd / 10.0);
                                                realAsce = qMax(realAsce, gm.ascent + gm.descent);
                                                wide += gm.width;
                                        }
                                        wide = (wide* scaleH) + (1 - scaleH);
                                        realAsce = realAsce  * scaleV + offset;
                                        if (realCharHeight == 0)
                                                realCharHeight = font.height(style.charStyle().fontSize() / 10.0);
                                        asce = font.ascent(hlcsize10);
                                        glyphCluster.setScaleH(glyphCluster.scaleH() / glyphCluster.scaleV());
                                        glyphCluster.setScaleV(realAsce / realCharHeight);
                                        glyphCluster.setScaleH(glyphCluster.scaleH() * glyphCluster.scaleV());
                                        glyphCluster.xoffset -= 0.5; //drop caps are always to far from column left edge
                                }
                                // This is to mimic pre-boxes branches in case first character of paragraph is a space
                                // If we don't do this, paragraph offset will not apply correctly to first line
                                if ((glyphCluster.scaleH() == 0.0) || (glyphCluster.scaleV() == 0.0))
                                {
                                        glyphCluster.setScaleH(1.0);
                                        glyphCluster.setScaleV(1.0);
                                        wide = 0.0;
                                }
                                desc = realDesc = 0;
                        }
                        else // !DropCMode
                        {
                                // find ascent / descent
                                if (HasObject)
                                        desc = realDesc = 0;
                                else
                                {
                                        if (itemText.text(a) != SpecialChars::OBJECT)
                                        {
                                                foreach (const GlyphLayout& gl, current.glyphs[currentIndex].glyphs())
                                                {
                                                        GlyphMetrics gm = font.glyphBBox(gl.glyph, hlcsize10);
                                                        realDesc = qMax(realDesc, gm.descent * scaleV - offset);
                                                        realAsce = gm.ascent;
                                                }
                                        }
                                        desc = -font.descent(hlcsize10);
                                        current.rememberShrinkStretch(itemText.text(a), wide, style);
                                }
                                if (HasObject)
                                {
                                //      asce = currentObject->height() + currentObject->lineWidth();
                                        asce = currentObjectBox.height();
                                        realAsce = asce * scaleV + offset;
                                        wide = currentObjectBox.width() * scaleH;
                                }
                                else
                                {
                                        asce = font.ascent(hlcsize10);
                                        if (HasMark && !BulNumMode)
                                                realAsce = asce * scaleV + offset;
                                        else
                                        {
                                                foreach (const GlyphLayout& gl, current.glyphs[currentIndex].glyphs())
                                                        realAsce = qMax(realAsce, font.glyphBBox(gl.glyph, hlcsize10).ascent * scaleV + offset);
                                        }
                                }
                        }
//                      if (BulNumMode)
//                              hl->glyph.last()->xadvance += style.parEffectOffset();
                        //check for Y position at beginning of line
                        if (current.isEmpty && !current.afterOverflow)
                        {
                                if (current.recalculateY)
                                {
                                        //if top of column Y position depends on first line offset
                                        if (current.startOfCol)
                                        {
                                                lastLineY = qMax(lastLineY, m_textDistanceMargins.top() + lineCorr);
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing || FlopBaseline)
                                                {
                                                        if (current.yPos <= lastLineY)
                                                                current.yPos = lastLineY +1;
                                                        double by = m_yPos;
                                                        if (OwnPage != -1)
                                                                by = m_yPos - m_Doc->Pages->at(OwnPage)->yOffset();
                                                        int ol1 = qRound((by + current.yPos - m_Doc->guidesPrefs().offsetBaselineGrid) * 10000.0);
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->guidesPrefs().valueBaselineGrid);
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->guidesPrefs().valueBaselineGrid + m_Doc->guidesPrefs().offsetBaselineGrid - by;
                                                }
                                                else if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
                                                {
                                                        if (firstLineOffset() == FLOPRealGlyphHeight)
                                                        {
                                                                if (DropCmode || (itemText.text(a) == SpecialChars::PARSEP))
                                                                        current.yPos += asce;
                                                                else
                                                                        current.yPos += realAsce;
                                                        }
                                                        else if (firstLineOffset() == FLOPLineSpacing)
                                                                current.yPos += style.lineSpacing();
                                                        else
                                                                current.yPos += asce;
                                                }
                                        }
                                        else
                                        {
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
                                                {
                                                        current.yPos += m_Doc->guidesPrefs().valueBaselineGrid;
                                                        double by = m_yPos;
                                                        if (OwnPage != -1)
                                                                by = m_yPos - m_Doc->Pages->at(OwnPage)->yOffset();
                                                        int ol1 = qRound((by + current.yPos - m_Doc->guidesPrefs().offsetBaselineGrid) * 10000.0);
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->guidesPrefs().valueBaselineGrid);
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->guidesPrefs().valueBaselineGrid + m_Doc->guidesPrefs().offsetBaselineGrid - by;
                                                }
                                                else
                                                        current.yPos += style.lineSpacing();
                                        }
                                        if (DropCmode)
                                                current.yPos += DropCapDrop;
                                }
                                //set left indentation
                                current.leftIndent = 0.0;
                                if (current.addLeftIndent && ((maxDX == 0) || DropCmode || BulNumMode))
                                {
                                        current.leftIndent = style.leftMargin() + autoLeftIndent;
                                        if (itemText.isBlockStart(a))
                                        {
                                                current.leftIndent += style.firstIndent();
                                                if (BulNumMode || DropCmode)
                                                {
                                                        if (style.parEffectIndent())
                                                        {
                                                                current.leftIndent -= style.parEffectOffset() + wide;
                                                                if (current.leftIndent < 0.0)
                                                                {
                                                                        autoLeftIndent = abs(current.leftIndent);
                                                                        current.leftIndent = 0.0;
                                                                }
                                                        }
                                                }
                                        }
                                        current.addLeftIndent = false;
                                }
                        }
                        current.recalculateY = true;
                        maxYAsc = 0.0, maxYDesc = 0.0;
                        double addAsce = 0.0;
                        if (current.startOfCol)
                        {
                                if (DropCmode)
                                        addAsce = qMax(realAsce, asce + offset);
                                else
                                        addAsce = asce + offset;
                                if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
                                {
                                        if (firstLineOffset() == FLOPRealGlyphHeight)
                                                addAsce = realAsce;
                                        else if (firstLineOffset() == FLOPLineSpacing)
                                                addAsce = style.lineSpacing();
                                }
                                maxYAsc = current.yPos - addAsce;
                        }
                        else
                                maxYAsc = current.yPos - realAsce;
                        //fix for glyphs with negative realAsce value
                        maxYAsc = qMax(maxYAsc, 0.0);
                        maxYDesc = current.yPos + realDesc;

                        if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
                        {
                                regionMinY = static_cast<int>(floor(maxYAsc));
                                regionMaxY = static_cast<int>(floor(maxYDesc));
                        }
                        else // #11727, #11628, etc.
                        {
                                regionMinY = static_cast<int>(qMax(0.0, floor(current.yPos - (asce + offset))));
                                regionMaxY = static_cast<int>(floor(current.yPos + desc));
                        }

                        if (current.isEmpty && !current.afterOverflow)
                        {
                                //start a new line
                                goNoRoom = false;

                                // find line`s start
                                pt1 = QPoint(static_cast<int>(floor(current.xPos)), regionMinY);
                                pt2 = QPoint(static_cast<int>(floor(current.xPos + (style.minGlyphExtension() * wide))), regionMaxY -1);
                                pt = QRect(pt1, pt2);
                                realEnd = 0;
                                //check if there is overflow at start of line, if so jump behind it and check again
                                double Xpos, Xend;
                                bool done = false;
                                bool newColumn = false;

                                //FIX ME - that should be paragraph style`s properties
                                //if set then indent is add to possible line start point (after overflow)
                                //if not then indent is calculated from column left edge
                                //if you don't agree that adding indent to overflow should be default behaviour
                                //then change it to false
                                bool addIndent2overflow = false; // should be addIndent2Overflow = style.addIndent2Overlow();
                                bool addFirstIndent2overflow = true; // should be addFirstIndent2Overflow = style.addFirstIndent2Overlow();
                                //if first line indent is negative and left indent should not be added to overflow
                                //then don't add first line ident either
                                if ((style.firstIndent() < 0) && !addIndent2overflow)
                                        addFirstIndent2overflow = false;

                                while (!done)
                                {
                                        Xpos = current.xPos + (addIndent2overflow ? 0 : current.leftIndent);
                                        Xend = current.xPos + current.leftIndent;
                                        //check if in indent any overflow occurs
                                        while (Xpos <= Xend && Xpos < current.colRight)
                                        {
                                                pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)), regionMinY));
                                                if (!regionContainsRect(m_availableRegion, pt))
                                                {
                                                        Xpos = current.xPos = realEnd = findRealOverflowEnd(m_availableRegion, pt, current.colRight);
                                                        Xend = current.xPos + (addIndent2overflow ? current.leftIndent : 0);
                                                        //for first paragraph`s line - if first line offset should be added
                                                        if ( addFirstIndent2overflow && itemText.isBlockStart(a))
                                                                Xend += style.firstIndent();
                                                }
                                                else
                                                        Xpos++;
                                        }
                                        current.xPos = Xend;
                                        done = true;
                                        if (current.isEndOfLine((style.minGlyphExtension() * wide) + current.rightMargin))
                                        {
                                                // new line
                                                current.xPos = qMax(current.colLeft, maxDX);
                                                if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing || FlopBaseline)
                                                {
                                                        current.yPos++;
                                                        double by = m_yPos;
                                                        if (OwnPage != -1)
                                                                by = m_yPos - m_Doc->Pages->at(OwnPage)->yOffset();
                                                        int ol1 = qRound((by + current.yPos - m_Doc->guidesPrefs().offsetBaselineGrid) * 10000.0);
                                                        int ol2 = static_cast<int>(ol1 / m_Doc->guidesPrefs().valueBaselineGrid);
                                                        current.yPos = ceil(  ol2 / 10000.0 ) * m_Doc->guidesPrefs().valueBaselineGrid + m_Doc->guidesPrefs().offsetBaselineGrid - by;
                                                }
                                                else if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing)
                                                        current.yPos += (current.startOfCol ? 1 : style.lineSpacing());
                                                else
                                                        current.yPos += (current.startOfCol ? 1 : style.lineSpacing());
                                                lastLineY = maxYAsc;
                                                if (current.startOfCol)
                                                {
//                                                      double addAsce;
//                                                      if (DropCmode)
//                                                              addAsce = qMax(realAsce, asce + offset);
//                                                      else
//                                                              addAsce = asce + offset;
//                                                      if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
//                                                      {
//                                                              if (firstLineOffset() == FLOPRealGlyphHeight)
//                                                                      addAsce = realAsce;
//                                                              else if (firstLineOffset() == FLOPLineSpacing)
//                                                                      addAsce = style.lineSpacing() + offset;
//                                                      }
                                                        maxYAsc = current.yPos - addAsce;
                                                }
                                                else
                                                        maxYAsc = current.yPos - realAsce;
                                                maxYDesc = current.yPos + realDesc;

                                                if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
                                                {
                                                        regionMinY = static_cast<int>(floor(maxYAsc));
                                                        regionMaxY = static_cast<int>(floor(maxYDesc));
                                                }
                                                else // #11727, #11628, etc.
                                                {
                                                        regionMinY = static_cast<int>(qMax(0.0, floor(current.yPos - (asce + offset))));
                                                        regionMaxY = static_cast<int>(floor(current.yPos + desc));
                                                }

                                                pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)), regionMinY));
                                                done = false;
                                        }
                                        if (current.isEndOfCol(realDesc))
                                        {
                                                current.column++;
                                                if (current.column < Cols)
                                                {
                                                        newColumn = true;
                                                        break;
                                                }
                                                else
                                                {
                                                        MaxChars = a;
                                                        goto NoRoom;
                                                }
                                        }
                                }
                                if (newColumn)
                                {
                                        current.nextColumn(textLayout);
                                        current.mustLineEnd = current.colRight;
                                        current.restartX = current.xPos;
                                        lastLineY = current.yPos;
                                        current.rowDesc = 0;
                                        i--;
                                        current.recalculateY = true;
                                        current.addLeftIndent = true;
                                        continue;
                                }
                                current.lineData.x = current.restartX = current.xPos;
                                current.lineData.y = current.yPos;
//                              if (glyphClusters[current.line.firstCluster].hasFlag(ScLayout_DropCap))
//                                      current.line.y -= DropCapDrop;
                        }

                        //check if line must start at new Y position due to current glyph height or previous line descent
                        if (!SpecialChars::isBreak(itemText.text(a), true)
                                && !SpecialChars::isBreakingSpace(itemText.text(a))
                                && !SpecialChars::isExpandingSpace(itemText.text(a))
                                && itemText.text(a) != SpecialChars::TAB)
                        {
                                double diff = 0;
                                if (current.startOfCol || DropCmode)
                                        diff = realAsce - (current.yPos - lastLineY);
                                else if (style.lineSpacingMode() != ParagraphStyle::FixedLineSpacing)
                                {
                                        if (HasObject)
                                        //      diff = (currentObject->height() + currentObject->lineWidth()) * scaleV + offset - (current.yPos - lastLineY);
                                                diff = (currentObjectBox.height() * scaleV + offset) - (current.yPos - lastLineY);
                                        else
                                        {
                                        //      Pre-boxes code equivalent below:
                                        //      int glyphID = font.char2CMap(QChar('l'));
                                        //      diff = font.glyphBBox(glyphID, hlcsize10).ascent * scaleV + offset - (current.yPos - lastLineY);
                                                diff = realAsce - (current.yPos - lastLineY);
                                        }
                                }
                                else
                                {
                                        if (HasObject)
                                        //      diff = (currentObject->height() + currentObject->lineWidth()) * scaleV + offset - (current.yPos - lastLineY);
                                                diff = currentObjectBox.height() * scaleV + offset - (current.yPos - lastLineY);
                                }
                                if (diff >= 1 || (!DropCmode && diff > 0))
                                {
                                        if (current.hasDropCap && DropLinesCount == 0)
                                        {
                                                current.hasDropCap = false;
                                                current.yPos = maxDY;
                                                maxDX = 0;
                                        }
                                        int linesDrop = 0;
                                        if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing || FlopBaseline)
                                        {
                                                linesDrop = ceil(diff / m_Doc->guidesPrefs().valueBaselineGrid);
                                                current.yPos += m_Doc->guidesPrefs().valueBaselineGrid * linesDrop;
                                                maxDX = 0;
                                        }
                                        else /*if (current.startOfCol)*/
                                        {
                                                //FIX ME - that is ugly hack I must made, because simply expression
                                                //current.yPos += diff; stop working, don't know why (compiler bug?)
                                                float YPOS = (float) current.yPos + (float) diff + 0.01;
                                                current.yPos = (double) YPOS;
                                                if (current.hasDropCap && diff > DropCapDrop)
                                                {
                                                        current.hasDropCap = false;
                                                }
                                        }
                                        if (current.hasDropCap && linesDrop > 0 && DropLinesCount > 1)
                                        {
                                                DropLinesCount += linesDrop;
                                                if (DropLinesCount >= DropLines)
                                                {
                                                        current.hasDropCap = false;
                                                        maxDX = 0;
                                                        maxDY = 0;
                                                }
                                        }
                                        i = current.restartRow(false);
                                        tabs.active = false;
                                        tabs.status = TabNONE;
                                        tabs.xPos   = 0.0;
                                        continue;
                                }
                        }
                        // right tab stuff
                        if (tabs.active)
                        {
                                if (((itemText.text(a) == '.') && (tabs.status == TabPOINT)) || ((itemText.text(a) == ',') && (tabs.status == TabCOMMA)) || (itemText.text(a) == SpecialChars::TAB))
                                {
                                        tabs.active = false;
                                        tabs.status = TabNONE;
                                }
                        }
                        // tab positioning
                        if (itemText.text(a) == SpecialChars::TAB)
                        {
                                wide = 1;
                                if (tabs.active)
                                        tabs.active = false;
                                else // ???
                                {
                                        tabs.xPos = current.xPos;
                                        tTabValues = style.tabValues();
                                        if (tTabValues.isEmpty())
                                        {
                                                current.xPos = nextAutoTab (current, this);
                                                tabs.status = TabNONE;
                                                tabs.active = false;
                                        }
                                        else
                                        {
                                                double tCurX = current.xPos;
                                                double oCurX = current.xPos - current.colLeft + wide;
                                                for (int yg = static_cast<int>(tTabValues.count()-1); yg > -1; yg--)
                                                {
                                                        if (oCurX < tTabValues.at(yg).tabPosition)
                                                        {
                                                                tabs.status = static_cast<int>(tTabValues.at(yg).tabType);
                                                                tabs.fillChar = tTabValues.at(yg).tabFillChar;
                                                                current.xPos = current.colLeft + tTabValues.at(yg).tabPosition;
                                                        }
                                                }
                                                tabs.active = (tabs.status != TabLEFT);
                                                if (current.xPos == tCurX)  // no more tabs found
                                                {
                                                        current.xPos = nextAutoTab (current, this);
                                                        tabs.status = TabNONE;
                                                        tabs.active = false;
                                                        tabs.fillChar = QChar();
                                                }

                                                // remember fill char
                                                if (!tabs.fillChar.isNull())
                                                {
                                                        current.glyphs[currentIndex].setFlag(ScLayout_TabLeaders);
                                                        GlyphLayout tglyph;
                                                        tglyph.glyph    = font.char2CMap(tabs.fillChar.unicode());
                                                        tglyph.scaleV   = tglyph.scaleH = chs / charStyle.fontSize();
                                                        tglyph.xadvance = 0;
                                                        current.glyphs[currentIndex].append(tglyph);
                                                }
                                        }
                                        current.xPos -= (legacy ? 1.0 : 0.0);
                                        GlyphLayout& firstGlyph = current.glyphs[currentIndex].glyphs().first();
                                        firstGlyph.xadvance = (current.xPos + wide - tabs.xPos) / firstGlyph.scaleH;
                                        tabs.tabGlyph = &firstGlyph;
                                }
                        }

                        // remember y pos
                        if (DropCmode)
                        {
                                double yoffset = 0.0;
                                foreach (const GlyphLayout& gl, current.glyphs[currentIndex].glyphs())
                                        yoffset = qMax(yoffset, font.glyphBBox(gl.glyph, chsd / 10.0).descent);
                                current.glyphs[currentIndex].yoffset -= yoffset;
                        }
                        // remember x pos
                        double breakPos = current.xPos;

                        if (!tabs.active) // normal case
                        {
                                current.xPos += wide;
                        }
                        else if (tabs.active && tabs.status == TabCENTER)       // center tab
                        {
                                current.xPos += wide / 2;
                                current.xPos = qMax(current.xPos, current.colLeft);
                        }
                        else // other tabs.active
                        {
                                current.xPos = qMax(current.xPos, current.colLeft);
                        }
                        // remember possible break
                        if (shapedText.haveMoreText(i + 1, glyphClusters))
                        {
                                const GlyphCluster& nextCluster = glyphClusters[i + 1];
                                if (nextCluster.hasFlag(ScLayout_LineBoundary))
                                {
                                        if (!current.glyphs[currentIndex].hasFlag(ScLayout_HyphenationPossible)
                                                && (itemText.text(a) != '-')
                                                && (itemText.text(a) != SpecialChars::SHYPHEN))
                                        {
                                                current.rememberBreak(i, breakPos, style.rightMargin());
                                        }
                                }
                        }
                        if (HasObject)
                        {
//                              qDebug() << "rememberBreak object @" << i;
                                current.rememberBreak(i, breakPos, style.rightMargin());
                        }

                        //check against space before PARSEP
                        /*if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP))
                        {
                                a++;
                                hl = itemText.item(a);
                        }*/


                        // test if end of line reached
                        double overflowWidth = 0.0;
                        double hyphWidth = 0.0;
                        bool inOverflow = false;
                        if (current.glyphs[currentIndex].hasFlag(ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
                                hyphWidth = font.hyphenWidth(charStyle, hlcsize10) * (charStyle.scaleH() / 1000.0);
                        if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(itemText.text(a), Cols > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd)
                        {
                                //end of row reached - right column, end of column, break char or line must end
                                if (current.isEmpty && !current.afterOverflow && !SpecialChars::isBreak(itemText.text(a), Cols > 1))
                                {
                                        //no glyphs in line, so start new row
                                        if (SpecialChars::isBreak(itemText.text(a), Cols > 1))
                                                current.restartRowIndex = i + 1;
                                        i = current.restartRow(true);
                                        inOverflow = false;
                                        outs = false;
                                        continue;
                                }
                                //there we have some glyphs
                                if (current.breakIndex < 0)
                                {
                                        //force break
                                        if (!SpecialChars::isBreak(itemText.text(a), Cols > 1))
                                        {
                                                //force line end at previouse glyph
                                                i--;
                                                currentIndex = i - current.lineData.firstCluster;
                                                a = (i >= 0) ? glyphClusters.at(i).firstChar() : (a - 1);
                                                current.mustLineEnd = current.lineData.x;
                                        }
//                                      qDebug() << "breakline forced @" << i;
                                        current.breakLine(i);
                                }
                                if (!current.addLine && !current.lastInRowLine && current.afterOverflow)
                                {
                                        //we reach right edge of column
                                        //if we are after overflow area we have to go back and try to insert text before it
                                        //if we have some text here - insert text WITHOUT right margin
                                        //if there is no place for text - insert text WITH right margin and end line
                                        current.lastInRowLine = false;
                                        if (current.lineData.firstCluster == current.restartIndex)
                                                current.lastInRowLine = true;
                                        if (current.hasDropCap && DropLinesCount == 0 && current.restartIndex == current.restartRowIndex)
                                        {
                                                current.hasDropCap = false;
                                                maxDX = 0;
                                                current.yPos = maxDY;
                                        }
                                        i = current.restartLine(false,true);
                                        outs = false;
                                        inOverflow = false;
                                        continue;
                                }
                                outs = true;

                                current.addLine = true;
                                current.lastInRowLine = true;
                                current.rightMargin = style.rightMargin();
                                if (current.isEndOfCol(realDesc))
                                        goNextColumn = true;
                        }
                        else
                        {
                                int charStart, charEnd;
                                if (current.isEmpty)
                                {
                                        charStart = static_cast<int>(floor(current.lineData.x));
                                        charEnd = static_cast<int>(ceil(current.xPos));
                                }
                                else
                                {
                                        charStart = static_cast<int>(qMax(floor(current.xPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0));
                                        charEnd = static_cast<int>(ceil(current.xPos - current.maxShrink));
                                }
                                if (legacy &&
                                                (((itemText.text(a) == '-' || current.glyphs[currentIndex].hasFlag(ScLayout_HyphenationPossible)) && (current.hyphenCount < style.hyphenConsecutiveLines() || style.hyphenConsecutiveLines() == 0))
                                                 || itemText.text(a) == SpecialChars::SHYPHEN))
                                {
                                        if (current.glyphs[currentIndex].hasFlag(ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
                                        {
                                                pt1 = QPoint(charStart,  regionMinY);
                                                pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), regionMaxY -1);
                                        }
                                        else
                                        {
                                                pt1 = QPoint(charStart, regionMinY);
                                                pt2 = QPoint(charEnd, regionMaxY -1);
                                        }
                                }
                                else if (!legacy && SpecialChars::isBreakingSpace(itemText.text(a)))
                                {
                                        pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), regionMinY);
                                        pt2 = QPoint(charEnd, regionMaxY -1);
                                }
                                else
                                {
                                        pt1 = QPoint(charStart, regionMinY);
                                        pt2 = QPoint(charEnd, regionMaxY -1);
                                }
                                pt = QRect(pt1, pt2);
                                if (!regionContainsRect(m_availableRegion, pt))
                                {
                                        realEnd = findRealOverflowEnd(m_availableRegion, pt, current.colRight);
                                        outs = true;
                                }
                                else if (style.rightMargin() > 0.0)
                                {
                                        if (current.lastInRowLine || current.xPos - current.maxShrink + style.rightMargin() > current.colRight - style.rightMargin())
                                                //condition after || is for find overflows in right margin area
                                        {
                                                pt.translate(static_cast<int>(ceil(style.rightMargin())), 0);
                                                if (!regionContainsRect(m_availableRegion, pt))
                                                {
                                                        realEnd = findRealOverflowEnd(m_availableRegion, pt, current.colRight);
                                                        outs = true;
                                                }
                                        }
                                }
                                if (outs)
                                {
                                        if (current.isEmpty)
                                        {
                                                current.lineData.x = current.xPos = realEnd;
                                                i--;
                                                current.startLine(i+1);
                                                if (!current.wasFirstInRow)
                                                        current.addLeftIndent = true;
                                                if (current.hasDropCap && DropLinesCount == 0 && !current.afterOverflow)
                                                {
                                                        current.hasDropCap = false;
                                                        current.yPos = maxDY;
                                                }
                                                current.recalculateY = false;
                                                outs = false;
                                                continue;
                                        }
                                        if (current.breakIndex < 0)
                                        {
                                                i--;
//                                              qDebug() << "forced break at glyph" << i;
                                                currentIndex = i - current.lineData.firstCluster;
                                                a = current.glyphs[currentIndex].firstChar();
                                                current.breakLine(i);
                                        }
                                        //check if after overflow text can be placed
                                        overflowWidth = realEnd - (current.xPos - current.maxShrink);
                                        double newXAdd = overflowWidth - style.rightMargin() + style.minGlyphExtension() * wide + hyphWidth;
                                        if (current.isEndOfLine(newXAdd) || current.xPos + newXAdd >= current.colRight || realEnd >= current.mustLineEnd)
                                        {
                                                if (!current.afterOverflow)
                                                {
                                                        current.addLine = true;
                                                        current.lastInRowLine = true;
                                                }
                                                //line must end before overflov
                                                if (!current.addLine && !current.lastInRowLine)
                                                {
                                                        if (current.afterOverflow)
                                                        {
                                                                if (current.breakIndex < 0)
                                                                {
                                                                        current.lastInRowLine = true;
                                                                        current.mustLineEnd = current.lineData.x;
                                                                }
                                                                else if (current.lineData.firstCluster == current.restartIndex)
                                                                        current.lastInRowLine = true;
                                                        }
                                                        else
                                                                current.lastInRowLine = true;
                                                        if (current.hasDropCap && DropLinesCount == 0)
                                                        {
                                                                current.hasDropCap = false;
                                                                maxDX = 0;
                                                        }
                                                        i = current.restartLine(false, true);
                                                        inOverflow = false;
                                                        outs = false;
                                                        continue;
                                                }
                                                current.addLine = true;
                                                current.rightMargin = style.rightMargin();
                                                current.lastInRowLine = true;
                                        }
                                        else
                                                inOverflow = true;
                                }
                                else
                                        setMaxY(maxYDesc);
                        }

                        // hyphenation
                        if ((current.glyphs[currentIndex].hasFlag(ScLayout_HyphenationPossible)
                                  || itemText.text(a) == '-'
                                  || itemText.text(a) == SpecialChars::SHYPHEN)
                                 && (!outs) && ((i == 0) || !itemText.text(glyphClusters[i - 1].lastChar()).isSpace()) )
                        {
                                breakPos = current.xPos;
                                if (itemText.text(a) != '-')
                                {
                                        breakPos += hyphWidth;
                                }

                                double rightHang = 0;
                                if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) {
                                        rightHang = 0.7 * hyphWidth;
                                }

                                if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin()))
                                {
                                        if ((current.hyphenCount < style.hyphenConsecutiveLines()) || (style.hyphenConsecutiveLines() == 0) || itemText.text(a) == SpecialChars::SHYPHEN)
                                        {
//                                              qDebug() << "rememberBreak hyphen @" << i;
                                                current.rememberBreak(i, breakPos, style.rightMargin() + hyphWidth);
                                        }
                                }
                        }

                        if ((itemText.text(a) == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1))
                                goNoRoom = true;
                        if ((itemText.text(a) == SpecialChars::COLBREAK) && (Cols > 1))
                                goNextColumn = true;

                        if (i != 0 && implicitBreak(itemText.text(glyphClusters[i - 1].lastChar()), itemText.text(current.glyphs[currentIndex].firstChar())))
                        {
//                              qDebug() << "rememberBreak implicitbreak @" << i-1;
                                current.rememberBreak(i - 1, breakPos);
                        }
                        current.isEmpty = (i - current.lineData.firstCluster + 1) == 0;

                        if (tabs.active)
                        {
                                double cen = 1;
                                if (tabs.status == TabCENTER)
                                        cen = 2;

                                double newTabAdvance = tabs.tabGlyph->xadvance;
                                newTabAdvance -= wide / cen / tabs.tabGlyph->scaleH;

                                if (newTabAdvance >= 0) {
                                        tabs.tabGlyph->xadvance = newTabAdvance;
                                }
                                else {
                                        tabs.active = false;
                                        tabs.status = TabNONE;
                                }
                        }
                        if ((DropCmode || BulNumMode) && !outs)
                        {
                                current.xPos += style.parEffectOffset();
                                if (style.hasNum())
                                {
                                        // make sure that Offset inserted only after the suffix
                                        // loop over previous current.glyphs and set their extraWidth to 0.0
                                        for (int j = 0; j < current.glyphs.size(); j++)
                                        {
                                                if (j != currentIndex)
                                                        current.glyphs[j].extraWidth = 0.0;
                                        }
                                }
                                // set the offset for Drop Cap, Bullet & Number List
                                current.glyphs[currentIndex].extraWidth += style.parEffectOffset();

                                if (DropCmode)
                                {
                                        DropCmode = false;
                                        DropLinesCount = 0;
                                        maxDY = current.yPos;
                                        current.hasDropCap = true;
                                        maxDX = current.xPos;
                                        double spacing = calculateLineSpacing (style, this);
                                        current.yPos -= spacing * (DropLines-1);
                                        if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
                                                current.yPos = adjustToBaselineGrid (current, this, OwnPage);
                                        current.recalculateY = false;
                                }
                        }
                        // end of line
                        if (outs)
                        {
                                tabs.active = false;
                                tabs.status = TabNONE;
                                tabs.xPos   = 0.0;
                                if (SpecialChars::isBreak(itemText.text(a), Cols > 1))
                                {
                                        // find end of line
//                                      qDebug() << "breakline isBreak @" << i;
                                        current.breakLine(i);
                                        regionMinY = qMax(0.0, current.lineData.y - current.lineData.ascent);
                                        regionMaxY = current.lineData.y + current.lineData.descent;
                                        EndX = current.endOfLine(m_availableRegion, style.rightMargin(), regionMinY, regionMaxY);
                                        current.finishLine(EndX);
                                        //addLine = true;
                                        assert(current.addLine);
                                        //current.startOfCol = false;
                                        //addLeftIndent = true;
                                        if (itemText.isBlockStart(a+1))
                                        {
                                                maxDX = 0;
                                                if (current.hasDropCap)
                                                {
                                                        current.yPos = maxDY;
                                                        maxDY = 0;
                                                        current.hasDropCap = false;
                                                }
                                        }

//                                      if (style.alignment() != 0)
                                        {
                                                if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
                                                        current.lineData.width += current.opticalRightMargin(itemText);

                                                OFs = 0;
                                                if (style.alignment() == ParagraphStyle::Rightaligned)
                                                        OFs = current.lineData.width - current.lineData.naturalWidth;
                                                if (style.alignment() == ParagraphStyle::Centered)
                                                        OFs = (current.lineData.width - current.lineData.naturalWidth) / 2;
                                                if (style.alignment() == ParagraphStyle::Justified ||
                                                        style.alignment() == ParagraphStyle::Extended)
                                                {
                                                        if (style.direction() == ParagraphStyle::RTL)
                                                                OFs = current.lineData.width - current.lineData.naturalWidth;
                                                        else
                                                                OFs = 0;
                                                }

                                                if (style.alignment() == ParagraphStyle::Extended
                                                        || (style.alignment() == ParagraphStyle::Justified
                                                                &&  (itemText.text(a) == SpecialChars::LINEBREAK ||
                                                                         itemText.text(a) == SpecialChars::FRAMEBREAK ||
                                                                         itemText.text(a) == SpecialChars::COLBREAK)
                                                                &&  (current.lineData.lastCluster - 1 >= 0)
                                                                &&  !itemText.text(glyphClusters[current.lineData.lastCluster - 1].lastChar()).isSpace()))
                                                {
                                                        current.justifyLine(style);
                                                }
                                                else
                                                {
                                                        if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
                                                                current.lineData.naturalWidth += current.opticalRightMargin(itemText);
                                                        double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.lineData.x;
                                                        if (current.lineData.naturalWidth > optiWidth)
                                                                current.lineData.width = qMax(current.lineData.width - current.maxShrink, optiWidth);
                                                        // simple offset
                                                        current.indentLine(style, OFs);
                                                }
                                                current.xPos = current.colRight;
                                        }
                                }
                                else // outs -- last char went outside the columns (or into flow-around shape)
                                {
                                        if (current.breakIndex >= 0)
                                        {
                                                // go back to last break position
                                                i = current.breakIndex;
                                                a = glyphClusters.at(i).firstChar();
                                                currentIndex = i - current.lineData.firstCluster;
                                                style = itemText.paragraphStyle(a);
                                                const_cast<ScFace&>(font) = itemText.charStyle(a).font();
                                                if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
                                                        style.setLineSpacing(font.height(hlcsize10) * autoLS);
                                                else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
                                                        style.setLineSpacing(m_Doc->guidesPrefs().valueBaselineGrid);
                                                charStyle = itemText.charStyle(a);
                                        }
                                        assert( i >= 0 );
                                        assert( i < glyphClusters.length() );
                                        //glyphs = itemText.getGlyphs(a);
                                        current.isEmpty = (i - current.lineData.firstCluster + 1) == 0;
                                        if (current.addLine && !current.isEmpty)
                                        {
                                                if (itemText.text(a) == ' ') {
                                                        current.glyphs[currentIndex].setFlag(ScLayout_SuppressSpace);
                                                }

                                                current.updateHeightMetrics();
                                                //current.updateLineOffset(itemText, style, firstLineOffset());
                                                //current.xPos = current.breakXPos;
                                                EndX = current.endOfLine(m_availableRegion, current.rightMargin, regionMinY, regionMaxY);
                                                current.finishLine(EndX);

                                                hyphWidth = 0.0;
                                                if (current.glyphs[currentIndex].hasFlag(ScLayout_HyphenationPossible) || itemText.text(a) == SpecialChars::SHYPHEN)
                                                {
                                                        // insert hyphen
                                                        if (current.lastInRowLine)
                                                                //increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow
                                                                current.hyphenCount++;
                                                        current.glyphs[currentIndex].setFlag(ScLayout_SoftHyphenVisible);
                                                        GlyphLayout hyphen;
                                                        hyphen.glyph = font.hyphenGlyph(charStyle);
                                                        hyphen.xadvance = font.hyphenWidth(charStyle, charStyle.fontSize() / 10.0);
                                                        hyphWidth = hyphen.xadvance * scaleH;
                                                        current.glyphs[currentIndex].append(hyphen);
                                                }
                                                else
                                                {
                                                        if (itemText.text(a) != '-')
                                                                current.hyphenCount = 0;
                                                        if (current.glyphs[currentIndex].hasFlag(ScLayout_SoftHyphenVisible))
                                                        {
                                                                current.glyphs[currentIndex].clearFlag(ScLayout_SoftHyphenVisible);
                                                                current.glyphs[currentIndex].glyphs().removeLast();
                                                        }
                                                }

                                                // Justification
                                                if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
                                                        current.lineData.width += current.opticalRightMargin(itemText);
                                                // #12565: Right alignment of hyphens
                                                // The additional character width has already been taken into account
                                                // above via the line break position, so it's not necessary to increase
                                                // the line natural width again:
                                                // line 2604: breakPos = current.xPos;
                                                // line 2605: if (currentCh != '-')
                                                // line 2606: {
                                                // line 2607:   breakPos += hyphWidth;
                                                // line 2608: }
                                                /*else
                                                        current.line.naturalWidth += hyphWidth;*/


                                                OFs = 0;
                                                if (style.alignment() == ParagraphStyle::Rightaligned)
                                                        OFs = current.lineData.width - current.lineData.naturalWidth;
                                                if (style.alignment() == ParagraphStyle::Centered)
                                                        OFs = (current.lineData.width - current.lineData.naturalWidth) / 2;
                                                if (style.alignment() == ParagraphStyle::Justified && style.direction() == ParagraphStyle::RTL)
                                                        OFs = current.lineData.width - current.lineData.naturalWidth;

                                                if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended))
                                                        current.justifyLine(style);
                                                else
                                                {
                                                        if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
                                                                current.lineData.naturalWidth += current.opticalRightMargin(itemText);
                                                        current.indentLine(style, OFs);
                                                }
                                                current.xPos = current.lineData.x + current.lineData.width;
                                        }
                                }
                                if (inOverflow)
                                        current.xPos = realEnd;

                                // line break and drop caps
                                // #11250: in case of a forced line break, we must not stop
                                // the drop cap layout process. This break case such as
                                // layout of poetry.
                                if (itemText.isBlockStart(a+1) && current.hasDropCap)
                                {
                                        current.hasDropCap = false;
                                        if (current.yPos < maxDY)
                                                current.yPos = maxDY;
                                        maxDX = 0;
                                }
                                // end of column
                                if (current.isEndOfCol(desc))
                                {
                                        //check if really line extends bottom margin
                                        current.updateHeightMetrics();
                                        if (current.isEndOfCol(current.lineData.descent))
                                        {
                                                if (current.isEmpty || current.column+1 == Cols)
                                                {
                                                        goNoRoom = true;
                                                        MaxChars = a + 1;
                                                        break;
                                                }
                                                goNextColumn = true;
                                        }
                                        else
                                                setMaxY(maxYDesc);
                                }
                                else
                                        setMaxY(maxYDesc);
                                if (current.lineData.firstCluster <= current.lineData.lastCluster && !current.isEmpty)
                                {
                                        if (current.addLine && current.breakIndex >= 0)
                                        {
                                                if (current.glyphs[0].hasFlag(ScLayout_DropCap))
                                                {
                                                        // put line back to top
                                                        current.lineData.y -= DropCapDrop;
                                                        current.glyphs[0].yoffset += DropCapDrop;
                                                }
                                                current.fillInTabLeaders();
                                                //if right margin is set we temporally save line, not append it
                                                textLayout.appendLine(current.createLineBox());
                                                setMaxY(maxYDesc);
                                                current.restartIndex = current.lineData.lastCluster + 1;
                                                i = current.lineData.lastCluster;
                                                currentIndex = i - current.lineData.firstCluster;
                                                a = current.glyphs[currentIndex].firstChar();
                                                current.rowDesc = qMax(current.rowDesc,current.yPos + current.lineData.descent);
                                        //      if (glyphClusters[current.line.firstCluster].hasFlag(ScLayout_DropCap))
                                        //              current.rowDesc = qMax(current.rowDesc,current.yPos + current.line.descent);
                                        //      else
                                                        current.rowDesc = qMax(current.rowDesc,current.yPos - current.lineData.descent);
                                                if (!current.lastInRowLine)
                                                {
                                                        current.restartX = current.xPos;
                                                        if (current.addLeftIndent)
                                                        {
                                                                current.addLeftIndent = false;
                                                                current.wasFirstInRow = true;
                                                        }
                                                }
                                        }
                                        else if (!inOverflow && !current.afterOverflow && current.lastInRowLine)
                                        {
                                                current.yPos++;
                                                i = current.restartLine(true, true);
                                                inOverflow = false;
                                                outs = false;
                                                current.mustLineEnd = current.colRight;
                                                continue;
                                        }
                                }
                                if (current.addLine && current.lastInRowLine)
                                {
                                        current.recalculateY = true;
                                        current.wasFirstInRow = false;
                                        current.addLeftIndent = true;
                                        inOverflow = false;
                                        outs = false;
                                        current.startOfCol = false;
                                        current.restartX = current.xPos = qMax(maxDX, current.colLeft);
                                        lastLineY = current.rowDesc;
                                        if (current.hasDropCap)
                                        {
                                                ++DropLinesCount;
                                                if (DropLinesCount >= DropLines)
                                                {
                                                        current.hasDropCap = false;
                                                        current.restartX = current.xPos = current.colLeft;
                                                        maxDX = 0;
                                                }
                                        }
                                        lastLineY = current.rowDesc;
                                        current.mustLineEnd = current.colRight;
                                        current.restartRowIndex = current.restartIndex;
                                }
                                if ( SpecialChars::isBreak(itemText.text(a)) )
                                {
                                        if (itemText.isBlockStart(a+1))
                                                current.yPos += style.gapAfter();
                                        current.hyphenCount = 0;
                                }
                                if (inOverflow)
                                {
                                        current.afterOverflow = true;
                                        inOverflow = false;
                                        current.addLeftIndent = false;
                                        current.recalculateY = false;
                                }
                                else
                                {
                                        current.afterOverflow = false;
                                }
                                outs = false;
                                current.addLine = false;
                                current.lastInRowLine = false;
                                // WTF does i+1 mean here, what if i is the last run we have!
                                current.startLine(i+1);
                                if (goNoRoom)
                                {
                                        goNoRoom = false;
                                        MaxChars = a+1;
                                        goto NoRoom;
                                }
                                if (goNextColumn)
                                {
                                        goNextColumn = false;
                                        current.column++;
                                        if (current.column < Cols)
                                        {
                                                if (firstLineOffset() == FLOPRealGlyphHeight)
                                                        asce = 0;
                                                current.nextColumn(textLayout);
                                                current.mustLineEnd = current.colRight;
                                                current.addLeftIndent = true;
                                                lastLineY = m_textDistanceMargins.top();
                                                current.rowDesc = 0;
                                                current.recalculateY = true;
                                        }
                                        else
                                        {
                                                MaxChars = a; // Always a+1???
                                                if (itemText.text(a) == SpecialChars::COLBREAK)
                                                        ++MaxChars;
                                                goto NoRoom;
                                        }
                                }
                        }
                        if (!shapedText.haveMoreText(i + 1, glyphClusters))
                        {
                                if (!current.afterOverflow || current.addLine)
                                {
                                        current.addLine = true;
                                        current.lastInRowLine = true;
//                                      qDebug() << "breakline A no more text @" << i;
                                        current.breakLine(i);
                                }
                                if (current.afterOverflow && !current.addLine)
                                {
                                        if (current.restartIndex < current.lineData.firstCluster)
                                        {
                                                i = current.restartLine(false,true);
                                                continue;
                                        }
                                        else
                                        {
//                                              qDebug() << "breakline B no more text @" << i;
                                                current.breakLine(i);
                                        }
                                }
                        }
                }
                if (goNoRoom)
                {
                        goNoRoom = false;
                        goto NoRoom;
                }
// end of itemText
// now place the last line
                if (!current.isEmpty)
                {
                        int a = itemText.length()-1;
                        int i = glyphClusters.length() - 1;
//                      qDebug() << "breakline end of text @" << i;
                        current.breakLine(i);

                        if (current.startOfCol)
                        {
                                double addAsce;
                                if (DropCmode)
                                        addAsce = qMax(realAsce, asce + offset);
                                else
                                        addAsce = asce + offset;
                                if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)
                                {
                                        if (firstLineOffset() == FLOPRealGlyphHeight)
                                                addAsce = realAsce;
                                        else if (firstLineOffset() == FLOPLineSpacing)
                                                addAsce = style.lineSpacing() + offset;
                                }
                                maxYAsc = current.yPos - addAsce;
                        }
                        else
                                maxYAsc = current.yPos - realAsce;
                        //fix for glyphs with negative realAsce value
                        maxYAsc = qMax(maxYAsc, 0.0);
                        maxYDesc = current.yPos + realDesc;

                        if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
                        {
                                regionMinY = static_cast<int>(floor(maxYAsc));
                                regionMaxY = static_cast<int>(floor(maxYDesc));
                        }
                        else // #11727, #11628, etc.
                        {
                                regionMinY = static_cast<int>(qMax(0.0, floor(current.yPos - (realAsce + offset))));
                                regionMaxY = static_cast<int>(floor(current.yPos + realDesc));
                        }

                        EndX = current.endOfLine(m_availableRegion, style.rightMargin(), regionMinY, regionMaxY);
                        current.finishLine(EndX);

                        if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
                                current.lineData.width += current.opticalRightMargin(itemText);

                        OFs = 0;
                        if (style.alignment() == ParagraphStyle::Rightaligned)
                                OFs = current.lineData.width - current.lineData.naturalWidth;
                        if (style.alignment() == ParagraphStyle::Centered)
                                OFs = (current.lineData.width - current.lineData.naturalWidth) / 2;
                        if (style.alignment() == ParagraphStyle::Justified ||
                                style.alignment() == ParagraphStyle::Extended)
                        {
                                if (style.direction() == ParagraphStyle::RTL)
                                        OFs = current.lineData.width - current.lineData.naturalWidth;
                                else
                                        OFs = 0;
                        }

                        if (style.alignment() == ParagraphStyle::Extended
                                || (style.alignment() == ParagraphStyle::Justified
                                        &&  (itemText.text(a) == SpecialChars::LINEBREAK ||
                                                 itemText.text(a) == SpecialChars::FRAMEBREAK ||
                                                 itemText.text(a) == SpecialChars::COLBREAK)
                                        &&  !itemText.text(a).isSpace()))
                        {
                                current.justifyLine(style);
                        }
                        else
                        {
                                if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
                                        current.lineData.naturalWidth += current.opticalRightMargin(itemText);
                                current.indentLine(style, OFs);
                        }
                        if (current.glyphs[0].hasFlag(ScLayout_DropCap))
                        {
                                // put line back to top
                                current.lineData.y -= DropCapDrop;
                                current.glyphs[0].yoffset += DropCapDrop;
                        }
                        current.fillInTabLeaders();
                        current.startOfCol = false;
                        goNextColumn = false;

                        textLayout.appendLine(current.createLineBox());
                        setMaxY(maxYDesc);
                        current.startOfCol = false;

                        if (moveLinesFromPreviousFrame ()) {
                                layout ();  // line moving ensures that this won't be an endless loop
                                itemText.blockSignals(false);
                                return;
                        }
                }
        }
        MaxChars = itemText.length();
        if (verticalAlign > 0)
        {
                double hAdjust = height() - textLayout.box()->naturalHeight() - m_textDistanceMargins.bottom();
                if (hAdjust > 0)
                {
                        if (verticalAlign == 1)
                                hAdjust /= 2;
                        if (FrameType == 0) // Rectangular frame
                                textLayout.box()->moveBy(0, hAdjust);
                        else
                        {
                                int vertAlign = verticalAlign;
                                double topDist = m_textDistanceMargins.top();
                                m_textDistanceMargins.setTop(topDist + hAdjust);
                                verticalAlign = 0;
                                layout();
                                verticalAlign = vertAlign;
                                m_textDistanceMargins.setTop(topDist);
                        }
                }
        }
        invalid = false;
        if (!isNoteFrame() && (!m_Doc->notesList().isEmpty() || m_Doc->notesChanged()))
        { //if notes are used
                UndoManager::instance()->setUndoEnabled(false);
                NotesInFrameMap notesMap = updateNotesFrames(noteMarksPosMap);
                if (notesMap != m_notesFramesMap)
                {
                        updateNotesMarks(notesMap);
                        notesFramesLayout();
                }
                UndoManager::instance()->setUndoEnabled(true);
        }
        if (NextBox != NULL)
        {
                PageItem_TextFrame * nextFrame = dynamic_cast<PageItem_TextFrame*>(NextBox);
                while (nextFrame)
                {
                        nextFrame->invalid   = true;
                        nextFrame->firstChar = MaxChars;
                        nextFrame = dynamic_cast<PageItem_TextFrame*>(nextFrame->NextBox);
                }
        }
        itemText.blockSignals(false);
//      qDebug("textframe: len=%d, done relayout", itemText.length());
        return;

NoRoom:
        invalid = false;
       
        adjustParagraphEndings ();

        if (verticalAlign > 0)
        {
                double hAdjust = height() - textLayout.box()->naturalHeight() - m_textDistanceMargins.bottom();
                if (hAdjust > 0)
                {
                        if (verticalAlign == 1)
                                hAdjust /= 2;
                        if (FrameType == 0) // Rectangular frame
                                textLayout.box()->moveBy(0, hAdjust);
                        else
                        {
                                int vertAlign = verticalAlign;
                                double topDist = m_textDistanceMargins.top();
                                m_textDistanceMargins.setTop(topDist + hAdjust);
                                verticalAlign = 0;
                                layout();
                                verticalAlign = vertAlign;
                                m_textDistanceMargins.setTop(topDist);
                        }
                }
        }

        if (!isNoteFrame() && (!m_Doc->notesList().isEmpty() || m_Doc->notesChanged()))
        {
                UndoManager::instance()->setUndoEnabled(false);
                NotesInFrameMap notesMap = updateNotesFrames(noteMarksPosMap);
                if (notesMap != m_notesFramesMap)
                {
                        updateNotesMarks(notesMap);
                        notesFramesLayout();
                }
                UndoManager::instance()->setUndoEnabled(true);
        }

        PageItem_TextFrame * next = dynamic_cast<PageItem_TextFrame*>(NextBox);
        if (next != NULL)
        {
                if (itemText.cursorPosition() > signed(MaxChars))
                {
                        int nCP = itemText.cursorPosition();
                        if (m_Doc->appMode == modeEdit)
                                next->itemText.setCursorPosition( qMax(nCP, signed(MaxChars)) );
                }
                while (next)
                {
                        next->invalid   = true;
                        next->firstChar = MaxChars;
                        next = dynamic_cast<PageItem_TextFrame*>(next->NextBox);
                }
        }
//      qDebug("textframe: len=%d, done relayout (no room %d)", itemText.length(), MaxChars);
        itemText.blockSignals(false);
}

void PageItem_TextFrame::invalidateLayout(bool wholeChain)
{
        //const bool wholeChain = true;
        invalid = true;
        if (wholeChain)
        {
                PageItem *prevFrame = this->prevInChain();
                while (prevFrame != 0)
                {
                        prevFrame->invalid = true;
                        prevFrame = prevFrame->prevInChain();
                }
                PageItem *nextFrame = this->nextInChain();
                while (nextFrame != 0)
                {
                        nextFrame->invalid = true;
                        nextFrame = nextFrame->nextInChain();
                }
        }
}

void PageItem_TextFrame::slotInvalidateLayout(int firstItem, int endItem)
{
        PageItem* firstFrame = firstInChain();
        firstItem = itemText.prevParagraph(firstItem);

        PageItem_TextFrame* firstInvalid = dynamic_cast<PageItem_TextFrame*>(firstFrame);
        while (firstInvalid)
        {
                if (firstInvalid->invalid)
                        break;
                if (firstInvalid->firstChar <= firstItem && firstItem <= firstInvalid->MaxChars)
                        break;
                firstInvalid = dynamic_cast<PageItem_TextFrame*>(firstInvalid->NextBox);
        }

        PageItem_TextFrame* invalidFrame = firstInvalid;
        while (invalidFrame)
        {
                invalidFrame->invalid = true;
                invalidFrame = dynamic_cast<PageItem_TextFrame*>(invalidFrame->NextBox);
        }
}

bool PageItem_TextFrame::isValidChainFromBegin()
{
        if (invalid)
                return false;
        if (BackBox == NULL)
                return !invalid;

        PageItem* prev = prevInChain();
        while (prev != NULL)
        {
                if (prev->invalid)
                        return false;
                prev = prev->prevInChain();
        }
        return true;
}

void PageItem_TextFrame::DrawObj_Item(ScPainter *p, QRectF cullingArea)
{
        if (invalid)
        {
                if (isNoteFrame() && asNoteFrame()->deleteIt)
                //do not layout notes frames which should be deleted
                        return;
                layout();
        }
        if (invalid)
                return;
        if (m_Doc->RePos)
                return;
        QTransform pf2;
        //      tTabValues.clear();
        p->save(); //SA1

        if (!isEmbedded)
                pf2.translate(m_xPos, m_yPos);
        pf2.rotate(m_rotation);

        if (!m_Doc->layerOutline(LayerID))
        {
                if ((fillColor() != CommonStrings::None) || (GrType != 0))
                {
                        if (isAnnotation() && !((m_Doc->appMode == modeEdit) && (m_Doc->m_Selection->findItem(this) != -1)) && ((annotation().Type() == 2) || (annotation().Type() == 5) || (annotation().Type() == 6)))
                        {
                                if ((annotation().Feed() == 1) && annotation().IsOn())
                                        p->setBrush(QColor(255 - fillQColor.red(), 255 - fillQColor.green(), 255 - fillQColor.blue(), fillQColor.alpha()));
                        }
                        p->setupPolygon(&PoLine);
                        p->fillPath();
                }
        }
        MarginStruct savedTextDistanceMargins(m_textDistanceMargins);
        if (isAnnotation() && !((m_Doc->appMode == modeEdit) && (m_Doc->m_Selection->findItem(this) != -1)) && (((annotation().Type() > 1) && (annotation().Type() < 11)) || (annotation().Type() > 12)))
        {

                if ((m_Doc->drawAsPreview && !m_Doc->editOnPreview) && ((annotation().Vis() == 1) || (annotation().Vis() == 3)))
                {
                        p->restore();
                        return;
                }
                QColor fontColor;
                SetQColor(&fontColor, itemText.defaultStyle().charStyle().fillColor(), itemText.defaultStyle().charStyle().fillShade());
                double fontSize = itemText.defaultStyle().charStyle().fontSize() / 10.0;
                ScFace font = itemText.defaultStyle().charStyle().font();
                QString bmUtf16("");
                QString cc;
                if (!((itemText.length() == 1) && (itemText.text(0, 1) == QChar(13))))
                {
                        for (uint d = 0; d < static_cast<uint>(itemText.length()); ++d)
                        {
                                if (d == 0)
                                {
                                        const CharStyle& charStyle(itemText.charStyle(d));
                                        SetQColor(&fontColor, charStyle.fillColor(), charStyle.fillShade());
                                        fontSize = charStyle.fontSize() / 10.0;
                                        font = charStyle.font();
                                }
                                cc = itemText.text(d, 1);
                                bmUtf16 += (cc == QChar(13) ? QChar(10) : cc);
                        }
                }
                p->save();
                if ((annotation().Bwid() > 0) && (annotation().borderColor() != CommonStrings::None) && (annotation().Type() != Annotation::Text))
                {
                        QColor tmp;
                        SetQColor(&tmp, annotation().borderColor(), 100);
                        int BStyle = annotation().Bsty();
                        if (annotation().IsOn())
                        {
                                if (annotation().Feed() == 2)
                                        tmp = QColor(255 - tmp.red(), 255 - tmp.green(), 255 - tmp.blue(), tmp.alpha());
                                if (annotation().Feed() == 3)
                                        BStyle = 4;
                        }
                        if (annotation().Type() == Annotation::RadioButton)
                        {
                                double bwh = annotation().Bwid() / 2.0;
                                if (annotation().IsOn())
                                {
                                        if (BStyle == 4)
                                                BStyle = 3;
                                        else
                                                BStyle = 4;
                                }
                                if ((BStyle == 0) || (BStyle == 1))
                                {
                                        QPainterPath clp;
                                        clp.addEllipse(QRectF(bwh, bwh, m_width - annotation().Bwid(), m_height - annotation().Bwid()));
                                        FPointArray clpArr;
                                        clpArr.fromQPainterPath(clp);
                                        p->setupPolygon(&clpArr);
                                        p->setPen(tmp, annotation().Bwid(), BStyle == 0 ? Qt::SolidLine : Qt::DashLine, Qt::FlatCap, Qt::MiterJoin);
                                        p->setFillMode(ScPainter::None);
                                        p->setStrokeMode(ScPainter::Solid);
                                        p->strokePath();
                                }
                                else if (BStyle == 3)
                                        p->drawShadeCircle(QRectF(0, 0, m_width, m_height), tmp, false, annotation().Bwid());
                                else if (BStyle == 4)
                                        p->drawShadeCircle(QRectF(0, 0, m_width, m_height), tmp, true, annotation().Bwid());
                        }
                        else
                        {
                                if ((annotation().Type() == Annotation::Checkbox) && annotation().IsOn())
                                {
                                        if (BStyle == 4)
                                                BStyle = 3;
                                        else
                                                BStyle = 4;
                                }
                                if (BStyle == 3)
                                        p->drawShadePanel(QRectF(0, 0, m_width, m_height), tmp, false, annotation().Bwid());
                                else if (BStyle == 4)
                                        p->drawShadePanel(QRectF(0, 0, m_width, m_height), tmp, true, annotation().Bwid());
                                else
                                {
                                        p->setPen(tmp, annotation().Bwid(), BStyle == 0 ? Qt::SolidLine : Qt::DashLine, Qt::FlatCap, Qt::MiterJoin);
                                        p->setStrokeMode(ScPainter::Solid);
                                        p->drawRect(0, 0, m_width, m_height);
                                }
                        }
                }
                if (annotation().Type() == Annotation::Button)
                {
                        int wdt = annotation().Bwid();
                        QPainterPath clp;
                        clp.addRect(QRectF(wdt, wdt, m_width - (2 * wdt), m_height - (2 * wdt)));
                        FPointArray clpArr;
                        clpArr.fromQPainterPath(clp);
                        p->setupPolygon(&clpArr);
                        p->setClipPath();
                        if (!bmUtf16.isEmpty())
                        {
                                if ((annotation().Feed() == 1) && annotation().IsOn())
                                        p->setPen(QColor(255 - fontColor.red(), 255 - fontColor.green(), 255 - fontColor.blue(), fontColor.alpha()));
                                else
                                        p->setPen(fontColor);
                                p->setFont(font, fontSize);
                                p->drawText(QRectF(wdt, wdt, m_width - (2 * wdt), m_height - (2 * wdt)), bmUtf16, false);
                        }
                        if ((!Pfile.isEmpty()) && (imageIsAvailable) && (m_imageVisible) && (annotation().UseIcons()))
                        {
                                p->save();//SA2
                                p->setupPolygon(&PoLine);
                                p->setClipPath();
                                p->scale(m_imageXScale, m_imageYScale);
                                p->translate(m_imageXOffset*m_imageXScale, m_imageYOffset*m_imageYScale);
                                p->rotate(m_imageRotation);
                                if (pixm.width() > 0 && pixm.height() > 0)
                                        p->drawImage(pixm.qImagePtr());
                                p->restore();//RE2
                        }
                        p->restore();
                        p->restore();
                        return;
                }
                else if (annotation().Type() == Annotation::Textfield)
                {
                        int wdt = annotation().Bwid();
                        m_textDistanceMargins.set(wdt, wdt, wdt, wdt);
                        invalid = true;
                        layout();
                }
                else if (annotation().Type() == Annotation::RadioButton)
                {
                        if (annotation().IsChecked())
                        {
                                QPainterPath clp2;
                                double siz = qMin(width(), height()) * 0.4;
                                QRectF sizR(0, 0, siz, siz);
                                sizR.moveCenter(QPointF(width() / 2.0, height() / 2.0));
                                clp2.addEllipse(sizR);
                                FPointArray clpArr2;
                                clpArr2.fromQPainterPath(clp2);
                                p->setBrush(fontColor);
                                p->setFillMode(ScPainter::Solid);
                                p->setupPolygon(&clpArr2);
                                p->fillPath();
                        }
                        p->restore();
                        p->restore();
                        return;
                }
                else if (annotation().Type() == Annotation::Checkbox)
                {
                        if (annotation().IsChecked())
                        {
                                p->setBrush(fontColor);
                                p->setFillMode(ScPainter::Solid);
                                p->setStrokeMode(ScPainter::None);
                                QPainterPath chkPath;
                                if (annotation().ChkStil() == 0)
                                {
                                        chkPath.moveTo(6.60156, 0);
                                        chkPath.lineTo(6.7725, 0.244063);
                                        chkPath.cubicTo(6.7725, 0.244063, 5.7275, 1.03031, 4.44813, 2.66609);
                                        chkPath.cubicTo(4.44813, 2.66609, 3.16891, 4.30172, 2.49516, 5.72266);
                                        chkPath.lineTo(2.13375, 5.96672);
                                        chkPath.cubicTo(2.13375, 5.96672, 1.68453, 6.27922, 1.52344, 6.43062);
                                        chkPath.cubicTo(1.52344, 6.43062, 1.46, 6.20109, 1.24516, 5.67875);
                                        chkPath.lineTo(1.10844, 5.36125);
                                        chkPath.cubicTo(1.10844, 5.36125, 0.815469, 4.67766, 0.563906, 4.35062);
                                        chkPath.cubicTo(0.563906, 4.35062, 0.3125, 4.02344, 0, 3.91594);
                                        chkPath.cubicTo(0, 3.91594, 0.527344, 3.35938, 0.966875, 3.35938);
                                        chkPath.cubicTo(0.966875, 3.35938, 1.34281, 3.35938, 1.80172, 4.37984);
                                        chkPath.lineTo(1.95312, 4.72172);
                                        chkPath.cubicTo(1.95312, 4.72172, 2.77828, 3.33, 4.07219, 2.01656);
                                        chkPath.cubicTo(4.07219, 2.01656, 5.36625, 0.703125, 6.60156, 0);
                                        chkPath.closeSubpath();
                                }
                                else if (annotation().ChkStil() == 1)
                                {
                                        chkPath.moveTo(2.42672, 3.30078);
                                        chkPath.lineTo(2.35359, 3.40328);
                                        chkPath.cubicTo(2.35359, 3.40328, 1.59187, 4.55563, 1.10359, 4.55563);
                                        chkPath.cubicTo(1.10359, 4.55563, 0.542031, 4.55563, 0, 3.64266);
                                        chkPath.cubicTo(0, 3.64266, 0.0732812, 3.6475, 0.1075, 3.6475);
                                        chkPath.cubicTo(0.1075, 3.6475, 0.747031, 3.6475, 1.53328, 2.67094);
                                        chkPath.lineTo(1.665, 2.50484);
                                        chkPath.lineTo(1.49422, 2.31937);
                                        chkPath.cubicTo(1.49422, 2.31937, 0.776406, 1.55766, 0.776406, 1.02547);
                                        chkPath.cubicTo(0.776406, 1.02547, 0.776406, 0.590781, 1.5625, 0);
                                        chkPath.cubicTo(1.5625, 0, 1.67484, 0.756875, 2.23141, 1.47469);
                                        chkPath.lineTo(2.37797, 1.66016);
                                        chkPath.lineTo(2.49516, 1.50875);
                                        chkPath.cubicTo(2.49516, 1.50875, 3.31062, 0.46875, 3.97469, 0.46875);
                                        chkPath.cubicTo(3.97469, 0.46875, 4.49219, 0.46875, 4.76078, 1.25484);
                                        chkPath.cubicTo(4.76078, 1.25484, 4.68266, 1.24516, 4.64844, 1.24516);
                                        chkPath.cubicTo(4.64844, 1.24516, 4.41406, 1.24516, 3.98922, 1.56016);
                                        chkPath.cubicTo(3.98922, 1.56016, 3.56453, 1.875, 3.27156, 2.27047);
                                        chkPath.lineTo(3.125, 2.47078);
                                        chkPath.lineTo(3.26656, 2.6075);
                                        chkPath.cubicTo(3.26656, 2.6075, 4.05281, 3.36922, 4.90719, 3.36922);
                                        chkPath.cubicTo(4.90719, 3.36922, 4.44828, 4.29687, 3.95016, 4.29687);
                                        chkPath.cubicTo(3.95016, 4.29687, 3.50094, 4.29687, 2.65141, 3.50594);
                                        chkPath.lineTo(2.42672, 3.30078);
                                        chkPath.closeSubpath();
                                }
                                else if (annotation().ChkStil() == 2)
                                {
                                        chkPath.moveTo(0, 4.09187);
                                        chkPath.lineTo(2.89062, 0);
                                        chkPath.lineTo(5.78125, 4.09187);
                                        chkPath.lineTo(2.89062, 8.17875);
                                        chkPath.closeSubpath();
                                }
                                else if (annotation().ChkStil() == 3)
                                {
                                        chkPath.moveTo(0, 2.89062);
                                        chkPath.cubicTo(0, 2.89062, 0, 1.69437, 0.847187, 0.847187);
                                        chkPath.cubicTo(0.847187, 0.847187, 1.69437, 0, 2.89062, 0);
                                        chkPath.cubicTo(2.89062, 0, 4.08703, 0, 4.93656, 0.847187);
                                        chkPath.cubicTo(4.93656, 0.847187, 5.78625, 1.69437, 5.78625, 2.89062);
                                        chkPath.cubicTo(5.78625, 2.89062, 5.78625, 4.08688, 4.93656, 4.93406);
                                        chkPath.cubicTo(4.93656, 4.93406, 4.08703, 5.78125, 2.89062, 5.78125);
                                        chkPath.cubicTo(2.89062, 5.78125, 1.69437, 5.78125, 0.847187, 4.93406);
                                        chkPath.cubicTo(0.847187, 4.93406, 0, 4.08688, 0, 2.89062);
                                        chkPath.closeSubpath();
                                }
                                else if (annotation().ChkStil() == 4)
                                {
                                        chkPath.moveTo(0, 2.49516);
                                        chkPath.lineTo(2.62219, 2.49516);
                                        chkPath.lineTo(3.43266, 0);
                                        chkPath.lineTo(4.24328, 2.49516);
                                        chkPath.lineTo(6.86531, 2.49516);
                                        chkPath.lineTo(4.74609, 4.03812);
                                        chkPath.lineTo(5.55672, 6.53313);
                                        chkPath.lineTo(3.43266, 4.99016);
                                        chkPath.lineTo(1.30859, 6.53313);
                                        chkPath.lineTo(2.11922, 4.03812);
                                        chkPath.closeSubpath();
                                }
                                else if (annotation().ChkStil() == 5)
                                {
                                        chkPath.moveTo(0, 5.78125);
                                        chkPath.lineTo(0, 0);
                                        chkPath.lineTo(5.78125, 0);
                                        chkPath.lineTo(5.78125, 5.78125);
                                        chkPath.closeSubpath();
                                }
                                if (!chkPath.isEmpty())
                                {
                                        QTransform mm;
                                        mm.scale(fontSize / 10.0, fontSize / 10.0);
                                        chkPath = mm.map(chkPath);
                                        QRectF bb = chkPath.boundingRect();
                                        QRectF bi = QRectF(0.0, 0.0, m_width, m_height);
                                        double dx = bi.center().x() - (bb.width() / 2.0);
                                        double dy = bi.center().y() - (bb.height() / 2.0);
                                        p->translate(dx, dy);
                                        FPointArray chArr;
                                        chArr.fromQPainterPath(chkPath);
                                        p->setupPolygon(&chArr);
                                        p->fillPath();
                                }
                                p->restore();
                                p->restore();
                                return;
                        }
                }
                else if (annotation().Type() == Annotation::Combobox)
                {
                        int wdt = annotation().Bwid();
                        if (m_width > 2 * wdt + 15)
                        {
                                if (!bmUtf16.isEmpty())
                                {
                                        p->save();
                                        QPainterPath clp;
                                        clp.addRect(QRectF(wdt + 1, wdt + 1, m_width - (2 * wdt) - 17, m_height - (2 * wdt) - 2));
                                        FPointArray clpArr;
                                        clpArr.fromQPainterPath(clp);
                                        p->setupPolygon(&clpArr);
                                        p->setClipPath();
                                        p->setPen(fontColor);
                                        p->setFont(font, fontSize);
                                        QStringList textList = bmUtf16.split("\n");
                                        p->drawText(QRectF(wdt + 1, wdt + 1, m_width - (2 * wdt) - 17, m_height - (2 * wdt) - 2), textList[0], false, 1);
                                        p->restore();
                                }
                                p->setFillMode(ScPainter::Solid);
                                p->setStrokeMode(ScPainter::None);
                                p->setBrush(QColor(200, 200, 200));
                                QRectF bi;
                                if ((annotation().Bsty() == 3) || (annotation().Bsty() == 4))
                                        bi = QRectF(m_width - wdt - 15, wdt, 15, m_height - (2 * wdt));
                                else
                                        bi = QRectF(m_width - (wdt / 2.0) - 15, wdt / 2.0, 15, m_height - wdt);
                                p->drawRect(bi.x(), bi.y(), bi.width(), bi.height());
                                QPainterPath chkPath;
                                chkPath.moveTo(bi.center().x() - 3, bi.center().y());
                                chkPath.lineTo(bi.center().x() + 3, bi.center().y());
                                chkPath.lineTo(bi.center().x(), bi.center().y() + 4);
                                chkPath.closeSubpath();
                                FPointArray chArr;
                                chArr.fromQPainterPath(chkPath);
                                p->setupPolygon(&chArr);
                                p->setBrush(QColor(0, 0, 0));
                                p->fillPath();
                                p->restore();
                                p->restore();
                                return;
                        }
                }
                else if (annotation().Type() == Annotation::Listbox)
                {
                        int wdt = annotation().Bwid();
                        if (m_width > 2 * wdt + 15)
                        {
                                if (!bmUtf16.isEmpty())
                                {
                                        p->save();
                                        QPainterPath clp;
                                        clp.addRect(QRectF(wdt + 1, wdt + 1, m_width - (2 * wdt) - 17, m_height - (2 * wdt) - 2));
                                        FPointArray clpArr;
                                        clpArr.fromQPainterPath(clp);
                                        p->setupPolygon(&clpArr);
                                        p->setClipPath();
                                        p->setPen(fontColor);
                                        p->setFont(font, fontSize);
                                        p->drawText(QRectF(wdt + 1, wdt + 1, m_width - (2 * wdt) - 17, m_height - (2 * wdt) - 2), bmUtf16, false, 2);
                                        p->restore();
                                }
                                p->restore();
                                p->restore();
                                return;
                        }
                }
                else if (annotation().Type() == Annotation::Text)
                {
                        if (m_Doc->drawAsPreview && !m_Doc->editOnPreview)
                        {
                                if (annotation().IsOpen())
                                {
                                        p->save();
                                        p->translate(m_origAnnotPos.x() - xPos(), m_origAnnotPos.y() - yPos());
                                        drawNoteIcon(p);
                                        p->restore();
                                        p->save();
                                        double basX = 15;
                                        double basY = 15;
                                        QPainterPath clp;
                                        clp.addRoundedRect(basX, basY, 250, 250, 5, 5);
                                        p->setBrush(QColor(240, 240, 0));
                                        p->setFillMode(ScPainter::Solid);
                                        p->setStrokeMode(ScPainter::None);
                                        FPointArray clpArr;
                                        clpArr.fromQPainterPath(clp);
                                        p->setupPolygon(&clpArr);
                                        p->fillPath();
                                        p->setPen(QColor(0, 0, 0), 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
                                        p->setBrush(QColor(255, 255, 255));
                                        p->setStrokeMode(ScPainter::Solid);
                                        p->drawRect(basX + 10, basY + 20, 230, 220);
                                        p->setFillMode(ScPainter::None);
                                        p->drawRect(basX + 230, basY + 5, 11, 11);
                                        p->setPen(QColor(0, 0, 0), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
                                        p->drawLine(QPointF(basX + 232, basY + 13), QPointF(basX + 239, basY + 13));
                                        p->save();
                                        p->translate(basX + 10, basY + 5);
                                        p->scale(0.5, 0.5);
                                        drawNoteIcon(p);
                                        p->restore();
                                        clp = QPainterPath();
                                        clp.addRect(basX + 10, basY + 20, 230, 220);
                                        clpArr.fromQPainterPath(clp);
                                        p->setupPolygon(&clpArr);
                                        p->setClipPath();