1 //
2 // C++ Implementation: fmlayout
3 //
4 // Description:
5 //
6 //
7 // Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12 #include "fmlayout.h"
13 #include "fontitem.h"
14 #include "shortcuts.h"
15 #include "fmlayoptwidget.h"
16 #include "typotek.h"
17 #include "textprogression.h"
18
19 #include <cstdlib>
20
21 #include <QDialog>
22 #include <QGridLayout>
23 #include <QString>
24 #include <QGraphicsScene>
25 #include <QGraphicsView>
26 #include <QGraphicsProxyWidget>
27 // #include <QProgressBar>
28 #include <QDebug>
29 #include <QApplication>
30 #include <QTime>
31 #include <QAction>
32 #include <QMenu>
33 // #include <QMutexLocker>
34 #include <QMutex>
35 // #include <QWaitCondition>
36 #include <QCoreApplication>
37 #include <QGraphicsObject>
38
39 #define OUT_OF_RECT 99999999.0
40
41 int fm_layout_total_nod_dbg;
42 int fm_layout_total_skip_nod_dbg;
43 int fm_layout_total_leaves_dbg;
44
ListItem()45 Node::ListItem::ListItem() :n ( 0 ), distance ( 0.0 )
46 {
47 // qDebug()<<"CV empty";
48 }
49
ListItem(Node * N,double D)50 Node::ListItem::ListItem ( Node * N, double D ) :n ( N ),distance ( D )
51 {
52 // qDebug()<<"CV n d"<<n->index<<distance;
53 }
54
~ListItem()55 Node::ListItem::~ListItem()
56 {
57 // qDebug()<<"~ListItem"<< n<<n->index;
58 if(n)
59 {
60 delete n;
61 n = 0;
62 }
63 }
64
Node(FMLayout * layoutEngine,int i)65 Node::Node (FMLayout * layoutEngine, int i )
66 :lyt(layoutEngine),
67 index ( i )
68 {
69 // if(index == 0)
70 // qDebug()<<"+N"<< this<<index << ++fm_layout_total_nod_dbg;
71 }
72
hasNode(int idx)73 bool Node::hasNode ( int idx )
74 {
75 for ( int i ( 0 ); i < nodes.count(); ++i )
76 {
77 if ( nodes[i]->n->index == idx )
78 return true;
79 }
80 return false;
81 }
82
nodes_clear()83 void Node::nodes_clear()
84 {
85 // if(index == 0)
86 // qDebug()<<"-C"<<this<< nodes.count();
87 while (!nodes.isEmpty())
88 delete nodes.takeFirst();
89 }
90
nodes_insert(ListItem * v)91 void Node::nodes_insert(ListItem * v)
92 {
93
94
95 if ( nodes.isEmpty() )
96 {
97 nodes.insert ( 0, v );
98 }
99 else
100 {
101 bool ist(false);
102 for ( int nI ( 0 );nI<nodes.count();++nI )
103 {
104 if ( v->distance <= nodes[nI]->distance )
105 {
106 nodes.insert ( nI,v );
107 ist = true;
108 break;
109 }
110 }
111 if(!ist)
112 nodes.append(v);
113 }
114 // qDebug()<<"+I"<<this <<v->n->index<<nodes.count();
115 }
116
~Node()117 Node::~Node()
118 {
119
120 // qDebug()<<"~N"<<this<< deepCount() << --fm_layout_total_nod_dbg;
121 nodes_clear();
122 }
123
deepCount()124 int Node::deepCount()
125 {
126 int c ( nodes.count() );
127 for ( int i ( 0 ); i < c ; ++i )
128 {
129 c += nodes[i]->n->deepCount();
130 }
131 return c;
132 }
133
sPath(double dist,QList<int> curList,QList<int> & theList,double & theScore)134 void Node::sPath ( double dist , QList< int > curList, QList< int > & theList, double & theScore )
135 {
136 // QList<int> debugL;
137 // foreach(ListItem v, nodes)
138 // {debugL << v.n->index;}
139 // qDebug()<<"Node::sPath(" <<dist<< ", "<<curList<<", "<<theList<<", "<<theScore<<")"<< "I L"<<index<<debugL;
140 int deep ( curList.count() + 1 );
141 // FMLayout* lyt ( FMLayout::getLayout() );
142 if ( lyt->stopIt )
143 {
144 theScore = 0;
145 }
146 // cIdx is first glyph of the line
147 int cIdx ( index );
148 // bIndex is the break which sits on cIdx
149 int bIndex ( lyt->breakList.indexOf ( cIdx ) );
150 bool wantPlus ( true );
151 while ( wantPlus )
152 {
153 ++bIndex;
154 if ( bIndex < lyt->breakList.count() )
155 {
156 // additive width of glyphs
157 double di ( lyt->distance ( cIdx, lyt->breakList[bIndex],lyt->theString ) );
158 if ( di >= lyt->lineWidth ( deep ) )
159 {
160 /// BEFORE
161 for ( int backIndex ( 1 ) ; ( bIndex - backIndex > 0 ) && ( lyt->breakList[bIndex - backIndex] != cIdx ); ++backIndex )
162 {
163 int soon ( lyt->breakList[bIndex - backIndex] );
164 double needWidth(lyt->distance ( cIdx, soon ,lyt->theString ));
165 double needWidthStripped(lyt->distance ( cIdx, soon ,lyt->theString , true ) );
166 double spaceWidth(needWidth - needWidthStripped);
167
168 double disN = needWidth - lyt->lineWidth ( deep ) ;
169
170 double compressValue( disN * 100.0 / spaceWidth );
171 // qDebug()<<"PRE spaceWidth("<<spaceWidth<<") disN("<<disN<<") compressValue("<<compressValue<<")";
172 if(compressValue > lyt->FM_LAYOUT_MAX_COMPRESSION)
173 {
174 break;
175 }
176 // else
177 // qDebug()<<"["<<cIdx<<","<<soon<<"]spaceWidth("<<spaceWidth<<") disN("<<disN<<") compressValue("<<compressValue<<")";
178
179
180 Node* sN = 0;
181 sN = new Node (lyt, soon );
182 if ( lyt->hyphenList.contains ( soon ) )
183 disN *= lyt->FM_LAYOUT_HYPHEN_PENALTY;
184
185 Node::ListItem* vN = new Node::ListItem( sN, qAbs ( disN * lyt->FM_LAYOUT_NODE_SOON_F ) );
186 nodes_insert(vN);
187 if ( QChar ( lyt->theString[soon].lChar ).category() == QChar::Separator_Space )
188 break;
189 }
190 /// AT CLOSEST BREAK (after)
191 {
192 int fit ( lyt->breakList[bIndex] );
193
194 double needWidth(lyt->distance ( cIdx, fit,lyt->theString ));
195 double needWidthStripped(lyt->distance ( cIdx, fit ,lyt->theString , true ) );
196 double spaceWidth(needWidth - needWidthStripped);
197
198 double disF = needWidth - lyt->lineWidth ( deep );
199
200 double compressValue( disF * 100.0 / spaceWidth );
201 if(compressValue <= lyt->FM_LAYOUT_MAX_COMPRESSION)
202 {
203 // qDebug()<<"["<<cIdx<<","<<fit<<"]("<< lyt->sepCount(cIdx, fit ,lyt->theString) <<") spaceWidth("<<spaceWidth<<") disF("<<disF<<") compressValue("<<compressValue<<")";
204
205 Node* sF = 0;
206 sF = new Node (lyt, fit );
207 if ( lyt->hyphenList.contains ( fit ) )
208 disF *= lyt->FM_LAYOUT_HYPHEN_PENALTY;
209
210 Node::ListItem* vF = new Node::ListItem ( sF,qAbs ( disF * lyt->FM_LAYOUT_NODE_FIT_F ) );
211 // curNode->nodes << vF;
212 nodes_insert ( vF );
213
214 }
215 }
216 /// AFTER
217 for ( int nextIndex ( 1 ); bIndex + nextIndex < lyt->breakList.count() ; ++nextIndex )
218 {
219 int late ( lyt->breakList[bIndex + nextIndex] );
220 double needWidth(lyt->distance ( cIdx, late ,lyt->theString ));
221 double needWidthStripped(lyt->distance ( cIdx, late ,lyt->theString , true ) );
222 double spaceWidth(needWidth - needWidthStripped);
223
224 double disL = needWidth - lyt->lineWidth ( deep );
225
226 double compressValue( disL * 100.0 / spaceWidth );
227 if(compressValue > lyt->FM_LAYOUT_MAX_COMPRESSION)
228 {
229 // qDebug()<<"break_ cV ="<<compressValue;
230 break;
231 }
232 // else
233 // qDebug()<<"["<<cIdx<<","<<late<<"]spaceWidth("<<spaceWidth<<") disL("<<disL<<") compressValue("<<compressValue<<")";
234
235 Node* sL = 0;
236 sL = new Node (lyt, late );
237 if ( lyt->hyphenList.contains ( late ) )
238 disL *= lyt->FM_LAYOUT_HYPHEN_PENALTY;
239
240 Node::ListItem* vL = new Node::ListItem ( sL, qAbs ( disL * lyt->FM_LAYOUT_NODE_LATE_F ) );
241 nodes_insert ( vL );
242
243 if ( late < lyt->theString.count() && QChar ( lyt->theString[late].lChar ).category() == QChar::Separator_Space )
244 break;
245 }
246
247 wantPlus = false;
248
249 }
250 else if ( lyt->lineWidth ( deep ) == OUT_OF_RECT )
251 {
252 wantPlus = false;
253 }
254 }
255 else // end of breaks list
256 {
257 // qDebug()<<"END OF BREAKS";
258 int soon ( lyt->breakList[bIndex - 1] );
259 if ( soon != cIdx && !hasNode ( soon ) )
260 {
261
262 Node* sN = 0;
263 sN = new Node (lyt, soon );
264 double disN = lyt->lineWidth ( deep ) - lyt->distance ( cIdx, soon,lyt->theString );
265
266 Node::ListItem* vN = new Node::ListItem ( sN, qAbs ( disN * lyt->FM_LAYOUT_NODE_END_F ) );
267 // curNode->nodes << vN;
268 nodes_insert ( vN );
269 }
270
271 wantPlus = false;
272 }
273 }
274
275 // qDebug()<<"N"<<nodes.count();
276 bool isLeaf ( nodes.isEmpty() );
277 curList << index ;//(isLeaf ? index-1 : index);
278
279 // double dCorrection ( ( double ) theList.count() / ( double ) curList.count() );
280 // dCorrection = 1.0;
281 // qDebug()<<"COR tl.c cl.c"<<dCorrection<<theList.count()<<curList.count();
282 while ( !nodes.isEmpty() )
283 {
284 // ListItem v = nodes.first() ;
285 double d1 ( dist + nodes[0]->distance / curList.count() /** dCorrection*/ );
286 double d2 ( theScore / qMax ( 1.0, ( double ) theList.count() ) );
287 if ( d1 < d2 )
288 {
289 nodes[0]->n->sPath ( dist + nodes[0]->distance, curList, theList, theScore );
290 }
291 else
292 ++fm_layout_total_skip_nod_dbg;
293 delete nodes.takeFirst();
294 // nodes.removeFirst();
295 }
296
297 if ( isLeaf )
298 {
299 double mDist ( dist / deep );
300 double mScore ( theScore / theList.count() );
301 // qDebug() <<"D S N"<< mDist << mScore << curList;
302 if ( mDist < mScore )
303 {
304 theScore = dist;
305 theList = curList;
306 }
307 ++fm_layout_total_leaves_dbg;
308 }
309 }
310
311 //FMLayout *FMLayout::instance = 0;
FMLayout(QGraphicsScene * scene,FontItem * font,QRectF rect)312 FMLayout::FMLayout ( QGraphicsScene * scene, FontItem * font , QRectF rect )
313 :theScene(scene),
314 theFont(font),
315 layoutIsFinished(true),
316 contextIsMainThread(true)
317 {
318 if(rect.isNull())
319 {
320 QRectF tmpRect = theScene->sceneRect();
321 double sUnitW ( tmpRect.width() * .1 );
322 double sUnitH ( tmpRect.height() * .1 );
323
324 theRect.setX ( 2.0 * sUnitW );
325 theRect.setY ( 1.0 * sUnitH );
326 theRect.setWidth ( 6.0 * sUnitW );
327 theRect.setHeight ( 8.0 * sUnitH );
328 }
329 else
330 theRect = rect;
331 rules = new QGraphicsRectItem;
332 node = 0;
333 // layoutMutex = new QMutex;
334 optionHasChanged = true;
335 persistentScene = false;
336
337 // progressBar = new QProgressBar ;
338 // onSceneProgressBar = new QGraphicsProxyWidget ;
339 // onSceneProgressBar->setWidget ( progressBar );
340 // onSceneProgressBar->setZValue ( 1000 );
341
342 // connect ( this, SIGNAL ( paragraphFinished() ), this, SLOT( endOfParagraph() ) );
343 // connect ( this, SIGNAL ( layoutFinished() ), this, SLOT ( doDraw() ) );
344 // connect ( this, SIGNAL ( paintFinished() ), this, SLOT ( endOfRun() ) );
345
346 FM_LAYOUT_NODE_SOON_F= 1200.0;
347 FM_LAYOUT_NODE_FIT_F= 1000.0;
348 FM_LAYOUT_NODE_LATE_F= 2000.0;
349 FM_LAYOUT_NODE_END_F= 2500.0;
350 FM_LAYOUT_HYPHEN_PENALTY = 1.5;
351 FM_LAYOUT_MAX_COMPRESSION = 50.0; // 50%
352
353 optionDialog = new QWidget;
354 // optionDialog->setWindowTitle ( tr ( "Text engine options" ) );
355 optionLayout = new QGridLayout(optionDialog) ;
356
357 optionsWidget = new FMLayOptWidget;
358 optionsWidget->setRange ( FMLayOptWidget::BEFORE, 1, 10000 );
359 optionsWidget->setRange ( FMLayOptWidget::EXACT, 1, 10000 );
360 optionsWidget->setRange ( FMLayOptWidget::AFTER, 1, 10000 );
361 optionsWidget->setRange ( FMLayOptWidget::END, 1, 10000 );
362 optionsWidget->setRange ( FMLayOptWidget::HYPHEN, 1, 100 );
363 optionsWidget->setRange ( FMLayOptWidget::SPACE, 1, 100 );
364
365 optionsWidget->setValue ( FMLayOptWidget::BEFORE,FM_LAYOUT_NODE_SOON_F );
366 optionsWidget->setValue ( FMLayOptWidget::EXACT,FM_LAYOUT_NODE_FIT_F );
367 optionsWidget->setValue ( FMLayOptWidget::AFTER,FM_LAYOUT_NODE_LATE_F );
368 optionsWidget->setValue ( FMLayOptWidget::END,FM_LAYOUT_NODE_END_F );
369 optionsWidget->setValue ( FMLayOptWidget::HYPHEN,FM_LAYOUT_HYPHEN_PENALTY * 10 );
370 optionsWidget->setValue ( FMLayOptWidget::SPACE,FM_LAYOUT_MAX_COMPRESSION );
371
372 optionLayout->addWidget(optionsWidget,0,0);
373
374 // connect ( optionsWidget,SIGNAL ( valueChanged ( int ) ),this,SLOT ( slotOption ( int ) ) );
375 connect(this, SIGNAL(objectWanted(QObject*)), typotek::getInstance(), SLOT(pushObject(QObject*)));
376
377 }
378
~FMLayout()379 FMLayout::~ FMLayout()
380 {
381 if(optionDialog)
382 delete optionDialog;
383 }
384
385 //FMLayout * FMLayout::getLayout()
386 //{
387 // if(!instance)
388 // {
389 // instance = new FMLayout;
390 // Q_ASSERT(instance);
391 // }
392 // return instance;
393 //}
394
run()395 void FMLayout::run()
396 {
397 // if(justRedraw)
398 // doDraw();
399 // else
400 {
401 for ( int i ( 0 ); i < paragraphs.count() ; ++ i )
402 {
403 // qDebug()<<"Oy Rb"<<origine.y()<<theRect.bottom();
404 if ( origine.y() > theRect.bottom() )
405 break;
406 theString = paragraphs[i];
407 if ( theString.isEmpty() )
408 continue;
409 // node = new Node ( 0 );
410 doGraph();
411 clearCaches();
412 {
413 // Debug output
414 fm_layout_total_leaves_dbg = 0;
415 fm_layout_total_nod_dbg = 0;
416 fm_layout_total_skip_nod_dbg = 0;
417 }
418
419 doLines();
420
421 // qDebug() <<"NODES LEAVES SKIP"<<fm_layout_total_nod_dbg<<fm_layout_total_leaves_dbg<<fm_layout_total_skip_nod_dbg;
422 // if ( node )
423 // {
424 // delete node;
425 // node = 0;
426 // }
427 clearCaches();
428 breakList.clear();
429 hyphenList.clear();
430 // emit paragraphFinished ( i + 1 );
431 emit paragraphFinished();
432
433 }
434 doDraw();
435 }
436 qDebug()<<"\tLayout Finished";
437 }
438
doLayout(const QList<GlyphList> & spec,double fs,FontItem * font)439 void FMLayout::doLayout ( const QList<GlyphList> & spec , double fs, FontItem* font)
440 {
441 qDebug()<<"FMLayout::doLayout"<<thread();
442 if(font)
443 theFont = font;
444 stopIt = false;
445 layoutIsFinished = false;
446
447 TextProgression *tp = TextProgression::getInstance();
448
449 if ( tp->inLine() == TextProgression::INLINE_LTR )
450 origine.rx() = theRect.left() ;
451 else if ( tp->inLine() == TextProgression::INLINE_RTL )
452 origine.rx() = theRect.right() ;
453 else if ( tp->inLine() == TextProgression::INLINE_BTT )
454 origine.ry() = theRect.bottom();
455 else if ( tp->inLine() == TextProgression::INLINE_TTB )
456 origine.ry() = theRect.top();
457
458 if ( tp->inBlock() == TextProgression::BLOCK_TTB )
459 origine.ry() = theRect.top();
460 else if ( tp->inBlock() == TextProgression::BLOCK_RTL )
461 origine.rx() = theRect.right();
462 else if ( tp->inBlock() == TextProgression::BLOCK_LTR )
463 origine.rx() = theRect.left();
464
465 // qDebug()<<"LO"<<lastOrigine<<"O"<<origine<<"options"<<optionHasChanged;
466 // if( !optionHasChanged && origine == lastOrigine && fontSize == fs && paragraphs == spec )
467 // {
468 // justRedraw = true;
469 // // typotek::getInstance()->startProgressJob( lines.count() );
470 // // qDebug()<<"LAYOUT O : lines "<<lines.count();
471 // }
472 // else
473 {
474 // qDebug()<<"LAYOUT 1";
475 justRedraw = false;
476 lines.clear();
477 // typotek::getInstance()->startProgressJob( paragraphs.count() + ( theRect.height() / fs*1.20 ) );// layout AND draw
478 }
479 lastOrigine = origine;
480 fontSize = fs;
481 paragraphs = spec;
482 optionHasChanged = false;
483
484 run();
485 layoutIsFinished = true;
486 emit layoutFinished();
487 qDebug()<< "FMLayout::doLayout return" << justRedraw;
488 }
489
endOfRun()490 void FMLayout::endOfRun()
491 {
492 // qDebug() <<"FMLayout::endOfRun()";
493 // theScene->removeItem ( onSceneProgressBar );
494 // disconnect ( this,SIGNAL ( paragraphFinished ( int ) ),progressBar,SLOT ( setValue ( int ) ) );
495 // if ( node )
496 // {
497 // delete node;
498 // node = 0;
499 // }
500 // qDebug()<<"EOR A"<<lines.count();
501 // layoutMutex->unlock();
502 if ( stopIt ) // We’re here after a interruption
503 {
504 stopIt = false;
505 // typotek::getInstance()->endProgressJob();
506 emit updateLayout();
507 }
508 // else
509 // typotek::getInstance()->endProgressJob();
510
511 // qDebug()<<"EOR B"<<lines.count();
512 }
513
stopLayout()514 void FMLayout::stopLayout()
515 {
516 stopIt = true;
517 emit clearScene();
518 }
519
doGraph()520 void FMLayout::doGraph() // Has became doBreaks
521 {
522 // qDebug() <<"FMLayout::doGraph()";
523 QTime t;
524 t.start();
525 /**
526 I hit a power issue with my graph thing as in its initial state.
527 So, I’ll try now to cut the tree as it’s built, not far than what’s done in chess programs.
528
529 */
530 // At first we’ll provide a very simple implementation to test things out
531
532 // A) where can we break?
533 breakList.clear();
534 hyphenList.clear();
535
536 for ( int a ( 0 ) ; a < theString.count() ; ++a )
537 {
538 if ( QChar ( theString[a].lChar ).category() == QChar::Separator_Space )
539 breakList << a+1;
540 if ( theString[a].isBreak )
541 {
542 breakList << a+1;
543 hyphenList << a+1;
544 }
545 }
546 breakList << theString.count();
547 // qDebug() <<"BREAKS"<<breakList.count();
548 // qDebug() <<"HYPHENS"<<hyphenList.count();
549 // qDebug() <<"doGraph T(ms)"<<t.elapsed();
550 }
551
doLines()552 void FMLayout::doLines()
553 {
554 // qDebug() <<"FMLayout::doLines()";
555 QTime t;
556 t.start();
557 // Run through the graph and find the shortest path
558 indices.clear();
559 double score ( INFINITE );
560 Node locNode(this, 0);
561 locNode.sPath ( 0,QList<int>(),indices,score );
562 // qDebug()<<"================================";
563 // qDebug()<< &locNode << locNode.nodes.count() << locNode.deepCount();
564 // qDebug()<<"================================";
565
566
567 clearCaches();
568 // la messe est dite ! :-)
569 // qDebug() <<"S I"<<score<<indices;
570
571 int startLine ( lines.count() );
572
573 int maxIndex ( indices.count() - 1 );
574 // qDebug()<<"SC IC"<<theString.count()<<indices.count();
575 bool hasHyph ( false );
576 GlyphList curHyph;
577
578 if(theString.isEmpty())
579 return;
580
581 for ( int lIdx ( 0 ); lIdx < maxIndex ; ++lIdx )
582 {
583 if ( stopIt || ((adjustedSampleInter * (lines.count() + 1)) > theRect.height()))
584 break;
585 int start1 ( /*!lIdx ?*/ indices[lIdx] /*: indices[lIdx] + 1*/ );
586 int end1 ( indices[ lIdx + 1 ] );
587
588 GlyphList inList ( theString.mid ( start1 , end1 - start1 /*+ 1 */ ) );
589
590 if(inList.isEmpty())
591 continue;
592 if ( QChar ( inList.first().lChar ).category() == QChar::Separator_Space )
593 {
594 while ( (!inList.isEmpty()) && (QChar ( inList.first().lChar ).category() == QChar::Separator_Space) )
595 inList.takeFirst();
596 }
597 if(inList.isEmpty())
598 continue;
599 if ( QChar ( inList.last().lChar ).category() == QChar::Separator_Space )
600 {
601 while ((!inList.isEmpty()) && ( QChar ( inList.last().lChar ).category() == QChar::Separator_Space ) )
602 inList.takeLast();
603 }
604
605
606 QString dStr;
607 QString dBk;
608 foreach ( RenderedGlyph rg, inList )
609 {
610 dStr += QChar ( rg.lChar );
611 dBk += rg.isBreak ? "#" : "_";
612 }
613 // qDebug() << "S"<<dStr;
614 // qDebug() << "H"<<dBk;
615
616 // qDebug()<<"S E Sib Eib"<<start<<end<<theString.at(start).isBreak<<theString.at(end).isBreak;
617
618 GlyphList lg;
619 /// * *
620 if ( !hasHyph && !inList.last().isBreak )
621 {
622 // qDebug() <<"/// * *";
623 lg = inList;
624 }
625 /// = *
626 else if ( hasHyph && !inList.last().isBreak )
627 {
628 // qDebug() <<"/// = *";
629
630 GlyphList hr ( curHyph );
631 hasHyph = false;
632
633 for ( int ih ( 0 ); ih < hr.count(); ++ih )
634 {
635 lg << hr[ih];
636 }
637
638 while ( !inList.isEmpty() && QChar ( inList.first() .lChar ).category() != QChar::Separator_Space )
639 {
640 inList.takeFirst();
641 }
642
643 if(!inList.isEmpty())
644 {
645 for ( int i ( 0 ); i < inList.count() ;++i )
646 lg << inList.at ( i );
647 }
648
649
650 }
651 /// * =
652 else if ( !hasHyph && inList.last().isBreak )
653 {
654 // qDebug() <<"/// * =";
655 GlyphList hr ( inList.last().hyphen.first );
656 hasHyph = true;
657 curHyph = inList.last().hyphen.second;
658
659 do
660 {
661 inList.takeLast();
662 }
663 while ( !inList.isEmpty() && QChar ( inList.last().lChar ).category() != QChar::Separator_Space );
664
665
666 if(!inList.isEmpty())
667 {
668 for ( int i ( 0 ); i < inList.count() ;++i )
669 lg << inList.at ( i );
670 }
671
672 QString dgS;
673 for ( int ih ( 0 ); ih < hr.count(); ++ih )
674 {
675 lg << hr[ih];
676 dgS +="("+ QString ( QChar ( lg.last().lChar ) ) +")";
677 }
678 QString dbh;for ( int h ( 0 );h<curHyph.count();++h ) {dbh+="["+ QString ( QChar ( curHyph[h].lChar ) ) +"]";}
679 // qDebug() <<dgS<<"="<<dbh;
680
681 }
682 /// = =
683 else if ( hasHyph && inList.last().isBreak )
684 {
685
686 // qDebug() <<"/// = =";
687 GlyphList hr ( curHyph );
688 GlyphList hr2 ( inList.last().hyphen.first );
689
690 hasHyph = true;
691 curHyph = inList.last().hyphen.second;
692
693 for ( int ih ( 0 ); ih < hr.count(); ++ih )
694 {
695 lg << hr[ih];
696 }
697
698 while ( !inList.isEmpty() && QChar ( inList.first() .lChar ).category() != QChar::Separator_Space )
699 {
700 inList.takeFirst();
701 }
702
703 if(!inList.isEmpty())
704 {
705 do
706 {
707 inList.takeLast();
708 }
709 while ( !inList.isEmpty() && QChar ( inList.last().lChar ).category() != QChar::Separator_Space );
710 }
711
712 QString dgS;
713 if(!inList.isEmpty())
714 {
715 for ( int i ( 0 ); i < inList.count() ;++i )
716 lg << inList.at ( i );
717 }
718
719 for ( int ih ( 0 ); ih < hr2.count(); ++ih )
720 {
721 lg << hr2[ih];
722 dgS +="("+ QString ( QChar ( lg.last().lChar ) ) +")";
723 }
724
725 QString dbh;for ( int h ( 0 );h<curHyph.count();++h ) {dbh+="["+ QString ( QChar ( curHyph[h].lChar ) ) +"]";}
726 // qDebug() <<dgS<<"="<<dbh;
727
728 }
729
730 lines << lg;
731 }
732
733 TextProgression *tp = TextProgression::getInstance();
734 bool verticalLayout ( tp->inBlock() == TextProgression::INLINE_BTT || tp->inBlock() == TextProgression::INLINE_TTB );
735
736 // qDebug()<<"lines finished";
737 for ( int lI ( startLine ); lI<lines.count(); ++lI )
738 {
739 if ( stopIt )
740 break;
741
742 GlyphList& lg ( lines[lI] );
743
744 if ( QChar ( lg.first().lChar ).category() == QChar::Separator_Space )
745 {
746 while ( QChar ( lg.first().lChar ).category() == QChar::Separator_Space && !lg.isEmpty() )
747 lg.takeFirst();
748 }
749 if ( QChar ( lg.last().lChar ).category() == QChar::Separator_Space )
750 {
751 while ( QChar ( lg.last().lChar ).category() == QChar::Separator_Space && !lg.isEmpty() )
752 lg.takeLast();
753 }
754
755 clearCaches();
756 double refW ( lineWidth( lI ) );
757 double actualW( distance ( 0, lg.count(), lg ) );
758 double diff ( refW - actualW );
759 if(!deviceIndy)
760 {
761 // qDebug()<< "R1 A1"<<refW<<actualW;
762 refW = refW * 72.0 / typotek::getInstance()->getDpiX() ;
763 actualW = actualW * 72.0 / typotek::getInstance()->getDpiX();
764 // qDebug()<< "R2 A2"<<refW<<actualW;
765 diff = refW - actualW ;
766
767 }
768
769 if ( lI != lines.count() - 1 || actualW > refW ) // not last line or last line is too long
770 {
771 QList<int> wsIds;
772 // qDebug()<< "Ref Dis"<< refW << distance ( 0, lg.count(), lg );
773 for ( int ri ( 0 ); ri < lg.count() ; ++ri )
774 {
775 if ( lg.at ( ri ).glyph && QChar ( lg.at ( ri ).lChar ).category() == QChar::Separator_Space )
776 {
777 wsIds << ri;
778 }
779 }
780 double shareLost ( diff / qMax ( 1.0 , ( double ) wsIds.count() ) );
781 // if(!oldIndy)
782 // shareLost *= typotek::getInstance()->getDpiX() / 72.0;
783 // qDebug() << "D N W"<<diff<<wsIds.count() << shareLost ;
784 // qDebug()<<"R D F"<< refW << actualW << actualW + ((double)wsIds.count() * shareLost);
785 if ( verticalLayout )
786 {
787 for ( int wi ( 0 ); wi < wsIds.count(); ++wi )
788 {
789 lg[ wsIds[wi] ].yadvance += shareLost;
790 }
791 }
792 else
793 {
794 for ( int wi ( 0 ); wi < wsIds.count(); ++wi )
795 {
796 lg[ wsIds[wi] ].xadvance += shareLost;
797 }
798 }
799 }
800 }
801 // qDebug() <<"doneLines:"<< lines.count() ;
802
803 }
804
doDraw()805 void FMLayout::doDraw()
806 {
807 // Ask paths or pixmaps to theFont for each glyph and draw it on theScene
808 // qDebug() <<"FMLayout::doDraw()";
809 resetScene();
810 QTime t;
811 t.start();
812 drawnLines = 0;
813 TextProgression *tp = TextProgression::getInstance();
814 QPointF pen ( origine );
815 if( tp->inLine() != TextProgression::INLINE_BTT )
816 pen.ry() += adjustedSampleInter;
817 if( tp->inBlock() == TextProgression::BLOCK_RTL )
818 pen.rx() -= adjustedSampleInter;
819
820 double pageTop(theRect.top());
821 double pageRight(theRect.right());
822 double pageBottom ( theRect.bottom() );
823 double pageLeft(theRect.left());
824
825 double scale = fontSize / theFont->getUnitPerEm();
826 double pixelAdjustX = typotek::getInstance()->getDpiX() / 72.0 ;
827 double pixelAdjustY = typotek::getInstance()->getDpiY() / 72.0 ;
828
829 int pd =0;
830
831 for ( int lIdx ( 0 ); lIdx < lines.count() ; ++lIdx )
832 {
833 if ( stopIt )
834 break;
835 if ( tp->inLine() != TextProgression::INLINE_BTT && pen.y() > pageBottom )
836 break;
837 else if(tp->inLine() == TextProgression::INLINE_BTT || tp->inLine() == TextProgression::INLINE_TTB)
838 {
839 if(tp->inBlock() == TextProgression::BLOCK_RTL && pen.x() < pageLeft)
840 break;
841 else if(tp->inBlock() == TextProgression::BLOCK_LTR && pen.x() > pageRight)
842 break;
843 }
844 ++drawnLines;
845 clearCaches();
846 GlyphList refGlyph ( lines[lIdx] );
847 // emit drawBaselineForMe(pen.y());
848 if ( !deviceIndy )
849 {
850 for ( int i=0; i < refGlyph.count(); ++i )
851 {
852 if ( !refGlyph[i].glyph )
853 continue;
854 QGraphicsItem *glyph;
855 if(contextIsMainThread)
856 glyph = theFont->itemFromGindexPix ( refGlyph[i].glyph , fontSize );
857 else
858 glyph = theFont->itemFromGindexPix_mt( refGlyph[i].glyph , fontSize );
859 if ( !glyph )
860 continue;
861 if ( tp->inLine() == TextProgression::INLINE_RTL )
862 {
863 pen.rx() -= refGlyph[i].xadvance * pixelAdjustX ;
864 }
865 else if ( tp->inLine() == TextProgression::INLINE_BTT )
866 {
867 pen.ry() -= refGlyph[i].yadvance * pixelAdjustY;
868 }
869
870 /*************************************************/
871 if(contextIsMainThread)
872 {
873 pixList << reinterpret_cast<QGraphicsPixmapItem*>(glyph);
874 theScene->addItem ( glyph );
875 glyph->setZValue ( 100.0 );
876 glyph->setPos ( pen.x()
877 + ( refGlyph[i].xoffset * pixelAdjustX )
878 + glyph->data (GLYPH_DATA_BITMAPLEFT).toDouble() * scale ,
879 pen.y()
880 + ( refGlyph[i].yoffset * pixelAdjustY )
881 - glyph->data(GLYPH_DATA_BITMAPTOP).toDouble());
882 }
883 else
884 {
885 // refGlyph[i].dump();
886 MetaGlyphItem * mgi(reinterpret_cast<MetaGlyphItem*>(glyph));
887 // qDebug()<<refGlyph[i].glyph<<pen.y() << ( refGlyph[i].yoffset * pixelAdjustY ) << mgi->metaData ( GLYPH_DATA_BITMAPTOP ).toDouble();
888 ++pd;
889 emit drawPixmapForMe(refGlyph[i].glyph,
890 fontSize,
891 pen.x()
892 + (refGlyph[i].xoffset * pixelAdjustX)
893 + mgi->metaData(GLYPH_DATA_BITMAPLEFT).toDouble() * scale,
894 pen.y()
895 + (refGlyph[i].yoffset * pixelAdjustY)
896 - mgi->metaData(GLYPH_DATA_BITMAPTOP).toDouble());
897 }
898 /*************************************************/
899
900 if ( tp->inLine() == TextProgression::INLINE_LTR )
901 pen.rx() += refGlyph[i].xadvance * pixelAdjustX ;
902 else if ( tp->inLine() == TextProgression::INLINE_TTB )
903 pen.ry() += refGlyph[i].yadvance * pixelAdjustY ;
904 }
905 }
906 else
907 {
908 for ( int i=0; i < refGlyph.count(); ++i )
909 {
910 if ( !refGlyph[i].glyph )
911 continue;
912 QGraphicsPathItem *glyph = theFont->itemFromGindex ( refGlyph[i].glyph , fontSize );
913
914 if ( tp->inLine() == TextProgression::INLINE_RTL )
915 {
916 pen.rx() -= refGlyph[i].xadvance ;
917 }
918 else if ( tp->inLine() == TextProgression::INLINE_BTT )
919 {
920 pen.ry() -= refGlyph[i].yadvance ;
921 }
922 /**********************************************/
923 glyphList << glyph;
924 theScene->addItem ( glyph );
925 glyph->setPen(Qt::NoPen);
926 #ifdef BUILD_TYPE_DEBUG
927 // visual debug
928 // QColor dbgColor( i * 255 / refGlyph.count() , i * 255 / refGlyph.count() , 0, 125);
929 // glyph->setBrush(dbgColor);
930 if(refGlyph[i].lChar == 32) glyph->setBrush(Qt::blue);
931 //end visual debug
932 #endif
933 glyph->setPos ( pen.x() + ( refGlyph[i].xoffset ),
934 pen.y() + ( refGlyph[i].yoffset ) );
935 glyph->setZValue ( 100.0 );
936 /*******************************************/
937
938 if ( tp->inLine() == TextProgression::INLINE_LTR )
939 pen.rx() += refGlyph[i].xadvance ;
940 else if ( tp->inLine() == TextProgression::INLINE_TTB )
941 pen.ry() += refGlyph[i].yadvance;
942
943 }
944 }
945
946 if ( tp->inBlock() == TextProgression::BLOCK_TTB )
947 {
948 pen.ry() += adjustedSampleInter;
949 pen.rx() = origine.x() ;
950 }
951 else if ( tp->inBlock() == TextProgression::BLOCK_RTL )
952 {
953 if(tp->inLine() == TextProgression::INLINE_TTB)
954 pen.ry() = origine.y() + adjustedSampleInter;
955 else
956 pen.ry() = origine.y();
957 pen.rx() -= adjustedSampleInter;
958 }
959 else if ( tp->inBlock() == TextProgression::BLOCK_LTR )
960 {
961 if(tp->inLine() == TextProgression::INLINE_TTB)
962 pen.ry() = origine.y() + adjustedSampleInter;
963 else
964 pen.ry() = origine.y();
965 pen.rx() += adjustedSampleInter;
966 }
967
968 // typotek::getInstance()->runProgressJob();
969 // qDebug() <<"P"<<pen;
970 }
971 //
972 // qDebug() <<"doDraw T(ms)"<<t.elapsed();
973 emit paintFinished();
974 emit drawPixmapForMe(-1,0,0,0);
975 qDebug()<<"P emitted:"<<pd;
976 }
977
sepCount(int start,int end,const GlyphList & gl)978 int FMLayout::sepCount(int start, int end, const GlyphList & gl)
979 {
980 if ( sepCache.contains ( start ) )
981 {
982 if ( sepCache[start].contains ( end ) )
983 return sepCache[start][end];
984 }
985 int storeStart(start);
986 int storeEnd(end);
987
988 GlyphList gList = gl;
989 if ( QChar ( gList.first().lChar ).category() == QChar::Separator_Space )
990 {
991 while ( QChar ( gList.first().lChar ).category() == QChar::Separator_Space && start < end )
992 {
993 ++start;
994 }
995 }
996 if ( QChar ( gList.last().lChar ).category() == QChar::Separator_Space )
997 {
998 while ( QChar ( gList.last().lChar ).category() == QChar::Separator_Space && end > start )
999 {
1000 --end;
1001 }
1002 }
1003 int ret(0);
1004 for ( int i ( start ); i < end ;++i )
1005 {
1006 if(QChar ( gList.at( i ).lChar ).category() == QChar::Separator_Space )
1007 ++ret;
1008 }
1009 sepCache[storeStart][storeEnd] = ret;
1010 return ret;
1011 }
1012
1013 // please move this method to GlyphList itself
distance(int start,int end,const GlyphList & gl,bool strip)1014 double FMLayout::distance ( int start, int end, const GlyphList& gl, bool strip )
1015 {
1016 // qDebug()<<"distance(start ="<<start<<",end"<<end<<",strip"<<strip<<" )";
1017 if(!strip)
1018 {
1019 if ( distCache.contains ( start ) )
1020 {
1021 if ( distCache[start].contains ( end ) )
1022 return distCache[start][end];
1023 }
1024 }
1025 else
1026 {
1027 if ( stripCache.contains ( start ) )
1028 {
1029 if ( stripCache[start].contains ( end ) )
1030 return stripCache[start][end];
1031 }
1032 }
1033 int storeStart(start);
1034 int storeEnd(end);
1035 bool hasHyph(false);
1036 GlyphList hyphList;
1037 if(start>0 && gl[start - 1].isBreak)
1038 {
1039 hasHyph = true;
1040 hyphList = gl[start - 1].hyphen.second;
1041 }
1042 GlyphList gList = gl;
1043 // if ( QChar ( gList.first().lChar ).category() == QChar::Separator_Space )
1044 // {
1045 // while ( QChar ( gList.first().lChar ).category() == QChar::Separator_Space && start < end )
1046 // {
1047 // ++start;
1048 // }
1049 // }
1050 // if ( QChar ( gList.last().lChar ).category() == QChar::Separator_Space )
1051 // {
1052 // while ( QChar ( gList.last().lChar ).category() == QChar::Separator_Space && end > start )
1053 // {
1054 // --end;
1055 // }
1056 // }
1057 //
1058 TextProgression *tp = TextProgression::getInstance();
1059 bool verticalLayout ( tp->inLine() == TextProgression::INLINE_BTT || tp->inLine() == TextProgression::INLINE_TTB );
1060 // qDebug()<<"IB VL"<<tp->inLine()<<verticalLayout;
1061 // QString dStr;
1062 // for(int di(start); di < end; ++di )
1063 // {
1064 // dStr += QChar(gl[di].lChar);
1065 // }
1066 // qDebug()<< "SD"<<dStr;
1067
1068 // qDebug()<<"DIS C S E"<<gList.count()<< start<< end;
1069 double ret ( 0.0 );
1070 if ( end <= start )
1071 {
1072 // qDebug()<<"ERR_LOGIC! S E"<< start<< end;
1073 return ret;
1074 }
1075 int EXend ( end -1 );
1076 if ( verticalLayout )
1077 {
1078 if ( !hasHyph && !gList.at ( EXend ).isBreak )
1079 {
1080 for ( int i ( start ); i < end ;++i )
1081 {
1082 // qDebug()<<"Ya"<< gList.at ( i ).yadvance;
1083 if(strip)
1084 {
1085 if( QChar ( gList.last().lChar ).category() != QChar::Separator_Space)
1086 ret += gList.at ( i ).yadvance;
1087 }
1088 else
1089 ret += gList.at ( i ).yadvance;
1090 }
1091 }
1092 else if ( hasHyph && !gList.at ( EXend ).isBreak )
1093 {
1094 GlyphList hr ( gList.at ( start - 1).hyphen.second );
1095 for ( int ih ( 0 ); ih < hr.count(); ++ih )
1096 {
1097 ret += hr[ih].yadvance;
1098 }
1099 int bp ( start );
1100 while ( bp < end )
1101 {
1102 if ( QChar ( gList.at ( bp ).lChar ).category() != QChar::Separator_Space )
1103 ++bp ;
1104 else
1105 break;
1106 }
1107
1108 for ( int i ( bp ); i < end ;++i )
1109 {
1110 if(strip)
1111 {
1112 if( QChar ( gList.last().lChar ).category() != QChar::Separator_Space)
1113 ret += gList.at ( i ).yadvance;
1114 }
1115 else
1116 ret += gList.at ( i ).yadvance ;
1117 }
1118 }
1119 else if ( !hasHyph && gList.at ( EXend ).isBreak )
1120 {
1121 int bp ( end );
1122 while ( QChar ( gList.at ( bp ).lChar ).category() != QChar::Separator_Space && bp > start ) --bp ;
1123 ++bp;
1124
1125 for ( int i ( start ); i < bp ;++i )
1126 {
1127 if(strip)
1128 {
1129 if( QChar ( gList.last().lChar ).category() != QChar::Separator_Space)
1130 ret += gList.at ( i ).yadvance;
1131 }
1132 else
1133 ret += gList.at ( i ).yadvance;
1134 }
1135 GlyphList hr ( gList.at ( EXend ).hyphen.first );
1136 for ( int ih ( 0 ); ih < hr.count(); ++ih )
1137 {
1138 ret += hr[ih].yadvance;
1139 }
1140
1141 }
1142 else if ( hasHyph && gList.at ( EXend ).isBreak )
1143 {
1144 GlyphList hr ( hyphList );
1145 for ( int ih ( 0 ); ih < hr.count(); ++ih )
1146 {
1147 ret += hr[ih].yadvance;
1148 }
1149 int bpS ( start );
1150 while ( bpS < end )
1151 {
1152 if ( QChar ( gList.at ( bpS ).lChar ).category() != QChar::Separator_Space )
1153 ++bpS ;
1154 else
1155 break;
1156 }
1157
1158 int bpE ( end );
1159 while ( QChar ( gList.at ( bpE ).lChar ).category() != QChar::Separator_Space && bpE > start ) --bpE ;
1160 ++bpE;
1161
1162 for ( int i ( bpS ); i < bpE ;++i )
1163 {
1164 if(strip)
1165 {
1166 if( QChar ( gList.last().lChar ).category() != QChar::Separator_Space)
1167 ret += gList.at ( i ).yadvance;
1168 }
1169 else
1170 ret += gList.at ( i ).yadvance;
1171 }
1172 GlyphList hr2 ( gList.at ( EXend ).hyphen.first );
1173 for ( int ih ( 0 ); ih < hr2.count(); ++ih )
1174 {
1175 ret += hr2[ih].yadvance;
1176 }
1177 }
1178 }
1179 else
1180 {
1181 if ( !hasHyph && !gList.at ( EXend ).isBreak )
1182 {
1183 // qDebug()<<". ." ;
1184 for ( int i ( start ); i < end ;++i )
1185 {
1186 if(strip)
1187 {
1188 if( QChar ( gList.at(i).lChar ).category() != QChar::Separator_Space)
1189 ret += gList.at ( i ).xadvance;
1190 }
1191 else
1192 ret += gList.at ( i ).xadvance /*+ gList.at ( i ).xoffset*/;
1193 }
1194 }
1195 else if ( hasHyph && !gList.at ( EXend ).isBreak )
1196 {
1197 // qDebug()<<"- ." ;
1198 GlyphList hr ( hyphList );
1199 for ( int ih ( 0 ); ih < hr.count(); ++ih )
1200 {
1201 // qDebug()<<"ih"<<ih;
1202 ret += hr[ih].xadvance;
1203 }
1204 int bp ( start );
1205 // qDebug()<<"bp"<<bp;
1206 while ( bp < end )
1207 {
1208 if ( QChar ( gList.at ( bp ).lChar ).category() != QChar::Separator_Space )
1209 ++bp ;
1210 else
1211 break;
1212 }
1213
1214 for ( int i ( bp ); i < end ;++i )
1215 {
1216 // qDebug()<<"i tS.xa"<<i<<gList.at ( i ).xadvance;
1217 if(strip)
1218 {
1219 if( QChar ( gList.at(i).lChar ).category() != QChar::Separator_Space)
1220 ret += gList.at ( i ).xadvance;
1221 }
1222 else
1223 ret += gList.at ( i ).xadvance ;
1224 }
1225
1226
1227 }
1228 else if ( !hasHyph && gList.at ( EXend ).isBreak )
1229 {
1230 // qDebug()<<". -" ;
1231 int bp ( end );
1232 while ( QChar ( gList.at ( bp ).lChar ).category() != QChar::Separator_Space && bp > start ) --bp ;
1233 ++bp;
1234
1235 for ( int i ( start ); i < bp ;++i )
1236 {
1237 if(strip)
1238 {
1239 if( QChar ( gList.at(i).lChar ).category() != QChar::Separator_Space)
1240 ret += gList.at ( i ).xadvance;
1241 }
1242 else
1243 ret += gList.at ( i ).xadvance /*+ gList.at ( i ).xoffset*/;
1244 }
1245 GlyphList hr ( gList.at ( EXend ).hyphen.first );
1246 for ( int ih ( 0 ); ih < hr.count(); ++ih )
1247 {
1248 ret += hr[ih].xadvance;
1249 }
1250
1251 }
1252 else if ( hasHyph && gList.at ( EXend ).isBreak )
1253 {
1254 // qDebug()<<"- -" ;
1255 // QString debStr;
1256 GlyphList hr ( hyphList);
1257 for ( int ih ( 0 ); ih < hr.count(); ++ih )
1258 {
1259 // debStr += QChar(hr[ih].lChar);
1260 ret += hr[ih].xadvance;
1261 }
1262
1263 int bpS ( start );
1264 while ( bpS < end )
1265 {
1266 if ( QChar ( gList.at ( bpS ).lChar ).category() != QChar::Separator_Space )
1267 ++bpS ;
1268 else
1269 break;
1270 }
1271
1272 int bpE ( end );
1273 while ( QChar ( gList.at ( bpE ).lChar ).category() != QChar::Separator_Space && bpE > start ) --bpE ;
1274 ++bpE;
1275
1276 for ( int i ( bpS ); i < bpE ;++i )
1277 {
1278 if(strip)
1279 {
1280 if( QChar ( gList.at(i).lChar ).category() != QChar::Separator_Space)
1281 ret += gList.at ( i ).xadvance;
1282 }
1283 else
1284 {
1285 // debStr += QChar(gList.at( i ).lChar);
1286 ret += gList.at ( i ).xadvance /*+ gList.at ( i ).xoffset*/;
1287 }
1288 }
1289 GlyphList hr2 ( gList.at ( EXend ).hyphen.first );
1290 for ( int ih ( 0 ); ih < hr2.count(); ++ih )
1291 {
1292 // debStr += QChar(hr2[ih].lChar);
1293 ret += hr2[ih].xadvance;
1294 }
1295 // qDebug()<<"D(= =)"<<debStr;
1296 }
1297 }
1298
1299 // qDebug()<<"SID" ;
1300 if(!deviceIndy)
1301 ret *= typotek::getInstance()->getDpiX() / 72.0 ;
1302 // if ( power )
1303 // {
1304 // distCache[storeStart][storeEnd] = ret*ret;
1305 // return ret*ret;
1306 // }
1307 distCache[start][end] = ret;
1308 return ret;
1309 }
1310
resetScene()1311 void FMLayout::resetScene()
1312 {
1313 if(persistentScene)
1314 return;
1315 if(!contextIsMainThread)
1316 {
1317 emit clearScene();
1318 return;
1319 }
1320 int pCount ( pixList.count() );
1321 for ( int i = 0; i < pCount ; ++i )
1322 {
1323 if ( pixList[i]->scene() && ( pixList[i]->scene() == theScene ) )
1324 {
1325 pixList[i]->scene()->removeItem ( pixList[i] );
1326 delete pixList[i];
1327 pixList[i] = 0;
1328 }
1329 }
1330 pixList.removeAll(0);
1331
1332 int gCount ( glyphList.count() );
1333 // QMap<QGraphicsScene*,int> ss;
1334 for ( int i = 0; i < gCount; ++i )
1335 {
1336 // ss[glyphList[i]->scene()]++;
1337 if ( glyphList[i]->scene() && (glyphList[i]->scene() == theScene) )
1338 {
1339 glyphList[i]->scene()->removeItem ( glyphList[i] );
1340 delete glyphList[i];
1341 glyphList[i] = 0;
1342 }
1343 }
1344 glyphList.removeAll(0);
1345 // QString dbs;
1346 // foreach(QGraphicsScene* qgs, ss)
1347 // {
1348 // dbs += "["+ QString::number(reinterpret_cast<unsigned int>(qgs)) +"]";
1349 // }
1350 // qDebug()<<"GC"<< ss <<gCount<< r <<glyphList.count() ;
1351 }
1352
1353 //void FMLayout::setTheScene ( QGraphicsScene* theValue , QRectF rect)
1354 //{
1355 // theScene = theValue;
1356 // if(rect.isNull())
1357 // {
1358 // QRectF tmpRect = theScene->sceneRect();
1359 // double sUnitW ( tmpRect.width() * .1 );
1360 // double sUnitH ( tmpRect.height() * .1 );
1361
1362 // theRect.setX ( 2.0 * sUnitW );
1363 // theRect.setY ( 1.0 * sUnitH );
1364 // theRect.setWidth ( 6.0 * sUnitW );
1365 // theRect.setHeight ( 8.0 * sUnitH );
1366 // }
1367 // else
1368 // {
1369 // theRect = rect;
1370 // }
1371 //// rules->setRect(theRect);
1372 //// rules->setZValue(9.9);
1373 //// if(rules->scene() != theScene)
1374 //// theScene->addItem(rules);
1375 //}
1376
1377 //void FMLayout::setTheFont ( FontItem* theValue )
1378 //{
1379 // theFont = theValue;
1380 // optionHasChanged = true;
1381 //}
1382
lineWidth(int l)1383 double FMLayout::lineWidth ( int l )
1384 {
1385 TextProgression *tp = TextProgression::getInstance();
1386 double offset ( ( double ) l * adjustedSampleInter ) ;
1387 if ( tp->inBlock() == TextProgression::BLOCK_TTB )
1388 {
1389 // if ( theRect.top() + offset > theRect.bottom() )
1390 // {
1391 // return OUT_OF_RECT;
1392 // }
1393 return theRect.width();
1394 }
1395 else if ( tp->inBlock() == TextProgression::BLOCK_RTL )
1396 {
1397 // if ( theRect.right() - offset < theRect.left() )
1398 // {
1399 // return OUT_OF_RECT;
1400 // }
1401 return theRect.height() - adjustedSampleInter;
1402 }
1403 else if ( tp->inBlock() == TextProgression::BLOCK_LTR )
1404 {
1405 // if ( theRect.left() + offset > theRect.right() )
1406 // {
1407 // return OUT_OF_RECT;
1408 // }
1409 return theRect.height() - adjustedSampleInter;
1410 }
1411
1412 return OUT_OF_RECT;
1413 }
1414
slotOption(int v)1415 void FMLayout::slotOption ( int v )
1416 {
1417 optionHasChanged = true;
1418
1419 if ( v == FMLayOptWidget::BEFORE )
1420 {
1421 FM_LAYOUT_NODE_SOON_F = optionsWidget->getValue ( FMLayOptWidget::BEFORE );
1422 emit updateLayout();
1423 }
1424 else if ( v == FMLayOptWidget::EXACT )
1425 {
1426 FM_LAYOUT_NODE_FIT_F = optionsWidget->getValue ( FMLayOptWidget::EXACT );
1427 emit updateLayout();
1428 }
1429 else if ( v == FMLayOptWidget::AFTER )
1430 {
1431 FM_LAYOUT_NODE_LATE_F = optionsWidget->getValue ( FMLayOptWidget::AFTER );
1432 emit updateLayout();
1433 }
1434 else if ( v == FMLayOptWidget::END )
1435 {
1436 FM_LAYOUT_NODE_END_F = optionsWidget->getValue ( FMLayOptWidget::END );
1437 emit updateLayout();
1438 }
1439 else if ( v == FMLayOptWidget::HYPHEN )
1440 {
1441 FM_LAYOUT_HYPHEN_PENALTY = ( double ) optionsWidget->getValue ( FMLayOptWidget::HYPHEN ) / 10.0;
1442 emit updateLayout();
1443 }
1444 else if ( v == FMLayOptWidget::SPACE )
1445 {
1446 FM_LAYOUT_MAX_COMPRESSION = optionsWidget->getValue ( FMLayOptWidget::SPACE );
1447 emit updateLayout();
1448 }
1449 }
1450
setAdjustedSampleInter(double theValue)1451 void FMLayout::setAdjustedSampleInter(double theValue)
1452 {
1453 adjustedSampleInter = !deviceIndy ? theValue * typotek::getInstance()->getDpiX() / 72.0 : theValue;
1454 }
1455
clearCaches()1456 void FMLayout::clearCaches()
1457 {
1458 sepCache.clear();
1459 distCache.clear();
1460 stripCache.clear();
1461 }
1462
endOfParagraph()1463 void FMLayout::endOfParagraph()
1464 {
1465 // typotek::getInstance()->runProgressJob();
1466 }
1467
1468
setContext(bool c)1469 void FMLayout::setContext(bool c)
1470 {
1471 contextIsMainThread = c;
1472 // if(c)
1473 // theFont->moveToThread(QApplication::instance()->thread());
1474 // else
1475 // emit objectWanted(theFont);
1476 }
1477
1478
1479
1480
1481
1482