00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <QPolygon>
00025 #include <QList>
00026 #include <QMatrix>
00027 #include <QPoint>
00028 #include <QRegion>
00029 #include <QPalette>
00030 #include <cmath>
00031 #include <cassert>
00032
00033 #include "canvas.h"
00034 #include "commonstrings.h"
00035 #include "guidemanager.h"
00036 #include "hyphenator.h"
00037 #include "page.h"
00038 #include "pageitem.h"
00039 #include "pageitem_textframe.h"
00040 #include "prefsmanager.h"
00041 #include "scconfig.h"
00042 #include "scpainter.h"
00043 #include "scpaths.h"
00044 #include "scraction.h"
00045 #include "scribus.h"
00046 #include "scribusdoc.h"
00047 #include "scribusstructs.h"
00048 #include "selection.h"
00049 #include "text/nlsconfig.h"
00050 #include "undomanager.h"
00051 #include "undostate.h"
00052 #include "util.h"
00053 #include "util_math.h"
00054
00055
00056 using namespace std;
00057
00058 PageItem_TextFrame::PageItem_TextFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, QString fill, QString outline)
00059 : PageItem(pa, PageItem::TextFrame, x, y, w, h, w2, fill, outline)
00060 {
00061 invalid = true;
00062 firstChar = 0;
00063 cursorBiasBackward = false;
00064 unicodeTextEditMode = false;
00065 unicodeInputCount = 0;
00066 unicodeInputString = "";
00067 }
00068
00069
00070 static QRegion itemShape(PageItem* docItem, double xOffset, double yOffset)
00071 {
00072 QRegion res;
00073 QMatrix pp;
00074
00075 pp.translate(docItem->xPos() - xOffset, docItem->yPos() - yOffset);
00076 pp.rotate(docItem->rotation());
00077 if (docItem->textFlowUsesBoundingBox())
00078 {
00079 QPolygon tcli(4);
00080 tcli.setPoint(0, QPoint(0,0));
00081 tcli.setPoint(1, QPoint(qRound(docItem->width()), 0));
00082 tcli.setPoint(2, QPoint(qRound(docItem->width()), qRound(docItem->height())));
00083 tcli.setPoint(3, QPoint(0, qRound(docItem->height())));
00084
00085 res = QRegion(pp.map(tcli));
00086 }
00087 else if ((docItem->textFlowUsesImageClipping()) && (docItem->imageClip.size() != 0))
00088 {
00089 QList<uint> Segs;
00090 QPolygon Clip2 = FlattenPath(docItem->imageClip, Segs);
00091
00092 res = QRegion(pp.map(Clip2)).intersect(QRegion(pp.map(docItem->Clip)));
00093 }
00094 else if ((docItem->textFlowUsesContourLine()) && (docItem->ContourLine.size() != 0))
00095 {
00096 QList<uint> Segs;
00097 QPolygon Clip2 = FlattenPath(docItem->ContourLine, Segs);
00098
00099 res = QRegion(pp.map(Clip2));
00100 }
00101 else
00102
00103 res = QRegion(pp.map(docItem->Clip));
00104
00105 return res;
00106 }
00107
00108 QRegion PageItem_TextFrame::availableRegion(QRegion clip)
00109 {
00110 QRegion result(clip);
00111 if (!isEmbedded)
00112 {
00113 int LayerLev = m_Doc->layerLevelFromNumber(LayerNr);
00114 uint docItemsCount=m_Doc->Items->count();
00115 Page* Mp=0;
00116 Page* Dp=0;
00117 PageItem* docItem=0;
00118 int LayerLevItem;
00119 if (!OnMasterPage.isEmpty())
00120 {
00121 if ((savedOwnPage == -1) || (savedOwnPage >= signed(m_Doc->Pages->count())))
00122 return result;
00123 Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]);
00124 Dp = m_Doc->Pages->at(savedOwnPage);
00125 int currentGroup = -1;
00126 for (int a = 0; a < m_Doc->MasterItems.count(); ++a)
00127 {
00128 docItem = m_Doc->MasterItems.at(a);
00129 LayerLevItem = m_Doc->layerLevelFromNumber(docItem->LayerNr);
00130 if (((docItem->ItemNr > ItemNr) && (docItem->LayerNr == LayerNr)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerNr)))
00131 {
00132 if (docItem->Groups.count() == 0)
00133 currentGroup = -1;
00134 if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top()))
00135 continue;
00136 if (docItem->textFlowAroundObject())
00137 {
00138 result = result.subtract(itemShape(docItem, Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset()));
00139 }
00140 if (docItem->isGroupControl)
00141 currentGroup = docItem->Groups.top();
00142 }
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 }
00160 else
00161 {
00162 int currentGroup = -1;
00163 for (uint a = 0; a < docItemsCount; ++a)
00164 {
00165 docItem = m_Doc->Items->at(a);
00166 LayerLevItem = m_Doc->layerLevelFromNumber(docItem->LayerNr);
00167 if (((docItem->ItemNr > ItemNr) && (docItem->LayerNr == LayerNr)) || (LayerLevItem > LayerLev && m_Doc->layerFlow(docItem->LayerNr)))
00168 {
00169 if (docItem->Groups.count() == 0)
00170 currentGroup = -1;
00171 if ((currentGroup != -1) && (docItem->Groups.count() != 0) && (currentGroup == docItem->Groups.top()))
00172 continue;
00173 if (docItem->textFlowAroundObject())
00174 result = result.subtract(itemShape(docItem, 0, 0));
00175 if (docItem->isGroupControl)
00176 currentGroup = docItem->Groups.top();
00177 }
00178 }
00179 }
00180 }
00181 return result;
00182 }
00183
00184
00185 void PageItem_TextFrame::setShadow()
00186 {
00187 if (OnMasterPage.isEmpty())
00188 return;
00189
00190 QString newShadow = m_Doc->masterPageMode() ? OnMasterPage : QString::number(OwnPage);
00191 if (newShadow != currentShadow) {
00192 if (currentShadow == OnMasterPage) {
00193
00194 shadows.clear();
00195 }
00196 if (!shadows.contains(newShadow)) {
00197 if (!shadows.contains(OnMasterPage)) {
00198 shadows[OnMasterPage] = itemText;
00199
00200
00201
00202 }
00203 if (newShadow != OnMasterPage) {
00204 shadows[newShadow] = shadows[OnMasterPage].copy();
00205
00206
00207 }
00208
00209 }
00210 itemText = shadows[newShadow];
00211
00212
00213 invalid = true;
00214 currentShadow = newShadow;
00215 }
00216 }
00217
00218 #ifdef NLS_PROTO
00219 #include "text/pageitem_textframe.cpp"
00220 #else
00221
00222 static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->"))
00223 {
00224 QString db = QString("%6%1/%2 @ %3: %4--%5 linespa%6: %7 align%8")
00225 .arg(pstyle.name())
00226 .arg(pstyle.parent())
00227 .arg( (unsigned long int) &pstyle)
00228 .arg(pstyle.leftMargin())
00229 .arg(pstyle.rightMargin())
00230 .arg(indent)
00231 .arg(pstyle.lineSpacingMode())
00232 .arg(pstyle.lineSpacing())
00233 .arg(pstyle.alignment());
00234 qDebug(db.toLatin1().constData());
00235 static QString more(" ");
00236 if (pstyle.hasParent())
00237 dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent);
00238 }
00239
00240
00241 static const bool legacy = true;
00242
00243
00244
00245
00246
00247
00248
00252 static void fillInTabLeaders(StoryText & itemText, LineSpec & curLine)
00253 {
00254
00255 double xPos = curLine.x;
00256 for (int ti= curLine.firstItem; ti < curLine.lastItem; ++ti)
00257 {
00258 ScText * hl = itemText.item(ti);
00259 if (hl->ch == SpecialChars::TAB)
00260 {
00261 GlyphLayout * tglyph = hl->glyph.more;
00262
00263 if (!tglyph)
00264 continue;
00265
00266 const CharStyle & charStyle(itemText.charStyle(ti));
00267 double wt = charStyle.font().glyphWidth(tglyph->glyph, charStyle.fontSize() * tglyph->scaleV / 10.0);
00268 double len = hl->glyph.xadvance;
00269 int count = static_cast<int>(len / wt);
00270 double sPos = -len;
00271 tglyph->xoffset = sPos;
00272
00273 for (int cx = 1; cx < count; ++cx)
00274 {
00275
00276 tglyph->grow();
00277 *(tglyph->more) = *tglyph;
00278 tglyph->more->more = NULL;
00279 tglyph = tglyph->more;
00280 tglyph->xoffset = sPos + wt * cx;
00281 }
00282 }
00283 xPos += hl->glyph.wide();
00284 }
00285 }
00286
00287
00288
00289 enum TabStatus {
00290 TabNONE = 0,
00291 TabLEFT = TabNONE,
00292 TabRIGHT = 1,
00293 TabPOINT = 2,
00294 TabCOMMA = 3,
00295 TabCENTER = 4
00296 };
00297
00298
00302 struct TabControl {
00303 bool active;
00304 int status;
00305 int charIndex;
00306 double xPos;
00307 QChar fillChar;
00308 };
00309
00313 struct LineControl {
00314 LineSpec line;
00315 int itemsInLine;
00316 int hyphenCount;
00317 double colWidth;
00318 double colGap;
00319 double colLeft;
00320 double colRight;
00321 int column;
00322 bool startOfCol;
00323 double ascend;
00324 double descend;
00325 double width;
00326 double xPos;
00327 double yPos;
00328 int breakIndex;
00329 double breakXPos;
00330
00331 double maxShrink;
00332 double maxStretch;
00333
00334
00336 void init(double w, double h, const MarginStruct& extra, double lCorr)
00337 {
00338 insets = extra;
00339 lineCorr = lCorr;
00340 frameWidth = w;
00341 frameHeight = h;
00342 }
00343
00345 void initColumns(double width, double gap)
00346 {
00347 column = 0;
00348 colWidth = width;
00349 colGap = gap;
00350 }
00351
00353 void nextColumn(double asce)
00354 {
00355 startOfCol = true;
00356 colLeft = (colWidth + colGap) * column + insets.Left + lineCorr;
00357 colRight = colLeft + colWidth;
00358 if (legacy)
00359 colRight += insets.Right + lineCorr;
00360 xPos = colLeft;
00361 yPos = asce + insets.Top + lineCorr + 1;
00362 }
00363
00364 bool isEndOfCol(double morespace = 0)
00365 {
00366 return yPos + morespace + insets.Bottom + lineCorr > frameHeight;
00367 }
00368
00372 void startLine(int first)
00373 {
00374 itemsInLine = 0;
00375 line.x = xPos;
00376 line.y = yPos;
00377 line.firstItem = first;
00378 line.ascent = 10;
00379 line.descent = 0;
00380 line.width = 0;
00381 line.naturalWidth = 0;
00382 breakIndex = -1;
00383 breakXPos = 0;
00384 maxShrink = 0;
00385 maxStretch = 0;
00386 }
00387
00388
00390 void rememberShrinkStretch(QChar ch, double wide, const ParagraphStyle& style)
00391 {
00392 if (SpecialChars::isExpandingSpace(ch))
00393 maxShrink += (1 - style.minWordTracking()) * wide;
00394 else
00395 {
00396 maxShrink += (1 - style.minGlyphExtension()) * wide;
00397 }
00398 maxStretch += (style.maxGlyphExtension() - 1) * wide;
00399 }
00400
00402 void rememberBreak(int index, double pos)
00403 {
00404 if (pos > colRight)
00405 {
00406
00407 maxShrink = 0;
00408
00409
00410 if (breakIndex >= 0)
00411 {
00412 double oldLooseness = qAbs(colRight - breakXPos);
00413
00414 double newLooseness = pos - colRight;
00415 if (newLooseness >= oldLooseness)
00416 return;
00417 }
00418 breakXPos = colRight;
00419 }
00420 else
00421 {
00422 breakXPos = pos;
00423 }
00424 breakIndex = index;
00425 }
00426
00428 void breakLine(const StoryText& itemText, int last)
00429 {
00430 breakIndex = last;
00431 breakXPos = line.x;
00432 for (int j = line.firstItem; j <= last; ++j)
00433 if ( (itemText.item(j)->effects() & ScStyle_SuppressSpace) == 0)
00434 breakXPos += itemText.item(j)->glyph.wide();
00435 }
00436
00438 void finishLine(double endX)
00439 {
00440 line.lastItem = breakIndex;
00441 line.naturalWidth = breakXPos - line.x;
00442 line.width = endX - line.x;
00443 maxShrink = maxStretch = 0;
00444 }
00445
00446
00447 bool isEndOfLine(double moreSpace = 0)
00448 {
00449 if (legacy)
00450 return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight;
00451 else
00452 return xPos + moreSpace - maxShrink >= colRight;
00453 }
00454
00456 double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace)
00457 {
00458 QPoint pt1, pt2;
00459 double tmpX = xPos;
00460 pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent));
00461 pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent)));
00462
00463 while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2))))
00464 {
00465 tmpX++;
00466 if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight)
00467 {
00468 return tmpX;
00469 }
00470 pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent));
00471 pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent)));
00472 }
00473 return tmpX;
00474 }
00475
00477 double endOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace = 0)
00478 {
00479 double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1));
00480 QPoint pt1, pt2;
00481
00482 do {
00483 EndX += 0.125;
00484 pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent));
00485 pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent)));
00486 } while
00487 ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace)
00488 && shape.contains(pf2.map(pt1))
00489 && shape.contains(pf2.map(pt2))
00490 );
00491
00492 return EndX;
00493 }
00494
00495
00496 double getLineAscent(const StoryText& itemText)
00497 {
00498 double result = 0;
00499 if ((itemText.text(line.firstItem) == SpecialChars::PARSEP) || (itemText.text(line.firstItem) == SpecialChars::LINEBREAK))
00500 result = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0);
00501 else if (itemText.object(line.firstItem) != 0)
00502 result = qMax(result, (itemText.object(line.firstItem)->gHeight + itemText.object(line.firstItem)->lineWidth()) * (itemText.charStyle(line.firstItem).scaleV() / 1000.0));
00503 else
00504 result = itemText.charStyle(line.firstItem).font().realCharAscent(itemText.text(line.firstItem), itemText.charStyle(line.firstItem).fontSize() / 10.0);
00505 for (int zc = 0; zc < itemsInLine; ++zc)
00506 {
00507 QChar ch = itemText.text(line.firstItem + zc);
00508 if (ch == SpecialChars::PAGENUMBER)
00509 ch = '8';
00510 const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc));
00511 if ((ch == SpecialChars::TAB) || (ch == QChar(10))
00512 || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN)
00513 || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::LINEBREAK)
00514 || (ch == SpecialChars::FRAMEBREAK) || (ch.isSpace()))
00515 continue;
00516 double asce;
00517 if (itemText.object(line.firstItem + zc) != 0)
00518 asce = itemText.object(line.firstItem + zc)->gHeight + itemText.object(line.firstItem + zc)->lineWidth() * (cStyle.scaleV() / 1000.0);
00519 else
00520 asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0);
00521
00522 result = qMax(result, asce);
00523 }
00524 return result;
00525 }
00526
00527 double getLineHeight(const StoryText& itemText)
00528 {
00529 double result = 0;
00530 if (itemText.object(line.firstItem) != 0)
00531 result = qMax(result, (itemText.object(line.firstItem)->gHeight + itemText.object(line.firstItem)->lineWidth()) * (itemText.charStyle(line.firstItem).scaleV() / 1000.0));
00532 else
00533 result = itemText.charStyle(line.firstItem).font().height(itemText.charStyle(line.firstItem).fontSize() / 10.0);
00534 for (int zc = 0; zc < itemsInLine; ++zc)
00535 {
00536 QChar ch = itemText.text(line.firstItem+zc);
00537 if ((ch == SpecialChars::TAB) || (ch == QChar(10))
00538 || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN)
00539 || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::FRAMEBREAK)
00540 || (ch == SpecialChars::LINEBREAK) || (ch.isSpace()))
00541 continue;
00542 double asce;
00543 if (itemText.object(line.firstItem+zc) != 0)
00544 asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0);
00545 else
00546 asce = itemText.charStyle(line.firstItem+zc).font().height(itemText.charStyle(line.firstItem+zc).fontSize() / 10.0);
00547
00548 result = qMax(result, asce);
00549 }
00550 return result;
00551 }
00552
00553
00554 private:
00555 double frameWidth;
00556 double frameHeight;
00557 MarginStruct insets;
00558 double lineCorr;
00559 };
00560
00561
00562
00564 static void justifyLine(StoryText& itemText, LineSpec& line)
00565 {
00566
00567 double glyphNatural = 0;
00568 double spaceNatural = 0;
00569 double glyphExtension;
00570 double spaceExtension;
00571
00572 const ParagraphStyle& style(itemText.paragraphStyle(line.firstItem));
00573
00574
00575 for (int sof = line.firstItem; sof <= line.lastItem; ++sof)
00576 {
00577 if (!SpecialChars::isExpandingSpace(itemText.text(sof)))
00578 {
00579 glyphNatural += itemText.item(sof)->glyph.wide();
00580 }
00581 else if ( (itemText.item(sof)->effects() & ScStyle_SuppressSpace) == 0)
00582 {
00583 spaceNatural += itemText.item(sof)->glyph.wide();
00584 }
00585 }
00586
00587
00588
00589 if (line.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0)
00590 {
00591 glyphExtension = style.minGlyphExtension() - 1;
00592 spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1;
00593 }
00594 else if (line.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0)
00595 {
00596 spaceExtension = 0;
00597 glyphExtension = (line.width - spaceNatural) / glyphNatural - 1;
00598 }
00599 else
00600 {
00601 glyphExtension = style.maxGlyphExtension() - 1;
00602 if (spaceNatural > 0)
00603 spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1;
00604 else
00605 spaceExtension = 0;
00606 }
00607
00608 double glyphScale = 1 + glyphExtension;
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618 for (int yof = line.firstItem; yof <= line.lastItem; ++yof)
00619 {
00620 double wide = itemText.item(yof)->glyph.wide();
00621 if (!SpecialChars::isExpandingSpace(itemText.text(yof)))
00622 {
00623 itemText.item(yof)->glyph.last()->xadvance += wide * glyphExtension;
00624 GlyphLayout* glyph = &(itemText.item(yof)->glyph);
00625 while (glyph)
00626 {
00627 glyph->xoffset *= glyphScale;
00628 glyph->scaleH *= glyphScale;
00629 glyph = glyph->more;
00630 }
00631 }
00632 else if ((itemText.item(yof)->effects() & ScStyle_SuppressSpace) == 0)
00633 {
00634 itemText.item(yof)->glyph.last()->xadvance += wide * spaceExtension;
00635 }
00636 }
00637 }
00638
00639
00641 static void indentLine(StoryText& itemText, LineSpec& line, double leftIndent)
00642 {
00643 if (line.naturalWidth > line.width)
00644 {
00645 justifyLine(itemText, line);
00646 }
00647 if (leftIndent > 0)
00648 {
00649 line.x += leftIndent;
00650 line.width -= leftIndent;
00651 }
00652 }
00653
00655 static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line)
00656 {
00657 int b = line.firstItem;
00658 while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace))
00659 ++b;
00660
00661 double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
00662 QChar chr = itemText.text(b);
00663 double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
00664 if (QString("'´`").indexOf(chr) >= 0
00665 || chr == QChar(0x2018)
00666 || chr == QChar(0x2019)
00667 || chr == QChar(0x201a)
00668 || chr == QChar(0x201b)
00669 || chr == QChar(0x2039)
00670 || chr == QChar(0x203a)
00671 )
00672 leftCorr *= -0.7;
00673 else if (QString("\"").indexOf(chr) >= 0
00674 || chr == QChar(0x00ab)
00675 || chr == QChar(0x00bb)
00676 || chr == QChar(0x201c)
00677 || chr == QChar(0x201d)
00678 || chr == QChar(0x201e)
00679 || chr == QChar(0x201f)
00680 )
00681 leftCorr *= -0.5;
00682 else {
00683 leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
00684 leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
00685
00686
00687
00688 }
00689 return leftCorr;
00690 }
00691
00692
00693
00695 static double opticalRightMargin(const StoryText& itemText, const LineSpec& line)
00696 {
00697 int b = line.lastItem;
00698 while (b > line.firstItem &&
00699 (SpecialChars::isBreakingSpace(itemText.text(b)) || SpecialChars::isBreak(itemText.text(b)))
00700 )
00701 --b;
00702 if (b >= line.firstItem)
00703 {
00704 double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
00705 QChar chr = (itemText.item(b)->effects() & ScStyle_SmartHyphenVisible) ?
00706 QChar('-') : itemText.text(b);
00707 double rightCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
00708 if (QString("-,.`´'~").indexOf(chr) >= 0
00709 || chr == QChar(0x2018)
00710 || chr == QChar(0x2019)
00711 || chr == QChar(0x201a)
00712 || chr == QChar(0x201b)
00713 || chr == QChar(0x2039)
00714 || chr == QChar(0x203a)
00715 || chr == QChar(0x2032)
00716 )
00717 rightCorr *= 0.7;
00718 else if (QString(";:\"").indexOf(chr) >= 0
00719 || chr == QChar(0x00ab)
00720 || chr == QChar(0x00bb)
00721 || chr == QChar(0x201c)
00722 || chr == QChar(0x201d)
00723 || chr == QChar(0x201e)
00724 || chr == QChar(0x201f)
00725 || chr == QChar(0x2013)
00726 || chr == QChar(0x2033)
00727 )
00728 rightCorr *= 0.5;
00729 else {
00730 rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0);
00731 rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.'));
00732 }
00733 return rightCorr;
00734 }
00735 return 0.0;
00736 }
00737
00738
00739
00740
00741
00742 void PageItem_TextFrame::layout()
00743 {
00744
00745 if (BackBox != NULL && BackBox->invalid) {
00746
00747 invalid = false;
00748 PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox);
00749 if (!prevInChain)
00750 qDebug(QString("layout(): backBox=%1 is no textframe!!").arg((ulong)BackBox).toLatin1().constData());
00751 else
00752 BackBox->layout();
00753 return;
00754 }
00755 else if (!invalid && OnMasterPage.isEmpty()) {
00756
00757 return;
00758 }
00759 if (invalid && BackBox == NULL)
00760 firstChar = 0;
00761
00762
00763
00764 QMatrix pf2;
00765 QPoint pt1, pt2;
00766 QRegion cm;
00767 double chs, chsd = 0;
00768 double oldCurY, EndX, OFs, wide, kernVal;
00769 QString chstr;
00770 ScText *hl;
00771 ParagraphStyle style;
00772 int opticalMargins = ParagraphStyle::OM_None;
00773
00774 bool outs = false;
00775 bool fBorder = false;
00776 bool goNoRoom = false;
00777 bool goNextColumn = false;
00778
00779 TabControl tabs;
00780 tabs.active = false;
00781 tabs.status = TabNONE;
00782 tabs.charIndex = -1;
00783 tabs.xPos = 0;
00784
00785 QList<ParagraphStyle::TabRecord> tTabValues;
00786 tTabValues.clear();
00787
00788 bool DropCmode = false;
00789 bool AbsHasDrop = false;
00790 double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0;
00791 int DropLines = 0;
00792 double DropCapDrop = 0;
00793
00794 itemText.clearLines();
00795
00796 double lineCorr = 0;
00797 if (lineColor() != CommonStrings::None)
00798 lineCorr = m_lineWidth / 2.0;
00799
00800
00801 MarginStruct extra;
00802 extra.Top = TExtra;
00803 extra.Left = Extra;
00804 extra.Right = RExtra;
00805 extra.Bottom = BExtra;
00806
00807 LineControl current;
00808 current.init(Width, Height, extra, lineCorr);
00809 current.initColumns(columnWidth(), ColGap);
00810 current.hyphenCount = 0;
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 pf2.translate(Xpos, Ypos);
00825 pf2.rotate(Rot);
00826
00827 setShadow();
00828 if ((itemText.length() != 0))
00829 {
00830
00831 QRegion cl = availableRegion(QRegion(pf2.map(Clip)));
00832
00833 if (imageFlippedH())
00834 {
00835 pf2.translate(Width, 0);
00836 pf2.scale(-1, 1);
00837 }
00838 if (imageFlippedV())
00839 {
00840 pf2.translate(0, Height);
00841 pf2.scale(1, -1);
00842 }
00843
00844 current.nextColumn(0);
00845
00846
00847 if (firstInFrame() < itemText.length())
00848 {
00849 hl = itemText.item(firstInFrame());
00850 style = itemText.paragraphStyle(firstInFrame());
00851 if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
00852 {
00853 style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0));
00854
00855 }
00856
00857
00858
00859 if (style.hasDropCap())
00860 {
00861 if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
00862 chs = qRound(m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines() * 10);
00863 else
00864 chs = qRound(style.lineSpacing() * style.dropCapLines() * 10);
00865 }
00866 else
00867 chs = hl->fontSize();
00868 desc2 = -hl->font().descent(chs / 10.0);
00869 current.yPos = extra.Top + lineCorr;
00870
00871 }
00872 else
00873 {
00874 desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0);
00875 current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2;
00876 }
00877 current.startLine(firstInFrame());
00878 outs = false;
00879 OFs = 0;
00880 MaxChars = 0;
00881 for (int a = firstInFrame(); a < itemText.length(); ++a)
00882 {
00883 hl = itemText.item(a);
00884 if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP)
00885 style = itemText.paragraphStyle(a);
00886 if (current.itemsInLine == 0)
00887 opticalMargins = style.opticalMargins();
00888
00889
00890 const CharStyle& charStyle = (chstr[0] != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle());
00891 if (!charStyle.parent().isEmpty())
00892 {
00893
00894
00895
00896 }
00897
00898
00899
00900
00901
00902 chstr = ExpandToken(a);
00903
00904 if (chstr.isEmpty())
00905 chstr = SpecialChars::ZWNBSPACE;
00906 if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
00907 {
00908 style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0));
00909 }
00910
00911 if (a == firstInFrame())
00912 {
00913 if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP)
00914 {
00915 current.yPos += style.gapBefore();
00916 if (chstr[0] != SpecialChars::PARSEP)
00917 {
00918 DropCmode = style.hasDropCap();
00919 if (DropCmode)
00920 DropLines = style.dropCapLines();
00921 }
00922 else
00923 DropCmode = false;
00924 }
00925 }
00926
00927 {
00928 StyleFlag fl = hl->effects();
00929 fl &= ~ScStyle_DropCap;
00930 fl &= ~ScStyle_SmartHyphenVisible;
00931 hl->setEffects(fl);
00932 }
00933
00934
00935 if (legacy)
00936 {
00937
00938 if ( (current.itemsInLine == 0) && (SpecialChars::isBreakingSpace(hl->ch))
00939 && (a > 0 && ! SpecialChars::isBreak(itemText.text(a-1)))
00940 && ! (a > 0 && SpecialChars::isBreakingSpace(itemText.text(a-1))
00941 && (itemText.charStyle(a-1).effects() & ScStyle_SuppressSpace) != ScStyle_SuppressSpace))
00942 {
00943 hl->setEffects(hl->effects() | ScStyle_SuppressSpace);
00944 hl->glyph.xadvance = 0;
00945 continue;
00946 }
00947 else
00948 hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace);
00949 }
00950 else
00951 {
00952 if ( current.itemsInLine == 0 && SpecialChars::isBreakingSpace(hl->ch))
00953 {
00954 hl->setEffects(hl->effects() | ScStyle_SuppressSpace);
00955 hl->glyph.xadvance = 0;
00956 continue;
00957 }
00958 else
00959 hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace);
00960 }
00961
00962
00963 if (current.i