View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0010251 | Scribus | Story Editor / Text Frames | public | 2011-09-08 10:20 | 2012-02-19 17:21 |
Reporter | cezaryece | Assigned To | jghali | ||
Priority | urgent | Severity | major | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Platform | all | ||||
Product Version | 1.4.0svn | ||||
Fixed in Version | 1.4.0svn | ||||
Summary | 0010251: [PATCH] wrong text formatting issues | ||||
Description | We have few issues with text formatting reported in few reports. It is very difficult and sensitive task to fix it, so it take about 3 months for me since I start working on it (and submitting patches, but they are not fixing all issues and bring few new issues). Hope my patch is near perfect - I test a lot working not only with study cases but also with production work (newspaper). | ||||
Steps To Reproduce | In attached SLA file you have 6 issuses fixed by this patch (but not only theese 6 are fixed). Openning this file in current Scribus and next in patched you can see theese issues fixed (look at screenshots too). Hope my patch fixes issues and dont bring any new one. | ||||
Additional Information | It is big patch mainly for PageItem_TextFrame::layout() routine. I was almost rewrote it whole. | ||||
Tags | No tags attached. | ||||
Patch | |||||
related to | 0009932 | closed | jghali | First text line does not flow around objects |
related to | 0009436 | closed | jghali | wrong text formating - text extend margins or columns |
related to | 0005891 | closed | jghali | Various settings of work tracking and glyph extension make text overlap in column gap |
related to | 0008538 | closed | jghali | Text wrap/flow around image frame fails when glyph extension and word tracking are not 100% |
|
formatting.patch (78,458 bytes)
Index: Version135/Scribus/scribus/pageitem_textframe.cpp =================================================================== --- Version135/Scribus/scribus/pageitem_textframe.cpp (wersja 16820) +++ Version135/Scribus/scribus/pageitem_textframe.cpp (kopia robocza) @@ -70,7 +70,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -83,7 +82,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -155,9 +153,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - { - result = result.subtract(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); - } + result = result.subtracted(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -192,7 +188,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - result = result.subtract(itemShape(docItem, 0, 0)); + result = result.subtracted(itemShape(docItem, 0, 0)); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -202,7 +198,6 @@ return result; } - void PageItem_TextFrame::setShadow() { if (OnMasterPage.isEmpty()) @@ -235,10 +230,6 @@ currentShadow = newShadow; } } - -#ifdef NLS_PROTO -#include "text/pageitem_textframe.cpp" -#else static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->")) { @@ -258,7 +249,6 @@ dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } - static const bool legacy = true; /* @@ -373,22 +363,23 @@ } /// move position to next column - void nextColumn(double asce) + void nextColumn(double asce = 0.0) { startOfCol = true; colLeft = (colWidth + colGap) * column + insets.Left + lineCorr; + //now colRight is REAL column right edge colRight = colLeft + colWidth; if (legacy) - colRight += insets.Right + lineCorr; //??? + colRight += lineCorr; xPos = colLeft; - yPos = asce + insets.Top + lineCorr + 1; + yPos = asce + insets.Top + lineCorr; } bool isEndOfCol(double morespace = 0) { return yPos + morespace + insets.Bottom + lineCorr > frameHeight; } - + /** init fields for a new line at current position */ @@ -398,7 +389,8 @@ line.x = xPos; line.y = yPos; line.firstItem = first; - line.ascent = 10; + line.lastItem = 0; + line.ascent = 0; line.descent = 0; line.width = 0; line.naturalWidth = 0; @@ -407,6 +399,7 @@ breakXPos = 0; maxShrink = 0; maxStretch = 0; + width = 0; } @@ -423,12 +416,12 @@ } /// called when a possible break is passed - void rememberBreak(int index, double pos) + void rememberBreak(int index, double pos, double morespace = 0) { - if (pos > colRight) + if (pos > colRight - morespace) { // only look for the first break behind the right edge - maxShrink = 0; + //maxShrink = 0; // check if we already have a better break if (breakIndex >= 0) @@ -439,12 +432,8 @@ if (newLooseness >= oldLooseness) return; } - breakXPos = colRight; } - else - { - breakXPos = pos; - } + breakXPos = pos; breakIndex = index; } @@ -462,7 +451,7 @@ // #9060 : update line offset too updateLineOffset(itemText, style, offsetPolicy); } - + /// use the last remembered break to set line width and itemrange void finishLine(double endX) { @@ -471,109 +460,44 @@ line.width = endX - line.x; maxShrink = maxStretch = 0; } - - + bool isEndOfLine(double moreSpace = 0) { + bool res; if (legacy) - return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight; + res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight); else - return xPos + moreSpace - maxShrink >= colRight; + res = ceil(xPos - maxShrink) + ceil(moreSpace) >= floor(colRight); + return res; } - - /// find x position to start current line - double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace) - { - QPoint pt1, pt2; - double tmpX = xPos; - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - // increase pt1/pt2 until i-beam reaches end of line - while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2)))) - { - tmpX++; - if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight) - { - return tmpX; - } - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - } - return tmpX; - } - + /// find x position where this line must end - double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace = 0) + double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace, int Yasc, int Ydesc) { - // Keep old code for reference - /*double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - QPoint pt1, pt2; - // qDebug() << QString("endx start=%1, hl is '%2'").arg(EndX).arg(hl->ch); - do { - EndX += 0.125; - pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent)); - pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent))); - } while ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace) - && shape.contains(pf2.map(pt1)) - && shape.contains(pf2.map(pt2)) - );*/ - // if we aren't restricted further, we'll end at this maxX: double maxX = colRight - morespace; - if (legacy) maxX -= (lineCorr + insets.Right); + if (legacy) maxX -= lineCorr; - double StartX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - int xPos = static_cast<int>(ceil(maxX + insets.Right)); - int yDesc = static_cast<int>(yPos+line.descent); - int yAsc = static_cast<int>(ceil(yPos-line.ascent)); + double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1); + int xPos = static_cast<int>(ceil(maxX)); - QPoint pt12 (xPos, yDesc); - QPoint pt22 (xPos, yAsc); + QPoint pt12 (xPos, Yasc); + QPoint pt22 (xPos, Ydesc); + QRect pt(pt12,pt22); - // simple and fast case: transformed line completely falls within range - // this will happen if we don't wrap around anything - ie. very often - QPolygon p; - p.append (pf2.map (QPoint (StartX, yAsc))); - p.append (pf2.map (QPoint (StartX, yDesc))); - p.append (pf2.map (pt12)); - p.append (pf2.map (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.numRects() == 1) - { - int xPos = qRound(ceil(StartX + 0.125 + insets.Right)); - pt12.setX(xPos); - pt22.setX(xPos); - if (shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))) - { - QRect rect = lineI.rects().at(0); - double mx = qMax(rect.left(), rect.right()) - pf2.dx(); - int steps = static_cast<int>((mx - StartX - insets.Right - 2)/0.125); - if (steps > 0) - StartX += steps * 0.125; - } - } - - // qDebug()<<"endOfLine: going for the hard case"; double EndX2 = StartX; - double Interval = 0.125; + double Interval = 0.25; do { + int xP = static_cast<int>(ceil(EndX2 + morespace)); + pt.moveTopLeft(QPoint(xP, Yasc)); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()) + break; EndX2 += Interval; - int xPos = qRound(ceil(EndX2 + insets.Right)); - pt12.setX (xPos); - pt22.setX (xPos); - } while ((EndX2 < maxX) && shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))); + } while ((EndX2 < maxX) && QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()); - /*if (EndX!=EndX2) - { - qDebug()<<EndX<<EndX2<<StartX<<maxX; - qDebug()<<"DIFFERING ENDX!!!!!"; - }*/ - return EndX2; + return qMin(EndX2, maxX); } - - + double getLineAscent(const StoryText& itemText) { double result = 0; @@ -684,15 +608,18 @@ || (ch == SpecialChars::LINEBREAK) || (ch.isSpace())) continue; const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc)); + double scaleV = cStyle.scaleV() / 1000.0; + double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0); + if (itemText.object(line.firstItem+zc) != 0) { - asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0); + asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset; desc = 0.0; } else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0) { - asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0); - desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0); + asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset; + desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset; } // qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result); line.ascent = qMax(line.ascent, asce); @@ -701,7 +628,8 @@ } void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) - { + {// yPos should not be changed when all line is calculated, at new y position there can be overflow!!! + return; if (itemsInLine <= 0) return; if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) @@ -712,7 +640,8 @@ double currasce (this->getLineAscent(itemText)); if( offsetPolicy == FLOPRealGlyphHeight ) { - adj = firstasce - currasce; + adj = line.y - insets.Top -currasce; + //adj = firstasce - currasce; } else if( offsetPolicy == FLOPFontAscent ) { @@ -802,8 +731,11 @@ .arg(style.minWordTracking()).arg(style.minGlyphExtension()); */ + int startItem = line.firstItem; + if (itemText.item(startItem)->effects() & ScStyle_DropCap) + startItem++; // distribute whitespace on spaces and glyphs - for (int yof = line.firstItem; yof <= line.lastItem; ++yof) + for (int yof = startItem; yof <= line.lastItem; ++yof) { double wide = itemText.item(yof)->glyph.wide(); if (!SpecialChars::isExpandingSpace(itemText.text(yof))) @@ -877,8 +809,6 @@ return leftCorr; } - - /// calculate how much the last char should stick out to the right static double opticalRightMargin(const StoryText& itemText, const LineSpec& line) { @@ -923,10 +853,15 @@ return 0.0; } +static double findRealOverflowEnd(const QRegion& shape, const QMatrix& pf2, QRect pt, double maxX) +{ + while (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty() && pt.right() < maxX) + pt.translate(1, 0); + if (pt.right() >= maxX) + return maxX; + return pt.left() +0.5; +} - - - void PageItem_TextFrame::layout() { // qDebug()<<"==Layout==" << itemName() ; @@ -957,10 +892,9 @@ firstChar = 0; // qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame()); -// ScribusView* view = m_Doc->view(); QMatrix pf2; QPoint pt1, pt2; - /*QRegion cm;*/ + QRect pt; double chs, chsd = 0; double oldCurY, EndX, OFs, wide, kernVal; QString chstr; @@ -969,7 +903,6 @@ int /*ParagraphStyle::OpticalMarginType*/ opticalMargins = ParagraphStyle::OM_None; bool outs = false; - bool fBorder = false; bool goNoRoom = false; bool goNextColumn = false; @@ -983,12 +916,12 @@ tTabValues.clear(); bool DropCmode = false; - double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0; + double desc=0, asce=0, realAsce=0, realDesc = 0; + double maxDY=0, maxDX=0; double DropCapDrop = 0; int DropLines = 0; int DropLinesCount = 0; - itemText.clearLines(); double lineCorr = 0; @@ -1006,7 +939,11 @@ current.init(Width, Height, extra, lineCorr); current.initColumns(columnWidth(), ColGap); current.hyphenCount = 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, currentRowDesc = 0; + // dump styles /* for (int i=0; i < itemText.nrOfParagraphs(); ++i) { @@ -1018,7 +955,6 @@ dumpIt(itemText.defaultStyle()); */ -// pf2.begin(view->viewport()); pf2.translate(Xpos, Ypos); pf2.rotate(Rot); @@ -1044,7 +980,8 @@ pf2.scale(1, -1); } - current.nextColumn(0); + current.nextColumn(); + lastLineY = extra.Top; // find start of first line if (firstInFrame() < itemText.length()) @@ -1070,19 +1007,35 @@ } else chs = hl->fontSize(); - desc2 = -hl->font().descent(chs / 10.0); + desc = -hl->font().descent(chs / 10.0); current.yPos = extra.Top + lineCorr; // qDebug() << QString("first line at y=%1").arg(current.yPos); } else // empty itemText: { - desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); - current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; + desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); + current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc; } current.startLine(firstInFrame()); + outs = false; OFs = 0; MaxChars = 0; + bool inOverflow = false; + bool afterOverflow = false; + bool addLine = false; + bool recalculateY = true; + bool lastInRowLine = false; + bool addLeftIndent = true; + bool wasFirstInRow = false; + double leftIndent = 0; + double rightMargin = 0.0; + double mustLineEnd = current.colRight; + int restartIndex = firstInFrame(); //index of char where line computing should be restarted + int restartRowIndex = firstInFrame(); //index of char where row of text is started + double restartX = 0; //starting X position of line if must be restarted + double realEnd = 0; + for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a); @@ -1091,27 +1044,17 @@ if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); -// qDebug() << QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); const CharStyle& charStyle = (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle()); - if (!charStyle.parent().isEmpty()) - { -// qDebug() << QString("charstyle pos %1: %2 (%3 %4 %5 %6 %7 %8 %9)").arg(a).arg(charStyle.parent()) -// .arg((uint)charStyle.parentStyle()).arg(charStyle.font().scName()).arg(charStyle.fontSize()) -// .arg(charStyle.fillColor()).arg(charStyle.strokeColor()).arg(charStyle.parentStyle()->name()).arg((uint)charStyle.parentStyle()->parentStyle()); - } -// qDebug() << QString("charstyle pos %1: %2 (%3)").arg(a).arg(charStyle.asString()).arg(charStyle.fontSize()); -// qDebug() << QString("style @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); + chstr = ExpandToken(a); + 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); - chstr = ExpandToken(a); -// qDebug() << QString("expanded token: '%1'").arg(chstr); if (chstr.isEmpty()) chstr = SpecialChars::ZWNBSPACE; if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); // find out about par gap and dropcap @@ -1119,7 +1062,6 @@ { if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP) { - current.yPos += style.gapBefore(); if (chstr[0] != SpecialChars::PARSEP) { DropCmode = style.hasDropCap(); @@ -1165,21 +1107,34 @@ else hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); } - // qDebug() << QString("textframe(%1,%2): len=%3, fontsize=%4, ascent=%5").arg(Xpos).arg(Ypos).arg(itemText.length()) -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()); if (current.itemsInLine == 0) { - // more about par gap and dropcaps - if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && !current.startOfCol)) // after || always evaluates to false? FIXME + if (style.rightMargin() == 0) { -// qDebug() << QString("gap before2: y=%1+%2").arg(current.yPos).arg(style.gapBefore()); - current.yPos += style.gapBefore(); + addLine = true; + rightMargin = 0.0; + } + else + { + if (lastInRowLine) + rightMargin = style.rightMargin(); + else + rightMargin = 0.0; + } + current.breakIndex = -1; + if (current.startOfCol && !afterOverflow && recalculateY) + current.yPos = qMax(current.yPos,extra.Top); + // more about par gap and dropcaps + if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol)) + { + if (!afterOverflow && recalculateY && !current.startOfCol) + current.yPos += style.gapBefore(); DropCapDrop = 0; if (chstr[0] != SpecialChars::PARSEP) DropCmode = style.hasDropCap(); else DropCmode = false; - if (DropCmode) + if (DropCmode && !afterOverflow) { DropLines = style.dropCapLines(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1189,35 +1144,22 @@ if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) DropCapDrop = style.lineSpacing() * (DropLines-1); else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); + DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines-1); } -// qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop); - current.yPos += DropCapDrop; } } } - // find charsize & y pos +// ######## find charsize factors if (DropCmode) { - // dropcap active? - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); - else - { - if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - DropCapDrop = style.lineSpacing() * (DropLines-1); - else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); - } - // FIXME : we should ensure that fonts are loaded before calls to layout() // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap() // ScFace::ascent() can be called safely afterwards double realCharHeight = charStyle.font().realCharHeight(chstr[0], 1); double realCharAscent = charStyle.font().realCharAscent(chstr[0], 1); - double fontAscent = charStyle.font().ascent(style.charStyle().fontSize() / 10.0); + double fontAscent = charStyle.font().ascent(hlcsize10); if (realCharHeight == 0.0) - realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); + realCharHeight = charStyle.font().height(hlcsize10); if (realCharAscent == 0.0) realCharAscent = fontAscent; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1234,7 +1176,7 @@ } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(hlcsize10); chsd = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharHeight)); chs = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharAscent)); } @@ -1249,7 +1191,7 @@ else chs = charStyle.fontSize(); } - // find tracking +// ######## set StartOfLine (and find tracking?) if (current.itemsInLine == 0) { itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine); @@ -1262,7 +1204,8 @@ } hl->glyph.yadvance = 0; oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); - // find out width of char + +// ######## find out width, ascent and descent of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1290,38 +1233,39 @@ itemHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - asce = m_Doc->typographicSettings.valueBaseGrid * DropLines; + realAsce = m_Doc->typographicSettings.valueBaseGrid * DropLines; else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - asce = style.lineSpacing() * DropLines; + realAsce = style.lineSpacing() * DropLines; else - asce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; + realAsce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; } hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / itemHeight); + hl->glyph.scaleV = (realAsce / itemHeight); hl->glyph.scaleH *= hl->glyph.scaleV; } else { - double realCharHeight = charStyle.font().realCharHeight(chstr[0], charStyle.fontSize() / 10.0); + double realCharHeight = charStyle.font().realCharHeight(chstr[0], hlcsize10); if (realCharHeight == 0) realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); - wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0); - asce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0); -// qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); + wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0) * scaleH +1; //dropcaps are always to close to next glyphs + realAsce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0) * scaleV + offset; + asce = charStyle.font().ascent(hlcsize10); + // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / realCharHeight); + hl->glyph.scaleV = (realAsce / realCharHeight); hl->glyph.scaleH *= hl->glyph.scaleV; + hl->glyph.xoffset -= 0.5; //drop caps are always to far from column left edge } hl->glyph.xadvance = wide; - desc2 = 0; - desc = 0; + desc = realDesc =0; } else // !DropCMode { -// qDebug( ) << QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent()); + // qDebug( ) << QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") + // .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent()); if (SpecialChars::isExpandingSpace(hl->ch)) { @@ -1329,129 +1273,145 @@ hl->glyph.xadvance *= wordtracking; wide *= wordtracking; } - // find ascent / descent - double hlcsize10=charStyle.fontSize() / 10.0; if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) - { - desc = desc2 = 0; - } + desc = realDesc = 0; else { - desc = desc2 = -charStyle.font().descent(hlcsize10); + desc = -charStyle.font().descent(hlcsize10); + realDesc = charStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset; current.rememberShrinkStretch(hl->ch, wide, style); } asce = charStyle.font().ascent(hlcsize10); -// wide = wide * hl->glyph.scaleH; + realAsce = charStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset; } - fBorder = false; - // end of col reached? -// qDebug() << QString("eocol? %1 + %2 + %3 > %4 -- asce=%5").arg(current.yPos).arg(extra.Bottom).arg(lineCorr).arg(Height).arg(asce); - if (current.isEndOfCol()) + +// ######## check for Y position at beginning of line + if (current.itemsInLine == 0 && !afterOverflow) { - current.column++; - if (current.column < Cols) + if (recalculateY) { - // start next col - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) - || ((a == firstInFrame()) && (BackBox == 0))) + //if top of column Y position depends on first line offset + if (current.startOfCol) { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) + lastLineY = qMax(lastLineY, extra.Top + lineCorr); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); + if (firstLineOffset() == FLOPRealGlyphHeight) + { + if (DropCmode) + current.yPos += asce; + else + current.yPos += realAsce; + } + else if (firstLineOffset() == FLOPLineSpacing) + current.yPos += style.lineSpacing(); else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); + current.yPos += asce; } - if (DropCmode) - DropLines = style.dropCapLines(); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + if (current.yPos <= lastLineY) + current.yPos = lastLineY +1; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } } -// qDebug() << QString("layout: nextcol grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + else { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + current.yPos += m_Doc->typographicSettings.valueBaseGrid; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } + else + current.yPos += style.lineSpacing(); } + if (DropCmode) + current.yPos += DropCapDrop; } - else + //set left indentation + leftIndent = 0.0; + if (addLeftIndent && (maxDX == 0 || DropCmode)) { - MaxChars = a; -// qDebug() << QString("no room A: %1").arg(a); - goto NoRoom; + leftIndent = style.leftMargin(); + if (current.hasDropCap) + leftIndent = 0; + if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))) + leftIndent += style.firstIndent(); + addLeftIndent = false; } } - // ok, there's more room in col - if (current.itemsInLine == 0) + recalculateY = true; + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) { -// qDebug() << QString("newline: '%1' %2 %3").arg(a).arg(current.yPos).arg(asce); - // start a new line - double TopOffset = asce; - double BotOffset = desc2; - goNoRoom = false; - if (current.startOfCol) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { -// qDebug() << QString("current.startOfCol: %1 + %2 + %3 + 1 =%4").arg(asce).arg(extra.Top).arg(lineCorr).arg(asce + extra.Top + lineCorr + 1); - current.yPos = asce + extra.Top + lineCorr + 1; -// if (((a > 0) && (itemText.at(a-1)->ch == QChar(13))) || ((a == 0) && (BackBox == 0))) -// current.yPos += m_Doc->docParagraphStyles[hl->cab].gapBefore; + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } -// qDebug() << QString("layout: nextline grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + if (current.itemsInLine == 0 && !afterOverflow) + { + //start a new line + goNoRoom = false; + + // find line`s start + pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc); + pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc); + pt = QRect(pt1, pt2); + //done is for two passes: + //1. from left edge (always) + //2. from leftIndent if it is set + + 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; + while (!done) { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("useBaselIneGrid: %1 * %2 + %3 - %4").arg(ol2 / 10000.0).arg(m_Doc->typographicSettings.valueBaseGrid).arg(m_Doc->typographicSettings.offsetBaseGrid).arg(by); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } - /* this causes different spacing for first line: - if (current.yPos-TopOffset < 0.0) - { - qDebug(= << QString("current.yPos - Ascender < 0 (%1 - %2 < 0)").arg(current.yPos).arg(TopOffset); - current.yPos = TopOffset+1; - } - */ - // find linelength: - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); - // increase pt1/pt2 until i-beam reaches end of line -// qDebug() << QString("linestart: %1 + %2 + %3 < %4").arg(current.xPos).arg(wide).arg(style.rightMargin()).arg(current.colRight); - double leftIndent = 0; - double xStep = legacy? 1 : 0.125; - while (!cl.contains(pf2.map(pt1)) || !cl.contains(pf2.map(pt2)) || current.isEndOfLine(wide + leftIndent + style.rightMargin())) - { - fBorder = true; - current.xPos += xStep; - if (current.isEndOfLine(wide + leftIndent + style.rightMargin())) + Xpos = current.xPos; + Xend = current.xPos + leftIndent; + //check if in indent any overflow occurs + while (Xpos <= Xend && Xpos < current.colRight) { -// qDebug() << QString("eocol %5? %1 + %2 + %3 + %4").arg(current.yPos).arg(current.startOfCol).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(style.lineSpacing()).arg(current.column); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + Xpos = current.xPos = realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + Xend = current.xPos + leftIndent; + } + else + Xpos++; + pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc)); + } + current.xPos = Xend; + done = true; + if (current.isEndOfLine((style.minGlyphExtension() * wide) + rightMargin + leftIndent)) + { // new line - fBorder = false; - current.xPos = current.colLeft; - - leftIndent = style.leftMargin(); - if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) - leftIndent += style.firstIndent(); - - if (current.startOfCol) - current.yPos++; - else - current.yPos += qMax(style.lineSpacing(), 1.0); -// qDebug() << QString("layout: next lower line grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); + current.xPos = qMax(current.colLeft, maxDX); + current.yPos ++; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { double by = Ypos; @@ -1459,83 +1419,113 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; } - if (current.isEndOfCol()) + lastLineY = maxYAsc +1; + if (current.startOfCol) { - fBorder = false; - current.column++; - if (current.column < Cols) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == firstInFrame()) && (BackBox == 0))) - { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) - { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); - else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); - } - if (DropCmode) - DropLines = style.dropCapLines(); - } -// qDebug() << QString("layout: nextcol2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } - else - { - MaxChars = a; -// qDebug() << QString("no room B: %1").arg(a); - goto NoRoom; - } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc)); + done = false; } - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); + if (current.isEndOfCol(realDesc)) + { + current.column++; + if (current.column < Cols) + { + newColumn = true; + break; + } + else + { + MaxChars = a; + goto NoRoom; + } + } } - - if (((fBorder)) && (!current.hasDropCap)) - current.xPos += extra.Left; - // indent first line of par - if (a > 0) + if (newColumn) { - if (itemText.text(a-1) == SpecialChars::PARSEP) - current.xPos += style.firstIndent(); + current.nextColumn(); + mustLineEnd = current.colRight; + restartX = current.xPos; + lastLineY = current.yPos; + currentRowDesc = 0; + a--; + recalculateY = true; + addLeftIndent = true; + continue; } + current.line.x = restartX = current.xPos; + current.line.y = current.yPos; + } + + //check if line must start at new Y position due to current glyph height or previous line descent + if (!SpecialChars::isBreak(hl->ch, true) + && !SpecialChars::isBreakingSpace(hl->ch) + && !SpecialChars::isExpandingSpace(hl->ch) + && hl->ch != SpecialChars::TAB) + { + double diff = 0; + if (current.startOfCol || DropCmode) + diff = realAsce * scaleV + offset - (current.yPos - lastLineY); else + diff = charStyle.font().realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY); + if (diff >= 1 || (!DropCmode && diff > 0)) { - if (legacy) - current.xPos += style.firstIndent(); + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + current.yPos = maxDY; + maxDX = 0; + } + int linesDrop = 0; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + linesDrop = ceil(diff/m_Doc->typographicSettings.valueBaseGrid); + current.yPos += m_Doc->typographicSettings.valueBaseGrid * linesDrop; + } + else /*if (current.startOfCol)*/ + { + 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; + } + } + recalculateY = false; + current.xPos = current.colLeft; + a = restartRowIndex -1; + current.startLine(a+1); + addLeftIndent = true; + afterOverflow = false; + continue; } - // add left margin - if (!current.hasDropCap) - current.xPos += style.leftMargin(); - if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct) { - current.xPos += opticalLeftMargin(itemText, current.line); - } -// qDebug() << QString("store line: (%1,%2)").arg(current.xPos).arg(current.yPos); - current.line.x = current.xPos; - current.line.y = current.yPos; - fBorder = false; } - else { -// qDebug() << QString("cont.' line: '%1'").arg(a); - } // right tab stuff if (tabs.active) { @@ -1589,7 +1579,6 @@ current.xPos = current.colLeft + tCurX; // remember fill char -// qDebug() << QString("tab: %1 '%2'").arg(tCurX).arg(tabs.fillChar); if (!tabs.fillChar.isNull()) { hl->glyph.growWithTabLayout(); TabLayout * tglyph = dynamic_cast<TabLayout*>(hl->glyph.more); @@ -1614,7 +1603,6 @@ if (DropCmode) hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0); - // remember x pos double breakPos = current.xPos; @@ -1630,57 +1618,181 @@ else // other tabs.active { current.xPos = qMax(current.xPos, current.colLeft); - } - - //FIXME: asce / desc set correctly? - if (legacy && - (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) - || hl->ch == SpecialChars::SHYPHEN)) + } + // remember possible break + if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB)) { - if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(ceil(current.yPos-asce))); + current.rememberBreak(a, breakPos, style.rightMargin()); } - else - { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); - } } - else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + //check against space before PARSEP + if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP)) { - pt1 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); + a++; + hl = itemText.item(a); } - else + + // test if end of line reached + double overflowWidth = 0.0; + double hyphWidth = 0.0; + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + hyphWidth = charStyle.font().charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0); + if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(hl->ch, Cols > 1) || current.xPos >= mustLineEnd) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(ceil(current.yPos-asce))); + if (!addLine && style.rightMargin() > 0.0 && !lastInRowLine && 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 + lastInRowLine = false; + if (current.breakIndex <=0) + mustLineEnd = current.line.x -1; + else if (current.line.firstItem == restartIndex) + lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0 && restartIndex == restartRowIndex) + { + current.hasDropCap = false; + maxDX = 0; + current.yPos = maxDY; + } + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + recalculateY = false; + addLine = true; + continue; + } + outs = true; + addLine = true; + lastInRowLine = true; + rightMargin = style.rightMargin(); + if (current.isEndOfCol(realDesc)) + goNextColumn = true; } - - // test if end of line reached - if ((!cl.contains(pf2.map(pt1))) || (!cl.contains(pf2.map(pt2))) || (legacy && current.isEndOfLine(style.rightMargin()))) - outs = true; - if (current.isEndOfCol()) - outs = true; - if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) - goNoRoom = true; - if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) - goNextColumn = true; - - - // remember possible break - // #5783 : comment out "&& !outs" as this make it possible to perform a line break - // before a space which contradicts unicode line breaking rules - if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB) /*&& !outs*/) + else { - if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) + int charStart, charEnd; + if (current.itemsInLine == 0) { - current.rememberBreak(a, breakPos); + charStart = static_cast<int>(floor(current.line.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) + hyphWidth); + } + if (legacy && + (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) + || hl->ch == SpecialChars::SHYPHEN)) + { + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + } + else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + { + pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + pt = QRect(pt1, pt2); + if (charEnd > 220) + qDebug(); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + if (current.breakIndex <=0) + { + current.line.x = current.xPos = restartX = realEnd; + current.itemsInLine = 0; + a = restartIndex -1; + if (!wasFirstInRow) + addLeftIndent = true; + if (current.hasDropCap && DropLinesCount == 0 && !afterOverflow) + { + current.hasDropCap = false; + current.yPos = maxDY; + } + recalculateY = false; + continue; + } + outs = true; + } + else if (style.rightMargin() > 0.0) + { + if (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 (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + outs = true; + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + } + } + } + if (outs) + { + //check if after overflow text can be placed + overflowWidth = realEnd - (current.xPos - current.maxShrink); + if (current.isEndOfLine(overflowWidth + style.rightMargin() + style.minGlyphExtension() * wide + hyphWidth) || realEnd >= mustLineEnd) + { + if (!addLine && style.rightMargin() > 0.0 && !lastInRowLine) + { + if (afterOverflow) + { + lastInRowLine = false; + if (current.breakIndex <=0) + { + lastInRowLine = true; + mustLineEnd = current.line.x -1; + } + else if (current.line.firstItem == restartIndex) + lastInRowLine = true; + } + else + lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + maxDX = 0; + } + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + recalculateY = false; + addLine = true; + continue; + } + addLine = true; + rightMargin = style.rightMargin(); + lastInRowLine = true; + } + else + inOverflow = true; + } } - // hyphenation if (((hl->effects() & ScStyle_HyphenationPossible) || (hl->ch == '-') || hl->ch == SpecialChars::SHYPHEN) && (!outs) && !itemText.text(a-1).isSpace() ) @@ -1688,24 +1800,28 @@ breakPos = current.xPos; if (hl->ch != '-') { - breakPos += charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0); + breakPos += hyphWidth; } double rightHang = 0; if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) { - rightHang = 0.7 * charStyle.font().realCharWidth('-', (charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0)); + rightHang = 0.7 * hyphWidth; } if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin())) { if ((current.hyphenCount < m_Doc->HyCount) || (m_Doc->HyCount == 0) || hl->ch == SpecialChars::SHYPHEN) { - current.rememberBreak(a, breakPos); + current.rememberBreak(a, breakPos, style.rightMargin() + hyphWidth); } } } - - + + if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) + goNoRoom = true; + if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) + goNextColumn = true; + ++current.itemsInLine; if (tabs.active) @@ -1725,7 +1841,7 @@ } } - if (DropCmode) + if (DropCmode && !outs) { DropCmode = false; DropLinesCount = 0; @@ -1733,10 +1849,7 @@ current.hasDropCap = true; current.xPos += style.dropCapOffset(); hl->glyph.xadvance += style.dropCapOffset(); -// qDebug() << QString("dropcapoffset: %1 -> %2").arg(current.xPos-style.dropCapOffset()).arg(current.xPos); - current.xPos = qMax(current.xPos, current.colLeft); maxDX = current.xPos; - QPolygon tcli(4); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { current.yPos -= m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); @@ -1745,40 +1858,24 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust after dropcaps: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - //FIXME: use current.colLeft instead of xOffset? - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); } else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) { current.yPos -= style.lineSpacing() * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY - DropLines * style.lineSpacing()))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*style.lineSpacing()))); } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(charStyle.fontSize() / 10.0); current.yPos -= currasce * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*currasce))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*currasce))); } } - tcli.setPoint(2, QPoint(qRound(maxDX), qRound(maxDY))); - tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); - // #6821 : the following two lines are causing bad text flow around drop caps - // in some case, discarding them put more emphasis on user control of line spacing - /*cm = QRegion(pf2.map(tcli)); - cl = cl.subtract(cm);*/ -// current.yPos = maxDY; + recalculateY = false; } // end of line - if ( SpecialChars::isBreak(hl->ch, Cols > 1) || (outs)) + if (outs) { tabs.active = false; tabs.status = TabNONE; @@ -1786,9 +1883,22 @@ { // find end of line current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); current.finishLine(EndX); - + addLine = true; + current.startOfCol = false; + addLeftIndent = true; + if (hl->ch == SpecialChars::PARSEP) + { + maxDX = 0; + if (current.hasDropCap) + { + current.yPos = maxDY; + maxDY = 0; + current.hasDropCap = false; + } + } + // if (style.alignment() != 0) { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) @@ -1815,7 +1925,7 @@ { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); - double optiWidth = current.colRight - style.lineSpacing()/2.0 - current.line.x; + double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.line.x; if (current.line.naturalWidth > optiWidth) current.line.width = qMax(current.line.width - current.maxShrink, optiWidth); // simple offset @@ -1826,64 +1936,73 @@ } else // outs -- last char went outside the columns (or into flow-around shape) { - if (current.breakIndex >= 0) // Hier koenen auch andere Trennungen eingebaut werden + if (current.breakIndex > 0) // Hier koenen auch andere Trennungen eingebaut werden { - // go back to last break position -// qDebug() << QString("new break pos a=%1 BuPos=%2 current.breakIndex=%3").arg(a).arg(BuPos).arg(current.breakIndex); a = current.breakIndex; assert( a >= 0 ); assert( a < itemText.length() ); hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) + current.itemsInLine = a - current.line.firstItem + 1; + if (addLine) { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - current.itemsInLine = a - current.line.firstItem + 1; -// qDebug() << QString("style outs pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style <@%6: %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():"") -// .arg(a); + // go back to last break position + style = itemText.paragraphStyle(a); + chstr = ExpandToken(a+1); + { + const CharStyle curCharStyle = (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a+1) : itemText.paragraphStyle(a+1).charStyle()); + hlcsize10 = curCharStyle.fontSize() / 10.0; + scaleV = curCharStyle.scaleV()/1000.0; + offset = hlcsize10 * (curCharStyle.baselineOffset() /1000.0); + realAsce = curCharStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset; + if (current.startOfCol) + maxYAsc = static_cast<int>(floor(current.yPos - realAsce)); + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + realDesc = curCharStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset; + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + } + if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) + style.setLineSpacing(charStyle.font().height(hlcsize10)); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - if (hl->ch == ' ') { - hl->setEffects(hl->effects() | ScStyle_SuppressSpace); - hl->glyph.xadvance = 0; - } - - current.updateHeightMetrics(itemText); - current.updateLineOffset(itemText, style, firstLineOffset()); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (hl->ch == ' ') { + hl->setEffects(hl->effects() | ScStyle_SuppressSpace); + hl->glyph.xadvance = 0; + } -//??? current.breakXPos = current.line.x; -//??? for (int j=current.line.firstItem; j <= a; ++j) -//??? current.breakXPos += itemText.item(j)->glyph.wide(); - - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - // insert hyphen - current.hyphenCount++; - hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); - hl->glyph.grow(); - hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); - hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); - } - else - { - if (hl->ch != '-') - current.hyphenCount = 0; - hl->setEffects(hl->effects() & ~ScStyle_SmartHyphenVisible); - hl->glyph.shrink(); - } - - // Justification -// if (style.alignment() != 0) - { + current.updateHeightMetrics(itemText); + current.updateLineOffset(itemText, style, firstLineOffset()); + //current.xPos = current.breakXPos; + EndX = current.endOfLine(cl, pf2, rightMargin, maxYAsc, maxYDesc); + current.finishLine(EndX); + + hyphWidth = 0.0; + if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) + { + // insert hyphen + if (lastInRowLine) + //increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow + current.hyphenCount++; + hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); + hl->glyph.grow(); + hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); + hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); + hyphWidth = hl->glyph.more->xadvance; + } + else + { + if (hl->ch != '-') + current.hyphenCount = 0; + hl->setEffects(hl->effects() & ~ScStyle_SmartHyphenVisible); + hl->glyph.shrink(); + } + + // Justification if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.width += opticalRightMargin(itemText, current.line); + else + current.line.naturalWidth += hyphWidth; OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -1891,229 +2010,143 @@ if (style.alignment() == ParagraphStyle::Centered) OFs = (current.line.width - current.line.naturalWidth) / 2; - if ((style.alignment() == ParagraphStyle::Justified) - || (style.alignment() == ParagraphStyle::Extended)) - { + if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended)) justifyLine(itemText, current.line); - } else { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } -// qDebug() << QString("line: endx=%1 next pos=(%2,%3").arg(EndX).arg(current.line.x + current.line.width).arg(current.yPos); current.xPos = current.line.x + current.line.width; } } - else // no break position +// else // no break position +// { +// if (a >= current.line.firstItem) +// { +// current.itemsInLine = 0; +// a = current.line.firstItem - 1; +// } +// if (a >= 0) +// { +// hl = itemText.item(a); +// style = itemText.paragraphStyle(a); +// if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) +// style.setLineSpacing(charStyle.font().height(charStyle.fontSize() / 10.0)); +// else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) +// style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); +// } +// } + } + if (inOverflow) + current.xPos = realEnd; + + //line break or end of column + if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) + && current.hasDropCap) + { + current.hasDropCap = false; + if (current.yPos < maxDY) + current.yPos = maxDY; + maxDX = 0; + } + if ( SpecialChars::isBreak(hl->ch) ) + { + if (hl->ch == SpecialChars::PARSEP) + current.yPos += style.gapAfter(); + current.hyphenCount = 0; + } + if (current.isEndOfCol(desc)) + { + //check if realy line extends bottom margin + current.updateHeightMetrics(itemText); + if (current.isEndOfCol(current.line.descent)) { - if (a >= current.line.firstItem) + if (current.itemsInLine == 0 || current.column+1 == Cols) { - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - current.itemsInLine = 0; - a = current.line.firstItem - 1; - } - else - { - --a; - --current.itemsInLine; - } + goNoRoom = true; + MaxChars = a + 1; + break; } - if (a >= 0) - { - hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - } - current.breakLine(itemText, style, firstLineOffset(), a); -// qDebug() << QString("style no break pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style nb @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); -// qDebug() << QString("no break pos: %1-%2 @ %3 wid %4 nat %5 endX %6") -// .arg(current.line.firstItem).arg(current.line.firstItem) -// .arg(current.line.x).arg(current.line.width).arg(current.line.naturalWidth).arg(EndX); - indentLine(itemText, current.line, 0); + goNextColumn = true; } } - if ( outs || SpecialChars::isBreak(hl->ch, (Cols > 1)) ) + if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0) { - if (outs && !current.isEndOfLine(hl->glyph.wide() + style.rightMargin())) + if (addLine) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) - && current.hasDropCap) + if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) { - current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcaps: y=%1 maxDY=%2").arg(current.yPos).arg(maxDY); + // put line back to top + current.line.y -= DropCapDrop; + itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - bool fromOut = true; - double BotOffset = desc+extra.Bottom+lineCorr; - while (!current.isEndOfLine(style.rightMargin())) + fillInTabLeaders(itemText, current.line); + //if right margin is set we temporally save line, not append it + itemText.appendLine(current.line); + restartIndex = current.line.lastItem +1; + a = restartIndex -1; + currentRowDesc = qMax(currentRowDesc,current.yPos + current.line.descent); + if (!lastInRowLine) { - current.xPos++; - if (current.isEndOfLine(style.rightMargin())) + restartX = current.xPos; + if (addLeftIndent) { - fromOut = false; -// qDebug() << QString("layout: next lower2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("nextline: y=%1+%2").arg(current.yPos).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing? m_Doc->typographicSettings.valueBaseGrid : style.lineSpacing()); - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - else - current.yPos += style.lineSpacing(); - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 1: %1").arg(a)); - break; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if (SpecialChars::isBreak(hl->ch)) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } - break; + addLeftIndent = false; + wasFirstInRow = true; } - // #7944 : Do not use static_cast<int> here, this is not consistent with computations - // performed at lines 1488-1512 and can trigger hang due to changing region detection - //pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); - //pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); - pt1 = QPoint(qRound(current.xPos+extra.Right), qRound(current.yPos+BotOffset)); - pt2 = QPoint(qRound(current.xPos+extra.Right), qRound(ceil(current.yPos-asce))); - if (cl.contains(pf2.map(pt1)) && cl.contains(pf2.map(pt2))) - break; -// else -// qDebug() << QString("looking for start of line at %1,%2").arg(current.xPos).arg(current.yPos); } - if (fromOut) - { - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 2: %1").arg(a); - break; - } - current.xPos--; - current.xPos = qMax(current.xPos, current.colLeft); - } } - else +// else if (!addRightMargin) +// { +// current.xPos = restartX = realEnd +1; +// restartIndex = a +1; +// } + } + if (addLine && lastInRowLine) + { + recalculateY = true; + wasFirstInRow = false; + addLeftIndent = true; + inOverflow = false; + outs = false; + current.startOfCol = false; + restartX = current.xPos = qMax(maxDX, current.colLeft); + lastLineY = currentRowDesc; + if (current.hasDropCap) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK ) - && current.hasDropCap) + ++DropLinesCount; + if (DropLinesCount >= DropLines) { current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcap2: y=%1+%2").arg(current.yPos).arg(maxDY); + restartX = current.xPos = current.colLeft; + maxDX = 0; } -// qDebug() << QString("layout: next lower3 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { -// qDebug() << QString("next line (grid): y=%1+%2").arg(current.yPos).arg(m_Doc->typographicSettings.valueBaseGrid); - - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - } - else - { -// qDebug() << QString("next line (auto): y=%1+%2").arg(current.yPos).arg(style.lineSpacing()); - //#5845 : use next paragraph line spacing for switching to next paragraph instead of current one - //current.yPos += style.lineSpacing(); - const ParagraphStyle& pStyle = itemText.paragraphStyle(a+1); - double lineSpacing = pStyle.lineSpacing(); - if (pStyle.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - lineSpacing = pStyle.charStyle().font().height(pStyle.charStyle().fontSize() / 10.0); - else if (pStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - lineSpacing = m_Doc->typographicSettings.valueBaseGrid; - current.yPos += lineSpacing; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if ( SpecialChars::isBreak(hl->ch) ) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } } + lastLineY = currentRowDesc; + mustLineEnd = current.colRight; + restartRowIndex = restartIndex; } - - - // calc. needed vertical space - // Let’s try to change into "calc. _wanted_ vertical space" - pm - if (current.itemsInLine != 0) + if (inOverflow) { - if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) - { - // put line back to top - current.line.y -= DropCapDrop; - itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; - } + afterOverflow = true; + inOverflow = false; + addLeftIndent = false; + recalculateY = false; } - - fillInTabLeaders(itemText, current.line); - - current.startOfCol = false; -// qDebug() << QString("layout: line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - if (current.line.firstItem > current.line.lastItem) - ; //qDebug() << QString("layout: empty line %1 - %2").arg(current.line.firstItem).arg(current.line.lastItem); - else if (current.itemsInLine > 0) - itemText.appendLine(current.line); + else + { + afterOverflow = false; + } + outs = false; + addLine = false; + lastInRowLine = false; current.startLine(a+1); - outs = false; if (goNoRoom) { goNoRoom = false; MaxChars = a+1; -// qDebug() << QString("no room C: %1").arg(a+1); goto NoRoom; } if (goNextColumn) @@ -2122,12 +2155,18 @@ current.column++; if (current.column < Cols) { - current.nextColumn(asce); + if (firstLineOffset() == FLOPRealGlyphHeight) + asce = 0; + current.nextColumn(); + mustLineEnd = current.colRight; + addLeftIndent = true; + lastLineY = extra.Top; + currentRowDesc = 0; + recalculateY = true; } else { MaxChars = a; -// qDebug() << QString("no room D: %1").arg(a); goto NoRoom; } } @@ -2139,18 +2178,35 @@ goto NoRoom; } // end of itemText - int a = itemText.length()-1; - hl = a >=0 ? itemText.item(a) : NULL; - current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (current.itemsInLine >0) + { + int a = itemText.length()-1; + hl = a >=0 ? itemText.item(a) : NULL; + current.breakLine(itemText, style, firstLineOffset(), a); -// if (style.alignment() != 0) - { + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) + { + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) + { + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); + } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); + current.finishLine(EndX); + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - { current.line.width += opticalRightMargin(itemText, current.line); - } OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -2174,26 +2230,19 @@ current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } - } - - if (current.itemsInLine != 0) - { if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap ) { // put line back to top current.line.y -= DropCapDrop; itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - } - fillInTabLeaders(itemText, current.line); - current.startOfCol = false; - goNextColumn = false; + fillInTabLeaders(itemText, current.line); + current.startOfCol = false; + goNextColumn = false; -// qDebug() << QString("layout: last line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - - if (current.itemsInLine > 0) { + assert(current.line.firstItem <0); itemText.appendLine(current.line); + current.startOfCol = false; } } MaxChars = itemText.length(); @@ -3310,7 +3359,6 @@ void PageItem_TextFrame::setNewPos(int oldPos, int len, int dir) { - bool isSpace, wasSpace; if ( dir > 0 && oldPos < len ) { @@ -3563,8 +3611,6 @@ } -#endif //NLS_PROTO - bool PageItem_TextFrame::createInfoGroup(QFrame *infoGroup, QGridLayout *infoGroupLayout) { int Parag = 0; |
|
|
|
|
|
|
|
Seems to work well enough, however crash directly when trying to type in an empty text frame : Scribus.exe!PageItem_TextFrame::layout() Line 2243 Scribus.exe!DocUpdater::changed(PageItem * it=0x06ed3628, bool layout=true) Line 148 + 0x12 bytes Scribus.exe!MassObservable<PageItem *>::updateNow(UpdateMemento * what=0x06e81b18) Line 270 + 0x1d bytes Scribus.exe!MassObservable<PageItem *>::updateLayout(PageItem * what=0x06ed3628) Line 260 + 0x12 bytes Scribus.exe!SingleObservable<PageItem>::updateLayout() Line 183 + 0x30 bytes Scribus.exe!PageItem_TextFrame::handleModeEditKey(QKeyEvent * k=0x0018d4c8, bool & keyRepeat=true) Line 3321 + 0x13 bytes Scribus.exe!ScribusMainWindow::keyPressEvent(QKeyEvent * k=0x0018d4c8) Line 1869 + 0x22 bytes Scribus.exe!ScribusView::eventFilter(QObject * obj=0x0685e040, QEvent * event=0x0018d4c8) Line 4846 + 0x1b bytes QtCored4.dll!QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject * receiver=0x0685e040, QEvent * event=0x0018d4c8) Line 846 + 0x15 bytes |
|
Another crash when typing into text frame after commenting out line 2243. The crash seems to occur when line break occurs just after the end of a word : Scribus.exe!StoryText::text(int pos=72) Line 534 Scribus.exe!PageItem::ExpandToken(unsigned int base=72) Line 1761 Scribus.exe!PageItem_TextFrame::layout() Line 1950 + 0x19 bytes Scribus.exe!DocUpdater::changed(PageItem * it=0x07d2dd88, bool layout=true) Line 148 + 0x12 bytes Scribus.exe!MassObservable<PageItem *>::updateNow(UpdateMemento * what=0x05f0b9d8) Line 270 + 0x1d bytes Scribus.exe!MassObservable<PageItem *>::updateLayout(PageItem * what=0x07d2dd88) Line 260 + 0x12 bytes Scribus.exe!SingleObservable<PageItem>::updateLayout() Line 183 + 0x30 bytes Scribus.exe!PageItem_TextFrame::handleModeEditKey(QKeyEvent * k=0x0018d4c8, bool & keyRepeat=true) Line 3321 + 0x13 bytes Scribus.exe!ScribusMainWindow::keyPressEvent(QKeyEvent * k=0x0018d4c8) Line 1869 + 0x22 bytes Scribus.exe!ScribusView::eventFilter(QObject * obj=0x07ab38c8, QEvent * event=0x0018d4c8) Line 4846 + 0x1b bytes |
|
I do not get those crashes on openSUSE 11.4 64bit with Qt 4.7.4. What I do get is missing text, when the line wraps occur. The typed text is visible in the Story Editor |
2011-09-11 15:57 viewer |
|
|
|
|
formatting2.patch (82,000 bytes)
Index: Version135/Scribus/scribus/pageitem_textframe.cpp =================================================================== --- Version135/Scribus/scribus/pageitem_textframe.cpp (wersja 16820) +++ Version135/Scribus/scribus/pageitem_textframe.cpp (kopia robocza) @@ -70,7 +70,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -83,7 +82,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -155,9 +153,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - { - result = result.subtract(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); - } + result = result.subtracted(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -192,7 +188,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - result = result.subtract(itemShape(docItem, 0, 0)); + result = result.subtracted(itemShape(docItem, 0, 0)); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -202,7 +198,6 @@ return result; } - void PageItem_TextFrame::setShadow() { if (OnMasterPage.isEmpty()) @@ -235,10 +230,6 @@ currentShadow = newShadow; } } - -#ifdef NLS_PROTO -#include "text/pageitem_textframe.cpp" -#else static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->")) { @@ -258,7 +249,6 @@ dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } - static const bool legacy = true; /* @@ -373,22 +363,23 @@ } /// move position to next column - void nextColumn(double asce) + void nextColumn(double asce = 0.0) { startOfCol = true; colLeft = (colWidth + colGap) * column + insets.Left + lineCorr; + //now colRight is REAL column right edge colRight = colLeft + colWidth; if (legacy) - colRight += insets.Right + lineCorr; //??? + colRight += lineCorr; xPos = colLeft; - yPos = asce + insets.Top + lineCorr + 1; + yPos = asce + insets.Top + lineCorr; } bool isEndOfCol(double morespace = 0) { return yPos + morespace + insets.Bottom + lineCorr > frameHeight; } - + /** init fields for a new line at current position */ @@ -398,7 +389,8 @@ line.x = xPos; line.y = yPos; line.firstItem = first; - line.ascent = 10; + line.lastItem = 0; + line.ascent = 0; line.descent = 0; line.width = 0; line.naturalWidth = 0; @@ -407,6 +399,7 @@ breakXPos = 0; maxShrink = 0; maxStretch = 0; + width = 0; } @@ -423,12 +416,12 @@ } /// called when a possible break is passed - void rememberBreak(int index, double pos) + void rememberBreak(int index, double pos, double morespace = 0) { - if (pos > colRight) + if (pos > colRight - morespace) { // only look for the first break behind the right edge - maxShrink = 0; + //maxShrink = 0; // check if we already have a better break if (breakIndex >= 0) @@ -439,12 +432,8 @@ if (newLooseness >= oldLooseness) return; } - breakXPos = colRight; } - else - { - breakXPos = pos; - } + breakXPos = pos; breakIndex = index; } @@ -460,9 +449,9 @@ // so that endOfLine() returns correct result updateHeightMetrics(itemText); // #9060 : update line offset too - updateLineOffset(itemText, style, offsetPolicy); + //updateLineOffset(itemText, style, offsetPolicy); } - + /// use the last remembered break to set line width and itemrange void finishLine(double endX) { @@ -471,109 +460,44 @@ line.width = endX - line.x; maxShrink = maxStretch = 0; } - - + bool isEndOfLine(double moreSpace = 0) { + bool res; if (legacy) - return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight; + res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight); else - return xPos + moreSpace - maxShrink >= colRight; + res = ceil(xPos - maxShrink) + ceil(moreSpace) >= floor(colRight); + return res; } - - /// find x position to start current line - double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace) - { - QPoint pt1, pt2; - double tmpX = xPos; - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - // increase pt1/pt2 until i-beam reaches end of line - while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2)))) - { - tmpX++; - if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight) - { - return tmpX; - } - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - } - return tmpX; - } - + /// find x position where this line must end - double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace = 0) + double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace, int Yasc, int Ydesc) { - // Keep old code for reference - /*double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - QPoint pt1, pt2; - // qDebug() << QString("endx start=%1, hl is '%2'").arg(EndX).arg(hl->ch); - do { - EndX += 0.125; - pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent)); - pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent))); - } while ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace) - && shape.contains(pf2.map(pt1)) - && shape.contains(pf2.map(pt2)) - );*/ - // if we aren't restricted further, we'll end at this maxX: double maxX = colRight - morespace; - if (legacy) maxX -= (lineCorr + insets.Right); + if (legacy) maxX -= lineCorr; - double StartX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - int xPos = static_cast<int>(ceil(maxX + insets.Right)); - int yDesc = static_cast<int>(yPos+line.descent); - int yAsc = static_cast<int>(ceil(yPos-line.ascent)); + double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1); + int xPos = static_cast<int>(ceil(maxX)); - QPoint pt12 (xPos, yDesc); - QPoint pt22 (xPos, yAsc); + QPoint pt12 (xPos, Yasc); + QPoint pt22 (xPos, Ydesc); + QRect pt(pt12,pt22); - // simple and fast case: transformed line completely falls within range - // this will happen if we don't wrap around anything - ie. very often - QPolygon p; - p.append (pf2.map (QPoint (StartX, yAsc))); - p.append (pf2.map (QPoint (StartX, yDesc))); - p.append (pf2.map (pt12)); - p.append (pf2.map (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.numRects() == 1) - { - int xPos = qRound(ceil(StartX + 0.125 + insets.Right)); - pt12.setX(xPos); - pt22.setX(xPos); - if (shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))) - { - QRect rect = lineI.rects().at(0); - double mx = qMax(rect.left(), rect.right()) - pf2.dx(); - int steps = static_cast<int>((mx - StartX - insets.Right - 2)/0.125); - if (steps > 0) - StartX += steps * 0.125; - } - } - - // qDebug()<<"endOfLine: going for the hard case"; double EndX2 = StartX; - double Interval = 0.125; + double Interval = 0.25; do { + int xP = static_cast<int>(ceil(EndX2 + morespace)); + pt.moveTopLeft(QPoint(xP, Yasc)); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()) + break; EndX2 += Interval; - int xPos = qRound(ceil(EndX2 + insets.Right)); - pt12.setX (xPos); - pt22.setX (xPos); - } while ((EndX2 < maxX) && shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))); + } while ((EndX2 < maxX) && QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()); - /*if (EndX!=EndX2) - { - qDebug()<<EndX<<EndX2<<StartX<<maxX; - qDebug()<<"DIFFERING ENDX!!!!!"; - }*/ - return EndX2; + return qMin(EndX2, maxX); } - - + double getLineAscent(const StoryText& itemText) { double result = 0; @@ -684,15 +608,18 @@ || (ch == SpecialChars::LINEBREAK) || (ch.isSpace())) continue; const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc)); + double scaleV = cStyle.scaleV() / 1000.0; + double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0); + if (itemText.object(line.firstItem+zc) != 0) { - asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0); + asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset; desc = 0.0; } else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0) { - asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0); - desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0); + asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset; + desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset; } // qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result); line.ascent = qMax(line.ascent, asce); @@ -700,44 +627,47 @@ } } - void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) - { - if (itemsInLine <= 0) - return; - if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) - { - //FIXME: use glyphs, not chars - double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).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.firstItem); - double firstasce = style.lineSpacing(); - double currasce = getLineHeight(itemText); - double adj = firstasce - currasce; -// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); - line.ascent = currasce; - line.y -= adj; - yPos -= adj; - } - } +// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!! +// +// void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) +// { +// if (itemsInLine <= 0) +// return; +// if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) +// { +// //FIXME: use glyphs, not chars +// double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0); +// double adj (0.0); +// double currasce (this->getLineAscent(itemText)); +// if( offsetPolicy == FLOPRealGlyphHeight ) +// { +// adj = line.y - insets.Top -currasce; +// //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.firstItem); +// double firstasce = style.lineSpacing(); +// double currasce = getLineHeight(itemText); +// double adj = firstasce - currasce; +//// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); +// line.ascent = currasce; +// line.y -= adj; +// yPos -= adj; +// } +// } private: double frameWidth; @@ -802,8 +732,11 @@ .arg(style.minWordTracking()).arg(style.minGlyphExtension()); */ + int startItem = line.firstItem; + if (itemText.item(startItem)->effects() & ScStyle_DropCap) + startItem++; // distribute whitespace on spaces and glyphs - for (int yof = line.firstItem; yof <= line.lastItem; ++yof) + for (int yof = startItem; yof <= line.lastItem; ++yof) { double wide = itemText.item(yof)->glyph.wide(); if (!SpecialChars::isExpandingSpace(itemText.text(yof))) @@ -839,46 +772,42 @@ } } -/// calculate how much the first char should stick out to the left -static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) -{ - int b = line.firstItem; - while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace)) - ++b; +//definied but not used +///// calculate how much the first char should stick out to the left +//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) +//{ +// int b = line.firstItem; +// while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_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; -} +// 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); +// } +// return leftCorr; +//} - - /// calculate how much the last char should stick out to the right static double opticalRightMargin(const StoryText& itemText, const LineSpec& line) { @@ -923,10 +852,15 @@ return 0.0; } +static double findRealOverflowEnd(const QRegion& shape, const QMatrix& pf2, QRect pt, double maxX) +{ + while (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty() && pt.right() < maxX) + pt.translate(1, 0); + if (pt.right() >= maxX) + return maxX; + return pt.left() +0.5; +} - - - void PageItem_TextFrame::layout() { // qDebug()<<"==Layout==" << itemName() ; @@ -957,10 +891,9 @@ firstChar = 0; // qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame()); -// ScribusView* view = m_Doc->view(); QMatrix pf2; QPoint pt1, pt2; - /*QRegion cm;*/ + QRect pt; double chs, chsd = 0; double oldCurY, EndX, OFs, wide, kernVal; QString chstr; @@ -969,7 +902,6 @@ int /*ParagraphStyle::OpticalMarginType*/ opticalMargins = ParagraphStyle::OM_None; bool outs = false; - bool fBorder = false; bool goNoRoom = false; bool goNextColumn = false; @@ -983,12 +915,12 @@ tTabValues.clear(); bool DropCmode = false; - double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0; + double desc=0, asce=0, realAsce=0, realDesc = 0; + double maxDY=0, maxDX=0; double DropCapDrop = 0; int DropLines = 0; int DropLinesCount = 0; - itemText.clearLines(); double lineCorr = 0; @@ -1006,7 +938,11 @@ current.init(Width, Height, extra, lineCorr); current.initColumns(columnWidth(), ColGap); current.hyphenCount = 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, currentRowDesc = 0; + // dump styles /* for (int i=0; i < itemText.nrOfParagraphs(); ++i) { @@ -1018,7 +954,6 @@ dumpIt(itemText.defaultStyle()); */ -// pf2.begin(view->viewport()); pf2.translate(Xpos, Ypos); pf2.rotate(Rot); @@ -1044,7 +979,8 @@ pf2.scale(1, -1); } - current.nextColumn(0); + current.nextColumn(); + lastLineY = extra.Top; // find start of first line if (firstInFrame() < itemText.length()) @@ -1070,19 +1006,35 @@ } else chs = hl->fontSize(); - desc2 = -hl->font().descent(chs / 10.0); + desc = -hl->font().descent(chs / 10.0); current.yPos = extra.Top + lineCorr; // qDebug() << QString("first line at y=%1").arg(current.yPos); } else // empty itemText: { - desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); - current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; + desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); + current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc; } current.startLine(firstInFrame()); + outs = false; OFs = 0; MaxChars = 0; + bool inOverflow = false; + bool afterOverflow = false; + bool addLine = false; + bool recalculateY = true; + bool lastInRowLine = false; + bool addLeftIndent = true; + bool wasFirstInRow = false; + double leftIndent = 0; + double rightMargin = 0.0; + double mustLineEnd = current.colRight; + int restartIndex = firstInFrame(); //index of char where line computing should be restarted + int restartRowIndex = firstInFrame(); //index of char where row of text is started + double restartX = 0; //starting X position of line if must be restarted + double realEnd = 0; + for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a); @@ -1091,27 +1043,17 @@ if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); -// qDebug() << QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); const CharStyle& charStyle = (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle()); - if (!charStyle.parent().isEmpty()) - { -// qDebug() << QString("charstyle pos %1: %2 (%3 %4 %5 %6 %7 %8 %9)").arg(a).arg(charStyle.parent()) -// .arg((uint)charStyle.parentStyle()).arg(charStyle.font().scName()).arg(charStyle.fontSize()) -// .arg(charStyle.fillColor()).arg(charStyle.strokeColor()).arg(charStyle.parentStyle()->name()).arg((uint)charStyle.parentStyle()->parentStyle()); - } -// qDebug() << QString("charstyle pos %1: %2 (%3)").arg(a).arg(charStyle.asString()).arg(charStyle.fontSize()); -// qDebug() << QString("style @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); + chstr = ExpandToken(a); + 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); - chstr = ExpandToken(a); -// qDebug() << QString("expanded token: '%1'").arg(chstr); if (chstr.isEmpty()) chstr = SpecialChars::ZWNBSPACE; if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); // find out about par gap and dropcap @@ -1119,7 +1061,6 @@ { if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP) { - current.yPos += style.gapBefore(); if (chstr[0] != SpecialChars::PARSEP) { DropCmode = style.hasDropCap(); @@ -1165,21 +1106,34 @@ else hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); } - // qDebug() << QString("textframe(%1,%2): len=%3, fontsize=%4, ascent=%5").arg(Xpos).arg(Ypos).arg(itemText.length()) -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()); if (current.itemsInLine == 0) { - // more about par gap and dropcaps - if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && !current.startOfCol)) // after || always evaluates to false? FIXME + if (style.rightMargin() == 0) { -// qDebug() << QString("gap before2: y=%1+%2").arg(current.yPos).arg(style.gapBefore()); - current.yPos += style.gapBefore(); + addLine = true; + rightMargin = 0.0; + } + else + { + if (lastInRowLine) + rightMargin = style.rightMargin(); + else + rightMargin = 0.0; + } + current.breakIndex = -1; + if (current.startOfCol && !afterOverflow && recalculateY) + current.yPos = qMax(current.yPos,extra.Top); + // more about par gap and dropcaps + if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol)) + { + if (!afterOverflow && recalculateY && !current.startOfCol) + current.yPos += style.gapBefore(); DropCapDrop = 0; if (chstr[0] != SpecialChars::PARSEP) DropCmode = style.hasDropCap(); else DropCmode = false; - if (DropCmode) + if (DropCmode && !afterOverflow) { DropLines = style.dropCapLines(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1189,35 +1143,22 @@ if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) DropCapDrop = style.lineSpacing() * (DropLines-1); else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); + DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines-1); } -// qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop); - current.yPos += DropCapDrop; } } } - // find charsize & y pos +// ######## find charsize factors if (DropCmode) { - // dropcap active? - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); - else - { - if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - DropCapDrop = style.lineSpacing() * (DropLines-1); - else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); - } - // FIXME : we should ensure that fonts are loaded before calls to layout() // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap() // ScFace::ascent() can be called safely afterwards double realCharHeight = charStyle.font().realCharHeight(chstr[0], 1); double realCharAscent = charStyle.font().realCharAscent(chstr[0], 1); - double fontAscent = charStyle.font().ascent(style.charStyle().fontSize() / 10.0); + double fontAscent = charStyle.font().ascent(hlcsize10); if (realCharHeight == 0.0) - realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); + realCharHeight = charStyle.font().height(hlcsize10); if (realCharAscent == 0.0) realCharAscent = fontAscent; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1234,7 +1175,7 @@ } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(hlcsize10); chsd = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharHeight)); chs = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharAscent)); } @@ -1249,7 +1190,7 @@ else chs = charStyle.fontSize(); } - // find tracking +// ######## set StartOfLine (and find tracking?) if (current.itemsInLine == 0) { itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine); @@ -1262,7 +1203,8 @@ } hl->glyph.yadvance = 0; oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); - // find out width of char + +// ######## find out width, ascent and descent of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1290,168 +1232,177 @@ itemHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - asce = m_Doc->typographicSettings.valueBaseGrid * DropLines; + realAsce = m_Doc->typographicSettings.valueBaseGrid * DropLines; else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - asce = style.lineSpacing() * DropLines; + realAsce = style.lineSpacing() * DropLines; else - asce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; + realAsce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; } hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / itemHeight); + hl->glyph.scaleV = (realAsce / itemHeight); hl->glyph.scaleH *= hl->glyph.scaleV; } else { - double realCharHeight = charStyle.font().realCharHeight(chstr[0], charStyle.fontSize() / 10.0); + double realCharHeight = charStyle.font().realCharHeight(chstr[0], hlcsize10); if (realCharHeight == 0) realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); - wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0); - asce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0); -// qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); + wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0) * scaleH +1; //dropcaps are always to close to next glyphs + realAsce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0) * scaleV + offset; + asce = charStyle.font().ascent(hlcsize10); + // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / realCharHeight); + hl->glyph.scaleV = (realAsce / realCharHeight); hl->glyph.scaleH *= hl->glyph.scaleV; + hl->glyph.xoffset -= 0.5; //drop caps are always to far from column left edge } hl->glyph.xadvance = wide; - desc2 = 0; - desc = 0; + desc = realDesc =0; } else // !DropCMode { -// qDebug( ) << QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent()); - if (SpecialChars::isExpandingSpace(hl->ch)) { double wordtracking = charStyle.wordTracking(); hl->glyph.xadvance *= wordtracking; wide *= wordtracking; } - // find ascent / descent - double hlcsize10=charStyle.fontSize() / 10.0; if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) - { - desc = desc2 = 0; - } + desc = realDesc = 0; else { - desc = desc2 = -charStyle.font().descent(hlcsize10); + desc = -charStyle.font().descent(hlcsize10); + realDesc = charStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset; current.rememberShrinkStretch(hl->ch, wide, style); } asce = charStyle.font().ascent(hlcsize10); -// wide = wide * hl->glyph.scaleH; + realAsce = charStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset; } - fBorder = false; - // end of col reached? -// qDebug() << QString("eocol? %1 + %2 + %3 > %4 -- asce=%5").arg(current.yPos).arg(extra.Bottom).arg(lineCorr).arg(Height).arg(asce); - if (current.isEndOfCol()) + +// ######## check for Y position at beginning of line + if (current.itemsInLine == 0 && !afterOverflow) { - current.column++; - if (current.column < Cols) + if (recalculateY) { - // start next col - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) - || ((a == firstInFrame()) && (BackBox == 0))) + //if top of column Y position depends on first line offset + if (current.startOfCol) { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) + lastLineY = qMax(lastLineY, extra.Top + lineCorr); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); + if (firstLineOffset() == FLOPRealGlyphHeight) + { + if (DropCmode) + current.yPos += asce; + else + current.yPos += realAsce; + } + else if (firstLineOffset() == FLOPLineSpacing) + current.yPos += style.lineSpacing(); else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); + current.yPos += asce; } - if (DropCmode) - DropLines = style.dropCapLines(); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + if (current.yPos <= lastLineY) + current.yPos = lastLineY +1; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } } -// qDebug() << QString("layout: nextcol grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + else { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + current.yPos += m_Doc->typographicSettings.valueBaseGrid; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } + else + current.yPos += style.lineSpacing(); } + if (DropCmode) + current.yPos += DropCapDrop; } - else + //set left indentation + leftIndent = 0.0; + if (addLeftIndent && (maxDX == 0 || DropCmode)) { - MaxChars = a; -// qDebug() << QString("no room A: %1").arg(a); - goto NoRoom; + leftIndent = style.leftMargin(); + if (current.hasDropCap) + leftIndent = 0; + if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))) + leftIndent += style.firstIndent(); + addLeftIndent = false; } } - // ok, there's more room in col - if (current.itemsInLine == 0) + recalculateY = true; + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) { -// qDebug() << QString("newline: '%1' %2 %3").arg(a).arg(current.yPos).arg(asce); - // start a new line - double TopOffset = asce; - double BotOffset = desc2; - goNoRoom = false; - if (current.startOfCol) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { -// qDebug() << QString("current.startOfCol: %1 + %2 + %3 + 1 =%4").arg(asce).arg(extra.Top).arg(lineCorr).arg(asce + extra.Top + lineCorr + 1); - current.yPos = asce + extra.Top + lineCorr + 1; -// if (((a > 0) && (itemText.at(a-1)->ch == QChar(13))) || ((a == 0) && (BackBox == 0))) -// current.yPos += m_Doc->docParagraphStyles[hl->cab].gapBefore; + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } -// qDebug() << QString("layout: nextline grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + if (current.itemsInLine == 0 && !afterOverflow) + { + //start a new line + goNoRoom = false; + + // find line`s start + pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc); + pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc); + 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; + while (!done) { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("useBaselIneGrid: %1 * %2 + %3 - %4").arg(ol2 / 10000.0).arg(m_Doc->typographicSettings.valueBaseGrid).arg(m_Doc->typographicSettings.offsetBaseGrid).arg(by); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } - /* this causes different spacing for first line: - if (current.yPos-TopOffset < 0.0) - { - qDebug(= << QString("current.yPos - Ascender < 0 (%1 - %2 < 0)").arg(current.yPos).arg(TopOffset); - current.yPos = TopOffset+1; - } - */ - // find linelength: - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); - // increase pt1/pt2 until i-beam reaches end of line -// qDebug() << QString("linestart: %1 + %2 + %3 < %4").arg(current.xPos).arg(wide).arg(style.rightMargin()).arg(current.colRight); - double leftIndent = 0; - double xStep = legacy? 1 : 0.125; - while (!cl.contains(pf2.map(pt1)) || !cl.contains(pf2.map(pt2)) || current.isEndOfLine(wide + leftIndent + style.rightMargin())) - { - fBorder = true; - current.xPos += xStep; - if (current.isEndOfLine(wide + leftIndent + style.rightMargin())) + Xpos = current.xPos; + Xend = current.xPos + leftIndent; + //check if in indent any overflow occurs + while (Xpos <= Xend && Xpos < current.colRight) { -// qDebug() << QString("eocol %5? %1 + %2 + %3 + %4").arg(current.yPos).arg(current.startOfCol).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(style.lineSpacing()).arg(current.column); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + Xpos = current.xPos = realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + Xend = current.xPos + leftIndent; + } + else + Xpos++; + pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc)); + } + current.xPos = Xend; + done = true; + if (current.isEndOfLine((style.minGlyphExtension() * wide) + rightMargin + leftIndent)) + { // new line - fBorder = false; - current.xPos = current.colLeft; - - leftIndent = style.leftMargin(); - if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) - leftIndent += style.firstIndent(); - - if (current.startOfCol) - current.yPos++; - else - current.yPos += qMax(style.lineSpacing(), 1.0); -// qDebug() << QString("layout: next lower line grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); + current.xPos = qMax(current.colLeft, maxDX); + current.yPos ++; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { double by = Ypos; @@ -1459,83 +1410,113 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; } - if (current.isEndOfCol()) + lastLineY = maxYAsc +1; + if (current.startOfCol) { - fBorder = false; - current.column++; - if (current.column < Cols) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == firstInFrame()) && (BackBox == 0))) - { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) - { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); - else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); - } - if (DropCmode) - DropLines = style.dropCapLines(); - } -// qDebug() << QString("layout: nextcol2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } - else - { - MaxChars = a; -// qDebug() << QString("no room B: %1").arg(a); - goto NoRoom; - } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc)); + done = false; } - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); + if (current.isEndOfCol(realDesc)) + { + current.column++; + if (current.column < Cols) + { + newColumn = true; + break; + } + else + { + MaxChars = a; + goto NoRoom; + } + } } - - if (((fBorder)) && (!current.hasDropCap)) - current.xPos += extra.Left; - // indent first line of par - if (a > 0) + if (newColumn) { - if (itemText.text(a-1) == SpecialChars::PARSEP) - current.xPos += style.firstIndent(); + current.nextColumn(); + mustLineEnd = current.colRight; + restartX = current.xPos; + lastLineY = current.yPos; + currentRowDesc = 0; + a--; + recalculateY = true; + addLeftIndent = true; + continue; } + current.line.x = restartX = current.xPos; + current.line.y = current.yPos; + } + + //check if line must start at new Y position due to current glyph height or previous line descent + if (!SpecialChars::isBreak(hl->ch, true) + && !SpecialChars::isBreakingSpace(hl->ch) + && !SpecialChars::isExpandingSpace(hl->ch) + && hl->ch != SpecialChars::TAB) + { + double diff = 0; + if (current.startOfCol || DropCmode) + diff = realAsce * scaleV + offset - (current.yPos - lastLineY); else + diff = charStyle.font().realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY); + if (diff >= 1 || (!DropCmode && diff > 0)) { - if (legacy) - current.xPos += style.firstIndent(); + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + current.yPos = maxDY; + maxDX = 0; + } + int linesDrop = 0; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + linesDrop = ceil(diff/m_Doc->typographicSettings.valueBaseGrid); + current.yPos += m_Doc->typographicSettings.valueBaseGrid * linesDrop; + } + else /*if (current.startOfCol)*/ + { + 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; + } + } + recalculateY = false; + current.xPos = current.colLeft; + a = restartRowIndex -1; + current.startLine(a+1); + addLeftIndent = true; + afterOverflow = false; + continue; } - // add left margin - if (!current.hasDropCap) - current.xPos += style.leftMargin(); - if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct) { - current.xPos += opticalLeftMargin(itemText, current.line); - } -// qDebug() << QString("store line: (%1,%2)").arg(current.xPos).arg(current.yPos); - current.line.x = current.xPos; - current.line.y = current.yPos; - fBorder = false; } - else { -// qDebug() << QString("cont.' line: '%1'").arg(a); - } // right tab stuff if (tabs.active) { @@ -1589,7 +1570,6 @@ current.xPos = current.colLeft + tCurX; // remember fill char -// qDebug() << QString("tab: %1 '%2'").arg(tCurX).arg(tabs.fillChar); if (!tabs.fillChar.isNull()) { hl->glyph.growWithTabLayout(); TabLayout * tglyph = dynamic_cast<TabLayout*>(hl->glyph.more); @@ -1614,7 +1594,6 @@ if (DropCmode) hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0); - // remember x pos double breakPos = current.xPos; @@ -1630,57 +1609,179 @@ else // other tabs.active { current.xPos = qMax(current.xPos, current.colLeft); - } - - //FIXME: asce / desc set correctly? - if (legacy && - (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) - || hl->ch == SpecialChars::SHYPHEN)) + } + // remember possible break + if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB)) { - if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(ceil(current.yPos-asce))); + current.rememberBreak(a, breakPos, style.rightMargin()); } - else - { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); - } } - else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + //check against space before PARSEP + if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP)) { - pt1 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); + a++; + hl = itemText.item(a); } - else + + // test if end of line reached + double overflowWidth = 0.0; + double hyphWidth = 0.0; + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + hyphWidth = charStyle.font().charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0); + if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(hl->ch, Cols > 1) || current.xPos >= mustLineEnd) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(ceil(current.yPos-asce))); + if (!addLine && style.rightMargin() > 0.0 && !lastInRowLine && 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 + lastInRowLine = false; + if (current.breakIndex <=0) + mustLineEnd = current.line.x -1; + else if (current.line.firstItem == restartIndex) + lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0 && restartIndex == restartRowIndex) + { + current.hasDropCap = false; + maxDX = 0; + current.yPos = maxDY; + } + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + recalculateY = false; + addLine = true; + continue; + } + outs = true; + addLine = true; + lastInRowLine = true; + rightMargin = style.rightMargin(); + if (current.isEndOfCol(realDesc)) + goNextColumn = true; } - - // test if end of line reached - if ((!cl.contains(pf2.map(pt1))) || (!cl.contains(pf2.map(pt2))) || (legacy && current.isEndOfLine(style.rightMargin()))) - outs = true; - if (current.isEndOfCol()) - outs = true; - if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) - goNoRoom = true; - if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) - goNextColumn = true; - - - // remember possible break - // #5783 : comment out "&& !outs" as this make it possible to perform a line break - // before a space which contradicts unicode line breaking rules - if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB) /*&& !outs*/) + else { - if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) + int charStart, charEnd; + if (current.itemsInLine == 0) { - current.rememberBreak(a, breakPos); + charStart = static_cast<int>(floor(current.line.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) + hyphWidth); + } + if (legacy && + (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) + || hl->ch == SpecialChars::SHYPHEN)) + { + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + } + else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + { + pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + pt = QRect(pt1, pt2); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + if (current.breakIndex <=0) + { + current.line.x = current.xPos = restartX = realEnd; + current.itemsInLine = 0; + a = restartIndex -1; + if (!wasFirstInRow) + addLeftIndent = true; + if (current.hasDropCap && DropLinesCount == 0 && !afterOverflow) + { + current.hasDropCap = false; + current.yPos = maxDY; + } + recalculateY = false; + continue; + } + outs = true; + } + else if (style.rightMargin() > 0.0) + { + if (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 (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + outs = true; + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + } + } + } + if (outs) + { + //check if after overflow text can be placed + overflowWidth = realEnd - (current.xPos - current.maxShrink); + if (current.isEndOfLine(overflowWidth + style.rightMargin() + style.minGlyphExtension() * wide + hyphWidth) || realEnd >= mustLineEnd) + { + if (!addLine && style.rightMargin() > 0.0 && !lastInRowLine) + { + if (afterOverflow) + { + lastInRowLine = false; + if (current.breakIndex <=0) + { + lastInRowLine = true; + mustLineEnd = current.line.x -1; + } + else if (current.line.firstItem == restartIndex) + lastInRowLine = true; + } + else + lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + maxDX = 0; + } + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + recalculateY = false; + addLine = true; + continue; + } + addLine = true; + rightMargin = style.rightMargin(); + lastInRowLine = true; + } + else + inOverflow = true; + } } - // hyphenation if (((hl->effects() & ScStyle_HyphenationPossible) || (hl->ch == '-') || hl->ch == SpecialChars::SHYPHEN) && (!outs) && !itemText.text(a-1).isSpace() ) @@ -1688,24 +1789,28 @@ breakPos = current.xPos; if (hl->ch != '-') { - breakPos += charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0); + breakPos += hyphWidth; } double rightHang = 0; if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) { - rightHang = 0.7 * charStyle.font().realCharWidth('-', (charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0)); + rightHang = 0.7 * hyphWidth; } if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin())) { if ((current.hyphenCount < m_Doc->HyCount) || (m_Doc->HyCount == 0) || hl->ch == SpecialChars::SHYPHEN) { - current.rememberBreak(a, breakPos); + current.rememberBreak(a, breakPos, style.rightMargin() + hyphWidth); } } } - - + + if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) + goNoRoom = true; + if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) + goNextColumn = true; + ++current.itemsInLine; if (tabs.active) @@ -1725,7 +1830,7 @@ } } - if (DropCmode) + if (DropCmode && !outs) { DropCmode = false; DropLinesCount = 0; @@ -1733,10 +1838,7 @@ current.hasDropCap = true; current.xPos += style.dropCapOffset(); hl->glyph.xadvance += style.dropCapOffset(); -// qDebug() << QString("dropcapoffset: %1 -> %2").arg(current.xPos-style.dropCapOffset()).arg(current.xPos); - current.xPos = qMax(current.xPos, current.colLeft); maxDX = current.xPos; - QPolygon tcli(4); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { current.yPos -= m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); @@ -1745,40 +1847,24 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust after dropcaps: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - //FIXME: use current.colLeft instead of xOffset? - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); } else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) { current.yPos -= style.lineSpacing() * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY - DropLines * style.lineSpacing()))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*style.lineSpacing()))); } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(charStyle.fontSize() / 10.0); current.yPos -= currasce * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*currasce))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*currasce))); } } - tcli.setPoint(2, QPoint(qRound(maxDX), qRound(maxDY))); - tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); - // #6821 : the following two lines are causing bad text flow around drop caps - // in some case, discarding them put more emphasis on user control of line spacing - /*cm = QRegion(pf2.map(tcli)); - cl = cl.subtract(cm);*/ -// current.yPos = maxDY; + recalculateY = false; } // end of line - if ( SpecialChars::isBreak(hl->ch, Cols > 1) || (outs)) + if (outs) { tabs.active = false; tabs.status = TabNONE; @@ -1786,9 +1872,22 @@ { // find end of line current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); current.finishLine(EndX); - + addLine = true; + current.startOfCol = false; + addLeftIndent = true; + if (hl->ch == SpecialChars::PARSEP) + { + maxDX = 0; + if (current.hasDropCap) + { + current.yPos = maxDY; + maxDY = 0; + current.hasDropCap = false; + } + } + // if (style.alignment() != 0) { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) @@ -1815,7 +1914,7 @@ { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); - double optiWidth = current.colRight - style.lineSpacing()/2.0 - current.line.x; + double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.line.x; if (current.line.naturalWidth > optiWidth) current.line.width = qMax(current.line.width - current.maxShrink, optiWidth); // simple offset @@ -1826,64 +1925,59 @@ } else // outs -- last char went outside the columns (or into flow-around shape) { - if (current.breakIndex >= 0) // Hier koenen auch andere Trennungen eingebaut werden + if (current.breakIndex > 0) // Hier koenen auch andere Trennungen eingebaut werden { - // go back to last break position -// qDebug() << QString("new break pos a=%1 BuPos=%2 current.breakIndex=%3").arg(a).arg(BuPos).arg(current.breakIndex); a = current.breakIndex; assert( a >= 0 ); assert( a < itemText.length() ); hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) + current.itemsInLine = a - current.line.firstItem + 1; + if (addLine) { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - current.itemsInLine = a - current.line.firstItem + 1; -// qDebug() << QString("style outs pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style <@%6: %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():"") -// .arg(a); + // go back to last break position + style = itemText.paragraphStyle(a); + if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) + style.setLineSpacing(charStyle.font().height(hlcsize10)); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - if (hl->ch == ' ') { - hl->setEffects(hl->effects() | ScStyle_SuppressSpace); - hl->glyph.xadvance = 0; - } - - current.updateHeightMetrics(itemText); - current.updateLineOffset(itemText, style, firstLineOffset()); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (hl->ch == ' ') { + hl->setEffects(hl->effects() | ScStyle_SuppressSpace); + hl->glyph.xadvance = 0; + } -//??? current.breakXPos = current.line.x; -//??? for (int j=current.line.firstItem; j <= a; ++j) -//??? current.breakXPos += itemText.item(j)->glyph.wide(); - - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - // insert hyphen - current.hyphenCount++; - hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); - hl->glyph.grow(); - hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); - hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); - } - else - { - if (hl->ch != '-') - current.hyphenCount = 0; - hl->setEffects(hl->effects() & ~ScStyle_SmartHyphenVisible); - hl->glyph.shrink(); - } - - // Justification -// if (style.alignment() != 0) - { + current.updateHeightMetrics(itemText); + //current.updateLineOffset(itemText, style, firstLineOffset()); + //current.xPos = current.breakXPos; + EndX = current.endOfLine(cl, pf2, rightMargin, maxYAsc, maxYDesc); + current.finishLine(EndX); + + hyphWidth = 0.0; + if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) + { + // insert hyphen + if (lastInRowLine) + //increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow + current.hyphenCount++; + hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); + hl->glyph.grow(); + hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); + hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); + hyphWidth = hl->glyph.more->xadvance; + } + else + { + if (hl->ch != '-') + current.hyphenCount = 0; + hl->setEffects(hl->effects() & ~ScStyle_SmartHyphenVisible); + hl->glyph.shrink(); + } + + // Justification if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.width += opticalRightMargin(itemText, current.line); + else + current.line.naturalWidth += hyphWidth; OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -1891,229 +1985,126 @@ if (style.alignment() == ParagraphStyle::Centered) OFs = (current.line.width - current.line.naturalWidth) / 2; - if ((style.alignment() == ParagraphStyle::Justified) - || (style.alignment() == ParagraphStyle::Extended)) - { + if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended)) justifyLine(itemText, current.line); - } else { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } -// qDebug() << QString("line: endx=%1 next pos=(%2,%3").arg(EndX).arg(current.line.x + current.line.width).arg(current.yPos); current.xPos = current.line.x + current.line.width; } } - else // no break position + } + if (inOverflow) + current.xPos = realEnd; + + //line break or end of column + if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) + && current.hasDropCap) + { + current.hasDropCap = false; + if (current.yPos < maxDY) + current.yPos = maxDY; + maxDX = 0; + } + if ( SpecialChars::isBreak(hl->ch) ) + { + if (hl->ch == SpecialChars::PARSEP) + current.yPos += style.gapAfter(); + current.hyphenCount = 0; + } + if (current.isEndOfCol(desc)) + { + //check if realy line extends bottom margin + current.updateHeightMetrics(itemText); + if (current.isEndOfCol(current.line.descent)) { - if (a >= current.line.firstItem) + if (current.itemsInLine == 0 || current.column+1 == Cols) { - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - current.itemsInLine = 0; - a = current.line.firstItem - 1; - } - else - { - --a; - --current.itemsInLine; - } + goNoRoom = true; + MaxChars = a + 1; + break; } - if (a >= 0) - { - hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - } - current.breakLine(itemText, style, firstLineOffset(), a); -// qDebug() << QString("style no break pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style nb @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); -// qDebug() << QString("no break pos: %1-%2 @ %3 wid %4 nat %5 endX %6") -// .arg(current.line.firstItem).arg(current.line.firstItem) -// .arg(current.line.x).arg(current.line.width).arg(current.line.naturalWidth).arg(EndX); - indentLine(itemText, current.line, 0); + goNextColumn = true; } } - if ( outs || SpecialChars::isBreak(hl->ch, (Cols > 1)) ) + if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0) { - if (outs && !current.isEndOfLine(hl->glyph.wide() + style.rightMargin())) + if (addLine) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) - && current.hasDropCap) + if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) { - current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcaps: y=%1 maxDY=%2").arg(current.yPos).arg(maxDY); + // put line back to top + current.line.y -= DropCapDrop; + itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - bool fromOut = true; - double BotOffset = desc+extra.Bottom+lineCorr; - while (!current.isEndOfLine(style.rightMargin())) + fillInTabLeaders(itemText, current.line); + //if right margin is set we temporally save line, not append it + itemText.appendLine(current.line); + restartIndex = current.line.lastItem +1; + a = restartIndex -1; + currentRowDesc = qMax(currentRowDesc,current.yPos + current.line.descent); + if (!lastInRowLine) { - current.xPos++; - if (current.isEndOfLine(style.rightMargin())) + restartX = current.xPos; + if (addLeftIndent) { - fromOut = false; -// qDebug() << QString("layout: next lower2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("nextline: y=%1+%2").arg(current.yPos).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing? m_Doc->typographicSettings.valueBaseGrid : style.lineSpacing()); - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - else - current.yPos += style.lineSpacing(); - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 1: %1").arg(a)); - break; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if (SpecialChars::isBreak(hl->ch)) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } - break; + addLeftIndent = false; + wasFirstInRow = true; } - // #7944 : Do not use static_cast<int> here, this is not consistent with computations - // performed at lines 1488-1512 and can trigger hang due to changing region detection - //pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); - //pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); - pt1 = QPoint(qRound(current.xPos+extra.Right), qRound(current.yPos+BotOffset)); - pt2 = QPoint(qRound(current.xPos+extra.Right), qRound(ceil(current.yPos-asce))); - if (cl.contains(pf2.map(pt1)) && cl.contains(pf2.map(pt2))) - break; -// else -// qDebug() << QString("looking for start of line at %1,%2").arg(current.xPos).arg(current.yPos); } - if (fromOut) - { - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 2: %1").arg(a); - break; - } - current.xPos--; - current.xPos = qMax(current.xPos, current.colLeft); - } } - else +// else if (!addRightMargin) +// { +// current.xPos = restartX = realEnd +1; +// restartIndex = a +1; +// } + } + if (addLine && lastInRowLine) + { + recalculateY = true; + wasFirstInRow = false; + addLeftIndent = true; + inOverflow = false; + outs = false; + current.startOfCol = false; + restartX = current.xPos = qMax(maxDX, current.colLeft); + lastLineY = currentRowDesc; + if (current.hasDropCap) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK ) - && current.hasDropCap) + ++DropLinesCount; + if (DropLinesCount >= DropLines) { current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcap2: y=%1+%2").arg(current.yPos).arg(maxDY); + restartX = current.xPos = current.colLeft; + maxDX = 0; } -// qDebug() << QString("layout: next lower3 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { -// qDebug() << QString("next line (grid): y=%1+%2").arg(current.yPos).arg(m_Doc->typographicSettings.valueBaseGrid); - - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - } - else - { -// qDebug() << QString("next line (auto): y=%1+%2").arg(current.yPos).arg(style.lineSpacing()); - //#5845 : use next paragraph line spacing for switching to next paragraph instead of current one - //current.yPos += style.lineSpacing(); - const ParagraphStyle& pStyle = itemText.paragraphStyle(a+1); - double lineSpacing = pStyle.lineSpacing(); - if (pStyle.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - lineSpacing = pStyle.charStyle().font().height(pStyle.charStyle().fontSize() / 10.0); - else if (pStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - lineSpacing = m_Doc->typographicSettings.valueBaseGrid; - current.yPos += lineSpacing; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if ( SpecialChars::isBreak(hl->ch) ) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } } + lastLineY = currentRowDesc; + mustLineEnd = current.colRight; + restartRowIndex = restartIndex; } - - - // calc. needed vertical space - // Let’s try to change into "calc. _wanted_ vertical space" - pm - if (current.itemsInLine != 0) + if (inOverflow) { - if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) - { - // put line back to top - current.line.y -= DropCapDrop; - itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; - } + afterOverflow = true; + inOverflow = false; + addLeftIndent = false; + recalculateY = false; } - - fillInTabLeaders(itemText, current.line); - - current.startOfCol = false; -// qDebug() << QString("layout: line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - if (current.line.firstItem > current.line.lastItem) - ; //qDebug() << QString("layout: empty line %1 - %2").arg(current.line.firstItem).arg(current.line.lastItem); - else if (current.itemsInLine > 0) - itemText.appendLine(current.line); + else + { + afterOverflow = false; + } + outs = false; + addLine = false; + lastInRowLine = false; current.startLine(a+1); - outs = false; if (goNoRoom) { goNoRoom = false; MaxChars = a+1; -// qDebug() << QString("no room C: %1").arg(a+1); goto NoRoom; } if (goNextColumn) @@ -2122,12 +2113,18 @@ current.column++; if (current.column < Cols) { - current.nextColumn(asce); + if (firstLineOffset() == FLOPRealGlyphHeight) + asce = 0; + current.nextColumn(); + mustLineEnd = current.colRight; + addLeftIndent = true; + lastLineY = extra.Top; + currentRowDesc = 0; + recalculateY = true; } else { MaxChars = a; -// qDebug() << QString("no room D: %1").arg(a); goto NoRoom; } } @@ -2139,18 +2136,35 @@ goto NoRoom; } // end of itemText - int a = itemText.length()-1; - hl = a >=0 ? itemText.item(a) : NULL; - current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (current.itemsInLine >0) + { + int a = itemText.length()-1; + hl = a >=0 ? itemText.item(a) : NULL; + current.breakLine(itemText, style, firstLineOffset(), a); -// if (style.alignment() != 0) - { + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) + { + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) + { + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); + } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); + current.finishLine(EndX); + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - { current.line.width += opticalRightMargin(itemText, current.line); - } OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -2174,26 +2188,19 @@ current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } - } - - if (current.itemsInLine != 0) - { if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap ) { // put line back to top current.line.y -= DropCapDrop; itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - } - fillInTabLeaders(itemText, current.line); - current.startOfCol = false; - goNextColumn = false; + fillInTabLeaders(itemText, current.line); + current.startOfCol = false; + goNextColumn = false; -// qDebug() << QString("layout: last line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - - if (current.itemsInLine > 0) { + assert(current.line.firstItem <0); itemText.appendLine(current.line); + current.startOfCol = false; } } MaxChars = itemText.length(); @@ -3310,7 +3317,6 @@ void PageItem_TextFrame::setNewPos(int oldPos, int len, int dir) { - bool isSpace, wasSpace; if ( dir > 0 && oldPos < len ) { @@ -3563,8 +3569,6 @@ } -#endif //NLS_PROTO - bool PageItem_TextFrame::createInfoGroup(QFrame *infoGroup, QGridLayout *infoGroupLayout) { int Parag = 0; |
|
OK, found one code problem and fix it - try formatting2.patch specially for yours issues. |
|
The first crash i reported (assert, now at line 2201) still occurs when trying to type in text frame. The assert condition is probably wrong or the assert should be simply removed. The second crash i mentioned is fixed. When the first line of a paragraph has no break possibility weird things happens. This is the issue mentioned by mrdocs. Seems to be still there. |
|
formatting3.patch (82,034 bytes)
Index: Version135/Scribus/scribus/pageitem_textframe.cpp =================================================================== --- Version135/Scribus/scribus/pageitem_textframe.cpp (wersja 16820) +++ Version135/Scribus/scribus/pageitem_textframe.cpp (kopia robocza) @@ -70,7 +70,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -83,7 +82,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -155,9 +153,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - { - result = result.subtract(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); - } + result = result.subtracted(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -192,7 +188,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - result = result.subtract(itemShape(docItem, 0, 0)); + result = result.subtracted(itemShape(docItem, 0, 0)); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -202,7 +198,6 @@ return result; } - void PageItem_TextFrame::setShadow() { if (OnMasterPage.isEmpty()) @@ -235,10 +230,6 @@ currentShadow = newShadow; } } - -#ifdef NLS_PROTO -#include "text/pageitem_textframe.cpp" -#else static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->")) { @@ -258,7 +249,6 @@ dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } - static const bool legacy = true; /* @@ -373,22 +363,23 @@ } /// move position to next column - void nextColumn(double asce) + void nextColumn(double asce = 0.0) { startOfCol = true; colLeft = (colWidth + colGap) * column + insets.Left + lineCorr; + //now colRight is REAL column right edge colRight = colLeft + colWidth; if (legacy) - colRight += insets.Right + lineCorr; //??? + colRight += lineCorr; xPos = colLeft; - yPos = asce + insets.Top + lineCorr + 1; + yPos = asce + insets.Top + lineCorr; } bool isEndOfCol(double morespace = 0) { return yPos + morespace + insets.Bottom + lineCorr > frameHeight; } - + /** init fields for a new line at current position */ @@ -398,7 +389,8 @@ line.x = xPos; line.y = yPos; line.firstItem = first; - line.ascent = 10; + line.lastItem = 0; + line.ascent = 0; line.descent = 0; line.width = 0; line.naturalWidth = 0; @@ -407,6 +399,7 @@ breakXPos = 0; maxShrink = 0; maxStretch = 0; + width = 0; } @@ -423,12 +416,12 @@ } /// called when a possible break is passed - void rememberBreak(int index, double pos) + void rememberBreak(int index, double pos, double morespace = 0) { - if (pos > colRight) + if (pos > colRight - morespace) { // only look for the first break behind the right edge - maxShrink = 0; + //maxShrink = 0; // check if we already have a better break if (breakIndex >= 0) @@ -439,12 +432,8 @@ if (newLooseness >= oldLooseness) return; } - breakXPos = colRight; } - else - { - breakXPos = pos; - } + breakXPos = pos; breakIndex = index; } @@ -460,9 +449,9 @@ // so that endOfLine() returns correct result updateHeightMetrics(itemText); // #9060 : update line offset too - updateLineOffset(itemText, style, offsetPolicy); + //updateLineOffset(itemText, style, offsetPolicy); } - + /// use the last remembered break to set line width and itemrange void finishLine(double endX) { @@ -471,109 +460,44 @@ line.width = endX - line.x; maxShrink = maxStretch = 0; } - - + bool isEndOfLine(double moreSpace = 0) { + bool res; if (legacy) - return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight; + res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight); else - return xPos + moreSpace - maxShrink >= colRight; + res = ceil(xPos - maxShrink) + ceil(moreSpace) >= floor(colRight); + return res; } - - /// find x position to start current line - double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace) - { - QPoint pt1, pt2; - double tmpX = xPos; - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - // increase pt1/pt2 until i-beam reaches end of line - while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2)))) - { - tmpX++; - if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight) - { - return tmpX; - } - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - } - return tmpX; - } - + /// find x position where this line must end - double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace = 0) + double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace, int Yasc, int Ydesc) { - // Keep old code for reference - /*double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - QPoint pt1, pt2; - // qDebug() << QString("endx start=%1, hl is '%2'").arg(EndX).arg(hl->ch); - do { - EndX += 0.125; - pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent)); - pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent))); - } while ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace) - && shape.contains(pf2.map(pt1)) - && shape.contains(pf2.map(pt2)) - );*/ - // if we aren't restricted further, we'll end at this maxX: double maxX = colRight - morespace; - if (legacy) maxX -= (lineCorr + insets.Right); + if (legacy) maxX -= lineCorr; - double StartX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - int xPos = static_cast<int>(ceil(maxX + insets.Right)); - int yDesc = static_cast<int>(yPos+line.descent); - int yAsc = static_cast<int>(ceil(yPos-line.ascent)); + double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1); + int xPos = static_cast<int>(ceil(maxX)); - QPoint pt12 (xPos, yDesc); - QPoint pt22 (xPos, yAsc); + QPoint pt12 (xPos, Yasc); + QPoint pt22 (xPos, Ydesc); + QRect pt(pt12,pt22); - // simple and fast case: transformed line completely falls within range - // this will happen if we don't wrap around anything - ie. very often - QPolygon p; - p.append (pf2.map (QPoint (StartX, yAsc))); - p.append (pf2.map (QPoint (StartX, yDesc))); - p.append (pf2.map (pt12)); - p.append (pf2.map (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.numRects() == 1) - { - int xPos = qRound(ceil(StartX + 0.125 + insets.Right)); - pt12.setX(xPos); - pt22.setX(xPos); - if (shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))) - { - QRect rect = lineI.rects().at(0); - double mx = qMax(rect.left(), rect.right()) - pf2.dx(); - int steps = static_cast<int>((mx - StartX - insets.Right - 2)/0.125); - if (steps > 0) - StartX += steps * 0.125; - } - } - - // qDebug()<<"endOfLine: going for the hard case"; double EndX2 = StartX; - double Interval = 0.125; + double Interval = 0.25; do { + int xP = static_cast<int>(ceil(EndX2 + morespace)); + pt.moveTopLeft(QPoint(xP, Yasc)); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()) + break; EndX2 += Interval; - int xPos = qRound(ceil(EndX2 + insets.Right)); - pt12.setX (xPos); - pt22.setX (xPos); - } while ((EndX2 < maxX) && shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))); + } while ((EndX2 < maxX) && QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()); - /*if (EndX!=EndX2) - { - qDebug()<<EndX<<EndX2<<StartX<<maxX; - qDebug()<<"DIFFERING ENDX!!!!!"; - }*/ - return EndX2; + return qMin(EndX2, maxX); } - - + double getLineAscent(const StoryText& itemText) { double result = 0; @@ -684,15 +608,18 @@ || (ch == SpecialChars::LINEBREAK) || (ch.isSpace())) continue; const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc)); + double scaleV = cStyle.scaleV() / 1000.0; + double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0); + if (itemText.object(line.firstItem+zc) != 0) { - asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0); + asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset; desc = 0.0; } else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0) { - asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0); - desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0); + asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset; + desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset; } // qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result); line.ascent = qMax(line.ascent, asce); @@ -700,44 +627,47 @@ } } - void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) - { - if (itemsInLine <= 0) - return; - if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) - { - //FIXME: use glyphs, not chars - double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).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.firstItem); - double firstasce = style.lineSpacing(); - double currasce = getLineHeight(itemText); - double adj = firstasce - currasce; -// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); - line.ascent = currasce; - line.y -= adj; - yPos -= adj; - } - } +// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!! +// +// void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) +// { +// if (itemsInLine <= 0) +// return; +// if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) +// { +// //FIXME: use glyphs, not chars +// double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0); +// double adj (0.0); +// double currasce (this->getLineAscent(itemText)); +// if( offsetPolicy == FLOPRealGlyphHeight ) +// { +// adj = line.y - insets.Top -currasce; +// //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.firstItem); +// double firstasce = style.lineSpacing(); +// double currasce = getLineHeight(itemText); +// double adj = firstasce - currasce; +//// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); +// line.ascent = currasce; +// line.y -= adj; +// yPos -= adj; +// } +// } private: double frameWidth; @@ -802,8 +732,11 @@ .arg(style.minWordTracking()).arg(style.minGlyphExtension()); */ + int startItem = line.firstItem; + if (itemText.item(startItem)->effects() & ScStyle_DropCap) + startItem++; // distribute whitespace on spaces and glyphs - for (int yof = line.firstItem; yof <= line.lastItem; ++yof) + for (int yof = startItem; yof <= line.lastItem; ++yof) { double wide = itemText.item(yof)->glyph.wide(); if (!SpecialChars::isExpandingSpace(itemText.text(yof))) @@ -839,46 +772,42 @@ } } -/// calculate how much the first char should stick out to the left -static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) -{ - int b = line.firstItem; - while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace)) - ++b; +//definied but not used +///// calculate how much the first char should stick out to the left +//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) +//{ +// int b = line.firstItem; +// while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_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; -} +// 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); +// } +// return leftCorr; +//} - - /// calculate how much the last char should stick out to the right static double opticalRightMargin(const StoryText& itemText, const LineSpec& line) { @@ -923,10 +852,15 @@ return 0.0; } +static double findRealOverflowEnd(const QRegion& shape, const QMatrix& pf2, QRect pt, double maxX) +{ + while (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty() && pt.right() < maxX) + pt.translate(1, 0); + if (pt.right() >= maxX) + return maxX; + return pt.left() +0.5; +} - - - void PageItem_TextFrame::layout() { // qDebug()<<"==Layout==" << itemName() ; @@ -957,10 +891,9 @@ firstChar = 0; // qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame()); -// ScribusView* view = m_Doc->view(); QMatrix pf2; QPoint pt1, pt2; - /*QRegion cm;*/ + QRect pt; double chs, chsd = 0; double oldCurY, EndX, OFs, wide, kernVal; QString chstr; @@ -969,7 +902,6 @@ int /*ParagraphStyle::OpticalMarginType*/ opticalMargins = ParagraphStyle::OM_None; bool outs = false; - bool fBorder = false; bool goNoRoom = false; bool goNextColumn = false; @@ -983,12 +915,12 @@ tTabValues.clear(); bool DropCmode = false; - double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0; + double desc=0, asce=0, realAsce=0, realDesc = 0; + double maxDY=0, maxDX=0; double DropCapDrop = 0; int DropLines = 0; int DropLinesCount = 0; - itemText.clearLines(); double lineCorr = 0; @@ -1006,7 +938,11 @@ current.init(Width, Height, extra, lineCorr); current.initColumns(columnWidth(), ColGap); current.hyphenCount = 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, currentRowDesc = 0; + // dump styles /* for (int i=0; i < itemText.nrOfParagraphs(); ++i) { @@ -1018,7 +954,6 @@ dumpIt(itemText.defaultStyle()); */ -// pf2.begin(view->viewport()); pf2.translate(Xpos, Ypos); pf2.rotate(Rot); @@ -1044,7 +979,8 @@ pf2.scale(1, -1); } - current.nextColumn(0); + current.nextColumn(); + lastLineY = extra.Top; // find start of first line if (firstInFrame() < itemText.length()) @@ -1070,19 +1006,35 @@ } else chs = hl->fontSize(); - desc2 = -hl->font().descent(chs / 10.0); + desc = -hl->font().descent(chs / 10.0); current.yPos = extra.Top + lineCorr; // qDebug() << QString("first line at y=%1").arg(current.yPos); } else // empty itemText: { - desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); - current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; + desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); + current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc; } current.startLine(firstInFrame()); + outs = false; OFs = 0; MaxChars = 0; + bool inOverflow = false; + bool afterOverflow = false; + bool addLine = false; + bool recalculateY = true; + bool lastInRowLine = false; + bool addLeftIndent = true; + bool wasFirstInRow = false; + double leftIndent = 0; + double rightMargin = 0.0; + double mustLineEnd = current.colRight; + int restartIndex = firstInFrame(); //index of char where line computing should be restarted + int restartRowIndex = firstInFrame(); //index of char where row of text is started + double restartX = 0; //starting X position of line if must be restarted + double realEnd = 0; + for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a); @@ -1091,27 +1043,17 @@ if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); -// qDebug() << QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); const CharStyle& charStyle = (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle()); - if (!charStyle.parent().isEmpty()) - { -// qDebug() << QString("charstyle pos %1: %2 (%3 %4 %5 %6 %7 %8 %9)").arg(a).arg(charStyle.parent()) -// .arg((uint)charStyle.parentStyle()).arg(charStyle.font().scName()).arg(charStyle.fontSize()) -// .arg(charStyle.fillColor()).arg(charStyle.strokeColor()).arg(charStyle.parentStyle()->name()).arg((uint)charStyle.parentStyle()->parentStyle()); - } -// qDebug() << QString("charstyle pos %1: %2 (%3)").arg(a).arg(charStyle.asString()).arg(charStyle.fontSize()); -// qDebug() << QString("style @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); + chstr = ExpandToken(a); + 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); - chstr = ExpandToken(a); -// qDebug() << QString("expanded token: '%1'").arg(chstr); if (chstr.isEmpty()) chstr = SpecialChars::ZWNBSPACE; if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); // find out about par gap and dropcap @@ -1119,7 +1061,6 @@ { if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP) { - current.yPos += style.gapBefore(); if (chstr[0] != SpecialChars::PARSEP) { DropCmode = style.hasDropCap(); @@ -1165,21 +1106,34 @@ else hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); } - // qDebug() << QString("textframe(%1,%2): len=%3, fontsize=%4, ascent=%5").arg(Xpos).arg(Ypos).arg(itemText.length()) -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()); if (current.itemsInLine == 0) { - // more about par gap and dropcaps - if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && !current.startOfCol)) // after || always evaluates to false? FIXME + if (style.rightMargin() == 0) { -// qDebug() << QString("gap before2: y=%1+%2").arg(current.yPos).arg(style.gapBefore()); - current.yPos += style.gapBefore(); + addLine = true; + rightMargin = 0.0; + } + else + { + if (lastInRowLine) + rightMargin = style.rightMargin(); + else + rightMargin = 0.0; + } + current.breakIndex = -1; + if (current.startOfCol && !afterOverflow && recalculateY) + current.yPos = qMax(current.yPos,extra.Top); + // more about par gap and dropcaps + if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol)) + { + if (!afterOverflow && recalculateY && !current.startOfCol) + current.yPos += style.gapBefore(); DropCapDrop = 0; if (chstr[0] != SpecialChars::PARSEP) DropCmode = style.hasDropCap(); else DropCmode = false; - if (DropCmode) + if (DropCmode && !afterOverflow) { DropLines = style.dropCapLines(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1189,35 +1143,22 @@ if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) DropCapDrop = style.lineSpacing() * (DropLines-1); else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); + DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines-1); } -// qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop); - current.yPos += DropCapDrop; } } } - // find charsize & y pos +// ######## find charsize factors if (DropCmode) { - // dropcap active? - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); - else - { - if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - DropCapDrop = style.lineSpacing() * (DropLines-1); - else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); - } - // FIXME : we should ensure that fonts are loaded before calls to layout() // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap() // ScFace::ascent() can be called safely afterwards double realCharHeight = charStyle.font().realCharHeight(chstr[0], 1); double realCharAscent = charStyle.font().realCharAscent(chstr[0], 1); - double fontAscent = charStyle.font().ascent(style.charStyle().fontSize() / 10.0); + double fontAscent = charStyle.font().ascent(hlcsize10); if (realCharHeight == 0.0) - realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); + realCharHeight = charStyle.font().height(hlcsize10); if (realCharAscent == 0.0) realCharAscent = fontAscent; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1234,7 +1175,7 @@ } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(hlcsize10); chsd = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharHeight)); chs = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharAscent)); } @@ -1249,7 +1190,7 @@ else chs = charStyle.fontSize(); } - // find tracking +// ######## set StartOfLine (and find tracking?) if (current.itemsInLine == 0) { itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine); @@ -1262,7 +1203,8 @@ } hl->glyph.yadvance = 0; oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); - // find out width of char + +// ######## find out width, ascent and descent of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1290,168 +1232,177 @@ itemHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - asce = m_Doc->typographicSettings.valueBaseGrid * DropLines; + realAsce = m_Doc->typographicSettings.valueBaseGrid * DropLines; else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - asce = style.lineSpacing() * DropLines; + realAsce = style.lineSpacing() * DropLines; else - asce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; + realAsce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; } hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / itemHeight); + hl->glyph.scaleV = (realAsce / itemHeight); hl->glyph.scaleH *= hl->glyph.scaleV; } else { - double realCharHeight = charStyle.font().realCharHeight(chstr[0], charStyle.fontSize() / 10.0); + double realCharHeight = charStyle.font().realCharHeight(chstr[0], hlcsize10); if (realCharHeight == 0) realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); - wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0); - asce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0); -// qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); + wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0) * scaleH +1; //dropcaps are always to close to next glyphs + realAsce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0) * scaleV + offset; + asce = charStyle.font().ascent(hlcsize10); + // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / realCharHeight); + hl->glyph.scaleV = (realAsce / realCharHeight); hl->glyph.scaleH *= hl->glyph.scaleV; + hl->glyph.xoffset -= 0.5; //drop caps are always to far from column left edge } hl->glyph.xadvance = wide; - desc2 = 0; - desc = 0; + desc = realDesc =0; } else // !DropCMode { -// qDebug( ) << QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent()); - if (SpecialChars::isExpandingSpace(hl->ch)) { double wordtracking = charStyle.wordTracking(); hl->glyph.xadvance *= wordtracking; wide *= wordtracking; } - // find ascent / descent - double hlcsize10=charStyle.fontSize() / 10.0; if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) - { - desc = desc2 = 0; - } + desc = realDesc = 0; else { - desc = desc2 = -charStyle.font().descent(hlcsize10); + desc = -charStyle.font().descent(hlcsize10); + realDesc = charStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset; current.rememberShrinkStretch(hl->ch, wide, style); } asce = charStyle.font().ascent(hlcsize10); -// wide = wide * hl->glyph.scaleH; + realAsce = charStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset; } - fBorder = false; - // end of col reached? -// qDebug() << QString("eocol? %1 + %2 + %3 > %4 -- asce=%5").arg(current.yPos).arg(extra.Bottom).arg(lineCorr).arg(Height).arg(asce); - if (current.isEndOfCol()) + +// ######## check for Y position at beginning of line + if (current.itemsInLine == 0 && !afterOverflow) { - current.column++; - if (current.column < Cols) + if (recalculateY) { - // start next col - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) - || ((a == firstInFrame()) && (BackBox == 0))) + //if top of column Y position depends on first line offset + if (current.startOfCol) { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) + lastLineY = qMax(lastLineY, extra.Top + lineCorr); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); + if (firstLineOffset() == FLOPRealGlyphHeight) + { + if (DropCmode) + current.yPos += asce; + else + current.yPos += realAsce; + } + else if (firstLineOffset() == FLOPLineSpacing) + current.yPos += style.lineSpacing(); else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); + current.yPos += asce; } - if (DropCmode) - DropLines = style.dropCapLines(); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + if (current.yPos <= lastLineY) + current.yPos = lastLineY +1; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } } -// qDebug() << QString("layout: nextcol grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + else { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + current.yPos += m_Doc->typographicSettings.valueBaseGrid; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } + else + current.yPos += style.lineSpacing(); } + if (DropCmode) + current.yPos += DropCapDrop; } - else + //set left indentation + leftIndent = 0.0; + if (addLeftIndent && (maxDX == 0 || DropCmode)) { - MaxChars = a; -// qDebug() << QString("no room A: %1").arg(a); - goto NoRoom; + leftIndent = style.leftMargin(); + if (current.hasDropCap) + leftIndent = 0; + if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))) + leftIndent += style.firstIndent(); + addLeftIndent = false; } } - // ok, there's more room in col - if (current.itemsInLine == 0) + recalculateY = true; + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) { -// qDebug() << QString("newline: '%1' %2 %3").arg(a).arg(current.yPos).arg(asce); - // start a new line - double TopOffset = asce; - double BotOffset = desc2; - goNoRoom = false; - if (current.startOfCol) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { -// qDebug() << QString("current.startOfCol: %1 + %2 + %3 + 1 =%4").arg(asce).arg(extra.Top).arg(lineCorr).arg(asce + extra.Top + lineCorr + 1); - current.yPos = asce + extra.Top + lineCorr + 1; -// if (((a > 0) && (itemText.at(a-1)->ch == QChar(13))) || ((a == 0) && (BackBox == 0))) -// current.yPos += m_Doc->docParagraphStyles[hl->cab].gapBefore; + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } -// qDebug() << QString("layout: nextline grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + if (current.itemsInLine == 0 && !afterOverflow) + { + //start a new line + goNoRoom = false; + + // find line`s start + pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc); + pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc); + 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; + while (!done) { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("useBaselIneGrid: %1 * %2 + %3 - %4").arg(ol2 / 10000.0).arg(m_Doc->typographicSettings.valueBaseGrid).arg(m_Doc->typographicSettings.offsetBaseGrid).arg(by); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } - /* this causes different spacing for first line: - if (current.yPos-TopOffset < 0.0) - { - qDebug(= << QString("current.yPos - Ascender < 0 (%1 - %2 < 0)").arg(current.yPos).arg(TopOffset); - current.yPos = TopOffset+1; - } - */ - // find linelength: - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); - // increase pt1/pt2 until i-beam reaches end of line -// qDebug() << QString("linestart: %1 + %2 + %3 < %4").arg(current.xPos).arg(wide).arg(style.rightMargin()).arg(current.colRight); - double leftIndent = 0; - double xStep = legacy? 1 : 0.125; - while (!cl.contains(pf2.map(pt1)) || !cl.contains(pf2.map(pt2)) || current.isEndOfLine(wide + leftIndent + style.rightMargin())) - { - fBorder = true; - current.xPos += xStep; - if (current.isEndOfLine(wide + leftIndent + style.rightMargin())) + Xpos = current.xPos; + Xend = current.xPos + leftIndent; + //check if in indent any overflow occurs + while (Xpos <= Xend && Xpos < current.colRight) { -// qDebug() << QString("eocol %5? %1 + %2 + %3 + %4").arg(current.yPos).arg(current.startOfCol).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(style.lineSpacing()).arg(current.column); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + Xpos = current.xPos = realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + Xend = current.xPos + leftIndent; + } + else + Xpos++; + pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc)); + } + current.xPos = Xend; + done = true; + if (current.isEndOfLine((style.minGlyphExtension() * wide) + rightMargin + leftIndent)) + { // new line - fBorder = false; - current.xPos = current.colLeft; - - leftIndent = style.leftMargin(); - if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) - leftIndent += style.firstIndent(); - - if (current.startOfCol) - current.yPos++; - else - current.yPos += qMax(style.lineSpacing(), 1.0); -// qDebug() << QString("layout: next lower line grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); + current.xPos = qMax(current.colLeft, maxDX); + current.yPos ++; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { double by = Ypos; @@ -1459,83 +1410,113 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; } - if (current.isEndOfCol()) + lastLineY = maxYAsc +1; + if (current.startOfCol) { - fBorder = false; - current.column++; - if (current.column < Cols) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == firstInFrame()) && (BackBox == 0))) - { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) - { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); - else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); - } - if (DropCmode) - DropLines = style.dropCapLines(); - } -// qDebug() << QString("layout: nextcol2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } - else - { - MaxChars = a; -// qDebug() << QString("no room B: %1").arg(a); - goto NoRoom; - } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc)); + done = false; } - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); + if (current.isEndOfCol(realDesc)) + { + current.column++; + if (current.column < Cols) + { + newColumn = true; + break; + } + else + { + MaxChars = a; + goto NoRoom; + } + } } - - if (((fBorder)) && (!current.hasDropCap)) - current.xPos += extra.Left; - // indent first line of par - if (a > 0) + if (newColumn) { - if (itemText.text(a-1) == SpecialChars::PARSEP) - current.xPos += style.firstIndent(); + current.nextColumn(); + mustLineEnd = current.colRight; + restartX = current.xPos; + lastLineY = current.yPos; + currentRowDesc = 0; + a--; + recalculateY = true; + addLeftIndent = true; + continue; } + current.line.x = restartX = current.xPos; + current.line.y = current.yPos; + } + + //check if line must start at new Y position due to current glyph height or previous line descent + if (!SpecialChars::isBreak(hl->ch, true) + && !SpecialChars::isBreakingSpace(hl->ch) + && !SpecialChars::isExpandingSpace(hl->ch) + && hl->ch != SpecialChars::TAB) + { + double diff = 0; + if (current.startOfCol || DropCmode) + diff = realAsce * scaleV + offset - (current.yPos - lastLineY); else + diff = charStyle.font().realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY); + if (diff >= 1 || (!DropCmode && diff > 0)) { - if (legacy) - current.xPos += style.firstIndent(); + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + current.yPos = maxDY; + maxDX = 0; + } + int linesDrop = 0; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + linesDrop = ceil(diff/m_Doc->typographicSettings.valueBaseGrid); + current.yPos += m_Doc->typographicSettings.valueBaseGrid * linesDrop; + } + else /*if (current.startOfCol)*/ + { + 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; + } + } + recalculateY = false; + current.xPos = current.colLeft; + a = restartRowIndex -1; + current.startLine(a+1); + addLeftIndent = true; + afterOverflow = false; + continue; } - // add left margin - if (!current.hasDropCap) - current.xPos += style.leftMargin(); - if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct) { - current.xPos += opticalLeftMargin(itemText, current.line); - } -// qDebug() << QString("store line: (%1,%2)").arg(current.xPos).arg(current.yPos); - current.line.x = current.xPos; - current.line.y = current.yPos; - fBorder = false; } - else { -// qDebug() << QString("cont.' line: '%1'").arg(a); - } // right tab stuff if (tabs.active) { @@ -1589,7 +1570,6 @@ current.xPos = current.colLeft + tCurX; // remember fill char -// qDebug() << QString("tab: %1 '%2'").arg(tCurX).arg(tabs.fillChar); if (!tabs.fillChar.isNull()) { hl->glyph.growWithTabLayout(); TabLayout * tglyph = dynamic_cast<TabLayout*>(hl->glyph.more); @@ -1614,7 +1594,6 @@ if (DropCmode) hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0); - // remember x pos double breakPos = current.xPos; @@ -1630,57 +1609,193 @@ else // other tabs.active { current.xPos = qMax(current.xPos, current.colLeft); - } - - //FIXME: asce / desc set correctly? - if (legacy && - (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) - || hl->ch == SpecialChars::SHYPHEN)) + } + // remember possible break + if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB)) { - if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(ceil(current.yPos-asce))); + current.rememberBreak(a, breakPos, style.rightMargin()); } - else - { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); - } } - else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + //check against space before PARSEP + if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP)) { - pt1 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); + a++; + hl = itemText.item(a); } - else + + // test if end of line reached + double overflowWidth = 0.0; + double hyphWidth = 0.0; + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + hyphWidth = charStyle.font().charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0); + if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(hl->ch, Cols > 1) || (current.xPos + current.maxShrink + hyphWidth) >= mustLineEnd) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(ceil(current.yPos-asce))); + if (current.breakIndex <=0 && !wasFirstInRow) + { + current.xPos = restartX = current.colLeft; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + current.yPos++; + recalculateY = true; + addLine = true; + continue; + } + if (!addLine && style.rightMargin() > 0.0 && !lastInRowLine && 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 + lastInRowLine = false; + if (current.breakIndex <=0) + mustLineEnd = current.line.x -1; + else if (current.line.firstItem == restartIndex) + lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0 && restartIndex == restartRowIndex) + { + current.hasDropCap = false; + maxDX = 0; + current.yPos = maxDY; + } + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + recalculateY = false; + addLine = true; + continue; + } + outs = true; + addLine = true; + lastInRowLine = true; + rightMargin = style.rightMargin(); + if (current.isEndOfCol(realDesc)) + goNextColumn = true; } - - // test if end of line reached - if ((!cl.contains(pf2.map(pt1))) || (!cl.contains(pf2.map(pt2))) || (legacy && current.isEndOfLine(style.rightMargin()))) - outs = true; - if (current.isEndOfCol()) - outs = true; - if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) - goNoRoom = true; - if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) - goNextColumn = true; - - - // remember possible break - // #5783 : comment out "&& !outs" as this make it possible to perform a line break - // before a space which contradicts unicode line breaking rules - if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB) /*&& !outs*/) + else { - if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) + int charStart, charEnd; + if (current.itemsInLine == 0) { - current.rememberBreak(a, breakPos); + charStart = static_cast<int>(floor(current.line.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) + hyphWidth); + } + if (legacy && + (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) + || hl->ch == SpecialChars::SHYPHEN)) + { + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + } + else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + { + pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + pt = QRect(pt1, pt2); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + if (current.breakIndex <=0) + { + current.line.x = current.xPos = restartX = realEnd; + current.itemsInLine = 0; + a = restartIndex -1; + current.startLine(a+1); + if (!wasFirstInRow) + addLeftIndent = true; + if (current.hasDropCap && DropLinesCount == 0 && !afterOverflow) + { + current.hasDropCap = false; + current.yPos = maxDY; + } + recalculateY = false; + continue; + } + outs = true; + } + else if (style.rightMargin() > 0.0) + { + if (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 (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + outs = true; + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + } + } + } + if (outs) + { + //check if after overflow text can be placed + overflowWidth = realEnd - (current.xPos - current.maxShrink); + if (current.isEndOfLine(overflowWidth + style.rightMargin() + style.minGlyphExtension() * wide + hyphWidth) || realEnd >= mustLineEnd) + { + if (!addLine && style.rightMargin() > 0.0 && !lastInRowLine) + { + if (afterOverflow) + { + lastInRowLine = false; + if (current.breakIndex <=0) + { + lastInRowLine = true; + mustLineEnd = current.line.x -1; + } + else if (current.line.firstItem == restartIndex) + lastInRowLine = true; + } + else + lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + maxDX = 0; + } + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + inOverflow = false; + afterOverflow = false; + outs = false; + recalculateY = false; + addLine = true; + continue; + } + addLine = true; + rightMargin = style.rightMargin(); + lastInRowLine = true; + } + else + inOverflow = true; + } } - // hyphenation if (((hl->effects() & ScStyle_HyphenationPossible) || (hl->ch == '-') || hl->ch == SpecialChars::SHYPHEN) && (!outs) && !itemText.text(a-1).isSpace() ) @@ -1688,24 +1803,28 @@ breakPos = current.xPos; if (hl->ch != '-') { - breakPos += charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0); + breakPos += hyphWidth; } double rightHang = 0; if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) { - rightHang = 0.7 * charStyle.font().realCharWidth('-', (charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0)); + rightHang = 0.7 * hyphWidth; } if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin())) { if ((current.hyphenCount < m_Doc->HyCount) || (m_Doc->HyCount == 0) || hl->ch == SpecialChars::SHYPHEN) { - current.rememberBreak(a, breakPos); + current.rememberBreak(a, breakPos, style.rightMargin() + hyphWidth); } } } - - + + if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) + goNoRoom = true; + if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) + goNextColumn = true; + ++current.itemsInLine; if (tabs.active) @@ -1725,7 +1844,7 @@ } } - if (DropCmode) + if (DropCmode && !outs) { DropCmode = false; DropLinesCount = 0; @@ -1733,10 +1852,7 @@ current.hasDropCap = true; current.xPos += style.dropCapOffset(); hl->glyph.xadvance += style.dropCapOffset(); -// qDebug() << QString("dropcapoffset: %1 -> %2").arg(current.xPos-style.dropCapOffset()).arg(current.xPos); - current.xPos = qMax(current.xPos, current.colLeft); maxDX = current.xPos; - QPolygon tcli(4); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { current.yPos -= m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); @@ -1745,40 +1861,24 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust after dropcaps: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - //FIXME: use current.colLeft instead of xOffset? - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); } else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) { current.yPos -= style.lineSpacing() * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY - DropLines * style.lineSpacing()))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*style.lineSpacing()))); } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(charStyle.fontSize() / 10.0); current.yPos -= currasce * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*currasce))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*currasce))); } } - tcli.setPoint(2, QPoint(qRound(maxDX), qRound(maxDY))); - tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); - // #6821 : the following two lines are causing bad text flow around drop caps - // in some case, discarding them put more emphasis on user control of line spacing - /*cm = QRegion(pf2.map(tcli)); - cl = cl.subtract(cm);*/ -// current.yPos = maxDY; + recalculateY = false; } // end of line - if ( SpecialChars::isBreak(hl->ch, Cols > 1) || (outs)) + if (outs) { tabs.active = false; tabs.status = TabNONE; @@ -1786,9 +1886,22 @@ { // find end of line current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); current.finishLine(EndX); - + addLine = true; + current.startOfCol = false; + addLeftIndent = true; + if (hl->ch == SpecialChars::PARSEP) + { + maxDX = 0; + if (current.hasDropCap) + { + current.yPos = maxDY; + maxDY = 0; + current.hasDropCap = false; + } + } + // if (style.alignment() != 0) { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) @@ -1815,7 +1928,7 @@ { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); - double optiWidth = current.colRight - style.lineSpacing()/2.0 - current.line.x; + double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.line.x; if (current.line.naturalWidth > optiWidth) current.line.width = qMax(current.line.width - current.maxShrink, optiWidth); // simple offset @@ -1826,52 +1939,45 @@ } else // outs -- last char went outside the columns (or into flow-around shape) { - if (current.breakIndex >= 0) // Hier koenen auch andere Trennungen eingebaut werden + a = current.breakIndex; + assert( a >= 0 ); + assert( a < itemText.length() ); + hl = itemText.item(a); + current.itemsInLine = a - current.line.firstItem + 1; + if (addLine) { // go back to last break position -// qDebug() << QString("new break pos a=%1 BuPos=%2 current.breakIndex=%3").arg(a).arg(BuPos).arg(current.breakIndex); - a = current.breakIndex; - assert( a >= 0 ); - assert( a < itemText.length() ); - hl = itemText.item(a); style = itemText.paragraphStyle(a); if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - current.itemsInLine = a - current.line.firstItem + 1; -// qDebug() << QString("style outs pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style <@%6: %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():"") -// .arg(a); - + if (hl->ch == ' ') { hl->setEffects(hl->effects() | ScStyle_SuppressSpace); hl->glyph.xadvance = 0; } current.updateHeightMetrics(itemText); - current.updateLineOffset(itemText, style, firstLineOffset()); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + //current.updateLineOffset(itemText, style, firstLineOffset()); + //current.xPos = current.breakXPos; + EndX = current.endOfLine(cl, pf2, rightMargin, maxYAsc, maxYDesc); current.finishLine(EndX); - -//??? current.breakXPos = current.line.x; -//??? for (int j=current.line.firstItem; j <= a; ++j) -//??? current.breakXPos += itemText.item(j)->glyph.wide(); + hyphWidth = 0.0; if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) { // insert hyphen - current.hyphenCount++; + if (lastInRowLine) + //increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow + current.hyphenCount++; hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); hl->glyph.grow(); hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); + hyphWidth = hl->glyph.more->xadvance; } - else + else { if (hl->ch != '-') current.hyphenCount = 0; @@ -1880,240 +1986,144 @@ } // Justification -// if (style.alignment() != 0) + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) + current.line.width += opticalRightMargin(itemText, current.line); + else + current.line.naturalWidth += hyphWidth; + + OFs = 0; + if (style.alignment() == ParagraphStyle::Rightaligned) + OFs = current.line.width - current.line.naturalWidth; + if (style.alignment() == ParagraphStyle::Centered) + OFs = (current.line.width - current.line.naturalWidth) / 2; + + if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended)) + justifyLine(itemText, current.line); + else { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - current.line.width += opticalRightMargin(itemText, current.line); - - OFs = 0; - if (style.alignment() == ParagraphStyle::Rightaligned) - OFs = current.line.width - current.line.naturalWidth; - if (style.alignment() == ParagraphStyle::Centered) - OFs = (current.line.width - current.line.naturalWidth) / 2; - - if ((style.alignment() == ParagraphStyle::Justified) - || (style.alignment() == ParagraphStyle::Extended)) - { - justifyLine(itemText, current.line); - } - else - { - if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - current.line.naturalWidth += opticalRightMargin(itemText, current.line); - indentLine(itemText, current.line, OFs); - } -// qDebug() << QString("line: endx=%1 next pos=(%2,%3").arg(EndX).arg(current.line.x + current.line.width).arg(current.yPos); - current.xPos = current.line.x + current.line.width; + current.line.naturalWidth += opticalRightMargin(itemText, current.line); + indentLine(itemText, current.line, OFs); } + current.xPos = current.line.x + current.line.width; } - else // no break position + } + if (inOverflow) + current.xPos = realEnd; + + //line break or end of column + if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) + && current.hasDropCap) + { + current.hasDropCap = false; + if (current.yPos < maxDY) + current.yPos = maxDY; + maxDX = 0; + } + if ( SpecialChars::isBreak(hl->ch) ) + { + if (hl->ch == SpecialChars::PARSEP) + current.yPos += style.gapAfter(); + current.hyphenCount = 0; + } + if (current.isEndOfCol(desc)) + { + //check if realy line extends bottom margin + current.updateHeightMetrics(itemText); + if (current.isEndOfCol(current.line.descent)) { - if (a >= current.line.firstItem) + if (current.itemsInLine == 0 || current.column+1 == Cols) { - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - current.itemsInLine = 0; - a = current.line.firstItem - 1; - } - else - { - --a; - --current.itemsInLine; - } + goNoRoom = true; + MaxChars = a + 1; + break; } - if (a >= 0) - { - hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - } - current.breakLine(itemText, style, firstLineOffset(), a); -// qDebug() << QString("style no break pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style nb @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); -// qDebug() << QString("no break pos: %1-%2 @ %3 wid %4 nat %5 endX %6") -// .arg(current.line.firstItem).arg(current.line.firstItem) -// .arg(current.line.x).arg(current.line.width).arg(current.line.naturalWidth).arg(EndX); - indentLine(itemText, current.line, 0); + goNextColumn = true; } } - if ( outs || SpecialChars::isBreak(hl->ch, (Cols > 1)) ) + if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0) { - if (outs && !current.isEndOfLine(hl->glyph.wide() + style.rightMargin())) + if (addLine && current.breakIndex > 0) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) - && current.hasDropCap) + if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) { - current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcaps: y=%1 maxDY=%2").arg(current.yPos).arg(maxDY); + // put line back to top + current.line.y -= DropCapDrop; + itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - bool fromOut = true; - double BotOffset = desc+extra.Bottom+lineCorr; - while (!current.isEndOfLine(style.rightMargin())) + fillInTabLeaders(itemText, current.line); + //if right margin is set we temporally save line, not append it + itemText.appendLine(current.line); + restartIndex = current.line.lastItem +1; + a = restartIndex -1; + currentRowDesc = qMax(currentRowDesc,current.yPos + current.line.descent); + if (!lastInRowLine) { - current.xPos++; - if (current.isEndOfLine(style.rightMargin())) + restartX = current.xPos; + if (addLeftIndent) { - fromOut = false; -// qDebug() << QString("layout: next lower2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("nextline: y=%1+%2").arg(current.yPos).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing? m_Doc->typographicSettings.valueBaseGrid : style.lineSpacing()); - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - else - current.yPos += style.lineSpacing(); - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 1: %1").arg(a)); - break; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if (SpecialChars::isBreak(hl->ch)) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } - break; + addLeftIndent = false; + wasFirstInRow = true; } - // #7944 : Do not use static_cast<int> here, this is not consistent with computations - // performed at lines 1488-1512 and can trigger hang due to changing region detection - //pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); - //pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); - pt1 = QPoint(qRound(current.xPos+extra.Right), qRound(current.yPos+BotOffset)); - pt2 = QPoint(qRound(current.xPos+extra.Right), qRound(ceil(current.yPos-asce))); - if (cl.contains(pf2.map(pt1)) && cl.contains(pf2.map(pt2))) - break; -// else -// qDebug() << QString("looking for start of line at %1,%2").arg(current.xPos).arg(current.yPos); } - if (fromOut) - { - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 2: %1").arg(a); - break; - } - current.xPos--; - current.xPos = qMax(current.xPos, current.colLeft); - } } - else + else if (!inOverflow && !afterOverflow && lastInRowLine) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK ) - && current.hasDropCap) + current.xPos = restartX; + a = restartIndex -1; + current.startLine(a+1); + current.yPos++; + inOverflow = false; + outs = false; + recalculateY = true; + addLine = true; + mustLineEnd = current.colRight; + continue; + } + } + if (addLine && lastInRowLine) + { + recalculateY = true; + wasFirstInRow = false; + addLeftIndent = true; + inOverflow = false; + outs = false; + current.startOfCol = false; + restartX = current.xPos = qMax(maxDX, current.colLeft); + lastLineY = currentRowDesc; + if (current.hasDropCap) + { + ++DropLinesCount; + if (DropLinesCount >= DropLines) { current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcap2: y=%1+%2").arg(current.yPos).arg(maxDY); + restartX = current.xPos = current.colLeft; + maxDX = 0; } -// qDebug() << QString("layout: next lower3 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { -// qDebug() << QString("next line (grid): y=%1+%2").arg(current.yPos).arg(m_Doc->typographicSettings.valueBaseGrid); - - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - } - else - { -// qDebug() << QString("next line (auto): y=%1+%2").arg(current.yPos).arg(style.lineSpacing()); - //#5845 : use next paragraph line spacing for switching to next paragraph instead of current one - //current.yPos += style.lineSpacing(); - const ParagraphStyle& pStyle = itemText.paragraphStyle(a+1); - double lineSpacing = pStyle.lineSpacing(); - if (pStyle.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - lineSpacing = pStyle.charStyle().font().height(pStyle.charStyle().fontSize() / 10.0); - else if (pStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - lineSpacing = m_Doc->typographicSettings.valueBaseGrid; - current.yPos += lineSpacing; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if ( SpecialChars::isBreak(hl->ch) ) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } } + lastLineY = currentRowDesc; + mustLineEnd = current.colRight; + restartRowIndex = restartIndex; } - - - // calc. needed vertical space - // Let’s try to change into "calc. _wanted_ vertical space" - pm - if (current.itemsInLine != 0) + if (inOverflow) { - if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) - { - // put line back to top - current.line.y -= DropCapDrop; - itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; - } + afterOverflow = true; + inOverflow = false; + addLeftIndent = false; + recalculateY = false; } - - fillInTabLeaders(itemText, current.line); - - current.startOfCol = false; -// qDebug() << QString("layout: line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - if (current.line.firstItem > current.line.lastItem) - ; //qDebug() << QString("layout: empty line %1 - %2").arg(current.line.firstItem).arg(current.line.lastItem); - else if (current.itemsInLine > 0) - itemText.appendLine(current.line); + else + { + afterOverflow = false; + } + outs = false; + addLine = false; + lastInRowLine = false; current.startLine(a+1); - outs = false; if (goNoRoom) { goNoRoom = false; MaxChars = a+1; -// qDebug() << QString("no room C: %1").arg(a+1); goto NoRoom; } if (goNextColumn) @@ -2122,12 +2132,18 @@ current.column++; if (current.column < Cols) { - current.nextColumn(asce); + if (firstLineOffset() == FLOPRealGlyphHeight) + asce = 0; + current.nextColumn(); + mustLineEnd = current.colRight; + addLeftIndent = true; + lastLineY = extra.Top; + currentRowDesc = 0; + recalculateY = true; } else { MaxChars = a; -// qDebug() << QString("no room D: %1").arg(a); goto NoRoom; } } @@ -2139,18 +2155,35 @@ goto NoRoom; } // end of itemText - int a = itemText.length()-1; - hl = a >=0 ? itemText.item(a) : NULL; - current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (current.itemsInLine >0) + { + int a = itemText.length()-1; + hl = a >=0 ? itemText.item(a) : NULL; + current.breakLine(itemText, style, firstLineOffset(), a); -// if (style.alignment() != 0) - { + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) + { + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) + { + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); + } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); + current.finishLine(EndX); + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - { current.line.width += opticalRightMargin(itemText, current.line); - } OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -2174,26 +2207,18 @@ current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } - } - - if (current.itemsInLine != 0) - { if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap ) { // put line back to top current.line.y -= DropCapDrop; itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - } - fillInTabLeaders(itemText, current.line); - current.startOfCol = false; - goNextColumn = false; + fillInTabLeaders(itemText, current.line); + current.startOfCol = false; + goNextColumn = false; -// qDebug() << QString("layout: last line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - - if (current.itemsInLine > 0) { itemText.appendLine(current.line); + current.startOfCol = false; } } MaxChars = itemText.length(); @@ -3310,7 +3335,6 @@ void PageItem_TextFrame::setNewPos(int oldPos, int len, int dir) { - bool isSpace, wasSpace; if ( dir > 0 && oldPos < len ) { @@ -3563,8 +3587,6 @@ } -#endif //NLS_PROTO - bool PageItem_TextFrame::createInfoGroup(QFrame *infoGroup, QGridLayout *infoGroupLayout) { int Parag = 0; |
|
OK, fixed problem with non-breaks case and buggy assert - see formatting3.patch |
|
Ok buggy assert problem is fixed, however behavior for the no-break case is still not correct : in such case almost every application force break when end of line is reached, including Indesign and QuarkXPress. Look at the behavior of a simple text editor to see what the behavior should be. Triggering directly a frame overflow would make Scribus unusable for Asian users. Ok, that relies on some missing features, but nevertheless there are some asian user out there. |
|
formatting4.patch (84,949 bytes)
Index: Version135/Scribus/scribus/pageitem_textframe.cpp =================================================================== --- Version135/Scribus/scribus/pageitem_textframe.cpp (wersja 16857) +++ Version135/Scribus/scribus/pageitem_textframe.cpp (kopia robocza) @@ -70,7 +70,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -83,7 +82,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -155,9 +153,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - { - result = result.subtract(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); - } + result = result.subtracted(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -192,7 +188,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - result = result.subtract(itemShape(docItem, 0, 0)); + result = result.subtracted(itemShape(docItem, 0, 0)); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -202,7 +198,6 @@ return result; } - void PageItem_TextFrame::setShadow() { if (OnMasterPage.isEmpty()) @@ -235,10 +230,6 @@ currentShadow = newShadow; } } - -#ifdef NLS_PROTO -#include "text/pageitem_textframe.cpp" -#else static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->")) { @@ -258,7 +249,6 @@ dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } - static const bool legacy = true; /* @@ -342,6 +332,20 @@ 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 char where line computing should be restarted + int restartRowIndex; //index of char where row of text is started + double restartX; //starting X position of line if must be restarted + double rowDesc; + double ascend; double descend; double width; @@ -373,22 +377,23 @@ } /// move position to next column - void nextColumn(double asce) + void nextColumn(double asce = 0.0) { startOfCol = true; colLeft = (colWidth + colGap) * column + insets.Left + lineCorr; + //now colRight is REAL column right edge colRight = colLeft + colWidth; if (legacy) - colRight += insets.Right + lineCorr; //??? + colRight += lineCorr; xPos = colLeft; - yPos = asce + insets.Top + lineCorr + 1; + yPos = asce + insets.Top + lineCorr; } bool isEndOfCol(double morespace = 0) { return yPos + morespace + insets.Bottom + lineCorr > frameHeight; } - + /** init fields for a new line at current position */ @@ -398,15 +403,20 @@ line.x = xPos; line.y = yPos; line.firstItem = first; - line.ascent = 10; - line.descent = 0; - line.width = 0; - line.naturalWidth = 0; + line.lastItem = 0; + line.ascent = 0.0; + line.descent = 0.0; + line.width = 0.0; + line.naturalWidth = 0.0; line.colLeft = colLeft; breakIndex = -1; - breakXPos = 0; - maxShrink = 0; - maxStretch = 0; + breakXPos = 0.0; + maxShrink = 0.0; + maxStretch = 0.0; + width = 0.0; + leftIndent = 0.0; + rightMargin = 0.0; + rowDesc = 0.0; } @@ -423,12 +433,12 @@ } /// called when a possible break is passed - void rememberBreak(int index, double pos) + void rememberBreak(int index, double pos, double morespace = 0) { - if (pos > colRight) + if (pos > colRight - morespace) { // only look for the first break behind the right edge - maxShrink = 0; + //maxShrink = 0; // check if we already have a better break if (breakIndex >= 0) @@ -439,12 +449,8 @@ if (newLooseness >= oldLooseness) return; } - breakXPos = colRight; } - else - { - breakXPos = pos; - } + breakXPos = pos; breakIndex = index; } @@ -460,9 +466,9 @@ // so that endOfLine() returns correct result updateHeightMetrics(itemText); // #9060 : update line offset too - updateLineOffset(itemText, style, offsetPolicy); + //updateLineOffset(itemText, style, offsetPolicy); } - + /// use the last remembered break to set line width and itemrange void finishLine(double endX) { @@ -471,109 +477,66 @@ line.width = endX - line.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) - return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight; + res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight); else - return xPos + moreSpace - maxShrink >= colRight; + res = ceil(xPos - maxShrink) + ceil(moreSpace) >= floor(colRight); + return res; } - - /// find x position to start current line - double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace) - { - QPoint pt1, pt2; - double tmpX = xPos; - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - // increase pt1/pt2 until i-beam reaches end of line - while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2)))) - { - tmpX++; - if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight) - { - return tmpX; - } - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - } - return tmpX; - } - + /// find x position where this line must end - double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace = 0) + double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace, int Yasc, int Ydesc) { - // Keep old code for reference - /*double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - QPoint pt1, pt2; - // qDebug() << QString("endx start=%1, hl is '%2'").arg(EndX).arg(hl->ch); - do { - EndX += 0.125; - pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent)); - pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent))); - } while ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace) - && shape.contains(pf2.map(pt1)) - && shape.contains(pf2.map(pt2)) - );*/ - // if we aren't restricted further, we'll end at this maxX: double maxX = colRight - morespace; - if (legacy) maxX -= (lineCorr + insets.Right); + if (legacy) maxX -= lineCorr; - double StartX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - int xPos = static_cast<int>(ceil(maxX + insets.Right)); - int yDesc = static_cast<int>(yPos+line.descent); - int yAsc = static_cast<int>(ceil(yPos-line.ascent)); + double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1); + int xPos = static_cast<int>(ceil(maxX)); - QPoint pt12 (xPos, yDesc); - QPoint pt22 (xPos, yAsc); + QPoint pt12 (xPos, Yasc); + QPoint pt22 (xPos, Ydesc); + QRect pt(pt12,pt22); - // simple and fast case: transformed line completely falls within range - // this will happen if we don't wrap around anything - ie. very often - QPolygon p; - p.append (pf2.map (QPoint (StartX, yAsc))); - p.append (pf2.map (QPoint (StartX, yDesc))); - p.append (pf2.map (pt12)); - p.append (pf2.map (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.numRects() == 1) - { - int xPos = qRound(ceil(StartX + 0.125 + insets.Right)); - pt12.setX(xPos); - pt22.setX(xPos); - if (shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))) - { - QRect rect = lineI.rects().at(0); - double mx = qMax(rect.left(), rect.right()) - pf2.dx(); - int steps = static_cast<int>((mx - StartX - insets.Right - 2)/0.125); - if (steps > 0) - StartX += steps * 0.125; - } - } - - // qDebug()<<"endOfLine: going for the hard case"; double EndX2 = StartX; - double Interval = 0.125; + double Interval = 0.25; do { + int xP = static_cast<int>(ceil(EndX2 + morespace)); + pt.moveTopLeft(QPoint(xP, Yasc)); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()) + break; EndX2 += Interval; - int xPos = qRound(ceil(EndX2 + insets.Right)); - pt12.setX (xPos); - pt22.setX (xPos); - } while ((EndX2 < maxX) && shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))); + } while ((EndX2 < maxX) && QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()); - /*if (EndX!=EndX2) - { - qDebug()<<EndX<<EndX2<<StartX<<maxX; - qDebug()<<"DIFFERING ENDX!!!!!"; - }*/ - return EndX2; + return qMin(EndX2, maxX); } - - + double getLineAscent(const StoryText& itemText) { double result = 0; @@ -684,15 +647,18 @@ || (ch == SpecialChars::LINEBREAK) || (ch.isSpace())) continue; const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc)); + double scaleV = cStyle.scaleV() / 1000.0; + double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0); + if (itemText.object(line.firstItem+zc) != 0) { - asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0); + asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset; desc = 0.0; } else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0) { - asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0); - desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0); + asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset; + desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset; } // qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result); line.ascent = qMax(line.ascent, asce); @@ -700,44 +666,47 @@ } } - void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) - { - if (itemsInLine <= 0) - return; - if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) - { - //FIXME: use glyphs, not chars - double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).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.firstItem); - double firstasce = style.lineSpacing(); - double currasce = getLineHeight(itemText); - double adj = firstasce - currasce; -// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); - line.ascent = currasce; - line.y -= adj; - yPos -= adj; - } - } +// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!! +// +// void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) +// { +// if (itemsInLine <= 0) +// return; +// if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) +// { +// //FIXME: use glyphs, not chars +// double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0); +// double adj (0.0); +// double currasce (this->getLineAscent(itemText)); +// if( offsetPolicy == FLOPRealGlyphHeight ) +// { +// adj = line.y - insets.Top -currasce; +// //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.firstItem); +// double firstasce = style.lineSpacing(); +// double currasce = getLineHeight(itemText); +// double adj = firstasce - currasce; +//// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); +// line.ascent = currasce; +// line.y -= adj; +// yPos -= adj; +// } +// } private: double frameWidth; @@ -802,8 +771,11 @@ .arg(style.minWordTracking()).arg(style.minGlyphExtension()); */ + int startItem = line.firstItem; + if (itemText.item(startItem)->effects() & ScStyle_DropCap) + startItem++; // distribute whitespace on spaces and glyphs - for (int yof = line.firstItem; yof <= line.lastItem; ++yof) + for (int yof = startItem; yof <= line.lastItem; ++yof) { double wide = itemText.item(yof)->glyph.wide(); if (!SpecialChars::isExpandingSpace(itemText.text(yof))) @@ -839,46 +811,42 @@ } } -/// calculate how much the first char should stick out to the left -static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) -{ - int b = line.firstItem; - while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace)) - ++b; +//definied but not used +///// calculate how much the first char should stick out to the left +//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) +//{ +// int b = line.firstItem; +// while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_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; -} +// 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); +// } +// return leftCorr; +//} - - /// calculate how much the last char should stick out to the right static double opticalRightMargin(const StoryText& itemText, const LineSpec& line) { @@ -923,10 +891,15 @@ return 0.0; } +static double findRealOverflowEnd(const QRegion& shape, const QMatrix& pf2, QRect pt, double maxX) +{ + while (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty() && pt.right() < maxX) + pt.translate(1, 0); + if (pt.right() >= maxX) + return maxX; + return pt.left() +0.5; +} - - - void PageItem_TextFrame::layout() { // qDebug()<<"==Layout==" << itemName() ; @@ -957,10 +930,9 @@ firstChar = 0; // qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame()); -// ScribusView* view = m_Doc->view(); QMatrix pf2; QPoint pt1, pt2; - /*QRegion cm;*/ + QRect pt; double chs, chsd = 0; double oldCurY, EndX, OFs, wide, kernVal; QString chstr; @@ -969,7 +941,6 @@ int /*ParagraphStyle::OpticalMarginType*/ opticalMargins = ParagraphStyle::OM_None; bool outs = false; - bool fBorder = false; bool goNoRoom = false; bool goNextColumn = false; @@ -983,12 +954,12 @@ tTabValues.clear(); bool DropCmode = false; - double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0; + double desc=0, asce=0, realAsce=0, realDesc = 0; + double maxDY=0, maxDX=0; double DropCapDrop = 0; int DropLines = 0; int DropLinesCount = 0; - itemText.clearLines(); double lineCorr = 0; @@ -1006,7 +977,11 @@ current.init(Width, Height, extra, lineCorr); current.initColumns(columnWidth(), ColGap); current.hyphenCount = 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; + // dump styles /* for (int i=0; i < itemText.nrOfParagraphs(); ++i) { @@ -1018,7 +993,6 @@ dumpIt(itemText.defaultStyle()); */ -// pf2.begin(view->viewport()); pf2.translate(Xpos, Ypos); pf2.rotate(Rot); @@ -1044,7 +1018,8 @@ pf2.scale(1, -1); } - current.nextColumn(0); + current.nextColumn(); + lastLineY = extra.Top; // find start of first line if (firstInFrame() < itemText.length()) @@ -1070,19 +1045,34 @@ } else chs = hl->fontSize(); - desc2 = -hl->font().descent(chs / 10.0); + desc = -hl->font().descent(chs / 10.0); current.yPos = extra.Top + lineCorr; // qDebug() << QString("first line at y=%1").arg(current.yPos); } else // empty itemText: { - desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); - current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; + desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); + current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc; } current.startLine(firstInFrame()); + outs = false; OFs = 0; MaxChars = 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.restartIndex = firstInFrame(); //index of char where line computing should be restarted + current.restartRowIndex = firstInFrame(); //index of char where row of text is started + current.restartX = 0; //starting X position of line if must be restarted + double realEnd = 0; + for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a); @@ -1091,27 +1081,17 @@ if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); -// qDebug() << QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); const CharStyle& charStyle = (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle()); - if (!charStyle.parent().isEmpty()) - { -// qDebug() << QString("charstyle pos %1: %2 (%3 %4 %5 %6 %7 %8 %9)").arg(a).arg(charStyle.parent()) -// .arg((uint)charStyle.parentStyle()).arg(charStyle.font().scName()).arg(charStyle.fontSize()) -// .arg(charStyle.fillColor()).arg(charStyle.strokeColor()).arg(charStyle.parentStyle()->name()).arg((uint)charStyle.parentStyle()->parentStyle()); - } -// qDebug() << QString("charstyle pos %1: %2 (%3)").arg(a).arg(charStyle.asString()).arg(charStyle.fontSize()); -// qDebug() << QString("style @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); + chstr = ExpandToken(a); + 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); - chstr = ExpandToken(a); -// qDebug() << QString("expanded token: '%1'").arg(chstr); if (chstr.isEmpty()) chstr = SpecialChars::ZWNBSPACE; if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); // find out about par gap and dropcap @@ -1119,7 +1099,6 @@ { if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP) { - current.yPos += style.gapBefore(); if (chstr[0] != SpecialChars::PARSEP) { DropCmode = style.hasDropCap(); @@ -1165,21 +1144,34 @@ else hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); } - // qDebug() << QString("textframe(%1,%2): len=%3, fontsize=%4, ascent=%5").arg(Xpos).arg(Ypos).arg(itemText.length()) -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()); if (current.itemsInLine == 0) { - // more about par gap and dropcaps - if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && !current.startOfCol)) // after || always evaluates to false? FIXME + if (style.rightMargin() == 0) { -// qDebug() << QString("gap before2: y=%1+%2").arg(current.yPos).arg(style.gapBefore()); - current.yPos += style.gapBefore(); + //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,extra.Top); + // more about par gap and dropcaps + if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol)) + { + if (!current.afterOverflow && current.recalculateY && !current.startOfCol) + current.yPos += style.gapBefore(); DropCapDrop = 0; if (chstr[0] != SpecialChars::PARSEP) DropCmode = style.hasDropCap(); else DropCmode = false; - if (DropCmode) + if (DropCmode && !current.afterOverflow) { DropLines = style.dropCapLines(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1189,35 +1181,22 @@ if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) DropCapDrop = style.lineSpacing() * (DropLines-1); else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); + DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines-1); } -// qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop); - current.yPos += DropCapDrop; } } } - // find charsize & y pos +// ######## find charsize factors if (DropCmode) { - // dropcap active? - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); - else - { - if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - DropCapDrop = style.lineSpacing() * (DropLines-1); - else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); - } - // FIXME : we should ensure that fonts are loaded before calls to layout() // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap() // ScFace::ascent() can be called safely afterwards double realCharHeight = charStyle.font().realCharHeight(chstr[0], 1); double realCharAscent = charStyle.font().realCharAscent(chstr[0], 1); - double fontAscent = charStyle.font().ascent(style.charStyle().fontSize() / 10.0); + double fontAscent = charStyle.font().ascent(hlcsize10); if (realCharHeight == 0.0) - realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); + realCharHeight = charStyle.font().height(hlcsize10); if (realCharAscent == 0.0) realCharAscent = fontAscent; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1234,7 +1213,7 @@ } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(hlcsize10); chsd = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharHeight)); chs = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharAscent)); } @@ -1249,7 +1228,7 @@ else chs = charStyle.fontSize(); } - // find tracking +// ######## set StartOfLine (and find tracking?) if (current.itemsInLine == 0) { itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine); @@ -1262,7 +1241,8 @@ } hl->glyph.yadvance = 0; oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); - // find out width of char + +// ######## find out width, ascent and descent of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1290,168 +1270,177 @@ itemHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - asce = m_Doc->typographicSettings.valueBaseGrid * DropLines; + realAsce = m_Doc->typographicSettings.valueBaseGrid * DropLines; else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - asce = style.lineSpacing() * DropLines; + realAsce = style.lineSpacing() * DropLines; else - asce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; + realAsce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; } hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / itemHeight); + hl->glyph.scaleV = (realAsce / itemHeight); hl->glyph.scaleH *= hl->glyph.scaleV; } else { - double realCharHeight = charStyle.font().realCharHeight(chstr[0], charStyle.fontSize() / 10.0); + double realCharHeight = charStyle.font().realCharHeight(chstr[0], hlcsize10); if (realCharHeight == 0) realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); - wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0); - asce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0); -// qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); + wide = (charStyle.font().realCharWidth(chstr[0], chsd / 10.0) * scaleH) + (1 - scaleH); //dropcaps are to close to next glyphs if glyphs are hard scaled + realAsce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0) * scaleV + offset; + asce = charStyle.font().ascent(hlcsize10); + // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / realCharHeight); + hl->glyph.scaleV = (realAsce / realCharHeight); hl->glyph.scaleH *= hl->glyph.scaleV; + hl->glyph.xoffset -= 0.5; //drop caps are always to far from column left edge } hl->glyph.xadvance = wide; - desc2 = 0; - desc = 0; + desc = realDesc =0; } else // !DropCMode { -// qDebug( ) << QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent()); - if (SpecialChars::isExpandingSpace(hl->ch)) { double wordtracking = charStyle.wordTracking(); hl->glyph.xadvance *= wordtracking; wide *= wordtracking; } - // find ascent / descent - double hlcsize10=charStyle.fontSize() / 10.0; if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) - { - desc = desc2 = 0; - } + desc = realDesc = 0; else { - desc = desc2 = -charStyle.font().descent(hlcsize10); + desc = -charStyle.font().descent(hlcsize10); + realDesc = charStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset; current.rememberShrinkStretch(hl->ch, wide, style); } asce = charStyle.font().ascent(hlcsize10); -// wide = wide * hl->glyph.scaleH; + realAsce = charStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset; } - fBorder = false; - // end of col reached? -// qDebug() << QString("eocol? %1 + %2 + %3 > %4 -- asce=%5").arg(current.yPos).arg(extra.Bottom).arg(lineCorr).arg(Height).arg(asce); - if (current.isEndOfCol()) + +// ######## check for Y position at beginning of line + if (current.itemsInLine == 0 && !current.afterOverflow) { - current.column++; - if (current.column < Cols) + if (current.recalculateY) { - // start next col - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) - || ((a == firstInFrame()) && (BackBox == 0))) + //if top of column Y position depends on first line offset + if (current.startOfCol) { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) + lastLineY = qMax(lastLineY, extra.Top + lineCorr); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); + if (firstLineOffset() == FLOPRealGlyphHeight) + { + if (DropCmode) + current.yPos += asce; + else + current.yPos += realAsce; + } + else if (firstLineOffset() == FLOPLineSpacing) + current.yPos += style.lineSpacing(); else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); + current.yPos += asce; } - if (DropCmode) - DropLines = style.dropCapLines(); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + if (current.yPos <= lastLineY) + current.yPos = lastLineY +1; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } } -// qDebug() << QString("layout: nextcol grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + else { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + current.yPos += m_Doc->typographicSettings.valueBaseGrid; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } + else + current.yPos += style.lineSpacing(); } + if (DropCmode) + current.yPos += DropCapDrop; } - else + //set left indentation + current.leftIndent = 0.0; + if (current.addLeftIndent && (maxDX == 0 || DropCmode)) { - MaxChars = a; -// qDebug() << QString("no room A: %1").arg(a); - goto NoRoom; + current.leftIndent = style.leftMargin(); + if (current.hasDropCap) + current.leftIndent = 0; + if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))) + current.leftIndent += style.firstIndent(); + current.addLeftIndent = false; } } - // ok, there's more room in col - if (current.itemsInLine == 0) + current.recalculateY = true; + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) { -// qDebug() << QString("newline: '%1' %2 %3").arg(a).arg(current.yPos).arg(asce); - // start a new line - double TopOffset = asce; - double BotOffset = desc2; - goNoRoom = false; - if (current.startOfCol) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { -// qDebug() << QString("current.startOfCol: %1 + %2 + %3 + 1 =%4").arg(asce).arg(extra.Top).arg(lineCorr).arg(asce + extra.Top + lineCorr + 1); - current.yPos = asce + extra.Top + lineCorr + 1; -// if (((a > 0) && (itemText.at(a-1)->ch == QChar(13))) || ((a == 0) && (BackBox == 0))) -// current.yPos += m_Doc->docParagraphStyles[hl->cab].gapBefore; + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } -// qDebug() << QString("layout: nextline grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + if (current.itemsInLine == 0 && !current.afterOverflow) + { + //start a new line + goNoRoom = false; + + // find line`s start + pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc); + pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc); + 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; + while (!done) { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("useBaselIneGrid: %1 * %2 + %3 - %4").arg(ol2 / 10000.0).arg(m_Doc->typographicSettings.valueBaseGrid).arg(m_Doc->typographicSettings.offsetBaseGrid).arg(by); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } - /* this causes different spacing for first line: - if (current.yPos-TopOffset < 0.0) - { - qDebug(= << QString("current.yPos - Ascender < 0 (%1 - %2 < 0)").arg(current.yPos).arg(TopOffset); - current.yPos = TopOffset+1; - } - */ - // find linelength: - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); - // increase pt1/pt2 until i-beam reaches end of line -// qDebug() << QString("linestart: %1 + %2 + %3 < %4").arg(current.xPos).arg(wide).arg(style.rightMargin()).arg(current.colRight); - double leftIndent = 0; - double xStep = legacy? 1 : 0.125; - while (!cl.contains(pf2.map(pt1)) || !cl.contains(pf2.map(pt2)) || current.isEndOfLine(wide + leftIndent + style.rightMargin())) - { - fBorder = true; - current.xPos += xStep; - if (current.isEndOfLine(wide + leftIndent + style.rightMargin())) + Xpos = current.xPos; + Xend = current.xPos + current.leftIndent; + //check if in indent any overflow occurs + while (Xpos <= Xend && Xpos < current.colRight) { -// qDebug() << QString("eocol %5? %1 + %2 + %3 + %4").arg(current.yPos).arg(current.startOfCol).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(style.lineSpacing()).arg(current.column); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + Xpos = current.xPos = realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + Xend = current.xPos + current.leftIndent; + } + else + Xpos++; + pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc)); + } + current.xPos = Xend; + done = true; + if (current.isEndOfLine((style.minGlyphExtension() * wide) + current.rightMargin + current.leftIndent)) + { // new line - fBorder = false; - current.xPos = current.colLeft; - - leftIndent = style.leftMargin(); - if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) - leftIndent += style.firstIndent(); - - if (current.startOfCol) - current.yPos++; - else - current.yPos += qMax(style.lineSpacing(), 1.0); -// qDebug() << QString("layout: next lower line grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); + current.xPos = qMax(current.colLeft, maxDX); + current.yPos ++; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { double by = Ypos; @@ -1459,83 +1448,110 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; } - if (current.isEndOfCol()) + lastLineY = maxYAsc +1; + if (current.startOfCol) { - fBorder = false; - current.column++; - if (current.column < Cols) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == firstInFrame()) && (BackBox == 0))) - { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) - { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); - else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); - } - if (DropCmode) - DropLines = style.dropCapLines(); - } -// qDebug() << QString("layout: nextcol2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } - else - { - MaxChars = a; -// qDebug() << QString("no room B: %1").arg(a); - goto NoRoom; - } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc)); + done = false; } - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); + if (current.isEndOfCol(realDesc)) + { + current.column++; + if (current.column < Cols) + { + newColumn = true; + break; + } + else + { + MaxChars = a; + goto NoRoom; + } + } } - - if (((fBorder)) && (!current.hasDropCap)) - current.xPos += extra.Left; - // indent first line of par - if (a > 0) + if (newColumn) { - if (itemText.text(a-1) == SpecialChars::PARSEP) - current.xPos += style.firstIndent(); + current.nextColumn(); + current.mustLineEnd = current.colRight; + current.restartX = current.xPos; + lastLineY = current.yPos; + current.rowDesc = 0; + a--; + current.recalculateY = true; + current.addLeftIndent = true; + continue; } + current.line.x = current.restartX = current.xPos; + current.line.y = current.yPos; + } + + //check if line must start at new Y position due to current glyph height or previous line descent + if (!SpecialChars::isBreak(hl->ch, true) + && !SpecialChars::isBreakingSpace(hl->ch) + && !SpecialChars::isExpandingSpace(hl->ch) + && hl->ch != SpecialChars::TAB) + { + double diff = 0; + if (current.startOfCol || DropCmode) + diff = realAsce * scaleV + offset - (current.yPos - lastLineY); else + diff = charStyle.font().realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY); + if (diff >= 1 || (!DropCmode && diff > 0)) { - if (legacy) - current.xPos += style.firstIndent(); + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + current.yPos = maxDY; + maxDX = 0; + } + int linesDrop = 0; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + linesDrop = ceil(diff/m_Doc->typographicSettings.valueBaseGrid); + current.yPos += m_Doc->typographicSettings.valueBaseGrid * linesDrop; + } + else /*if (current.startOfCol)*/ + { + //FIX ME - that is ugly hack I must made, because simply expression + //current.yPos += diff; stop working, dont 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; + } + } + a = current.restartRow(false); + continue; } - // add left margin - if (!current.hasDropCap) - current.xPos += style.leftMargin(); - if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct) { - current.xPos += opticalLeftMargin(itemText, current.line); - } -// qDebug() << QString("store line: (%1,%2)").arg(current.xPos).arg(current.yPos); - current.line.x = current.xPos; - current.line.y = current.yPos; - fBorder = false; } - else { -// qDebug() << QString("cont.' line: '%1'").arg(a); - } // right tab stuff if (tabs.active) { @@ -1589,7 +1605,6 @@ current.xPos = current.colLeft + tCurX; // remember fill char -// qDebug() << QString("tab: %1 '%2'").arg(tCurX).arg(tabs.fillChar); if (!tabs.fillChar.isNull()) { hl->glyph.growWithTabLayout(); TabLayout * tglyph = dynamic_cast<TabLayout*>(hl->glyph.more); @@ -1614,7 +1629,6 @@ if (DropCmode) hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0); - // remember x pos double breakPos = current.xPos; @@ -1630,57 +1644,194 @@ else // other tabs.active { current.xPos = qMax(current.xPos, current.colLeft); - } - - //FIXME: asce / desc set correctly? - if (legacy && - (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) - || hl->ch == SpecialChars::SHYPHEN)) + } + // remember possible break + if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB)) { - if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(ceil(current.yPos-asce))); + current.rememberBreak(a, breakPos, style.rightMargin()); } - else - { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); - } } - else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + //check against space before PARSEP + if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP)) { - pt1 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); + a++; + hl = itemText.item(a); } - else + + // test if end of line reached + double overflowWidth = 0.0; + double hyphWidth = 0.0; + bool inOverflow = false; + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + hyphWidth = charStyle.font().charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0); + if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(hl->ch, Cols > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(ceil(current.yPos-asce))); + //end of row reached - right column, end of column, break char or line must end + if (current.itemsInLine == 0 && !current.afterOverflow) + { + //no glyphs in line, so start new row + if (hl->ch == SpecialChars::PARSEP) + current.restartRowIndex = a +1; + a = current.restartRow(true); + inOverflow = false; + outs = false; + continue; + } + //there we have some glyphs + if ((current.breakIndex < 0) && !SpecialChars::isBreak(hl->ch, Cols > 1)) + { + //force break + a--; + current.breakLine(itemText, style, firstLineOffset(),a); + } + 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.breakIndex <0) + current.mustLineEnd = current.line.x -1; + else if (current.line.firstItem == current.restartIndex) + current.lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0 && current.restartIndex == current.restartRowIndex) + { + current.hasDropCap = false; + maxDX = 0; + current.yPos = maxDY; + } + a = 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; } - - // test if end of line reached - if ((!cl.contains(pf2.map(pt1))) || (!cl.contains(pf2.map(pt2))) || (legacy && current.isEndOfLine(style.rightMargin()))) - outs = true; - if (current.isEndOfCol()) - outs = true; - if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) - goNoRoom = true; - if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) - goNextColumn = true; - - - // remember possible break - // #5783 : comment out "&& !outs" as this make it possible to perform a line break - // before a space which contradicts unicode line breaking rules - if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB) /*&& !outs*/) + else { - if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) + int charStart, charEnd; + if (current.itemsInLine == 0) { - current.rememberBreak(a, breakPos); + charStart = static_cast<int>(floor(current.line.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) + hyphWidth); + } + if (legacy && + (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) + || hl->ch == SpecialChars::SHYPHEN)) + { + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + } + else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + { + pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + pt = QRect(pt1, pt2); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, 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 (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + outs = true; + } + } + } + if (outs) + { + if (current.itemsInLine ==0) + { + current.line.x = current.xPos = realEnd; + a--; + current.startLine(a+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) + { + a--; + current.breakLine(itemText, style, firstLineOffset(), a); + } + //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.addLine && !current.lastInRowLine) + { + if (current.afterOverflow) + { + if (current.breakIndex < 0) + { + current.lastInRowLine = true; + current.mustLineEnd = current.line.x -1; + } + else if (current.line.firstItem == current.restartIndex) + current.lastInRowLine = true; + } + else + current.lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + maxDX = 0; + } + a = current.restartLine(false, true); + inOverflow = false; + outs = false; + continue; + } + current.addLine = true; + current.rightMargin = style.rightMargin(); + current.lastInRowLine = true; + } + else + inOverflow = true; + } } - // hyphenation if (((hl->effects() & ScStyle_HyphenationPossible) || (hl->ch == '-') || hl->ch == SpecialChars::SHYPHEN) && (!outs) && !itemText.text(a-1).isSpace() ) @@ -1688,24 +1839,28 @@ breakPos = current.xPos; if (hl->ch != '-') { - breakPos += charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0); + breakPos += hyphWidth; } double rightHang = 0; if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) { - rightHang = 0.7 * charStyle.font().realCharWidth('-', (charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0)); + rightHang = 0.7 * hyphWidth; } if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin())) { if ((current.hyphenCount < m_Doc->HyCount) || (m_Doc->HyCount == 0) || hl->ch == SpecialChars::SHYPHEN) { - current.rememberBreak(a, breakPos); + current.rememberBreak(a, breakPos, style.rightMargin() + hyphWidth); } } } - - + + if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) + goNoRoom = true; + if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) + goNextColumn = true; + ++current.itemsInLine; if (tabs.active) @@ -1725,7 +1880,7 @@ } } - if (DropCmode) + if (DropCmode && !outs) { DropCmode = false; DropLinesCount = 0; @@ -1733,10 +1888,7 @@ current.hasDropCap = true; current.xPos += style.dropCapOffset(); hl->glyph.xadvance += style.dropCapOffset(); -// qDebug() << QString("dropcapoffset: %1 -> %2").arg(current.xPos-style.dropCapOffset()).arg(current.xPos); - current.xPos = qMax(current.xPos, current.colLeft); maxDX = current.xPos; - QPolygon tcli(4); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { current.yPos -= m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); @@ -1745,40 +1897,24 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust after dropcaps: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - //FIXME: use current.colLeft instead of xOffset? - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); } else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) { current.yPos -= style.lineSpacing() * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY - DropLines * style.lineSpacing()))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*style.lineSpacing()))); } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(charStyle.fontSize() / 10.0); current.yPos -= currasce * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*currasce))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*currasce))); } } - tcli.setPoint(2, QPoint(qRound(maxDX), qRound(maxDY))); - tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); - // #6821 : the following two lines are causing bad text flow around drop caps - // in some case, discarding them put more emphasis on user control of line spacing - /*cm = QRegion(pf2.map(tcli)); - cl = cl.subtract(cm);*/ -// current.yPos = maxDY; + current.recalculateY = false; } // end of line - if ( SpecialChars::isBreak(hl->ch, Cols > 1) || (outs)) + if (outs) { tabs.active = false; tabs.status = TabNONE; @@ -1786,9 +1922,23 @@ { // find end of line current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); current.finishLine(EndX); - + //addLine = true; + assert(current.addLine); + //current.startOfCol = false; + //addLeftIndent = true; + if (hl->ch == SpecialChars::PARSEP) + { + maxDX = 0; + if (current.hasDropCap) + { + current.yPos = maxDY; + maxDY = 0; + current.hasDropCap = false; + } + } + // if (style.alignment() != 0) { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) @@ -1815,7 +1965,7 @@ { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); - double optiWidth = current.colRight - style.lineSpacing()/2.0 - current.line.x; + double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.line.x; if (current.line.naturalWidth > optiWidth) current.line.width = qMax(current.line.width - current.maxShrink, optiWidth); // simple offset @@ -1826,52 +1976,46 @@ } else // outs -- last char went outside the columns (or into flow-around shape) { - if (current.breakIndex >= 0) // Hier koenen auch andere Trennungen eingebaut werden + if (current.breakIndex >= 0) + a = current.breakIndex; + assert( a >= 0 ); + assert( a < itemText.length() ); + hl = itemText.item(a); + current.itemsInLine = a - current.line.firstItem + 1; + if (current.addLine) { // go back to last break position -// qDebug() << QString("new break pos a=%1 BuPos=%2 current.breakIndex=%3").arg(a).arg(BuPos).arg(current.breakIndex); - a = current.breakIndex; - assert( a >= 0 ); - assert( a < itemText.length() ); - hl = itemText.item(a); style = itemText.paragraphStyle(a); if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - current.itemsInLine = a - current.line.firstItem + 1; -// qDebug() << QString("style outs pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style <@%6: %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():"") -// .arg(a); - + if (hl->ch == ' ') { hl->setEffects(hl->effects() | ScStyle_SuppressSpace); hl->glyph.xadvance = 0; } current.updateHeightMetrics(itemText); - current.updateLineOffset(itemText, style, firstLineOffset()); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + //current.updateLineOffset(itemText, style, firstLineOffset()); + //current.xPos = current.breakXPos; + EndX = current.endOfLine(cl, pf2, current.rightMargin, maxYAsc, maxYDesc); current.finishLine(EndX); - -//??? current.breakXPos = current.line.x; -//??? for (int j=current.line.firstItem; j <= a; ++j) -//??? current.breakXPos += itemText.item(j)->glyph.wide(); + hyphWidth = 0.0; if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) { // insert hyphen - current.hyphenCount++; + if (current.lastInRowLine) + //increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow + current.hyphenCount++; hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); hl->glyph.grow(); hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); - hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); + hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * scaleH; //FIX ME - hyphen is not rendered with proper width - check yhis with large glyphs horizontal scaling eg. 20% + hyphWidth = hl->glyph.more->xadvance; } - else + else { if (hl->ch != '-') current.hyphenCount = 0; @@ -1880,240 +2024,140 @@ } // Justification -// if (style.alignment() != 0) + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) + current.line.width += opticalRightMargin(itemText, current.line); + else + current.line.naturalWidth += hyphWidth; + + OFs = 0; + if (style.alignment() == ParagraphStyle::Rightaligned) + OFs = current.line.width - current.line.naturalWidth; + if (style.alignment() == ParagraphStyle::Centered) + OFs = (current.line.width - current.line.naturalWidth) / 2; + + if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended)) + justifyLine(itemText, current.line); + else { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - current.line.width += opticalRightMargin(itemText, current.line); - - OFs = 0; - if (style.alignment() == ParagraphStyle::Rightaligned) - OFs = current.line.width - current.line.naturalWidth; - if (style.alignment() == ParagraphStyle::Centered) - OFs = (current.line.width - current.line.naturalWidth) / 2; - - if ((style.alignment() == ParagraphStyle::Justified) - || (style.alignment() == ParagraphStyle::Extended)) - { - justifyLine(itemText, current.line); - } - else - { - if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - current.line.naturalWidth += opticalRightMargin(itemText, current.line); - indentLine(itemText, current.line, OFs); - } -// qDebug() << QString("line: endx=%1 next pos=(%2,%3").arg(EndX).arg(current.line.x + current.line.width).arg(current.yPos); - current.xPos = current.line.x + current.line.width; + current.line.naturalWidth += opticalRightMargin(itemText, current.line); + indentLine(itemText, current.line, OFs); } + current.xPos = current.line.x + current.line.width; } - else // no break position + } + if (inOverflow) + current.xPos = realEnd; + + //line break or end of column + if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) + && current.hasDropCap) + { + current.hasDropCap = false; + if (current.yPos < maxDY) + current.yPos = maxDY; + maxDX = 0; + } + if ( SpecialChars::isBreak(hl->ch) ) + { + if (hl->ch == SpecialChars::PARSEP) + current.yPos += style.gapAfter(); + current.hyphenCount = 0; + } + if (current.isEndOfCol(desc)) + { + //check if realy line extends bottom margin + current.updateHeightMetrics(itemText); + if (current.isEndOfCol(current.line.descent)) { - if (a >= current.line.firstItem) + if (current.itemsInLine == 0 || current.column+1 == Cols) { - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - current.itemsInLine = 0; - a = current.line.firstItem - 1; - } - else - { - --a; - --current.itemsInLine; - } + goNoRoom = true; + MaxChars = a + 1; + break; } - if (a >= 0) - { - hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - } - current.breakLine(itemText, style, firstLineOffset(), a); -// qDebug() << QString("style no break pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style nb @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); -// qDebug() << QString("no break pos: %1-%2 @ %3 wid %4 nat %5 endX %6") -// .arg(current.line.firstItem).arg(current.line.firstItem) -// .arg(current.line.x).arg(current.line.width).arg(current.line.naturalWidth).arg(EndX); - indentLine(itemText, current.line, 0); + goNextColumn = true; } } - if ( outs || SpecialChars::isBreak(hl->ch, (Cols > 1)) ) + if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0) { - if (outs && !current.isEndOfLine(hl->glyph.wide() + style.rightMargin())) + if (current.addLine && current.breakIndex >= 0) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) - && current.hasDropCap) + if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) { - current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcaps: y=%1 maxDY=%2").arg(current.yPos).arg(maxDY); + // put line back to top + current.line.y -= DropCapDrop; + itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - bool fromOut = true; - double BotOffset = desc+extra.Bottom+lineCorr; - while (!current.isEndOfLine(style.rightMargin())) + fillInTabLeaders(itemText, current.line); + //if right margin is set we temporally save line, not append it + itemText.appendLine(current.line); + current.restartIndex = current.line.lastItem +1; + a = current.restartIndex -1; + current.rowDesc = qMax(current.rowDesc,current.yPos + current.line.descent); + if (!current.lastInRowLine) { - current.xPos++; - if (current.isEndOfLine(style.rightMargin())) + current.restartX = current.xPos; + if (current.addLeftIndent) { - fromOut = false; -// qDebug() << QString("layout: next lower2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("nextline: y=%1+%2").arg(current.yPos).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing? m_Doc->typographicSettings.valueBaseGrid : style.lineSpacing()); - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - else - current.yPos += style.lineSpacing(); - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 1: %1").arg(a)); - break; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if (SpecialChars::isBreak(hl->ch)) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } - break; + current.addLeftIndent = false; + current.wasFirstInRow = true; } - // #7944 : Do not use static_cast<int> here, this is not consistent with computations - // performed at lines 1488-1512 and can trigger hang due to changing region detection - //pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); - //pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); - pt1 = QPoint(qRound(current.xPos+extra.Right), qRound(current.yPos+BotOffset)); - pt2 = QPoint(qRound(current.xPos+extra.Right), qRound(ceil(current.yPos-asce))); - if (cl.contains(pf2.map(pt1)) && cl.contains(pf2.map(pt2))) - break; -// else -// qDebug() << QString("looking for start of line at %1,%2").arg(current.xPos).arg(current.yPos); } - if (fromOut) - { - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 2: %1").arg(a); - break; - } - current.xPos--; - current.xPos = qMax(current.xPos, current.colLeft); - } } - else + else if (!inOverflow && !current.afterOverflow && current.lastInRowLine) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK ) - && current.hasDropCap) + current.yPos++; + a = 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; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcap2: y=%1+%2").arg(current.yPos).arg(maxDY); + current.restartX = current.xPos = current.colLeft; + maxDX = 0; } -// qDebug() << QString("layout: next lower3 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { -// qDebug() << QString("next line (grid): y=%1+%2").arg(current.yPos).arg(m_Doc->typographicSettings.valueBaseGrid); - - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - } - else - { -// qDebug() << QString("next line (auto): y=%1+%2").arg(current.yPos).arg(style.lineSpacing()); - //#5845 : use next paragraph line spacing for switching to next paragraph instead of current one - //current.yPos += style.lineSpacing(); - const ParagraphStyle& pStyle = itemText.paragraphStyle(a+1); - double lineSpacing = pStyle.lineSpacing(); - if (pStyle.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - lineSpacing = pStyle.charStyle().font().height(pStyle.charStyle().fontSize() / 10.0); - else if (pStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - lineSpacing = m_Doc->typographicSettings.valueBaseGrid; - current.yPos += lineSpacing; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if ( SpecialChars::isBreak(hl->ch) ) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } } + lastLineY = current.rowDesc; + current.mustLineEnd = current.colRight; + current.restartRowIndex = current.restartIndex; } - - - // calc. needed vertical space - // Let’s try to change into "calc. _wanted_ vertical space" - pm - if (current.itemsInLine != 0) + if (inOverflow) { - if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) - { - // put line back to top - current.line.y -= DropCapDrop; - itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; - } + current.afterOverflow = true; + inOverflow = false; + current.addLeftIndent = false; + current.recalculateY = false; } - - fillInTabLeaders(itemText, current.line); - - current.startOfCol = false; -// qDebug() << QString("layout: line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - if (current.line.firstItem > current.line.lastItem) - ; //qDebug() << QString("layout: empty line %1 - %2").arg(current.line.firstItem).arg(current.line.lastItem); - else if (current.itemsInLine > 0) - itemText.appendLine(current.line); + else + { + current.afterOverflow = false; + } + outs = false; + current.addLine = false; + current.lastInRowLine = false; current.startLine(a+1); - outs = false; if (goNoRoom) { goNoRoom = false; MaxChars = a+1; -// qDebug() << QString("no room C: %1").arg(a+1); goto NoRoom; } if (goNextColumn) @@ -2122,16 +2166,41 @@ current.column++; if (current.column < Cols) { - current.nextColumn(asce); + if (firstLineOffset() == FLOPRealGlyphHeight) + asce = 0; + current.nextColumn(); + current.mustLineEnd = current.colRight; + current.addLeftIndent = true; + lastLineY = extra.Top; + current.rowDesc = 0; + current.recalculateY = true; } else { MaxChars = a; -// qDebug() << QString("no room D: %1").arg(a); goto NoRoom; } } } + if (a == itemText.length() -1) + { + if (!current.afterOverflow || current.addLine) + { + current.addLine = true; + current.lastInRowLine = true; + current.breakLine(itemText, style, firstLineOffset(),a); + } + if (current.afterOverflow && !current.addLine) + { + if (current.restartIndex < current.line.firstItem) + { + a = current.restartLine(false,true); + continue; + } + else + current.breakLine(itemText, style, firstLineOffset(),a); + } + } } if (goNoRoom) { @@ -2139,18 +2208,35 @@ goto NoRoom; } // end of itemText - int a = itemText.length()-1; - hl = a >=0 ? itemText.item(a) : NULL; - current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (current.itemsInLine >0) + { + int a = itemText.length()-1; + hl = a >=0 ? itemText.item(a) : NULL; + current.breakLine(itemText, style, firstLineOffset(), a); -// if (style.alignment() != 0) - { + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) + { + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) + { + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); + } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); + current.finishLine(EndX); + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - { current.line.width += opticalRightMargin(itemText, current.line); - } OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -2174,26 +2260,18 @@ current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } - } - - if (current.itemsInLine != 0) - { if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap ) { // put line back to top current.line.y -= DropCapDrop; itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - } - fillInTabLeaders(itemText, current.line); - current.startOfCol = false; - goNextColumn = false; + fillInTabLeaders(itemText, current.line); + current.startOfCol = false; + goNextColumn = false; -// qDebug() << QString("layout: last line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - - if (current.itemsInLine > 0) { itemText.appendLine(current.line); + current.startOfCol = false; } } MaxChars = itemText.length(); @@ -3310,7 +3388,6 @@ void PageItem_TextFrame::setNewPos(int oldPos, int len, int dir) { - bool isSpace, wasSpace; if ( dir > 0 && oldPos < len ) { @@ -3563,8 +3640,6 @@ } -#endif //NLS_PROTO - bool PageItem_TextFrame::createInfoGroup(QFrame *infoGroup, QGridLayout *infoGroupLayout) { int Parag = 0; |
|
I have lost my hope to end this task. Almost... In formatting4.patch you have my next try. I am crossing fingers for that it will work in acceptable manner. I wish to get new staff into my C++ IDE. |
|
Looks good now! I continue testing. |
|
Seems something wrong happens with empty paragraphs - starting investigation. |
|
formatting5.patch (84,636 bytes)
Index: Scribus/scribus/pageitem_textframe.cpp =================================================================== --- Scribus/scribus/pageitem_textframe.cpp (wersja 16855) +++ Scribus/scribus/pageitem_textframe.cpp (kopia robocza) @@ -70,7 +70,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -83,7 +82,6 @@ unicodeInputCount = 0; unicodeInputString = ""; lastUndoAction = NOACTION; -// lastAction4Paragraph = false; connect(&itemText,SIGNAL(changed()), this, SLOT(slotInvalidateLayout())); } @@ -155,9 +153,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - { - result = result.subtract(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); - } + result = result.subtracted(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -192,7 +188,7 @@ if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top())) continue; if (docItem->textFlowAroundObject()) - result = result.subtract(itemShape(docItem, 0, 0)); + result = result.subtracted(itemShape(docItem, 0, 0)); if (docItem->isGroupControl) currentGroup = docItem->Groups.top(); } @@ -202,7 +198,6 @@ return result; } - void PageItem_TextFrame::setShadow() { if (OnMasterPage.isEmpty()) @@ -235,10 +230,6 @@ currentShadow = newShadow; } } - -#ifdef NLS_PROTO -#include "text/pageitem_textframe.cpp" -#else static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->")) { @@ -258,7 +249,6 @@ dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } - static const bool legacy = true; /* @@ -342,6 +332,20 @@ 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 char where line computing should be restarted + int restartRowIndex; //index of char where row of text is started + double restartX; //starting X position of line if must be restarted + double rowDesc; + double ascend; double descend; double width; @@ -373,22 +377,23 @@ } /// move position to next column - void nextColumn(double asce) + void nextColumn(double asce = 0.0) { startOfCol = true; colLeft = (colWidth + colGap) * column + insets.Left + lineCorr; + //now colRight is REAL column right edge colRight = colLeft + colWidth; if (legacy) - colRight += insets.Right + lineCorr; //??? + colRight += lineCorr; xPos = colLeft; - yPos = asce + insets.Top + lineCorr + 1; + yPos = asce + insets.Top + lineCorr; } bool isEndOfCol(double morespace = 0) { return yPos + morespace + insets.Bottom + lineCorr > frameHeight; } - + /** init fields for a new line at current position */ @@ -398,15 +403,20 @@ line.x = xPos; line.y = yPos; line.firstItem = first; - line.ascent = 10; - line.descent = 0; - line.width = 0; - line.naturalWidth = 0; + line.lastItem = 0; + line.ascent = 0.0; + line.descent = 0.0; + line.width = 0.0; + line.naturalWidth = 0.0; line.colLeft = colLeft; breakIndex = -1; - breakXPos = 0; - maxShrink = 0; - maxStretch = 0; + breakXPos = 0.0; + maxShrink = 0.0; + maxStretch = 0.0; + width = 0.0; + leftIndent = 0.0; + rightMargin = 0.0; + rowDesc = 0.0; } @@ -423,12 +433,12 @@ } /// called when a possible break is passed - void rememberBreak(int index, double pos) + void rememberBreak(int index, double pos, double morespace = 0) { - if (pos > colRight) + if (pos > colRight - morespace) { // only look for the first break behind the right edge - maxShrink = 0; + //maxShrink = 0; // check if we already have a better break if (breakIndex >= 0) @@ -439,12 +449,8 @@ if (newLooseness >= oldLooseness) return; } - breakXPos = colRight; } - else - { - breakXPos = pos; - } + breakXPos = pos; breakIndex = index; } @@ -460,9 +466,9 @@ // so that endOfLine() returns correct result updateHeightMetrics(itemText); // #9060 : update line offset too - updateLineOffset(itemText, style, offsetPolicy); + //updateLineOffset(itemText, style, offsetPolicy); } - + /// use the last remembered break to set line width and itemrange void finishLine(double endX) { @@ -471,109 +477,66 @@ line.width = endX - line.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) - return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight; + res = ceil(xPos + lineCorr - maxShrink) + ceil(moreSpace) >= floor(colRight); else - return xPos + moreSpace - maxShrink >= colRight; + res = ceil(xPos - maxShrink) + ceil(moreSpace) >= floor(colRight); + return res; } - - /// find x position to start current line - double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace) - { - QPoint pt1, pt2; - double tmpX = xPos; - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - // increase pt1/pt2 until i-beam reaches end of line - while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2)))) - { - tmpX++; - if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight) - { - return tmpX; - } - pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); - pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); - } - return tmpX; - } - + /// find x position where this line must end - double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace = 0) + double endOfLine(const QRegion& shape, const QMatrix& pf2, double morespace, int Yasc, int Ydesc) { - // Keep old code for reference - /*double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - QPoint pt1, pt2; - // qDebug() << QString("endx start=%1, hl is '%2'").arg(EndX).arg(hl->ch); - do { - EndX += 0.125; - pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent)); - pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent))); - } while ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace) - && shape.contains(pf2.map(pt1)) - && shape.contains(pf2.map(pt2)) - );*/ - // if we aren't restricted further, we'll end at this maxX: double maxX = colRight - morespace; - if (legacy) maxX -= (lineCorr + insets.Right); + if (legacy) maxX -= lineCorr; - double StartX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); - int xPos = static_cast<int>(ceil(maxX + insets.Right)); - int yDesc = static_cast<int>(yPos+line.descent); - int yAsc = static_cast<int>(ceil(yPos-line.ascent)); + double StartX = floor(qMax(line.x, qMin(maxX,breakXPos-maxShrink-1))-1); + int xPos = static_cast<int>(ceil(maxX)); - QPoint pt12 (xPos, yDesc); - QPoint pt22 (xPos, yAsc); + QPoint pt12 (xPos, Yasc); + QPoint pt22 (xPos, Ydesc); + QRect pt(pt12,pt22); - // simple and fast case: transformed line completely falls within range - // this will happen if we don't wrap around anything - ie. very often - QPolygon p; - p.append (pf2.map (QPoint (StartX, yAsc))); - p.append (pf2.map (QPoint (StartX, yDesc))); - p.append (pf2.map (pt12)); - p.append (pf2.map (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.numRects() == 1) - { - int xPos = qRound(ceil(StartX + 0.125 + insets.Right)); - pt12.setX(xPos); - pt22.setX(xPos); - if (shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))) - { - QRect rect = lineI.rects().at(0); - double mx = qMax(rect.left(), rect.right()) - pf2.dx(); - int steps = static_cast<int>((mx - StartX - insets.Right - 2)/0.125); - if (steps > 0) - StartX += steps * 0.125; - } - } - - // qDebug()<<"endOfLine: going for the hard case"; double EndX2 = StartX; - double Interval = 0.125; + double Interval = 0.25; do { + int xP = static_cast<int>(ceil(EndX2 + morespace)); + pt.moveTopLeft(QPoint(xP, Yasc)); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()) + break; EndX2 += Interval; - int xPos = qRound(ceil(EndX2 + insets.Right)); - pt12.setX (xPos); - pt22.setX (xPos); - } while ((EndX2 < maxX) && shape.contains(pf2.map(pt12)) && shape.contains(pf2.map(pt22))); + } while ((EndX2 < maxX) && QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty()); - /*if (EndX!=EndX2) - { - qDebug()<<EndX<<EndX2<<StartX<<maxX; - qDebug()<<"DIFFERING ENDX!!!!!"; - }*/ - return EndX2; + return qMin(EndX2, maxX); } - - + double getLineAscent(const StoryText& itemText) { double result = 0; @@ -684,15 +647,18 @@ || (ch == SpecialChars::LINEBREAK) || (ch.isSpace())) continue; const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc)); + double scaleV = cStyle.scaleV() / 1000.0; + double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0); + if (itemText.object(line.firstItem+zc) != 0) { - asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0); + asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * scaleV + offset; desc = 0.0; } else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0) { - asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0); - desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0); + asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0) * scaleV + offset; + desc = cStyle.font().realCharDescent(ch, cStyle.fontSize() / 10.0) * scaleV - offset; } // qDebug() << QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result); line.ascent = qMax(line.ascent, asce); @@ -700,44 +666,47 @@ } } - void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) - { - if (itemsInLine <= 0) - return; - if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) - { - //FIXME: use glyphs, not chars - double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).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.firstItem); - double firstasce = style.lineSpacing(); - double currasce = getLineHeight(itemText); - double adj = firstasce - currasce; -// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); - line.ascent = currasce; - line.y -= adj; - yPos -= adj; - } - } +// yPos should not be changed when all line is already calculated - at new y position there can be overflow!!! +// +// void updateLineOffset(const StoryText& itemText, const ParagraphStyle& style, FirstLineOffsetPolicy offsetPolicy) +// { +// if (itemsInLine <= 0) +// return; +// if ((!hasDropCap) && (startOfCol) && (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing)) +// { +// //FIXME: use glyphs, not chars +// double firstasce = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0); +// double adj (0.0); +// double currasce (this->getLineAscent(itemText)); +// if( offsetPolicy == FLOPRealGlyphHeight ) +// { +// adj = line.y - insets.Top -currasce; +// //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.firstItem); +// double firstasce = style.lineSpacing(); +// double currasce = getLineHeight(itemText); +// double adj = firstasce - currasce; +//// qDebug() << QString("move2 line %1.. down by %2").arg(current.line.firstItem).arg(-adj); +// line.ascent = currasce; +// line.y -= adj; +// yPos -= adj; +// } +// } private: double frameWidth; @@ -802,8 +771,11 @@ .arg(style.minWordTracking()).arg(style.minGlyphExtension()); */ + int startItem = line.firstItem; + if (itemText.item(startItem)->effects() & ScStyle_DropCap) + startItem++; // distribute whitespace on spaces and glyphs - for (int yof = line.firstItem; yof <= line.lastItem; ++yof) + for (int yof = startItem; yof <= line.lastItem; ++yof) { double wide = itemText.item(yof)->glyph.wide(); if (!SpecialChars::isExpandingSpace(itemText.text(yof))) @@ -839,46 +811,42 @@ } } -/// calculate how much the first char should stick out to the left -static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) -{ - int b = line.firstItem; - while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace)) - ++b; +//definied but not used +///// calculate how much the first char should stick out to the left +//static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) +//{ +// int b = line.firstItem; +// while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_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; -} +// 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); +// } +// return leftCorr; +//} - - /// calculate how much the last char should stick out to the right static double opticalRightMargin(const StoryText& itemText, const LineSpec& line) { @@ -923,10 +891,15 @@ return 0.0; } +static double findRealOverflowEnd(const QRegion& shape, const QMatrix& pf2, QRect pt, double maxX) +{ + while (!QRegion(pf2.mapToPolygon(pt)).subtracted(shape).isEmpty() && pt.right() < maxX) + pt.translate(1, 0); + if (pt.right() >= maxX) + return maxX; + return pt.left() +0.5; +} - - - void PageItem_TextFrame::layout() { // qDebug()<<"==Layout==" << itemName() ; @@ -957,10 +930,9 @@ firstChar = 0; // qDebug() << QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame()); -// ScribusView* view = m_Doc->view(); QMatrix pf2; QPoint pt1, pt2; - /*QRegion cm;*/ + QRect pt; double chs, chsd = 0; double oldCurY, EndX, OFs, wide, kernVal; QString chstr; @@ -969,7 +941,6 @@ int /*ParagraphStyle::OpticalMarginType*/ opticalMargins = ParagraphStyle::OM_None; bool outs = false; - bool fBorder = false; bool goNoRoom = false; bool goNextColumn = false; @@ -983,12 +954,12 @@ tTabValues.clear(); bool DropCmode = false; - double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0; + double desc=0, asce=0, realAsce=0, realDesc = 0; + double maxDY=0, maxDX=0; double DropCapDrop = 0; int DropLines = 0; int DropLinesCount = 0; - itemText.clearLines(); double lineCorr = 0; @@ -1006,7 +977,11 @@ current.init(Width, Height, extra, lineCorr); current.initColumns(columnWidth(), ColGap); current.hyphenCount = 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; + // dump styles /* for (int i=0; i < itemText.nrOfParagraphs(); ++i) { @@ -1018,7 +993,6 @@ dumpIt(itemText.defaultStyle()); */ -// pf2.begin(view->viewport()); pf2.translate(Xpos, Ypos); pf2.rotate(Rot); @@ -1044,7 +1018,8 @@ pf2.scale(1, -1); } - current.nextColumn(0); + current.nextColumn(); + lastLineY = extra.Top; // find start of first line if (firstInFrame() < itemText.length()) @@ -1070,19 +1045,33 @@ } else chs = hl->fontSize(); - desc2 = -hl->font().descent(chs / 10.0); + desc = -hl->font().descent(chs / 10.0); current.yPos = extra.Top + lineCorr; // qDebug() << QString("first line at y=%1").arg(current.yPos); } else // empty itemText: { - desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); - current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; + desc = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); + current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc; } current.startLine(firstInFrame()); + outs = false; OFs = 0; MaxChars = 0; + double realEnd = 0; + current.restartIndex = current.restartRowIndex = firstInFrame(); + 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; + for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a); @@ -1091,27 +1080,17 @@ if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); -// qDebug() << QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); const CharStyle& charStyle = (hl->ch != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle()); - if (!charStyle.parent().isEmpty()) - { -// qDebug() << QString("charstyle pos %1: %2 (%3 %4 %5 %6 %7 %8 %9)").arg(a).arg(charStyle.parent()) -// .arg((uint)charStyle.parentStyle()).arg(charStyle.font().scName()).arg(charStyle.fontSize()) -// .arg(charStyle.fillColor()).arg(charStyle.strokeColor()).arg(charStyle.parentStyle()->name()).arg((uint)charStyle.parentStyle()->parentStyle()); - } -// qDebug() << QString("charstyle pos %1: %2 (%3)").arg(a).arg(charStyle.asString()).arg(charStyle.fontSize()); -// qDebug() << QString("style @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); + chstr = ExpandToken(a); + 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); - chstr = ExpandToken(a); -// qDebug() << QString("expanded token: '%1'").arg(chstr); if (chstr.isEmpty()) chstr = SpecialChars::ZWNBSPACE; if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); // find out about par gap and dropcap @@ -1119,7 +1098,6 @@ { if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP) { - current.yPos += style.gapBefore(); if (chstr[0] != SpecialChars::PARSEP) { DropCmode = style.hasDropCap(); @@ -1165,21 +1143,34 @@ else hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); } - // qDebug() << QString("textframe(%1,%2): len=%3, fontsize=%4, ascent=%5").arg(Xpos).arg(Ypos).arg(itemText.length()) -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()); if (current.itemsInLine == 0) { - // more about par gap and dropcaps - if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && !current.startOfCol)) // after || always evaluates to false? FIXME + if (style.rightMargin() == 0) { -// qDebug() << QString("gap before2: y=%1+%2").arg(current.yPos).arg(style.gapBefore()); - current.yPos += style.gapBefore(); + //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,extra.Top); + // more about par gap and dropcaps + if ((a > firstInFrame() && itemText.text(a-1) == SpecialChars::PARSEP) || (a == 0 && BackBox == 0 && current.startOfCol)) + { + if (!current.afterOverflow && current.recalculateY && !current.startOfCol) + current.yPos += style.gapBefore(); DropCapDrop = 0; if (chstr[0] != SpecialChars::PARSEP) DropCmode = style.hasDropCap(); else DropCmode = false; - if (DropCmode) + if (DropCmode && !current.afterOverflow) { DropLines = style.dropCapLines(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1189,35 +1180,22 @@ if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) DropCapDrop = style.lineSpacing() * (DropLines-1); else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); + DropCapDrop = charStyle.font().height(hlcsize10) * (DropLines-1); } -// qDebug() << QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop); - current.yPos += DropCapDrop; } } } - // find charsize & y pos +// ######## find charsize factors if (DropCmode) { - // dropcap active? - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); - else - { - if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - DropCapDrop = style.lineSpacing() * (DropLines-1); - else - DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); - } - // FIXME : we should ensure that fonts are loaded before calls to layout() // ScFace::realCharHeight()/Ascent() ensure font is loaded thanks to an indirect call to char2CMap() // ScFace::ascent() can be called safely afterwards double realCharHeight = charStyle.font().realCharHeight(chstr[0], 1); double realCharAscent = charStyle.font().realCharAscent(chstr[0], 1); - double fontAscent = charStyle.font().ascent(style.charStyle().fontSize() / 10.0); + double fontAscent = charStyle.font().ascent(hlcsize10); if (realCharHeight == 0.0) - realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); + realCharHeight = charStyle.font().height(hlcsize10); if (realCharAscent == 0.0) realCharAscent = fontAscent; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) @@ -1234,7 +1212,7 @@ } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(hlcsize10); chsd = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharHeight)); chs = (10 * ((currasce * (DropLines-1) + fontAscent) / realCharAscent)); } @@ -1249,7 +1227,7 @@ else chs = charStyle.fontSize(); } - // find tracking +// ######## set StartOfLine (and find tracking?) if (current.itemsInLine == 0) { itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine); @@ -1262,7 +1240,8 @@ } hl->glyph.yadvance = 0; oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); - // find out width of char + +// ######## find out width, ascent and descent of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1290,168 +1269,177 @@ itemHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - asce = m_Doc->typographicSettings.valueBaseGrid * DropLines; + realAsce = m_Doc->typographicSettings.valueBaseGrid * DropLines; else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) - asce = style.lineSpacing() * DropLines; + realAsce = style.lineSpacing() * DropLines; else - asce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; + realAsce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; } hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / itemHeight); + hl->glyph.scaleV = (realAsce / itemHeight); hl->glyph.scaleH *= hl->glyph.scaleV; } else { - double realCharHeight = charStyle.font().realCharHeight(chstr[0], charStyle.fontSize() / 10.0); + double realCharHeight = charStyle.font().realCharHeight(chstr[0], hlcsize10); if (realCharHeight == 0) realCharHeight = charStyle.font().height(style.charStyle().fontSize() / 10.0); - wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0); - asce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0); -// qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); + wide = (charStyle.font().realCharWidth(chstr[0], chsd / 10.0) * scaleH) + (1 - scaleH); //dropcaps are to close to next glyphs if glyphs are hard scaled + realAsce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0) * scaleV + offset; + asce = charStyle.font().ascent(hlcsize10); + // qDebug() QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0]); hl->glyph.scaleH /= hl->glyph.scaleV; - hl->glyph.scaleV = (asce / realCharHeight); + hl->glyph.scaleV = (realAsce / realCharHeight); hl->glyph.scaleH *= hl->glyph.scaleV; + hl->glyph.xoffset -= 0.5; //drop caps are always to far from column left edge } hl->glyph.xadvance = wide; - desc2 = 0; - desc = 0; + desc = realDesc =0; } else // !DropCMode { -// qDebug( ) << QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") -// .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent()); - if (SpecialChars::isExpandingSpace(hl->ch)) { double wordtracking = charStyle.wordTracking(); hl->glyph.xadvance *= wordtracking; wide *= wordtracking; } - // find ascent / descent - double hlcsize10=charStyle.fontSize() / 10.0; if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) - { - desc = desc2 = 0; - } + desc = realDesc = 0; else { - desc = desc2 = -charStyle.font().descent(hlcsize10); + desc = -charStyle.font().descent(hlcsize10); + realDesc = charStyle.font().realCharDescent(chstr[0], hlcsize10) * scaleV - offset; current.rememberShrinkStretch(hl->ch, wide, style); } asce = charStyle.font().ascent(hlcsize10); -// wide = wide * hl->glyph.scaleH; + realAsce = charStyle.font().realCharAscent(chstr[0], hlcsize10) * scaleV + offset; } - fBorder = false; - // end of col reached? -// qDebug() << QString("eocol? %1 + %2 + %3 > %4 -- asce=%5").arg(current.yPos).arg(extra.Bottom).arg(lineCorr).arg(Height).arg(asce); - if (current.isEndOfCol()) + +// ######## check for Y position at beginning of line + if (current.itemsInLine == 0 && !current.afterOverflow) { - current.column++; - if (current.column < Cols) + if (current.recalculateY) { - // start next col - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) - || ((a == firstInFrame()) && (BackBox == 0))) + //if top of column Y position depends on first line offset + if (current.startOfCol) { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) + lastLineY = qMax(lastLineY, extra.Top + lineCorr); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); + if (firstLineOffset() == FLOPRealGlyphHeight) + { + if (DropCmode) + current.yPos += asce; + else + current.yPos += realAsce; + } + else if (firstLineOffset() == FLOPLineSpacing) + current.yPos += style.lineSpacing(); else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); + current.yPos += asce; } - if (DropCmode) - DropLines = style.dropCapLines(); + else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + if (current.yPos <= lastLineY) + current.yPos = lastLineY +1; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } } -// qDebug() << QString("layout: nextcol grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + else { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + current.yPos += m_Doc->typographicSettings.valueBaseGrid; + double by; + if (OwnPage != -1) + by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); + int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); + int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); + current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; + } + else + current.yPos += style.lineSpacing(); } + if (DropCmode) + current.yPos += DropCapDrop; } - else + //set left indentation + current.leftIndent = 0.0; + if (current.addLeftIndent && (maxDX == 0 || DropCmode)) { - MaxChars = a; -// qDebug() << QString("no room A: %1").arg(a); - goto NoRoom; + current.leftIndent = style.leftMargin(); + if (current.hasDropCap) + current.leftIndent = 0; + if (a==0 || (a > 0 && (itemText.text(a-1) == SpecialChars::PARSEP))) + current.leftIndent += style.firstIndent(); + current.addLeftIndent = false; } } - // ok, there's more room in col - if (current.itemsInLine == 0) + current.recalculateY = true; + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) { -// qDebug() << QString("newline: '%1' %2 %3").arg(a).arg(current.yPos).arg(asce); - // start a new line - double TopOffset = asce; - double BotOffset = desc2; - goNoRoom = false; - if (current.startOfCol) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { -// qDebug() << QString("current.startOfCol: %1 + %2 + %3 + 1 =%4").arg(asce).arg(extra.Top).arg(lineCorr).arg(asce + extra.Top + lineCorr + 1); - current.yPos = asce + extra.Top + lineCorr + 1; -// if (((a > 0) && (itemText.at(a-1)->ch == QChar(13))) || ((a == 0) && (BackBox == 0))) -// current.yPos += m_Doc->docParagraphStyles[hl->cab].gapBefore; + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } -// qDebug() << QString("layout: nextline grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + if (current.itemsInLine == 0 && !current.afterOverflow) + { + //start a new line + goNoRoom = false; + + // find line`s start + pt1 = QPoint(static_cast<int>(floor(current.xPos)), maxYAsc); + pt2 = QPoint(static_cast<int>(ceil(current.xPos + (style.minGlyphExtension() * wide))),maxYDesc); + 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; + while (!done) { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("useBaselIneGrid: %1 * %2 + %3 - %4").arg(ol2 / 10000.0).arg(m_Doc->typographicSettings.valueBaseGrid).arg(m_Doc->typographicSettings.offsetBaseGrid).arg(by); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } - /* this causes different spacing for first line: - if (current.yPos-TopOffset < 0.0) - { - qDebug(= << QString("current.yPos - Ascender < 0 (%1 - %2 < 0)").arg(current.yPos).arg(TopOffset); - current.yPos = TopOffset+1; - } - */ - // find linelength: - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); - // increase pt1/pt2 until i-beam reaches end of line -// qDebug() << QString("linestart: %1 + %2 + %3 < %4").arg(current.xPos).arg(wide).arg(style.rightMargin()).arg(current.colRight); - double leftIndent = 0; - double xStep = legacy? 1 : 0.125; - while (!cl.contains(pf2.map(pt1)) || !cl.contains(pf2.map(pt2)) || current.isEndOfLine(wide + leftIndent + style.rightMargin())) - { - fBorder = true; - current.xPos += xStep; - if (current.isEndOfLine(wide + leftIndent + style.rightMargin())) + Xpos = current.xPos; + Xend = current.xPos + current.leftIndent; + //check if in indent any overflow occurs + while (Xpos <= Xend && Xpos < current.colRight) { -// qDebug() << QString("eocol %5? %1 + %2 + %3 + %4").arg(current.yPos).arg(current.startOfCol).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(style.lineSpacing()).arg(current.column); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + Xpos = current.xPos = realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + Xend = current.xPos + current.leftIndent; + } + else + Xpos++; + pt.moveTopLeft(QPoint(static_cast<int>(floor(Xpos)),maxYAsc)); + } + current.xPos = Xend; + done = true; + if (current.isEndOfLine((style.minGlyphExtension() * wide) + current.rightMargin + current.leftIndent)) + { // new line - fBorder = false; - current.xPos = current.colLeft; - - leftIndent = style.leftMargin(); - if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) - leftIndent += style.firstIndent(); - - if (current.startOfCol) - current.yPos++; - else - current.yPos += qMax(style.lineSpacing(), 1.0); -// qDebug() << QString("layout: next lower line grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); + current.xPos = qMax(current.colLeft, maxDX); + current.yPos ++; if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { double by = Ypos; @@ -1459,83 +1447,110 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; } - if (current.isEndOfCol()) + lastLineY = maxYAsc +1; + if (current.startOfCol) { - fBorder = false; - current.column++; - if (current.column < Cols) + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) { - current.nextColumn(asce); - if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == firstInFrame()) && (BackBox == 0))) - { - if (chstr[0] != SpecialChars::PARSEP) - DropCmode = style.hasDropCap(); - else - DropCmode = false; - if (DropCmode) - { - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); - else - desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); - } - if (DropCmode) - DropLines = style.dropCapLines(); - } -// qDebug() << QString("layout: nextcol2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { - double by = Ypos; - if (OwnPage != -1) - by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); - int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); - int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); - current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - } + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); } - else - { - MaxChars = a; -// qDebug() << QString("no room B: %1").arg(a); - goto NoRoom; - } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + pt.moveTopLeft(QPoint(static_cast<int>(floor(current.xPos)),maxYAsc)); + done = false; } - pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); - pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); + if (current.isEndOfCol(realDesc)) + { + current.column++; + if (current.column < Cols) + { + newColumn = true; + break; + } + else + { + MaxChars = a; + goto NoRoom; + } + } } - - if (((fBorder)) && (!current.hasDropCap)) - current.xPos += extra.Left; - // indent first line of par - if (a > 0) + if (newColumn) { - if (itemText.text(a-1) == SpecialChars::PARSEP) - current.xPos += style.firstIndent(); + current.nextColumn(); + current.mustLineEnd = current.colRight; + current.restartX = current.xPos; + lastLineY = current.yPos; + current.rowDesc = 0; + a--; + current.recalculateY = true; + current.addLeftIndent = true; + continue; } + current.line.x = current.restartX = current.xPos; + current.line.y = current.yPos; + } + + //check if line must start at new Y position due to current glyph height or previous line descent + if (!SpecialChars::isBreak(hl->ch, true) + && !SpecialChars::isBreakingSpace(hl->ch) + && !SpecialChars::isExpandingSpace(hl->ch) + && hl->ch != SpecialChars::TAB) + { + double diff = 0; + if (current.startOfCol || DropCmode) + diff = realAsce * scaleV + offset - (current.yPos - lastLineY); else + diff = charStyle.font().realCharAscent(QChar('l'), hlcsize10) * scaleV + offset - (current.yPos - lastLineY); + if (diff >= 1 || (!DropCmode && diff > 0)) { - if (legacy) - current.xPos += style.firstIndent(); + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + current.yPos = maxDY; + maxDX = 0; + } + int linesDrop = 0; + if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) + { + linesDrop = ceil(diff/m_Doc->typographicSettings.valueBaseGrid); + current.yPos += m_Doc->typographicSettings.valueBaseGrid * linesDrop; + } + else /*if (current.startOfCol)*/ + { + //FIX ME - that is ugly hack I must made, because simply expression + //current.yPos += diff; stop working, dont 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; + } + } + a = current.restartRow(false); + continue; } - // add left margin - if (!current.hasDropCap) - current.xPos += style.leftMargin(); - if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct) { - current.xPos += opticalLeftMargin(itemText, current.line); - } -// qDebug() << QString("store line: (%1,%2)").arg(current.xPos).arg(current.yPos); - current.line.x = current.xPos; - current.line.y = current.yPos; - fBorder = false; } - else { -// qDebug() << QString("cont.' line: '%1'").arg(a); - } // right tab stuff if (tabs.active) { @@ -1589,7 +1604,6 @@ current.xPos = current.colLeft + tCurX; // remember fill char -// qDebug() << QString("tab: %1 '%2'").arg(tCurX).arg(tabs.fillChar); if (!tabs.fillChar.isNull()) { hl->glyph.growWithTabLayout(); TabLayout * tglyph = dynamic_cast<TabLayout*>(hl->glyph.more); @@ -1614,7 +1628,6 @@ if (DropCmode) hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0); - // remember x pos double breakPos = current.xPos; @@ -1630,57 +1643,194 @@ else // other tabs.active { current.xPos = qMax(current.xPos, current.colLeft); - } - - //FIXME: asce / desc set correctly? - if (legacy && - (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) - || hl->ch == SpecialChars::SHYPHEN)) + } + // remember possible break + if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB)) { - if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink + charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0))), qRound(ceil(current.yPos-asce))); + current.rememberBreak(a, breakPos, style.rightMargin()); } - else - { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); - } } - else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + //check against space before PARSEP + if (SpecialChars::isBreakingSpace(hl->ch) && (a + 1 < itemText.length()) && (itemText.item(a+1)->ch == SpecialChars::PARSEP)) { - pt1 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); + a++; + hl = itemText.item(a); } - else + + // test if end of line reached + double overflowWidth = 0.0; + double hyphWidth = 0.0; + bool inOverflow = false; + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + hyphWidth = charStyle.font().charWidth('-', hlcsize10) * (charStyle.scaleH() / 1000.0); + if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(hl->ch, Cols > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd) { - pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(current.yPos+desc)); - pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(ceil(current.yPos-asce))); + //end of row reached - right column, end of column, break char or line must end + if (current.itemsInLine == 0 && !current.afterOverflow && !SpecialChars::isBreak(hl->ch, Cols > 1)) + { + //no glyphs in line, so start new row + if (SpecialChars::isBreak(hl->ch, Cols > 1)) + current.restartRowIndex = a +1; + a = current.restartRow(true); + inOverflow = false; + outs = false; + continue; + } + //there we have some glyphs + if ((current.breakIndex < 0) && !SpecialChars::isBreak(hl->ch, Cols > 1)) + { + //force break + a--; + current.breakLine(itemText, style, firstLineOffset(),a); + } + 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.breakIndex <0) + current.mustLineEnd = current.line.x -1; + else if (current.line.firstItem == current.restartIndex) + current.lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0 && current.restartIndex == current.restartRowIndex) + { + current.hasDropCap = false; + maxDX = 0; + current.yPos = maxDY; + } + a = 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; } - - // test if end of line reached - if ((!cl.contains(pf2.map(pt1))) || (!cl.contains(pf2.map(pt2))) || (legacy && current.isEndOfLine(style.rightMargin()))) - outs = true; - if (current.isEndOfCol()) - outs = true; - if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) - goNoRoom = true; - if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) - goNextColumn = true; - - - // remember possible break - // #5783 : comment out "&& !outs" as this make it possible to perform a line break - // before a space which contradicts unicode line breaking rules - if ( (SpecialChars::isBreakingSpace(hl->ch) || hl->ch == SpecialChars::TAB) /*&& !outs*/) + else { - if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) + int charStart, charEnd; + if (current.itemsInLine == 0) { - current.rememberBreak(a, breakPos); + charStart = static_cast<int>(floor(current.line.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) + hyphWidth); + } + if (legacy && + (((hl->ch == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) + || hl->ch == SpecialChars::SHYPHEN)) + { + if (hl->effects() & ScStyle_HyphenationPossible || hl->ch == SpecialChars::SHYPHEN) + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(static_cast<int>(charEnd + hyphWidth), maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + } + else if (!legacy && SpecialChars::isBreakingSpace(hl->ch)) + { + pt1 = QPoint(static_cast<int>(qMax(floor(breakPos - current.maxShrink - (style.minGlyphExtension() * wide)),0.0)), maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + else + { + pt1 = QPoint(charStart, maxYAsc); + pt2 = QPoint(charEnd, maxYDesc); + } + pt = QRect(pt1, pt2); + if (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, 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 (!QRegion(pf2.mapToPolygon(pt)).subtracted(cl).isEmpty()) + { + realEnd = findRealOverflowEnd(cl, pf2, pt, current.colRight); + outs = true; + } + } + } + if (outs) + { + if (current.itemsInLine ==0) + { + current.line.x = current.xPos = realEnd; + a--; + current.startLine(a+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) + { + a--; + current.breakLine(itemText, style, firstLineOffset(), a); + } + //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.addLine && !current.lastInRowLine) + { + if (current.afterOverflow) + { + if (current.breakIndex < 0) + { + current.lastInRowLine = true; + current.mustLineEnd = current.line.x -1; + } + else if (current.line.firstItem == current.restartIndex) + current.lastInRowLine = true; + } + else + current.lastInRowLine = true; + if (current.hasDropCap && DropLinesCount == 0) + { + current.hasDropCap = false; + maxDX = 0; + } + a = current.restartLine(false, true); + inOverflow = false; + outs = false; + continue; + } + current.addLine = true; + current.rightMargin = style.rightMargin(); + current.lastInRowLine = true; + } + else + inOverflow = true; + } } - // hyphenation if (((hl->effects() & ScStyle_HyphenationPossible) || (hl->ch == '-') || hl->ch == SpecialChars::SHYPHEN) && (!outs) && !itemText.text(a-1).isSpace() ) @@ -1688,24 +1838,28 @@ breakPos = current.xPos; if (hl->ch != '-') { - breakPos += charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0); + breakPos += hyphWidth; } double rightHang = 0; if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) { - rightHang = 0.7 * charStyle.font().realCharWidth('-', (charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0)); + rightHang = 0.7 * hyphWidth; } if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin())) { if ((current.hyphenCount < m_Doc->HyCount) || (m_Doc->HyCount == 0) || hl->ch == SpecialChars::SHYPHEN) { - current.rememberBreak(a, breakPos); + current.rememberBreak(a, breakPos, style.rightMargin() + hyphWidth); } } } - - + + if ((hl->ch == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) + goNoRoom = true; + if ((hl->ch == SpecialChars::COLBREAK) && (Cols > 1)) + goNextColumn = true; + ++current.itemsInLine; if (tabs.active) @@ -1725,7 +1879,7 @@ } } - if (DropCmode) + if (DropCmode && !outs) { DropCmode = false; DropLinesCount = 0; @@ -1733,10 +1887,7 @@ current.hasDropCap = true; current.xPos += style.dropCapOffset(); hl->glyph.xadvance += style.dropCapOffset(); -// qDebug() << QString("dropcapoffset: %1 -> %2").arg(current.xPos-style.dropCapOffset()).arg(current.xPos); - current.xPos = qMax(current.xPos, current.colLeft); maxDX = current.xPos; - QPolygon tcli(4); if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) { current.yPos -= m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); @@ -1745,40 +1896,24 @@ by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("baseline adjust after dropcaps: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by); current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; - //FIXME: use current.colLeft instead of xOffset? - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); } else { if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) { current.yPos -= style.lineSpacing() * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY - DropLines * style.lineSpacing()))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*style.lineSpacing()))); } else { - double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); + double currasce = charStyle.font().height(charStyle.fontSize() / 10.0); current.yPos -= currasce * (DropLines-1); -// qDebug() << QString("after dropcaps: y=%1").arg(current.yPos); - tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*currasce))); - tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*currasce))); } } - tcli.setPoint(2, QPoint(qRound(maxDX), qRound(maxDY))); - tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); - // #6821 : the following two lines are causing bad text flow around drop caps - // in some case, discarding them put more emphasis on user control of line spacing - /*cm = QRegion(pf2.map(tcli)); - cl = cl.subtract(cm);*/ -// current.yPos = maxDY; + current.recalculateY = false; } // end of line - if ( SpecialChars::isBreak(hl->ch, Cols > 1) || (outs)) + if (outs) { tabs.active = false; tabs.status = TabNONE; @@ -1786,9 +1921,23 @@ { // find end of line current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); current.finishLine(EndX); - + //addLine = true; + assert(current.addLine); + //current.startOfCol = false; + //addLeftIndent = true; + if (hl->ch == SpecialChars::PARSEP) + { + maxDX = 0; + if (current.hasDropCap) + { + current.yPos = maxDY; + maxDY = 0; + current.hasDropCap = false; + } + } + // if (style.alignment() != 0) { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) @@ -1815,7 +1964,7 @@ { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) current.line.naturalWidth += opticalRightMargin(itemText, current.line); - double optiWidth = current.colRight - style.lineSpacing()/2.0 - current.line.x; + double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing()/2.0 - current.line.x; if (current.line.naturalWidth > optiWidth) current.line.width = qMax(current.line.width - current.maxShrink, optiWidth); // simple offset @@ -1826,52 +1975,46 @@ } else // outs -- last char went outside the columns (or into flow-around shape) { - if (current.breakIndex >= 0) // Hier koenen auch andere Trennungen eingebaut werden + if (current.breakIndex >= 0) + a = current.breakIndex; + assert( a >= 0 ); + assert( a < itemText.length() ); + hl = itemText.item(a); + current.itemsInLine = a - current.line.firstItem + 1; + if (current.addLine) { // go back to last break position -// qDebug() << QString("new break pos a=%1 BuPos=%2 current.breakIndex=%3").arg(a).arg(BuPos).arg(current.breakIndex); - a = current.breakIndex; - assert( a >= 0 ); - assert( a < itemText.length() ); - hl = itemText.item(a); style = itemText.paragraphStyle(a); if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } + style.setLineSpacing(charStyle.font().height(hlcsize10)); else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - current.itemsInLine = a - current.line.firstItem + 1; -// qDebug() << QString("style outs pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style <@%6: %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():"") -// .arg(a); - + if (hl->ch == ' ') { hl->setEffects(hl->effects() | ScStyle_SuppressSpace); hl->glyph.xadvance = 0; } current.updateHeightMetrics(itemText); - current.updateLineOffset(itemText, style, firstLineOffset()); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); + //current.updateLineOffset(itemText, style, firstLineOffset()); + //current.xPos = current.breakXPos; + EndX = current.endOfLine(cl, pf2, current.rightMargin, maxYAsc, maxYDesc); current.finishLine(EndX); - -//??? current.breakXPos = current.line.x; -//??? for (int j=current.line.firstItem; j <= a; ++j) -//??? current.breakXPos += itemText.item(j)->glyph.wide(); + hyphWidth = 0.0; if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) { // insert hyphen - current.hyphenCount++; + if (current.lastInRowLine) + //increase hyphen count only for hyphens a the end of text row, omit hyphens before overflow + current.hyphenCount++; hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); hl->glyph.grow(); hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); - hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); + hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * scaleH; //FIX ME - hyphen is not rendered with proper width - check yhis with large glyphs horizontal scaling eg. 20% + hyphWidth = hl->glyph.more->xadvance; } - else + else { if (hl->ch != '-') current.hyphenCount = 0; @@ -1880,240 +2023,140 @@ } // Justification -// if (style.alignment() != 0) + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) + current.line.width += opticalRightMargin(itemText, current.line); + else + current.line.naturalWidth += hyphWidth; + + OFs = 0; + if (style.alignment() == ParagraphStyle::Rightaligned) + OFs = current.line.width - current.line.naturalWidth; + if (style.alignment() == ParagraphStyle::Centered) + OFs = (current.line.width - current.line.naturalWidth) / 2; + + if ((style.alignment() == ParagraphStyle::Justified) || (style.alignment() == ParagraphStyle::Extended)) + justifyLine(itemText, current.line); + else { if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - current.line.width += opticalRightMargin(itemText, current.line); - - OFs = 0; - if (style.alignment() == ParagraphStyle::Rightaligned) - OFs = current.line.width - current.line.naturalWidth; - if (style.alignment() == ParagraphStyle::Centered) - OFs = (current.line.width - current.line.naturalWidth) / 2; - - if ((style.alignment() == ParagraphStyle::Justified) - || (style.alignment() == ParagraphStyle::Extended)) - { - justifyLine(itemText, current.line); - } - else - { - if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - current.line.naturalWidth += opticalRightMargin(itemText, current.line); - indentLine(itemText, current.line, OFs); - } -// qDebug() << QString("line: endx=%1 next pos=(%2,%3").arg(EndX).arg(current.line.x + current.line.width).arg(current.yPos); - current.xPos = current.line.x + current.line.width; + current.line.naturalWidth += opticalRightMargin(itemText, current.line); + indentLine(itemText, current.line, OFs); } + current.xPos = current.line.x + current.line.width; } - else // no break position + } + if (inOverflow) + current.xPos = realEnd; + + //line break or end of column + if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) + && current.hasDropCap) + { + current.hasDropCap = false; + if (current.yPos < maxDY) + current.yPos = maxDY; + maxDX = 0; + } + if ( SpecialChars::isBreak(hl->ch) ) + { + if (hl->ch == SpecialChars::PARSEP) + current.yPos += style.gapAfter(); + current.hyphenCount = 0; + } + if (current.isEndOfCol(desc)) + { + //check if realy line extends bottom margin + current.updateHeightMetrics(itemText); + if (current.isEndOfCol(current.line.descent)) { - if (a >= current.line.firstItem) + if (current.itemsInLine == 0 || current.column+1 == Cols) { - if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch == SpecialChars::SHYPHEN) - { - current.itemsInLine = 0; - a = current.line.firstItem - 1; - } - else - { - --a; - --current.itemsInLine; - } + goNoRoom = true; + MaxChars = a + 1; + break; } - if (a >= 0) - { - hl = itemText.item(a); - style = itemText.paragraphStyle(a); - if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - { - style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); -// qDebug() << QString("auto linespacing: %1").arg(style.lineSpacing()); - } - else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - style.setLineSpacing(m_Doc->typographicSettings.valueBaseGrid); - } - current.breakLine(itemText, style, firstLineOffset(), a); -// qDebug() << QString("style no break pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent()); -// qDebug() << QString("style nb @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) -// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) -// .arg(a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); -// qDebug() << QString("no break pos: %1-%2 @ %3 wid %4 nat %5 endX %6") -// .arg(current.line.firstItem).arg(current.line.firstItem) -// .arg(current.line.x).arg(current.line.width).arg(current.line.naturalWidth).arg(EndX); - indentLine(itemText, current.line, 0); + goNextColumn = true; } } - if ( outs || SpecialChars::isBreak(hl->ch, (Cols > 1)) ) + if (current.line.firstItem <= current.line.lastItem && current.itemsInLine > 0) { - if (outs && !current.isEndOfLine(hl->glyph.wide() + style.rightMargin())) + if (current.addLine && current.breakIndex >= 0) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK) - && current.hasDropCap) + if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) { - current.hasDropCap = false; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcaps: y=%1 maxDY=%2").arg(current.yPos).arg(maxDY); + // put line back to top + current.line.y -= DropCapDrop; + itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - bool fromOut = true; - double BotOffset = desc+extra.Bottom+lineCorr; - while (!current.isEndOfLine(style.rightMargin())) + fillInTabLeaders(itemText, current.line); + //if right margin is set we temporally save line, not append it + itemText.appendLine(current.line); + current.restartIndex = current.line.lastItem +1; + a = current.restartIndex -1; + current.rowDesc = qMax(current.rowDesc,current.yPos + current.line.descent); + if (!current.lastInRowLine) { - current.xPos++; - if (current.isEndOfLine(style.rightMargin())) + current.restartX = current.xPos; + if (current.addLeftIndent) { - fromOut = false; -// qDebug() << QString("layout: next lower2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); -// qDebug() << QString("nextline: y=%1+%2").arg(current.yPos).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing? m_Doc->typographicSettings.valueBaseGrid : style.lineSpacing()); - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - else - current.yPos += style.lineSpacing(); - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 1: %1").arg(a)); - break; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if (SpecialChars::isBreak(hl->ch)) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } - break; + current.addLeftIndent = false; + current.wasFirstInRow = true; } - // #7944 : Do not use static_cast<int> here, this is not consistent with computations - // performed at lines 1488-1512 and can trigger hang due to changing region detection - //pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); - //pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); - pt1 = QPoint(qRound(current.xPos+extra.Right), qRound(current.yPos+BotOffset)); - pt2 = QPoint(qRound(current.xPos+extra.Right), qRound(ceil(current.yPos-asce))); - if (cl.contains(pf2.map(pt1)) && cl.contains(pf2.map(pt2))) - break; -// else -// qDebug() << QString("looking for start of line at %1,%2").arg(current.xPos).arg(current.yPos); } - if (fromOut) - { - if (current.isEndOfCol(desc) && (current.column+1 == Cols)) - { - goNoRoom = true; - MaxChars = a + 1; -// qDebug() << QString("go no room 2: %1").arg(a); - break; - } - current.xPos--; - current.xPos = qMax(current.xPos, current.colLeft); - } } - else + else if (!inOverflow && !current.afterOverflow && current.lastInRowLine) { - if (( hl->ch == SpecialChars::PARSEP || hl->ch == SpecialChars::LINEBREAK ) - && current.hasDropCap) + current.yPos++; + a = 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; - if (current.yPos < maxDY) - current.yPos = maxDY; -// qDebug() << QString("after dropcap2: y=%1+%2").arg(current.yPos).arg(maxDY); + current.restartX = current.xPos = current.colLeft; + maxDX = 0; } -// qDebug() << QString("layout: next lower3 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid); - - - if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - { -// qDebug() << QString("next line (grid): y=%1+%2").arg(current.yPos).arg(m_Doc->typographicSettings.valueBaseGrid); - - current.yPos += m_Doc->typographicSettings.valueBaseGrid; - } - else - { -// qDebug() << QString("next line (auto): y=%1+%2").arg(current.yPos).arg(style.lineSpacing()); - //#5845 : use next paragraph line spacing for switching to next paragraph instead of current one - //current.yPos += style.lineSpacing(); - const ParagraphStyle& pStyle = itemText.paragraphStyle(a+1); - double lineSpacing = pStyle.lineSpacing(); - if (pStyle.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) - lineSpacing = pStyle.charStyle().font().height(pStyle.charStyle().fontSize() / 10.0); - else if (pStyle.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) - lineSpacing = m_Doc->typographicSettings.valueBaseGrid; - current.yPos += lineSpacing; - } - if (current.hasDropCap) - { - ++DropLinesCount; - if (DropLinesCount >= DropLines) - { - current.hasDropCap = false; - current.xPos = current.colLeft; - } - else - current.xPos = maxDX; - } - else - current.xPos = current.colLeft; - if ( SpecialChars::isBreak(hl->ch) ) - { - if (hl->ch == SpecialChars::PARSEP) - { -// qDebug() << QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter()); - current.yPos += style.gapAfter(); - } - current.hyphenCount = 0; - } } + lastLineY = current.rowDesc; + current.mustLineEnd = current.colRight; + current.restartRowIndex = current.restartIndex; } - - - // calc. needed vertical space - // Let’s try to change into "calc. _wanted_ vertical space" - pm - if (current.itemsInLine != 0) + if (inOverflow) { - if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap) - { - // put line back to top - current.line.y -= DropCapDrop; - itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; - } + current.afterOverflow = true; + inOverflow = false; + current.addLeftIndent = false; + current.recalculateY = false; } - - fillInTabLeaders(itemText, current.line); - - current.startOfCol = false; -// qDebug() << QString("layout: line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - if (current.line.firstItem > current.line.lastItem) - ; //qDebug() << QString("layout: empty line %1 - %2").arg(current.line.firstItem).arg(current.line.lastItem); - else if (current.itemsInLine > 0) - itemText.appendLine(current.line); + else + { + current.afterOverflow = false; + } + outs = false; + current.addLine = false; + current.lastInRowLine = false; current.startLine(a+1); - outs = false; if (goNoRoom) { goNoRoom = false; MaxChars = a+1; -// qDebug() << QString("no room C: %1").arg(a+1); goto NoRoom; } if (goNextColumn) @@ -2122,16 +2165,41 @@ current.column++; if (current.column < Cols) { - current.nextColumn(asce); + if (firstLineOffset() == FLOPRealGlyphHeight) + asce = 0; + current.nextColumn(); + current.mustLineEnd = current.colRight; + current.addLeftIndent = true; + lastLineY = extra.Top; + current.rowDesc = 0; + current.recalculateY = true; } else { MaxChars = a; -// qDebug() << QString("no room D: %1").arg(a); goto NoRoom; } } } + if (a == itemText.length() -1) + { + if (!current.afterOverflow || current.addLine) + { + current.addLine = true; + current.lastInRowLine = true; + current.breakLine(itemText, style, firstLineOffset(),a); + } + if (current.afterOverflow && !current.addLine) + { + if (current.restartIndex < current.line.firstItem) + { + a = current.restartLine(false,true); + continue; + } + else + current.breakLine(itemText, style, firstLineOffset(),a); + } + } } if (goNoRoom) { @@ -2139,18 +2207,35 @@ goto NoRoom; } // end of itemText - int a = itemText.length()-1; - hl = a >=0 ? itemText.item(a) : NULL; - current.breakLine(itemText, style, firstLineOffset(), a); - EndX = current.endOfLine(cl, pf2, style.rightMargin()); - current.finishLine(EndX); + if (current.itemsInLine >0) + { + int a = itemText.length()-1; + hl = a >=0 ? itemText.item(a) : NULL; + current.breakLine(itemText, style, firstLineOffset(), a); -// if (style.alignment() != 0) - { + int maxYAsc = 0, maxYDesc = 0; + if (current.startOfCol) + { + //qMax is used for glyphs shifted or vertically scalled above ascent or below descent + double addAsce = qMax(realAsce, asce); + if (style.lineSpacingMode() != ParagraphStyle::BaselineGridLineSpacing) + { + if (firstLineOffset() == FLOPRealGlyphHeight) + addAsce = realAsce; + else if (firstLineOffset() == FLOPLineSpacing) + addAsce = style.lineSpacing(); + } + maxYAsc = static_cast<int>(floor(current.yPos - addAsce)); + } + else + maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); + + EndX = current.endOfLine(cl, pf2, style.rightMargin(), maxYAsc, maxYDesc); + current.finishLine(EndX); + if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) - { current.line.width += opticalRightMargin(itemText, current.line); - } OFs = 0; if (style.alignment() == ParagraphStyle::Rightaligned) @@ -2174,26 +2259,18 @@ current.line.naturalWidth += opticalRightMargin(itemText, current.line); indentLine(itemText, current.line, OFs); } - } - - if (current.itemsInLine != 0) - { if ( itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap ) { // put line back to top current.line.y -= DropCapDrop; itemText.item(current.line.firstItem)->glyph.yoffset += DropCapDrop; } - } - fillInTabLeaders(itemText, current.line); - current.startOfCol = false; - goNextColumn = false; + fillInTabLeaders(itemText, current.line); + current.startOfCol = false; + goNextColumn = false; -// qDebug() << QString("layout: last line %1 - %2 @ (%3,%4) wd %5/%6").arg(current.line.firstItem).arg(current.line.lastItem) -// .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); - - if (current.itemsInLine > 0) { itemText.appendLine(current.line); + current.startOfCol = false; } } MaxChars = itemText.length(); @@ -3563,8 +3639,6 @@ } -#endif //NLS_PROTO - bool PageItem_TextFrame::createInfoGroup(QFrame *infoGroup, QGridLayout *infoGroupLayout) { int Parag = 0; |
|
ok, issue with empty lines fixed in formatting5.patch |
|
Arghh, found another regression : - create two text frames and link them - insert sample text so that text runs inside second frame - type 'Enter' in second frame in the middle of text - a red square will appear t the place "Enter" was typed |
|
Fixed that last issue by commenting out the corresponding lines and committed patch. Thanks again, cezaryece! Note : I created a clone of this issue for porting patch to 1.5.0svn |
|
0009902 you can also set as solved |
|
Just with the most recent version of 140svn I discovered following regression: Create Textframe, Insert some underscore followed by some text. First line offset set to "max. ascent". So far everything is fine. Then insert a tabulator (tab-key) between underscore and text. The underscores will move to right above the text. See uploaded snapshot. |
|
|
|
10251_c27028.patch (598 bytes)
Index: Version135/Scribus/scribus/pageitem_textframe.cpp =================================================================== --- Version135/Scribus/scribus/pageitem_textframe.cpp (wersja 16898) +++ Version135/Scribus/scribus/pageitem_textframe.cpp (kopia robocza) @@ -1399,6 +1399,8 @@ } else maxYAsc = static_cast<int>(floor(current.yPos - qMax(realAsce, asce))); + //fix for glyphs with negative realAsce value + maxYAsc = qMax(maxYAsc, 0); maxYDesc = static_cast<int>(ceil(current.yPos + qMax(realDesc, desc))); if (current.itemsInLine == 0 && !current.afterOverflow) |
|
fix in 10251_c27028.patch |
|
Final patch is in svn/rc6. Please raise any new issues in related bugs or open new bugs. |
Date Modified | Username | Field | Change |
---|---|---|---|
2011-09-08 10:20 | cezaryece | New Issue | |
2011-09-08 10:20 | cezaryece | File Added: formatting.patch | |
2011-09-08 10:20 | cezaryece | File Added: formatting patch.sla | |
2011-09-08 10:21 | cezaryece | File Added: formating_wrong.jpg | |
2011-09-08 10:21 | cezaryece | File Added: formating_good.jpg | |
2011-09-10 21:49 | jghali | Note Added: 0026848 | |
2011-09-11 15:18 | jghali | Note Added: 0026850 | |
2011-09-11 15:55 |
|
Note Added: 0026851 | |
2011-09-11 15:57 |
|
File Added: textwithpatch.png | |
2011-09-12 06:22 | cezaryece | Note Added: 0026854 | |
2011-09-13 13:37 | cezaryece | File Added: formatting2.patch | |
2011-09-13 13:39 | cezaryece | Note Added: 0026859 | |
2011-09-13 20:59 | jghali | Note Added: 0026862 | |
2011-09-19 11:14 | cezaryece | File Added: formatting3.patch | |
2011-09-19 11:15 | cezaryece | Note Added: 0026890 | |
2011-09-19 21:40 | jghali | Note Added: 0026892 | |
2011-09-26 12:45 | cezaryece | File Added: formatting4.patch | |
2011-09-26 12:49 | cezaryece | Note Added: 0026907 | |
2011-09-26 20:03 | jghali | Note Added: 0026909 | |
2011-09-27 12:21 | cezaryece | Note Added: 0026914 | |
2011-09-27 18:54 | cezaryece | File Added: formatting5.patch | |
2011-09-27 18:54 | cezaryece | Note Added: 0026916 | |
2011-09-28 20:35 | jghali | Note Added: 0026925 | |
2011-10-01 15:35 | jghali | Issue cloned: 0010294 | |
2011-10-01 15:37 | jghali | Note Added: 0026938 | |
2011-10-01 15:37 | jghali | Status | new => resolved |
2011-10-01 15:37 | jghali | Fixed in Version | => 1.4.0svn |
2011-10-01 15:37 | jghali | Resolution | open => fixed |
2011-10-01 15:37 | jghali | Assigned To | => jghali |
2011-10-02 06:59 | cezaryece | Note Added: 0026944 | |
2011-10-05 20:02 | cbradney | Relationship added | related to 0009932 |
2011-10-05 20:02 | cbradney | Relationship added | related to 0009436 |
2011-10-05 20:03 | cbradney | Relationship added | related to 0005891 |
2011-10-17 07:43 | rdebel | Note Added: 0027028 | |
2011-10-17 07:44 | rdebel | File Added: snapshot_error.png | |
2011-10-17 12:55 | cezaryece | File Added: 10251_c27028.patch | |
2011-10-17 12:56 | cezaryece | Note Added: 0027032 | |
2011-10-17 18:55 | cbradney | Status | resolved => closed |
2011-10-17 21:36 | cbradney | Note Added: 0027039 | |
2012-02-19 17:21 | jghali | Relationship added | related to 0008538 |
2015-09-17 20:08 | Kunda | Category | Story Editor / Text Frames => Story Ed/Txt Frames |
2015-09-17 20:12 | Kunda | Category | Story Ed/Txt Frames => Story Editor / Text Frames |