Rev 9646 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4430 | cbradney | 1 | /* |
2 | For general Scribus (>=1.3.2) copyright and licensing information please refer |
||
3 | to the COPYING file provided with the program. Following this notice may exist |
||
4 | a copyright and/or license notice that predates the release of Scribus 1.3.2 |
||
5 | for which a new license (GPL+exception) is in place. |
||
6 | */ |
||
3614 | cbradney | 7 | /*************************************************************************** |
8 | pageitem.cpp - description |
||
9 | ------------------- |
||
10 | begin : Sat Apr 7 2001 |
||
11 | copyright : (C) 2001 by Franz Schmid |
||
12 | email : Franz.Schmid@altmuehlnet.de |
||
13 | ***************************************************************************/ |
||
14 | |||
15 | /*************************************************************************** |
||
16 | * * |
||
17 | * This program is free software; you can redistribute it and/or modify * |
||
18 | * it under the terms of the GNU General Public License as published by * |
||
19 | * the Free Software Foundation; either version 2 of the License, or * |
||
20 | * (at your option) any later version. * |
||
21 | * * |
||
22 | ***************************************************************************/ |
||
23 | |||
24 | #include "pageitem_textframe.h" |
||
8521 | cbradney | 25 | //#include "pageitem_textframe.moc" |
3614 | cbradney | 26 | #include <qpainter.h> |
27 | #include <qpen.h> |
||
28 | #include <qfont.h> |
||
29 | #include <qregion.h> |
||
30 | #include <qpoint.h> |
||
31 | #include <qfileinfo.h> |
||
32 | #include <qdrawutil.h> |
||
33 | #include <qbitmap.h> |
||
34 | #include <qregexp.h> |
||
35 | #include <qmessagebox.h> |
||
8501 | cbradney | 36 | //Added by qt3to4: |
37 | #include <Q3ValueList> |
||
38 | #include <QKeyEvent> |
||
39 | #include <Q3PointArray> |
||
3614 | cbradney | 40 | #include <cmath> |
41 | #include <cassert> |
||
42 | |||
3829 | cbradney | 43 | #include "hyphenator.h" |
3614 | cbradney | 44 | #include "mpalette.h" |
45 | #include "page.h" |
||
46 | #include "pageitem.h" |
||
47 | #include "prefsmanager.h" |
||
48 | #include "scpaths.h" |
||
49 | #include "scribus.h" |
||
50 | #include "scribusstructs.h" |
||
51 | #include "scribusdoc.h" |
||
4145 | cbradney | 52 | #include "selection.h" |
3614 | cbradney | 53 | #include "undomanager.h" |
54 | #include "undostate.h" |
||
55 | #include "scconfig.h" |
||
4546 | subik | 56 | #include "commonstrings.h" |
5087 | subik | 57 | #include "guidemanager.h" |
3614 | cbradney | 58 | |
59 | #include "util.h" |
||
5291 | avox | 60 | #include "text/nlsconfig.h" |
3614 | cbradney | 61 | |
62 | using namespace std; |
||
63 | |||
64 | PageItem_TextFrame::PageItem_TextFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, QString fill, QString outline) |
||
65 | : PageItem(pa, PageItem::TextFrame, x, y, w, h, w2, fill, outline) |
||
66 | { |
||
8931 | cbradney | 67 | cursorBiasBackward = false; |
3829 | cbradney | 68 | unicodeTextEditMode = false; |
69 | unicodeInputCount = 0; |
||
70 | unicodeInputString = ""; |
||
3614 | cbradney | 71 | } |
72 | |||
5184 | avox | 73 | |
74 | static QRegion itemShape(PageItem* docItem, ScribusView* view, double xOffset, double yOffset) |
||
75 | { |
||
76 | QRegion res; |
||
9372 | fschmid | 77 | QMatrix pp; |
78 | // pp.begin(view->viewport()); |
||
5184 | avox | 79 | pp.translate(docItem->xPos() - xOffset, docItem->yPos() - yOffset); |
80 | pp.rotate(docItem->rotation()); |
||
81 | if (docItem->textFlowUsesBoundingBox()) |
||
82 | { |
||
8501 | cbradney | 83 | Q3PointArray tcli(4); |
5184 | avox | 84 | tcli.setPoint(0, QPoint(0,0)); |
85 | tcli.setPoint(1, QPoint(qRound(docItem->width()), 0)); |
||
86 | tcli.setPoint(2, QPoint(qRound(docItem->width()), qRound(docItem->height()))); |
||
87 | tcli.setPoint(3, QPoint(0, qRound(docItem->height()))); |
||
9372 | fschmid | 88 | // res = QRegion(pp.xForm(tcli)); |
89 | res = QRegion(pp.map(tcli)); |
||
5184 | avox | 90 | } |
8445 | fschmid | 91 | else if ((docItem->textFlowUsesImageClipping()) && (docItem->imageClip.size() != 0)) |
5184 | avox | 92 | { |
8501 | cbradney | 93 | Q3ValueList<uint> Segs; |
94 | Q3PointArray Clip2 = FlattenPath(docItem->imageClip, Segs); |
||
9372 | fschmid | 95 | // res = QRegion(pp.xForm(Clip2)); |
9668 | fschmid | 96 | res = QRegion(pp.map(Clip2)).intersect(QRegion(pp.map(docItem->Clip))); |
5184 | avox | 97 | } |
8445 | fschmid | 98 | else if ((docItem->textFlowUsesContourLine()) && (docItem->ContourLine.size() != 0)) |
99 | { |
||
8501 | cbradney | 100 | Q3ValueList<uint> Segs; |
101 | Q3PointArray Clip2 = FlattenPath(docItem->ContourLine, Segs); |
||
9372 | fschmid | 102 | // res = QRegion(pp.xForm(Clip2)); |
103 | res = QRegion(pp.map(Clip2)); |
||
8445 | fschmid | 104 | } |
105 | else |
||
9372 | fschmid | 106 | // res = QRegion(pp.xForm(docItem->Clip)); |
107 | res = QRegion(pp.map(docItem->Clip)); |
||
108 | // pp.end(); |
||
5184 | avox | 109 | return res; |
110 | } |
||
111 | |||
112 | QRegion PageItem_TextFrame::availableRegion(QRegion clip) |
||
113 | { |
||
7181 | cbradney | 114 | QRegion result(clip); |
5184 | avox | 115 | if (!isEmbedded) |
116 | { |
||
7181 | cbradney | 117 | int LayerLev = m_Doc->layerLevelFromNumber(LayerNr); |
118 | uint docItemsCount=m_Doc->Items->count(); |
||
119 | Page* Mp=0; |
||
120 | Page* Dp=0; |
||
121 | PageItem* docItem=0; |
||
122 | int LayerLevItem; |
||
5184 | avox | 123 | if (!OnMasterPage.isEmpty()) |
124 | { |
||
5559 | avox | 125 | if ((savedOwnPage == -1) || (savedOwnPage >= signed(m_Doc->Pages->count()))) |
5375 | fschmid | 126 | return result; |
7175 | fschmid | 127 | Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]); |
128 | Dp = m_Doc->Pages->at(savedOwnPage); |
||
5184 | avox | 129 | for (uint a = 0; a < m_Doc->MasterItems.count(); ++a) |
130 | { |
||
7175 | fschmid | 131 | docItem = m_Doc->MasterItems.at(a); |
132 | LayerLevItem = m_Doc->layerLevelFromNumber(docItem->LayerNr); |
||
5359 | fschmid | 133 | if (((docItem->ItemNr > ItemNr) && (docItem->LayerNr == LayerNr)) || (LayerLevItem > LayerLev) && (m_Doc->layerFlow(docItem->LayerNr))) |
5184 | avox | 134 | { |
5620 | jghali | 135 | if (docItem->textFlowAroundObject()) |
5184 | avox | 136 | { |
137 | result = result.subtract(itemShape(docItem, m_Doc->view(), Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); |
||
138 | } |
||
5387 | avox | 139 | } |
140 | } // for all masterItems |
||
5184 | avox | 141 | if (!m_Doc->masterPageMode()) |
142 | { |
||
143 | for (uint a = 0; a < docItemsCount; ++a) |
||
144 | { |
||
7175 | fschmid | 145 | docItem = m_Doc->Items->at(a); |
146 | Mp = m_Doc->MasterPages.at(m_Doc->MasterNames[OnMasterPage]); |
||
147 | Dp = m_Doc->Pages->at(OwnPage); |
||
5620 | jghali | 148 | if ((docItem->textFlowAroundObject()) && (docItem->OwnPage == OwnPage)) |
5184 | avox | 149 | { |
150 | result = result.subtract(itemShape(docItem, m_Doc->view(), Mp->xOffset() - Dp->xOffset(), Mp->yOffset() - Dp->yOffset())); |
||
151 | } |
||
152 | } // for all docItems |
||
153 | } // if (! masterPageMode) |
||
5387 | avox | 154 | } // if (!OnMasterPage.isEmpty()) |
5184 | avox | 155 | else |
156 | { |
||
157 | for (uint a = 0; a < docItemsCount; ++a) |
||
158 | { |
||
7175 | fschmid | 159 | docItem = m_Doc->Items->at(a); |
160 | LayerLevItem = m_Doc->layerLevelFromNumber(docItem->LayerNr); |
||
5359 | fschmid | 161 | if (((docItem->ItemNr > ItemNr) && (docItem->LayerNr == LayerNr)) || (LayerLevItem > LayerLev) && (m_Doc->layerFlow(docItem->LayerNr))) |
5184 | avox | 162 | { |
5620 | jghali | 163 | if (docItem->textFlowAroundObject()) |
5229 | fschmid | 164 | result = result.subtract(itemShape(docItem, m_Doc->view(), 0, 0)); |
5387 | avox | 165 | } |
166 | } // for all docItems |
||
5184 | avox | 167 | } // if(OnMasterPage.isEmpty() |
168 | } // if(!Embedded) |
||
169 | return result; |
||
170 | } |
||
171 | |||
6144 | avox | 172 | |
173 | void PageItem_TextFrame::setShadow() |
||
174 | { |
||
175 | if (OnMasterPage.isEmpty()) |
||
176 | return; |
||
6366 | avox | 177 | |
6144 | avox | 178 | QString newShadow = m_Doc->masterPageMode() ? OnMasterPage : QString::number(OwnPage); |
179 | if (newShadow != currentShadow) { |
||
6366 | avox | 180 | if (currentShadow == OnMasterPage) { |
181 | // masterpage was edited, clear all shadows |
||
182 | shadows.clear(); |
||
183 | } |
||
6144 | avox | 184 | if (!shadows.contains(newShadow)) { |
185 | if (!shadows.contains(OnMasterPage)) { |
||
186 | shadows[OnMasterPage] = itemText; |
||
7905 | avox | 187 | // const ParagraphStyle& pstyle(shadows[OnMasterPage].paragraphStyle(0)); |
7887 | avox | 188 | // qDebug(QString("Pageitem_Textframe: style of master: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment())); |
6375 | avox | 189 | // qDebug(QString("Pageitem_Textframe: shadow itemText->%1").arg(OnMasterPage)); |
6144 | avox | 190 | } |
7887 | avox | 191 | if (newShadow != OnMasterPage) { |
192 | shadows[newShadow] = shadows[OnMasterPage].copy(); |
||
193 | // const ParagraphStyle& pstyle(shadows[newShadow].paragraphStyle(0)); |
||
194 | // qDebug(QString("Pageitem_Textframe: style of shadow copy: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment())); |
||
195 | } |
||
6375 | avox | 196 | // qDebug(QString("Pageitem_Textframe: shadow %1<-%2").arg(newShadow).arg(OnMasterPage)); |
6144 | avox | 197 | } |
198 | itemText = shadows[newShadow]; |
||
7887 | avox | 199 | // const ParagraphStyle& pstyle(itemText.paragraphStyle(0)); |
200 | // qDebug(QString("Pageitem_Textframe: style of shadow: %1 align=%2").arg(pstyle.parent()).arg(pstyle.alignment())); |
||
6144 | avox | 201 | invalid = true; |
202 | currentShadow = newShadow; |
||
203 | } |
||
204 | } |
||
205 | |||
5291 | avox | 206 | #ifdef NLS_PROTO |
207 | #include "text/pageitem_textframe.cpp" |
||
208 | #else |
||
209 | |||
5778 | avox | 210 | static void dumpIt(const ParagraphStyle& pstyle, QString indent = QString("->")) |
211 | { |
||
6805 | avox | 212 | qDebug(QString("%6%1/%2 @ %3: %4--%5 linespa%6: %7 align%8") |
5778 | avox | 213 | .arg(pstyle.name()) |
6733 | avox | 214 | .arg(pstyle.parent()) |
5850 | tsoots | 215 | .arg( (unsigned long int) &pstyle) |
5778 | avox | 216 | .arg(pstyle.leftMargin()) |
217 | .arg(pstyle.rightMargin()) |
||
6805 | avox | 218 | .arg(indent) |
219 | .arg(pstyle.lineSpacingMode()) |
||
220 | .arg(pstyle.lineSpacing()) |
||
221 | .arg(pstyle.alignment())); |
||
5778 | avox | 222 | static QString more(" "); |
6733 | avox | 223 | if (pstyle.hasParent()) |
224 | dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); |
||
5778 | avox | 225 | } |
226 | |||
5390 | avox | 227 | |
8103 | avox | 228 | static const bool legacy = true; |
229 | |||
230 | |||
7313 | avox | 231 | static void layoutDropCap(GlyphLayout layout, double curX, double curY, double offsetX, double offsetY, double dropCapDrop) |
232 | { |
||
6370 | avox | 233 | } |
234 | |||
7905 | avox | 235 | |
8761 | avox | 236 | /** |
237 | Clones the tab fill char as often as necssary after all distances are known |
||
238 | */ |
||
7905 | avox | 239 | static void fillInTabLeaders(StoryText & itemText, LineSpec & curLine) |
240 | { |
||
241 | // fill in tab leaders |
||
242 | double xPos = curLine.x; |
||
243 | for (int ti= curLine.firstItem; ti < curLine.lastItem; ++ti) |
||
244 | { |
||
245 | ScText * hl = itemText.item(ti); |
||
246 | if (hl->ch[0] == SpecialChars::TAB) |
||
247 | { |
||
248 | GlyphLayout * tglyph = hl->glyph.more; |
||
249 | |||
250 | if (!tglyph) |
||
251 | continue; |
||
252 | |||
253 | const CharStyle & charStyle(itemText.charStyle(ti)); |
||
254 | double wt = charStyle.font().glyphWidth(tglyph->glyph, charStyle.fontSize() * tglyph->scaleV / 10.0); |
||
255 | double len = hl->glyph.xadvance; |
||
256 | int count = static_cast<int>(len / wt); |
||
257 | double sPos = -len; |
||
258 | tglyph->xoffset = sPos; |
||
259 | // qDebug(QString("tab leaders: %1 %2 width=%3 count=%4").arg(sPos).arg(curLine.y).arg(wt).arg(count)); |
||
260 | for (int cx = 1; cx < count; ++cx) |
||
261 | { |
||
262 | // clone fillchar |
||
263 | tglyph->grow(); |
||
264 | *(tglyph->more) = *tglyph; |
||
265 | tglyph->more->more = NULL; |
||
266 | tglyph = tglyph->more; |
||
267 | tglyph->xoffset = sPos + wt * cx; |
||
268 | } |
||
269 | } |
||
270 | xPos += hl->glyph.wide(); |
||
271 | } |
||
272 | } |
||
273 | |||
274 | |||
7887 | avox | 275 | |
7905 | avox | 276 | enum TabStatus { |
277 | TabNONE = 0, |
||
278 | TabLEFT = TabNONE, |
||
279 | TabRIGHT = 1, |
||
280 | TabPOINT = 2, |
||
281 | TabCOMMA = 3, |
||
282 | TabCENTER = 4 |
||
7313 | avox | 283 | }; |
6370 | avox | 284 | |
8761 | avox | 285 | |
286 | /** |
||
287 | fields which describe what type of tab is currently active |
||
288 | */ |
||
7313 | avox | 289 | struct TabControl { |
290 | bool active; |
||
7905 | avox | 291 | int status; |
7313 | avox | 292 | int charIndex; |
293 | double xPos; |
||
7905 | avox | 294 | QChar fillChar; |
7313 | avox | 295 | }; |
296 | |||
8761 | avox | 297 | /** |
298 | fields which describe how the current line is placed into the frame |
||
299 | */ |
||
7313 | avox | 300 | struct LineControl { |
301 | LineSpec line; |
||
302 | int itemsInLine; |
||
303 | int hyphenCount; |
||
304 | double colWidth; |
||
8095 | avox | 305 | double colGap; |
7313 | avox | 306 | double colLeft; |
307 | double colRight; |
||
308 | int column; |
||
309 | bool startOfCol; |
||
310 | double ascend; |
||
311 | double descend; |
||
312 | double width; |
||
313 | double xPos; |
||
314 | double yPos; |
||
315 | int breakIndex; |
||
316 | double breakXPos; |
||
9047 | avox | 317 | |
318 | double maxShrink; |
||
319 | double maxStretch; |
||
8095 | avox | 320 | |
321 | |||
8761 | avox | 322 | /// remember frame dimensions and offsets |
8095 | avox | 323 | void init(double w, double h, const MarginStruct& extra, double lCorr) |
324 | { |
||
325 | insets = extra; |
||
326 | lineCorr = lCorr; |
||
327 | frameWidth = w; |
||
328 | frameHeight = h; |
||
329 | } |
||
330 | |||
8761 | avox | 331 | /// start at column 0 |
8095 | avox | 332 | void initColumns(double width, double gap) |
333 | { |
||
334 | column = 0; |
||
335 | colWidth = width; |
||
336 | colGap = gap; |
||
337 | } |
||
338 | |||
8761 | avox | 339 | /// move position to next column |
8095 | avox | 340 | void nextColumn(double asce) |
341 | { |
||
342 | startOfCol = true; |
||
343 | colLeft = (colWidth + colGap) * column + insets.Left + lineCorr; |
||
344 | colRight = colLeft + colWidth; |
||
8103 | avox | 345 | if (legacy) |
346 | colRight += insets.Right + lineCorr; //??? |
||
8095 | avox | 347 | xPos = colLeft; |
348 | yPos = asce + insets.Top + lineCorr + 1; |
||
349 | } |
||
350 | |||
351 | bool isEndOfCol(double morespace = 0) |
||
352 | { |
||
353 | return yPos + morespace + insets.Bottom + lineCorr > frameHeight; |
||
354 | } |
||
355 | |||
8761 | avox | 356 | /** |
357 | init fields for a new line at current position |
||
358 | */ |
||
8095 | avox | 359 | void startLine(int first) |
360 | { |
||
361 | itemsInLine = 0; |
||
362 | line.x = xPos; |
||
363 | line.y = yPos; |
||
364 | line.firstItem = first; |
||
365 | line.ascent = 10; |
||
366 | line.descent = 0; |
||
367 | line.width = 0; |
||
368 | line.naturalWidth = 0; |
||
369 | breakIndex = -1; |
||
370 | breakXPos = 0; |
||
9047 | avox | 371 | maxShrink = 0; |
372 | maxStretch = 0; |
||
8095 | avox | 373 | } |
374 | |||
9047 | avox | 375 | |
376 | /// called when glyphs are placed on the line |
||
377 | void rememberShrinkStretch(QChar ch, double wide, const ParagraphStyle& style) |
||
378 | { |
||
379 | if (SpecialChars::isExpandingSpace(ch)) |
||
380 | maxShrink += (1 - style.minWordTracking()) * wide; |
||
381 | else |
||
382 | { |
||
383 | maxShrink += (1 - style.minGlyphExtension()) * wide; |
||
384 | } |
||
385 | maxStretch += (style.maxGlyphExtension() - 1) * wide; |
||
386 | } |
||
387 | |||
8761 | avox | 388 | /// called when a possible break is passed |
8095 | avox | 389 | void rememberBreak(int index, double pos) |
390 | { |
||
9047 | avox | 391 | if (pos > colRight) |
392 | { |
||
393 | // only look for the first break behind the right edge |
||
394 | maxShrink = 0; |
||
395 | |||
396 | // check if we already have a better break |
||
397 | if (breakIndex >= 0) |
||
398 | { |
||
399 | double oldLooseness = qAbs(colRight - breakXPos); |
||
400 | |||
401 | double newLooseness = pos - colRight; |
||
402 | if (newLooseness >= oldLooseness) |
||
403 | return; |
||
404 | } |
||
405 | breakXPos = colRight; |
||
406 | } |
||
407 | else |
||
408 | { |
||
409 | breakXPos = pos; |
||
410 | } |
||
8095 | avox | 411 | breakIndex = index; |
412 | } |
||
413 | |||
8761 | avox | 414 | /// called when a mandatory break is found |
8095 | avox | 415 | void breakLine(const StoryText& itemText, int last) |
416 | { |
||
417 | breakIndex = last; |
||
418 | breakXPos = line.x; |
||
419 | for (int j = line.firstItem; j <= last; ++j) |
||
420 | if ( (itemText.item(j)->effects() & ScStyle_SuppressSpace) == 0) |
||
421 | breakXPos += itemText.item(j)->glyph.wide(); |
||
422 | } |
||
423 | |||
8761 | avox | 424 | /// use the last remembered break to set line width and itemrange |
8095 | avox | 425 | void finishLine(double endX) |
426 | { |
||
427 | line.lastItem = breakIndex; |
||
428 | line.naturalWidth = breakXPos - line.x; |
||
429 | line.width = endX - line.x; |
||
9047 | avox | 430 | maxShrink = maxStretch = 0; |
8095 | avox | 431 | } |
432 | |||
433 | |||
434 | bool isEndOfLine(double moreSpace = 0) |
||
435 | { |
||
8103 | avox | 436 | if (legacy) |
9047 | avox | 437 | return xPos + insets.Right + lineCorr + moreSpace - maxShrink >= colRight; |
8103 | avox | 438 | else |
9047 | avox | 439 | return xPos + moreSpace - maxShrink >= colRight; |
8095 | avox | 440 | } |
441 | |||
8761 | avox | 442 | /// find x position to start current line |
9372 | fschmid | 443 | double startOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace) |
8095 | avox | 444 | { |
445 | QPoint pt1, pt2; |
||
446 | double tmpX = xPos; |
||
447 | pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); |
||
448 | pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); |
||
449 | // increase pt1/pt2 until i-beam reaches end of line |
||
9372 | fschmid | 450 | while ((!shape.contains(pf2.map(pt1))) || (!shape.contains(pf2.map(pt2)))) |
8095 | avox | 451 | { |
452 | tmpX++; |
||
9047 | avox | 453 | if (xPos + (legacy? lineCorr + insets.Right : 0) + lineCorr + morespace >= colRight) |
8095 | avox | 454 | { |
455 | return tmpX; |
||
456 | } |
||
457 | pt1 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(yPos + descent)); |
||
458 | pt2 = QPoint(static_cast<int>(ceil(tmpX)), static_cast<int>(ceil(yPos - ascent))); |
||
459 | } |
||
460 | return tmpX; |
||
461 | } |
||
462 | |||
8761 | avox | 463 | /// find x position where this line must end |
9372 | fschmid | 464 | double endOfLine(const QRegion& shape, const QMatrix& pf2, double ascent, double descent, double morespace = 0) |
8095 | avox | 465 | { |
9047 | avox | 466 | double EndX = floor(qMax(line.x, qMin(colRight,breakXPos) - 1)); |
8095 | avox | 467 | QPoint pt1, pt2; |
468 | // qDebug(QString("endx start=%1, hl is '%2'").arg(EndX).arg(hl->ch)); |
||
469 | do { |
||
470 | EndX += 0.125; |
||
8103 | avox | 471 | pt1 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(yPos+descent)); |
472 | pt2 = QPoint(qRound(ceil(EndX + insets.Right)), static_cast<int>(ceil(yPos-ascent))); |
||
8095 | avox | 473 | } while |
8547 | cbradney | 474 | ( (EndX + (legacy? lineCorr + insets.Right : 0) < colRight - morespace) |
9372 | fschmid | 475 | && shape.contains(pf2.map(pt1)) |
476 | && shape.contains(pf2.map(pt2)) |
||
8095 | avox | 477 | ); |
478 | |||
479 | return EndX; |
||
480 | } |
||
481 | |||
482 | |||
8956 | avox | 483 | double getLineAscent(const StoryText& itemText) |
484 | { |
||
485 | double result = 0; |
||
486 | if ((itemText.text(line.firstItem) == SpecialChars::PARSEP) || (itemText.text(line.firstItem) == SpecialChars::LINEBREAK)) |
||
487 | result = itemText.charStyle(line.firstItem).font().ascent(itemText.charStyle(line.firstItem).fontSize() / 10.0); |
||
488 | else if (itemText.object(line.firstItem) != 0) |
||
489 | result = QMAX(result, (itemText.object(line.firstItem)->gHeight + itemText.object(line.firstItem)->lineWidth()) * (itemText.charStyle(line.firstItem).scaleV() / 1000.0)); |
||
490 | else //if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap == 0) |
||
491 | result = itemText.charStyle(line.firstItem).font().realCharAscent(itemText.text(line.firstItem), itemText.charStyle(line.firstItem).fontSize() / 10.0); |
||
492 | for (int zc = 0; zc < itemsInLine; ++zc) |
||
493 | { |
||
494 | QChar ch = itemText.text(line.firstItem + zc); |
||
495 | if (ch == SpecialChars::PAGENUMBER) |
||
496 | ch = '8'; // should have highest ascender even in oldstyle |
||
497 | const CharStyle& cStyle(itemText.charStyle(line.firstItem + zc)); |
||
498 | if ((ch == SpecialChars::TAB) || (ch == QChar(10)) |
||
499 | || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN) |
||
500 | || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::LINEBREAK) |
||
501 | || (ch == SpecialChars::FRAMEBREAK) || (ch.isSpace())) |
||
502 | continue; |
||
503 | double asce; |
||
504 | if (itemText.object(line.firstItem + zc) != 0) |
||
505 | asce = itemText.object(line.firstItem + zc)->gHeight + itemText.object(line.firstItem + zc)->lineWidth() * (cStyle.scaleV() / 1000.0); |
||
506 | else //if (itemText.charStyle(current.line.firstItem + zc).effects() & ScStyle_DropCap == 0) |
||
507 | asce = cStyle.font().realCharAscent(ch, cStyle.fontSize() / 10.0); |
||
508 | // qDebug(QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result)); |
||
509 | result = QMAX(result, asce); |
||
510 | } |
||
511 | return result; |
||
512 | } |
||
513 | |||
514 | double getLineHeight(const StoryText& itemText) |
||
515 | { |
||
516 | double result = 0; |
||
517 | if (itemText.object(line.firstItem) != 0) |
||
518 | result = QMAX(result, (itemText.object(line.firstItem)->gHeight + itemText.object(line.firstItem)->lineWidth()) * (itemText.charStyle(line.firstItem).scaleV() / 1000.0)); |
||
519 | else //if (itemText.charStyle(current.line.firstItem).effects() & ScStyle_DropCap == 0) |
||
520 | result = itemText.charStyle(line.firstItem).font().height(itemText.charStyle(line.firstItem).fontSize() / 10.0); |
||
521 | for (int zc = 0; zc < itemsInLine; ++zc) |
||
522 | { |
||
523 | QChar ch = itemText.text(line.firstItem+zc); |
||
524 | if ((ch == SpecialChars::TAB) || (ch == QChar(10)) |
||
525 | || (ch == SpecialChars::PARSEP) || (ch == SpecialChars::NBHYPHEN) |
||
526 | || (ch == SpecialChars::COLBREAK) || (ch == SpecialChars::FRAMEBREAK) |
||
527 | || (ch == SpecialChars::LINEBREAK) || (ch.isSpace())) |
||
528 | continue; |
||
529 | double asce; |
||
530 | if (itemText.object(line.firstItem+zc) != 0) |
||
531 | asce = (itemText.object(line.firstItem+zc)->gHeight + itemText.object(line.firstItem+zc)->lineWidth()) * (itemText.charStyle(line.firstItem+zc).scaleV() / 1000.0); |
||
532 | else //if (itemText.charStyle(current.line.firstItem+zc).effects() & ScStyle_DropCap == 0) |
||
533 | asce = itemText.charStyle(line.firstItem+zc).font().height(itemText.charStyle(line.firstItem+zc).fontSize() / 10.0); |
||
534 | // qDebug(QString("checking char 'x%2' with ascender %1 > %3").arg(asce).arg(ch.unicode()).arg(result)); |
||
535 | result = QMAX(result, asce); |
||
536 | } |
||
537 | return result; |
||
538 | } |
||
539 | |||
540 | |||
8095 | avox | 541 | private: |
542 | double frameWidth; |
||
543 | double frameHeight; |
||
544 | MarginStruct insets; |
||
545 | double lineCorr; |
||
7313 | avox | 546 | }; |
547 | |||
548 | |||
8095 | avox | 549 | |
8761 | avox | 550 | /// called when line length is known and line is to be justified |
8095 | avox | 551 | static void justifyLine(StoryText& itemText, LineSpec& line) |
552 | { |
||
8761 | avox | 553 | |
9047 | avox | 554 | double glyphNatural = 0; |
555 | double spaceNatural = 0; |
||
556 | double glyphExtension; |
||
557 | double spaceExtension; |
||
558 | |||
559 | const ParagraphStyle& style(itemText.paragraphStyle(line.firstItem)); |
||
560 | |||
561 | // measure natural widths for glyphs and spaces |
||
9054 | avox | 562 | for (int sof = line.firstItem; sof <= line.lastItem; ++sof) |
8095 | avox | 563 | { |
9047 | avox | 564 | if (!SpecialChars::isExpandingSpace(itemText.text(sof))) |
565 | { |
||
566 | glyphNatural += itemText.item(sof)->glyph.wide(); |
||
567 | } |
||
568 | else if ( (itemText.item(sof)->effects() & ScStyle_SuppressSpace) == 0) |
||
569 | { |
||
570 | spaceNatural += itemText.item(sof)->glyph.wide(); |
||
571 | } |
||
8095 | avox | 572 | } |
9047 | avox | 573 | |
574 | // decision: prio 1: stretch glyph; prio 2: stretch spaces |
||
575 | |||
576 | if (line.width < spaceNatural + glyphNatural * style.minGlyphExtension() && spaceNatural > 0) |
||
577 | { |
||
578 | glyphExtension = style.minGlyphExtension() - 1; |
||
579 | spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1; |
||
580 | } |
||
581 | else if (line.width < spaceNatural + glyphNatural * style.maxGlyphExtension() && glyphNatural > 0) |
||
582 | { |
||
583 | spaceExtension = 0; |
||
584 | glyphExtension = (line.width - spaceNatural) / glyphNatural - 1; |
||
585 | } |
||
8095 | avox | 586 | else |
9047 | avox | 587 | { |
588 | glyphExtension = style.maxGlyphExtension() - 1; |
||
589 | if (spaceNatural > 0) |
||
590 | spaceExtension = (line.width - glyphNatural * (1+glyphExtension) ) / spaceNatural - 1; |
||
591 | else |
||
592 | spaceExtension = 0; |
||
593 | } |
||
8095 | avox | 594 | |
9047 | avox | 595 | double glyphScale = 1 + glyphExtension; |
596 | |||
597 | /* |
||
598 | qDebug(QString("justify: line = %7 natural = %1 + %2 = %3 (%4); spaces + %5%%; min=%8; glyphs + %6%%; min=%9") |
||
599 | .arg(spaceNatural).arg(glyphNatural).arg(spaceNatural+glyphNatural).arg(line.naturalWidth) |
||
600 | .arg(spaceExtension).arg(glyphExtension).arg(line.width) |
||
601 | .arg(style.minWordTracking()).arg(style.minGlyphExtension())); |
||
602 | */ |
||
603 | |||
604 | // distribute whitespace on spaces and glyphs |
||
605 | for (int yof = line.firstItem; yof <= line.lastItem; ++yof) |
||
8095 | avox | 606 | { |
9047 | avox | 607 | double wide = itemText.item(yof)->glyph.wide(); |
608 | if (!SpecialChars::isExpandingSpace(itemText.text(yof))) |
||
8095 | avox | 609 | { |
9047 | avox | 610 | itemText.item(yof)->glyph.last()->xadvance += wide * glyphExtension; |
611 | GlyphLayout* glyph = &(itemText.item(yof)->glyph); |
||
612 | while (glyph) |
||
613 | { |
||
614 | glyph->xoffset *= glyphScale; |
||
615 | glyph->scaleH *= glyphScale; |
||
616 | glyph = glyph->more; |
||
617 | } |
||
8095 | avox | 618 | } |
9047 | avox | 619 | else if ((itemText.item(yof)->effects() & ScStyle_SuppressSpace) == 0) |
620 | { |
||
621 | itemText.item(yof)->glyph.last()->xadvance += wide * spaceExtension; |
||
622 | } |
||
8095 | avox | 623 | } |
624 | } |
||
625 | |||
626 | |||
9047 | avox | 627 | /// called when linelength is known and line is not justified |
628 | static void indentLine(StoryText& itemText, LineSpec& line, double leftIndent) |
||
8095 | avox | 629 | { |
9047 | avox | 630 | if (line.naturalWidth > line.width) |
631 | { |
||
632 | justifyLine(itemText, line); |
||
633 | } |
||
634 | if (leftIndent > 0) |
||
635 | { |
||
636 | line.x += leftIndent; |
||
637 | line.width -= leftIndent; |
||
638 | } |
||
8095 | avox | 639 | } |
640 | |||
8761 | avox | 641 | /// calculate how much the first char should stick out to the left |
8095 | avox | 642 | static double opticalLeftMargin(const StoryText& itemText, const LineSpec& line) |
643 | { |
||
644 | int b = line.firstItem; |
||
645 | while (b < line.lastItem && (itemText.item(b)->effects() & ScStyle_SuppressSpace)) |
||
646 | ++b; |
||
647 | |||
648 | double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0); |
||
649 | QChar chr = itemText.text(b); |
||
650 | double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0); |
||
651 | if (QString("'´`").find(chr) >= 0 |
||
8761 | avox | 652 | || chr == QChar(0x2018) // quote 6 |
653 | || chr == QChar(0x2019) // quote 9 |
||
654 | || chr == QChar(0x201a) // lower quote 9 |
||
655 | || chr == QChar(0x201b) // upper reversed 9 6 |
||
656 | || chr == QChar(0x2039) // single guillemet < |
||
657 | || chr == QChar(0x203a) // single guillemet > |
||
8095 | avox | 658 | ) |
659 | leftCorr *= -0.7; |
||
660 | else if (QString("\"").find(chr) >= 0 |
||
8761 | avox | 661 | || chr == QChar(0x00ab) // guillemet << |
662 | || chr == QChar(0x00bb) // guillemet >> |
||
663 | || chr == QChar(0x201c) // quote 66 |
||
664 | || chr == QChar(0x201d) // quote 99 |
||
665 | || chr == QChar(0x201e) // lower quote 99 |
||
666 | || chr == QChar(0x201f) // upper reversed 99 |
||
8095 | avox | 667 | ) |
668 | leftCorr *= -0.5; |
||
669 | else { |
||
670 | leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr); |
||
671 | leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0); |
||
672 | // double leftCorr2 = itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0, chr); |
||
673 | // leftCorr2 -= itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0); |
||
8562 | jghali | 674 | // leftCorr = qMin(leftCorr, leftCorr2); |
8095 | avox | 675 | } |
676 | return leftCorr; |
||
677 | } |
||
678 | |||
679 | |||
8761 | avox | 680 | |
681 | /// calculate how much the last char should stick out to the right |
||
8095 | avox | 682 | static double opticalRightMargin(const StoryText& itemText, const LineSpec& line) |
683 | { |
||
684 | int b = line.lastItem; |
||
685 | while (b > line.firstItem && |
||
8177 | avox | 686 | (SpecialChars::isBreakingSpace(itemText.text(b)) || SpecialChars::isBreak(itemText.text(b))) |
8095 | avox | 687 | ) |
688 | --b; |
||
689 | if (b >= line.firstItem) |
||
690 | { |
||
691 | double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0); |
||
692 | QChar chr = (itemText.item(b)->effects() & ScStyle_SmartHyphenVisible) ? |
||
693 | QChar('-') : itemText.text(b); |
||
694 | double rightCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0); |
||
695 | if (QString("-,.`´'~").find(chr) >= 0 |
||
696 | || chr == QChar(0x2018) |
||
697 | || chr == QChar(0x2019) |
||
698 | || chr == QChar(0x201a) |
||
699 | || chr == QChar(0x201b) |
||
700 | || chr == QChar(0x2039) |
||
701 | || chr == QChar(0x203a) |
||
8761 | avox | 702 | || chr == QChar(0x2032) // PRIME |
8095 | avox | 703 | ) |
704 | rightCorr *= 0.7; |
||
705 | else if (QString(";:\"").find(chr) >= 0 |
||
706 | || chr == QChar(0x00ab) |
||
707 | || chr == QChar(0x00bb) |
||
708 | || chr == QChar(0x201c) |
||
709 | || chr == QChar(0x201d) |
||
710 | || chr == QChar(0x201e) |
||
711 | || chr == QChar(0x201f) |
||
8761 | avox | 712 | || chr == QChar(0x2013) // EN DASH |
713 | || chr == QChar(0x2033) // double prime |
||
8095 | avox | 714 | ) |
715 | rightCorr *= 0.5; |
||
716 | else { |
||
717 | rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0); |
||
718 | rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); |
||
719 | } |
||
720 | return rightCorr; |
||
721 | } |
||
722 | return 0.0; |
||
723 | } |
||
724 | |||
725 | |||
8761 | avox | 726 | |
727 | |||
728 | |||
5362 | avox | 729 | void PageItem_TextFrame::layout() |
3614 | cbradney | 730 | { |
8103 | avox | 731 | |
5732 | avox | 732 | if (BackBox != NULL && BackBox->invalid) { |
733 | // qDebug("textframe: len=%d, going back", itemText.length()); |
||
7379 | avox | 734 | invalid = false; |
8060 | avox | 735 | PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); |
736 | if (!prevInChain) |
||
8939 | avox | 737 | qDebug(QString("layout(): backBox=%1 is no textframe!!").arg((ulong)BackBox)); |
8060 | avox | 738 | else |
739 | BackBox->layout(); |
||
5362 | avox | 740 | return; |
741 | } |
||
6370 | avox | 742 | else if (!invalid && OnMasterPage.isEmpty()) { |
6375 | avox | 743 | // qDebug(QString("textframe: len=%1, invalid=%2 OnMasterPage=%3: no relayout").arg(itemText.length()).arg(invalid).arg(OnMasterPage)); |
5732 | avox | 744 | return; |
745 | } |
||
8334 | avox | 746 | if (invalid && BackBox == NULL) |
747 | firstChar = 0; |
||
748 | |||
5732 | avox | 749 | // qDebug(QString("textframe(%1,%2): len=%3, start relayout at %4").arg(Xpos).arg(Ypos).arg(itemText.length()).arg(firstInFrame())); |
9380 | fschmid | 750 | // ScribusView* view = m_Doc->view(); |
9372 | fschmid | 751 | QMatrix pf2; |
5362 | avox | 752 | QPoint pt1, pt2; |
753 | QRegion cm; |
||
7969 | avox | 754 | double chs, chsd = 0; |
8095 | avox | 755 | double oldCurY, EndX, OFs, wide, kernVal; |
7313 | avox | 756 | QString chstr; |
5362 | avox | 757 | ScText *hl; |
6805 | avox | 758 | ParagraphStyle style; |
8095 | avox | 759 | int /*ParagraphStyle::OpticalMarginType*/ opticalMargins = ParagraphStyle::OM_None; |
5362 | avox | 760 | |
761 | bool outs = false; |
||
762 | bool fBorder = false; |
||
763 | bool goNoRoom = false; |
||
764 | bool goNextColumn = false; |
||
7905 | avox | 765 | |
766 | TabControl tabs; |
||
767 | tabs.active = false; // RTab |
||
768 | tabs.status = TabNONE; // TabCode |
||
769 | tabs.charIndex = -1; // StartRT |
||
770 | tabs.xPos = 0; // RTabX |
||
771 | |||
8501 | cbradney | 772 | Q3ValueList<ParagraphStyle::TabRecord> tTabValues; |
7905 | avox | 773 | tTabValues.clear(); |
774 | |||
5362 | avox | 775 | bool DropCmode = false; |
776 | bool AbsHasDrop = false; |
||
7969 | avox | 777 | double desc=0, asce=0, maxDY=0, desc2=0, maxDX=0; |
778 | int DropLines = 0; |
||
6370 | avox | 779 | double DropCapDrop = 0; |
5362 | avox | 780 | |
6144 | avox | 781 | itemText.clearLines(); |
8095 | avox | 782 | |
783 | double lineCorr = 0; |
||
784 | if (lineColor() != CommonStrings::None) |
||
785 | lineCorr = m_lineWidth / 2.0; |
||
786 | |||
787 | // TODO: refactor this into PageItem |
||
788 | MarginStruct extra; |
||
789 | extra.Top = TExtra; |
||
790 | extra.Left = Extra; |
||
791 | extra.Right = RExtra; |
||
792 | extra.Bottom = BExtra; |
||
793 | |||
794 | LineControl current; |
||
795 | current.init(Width, Height, extra, lineCorr); |
||
796 | current.initColumns(columnWidth(), ColGap); |
||
797 | current.hyphenCount = 0; |
||
798 | |||
5778 | avox | 799 | // dump styles |
800 | /* |
||
801 | for (int i=0; i < itemText.nrOfParagraphs(); ++i) { |
||
802 | const ParagraphStyle& pstyle(itemText.paragraphStyle(itemText.endOfParagraph(i))); |
||
803 | qDebug(QString("par %1:").arg(i)); |
||
804 | dumpIt(pstyle); |
||
805 | } |
||
806 | qDebug(QString("default:")); |
||
807 | dumpIt(itemText.defaultStyle()); |
||
6805 | avox | 808 | */ |
5778 | avox | 809 | |
9372 | fschmid | 810 | // pf2.begin(view->viewport()); |
5362 | avox | 811 | pf2.translate(Xpos, Ypos); |
812 | pf2.rotate(Rot); |
||
6144 | avox | 813 | |
814 | setShadow(); |
||
5732 | avox | 815 | if ((itemText.length() != 0)) // || (NextBox != 0)) |
8095 | avox | 816 | { |
5408 | avox | 817 | // determine layout area |
9372 | fschmid | 818 | QRegion cl = availableRegion(QRegion(pf2.map(Clip))); |
5362 | avox | 819 | |
820 | if (imageFlippedH()) |
||
821 | { |
||
822 | pf2.translate(Width, 0); |
||
823 | pf2.scale(-1, 1); |
||
824 | } |
||
825 | if (imageFlippedV()) |
||
826 | { |
||
827 | pf2.translate(0, Height); |
||
828 | pf2.scale(1, -1); |
||
829 | } |
||
5408 | avox | 830 | |
8095 | avox | 831 | current.nextColumn(0); |
832 | |||
5559 | avox | 833 | // find start of first line |
7887 | avox | 834 | if (firstInFrame() < itemText.length()) |
5362 | avox | 835 | { |
7887 | avox | 836 | hl = itemText.item(firstInFrame()); |
837 | style = itemText.paragraphStyle(firstInFrame()); |
||
8956 | avox | 838 | if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) |
839 | { |
||
840 | style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); |
||
841 | // qDebug(QString("auto linespacing: %1").arg(style.lineSpacing())); |
||
842 | } |
||
843 | |||
5721 | avox | 844 | // qDebug(QString("style @0: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) |
845 | // .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()?style.parent()->name():"")); |
||
6805 | avox | 846 | if (style.hasDropCap()) |
3614 | cbradney | 847 | { |
8062 | avox | 848 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
6805 | avox | 849 | chs = qRound(m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines() * 10); |
5362 | avox | 850 | else |
6805 | avox | 851 | chs = qRound(style.lineSpacing() * style.dropCapLines() * 10); |
3614 | cbradney | 852 | } |
6370 | avox | 853 | else |
5691 | avox | 854 | chs = hl->fontSize(); |
5980 | avox | 855 | desc2 = -hl->font().descent(chs / 10.0); |
8095 | avox | 856 | current.yPos = extra.Top + lineCorr; |
8956 | avox | 857 | // qDebug(QString("first line at y=%1").arg(current.yPos)); |
5362 | avox | 858 | } |
6370 | avox | 859 | else // empty itemText: |
5362 | avox | 860 | { |
6370 | avox | 861 | desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); |
8095 | avox | 862 | current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; |
5362 | avox | 863 | } |
8095 | avox | 864 | current.startLine(firstInFrame()); |
5362 | avox | 865 | outs = false; |
866 | OFs = 0; |
||
867 | MaxChars = 0; |
||
5721 | avox | 868 | for (int a = firstInFrame(); a < itemText.length(); ++a) |
5362 | avox | 869 | { |
5721 | avox | 870 | hl = itemText.item(a); |
8060 | avox | 871 | if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) |
872 | style = itemText.paragraphStyle(a); |
||
8095 | avox | 873 | if (current.itemsInLine == 0) |
8060 | avox | 874 | opticalMargins = style.opticalMargins(); |
875 | |||
7887 | avox | 876 | // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); |
8939 | avox | 877 | const CharStyle& charStyle = (chstr[0] != SpecialChars::PARSEP? itemText.charStyle(a) : itemText.paragraphStyle(a).charStyle()); |
8060 | avox | 878 | if (!charStyle.parent().isEmpty()) |
879 | { |
||
880 | // qDebug(QString("charstyle pos %1: %2 (%3 %4 %5 %6 %7 %8 %9)").arg(a).arg(charStyle.parent()) |
||
881 | // .arg((uint)charStyle.parentStyle()).arg(charStyle.font().scName()).arg(charStyle.fontSize()) |
||
882 | // .arg(charStyle.fillColor()).arg(charStyle.strokeColor()).arg(charStyle.parentStyle()->name()).arg((uint)charStyle.parentStyle()->parentStyle())); |
||
883 | } |
||
6144 | avox | 884 | // qDebug(QString("charstyle pos %1: %2 (%3)").arg(a).arg(charStyle.asString()).arg(charStyle.fontSize())); |
5721 | avox | 885 | // qDebug(QString("style @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) |
7287 | avox | 886 | // .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) |
5721 | avox | 887 | // .arg(a)); |
888 | |||
6144 | avox | 889 | chstr = ExpandToken(a); |
890 | // qDebug(QString("expanded token: '%1'").arg(chstr)); |
||
891 | if (chstr.isEmpty()) |
||
8861 | cbradney | 892 | chstr = SpecialChars::ZWNBSPACE; |
8956 | avox | 893 | if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) |
894 | { |
||
895 | style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); |
||
896 | } |
||
5408 | avox | 897 | // find out about par gap and dropcap |
5721 | avox | 898 | if (a == firstInFrame()) |
3614 | cbradney | 899 | { |
8814 | cbradney | 900 | if (a == 0 || itemText.text(a-1) == SpecialChars::PARSEP) |
5362 | avox | 901 | { |
8814 | cbradney | 902 | current.yPos += style.gapBefore(); |
7313 | avox | 903 | if (chstr[0] != SpecialChars::PARSEP) |
5362 | avox | 904 | { |
5721 | avox | 905 | DropCmode = style.hasDropCap(); |
5362 | avox | 906 | if (DropCmode) |
5721 | avox | 907 | DropLines = style.dropCapLines(); |
5362 | avox | 908 | } |
909 | else |
||
910 | DropCmode = false; |
||
911 | } |
||
3614 | cbradney | 912 | } |
8814 | cbradney | 913 | |
6370 | avox | 914 | { // local block for 'fl' |
5691 | avox | 915 | StyleFlag fl = hl->effects(); |
916 | fl &= ~ScStyle_DropCap; |
||
917 | fl &= ~ScStyle_SmartHyphenVisible; |
||
918 | hl->setEffects(fl); |
||
919 | } |
||
8814 | cbradney | 920 | |
8150 | avox | 921 | // No space at begin of line, |
922 | if (legacy) |
||
3614 | cbradney | 923 | { |
8150 | avox | 924 | // unless at begin of par (eeks) |
8177 | avox | 925 | if ( (current.itemsInLine == 0) && (SpecialChars::isBreakingSpace(hl->ch[0])) |
926 | && (a > 0 && ! SpecialChars::isBreak(itemText.text(a-1))) |
||
927 | && ! (a > 0 && SpecialChars::isBreakingSpace(itemText.text(a-1)) |
||
8150 | avox | 928 | && (itemText.charStyle(a-1).effects() & ScStyle_SuppressSpace) != ScStyle_SuppressSpace)) |
929 | { |
||
930 | hl->setEffects(hl->effects() | ScStyle_SuppressSpace); |
||
931 | hl->glyph.xadvance = 0; |
||
932 | continue; |
||
933 | } |
||
934 | else |
||
935 | hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); |
||
5362 | avox | 936 | } |
8150 | avox | 937 | else // from 134 on use NBSPACE for this effect |
938 | { |
||
8177 | avox | 939 | if ( current.itemsInLine == 0 && SpecialChars::isBreakingSpace(hl->ch[0])) |
8150 | avox | 940 | { |
941 | hl->setEffects(hl->effects() | ScStyle_SuppressSpace); |
||
942 | hl->glyph.xadvance = 0; |
||
943 | continue; |
||
944 | } |
||
945 | else |
||
946 | hl->setEffects(hl->effects() & ~ScStyle_SuppressSpace); |
||
947 | } |
||
948 | // qDebug(QString("textframe(%1,%2): len=%3, fontsize=%4, ascent=%5").arg(Xpos).arg(Ypos).arg(itemText.length()) |
||
6144 | avox | 949 | // .arg(charStyle.fontSize()).arg(charStyle.font().ascent())); |
8095 | avox | 950 | if (current.itemsInLine == 0) |
5362 | avox | 951 | { |
5732 | avox | 952 | // more about par gap and dropcaps |
8814 | cbradney | 953 | if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == 0) && (BackBox == 0)) && (!current.startOfCol)) // after || always evaluates to false? FIXME |
3614 | cbradney | 954 | { |
8956 | avox | 955 | // qDebug(QString("gap before2: y=%1+%2").arg(current.yPos).arg(style.gapBefore())); |
8095 | avox | 956 | current.yPos += style.gapBefore(); |
6370 | avox | 957 | DropCapDrop = 0; |
7313 | avox | 958 | if (chstr[0] != SpecialChars::PARSEP) |
5721 | avox | 959 | DropCmode = style.hasDropCap(); |
5362 | avox | 960 | else |
961 | DropCmode = false; |
||
962 | if (DropCmode) |
||
963 | { |
||
5721 | avox | 964 | DropLines = style.dropCapLines(); |
8062 | avox | 965 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
6370 | avox | 966 | DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); |
5362 | avox | 967 | else |
968 | { |
||
5721 | avox | 969 | if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) |
6805 | avox | 970 | DropCapDrop = style.lineSpacing() * (DropLines-1); |
5362 | avox | 971 | else |
6370 | avox | 972 | DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); |
5362 | avox | 973 | } |
8956 | avox | 974 | // qDebug(QString("dropcapdrop: y=%1+%2").arg(current.yPos).arg(DropCapDrop)); |
8095 | avox | 975 | current.yPos += DropCapDrop; |
5362 | avox | 976 | } |
3614 | cbradney | 977 | } |
5362 | avox | 978 | } |
5408 | avox | 979 | // find charsize & y pos |
5362 | avox | 980 | if (DropCmode) |
981 | { |
||
5408 | avox | 982 | // dropcap active? |
8062 | avox | 983 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
6370 | avox | 984 | DropCapDrop = m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); |
985 | else |
||
3614 | cbradney | 986 | { |
6370 | avox | 987 | if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) |
6805 | avox | 988 | DropCapDrop = style.lineSpacing() * (DropLines-1); |
6370 | avox | 989 | else |
990 | DropCapDrop = charStyle.font().height(style.charStyle().fontSize() / 10.0) * (DropLines-1); |
||
991 | } |
||
992 | |||
8062 | avox | 993 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
6370 | avox | 994 | { |
6144 | avox | 995 | chsd = (10 * ((m_Doc->typographicSettings.valueBaseGrid * (DropLines-1)+(charStyle.font().ascent(style.charStyle().fontSize() / 10.0))) / (charStyle.font().realCharHeight(chstr[0], 1)))); |
996 | chs = (10 * ((m_Doc->typographicSettings.valueBaseGrid * (DropLines-1)+(charStyle.font().ascent(style.charStyle().fontSize() / 10.0))) / charStyle.font().realCharAscent(chstr[0], 1))); |
||
3614 | cbradney | 997 | } |
5362 | avox | 998 | else |
3614 | cbradney | 999 | { |
5721 | avox | 1000 | if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) |
5362 | avox | 1001 | { |
6805 | avox | 1002 | chsd = (10 * ((style.lineSpacing() * (DropLines-1)+(charStyle.font().ascent(style.charStyle().fontSize() / 10.0))) / (charStyle.font().realCharHeight(chstr[0], 1)))); |
1003 | chs = (10 * ((style.lineSpacing() * (DropLines-1)+(charStyle.font().ascent(style.charStyle().fontSize() / 10.0))) / charStyle.font().realCharAscent(chstr[0], 1))); |
||
5184 | avox | 1004 | } |
3614 | cbradney | 1005 | else |
1006 | { |
||
6144 | avox | 1007 | double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); |
1008 | chsd = (10 * ((currasce * (DropLines-1)+(charStyle.font().ascent(style.charStyle().fontSize() / 10.0))) / (charStyle.font().realCharHeight(chstr[0], 1)))); |
||
1009 | chs = (10 * ((currasce * (DropLines-1)+(charStyle.font().ascent(style.charStyle().fontSize() / 10.0))) / charStyle.font().realCharAscent(chstr[0], 1))); |
||
3614 | cbradney | 1010 | } |
5362 | avox | 1011 | } |
5691 | avox | 1012 | hl->setEffects(hl->effects() | ScStyle_DropCap); |
6370 | avox | 1013 | hl->glyph.yoffset -= DropCapDrop; |
5362 | avox | 1014 | } |
5408 | avox | 1015 | else // ! dropCapMode |
5362 | avox | 1016 | { |
8629 | cbradney | 1017 | if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) |
8177 | avox | 1018 | chs = qRound((hl->embedded.getItem()->gHeight + hl->embedded.getItem()->lineWidth()) * 10); |
5362 | avox | 1019 | else |
6144 | avox | 1020 | chs = charStyle.fontSize(); |
5362 | avox | 1021 | } |
8098 | avox | 1022 | // find tracking |
1023 | if (current.itemsInLine == 0) |
||
1024 | { |
||
1025 | itemText.item(a)->setEffects(itemText.item(a)->effects() | ScStyle_StartOfLine); |
||
1026 | kernVal = 0; |
||
1027 | } |
||
1028 | else |
||
1029 | { |
||
1030 | kernVal = 0; // chs * charStyle.tracking() / 10000.0; |
||
1031 | itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); |
||
1032 | } |
||
6144 | avox | 1033 | hl->glyph.yadvance = 0; |
5980 | avox | 1034 | oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); |
5408 | avox | 1035 | // find out width of char |
8629 | cbradney | 1036 | if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) |
8177 | avox | 1037 | wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); |
5362 | avox | 1038 | else |
1039 | { |
||
6354 | avox | 1040 | wide = hl->glyph.wide(); |
8814 | cbradney | 1041 | // apply kerning |
6354 | avox | 1042 | if (a+1 < itemText.length()) |
1043 | { |
||
1044 | uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); |
||
7356 | avox | 1045 | double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; |
1046 | wide += kern; |
||
1047 | hl->glyph.xadvance += kern; |
||
6354 | avox | 1048 | } |
5362 | avox | 1049 | } |
1050 | if (DropCmode) |
||
1051 | { |
||
5408 | avox | 1052 | // drop caps are wider... |
8629 | cbradney | 1053 | if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) |
5362 | avox | 1054 | { |
8177 | avox | 1055 | wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); |
8062 | avox | 1056 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
5362 | avox | 1057 | asce = m_Doc->typographicSettings.valueBaseGrid * DropLines; |
1058 | else |
||
3614 | cbradney | 1059 | { |
5721 | avox | 1060 | if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) |
6805 | avox | 1061 | asce = style.lineSpacing() * DropLines; |
5362 | avox | 1062 | else |
6144 | avox | 1063 | asce = charStyle.font().height(style.charStyle().fontSize() / 10.0) * DropLines; |
3614 | cbradney | 1064 | } |
6144 | avox | 1065 | hl->glyph.scaleH /= hl->glyph.scaleV; |
8177 | avox | 1066 | hl->glyph.scaleV = (asce / (hl->embedded.getItem()->gHeight + hl->embedded.getItem()->lineWidth())); |
6144 | avox | 1067 | hl->glyph.scaleH *= hl->glyph.scaleV; |
5362 | avox | 1068 | } |
1069 | else |
||
1070 | { |
||
7313 | avox | 1071 | wide = charStyle.font().realCharWidth(chstr[0], chsd / 10.0); |
1072 | asce = charStyle.font().realCharHeight(chstr[0], chsd / 10.0); |
||
6375 | avox | 1073 | // qDebug(QString("dropcaps pre: chsd=%1 realCharHeight = %2 chstr=%3").arg(chsd).arg(asce).arg(chstr2[0])); |
6144 | avox | 1074 | hl->glyph.scaleH /= hl->glyph.scaleV; |
8072 | avox | 1075 | hl->glyph.scaleV = (asce / charStyle.font().realCharHeight(chstr[0], charStyle.fontSize() / 10.0)); |
6144 | avox | 1076 | hl->glyph.scaleH *= hl->glyph.scaleV; |
5362 | avox | 1077 | } |
6370 | avox | 1078 | hl->glyph.xadvance = wide; |
5362 | avox | 1079 | desc2 = 0; |
1080 | desc = 0; |
||
1081 | } |
||
8814 | cbradney | 1082 | else // !DropCMode |
5362 | avox | 1083 | { |
6144 | avox | 1084 | // qDebug(QString("textframe ascent/descent: fontsize=%1, ascent=%2, descent=%3") |
1085 | // .arg(charStyle.fontSize()).arg(charStyle.font().ascent()).arg(charStyle.font().descent())); |
||
8761 | avox | 1086 | |
8900 | cbradney | 1087 | if (SpecialChars::isExpandingSpace(hl->ch[0])) |
1088 | { |
||
8931 | cbradney | 1089 | double wordtracking = charStyle.wordTracking(); |
8900 | cbradney | 1090 | hl->glyph.xadvance *= wordtracking; |
1091 | wide *= wordtracking; |
||
1092 | } |
||
8761 | avox | 1093 | |
5408 | avox | 1094 | // find ascent / descent |
6144 | avox | 1095 | double hlcsize10=charStyle.fontSize() / 10.0; |
8629 | cbradney | 1096 | if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) |
5362 | avox | 1097 | { |
1098 | desc = desc2 = 0; |
||
1099 | } |
||
1100 | else |
||
1101 | { |
||
6144 | avox | 1102 | desc = desc2 = -charStyle.font().descent(hlcsize10); |
9047 | avox | 1103 | current.rememberShrinkStretch(hl->ch[0], wide, style); |
5362 | avox | 1104 | } |
6144 | avox | 1105 | asce = charStyle.font().ascent(hlcsize10); |
6366 | avox | 1106 | // wide = wide * hl->glyph.scaleH; |
5362 | avox | 1107 | } |
1108 | fBorder = false; |
||
5408 | avox | 1109 | // end of col reached? |
8095 | avox | 1110 | // qDebug(QString("eocol? %1 + %2 + %3 > %4 -- asce=%5").arg(current.yPos).arg(extra.Bottom).arg(lineCorr).arg(Height).arg(asce)); |
1111 | if (current.isEndOfCol()) |
||
5362 | avox | 1112 | { |
8095 | avox | 1113 | current.column++; |
1114 | if (current.column < Cols) |
||
5362 | avox | 1115 | { |
5408 | avox | 1116 | // start next col |
8095 | avox | 1117 | current.nextColumn(asce); |
5721 | avox | 1118 | if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) |
1119 | || ((a == firstInFrame()) && (BackBox == 0))) |
||
3614 | cbradney | 1120 | { |
7313 | avox | 1121 | if (chstr[0] != SpecialChars::PARSEP) |
5721 | avox | 1122 | DropCmode = style.hasDropCap(); |
3614 | cbradney | 1123 | else |
5362 | avox | 1124 | DropCmode = false; |
1125 | if (DropCmode) |
||
3614 | cbradney | 1126 | { |
8062 | avox | 1127 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
6144 | avox | 1128 | desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); |
3614 | cbradney | 1129 | else |
6805 | avox | 1130 | desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); |
3614 | cbradney | 1131 | } |
5362 | avox | 1132 | if (DropCmode) |
5721 | avox | 1133 | DropLines = style.dropCapLines(); |
3614 | cbradney | 1134 | } |
8062 | avox | 1135 | // qDebug(QString("layout: nextcol grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid)); |
1136 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
||
3614 | cbradney | 1137 | { |
5362 | avox | 1138 | double by = Ypos; |
1139 | if (OwnPage != -1) |
||
1140 | by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); |
||
8095 | avox | 1141 | int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); |
5362 | avox | 1142 | int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); |
8956 | avox | 1143 | // qDebug(QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by)); |
1144 | |||
8095 | avox | 1145 | current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; |
3614 | cbradney | 1146 | } |
5362 | avox | 1147 | } |
1148 | else |
||
1149 | { |
||
8095 | avox | 1150 | MaxChars = a; |
6144 | avox | 1151 | // qDebug(QString("no room A: %1").arg(a)); |
5362 | avox | 1152 | goto NoRoom; |
1153 | } |
||
1154 | } |
||
5408 | avox | 1155 | // ok, there's more room in col |
8095 | avox | 1156 | if (current.itemsInLine == 0) |
5362 | avox | 1157 | { |
8095 | avox | 1158 | // qDebug(QString("newline: '%1' %2 %3").arg(a).arg(current.yPos).arg(asce)); |
5408 | avox | 1159 | // start a new line |
5362 | avox | 1160 | double TopOffset = asce; |
1161 | double BotOffset = desc2; |
||
1162 | goNoRoom = false; |
||
8095 | avox | 1163 | if (current.startOfCol) |
5362 | avox | 1164 | { |
8956 | avox | 1165 | // qDebug(QString("current.startOfCol: %1 + %2 + %3 + 1 =%4").arg(asce).arg(extra.Top).arg(lineCorr).arg(asce + extra.Top + lineCorr + 1)); |
8095 | avox | 1166 | current.yPos = asce + extra.Top + lineCorr + 1; |
5408 | avox | 1167 | // if (((a > 0) && (itemText.at(a-1)->ch == QChar(13))) || ((a == 0) && (BackBox == 0))) |
8095 | avox | 1168 | // current.yPos += m_Doc->docParagraphStyles[hl->cab].gapBefore; |
5362 | avox | 1169 | } |
8062 | avox | 1170 | // qDebug(QString("layout: nextline grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid)); |
1171 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
||
5362 | avox | 1172 | { |
1173 | double by = Ypos; |
||
1174 | if (OwnPage != -1) |
||
1175 | by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); |
||
8095 | avox | 1176 | int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); |
5362 | avox | 1177 | int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); |
6144 | avox | 1178 | // qDebug(QString("useBaselIneGrid: %1 * %2 + %3 - %4").arg(ol2 / 10000.0).arg(m_Doc->typographicSettings.valueBaseGrid).arg(m_Doc->typographicSettings.offsetBaseGrid).arg(by)); |
8956 | avox | 1179 | // qDebug(QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by)); |
8095 | avox | 1180 | current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; |
5362 | avox | 1181 | } |
8814 | cbradney | 1182 | /* this causes different spacing for first line: |
8095 | avox | 1183 | if (current.yPos-TopOffset < 0.0) |
8814 | cbradney | 1184 | { |
1185 | qDebug(QString("current.yPos - Ascender < 0 (%1 - %2 < 0)").arg(current.yPos).arg(TopOffset)); |
||
1186 | current.yPos = TopOffset+1; |
||
1187 | } |
||
1188 | */ |
||
5408 | avox | 1189 | // find linelength: |
8095 | avox | 1190 | pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); |
1191 | pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); |
||
5408 | avox | 1192 | // increase pt1/pt2 until i-beam reaches end of line |
8095 | avox | 1193 | // qDebug(QString("linestart: %1 + %2 + %3 < %4").arg(current.xPos).arg(wide).arg(style.rightMargin()).arg(current.colRight)); |
1194 | double leftIndent = 0; |
||
8127 | avox | 1195 | double xStep = legacy? 1 : 0.125; |
9372 | fschmid | 1196 | while (!cl.contains(pf2.map(pt1)) || !cl.contains(pf2.map(pt2)) || current.isEndOfLine(wide + leftIndent + style.rightMargin())) |
5362 | avox | 1197 | { |
1198 | fBorder = true; |
||
8127 | avox | 1199 | current.xPos += xStep; |
8095 | avox | 1200 | if (current.isEndOfLine(wide + leftIndent + style.rightMargin())) |
3614 | cbradney | 1201 | { |
8097 | avox | 1202 | // 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)); |
5408 | avox | 1203 | // new line |
5362 | avox | 1204 | fBorder = false; |
8095 | avox | 1205 | current.xPos = current.colLeft; |
1206 | |||
1207 | leftIndent = style.leftMargin(); |
||
1208 | if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) |
||
1209 | leftIndent += style.firstIndent(); |
||
1210 | |||
1211 | if (current.startOfCol) |
||
3614 | cbradney | 1212 | { |
8956 | avox | 1213 | // qDebug(QString("startofcol adjust: y=%1->%2").arg(current.yPos).arg(current.yPos+1)); |
1214 | |||
8095 | avox | 1215 | current.yPos++; |
3614 | cbradney | 1216 | } |
5362 | avox | 1217 | else |
3614 | cbradney | 1218 | { |
8095 | avox | 1219 | current.yPos += style.lineSpacing(); |
8956 | avox | 1220 | // qDebug(QString("next line: y=%1").arg(current.yPos)); |
3614 | cbradney | 1221 | } |
8062 | avox | 1222 | // qDebug(QString("layout: next lower line grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid)); |
1223 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
||
3614 | cbradney | 1224 | { |
5362 | avox | 1225 | double by = Ypos; |
1226 | if (OwnPage != -1) |
||
1227 | by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); |
||
8095 | avox | 1228 | int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); |
5362 | avox | 1229 | int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); |
8956 | avox | 1230 | // qDebug(QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by)); |
8095 | avox | 1231 | current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; |
5362 | avox | 1232 | } |
8095 | avox | 1233 | if (current.isEndOfCol()) |
5362 | avox | 1234 | { |
1235 | fBorder = false; |
||
8095 | avox | 1236 | current.column++; |
1237 | if (current.column < Cols) |
||
3614 | cbradney | 1238 | { |
8095 | avox | 1239 | current.nextColumn(asce); |
5721 | avox | 1240 | if (((a > firstInFrame()) && (itemText.text(a-1) == SpecialChars::PARSEP)) || ((a == firstInFrame()) && (BackBox == 0))) |
3614 | cbradney | 1241 | { |
7313 | avox | 1242 | if (chstr[0] != SpecialChars::PARSEP) |
5721 | avox | 1243 | DropCmode = style.hasDropCap(); |
3614 | cbradney | 1244 | else |
5362 | avox | 1245 | DropCmode = false; |
1246 | if (DropCmode) |
||
1247 | { |
||
8062 | avox | 1248 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
6144 | avox | 1249 | desc2 = -charStyle.font().descent() * m_Doc->typographicSettings.valueBaseGrid * style.dropCapLines(); |
5362 | avox | 1250 | else |
6805 | avox | 1251 | desc2 = -charStyle.font().descent() * style.lineSpacing() * style.dropCapLines(); |
5362 | avox | 1252 | } |
1253 | if (DropCmode) |
||
5721 | avox | 1254 | DropLines = style.dropCapLines(); |
3614 | cbradney | 1255 | } |
8062 | avox | 1256 | // qDebug(QString("layout: nextcol2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid)); |
1257 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
||
3614 | cbradney | 1258 | { |
5362 | avox | 1259 | double by = Ypos; |
1260 | if (OwnPage != -1) |
||
1261 | by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); |
||
8095 | avox | 1262 | int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); |
5362 | avox | 1263 | int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); |
8956 | avox | 1264 | // qDebug(QString("baseline adjust: y=%1->%2").arg(current.yPos).arg(ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by)); |
8095 | avox | 1265 | current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; |
3614 | cbradney | 1266 | } |
1267 | } |
||
1268 | else |
||
5362 | avox | 1269 | { |
8095 | avox | 1270 | MaxChars = a; |
6144 | avox | 1271 | // qDebug(QString("no room B: %1").arg(a)); |
5362 | avox | 1272 | goto NoRoom; |
1273 | } |
||
3614 | cbradney | 1274 | } |
5362 | avox | 1275 | } |
8095 | avox | 1276 | pt1 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(current.yPos+BotOffset)); |
1277 | pt2 = QPoint(static_cast<int>(ceil(current.xPos)), static_cast<int>(ceil(current.yPos-TopOffset))); |
||
5362 | avox | 1278 | } |
5408 | avox | 1279 | |
5362 | avox | 1280 | if (((fBorder)) && (!AbsHasDrop)) |
8095 | avox | 1281 | current.xPos += extra.Left; |
5408 | avox | 1282 | // indent first line of par |
5362 | avox | 1283 | if (a > 0) |
1284 | { |
||
5721 | avox | 1285 | if (itemText.text(a-1) == SpecialChars::PARSEP) |
8095 | avox | 1286 | current.xPos += style.firstIndent(); |
5362 | avox | 1287 | } |
1288 | else |
||
1289 | { |
||
8814 | cbradney | 1290 | if (legacy) |
8095 | avox | 1291 | current.xPos += style.firstIndent(); |
3614 | cbradney | 1292 | } |
5408 | avox | 1293 | // add left margin |
5362 | avox | 1294 | if (!AbsHasDrop) |
8095 | avox | 1295 | current.xPos += style.leftMargin(); |
1296 | if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct) { |
||
1297 | current.xPos += opticalLeftMargin(itemText, current.line); |
||
5390 | avox | 1298 | } |
8956 | avox | 1299 | // qDebug(QString("store line: (%1,%2)").arg(current.xPos).arg(current.yPos)); |
8095 | avox | 1300 | current.line.x = current.xPos; |
1301 | current.line.y = current.yPos; |
||
5362 | avox | 1302 | fBorder = false; |
1303 | } |
||
6144 | avox | 1304 | else { |
1305 | // qDebug(QString("cont.' line: '%1'").arg(a)); |
||
1306 | } |
||
5408 | avox | 1307 | // right tab stuff |
7905 | avox | 1308 | if (tabs.active) |
5362 | avox | 1309 | { |
8633 | jghali | 1310 | if (((hl->ch[0] == '.') && (tabs.status == TabPOINT)) || ((hl->ch[0] == ',') && (tabs.status == TabCOMMA)) || (hl->ch[0] == SpecialChars::TAB)) |
5362 | avox | 1311 | { |
7905 | avox | 1312 | tabs.active = false; |
1313 | tabs.status = TabNONE; |
||
3614 | cbradney | 1314 | } |
1315 | } |
||
5408 | avox | 1316 | // tab positioning |
8629 | cbradney | 1317 | if (hl->ch[0] == SpecialChars::TAB) |
3614 | cbradney | 1318 | { |
5362 | avox | 1319 | wide = 1; |
7905 | avox | 1320 | if (tabs.active) |
1321 | tabs.active = false; |
||
1322 | else // ??? |
||
3614 | cbradney | 1323 | { |
8095 | avox | 1324 | tabs.xPos = current.xPos; |
5721 | avox | 1325 | tTabValues = style.tabValues(); |
5362 | avox | 1326 | if (tTabValues.isEmpty()) |
3614 | cbradney | 1327 | { |
8095 | avox | 1328 | if ((current.xPos - current.colLeft) != 0) |
3614 | cbradney | 1329 | { |
8095 | avox | 1330 | if (current.xPos == current.colLeft + ceil((current.xPos-current.colLeft) / m_Doc->toolSettings.dTabWidth) * m_Doc->toolSettings.dTabWidth) |
1331 | current.xPos += m_Doc->toolSettings.dTabWidth; |
||
5362 | avox | 1332 | else |
8095 | avox | 1333 | current.xPos = current.colLeft + ceil((current.xPos-current.colLeft) / m_Doc->toolSettings.dTabWidth) * m_Doc->toolSettings.dTabWidth; |
3614 | cbradney | 1334 | } |
5362 | avox | 1335 | else |
8095 | avox | 1336 | current.xPos = current.colLeft + m_Doc->toolSettings.dTabWidth; |
7905 | avox | 1337 | tabs.status = TabNONE; |
1338 | tabs.active = false; |
||
3614 | cbradney | 1339 | } |
5362 | avox | 1340 | else |
1341 | { |
||
8095 | avox | 1342 | double tCurX = current.xPos - current.colLeft; |
5362 | avox | 1343 | double oCurX = tCurX + wide; |
1344 | for (int yg = static_cast<int>(tTabValues.count()-1); yg > -1; yg--) |
||
1345 | { |
||
1346 | if (oCurX < tTabValues[yg].tabPosition) |
||
1347 | { |
||
7905 | avox | 1348 | tabs.status = static_cast<int>(tTabValues[yg].tabType); |
5362 | avox | 1349 | tCurX = tTabValues[yg].tabPosition; |
7905 | avox | 1350 | tabs.fillChar = tTabValues[yg].tabFillChar; |
5362 | avox | 1351 | } |
1352 | } |
||
7905 | avox | 1353 | tabs.active = (tabs.status != TabLEFT); |
5362 | avox | 1354 | if (tCurX == oCurX-wide) |
8095 | avox | 1355 | current.xPos = current.colLeft + ceil((current.xPos-current.colLeft) / m_Doc->toolSettings.dTabWidth) * m_Doc->toolSettings.dTabWidth; |
5362 | avox | 1356 | else |
8095 | avox | 1357 | current.xPos = current.colLeft + tCurX; |
7905 | avox | 1358 | |
1359 | // remember fill char |
||
7994 | avox | 1360 | // qDebug(QString("tab: %1 '%2'").arg(tCurX).arg(tabs.fillChar)); |
7905 | avox | 1361 | if (!tabs.fillChar.isNull()) { |
1362 | hl->glyph.grow(); |
||
1363 | GlyphLayout * tglyph = hl->glyph.more; |
||
1364 | tglyph->glyph = charStyle.font().char2CMap(tabs.fillChar); |
||
1365 | tglyph->yoffset = hl->glyph.yoffset; |
||
1366 | tglyph->scaleV = tglyph->scaleH = chs / charStyle.fontSize(); |
||
1367 | tglyph->xadvance = 0; |
||
1368 | } |
||
5362 | avox | 1369 | } |
8095 | avox | 1370 | hl->glyph.xadvance = current.xPos - tabs.xPos; |
1371 | // wide = current.xPos - RTabX; |
||
7905 | avox | 1372 | tabs.charIndex = a; |
3614 | cbradney | 1373 | } |
5362 | avox | 1374 | } |
1375 | |||
5408 | avox | 1376 | // remember y pos |
5362 | avox | 1377 | if (DropCmode) |
7313 | avox | 1378 | hl->glyph.yoffset -= charStyle.font().realCharHeight(chstr[0], chsd / 10.0) - charStyle.font().realCharAscent(chstr[0], chsd / 10.0); |
8095 | avox | 1379 | |
1380 | |||
8103 | avox | 1381 | // remember x pos |
1382 | double breakPos = current.xPos; |
||
8095 | avox | 1383 | |
7905 | avox | 1384 | if (!tabs.active) // normal case |
5362 | avox | 1385 | { |
8095 | avox | 1386 | current.xPos += wide+kernVal; |
5362 | avox | 1387 | } |
7905 | avox | 1388 | else if (tabs.active && tabs.status == TabCENTER) // center tab |
5362 | avox | 1389 | { |
8095 | avox | 1390 | current.xPos += (wide+kernVal) / 2; |
8562 | jghali | 1391 | current.xPos = qMax(current.xPos, current.colLeft); |
5362 | avox | 1392 | } |
7905 | avox | 1393 | else // other tabs.active |
5362 | avox | 1394 | { |
8562 | jghali | 1395 | current.xPos = qMax(current.xPos, current.colLeft); |
5362 | avox | 1396 | } |
7231 | avox | 1397 | |
8095 | avox | 1398 | |
7346 | avox | 1399 | //FIXME: asce / desc set correctly? |
8103 | avox | 1400 | if (legacy && |
8633 | jghali | 1401 | ((hl->ch[0] == '-' || (hl->effects() & ScStyle_HyphenationPossible)) && (current.hyphenCount < m_Doc->HyCount || m_Doc->HyCount == 0)) |
8103 | avox | 1402 | || hl->ch[0] == SpecialChars::SHYPHEN) |
5362 | avox | 1403 | { |
6934 | avox | 1404 | if (hl->effects() & ScStyle_HyphenationPossible || hl->ch[0] == SpecialChars::SHYPHEN) |
3614 | cbradney | 1405 | { |
9047 | avox | 1406 | 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)); |
1407 | 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))); |
||
3614 | cbradney | 1408 | } |
5362 | avox | 1409 | else |
3614 | cbradney | 1410 | { |
9047 | avox | 1411 | pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(current.yPos+desc)); |
1412 | pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); |
||
3614 | cbradney | 1413 | } |
5362 | avox | 1414 | } |
8177 | avox | 1415 | else if (!legacy && SpecialChars::isBreakingSpace(hl->ch[0])) |
8127 | avox | 1416 | { |
9047 | avox | 1417 | pt1 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(current.yPos+desc)); |
1418 | pt2 = QPoint(qRound(ceil(breakPos + extra.Right - current.maxShrink )), qRound(ceil(current.yPos-asce))); |
||
8127 | avox | 1419 | } |
8103 | avox | 1420 | else |
5362 | avox | 1421 | { |
9057 | fschmid | 1422 | pt1 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(current.yPos+desc)); |
1423 | pt2 = QPoint(qRound(ceil(current.xPos+extra.Right - current.maxShrink)), qRound(ceil(current.yPos-asce))); |
||
5362 | avox | 1424 | } |
8127 | avox | 1425 | |
5408 | avox | 1426 | // test if end of line reached |
9372 | fschmid | 1427 | if ((!cl.contains(pf2.map(pt1))) || (!cl.contains(pf2.map(pt2))) || (legacy && current.isEndOfLine(style.rightMargin()))) |
5362 | avox | 1428 | outs = true; |
8095 | avox | 1429 | if (current.isEndOfCol()) |
5362 | avox | 1430 | outs = true; |
8629 | cbradney | 1431 | if ((hl->ch[0] == SpecialChars::FRAMEBREAK) && (a < itemText.length()-1)) |
5362 | avox | 1432 | goNoRoom = true; |
8629 | cbradney | 1433 | if ((hl->ch[0] == SpecialChars::COLBREAK) && (Cols > 1)) |
5362 | avox | 1434 | goNextColumn = true; |
6144 | avox | 1435 | |
8103 | avox | 1436 | |
1437 | // remember possible break |
||
8629 | cbradney | 1438 | if ( (SpecialChars::isBreakingSpace(hl->ch[0]) || hl->ch[0] == SpecialChars::TAB) && !outs) |
8103 | avox | 1439 | { |
8177 | avox | 1440 | if ( a == firstInFrame() || !SpecialChars::isBreakingSpace(itemText.text(a-1)) ) |
8103 | avox | 1441 | { |
8127 | avox | 1442 | current.rememberBreak(a, breakPos); |
8103 | avox | 1443 | } |
1444 | } |
||
1445 | |||
1446 | |||
1447 | // hyphenation |
||
8633 | jghali | 1448 | if (((hl->effects() & ScStyle_HyphenationPossible) || (hl->ch[0] == '-') || hl->ch[0] == SpecialChars::SHYPHEN) && (!outs) && !itemText.text(a-1).isSpace() ) |
8103 | avox | 1449 | { |
1450 | breakPos = current.xPos; |
||
8633 | jghali | 1451 | if (hl->ch[0] != '-') |
8103 | avox | 1452 | { |
1453 | breakPos += charStyle.font().charWidth('-', charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0); |
||
1454 | } |
||
1455 | |||
1456 | double rightHang = 0; |
||
1457 | if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) { |
||
1458 | rightHang = 0.7 * charStyle.font().realCharWidth('-', (charStyle.fontSize() / 10.0) * (charStyle.scaleH() / 1000.0)); |
||
1459 | } |
||
1460 | |||
8127 | avox | 1461 | if (legacy || (breakPos - rightHang < current.colRight - style.rightMargin())) |
8103 | avox | 1462 | { |
1463 | if ((current.hyphenCount < m_Doc->HyCount) || (m_Doc->HyCount == 0) || hl->ch[0] == SpecialChars::SHYPHEN) |
||
1464 | { |
||
1465 | current.rememberBreak(a, breakPos); |
||
1466 | } |
||
1467 | } |
||
1468 | } |
||
1469 | |||
1470 | |||
1471 | ++current.itemsInLine; |
||
1472 | |||
7905 | avox | 1473 | if (tabs.active) |
5362 | avox | 1474 | { |
1475 | double cen = 1; |
||
7905 | avox | 1476 | if (tabs.status == TabCENTER) |
5362 | avox | 1477 | cen = 2; |
7231 | avox | 1478 | |
7905 | avox | 1479 | double newTabAdvance = itemText.item(tabs.charIndex)->glyph.xadvance - (wide+kernVal) / cen; |
7231 | avox | 1480 | |
1481 | if (newTabAdvance >= 0) { |
||
7905 | avox | 1482 | itemText.item(tabs.charIndex)->glyph.xadvance = newTabAdvance; |
7231 | avox | 1483 | } |
1484 | else { |
||
7905 | avox | 1485 | tabs.active = false; |
1486 | tabs.status = TabNONE; |
||
7231 | avox | 1487 | } |
5362 | avox | 1488 | } |
8103 | avox | 1489 | |
5362 | avox | 1490 | if (DropCmode) |
1491 | { |
||
1492 | DropCmode = false; |
||
1493 | AbsHasDrop = true; |
||
8095 | avox | 1494 | maxDY = current.yPos; |
1495 | current.xPos += style.dropCapOffset(); |
||
7287 | avox | 1496 | hl->glyph.xadvance += style.dropCapOffset(); |
8095 | avox | 1497 | // qDebug(QString("dropcapoffset: %1 -> %2").arg(current.xPos-style.dropCapOffset()).arg(current.xPos)); |
8562 | jghali | 1498 | current.xPos = qMax(current.xPos, current.colLeft); |
8095 | avox | 1499 | maxDX = current.xPos; |
8501 | cbradney | 1500 | Q3PointArray tcli(4); |
8062 | avox | 1501 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
5362 | avox | 1502 | { |
8095 | avox | 1503 | current.yPos -= m_Doc->typographicSettings.valueBaseGrid * (DropLines-1); |
5362 | avox | 1504 | double by = Ypos; |
1505 | if (OwnPage != -1) |
||
1506 | by = Ypos - m_Doc->Pages->at(OwnPage)->yOffset(); |
||
8095 | avox | 1507 | int ol1 = qRound((by + current.yPos - m_Doc->typographicSettings.offsetBaseGrid) * 10000.0); |
5362 | avox | 1508 | int ol2 = static_cast<int>(ol1 / m_Doc->typographicSettings.valueBaseGrid); |
8956 | avox | 1509 | // 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)); |
8095 | avox | 1510 | current.yPos = ceil( ol2 / 10000.0 ) * m_Doc->typographicSettings.valueBaseGrid + m_Doc->typographicSettings.offsetBaseGrid - by; |
1511 | //FIXME: use current.colLeft instead of xOffset? |
||
5691 | avox | 1512 | tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); |
5362 | avox | 1513 | tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*m_Doc->typographicSettings.valueBaseGrid))); |
1514 | } |
||
1515 | else |
||
1516 | { |
||
5721 | avox | 1517 | if (style.lineSpacingMode() == ParagraphStyle::FixedLineSpacing) |
3614 | cbradney | 1518 | { |
8095 | avox | 1519 | current.yPos -= style.lineSpacing() * (DropLines-1); |
8956 | avox | 1520 | // qDebug(QString("after dropcaps: y=%1").arg(current.yPos)); |
6805 | avox | 1521 | tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY - DropLines * style.lineSpacing()))); |
1522 | tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*style.lineSpacing()))); |
||
5362 | avox | 1523 | } |
1524 | else |
||
1525 | { |
||
6144 | avox | 1526 | double currasce = charStyle.font().height(style.charStyle().fontSize() / 10.0); |
8095 | avox | 1527 | current.yPos -= currasce * (DropLines-1); |
8956 | avox | 1528 | // qDebug(QString("after dropcaps: y=%1").arg(current.yPos)); |
5691 | avox | 1529 | tcli.setPoint(0, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY-DropLines*currasce))); |
5362 | avox | 1530 | tcli.setPoint(1, QPoint(qRound(maxDX), qRound(maxDY-DropLines*currasce))); |
1531 | } |
||
1532 | } |
||
1533 | tcli.setPoint(2, QPoint(qRound(maxDX), qRound(maxDY))); |
||
5691 | avox | 1534 | tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); |
9372 | fschmid | 1535 | cm = QRegion(pf2.map(tcli)); |
5362 | avox | 1536 | cl = cl.subtract(cm); |
8095 | avox | 1537 | // current.yPos = maxDY; |
5362 | avox | 1538 | } |
5408 | avox | 1539 | // end of line |
8177 | avox | 1540 | if ( SpecialChars::isBreak(hl->ch[0], Cols > 1) || (outs)) |
5362 | avox | 1541 | { |
7905 | avox | 1542 | tabs.active = false; |
1543 | tabs.status = TabNONE; |
||
8177 | avox | 1544 | if (SpecialChars::isBreak(hl->ch[0], Cols > 1)) |
5362 | avox | 1545 | { |
8095 | avox | 1546 | // find end of line |
1547 | current.breakLine(itemText, a); |
||
1548 | EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); |
||
1549 | current.finishLine(EndX); |
||
1550 | |||
9047 | avox | 1551 | // if (style.alignment() != 0) |
5362 | avox | 1552 | { |
8095 | avox | 1553 | if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) |
1554 | current.line.width += opticalRightMargin(itemText, current.line); |
||
1555 | |||
1556 | OFs = 0; |
||
5721 | avox | 1557 | if (style.alignment() == 2) |
8095 | avox | 1558 | OFs = current.line.width - current.line.naturalWidth; |
5721 | avox | 1559 | if (style.alignment() == 1) |
8095 | avox | 1560 | OFs = (current.line.width - current.line.naturalWidth) / 2; |
5721 | avox | 1561 | if (style.alignment() == 3) |
5362 | avox | 1562 | OFs = 0; |
8095 | avox | 1563 | |
7037 | avox | 1564 | if (style.alignment() == 4 |
1565 | || (style.alignment() == 3 |
||
8629 | cbradney | 1566 | && (hl->ch[0] == SpecialChars::LINEBREAK || |
1567 | hl->ch[0] == SpecialChars::FRAMEBREAK || |
||
1568 | hl->ch[0] == SpecialChars::COLBREAK) |
||
8095 | avox | 1569 | && !itemText.text(current.line.lastItem - 1).isSpace())) |
5362 | avox | 1570 | { |
8095 | avox | 1571 | justifyLine(itemText, current.line); |
3614 | cbradney | 1572 | } |
1573 | else |
||
1574 | { |
||
9047 | avox | 1575 | if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) |
1576 | current.line.naturalWidth += opticalRightMargin(itemText, current.line); |
||
1577 | double optiWidth = current.colRight - style.lineSpacing()/2.0 - current.line.x; |
||
1578 | if (current.line.naturalWidth > optiWidth) |
||
1579 | current.line.width = QMAX(current.line.width - current.maxShrink, optiWidth); |
||
5408 | avox | 1580 | // simple offset |
9047 | avox | 1581 | indentLine(itemText, current.line, OFs); |
3614 | cbradney | 1582 | } |
9047 | avox | 1583 | current.xPos = current.colRight; |
3614 | cbradney | 1584 | } |
5362 | avox | 1585 | } |
8845 | cbradney | 1586 | else // outs -- last char went outside the columns (or into flow-around shape) |
5362 | avox | 1587 | { |
8095 | avox | 1588 | if (current.breakIndex >= 0) // Hier koenen auch andere Trennungen eingebaut werden |
3614 | cbradney | 1589 | { |
5408 | avox | 1590 | // go back to last break position |
8095 | avox | 1591 | // qDebug(QString("new break pos a=%1 BuPos=%2 current.breakIndex=%3").arg(a).arg(BuPos).arg(current.breakIndex)); |
1592 | a = current.breakIndex; |
||
5980 | avox | 1593 | assert( a >= 0 ); |
1594 | assert( a < itemText.length() ); |
||
5721 | avox | 1595 | hl = itemText.item(a); |
6805 | avox | 1596 | style = itemText.paragraphStyle(a); |
8956 | avox | 1597 | if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) |
1598 | { |
||
1599 | style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); |
||
1600 | // qDebug(QString("auto linespacing: %1").arg(style.lineSpacing())); |
||
1601 | } |
||
8095 | avox | 1602 | current.itemsInLine = a - current.line.firstItem + 1; |
7887 | avox | 1603 | // qDebug(QString("style outs pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); |
6805 | avox | 1604 | // qDebug(QString("style <@%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) |
1605 | // .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()?style.parent()->name():"") |
||
5721 | avox | 1606 | // .arg(a)); |
7356 | avox | 1607 | |
1608 | if (hl->ch[0] == ' ') { |
||
1609 | hl->setEffects(hl->effects() | ScStyle_SuppressSpace); |
||
1610 | hl->glyph.xadvance = 0; |
||
1611 | } |
||
6144 | avox | 1612 | |
8095 | avox | 1613 | EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); |
1614 | current.finishLine(EndX); |
||
1615 | |||
1616 | //??? current.breakXPos = current.line.x; |
||
1617 | //??? for (int j=current.line.firstItem; j <= a; ++j) |
||
1618 | //??? current.breakXPos += itemText.item(j)->glyph.wide(); |
||
1619 | |||
6998 | avox | 1620 | if ((hl->effects() & ScStyle_HyphenationPossible) || hl->ch[0] == SpecialChars::SHYPHEN) |
3614 | cbradney | 1621 | { |
5362 | avox | 1622 | // insert hyphen |
8095 | avox | 1623 | current.hyphenCount++; |
5691 | avox | 1624 | hl->setEffects(hl->effects() | ScStyle_SmartHyphenVisible); |
8095 | avox | 1625 | hl->glyph.grow(); |
6144 | avox | 1626 | hl->glyph.more->glyph = charStyle.font().char2CMap(QChar('-')); |
1627 | hl->glyph.more->xadvance = charStyle.font().charWidth('-', itemText.charStyle(a).fontSize() / 10.0) * (itemText.charStyle(a).scaleH() / 1000.0); |
||
5362 | avox | 1628 | } |
5408 | avox | 1629 | else |
5362 | avox | 1630 | { |
8095 | avox | 1631 | if (hl->ch[0] != '-') |
1632 | current.hyphenCount = 0; |
||
5691 | avox | 1633 | hl->setEffects(hl->effects() & ~ScStyle_SmartHyphenVisible); |
8095 | avox | 1634 | hl->glyph.shrink(); |
5362 | avox | 1635 | } |
8095 | avox | 1636 | |
5408 | avox | 1637 | // Justification |
9047 | avox | 1638 | // if (style.alignment() != 0) |
5362 | avox | 1639 | { |
8095 | avox | 1640 | if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) |
1641 | current.line.width += opticalRightMargin(itemText, current.line); |
||
5408 | avox | 1642 | |
8095 | avox | 1643 | OFs = 0; |
6805 | avox | 1644 | if (style.alignment() == 2) |
8095 | avox | 1645 | OFs = current.line.width - current.line.naturalWidth; |
6805 | avox | 1646 | if (style.alignment() == 1) |
8095 | avox | 1647 | OFs = (current.line.width - current.line.naturalWidth) / 2; |
1648 | |||
6805 | avox | 1649 | if ((style.alignment() == 3) |
1650 | || (style.alignment() == 4)) |
||
5362 | avox | 1651 | { |
8095 | avox | 1652 | justifyLine(itemText, current.line); |
3614 | cbradney | 1653 | } |
5362 | avox | 1654 | else |
1655 | { |
||
9047 | avox | 1656 | if (opticalMargins & ParagraphStyle::OM_RightHangingPunct) |
1657 | current.line.naturalWidth += opticalRightMargin(itemText, current.line); |
||
1658 | indentLine(itemText, current.line, OFs); |
||
5362 | avox | 1659 | } |
9047 | avox | 1660 | // qDebug(QString("line: endx=%1 next pos=(%2,%3").arg(EndX).arg(current.line.x + current.line.width).arg(current.yPos)); |
8095 | avox | 1661 | current.xPos = current.line.x + current.line.width; |
3614 | cbradney | 1662 | } |
1663 | } |
||
8095 | avox | 1664 | else // no break position |
3614 | cbradney | 1665 | { |
8845 | cbradney | 1666 | if (a >= current.line.firstItem) |
8095 | avox | 1667 | { |
1668 | --a; |
||
1669 | --current.itemsInLine; |
||
8845 | cbradney | 1670 | } |
1671 | if (a >= 0) |
||
1672 | { |
||
8095 | avox | 1673 | hl = itemText.item(a); |
1674 | style = itemText.paragraphStyle(a); |
||
8956 | avox | 1675 | if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing) |
1676 | { |
||
1677 | style.setLineSpacing(style.charStyle().font().height(style.charStyle().fontSize() / 10.0)); |
||
1678 | // qDebug(QString("auto linespacing: %1").arg(style.lineSpacing())); |
||
1679 | } |
||
8095 | avox | 1680 | } |
1681 | current.breakLine(itemText, a); |
||
7887 | avox | 1682 | // qDebug(QString("style no break pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); |
6805 | avox | 1683 | // qDebug(QString("style nb @%6: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin()) |
7188 | avox | 1684 | // .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()) |
5778 | avox | 1685 | // .arg(a)); |
8095 | avox | 1686 | EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); |
1687 | current.finishLine(EndX); |
||
9492 | avox | 1688 | // qDebug(QString("no break pos: %1-%2 @ %3 wid %4 nat %5 endX %6") |
1689 | // .arg(current.line.firstItem).arg(current.line.firstItem) |
||
1690 | // .arg(current.line.x).arg(current.line.width).arg(current.line.naturalWidth).arg(EndX)); |
||
9047 | avox | 1691 | indentLine(itemText, current.line, 0); |
5362 | avox | 1692 | } |
1693 | } |
||
8177 | avox | 1694 | if ( outs || SpecialChars::isBreak(hl->ch[0], (Cols > 1)) ) |
5362 | avox | 1695 | { |
8845 | cbradney | 1696 | if (outs && !current.isEndOfLine(hl->glyph.wide() + style.rightMargin())) |
5362 | avox | 1697 | { |
8095 | avox | 1698 | if (( hl->ch[0] == SpecialChars::PARSEP || hl->ch[0] == SpecialChars::LINEBREAK) |
5362 | avox | 1699 | && AbsHasDrop) |
3614 | cbradney | 1700 | { |
5362 | avox | 1701 | AbsHasDrop = false; |
8095 | avox | 1702 | if (current.yPos < maxDY) |
1703 | current.yPos = maxDY; |
||
8956 | avox | 1704 | // qDebug(QString("after dropcaps: y=%1 maxDY=%2").arg(current.yPos).arg(maxDY)); |
3614 | cbradney | 1705 | } |
5362 | avox | 1706 | bool fromOut = true; |
8095 | avox | 1707 | double BotOffset = desc+extra.Bottom+lineCorr; |
1708 | // pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); |
||
1709 | // pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); |
||
1710 | while (!current.isEndOfLine(style.rightMargin())) |
||
3614 | cbradney | 1711 | { |
8095 | avox | 1712 | current.xPos++; |
1713 | if (current.isEndOfLine(style.rightMargin())) |
||
3614 | cbradney | 1714 | { |
5362 | avox | 1715 | fromOut = false; |
8062 | avox | 1716 | // qDebug(QString("layout: next lower2 grid=%1 x %2").arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing).arg(m_Doc->typographicSettings.valueBaseGrid)); |
8956 | avox | 1717 | // qDebug(QString("nextline: y=%1+%2").arg(current.yPos).arg(style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing? m_Doc->typographicSettings.valueBaseGrid : style.lineSpacing())); |
1718 | |||
8062 | avox | 1719 | if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing) |
8095 | avox | 1720 | current.yPos += m_Doc->typographicSettings.valueBaseGrid; |
5362 | avox | 1721 | else |
8095 | avox | 1722 | current.yPos += style.lineSpacing(); |
1723 | if (current.isEndOfCol(desc) && (current.column+1 == Cols)) |
||
5362 | avox | 1724 | { |
1725 | goNoRoom = true; |
||
6375 | avox | 1726 | // qDebug(QString("go no room 1: %1").arg(a)); |
5362 | avox | 1727 | break; |
1728 | } |
||
1729 | if (AbsHasDrop) |
||
1730 | { |
||
8095 | avox | 1731 | if ((current.yPos > maxDY) && (current.yPos - asce > maxDY)) |
5362 | avox | 1732 | { |
1733 | AbsHasDrop = false; |
||
8095 | avox | 1734 | current.xPos = current.colLeft; |
5362 | avox | 1735 | } |
1736 | else |
||
8095 | avox | 1737 | current.xPos = maxDX; |
5362 | avox | 1738 | } |
1739 | else |
||
8095 | avox | 1740 | current.xPos = current.colLeft; |
8177 | avox | 1741 | if (SpecialChars::isBreak(hl->ch[0])) |
5362 | avox | 1742 | { |
8629 | cbradney | 1743 | if (hl->ch[0] == SpecialChars::PARSEP) |
8956 | avox | 1744 | { |
1745 | // qDebug(QString("gap after: y=%1+%2").arg(current.yPos).arg(style.gapAfter())); |
||
8095 | avox | 1746 | current.yPos += style.gapAfter(); |
8956 | avox | 1747 | } |
8095 | avox | 1748 | current.hyphenCount = 0; |
5362 | avox | 1749 | } |
1750 | break; |
||
3614 | cbradney | 1751 | } |
8095 | avox | 1752 | pt1 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(current.yPos+BotOffset)); |
1753 | pt2 = QPoint(qRound(current.xPos+extra.Right), static_cast<int>(ceil(current.yPos-asce))); |
||
9372 | fschmid | 1754 | if (cl.contains(pf2.map(pt1)) && cl.contains(pf2.map(pt2))) |
5362 | avox | 1755 | break; |
8095 | avox | 1756 | // else |
1757 | // qDebug(QString("looking for start of line at %1,%2").arg(current.xPos).arg(current.yPos)); |
||
5362 | avox | 1758 | } |
1759 | if (fromOut) |
||
1760 | { |
||
8095 | avox | 1761 | if (current.isEndOfCol(desc) && (current.column+1 == Cols)) |
3614 | cbradney | 1762 | { |
5362 | avox | 1763 | goNoRoom = true; |
6375 | avox | 1764 | // qDebug(QString("go no room 2: %1").arg(a)); |
5362 | avox | 1765 | break; |
3614 | cbradney | 1766 | } |
8095 | avox | 1767 | current.xPos--; |
8562 | jghali | 1768 | current.xPos = qMax(current.xPos, current.colLeft); |
3614 | cbradney | 1769 | } |
1770 | } |
||
1771 | else |
||
1772 | { |
||
8629 | cbradney | 1773 | if (( hl->ch[0] == SpecialChars::PARSEP || hl->ch[0] == SpecialChars::LINEBREAK ) |
5362 | avox | 1774 | && AbsHasDrop) |
1775 | { |
||
1776 | AbsHasDrop = false; |
||