rendered paste bodyIndex: scribus/pageitem_textframe.h===================================================================--- scribus/pageitem_textframe.h (rvision 13613)+++ scribus/pageitem_textframe.h (copie de travail)@@ -103,6 +103,12 @@ void setShadow(); QString currentShadow; QMap<QString,StoryText> shadows;++ double lastLineHash;+ double scaleCacheControl;+ QList<double> selectCacheControl;+ QList<double> lineCacheControl;+ QMap<double, QImage*> lineCache; private slots: void slotInvalidateLayout();Index: scribus/pageitem_textframe.cpp===================================================================--- scribus/pageitem_textframe.cpp (rvision 13613)+++ scribus/pageitem_textframe.cpp (copie de travail)@@ -28,6 +28,7 @@ #include <QPoint> #include <QPolygon> #include <QRegion>+#include <QTime> #include <cassert> #include <cmath> @@ -253,9 +254,9 @@ dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } +// 2009.06.08 is great day - pm+static const bool legacy = false; -static const bool legacy = true;- /* static void layoutDropCap(GlyphLayout layout, double curX, double curY, double offsetX, double offsetY, double dropCapDrop) { @@ -618,8 +619,41 @@ } return result; }- - ++ void adjustLineHeight(const StoryText& itemText)+ {+ for(int idx(line.firstItem); idx <= line.lastItem; ++idx)+ {+ const ScText * c(itemText.item(idx));+ double rca(c->glyph.scaleV * itemText.charStyle(idx).+ font().+ realCharAscent(itemText.text(idx), itemText.charStyle(idx).fontSize() / 10.0));+ double rcd(c->glyph.scaleV * itemText.charStyle(idx).+ font().+ realCharDescent(itemText.text(idx), itemText.charStyle(idx).fontSize() / 10.0));+ line.ascent = qMax(line.ascent, c->glyph.yoffset + rca );+ line.descent = qMax(line.descent, rcd - c->glyph.yoffset );+ }+ }++ double getLineHash(const StoryText& itemText, const LineSpec * linespec = 0) const+ {+ const LineSpec * ls(linespec ? linespec : &line);+ double controlValue(ls->x);+ double cc(1.0);+ for(int cidx(ls->firstItem); cidx <= ls->lastItem; ++cidx)+ {+ const GlyphLayout glyt(itemText.item(cidx)->glyph);+ controlValue += ((glyt.glyph != 0.0) ? glyt.glyph : 1.0) * cc * 2.0;+ controlValue += ((glyt.scaleH != 0.0) ? glyt.scaleH : 1.0) * cc * 3.0;+ controlValue += ((glyt.scaleV != 0.0) ? glyt.scaleV : 1.0) * cc * 4.0;+ controlValue += ((glyt.xadvance != 0.0) ? glyt.xadvance : 1.0) * cc * 5.0;+ controlValue += ((glyt.xoffset != 0.0) ? glyt.xoffset : 1.0) * cc * 6.0;+ controlValue += ((glyt.yoffset != 0.0) ? glyt.yoffset : 1.0) * cc * 7.0;+ cc *= 1.1;+ }+ return controlValue * ((ls->y != 0.0)? ls->y :1.0);+ } private: double frameWidth; double frameHeight;@@ -829,6 +863,8 @@ if (invalid && BackBox == NULL) firstChar = 0; +// lineCacheControlOld = lineCacheControl;+ lineCacheControl.clear(); // 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;@@ -952,6 +988,8 @@ outs = false; OFs = 0; MaxChars = 0;+// qDebug()<<"Layout"<<itemName()<<firstInFrame()<<itemText.length()+// <<"\n\tClip"<< (&itemText) << itemText.invalidIntervalStart()<<itemText.invalidIntervalEnd(); for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a);@@ -1125,8 +1163,13 @@ kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); }- hl->glyph.yadvance = 0;- oldCurY = layoutGlyphs(*hl, chstr, hl->glyph);+ // I dont know exactly why but it does not respect the layout in all occasions+// if(((a >= itemText.invalidIntervalStart()) && (a < itemText.invalidIntervalEnd()))+// || (SpecialChars::isBreakingSpace(hl->ch) || hl->ch.isSpace()) )+ {+ hl->glyph.yadvance = 0;+ oldCurY = layoutGlyphs(*hl, chstr, hl->glyph);+ } // find out width of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth();@@ -2075,7 +2118,18 @@ 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)+ {+ current.adjustLineHeight(itemText); itemText.appendLine(current.line);+ double hLine(current.getLineHash(itemText));+ if(!lineCacheControl.contains(hLine))+ {+ lineCacheControl << hLine;+ }+ else+ qDebug()<<"Ooops 2 lines with same hash!"<< hLine;+ }+ current.startLine(a+1); outs = false; if (goNoRoom)@@ -2248,7 +2302,15 @@ // .arg(current.line.x).arg(current.line.y).arg(current.line.naturalWidth).arg(current.line.width); if (current.itemsInLine > 0) {+ current.adjustLineHeight(itemText); itemText.appendLine(current.line);+ double hLine(current.getLineHash(itemText));+ if(!lineCacheControl.contains(hLine))+ {+ lineCacheControl << hLine;+ }+ else+ qDebug()<<"Ooops 2 lines with same hash!"<< hLine; } } MaxChars = itemText.length();@@ -2257,21 +2319,35 @@ if (NextBox != NULL) { PageItem_TextFrame* nextFrame = dynamic_cast<PageItem_TextFrame*>(NextBox);- if (nextFrame != NULL)+ double currentLastLineHash(0);+ if(itemText.length() > 0)+ currentLastLineHash = current.getLineHash(itemText);+ if ((nextFrame != NULL)+ && (currentLastLineHash != lastLineHash)) {+ lastLineHash = currentLastLineHash; nextFrame->invalid = true; nextFrame->firstChar = MaxChars; } } // qDebug("textframe: len=%d, done relayout", itemText.length());+ if(itemText.length() > 0)+ lastLineHash = current.getLineHash(itemText);+ else+ lastLineHash = 0; return; NoRoom: // pf2.end(); invalid = false; PageItem_TextFrame * next = dynamic_cast<PageItem_TextFrame*>(NextBox);- if (next != NULL)+ double currentLastLineHash(0);+ if(itemText.length() > 0)+ currentLastLineHash = current.getLineHash(itemText);+ if ((next != NULL)+ && (currentLastLineHash != lastLineHash)) {+ lastLineHash = currentLastLineHash; next->invalid = true; next->firstChar = MaxChars; if (CPos > signed(MaxChars))@@ -2301,12 +2377,10 @@ this->invalid = true; if (wholeChain) {- PageItem *prevFrame = this->prevInChain();- while (prevFrame != 0)- {- prevFrame->invalid = true;- prevFrame = prevFrame->prevInChain();- }+ // lets see if it could work. I can be wrong, but I have the idea that something changed in a frame _cannot_ alters the previous frame in the string. So its not the place to invalidate it.+// PageItem *prevFrame = this->prevInChain();+// if (prevFrame != 0)+// prevFrame->invalid = true; PageItem *nextFrame = this->nextInChain(); while (nextFrame != 0) {@@ -2318,10 +2392,40 @@ void PageItem_TextFrame::DrawObj_Item(ScPainter *p, QRectF cullingArea, double sc) {+ QTime t,tt;+ t.start();+ int dl(0);+ int dg(0);+ int dgdg(0);++ QList<double> usedCached;+ QList<double> selectLines;+ QMap<double, double> coorX;+ QMap<double, double> coorY;+ QMap<double, double> lHeight;++ if(sc != scaleCacheControl)+ {+ scaleCacheControl = sc;+ foreach(const double& ik, lineCache.keys())+ {+ delete lineCache[ik];+ }+ lineCache.clear();+ }+ if(invalid)+ { layout();+ itemText.resetInvalidInterval();+ dl = t.elapsed();+ } if (invalid)+ {+ qDebug()<<"Layout of"<<itemName()<<"did not fix invalidity"; return;+ }+ QMatrix pf2; QPoint pt1, pt2; double wide, lineCorr;@@ -2431,8 +2535,10 @@ for (uint ll=0; ll < itemText.lines(); ++ll) { ls = itemText.line(ll);+ double hLine(LineControl().getLineHash(itemText, &ls)); tabDist = ls.x;- double CurX = ls.x;+// double CurX = ls.x;+ double CurX(0.0); // Draw text selection rectangles QRectF selectedFrame;@@ -2484,7 +2590,23 @@ selX += hls->glyph.wide(); } if(!selectedFrame.isNull())+ { sFList << selectedFrame;+ lineCacheControl.removeAll(hLine);+ selectLines << hLine;+ }+ // We need to invalidate lines which were just deselected+ foreach(const double& ik, selectCacheControl)+ {+ if(!selectLines.contains(ik)+ && lineCache.contains(ik))+ {+ delete lineCache[ik];+ lineCache.remove(ik);+ }+ }+ selectCacheControl = selectLines;+ p->save();//SA3 p->setFillMode(1); p->setBrush(qApp->palette().color(QPalette::Active, QPalette::Highlight));@@ -2498,6 +2620,39 @@ p->restore();//RE3 // End of selection + // cached++// qDebug()<<"HLine"<<ls.y<<hLine;+ if(lineCacheControl.contains(hLine) && lineCache.contains(hLine))+ {+// qDebug()<<"Skip painting of"<<ls.y<<hLine;+ coorX[hLine] = ls.x;+ coorY[hLine] = ls.y;+ lHeight[hLine] = ceil(ls.ascent);+ usedCached << hLine;+ continue;+ }+ else if(lineCache.contains(hLine))+ {+ delete lineCache[hLine];+// qDebug()<<"Deleted line cache image"<<hLine;+ }+ int intLineAscent(ceil(ls.ascent));+ int intScaledLineAscent(ceil(ls.ascent * sc ));+ int intScaledLineHeight(ceil(ls.descent * sc ) + intScaledLineAscent );+ lineCache[hLine] = new QImage(ceil( ls.width * sc ), intScaledLineHeight , QImage::Format_ARGB32);+ lineCache[hLine]->fill(Qt::transparent);+ ScPainter cachepainter(lineCache[hLine], lineCache[hLine]->width() , lineCache[hLine]->height());+ ScPainter *sp(&cachepainter);+ sp->scale(sc,sc);+ coorX[hLine] = ls.x;+ coorY[hLine] = ls.y;+ lHeight[hLine] = intLineAscent;+// qDebug()<<"\tLine"<<"\tsc:"<<sc<<"\ty:"<<ls.y<<"\tasc:"<<ls.ascent<<"\tdesc:"<<ls.descent+// <<"\n\t\tISAsc:"<<intScaledLineAscent<<"\tISDesc:"<< ceil(ls.descent * sc ) << "\tSH:"<<intScaledLineHeight ;++ // end of cached+ QColor tmp; ScText *hl = 0; for (int a = ls.firstItem; a <= qMin(ls.lastItem, itemText.length()); ++a)@@ -2513,20 +2668,20 @@ actFillShade = charStyle.fillShade(); if (actFill != CommonStrings::None) {- p->setFillMode(ScPainter::Solid);+ sp->setFillMode(ScPainter::Solid); if ((cachedFillShade != actFillShade) || (cachedFill != actFill)) { SetQColor(&tmp, actFill, actFillShade);- p->setBrush(tmp);+ sp->setBrush(tmp); cachedFillQ = tmp; cachedFill = actFill; cachedFillShade = actFillShade; } else- p->setBrush(cachedFillQ);+ sp->setBrush(cachedFillQ); } else- p->setFillMode(ScPainter::None);+ sp->setFillMode(ScPainter::None); if (charStyle.effects() & ScStyle_DropCap) { const ParagraphStyle& style(itemText.paragraphStyle(a));@@ -2553,7 +2708,7 @@ if (((selected && Select) || ((NextBox != 0 || BackBox != 0) && selected)) && (m_Doc->appMode == modeEdit)) { // set text color to highlight if its selected- p->setBrush(qApp->palette().color(QPalette::Active, QPalette::HighlightedText));+ sp->setBrush(qApp->palette().color(QPalette::Active, QPalette::HighlightedText)); } actStroke = charStyle.strokeColor();@@ -2563,24 +2718,29 @@ if ((cachedStrokeShade != actStrokeShade) || (cachedStroke != actStroke)) { SetQColor(&tmp, actStroke, actStrokeShade);- p->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);+ sp->setPen(tmp, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); cachedStrokeQ = tmp; cachedStroke = actStroke; cachedStrokeShade = actStrokeShade; } else- p->setPen(cachedStrokeQ, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);+ sp->setPen(cachedStrokeQ, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); } // paint glyphs if (cullingArea.intersects(pf2.mapRect(QRect(qRound(CurX + hl->glyph.xoffset),qRound(ls.y + hl->glyph.yoffset-asce), qRound(hl->glyph.xadvance+1), qRound(asce+desc))))) {- p->save();//SA4- p->translate(CurX, ls.y);+ usedCached << hLine;+ tt.restart();+ sp->save();//SA4+// sp->translate(CurX, ls.y);+ sp->translate(CurX, intLineAscent); if (hl->ch == SpecialChars::OBJECT)- DrawObj_Embedded(p, cullingArea, charStyle, hl->embedded.getItem());+ DrawObj_Embedded(sp, cullingArea, charStyle, hl->embedded.getItem()); else- drawGlyphs(p, charStyle, hl->glyph);- p->restore();//RE4+ drawGlyphs(sp, charStyle, hl->glyph);+ sp->restore();//RE4+ dg += tt.elapsed();+ ++dgdg; } if (hl->ch == SpecialChars::OBJECT) CurX += (hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth()) * hl->glyph.scaleH;@@ -2595,7 +2755,33 @@ // } // pf2.end(); }++// Commit lines images to argued device+ if(itemText.lines() > 0)+ {+ p->save();+ p->scale(1.0/sc,1.0/sc);+ foreach(const double& ik, lineCache.keys())+ {+ if(usedCached.contains(ik))+ {+ double stripYPos((coorY[ik]*sc) - (lHeight[ik]*sc));+ double stripXPos(coorX[ik] * sc);++ p->translate(stripXPos, stripYPos);+ p->drawImage(lineCache[ik]);+ p->translate(-stripXPos, -stripYPos);+ }+ else+ {+ delete lineCache[ik];+ lineCache.remove(ik);+ }+ }+ p->restore();+ } p->restore();//RE1+ qDebug()<<"Text Drawing"<<t.elapsed()<<"ms; layout"<<dl<<"ms;"<< dg <<"ms actually drawing"<<dgdg<<"items, thus"<< (double(dg) / double(dgdg)) <<"ms/item"; } void PageItem_TextFrame::DrawObj_Post(ScPainter *p)