dillo  3.0.5
About: dillo is a small, fast, extensible Web browser particularly suitable for older or smaller computers and embedded systems (but only limited or no support for frames, CSS, JavaScript, Java).
  Fossies Dox: dillo-3.0.5.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

textblock_linebreaking.cc
Go to the documentation of this file.
1 /*
2  * Dillo Widget
3  *
4  * Copyright 2005-2007, 2012-2013 Sebastian Geerken <sgeerken@dillo.org>
5  *
6  * (Parts of this file were originally part of textblock.cc.)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 
23 #include "textblock.hh"
24 #include "hyphenator.hh"
25 #include "../lout/msg.h"
26 #include "../lout/misc.hh"
27 
28 #include <stdio.h>
29 #include <math.h>
30 
31 using namespace lout;
32 
33 namespace dw {
34 
35 int Textblock::BadnessAndPenalty::badnessValue (int infLevel)
36 {
37  switch (badnessState) {
38  case NOT_STRETCHABLE:
39  return infLevel == INF_NOT_STRETCHABLE ? 1 : 0;
40 
41  case QUITE_LOOSE:
42  return infLevel == INF_LARGE ? 1 : 0;
43 
44  case BADNESS_VALUE:
45  return infLevel == INF_VALUE ? badness : 0;
46 
47  case TOO_TIGHT:
48  return infLevel == INF_TOO_TIGHT ? 1 : 0;
49  }
50 
51  // compiler happiness
53  return 0;
54 }
55 
56 int Textblock::BadnessAndPenalty::penaltyValue (int index, int infLevel)
57 {
58  if (penalty[index] == INT_MIN)
59  return infLevel == INF_PENALTIES ? -1 : 0;
60  else if (penalty[index] == INT_MAX)
61  return infLevel == INF_PENALTIES ? 1 : 0;
62  else
63  return infLevel == INF_VALUE ? penalty[index] : 0;
64 }
65 
66 void Textblock::BadnessAndPenalty::calcBadness (int totalWidth, int idealWidth,
67  int totalStretchability,
68  int totalShrinkability)
69 {
70 #ifdef DEBUG
71  this->totalWidth = totalWidth;
72  this->idealWidth = idealWidth;
73  this->totalStretchability = totalStretchability;
74  this->totalShrinkability = totalShrinkability;
75 #endif
76 
77  ratio = 0; // because this is used in print()
78 
79  if (totalWidth == idealWidth) {
80  badnessState = BADNESS_VALUE;
81  badness = 0;
82  } else if (totalWidth < idealWidth) {
83  if (totalStretchability == 0)
84  badnessState = NOT_STRETCHABLE;
85  else {
86  ratio = 100 * (idealWidth - totalWidth) / totalStretchability;
87  if (ratio > 1024)
88  badnessState = QUITE_LOOSE;
89  else {
90  badnessState = BADNESS_VALUE;
91  badness = ratio * ratio * ratio;
92  }
93  }
94  } else { // if (totalWidth > availWidth)
95  if (totalShrinkability == 0)
96  badnessState = TOO_TIGHT;
97  else {
98  // ratio is negative here
99  ratio = 100 * (idealWidth - totalWidth) / totalShrinkability;
100  if (ratio <= - 100)
101  badnessState = TOO_TIGHT;
102  else {
103  badnessState = BADNESS_VALUE;
104  badness = - ratio * ratio * ratio;
105  }
106  }
107  }
108 }
109 
128 void Textblock::BadnessAndPenalty::setPenalties (int penalty1, int penalty2)
129 {
130  // TODO Check here some cases, e.g. both or no penalty INT_MIN.
131  setSinglePenalty(0, penalty1);
132  setSinglePenalty(1, penalty2);
133 }
134 
135 void Textblock::BadnessAndPenalty::setSinglePenalty (int index, int penalty)
136 {
137  if (penalty == INT_MAX || penalty == INT_MIN)
138  this->penalty[index] = penalty;
139  else
140  // This factor consists of: (i) 100^3, since in calcBadness(), the
141  // ratio is multiplied with 100 (again, to use integer numbers for
142  // fractional numbers), and the badness (which has to be compared
143  // to the penalty!) is the third power or it; (ii) the denominator
144  // 100, of course, since 100 times the penalty is passed to this
145  // method.
146  this->penalty[index] = penalty * (100 * 100 * 100 / 100);
147 }
148 
149 bool Textblock::BadnessAndPenalty::lineLoose ()
150 {
151  return
152  badnessState == NOT_STRETCHABLE || badnessState == QUITE_LOOSE ||
153  (badnessState == BADNESS_VALUE && ratio > 0);
154 }
155 
156 bool Textblock::BadnessAndPenalty::lineTight ()
157 {
158  return
159  badnessState == TOO_TIGHT || (badnessState == BADNESS_VALUE && ratio < 0);
160 }
161 
162 bool Textblock::BadnessAndPenalty::lineTooTight ()
163 {
164  return badnessState == TOO_TIGHT;
165 }
166 
167 
168 bool Textblock::BadnessAndPenalty::lineMustBeBroken (int penaltyIndex)
169 {
170  return penalty[penaltyIndex] == PENALTY_FORCE_BREAK;
171 }
172 
173 bool Textblock::BadnessAndPenalty::lineCanBeBroken (int penaltyIndex)
174 {
175  return penalty[penaltyIndex] != PENALTY_PROHIBIT_BREAK;
176 }
177 
178 int Textblock::BadnessAndPenalty::compareTo (int penaltyIndex,
179  BadnessAndPenalty *other)
180 {
181  for (int l = INF_MAX; l >= 0; l--) {
182  int thisValue = badnessValue (l) + penaltyValue (penaltyIndex, l);
183  int otherValue =
184  other->badnessValue (l) + other->penaltyValue (penaltyIndex, l);
185 
186  if (thisValue != otherValue)
187  return thisValue - otherValue;
188  }
189 
190  return 0;
191 }
192 
193 void Textblock::BadnessAndPenalty::print ()
194 {
195  switch (badnessState) {
196  case NOT_STRETCHABLE:
197  printf ("not stretchable");
198  break;
199 
200  case TOO_TIGHT:
201  printf ("too tight");
202  break;
203 
204  case QUITE_LOOSE:
205  printf ("quite loose (ratio = %d)", ratio);
206  break;
207 
208  case BADNESS_VALUE:
209  printf ("%d", badness);
210  break;
211  }
212 
213 #ifdef DEBUG
214  printf (" [%d + %d - %d vs. %d]",
215  totalWidth, totalStretchability, totalShrinkability, idealWidth);
216 #endif
217 
218  printf (" + (");
219  for (int i = 0; i < 2; i++) {
220  if (penalty[i] == INT_MIN)
221  printf ("-inf");
222  else if (penalty[i] == INT_MAX)
223  printf ("inf");
224  else
225  printf ("%d", penalty[i]);
226 
227  if (i == 0)
228  printf (", ");
229  }
230  printf (")");
231 }
232 
233 void Textblock::printWordShort (Word *word)
234 {
235  switch(word->content.type) {
236  case core::Content::TEXT:
237  printf ("\"%s\"", word->content.text);
238  break;
239  case core::Content::WIDGET:
240  printf ("<widget: %p (%s)>",
241  word->content.widget, word->content.widget->getClassName());
242  break;
243  case core::Content::BREAK:
244  printf ("<break>");
245  break;
246  default:
247  printf ("<?>");
248  break;
249  }
250 }
251 
252 void Textblock::printWordFlags (short flags)
253 {
254  printf ("%s:%s:%s:%s:%s:%s:%s",
255  (flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--",
256  (flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--",
257  (flags & Word::PERM_DIV_CHAR) ? "dp" : "--",
258  (flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--",
259  (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--",
260  (flags & Word::WORD_START) ? "st" : "--",
261  (flags & Word::WORD_END) ? "en" : "--");
262 }
263 
264 void Textblock::printWordWithFlags (Word *word)
265 {
266  printWordShort (word);
267  printf (" (flags = ");
268  printWordFlags (word->flags);
269  printf (")");
270 }
271 
272 void Textblock::printWord (Word *word)
273 {
274  printWordWithFlags (word);
275 
276  printf (" [%d / %d + %d - %d => %d + %d - %d] => ",
277  word->size.width, word->origSpace, getSpaceStretchability(word),
278  getSpaceShrinkability(word), word->totalWidth,
280  word->badnessAndPenalty.print ();
281 }
282 
283 /*
284  * ...
285  *
286  * diff ...
287  */
288 void Textblock::justifyLine (Line *line, int diff)
289 {
290  /* To avoid rounding errors, the calculation is based on accumulated
291  * values. */
292 
293  if (diff > 0) {
294  int spaceStretchabilitySum = 0;
295  for (int i = line->firstWord; i < line->lastWord; i++)
296  spaceStretchabilitySum += getSpaceStretchability(words->getRef(i));
297 
298  if (spaceStretchabilitySum > 0) {
299  int spaceStretchabilityCum = 0;
300  int spaceDiffCum = 0;
301  for (int i = line->firstWord; i < line->lastWord; i++) {
302  Word *word = words->getRef (i);
303  spaceStretchabilityCum += getSpaceStretchability(word);
304  int spaceDiff =
305  spaceStretchabilityCum * diff / spaceStretchabilitySum
306  - spaceDiffCum;
307  spaceDiffCum += spaceDiff;
308 
309  PRINTF (" %d (of %d): diff = %d\n", i, words->size (),
310  spaceDiff);
311 
312  word->effSpace = word->origSpace + spaceDiff;
313  }
314  }
315  } else if (diff < 0) {
316  int spaceShrinkabilitySum = 0;
317  for (int i = line->firstWord; i < line->lastWord; i++)
318  spaceShrinkabilitySum += getSpaceShrinkability(words->getRef(i));
319 
320  if (spaceShrinkabilitySum > 0) {
321  int spaceShrinkabilityCum = 0;
322  int spaceDiffCum = 0;
323  for (int i = line->firstWord; i < line->lastWord; i++) {
324  Word *word = words->getRef (i);
325  spaceShrinkabilityCum += getSpaceShrinkability(word);
326  int spaceDiff =
327  spaceShrinkabilityCum * diff / spaceShrinkabilitySum
328  - spaceDiffCum;
329  spaceDiffCum += spaceDiff;
330 
331  word->effSpace = word->origSpace + spaceDiff;
332  }
333  }
334  }
335 }
336 
337 
338 Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
339  bool temporary)
340 {
341  PRINTF ("[%p] ADD_LINE (%d, %d) => %d\n",
342  this, firstWord, lastWord, lines->size ());
343 
344  Word *lastWordOfLine = words->getRef(lastWord);
345  // Word::totalWidth includes the hyphen (which is what we want here).
346  int lineWidth = lastWordOfLine->totalWidth;
347  // "lineWidth" is relative to leftOffset, so we may have to add
348  // "line1OffsetEff" (remember: this is, for list items, negative).
349  if (lines->size () == 0)
350  lineWidth += line1OffsetEff;
351 
352  int maxOfMinWidth, sumOfMaxWidth;
353  accumulateWordExtremes (firstWord, lastWord, &maxOfMinWidth,
354  &sumOfMaxWidth);
355 
356  PRINTF (" words[%d]->totalWidth = %d\n", lastWord,
357  lastWordOfLine->totalWidth);
358 
359  PRINTF ("[%p] ##### LINE ADDED: %d, from %d to %d #####\n",
360  this, lines->size (), firstWord, lastWord);
361 
362  lines->increase ();
363  if(!temporary) {
364  // If the last line was temporary, this will be temporary, too, even
365  // if not requested.
366  if (lines->size () == 1 || nonTemporaryLines == lines->size () -1)
367  nonTemporaryLines = lines->size ();
368  }
369 
370  PRINTF ("nonTemporaryLines = %d\n", nonTemporaryLines);
371 
372  int lineIndex = lines->size () - 1;
373  Line *line = lines->getRef (lineIndex);
374 
375  line->firstWord = firstWord;
376  line->lastWord = lastWord;
377  line->boxAscent = line->contentAscent = 0;
378  line->boxDescent = line->contentDescent = 0;
379  line->marginDescent = 0;
380  line->breakSpace = 0;
381  line->leftOffset = 0;
382 
383  alignLine (lineIndex);
384  for (int i = line->firstWord; i < line->lastWord; i++) {
385  Word *word = words->getRef (i);
386  lineWidth += (word->effSpace - word->origSpace);
387  }
388 
389  if (lines->size () == 1) {
390  // first line
391  line->top = 0;
392  line->maxLineWidth = lineWidth;
393  } else {
394  Line *prevLine = lines->getRef (lines->size () - 2);
395  line->top = prevLine->top + prevLine->boxAscent +
396  prevLine->boxDescent + prevLine->breakSpace;
397  line->maxLineWidth = misc::max (lineWidth, prevLine->maxLineWidth);
398  }
399 
400  for(int i = line->firstWord; i <= line->lastWord; i++)
401  accumulateWordForLine (lineIndex, i);
402 
403  PRINTF (" line[%d].top = %d\n", lines->size () - 1, line->top);
404  PRINTF (" line[%d].boxAscent = %d\n", lines->size () - 1, line->boxAscent);
405  PRINTF (" line[%d].boxDescent = %d\n",
406  lines->size () - 1, line->boxDescent);
407  PRINTF (" line[%d].contentAscent = %d\n", lines->size () - 1,
408  line->contentAscent);
409  PRINTF (" line[%d].contentDescent = %d\n",
410  lines->size () - 1, line->contentDescent);
411 
412  PRINTF (" line[%d].maxLineWidth = %d\n",
413  lines->size () - 1, line->maxLineWidth);
414 
415  mustQueueResize = true;
416 
417  //printWordShort (words->getRef (line->firstWord));
418  //printf (" ... ");
419  //printWordShort (words->getRef (line->lastWord));
420  //printf (": ");
421  //words->getRef(line->lastWord)->badnessAndPenalty.print ();
422  //printf ("\n");
423 
424  int xWidget = lineXOffsetWidget(line);
425  for (int i = firstWord; i <= lastWord; i++) {
426  Word *word = words->getRef (i);
427  if (word->wordImgRenderer)
428  word->wordImgRenderer->setData (xWidget, lines->size () - 1);
429  if (word->spaceImgRenderer)
430  word->spaceImgRenderer->setData (xWidget, lines->size () - 1);
431  xWidget += word->size.width + word->effSpace;
432  }
433 
434  return line;
435 }
436 
437 void Textblock::accumulateWordExtremes (int firstWord, int lastWord,
438  int *maxOfMinWidth, int *sumOfMaxWidth)
439 {
440  int parMin = 0;
441  *maxOfMinWidth = *sumOfMaxWidth = 0;
442 
443  for (int i = firstWord; i <= lastWord; i++) {
444  Word *word = words->getRef (i);
445  bool atLastWord = i == lastWord;
446 
447  core::Extremes extremes;
448  getWordExtremes (word, &extremes);
449 
450  // Minimum: between two *possible* breaks (or at the end).
451  // TODO This is redundant to getExtremesImpl().
452  // TODO: Again, index 1 is used for lineCanBeBroken(). See getExtremes().
453  if (word->badnessAndPenalty.lineCanBeBroken (1) || atLastWord) {
454  parMin += extremes.minWidth + word->hyphenWidth;
455  *maxOfMinWidth = misc::max (*maxOfMinWidth, parMin);
456  parMin = 0;
457  } else
458  // Shrinkability could be considered, but really does not play a
459  // role.
460  parMin += extremes.minWidth + word->origSpace;
461 
462  //printf ("[%p] after word: ", this);
463  //printWord (word);
464  //printf ("\n");
465 
466  //printf ("[%p] (%d / %d) => parMin = %d, maxOfMinWidth = %d\n",
467  // this, extremes.minWidth, extremes.maxWidth, parMin,
468  // *maxOfMinWidth);
469 
470  *sumOfMaxWidth += (extremes.maxWidth + word->origSpace);
471  // Notice that the last space is added. See also: Line::parMax.
472  }
473 }
474 
475 void Textblock::processWord (int wordIndex)
476 {
477  bool wordListChanged = wordWrap (wordIndex, false);
478 
479  if (wordListChanged) {
480  // If wordWrap has called hyphenateWord here, this has an effect
481  // on the call of handleWordExtremes. To avoid adding values
482  // more than one time (original un-hyphenated word, plus all
483  // parts of the hyphenated word, except the first one), the
484  // whole paragraph is recalculated again.
485 
486  int firstWord;
487  if (paragraphs->size() > 0) {
488  firstWord = paragraphs->getLastRef()->firstWord;
489  paragraphs->setSize (paragraphs->size() - 1);
490  } else
491  firstWord = 0;
492 
493  for (int i = firstWord; i <= wordIndex - 1; i++)
494  handleWordExtremes (i);
495  }
496 
497  handleWordExtremes (wordIndex);
498 }
499 
500 /*
501  * This method is called in two cases: (i) when a word is added
502  * (ii) when a page has to be (partially) rewrapped. It does word wrap,
503  * and adds new lines if necessary.
504  *
505  * Returns whether the words list has changed at, or before, the word
506  * index.
507  */
508 bool Textblock::wordWrap (int wordIndex, bool wrapAll)
509 {
510  PRINTF ("[%p] WORD_WRAP (%d, %s)\n",
511  this, wordIndex, wrapAll ? "true" : "false");
512 
513  Word *word;
514  bool wordListChanged = false;
515 
516  if (!wrapAll)
517  removeTemporaryLines ();
518 
519  initLine1Offset (wordIndex);
520 
521  word = words->getRef (wordIndex);
522  word->effSpace = word->origSpace;
523 
524  accumulateWordData (wordIndex);
525 
526  //printf (" ");
527  //printWord (word);
528  //printf ("\n");
529 
530  int penaltyIndex = calcPenaltyIndexForNewLine ();
531 
532  bool newLine;
533  do {
534  bool tempNewLine = false;
535  int firstIndex =
536  lines->size() == 0 ? 0 : lines->getLastRef()->lastWord + 1;
537  int searchUntil;
538 
539  if (wrapAll && wordIndex >= firstIndex && wordIndex == words->size() -1) {
540  newLine = true;
541  searchUntil = wordIndex;
542  tempNewLine = true;
543  PRINTF (" NEW LINE: last word\n");
544  } else if (wordIndex >= firstIndex &&
545  // TODO: lineMustBeBroken should be independent of
546  // the penalty index?
547  word->badnessAndPenalty.lineMustBeBroken (penaltyIndex)) {
548  newLine = true;
549  searchUntil = wordIndex;
550  PRINTF (" NEW LINE: forced break\n");
551  } else {
552  // Break the line when too tight, but only when there is a
553  // possible break point so far. (TODO: I've forgotten the
554  // original bug which is fixed by this.)
555  bool possibleLineBreak = false;
556  for (int i = firstIndex; !possibleLineBreak && i <= wordIndex - 1; i++)
557  if (words->getRef(i)->badnessAndPenalty
558  .lineCanBeBroken (penaltyIndex))
559  possibleLineBreak = true;
560 
561  if (possibleLineBreak && word->badnessAndPenalty.lineTooTight ()) {
562  newLine = true;
563  searchUntil = wordIndex - 1;
564  PRINTF (" NEW LINE: line too tight\n");
565  } else
566  newLine = false;
567  }
568 
569  if(!newLine && !wrapAll)
570  // No new line is added. "mustQueueResize" must,
571  // nevertheless, be set, so that flush() will call
572  // queueResize(), and later sizeRequestImpl() is called,
573  // which then calls showMissingLines(), which eventually
574  // calls this method again, with wrapAll == true, so that
575  // newLine is calculated as "true".
576  mustQueueResize = true;
577 
578  if(newLine) {
579  accumulateWordData (wordIndex);
580  int wordIndexEnd = wordIndex;
581 
582  bool lineAdded;
583  do {
584  int breakPos =
585  searchMinBap (firstIndex, searchUntil, penaltyIndex, wrapAll);
586  int hyphenatedWord = considerHyphenation (firstIndex, breakPos);
587 
588  //printf ("[%p] breakPos = %d (", this, breakPos);
589  //printWordShort (words->getRef (breakPos));
590  //printf ("), hyphenatedWord = %d", hyphenatedWord);
591  //if (hyphenatedWord != -1) {
592  // printf (" (");
593  // printWordShort (words->getRef (hyphenatedWord));
594  // printf (")");
595  //}
596  //printf ("\n");
597 
598  if(hyphenatedWord == -1) {
599  addLine (firstIndex, breakPos, tempNewLine);
600  PRINTF ("[%p] new line %d (%s), from %d to %d\n",
601  this, lines->size() - 1,
602  tempNewLine ? "temporally" : "permanently",
603  firstIndex, breakPos);
604  lineAdded = true;
605  penaltyIndex = calcPenaltyIndexForNewLine ();
606  } else {
607  // TODO hyphenateWord() should return whether something has
608  // changed at all. So that a second run, with
609  // !word->canBeHyphenated, is unnecessary.
610  // TODO Update: for this, searchUntil == 0 should be checked.
611  PRINTF ("[%p] old searchUntil = %d ...\n", this, searchUntil);
612  int n = hyphenateWord (hyphenatedWord);
613  searchUntil += n;
614  if (hyphenatedWord <= wordIndex)
615  wordIndexEnd += n;
616  PRINTF ("[%p] -> new searchUntil = %d ...\n", this, searchUntil);
617  lineAdded = false;
618 
619  // update word pointer as hyphenateWord() can trigger a
620  // reorganization of the words structure
621  word = words->getRef (wordIndex);
622 
623  if (n > 0 && hyphenatedWord <= wordIndex)
624  wordListChanged = true;
625  }
626 
627  PRINTF ("[%p] accumulating again from %d to %d\n",
628  this, breakPos + 1, wordIndexEnd);
629  for(int i = breakPos + 1; i <= wordIndexEnd; i++)
630  accumulateWordData (i);
631 
632  } while(!lineAdded);
633  }
634  } while (newLine);
635 
636  if(word->content.type == core::Content::WIDGET) {
637  // Set parentRef for the child, when necessary.
638  //
639  // parentRef is set for the child already, when a line is
640  // added. There are a couple of different situations to
641  // consider, e.g. when called from showMissingLines(), this word
642  // may already have been added in a previous call. To make
643  // things simple, we just check whether this word is contained
644  // within any line, or still "missing".
645 
646  int firstWordWithoutLine;
647  if (lines->size() == 0)
648  firstWordWithoutLine = 0;
649  else
650  firstWordWithoutLine = lines->getLastRef()->lastWord + 1;
651 
652  if (wordIndex >= firstWordWithoutLine) {
653  word->content.widget->parentRef = lines->size ();
654  PRINTF ("The %s %p is assigned parentRef = %d.\n",
655  word->content.widget->getClassName(), word->content.widget,
656  word->content.widget->parentRef);
657  }
658  }
659 
660  return wordListChanged;
661 }
662 
663 int Textblock::searchMinBap (int firstWord, int lastWord, int penaltyIndex,
664  bool correctAtEnd)
665 {
666  PRINTF (" searching from %d to %d\n", firstWord, lastWord);
667 
668  int pos = -1;
669 
670  for (int i = firstWord; i <= lastWord; i++) {
671  Word *w = words->getRef(i);
672 
673  //printf (" %d (of %d): ", i, words->size ());
674  //printWord (w);
675  //printf ("\n");
676 
677  if (pos == -1 ||
678  w->badnessAndPenalty.compareTo (penaltyIndex,
679  &words->getRef(pos)
680  ->badnessAndPenalty) <= 0)
681  // "<=" instead of "<" in the next lines tends to result in
682  // more words per line -- theoretically. Practically, the
683  // case "==" will never occur.
684  pos = i;
685  }
686 
687  PRINTF (" found at %d\n", pos);
688 
689  if (correctAtEnd && lastWord == words->size () - 1) {
690  // Since no break and no space is added, the last word will have
691  // a penalty of inf. Actually, it should be less, since it is
692  // the last word. However, since more words may follow, the
693  // penalty is not changed, but here, the search is corrected
694  // (maybe only temporary).
695 
696  // (Notice that it was once (temporally) set to -inf, not 0, but
697  // this will make e.g. test/table-1.html not work.)
698  Word *w = words->getRef (lastWord);
699  BadnessAndPenalty correctedBap = w->badnessAndPenalty;
700  correctedBap.setPenalty (0);
701 
702  //printf (" corrected bap: ");
703  //correctedBap.print ();
704  //printf ("\n");
705 
706  if (correctedBap.compareTo(penaltyIndex,
707  &words->getRef(pos)->badnessAndPenalty) <= 0) {
708  pos = lastWord;
709  PRINTF (" corrected => %d\n", pos);
710  }
711  }
712 
713  return pos;
714 }
715 
716 
722 int Textblock::considerHyphenation (int firstIndex, int breakPos)
723 {
724  int hyphenatedWord = -1;
725 
726  Word *wordBreak = words->getRef(breakPos);
727  //printf ("[%p] line (broken at word %d): ", this, breakPos);
728  //printWord (wordBreak);
729  //printf ("\n");
730 
731  // A tight line: maybe, after hyphenation, some parts of the last
732  // word of this line can be put into the next line.
733  if (wordBreak->badnessAndPenalty.lineTight ()) {
734  // Sometimes, it is not the last word, which must be hyphenated,
735  // but some word before. Here, we search for the first word
736  // which can be hyphenated, *and* makes the line too tight.
737  for (int i = breakPos; i >= firstIndex; i--) {
738  Word *word1 = words->getRef (i);
739  if (word1->badnessAndPenalty.lineTight () &&
740  isHyphenationCandidate (word1))
741  hyphenatedWord = i;
742  }
743  }
744 
745  // A loose line: maybe, after hyphenation, some parts of the first
746  // word of the next line can be put into this line.
747  if (wordBreak->badnessAndPenalty.lineLoose () &&
748  breakPos + 1 < words->size ()) {
749  Word *word2 = words->getRef(breakPos + 1);
750  if (isHyphenationCandidate (word2))
751  hyphenatedWord = breakPos + 1;
752  }
753 
754  return hyphenatedWord;
755 }
756 
757 bool Textblock::isHyphenationCandidate (Word *word)
758 {
759  return (word->flags & Word::CAN_BE_HYPHENATED) &&
760  word->style->x_lang[0] &&
761  isBreakAllowed(word) &&
762  word->content.type == core::Content::TEXT &&
763  Hyphenator::isHyphenationCandidate (word->content.text);
764 }
765 
766 
770 void Textblock::handleWordExtremes (int wordIndex)
771 {
772  // TODO Overall, clarify penalty index.
773 
774  Word *word = words->getRef (wordIndex);
775  core::Extremes wordExtremes;
776  getWordExtremes (word, &wordExtremes);
777 
778  //printf ("[%p] HANDLE_WORD_EXTREMES (%d): ", this, wordIndex);
779  //printWordWithFlags (word);
780  //printf (" => %d / %d\n", wordExtremes.minWidth, wordExtremes.maxWidth);
781 
782  if (wordIndex == 0) {
783  wordExtremes.minWidth += line1Offset;
784  wordExtremes.maxWidth += line1Offset;
785  }
786 
787  if (paragraphs->size() == 0 ||
788  words->getRef(paragraphs->getLastRef()->lastWord)
789  ->badnessAndPenalty.lineMustBeBroken (1)) {
790  // Add a new paragraph.
791  paragraphs->increase ();
792  Paragraph *prevPar = paragraphs->size() == 1 ?
793  NULL : paragraphs->getRef(paragraphs->size() - 2);
794  Paragraph *par = paragraphs->getLastRef();
795 
796  par->firstWord = par->lastWord = wordIndex;
797  par->parMin = par->parMax = 0;
798 
799  if (prevPar) {
800  par->maxParMin = prevPar->maxParMin;
801  par->maxParMax = prevPar->maxParMax;
802  } else
803  par->maxParMin = par->maxParMax = 0;
804 
805  PRINTF (" new par: %d\n", paragraphs->size() - 1);
806  }
807 
808  PRINTF (" last par: %d\n", paragraphs->size() - 1);
809  Paragraph *lastPar = paragraphs->getLastRef();
810 
811  int corrDiffMin, corrDiffMax;
812  if (wordIndex - 1 >= lastPar->firstWord) {
813  Word *lastWord = words->getRef (wordIndex - 1);
814  if (lastWord->badnessAndPenalty.lineCanBeBroken (1) &&
815  (lastWord->flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) == 0)
816  corrDiffMin = 0;
817  else
818  corrDiffMin = lastWord->origSpace - lastWord->hyphenWidth;
819 
820  corrDiffMax = lastWord->origSpace - lastWord->hyphenWidth;
821  } else
822  corrDiffMin = corrDiffMax = 0;
823 
824  PRINTF (" (lastPar from %d to %d; corrDiffMin = %d, corDiffMax = %d)\n",
825  lastPar->firstWord, lastPar->lastWord, corrDiffMin, corrDiffMax);
826 
827  // Minimum: between two *possible* breaks.
828  // Shrinkability could be considered, but really does not play a role.
829  lastPar->parMin += wordExtremes.minWidth + word->hyphenWidth + corrDiffMin;
830  lastPar->maxParMin = misc::max (lastPar->maxParMin, lastPar->parMin);
831  if (word->badnessAndPenalty.lineCanBeBroken (1) &&
832  (word->flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) == 0)
833  lastPar->parMin = 0;
834 
835  // Maximum: between two *necessary* breaks.
836  lastPar->parMax += wordExtremes.maxWidth + word->hyphenWidth + corrDiffMax;
837  lastPar->maxParMax = misc::max (lastPar->maxParMax, lastPar->parMax);
838 
839  PRINTF (" => parMin = %d (max = %d), parMax = %d (max = %d)\n",
840  lastPar->parMin, lastPar->maxParMin, lastPar->parMax,
841  lastPar->maxParMax);
842 
843  lastPar->lastWord = wordIndex;
844 }
845 
849 void Textblock::correctLastWordExtremes ()
850 {
851  if (paragraphs->size() > 0) {
852  Word *word = words->getLastRef ();
853  if (word->badnessAndPenalty.lineCanBeBroken (1) &&
854  (word->flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) == 0) {
855  paragraphs->getLastRef()->parMin = 0;
856  PRINTF (" => corrected; parMin = %d\n",
857  paragraphs->getLastRef()->parMin);
858  }
859  }
860 }
861 
862 
863 int Textblock::hyphenateWord (int wordIndex)
864 {
865  Word *hyphenatedWord = words->getRef(wordIndex);
866  char lang[3] = { hyphenatedWord->style->x_lang[0],
867  hyphenatedWord->style->x_lang[1], 0 };
868  Hyphenator *hyphenator = Hyphenator::getHyphenator (lang);
869  PRINTF ("[%p] considering to hyphenate word %d, '%s', in language '%s'\n",
870  this, wordIndex, words->getRef(wordIndex)->content.text, lang);
871  int numBreaks;
872  int *breakPos =
873  hyphenator->hyphenateWord (layout->getPlatform (),
874  hyphenatedWord->content.text, &numBreaks);
875 
876  if (numBreaks > 0) {
877  Word origWord = *hyphenatedWord;
878 
879  core::Requisition wordSize[numBreaks + 1];
880  calcTextSizes (origWord.content.text, strlen (origWord.content.text),
881  origWord.style, numBreaks, breakPos, wordSize);
882 
883  PRINTF ("[%p] %d words ...\n", this, words->size ());
884  words->insert (wordIndex, numBreaks);
885  for (int i = 0; i < numBreaks; i++)
886  initWord (wordIndex + i);
887  PRINTF ("[%p] ... => %d words\n", this, words->size ());
888 
889  // Adjust anchor indexes.
890  for (int i = 0; i < anchors->size (); i++) {
891  Anchor *anchor = anchors->getRef (i);
892  if (anchor->wordIndex > wordIndex)
893  anchor->wordIndex += numBreaks;
894  }
895 
896  for (int i = 0; i < numBreaks + 1; i++) {
897  Word *w = words->getRef (wordIndex + i);
898  fillWord (wordIndex + i, wordSize[i].width, wordSize[i].ascent,
899  wordSize[i].descent, false, origWord.style);
900 
901  // TODO There should be a method fillText0.
902  w->content.type = core::Content::TEXT;
903 
904  int start = (i == 0 ? 0 : breakPos[i - 1]);
905  int end = (i == numBreaks ?
906  strlen (origWord.content.text) : breakPos[i]);
907  w->content.text =
908  layout->textZone->strndup (origWord.content.text + start,
909  end - start);
910  PRINTF (" [%d] -> '%s'\n", wordIndex + i, w->content.text);
911 
912  // Note: there are numBreaks + 1 word parts.
913  if (i == 0)
914  w->flags |= Word::WORD_START;
915  else
916  w->flags &= ~Word::WORD_START;
917 
918  if (i == numBreaks)
919  w->flags |= Word::WORD_END;
920  else
921  w->flags &= ~Word::WORD_END;
922 
923  if (i < numBreaks) {
924  // TODO There should be a method fillHyphen.
925  w->badnessAndPenalty.setPenalties (penalties[PENALTY_HYPHEN][0],
926  penalties[PENALTY_HYPHEN][1]);
927  // "\xe2\x80\x90" is an unconditional hyphen.
928  w->hyphenWidth =
929  layout->textWidth (w->style->font, hyphenDrawChar,
930  strlen (hyphenDrawChar));
931  w->flags |= (Word::DRAW_AS_ONE_TEXT | Word::DIV_CHAR_AT_EOL |
932  Word::UNBREAKABLE_FOR_MIN_WIDTH);
933 
934  PRINTF (" [%d] + hyphen\n", wordIndex + i);
935  } else {
936  if (origWord.content.space) {
937  fillSpace (wordIndex + i, origWord.spaceStyle);
938  PRINTF (" [%d] + space\n", wordIndex + i);
939  } else {
940  PRINTF (" [%d] + nothing\n", wordIndex + i);
941  }
942  }
943 
944  accumulateWordData (wordIndex + i);
945 
946  //printf ("[%p] %d: hyphenated word part: ", this, wordIndex + i);
947  //printWordWithFlags (w);
948  //printf ("\n");
949  }
950 
951  PRINTF (" finished\n");
952 
953  //delete origword->content.text; TODO: Via textZone?
954  origWord.style->unref ();
955  origWord.spaceStyle->unref ();
956 
957  free (breakPos);
958  } else
959  words->getRef(wordIndex)->flags &= ~Word::CAN_BE_HYPHENATED;
960 
961  return numBreaks;
962 }
963 
964 void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
965 {
966  Line *line = lines->getRef (lineIndex);
967  Word *word = words->getRef (wordIndex);
968 
969  PRINTF (" %d + %d / %d + %d\n", line->boxAscent, line->boxDescent,
970  word->size.ascent, word->size.descent);
971 
972  line->boxAscent = misc::max (line->boxAscent, word->size.ascent);
973  line->boxDescent = misc::max (line->boxDescent, word->size.descent);
974 
975  int len = word->style->font->ascent;
976  if (word->style->valign == core::style::VALIGN_SUPER)
977  len += len / 2;
978  line->contentAscent = misc::max (line->contentAscent, len);
979 
980  len = word->style->font->descent;
981  if (word->style->valign == core::style::VALIGN_SUB)
982  len += word->style->font->ascent / 3;
983  line->contentDescent = misc::max (line->contentDescent, len);
984 
985  if (word->content.type == core::Content::WIDGET) {
986  int collapseMarginTop = 0;
987 
988  line->marginDescent =
989  misc::max (line->marginDescent,
990  word->size.descent +
991  word->content.widget->getStyle()->margin.bottom);
992 
993  if (lines->size () == 1 &&
994  word->content.widget->blockLevel () &&
995  getStyle ()->borderWidth.top == 0 &&
996  getStyle ()->padding.top == 0) {
997  // collapse top margins of parent element and its first child
998  // see: http://www.w3.org/TR/CSS21/box.html#collapsing-margins
999  collapseMarginTop = getStyle ()->margin.top;
1000  }
1001 
1002  line->boxAscent =
1003  misc::max (line->boxAscent,
1004  word->size.ascent,
1005  word->size.ascent
1006  + word->content.widget->getStyle()->margin.top
1007  - collapseMarginTop);
1008 
1009  word->content.widget->parentRef = lineIndex;
1010  } else {
1011  line->marginDescent =
1012  misc::max (line->marginDescent, line->boxDescent);
1013 
1014  if (word->content.type == core::Content::BREAK)
1015  line->breakSpace =
1016  misc::max (word->content.breakSpace,
1017  line->marginDescent - line->boxDescent,
1018  line->breakSpace);
1019  }
1020 }
1021 
1022 void Textblock::accumulateWordData (int wordIndex)
1023 {
1024  // Typically, the word in question is in the last line; in any case
1025  // quite at the end of the text, so that linear search is actually
1026  // the fastest option.
1027  int lineIndex = lines->size ();
1028  while (lineIndex > 0 && wordIndex <= lines->getRef(lineIndex - 1)->lastWord)
1029  lineIndex--;
1030 
1031  int firstWordOfLine;
1032  if (lineIndex == 0)
1033  firstWordOfLine = 0;
1034  else
1035  firstWordOfLine = lines->getRef(lineIndex - 1)->lastWord + 1;
1036 
1037  Word *word = words->getRef (wordIndex);
1038  PRINTF ("[%p] ACCUMULATE_WORD_DATA (%d); lineIndex = %d: ...\n",
1039  this, wordIndex, lineIndex);
1040 
1041  int availWidth = calcAvailWidth (lineIndex);
1042 
1043  PRINTF (" (%s existing line %d starts with word %d)\n",
1044  lineIndex < lines->size () ? "already" : "not yet",
1045  lineIndex, firstWordOfLine);
1046 
1047  if (wordIndex == firstWordOfLine) {
1048  // first word of the (not neccessarily yet existing) line
1049  word->totalWidth = word->size.width + word->hyphenWidth;
1050  word->maxAscent = word->size.ascent;
1051  word->maxDescent = word->size.descent;
1052  word->totalSpaceStretchability = 0;
1053  word->totalSpaceShrinkability = 0;
1054  } else {
1055  Word *prevWord = words->getRef (wordIndex - 1);
1056 
1057  word->totalWidth = prevWord->totalWidth
1058  + prevWord->origSpace - prevWord->hyphenWidth
1059  + word->size.width + word->hyphenWidth;
1060  word->maxAscent = misc::max (prevWord->size.ascent, word->size.ascent);
1061  word->maxDescent = misc::max (prevWord->size.descent, word->size.descent);
1062  word->totalSpaceStretchability =
1063  prevWord->totalSpaceStretchability + getSpaceStretchability(prevWord);
1064  word->totalSpaceShrinkability =
1065  prevWord->totalSpaceShrinkability + getSpaceShrinkability(prevWord);
1066  }
1067 
1068  int totalStretchability =
1069  word->totalSpaceStretchability + getLineStretchability (word);
1070  int totalShrinkability =
1071  word->totalSpaceShrinkability + getLineShrinkability (word);
1072  word->badnessAndPenalty.calcBadness (word->totalWidth, availWidth,
1073  totalStretchability,
1074  totalShrinkability);
1075 
1076  //printf (" => ");
1077  //printWord (word);
1078  //printf ("\n");
1079 }
1080 
1081 int Textblock::calcAvailWidth (int lineIndex)
1082 {
1083  int availWidth =
1084  this->availWidth - getStyle()->boxDiffWidth() - innerPadding;
1085  if (limitTextWidth &&
1086  layout->getUsesViewport () &&
1087  availWidth > layout->getWidthViewport () - 10)
1088  availWidth = layout->getWidthViewport () - 10;
1089  if (lineIndex == 0)
1090  availWidth -= line1OffsetEff;
1091 
1092  //PRINTF("[%p] CALC_AVAIL_WIDTH => %d - %d - %d = %d\n",
1093  // this, this->availWidth, getStyle()->boxDiffWidth(), innerPadding,
1094  // availWidth);
1095 
1096  return availWidth;
1097 }
1098 
1099 void Textblock::initLine1Offset (int wordIndex)
1100 {
1101  Word *word = words->getRef (wordIndex);
1102 
1103  /* Test whether line1Offset can be used. */
1104  if (wordIndex == 0) {
1105  if (ignoreLine1OffsetSometimes &&
1106  line1Offset + word->size.width > availWidth) {
1107  line1OffsetEff = 0;
1108  } else {
1109  int indent = 0;
1110 
1111  if (word->content.type == core::Content::WIDGET &&
1112  word->content.widget->blockLevel() == true) {
1113  /* don't use text-indent when nesting blocks */
1114  } else {
1115  if (core::style::isPerLength(getStyle()->textIndent)) {
1117  (this->availWidth, getStyle()->textIndent);
1118  } else {
1119  indent = core::style::absLengthVal (getStyle()->textIndent);
1120  }
1121  }
1122  line1OffsetEff = line1Offset + indent;
1123  }
1124  }
1125 }
1126 
1132 void Textblock::alignLine (int lineIndex)
1133 {
1134  Line *line = lines->getRef (lineIndex);
1135  int availWidth = calcAvailWidth (lineIndex);
1136  Word *firstWord = words->getRef (line->firstWord);
1137  Word *lastWord = words->getRef (line->lastWord);
1138 
1139  for (int i = line->firstWord; i < line->lastWord; i++)
1140  words->getRef(i)->origSpace = words->getRef(i)->effSpace;
1141 
1142  if (firstWord->content.type != core::Content::BREAK) {
1143  switch (firstWord->style->textAlign) {
1145  case core::style::TEXT_ALIGN_STRING: /* handled elsewhere (in the
1146  * future)? */
1147  line->leftOffset = 0;
1148  break;
1149  case core::style::TEXT_ALIGN_JUSTIFY: /* see some lines above */
1150  line->leftOffset = 0;
1151  // Do not justify the last line of a paragraph (which ends on a
1152  // BREAK or with the last word of the page).
1153  if(!(lastWord->content.type == core::Content::BREAK ||
1154  line->lastWord == words->size () - 1) ||
1155  // In some cases, however, an unjustified line would be too wide:
1156  // when the line would be shrunken otherwise. (This solution is
1157  // far from perfect, but a better solution would make changes in
1158  // the line breaking algorithm necessary.)
1159  availWidth < lastWord->totalWidth)
1160  justifyLine (line, availWidth - lastWord->totalWidth);
1161  break;
1163  line->leftOffset = availWidth - lastWord->totalWidth;
1164  break;
1166  line->leftOffset = (availWidth - lastWord->totalWidth) / 2;
1167  break;
1168  default:
1169  /* compiler happiness */
1170  line->leftOffset = 0;
1171  }
1172 
1173  /* For large lines (images etc), which do not fit into the viewport: */
1174  if (line->leftOffset < 0)
1175  line->leftOffset = 0;
1176  }
1177 }
1178 
1185 void Textblock::rewrap ()
1186 {
1187  PRINTF ("[%p] REWRAP: wrapRef = %d\n", this, wrapRef);
1188 
1189  if (wrapRefLines == -1)
1190  /* page does not have to be rewrapped */
1191  return;
1192 
1193  /* All lines up from wrapRef will be rebuild from the word list,
1194  * the line list up from this position is rebuild. */
1195  lines->setSize (wrapRefLines);
1196  nonTemporaryLines = misc::min (nonTemporaryLines, wrapRefLines);
1197 
1198  int firstWord;
1199  if (lines->size () > 0)
1200  firstWord = lines->getLastRef()->lastWord + 1;
1201  else
1202  firstWord = 0;
1203 
1204  for (int i = firstWord; i < words->size (); i++) {
1205  Word *word = words->getRef (i);
1206 
1207  if (word->content.type == core::Content::WIDGET)
1208  calcWidgetSize (word->content.widget, &word->size);
1209 
1210  wordWrap (i, false);
1211 
1212  // Somewhat historical, but still important, note:
1213  //
1214  // For the case that something else is done with this word, it
1215  // is important that wordWrap() may insert some new words; since
1216  // NotSoSimpleVector is used for the words list, the internal
1217  // structure may have changed, so getRef() must be called again.
1218  //
1219  // So this is necessary: word = words->getRef (i);
1220  }
1221 
1222  /* Next time, the page will not have to be rewrapped. */
1223  wrapRefLines = -1;
1224 }
1225 
1229 void Textblock::fillParagraphs ()
1230 {
1231  if (wrapRefParagraphs == -1)
1232  return;
1233 
1234  // Notice that wrapRefParagraphs refers to the lines, not to the paragraphs.
1235  int firstWordOfLine;
1236  if (lines->size () > 0 && wrapRefParagraphs > 0)
1237  firstWordOfLine = lines->getRef(wrapRefParagraphs - 1)->lastWord + 1;
1238  else
1239  firstWordOfLine = 0;
1240 
1241  int parNo;
1242  if (paragraphs->size() > 0 &&
1243  firstWordOfLine > paragraphs->getLastRef()->firstWord)
1244  // A special case: the paragraphs list has been partly built, but
1245  // not yet the paragraph containing the word in question. In
1246  // this case, only the rest of the paragraphs list must be
1247  // constructed. (Without this check, findParagraphOfWord would
1248  // return -1 in this case, so that all paragraphs would be
1249  // rebuilt.)
1250  parNo = paragraphs->size ();
1251  else
1252  // If there are no paragraphs yet, findParagraphOfWord will return
1253  // -1: use 0 then instead.
1254  parNo = misc::max (0, findParagraphOfWord (firstWordOfLine));
1255 
1256  paragraphs->setSize (parNo);
1257 
1258  int firstWord;
1259  if (paragraphs->size () > 0)
1260  firstWord = paragraphs->getLastRef()->lastWord + 1;
1261  else
1262  firstWord = 0;
1263 
1264  PRINTF ("[%p] FILL_PARAGRAPHS: now %d paragraphs; starting from word %d\n",
1265  this, parNo, firstWord);
1266 
1267  for (int i = firstWord; i < words->size (); i++)
1268  handleWordExtremes (i);
1269 
1270  wrapRefParagraphs = -1;
1271 }
1272 
1273 void Textblock::showMissingLines ()
1274 {
1275  int firstWordToWrap = lines->size () > 0 ?
1276  lines->getRef(lines->size () - 1)->lastWord + 1 : 0;
1277  PRINTF ("[%p] SHOW_MISSING_LINES: wrap from %d to %d\n",
1278  this, firstWordToWrap, words->size () - 1);
1279  for (int i = firstWordToWrap; i < words->size (); i++)
1280  wordWrap (i, true);
1281 }
1282 
1283 
1284 void Textblock::removeTemporaryLines ()
1285 {
1286  lines->setSize (nonTemporaryLines);
1287 }
1288 
1289 int Textblock::getSpaceShrinkability(struct Word *word)
1290 {
1292  return word->origSpace / 3;
1293  else
1294  return 0;
1295 }
1296 
1297 int Textblock::getSpaceStretchability(struct Word *word)
1298 {
1300  return word->origSpace / 2;
1301  else
1302  return 0;
1303 
1304  // Alternative: return word->origSpace / 2;
1305 }
1306 
1307 int Textblock::getLineShrinkability(Word *lastWord)
1308 {
1309  return 0;
1310 }
1311 
1312 int Textblock::getLineStretchability(Word *lastWord)
1313 {
1315  return 0;
1316  else
1317  return stretchabilityFactor * (lastWord->maxAscent
1318  + lastWord->maxDescent) / 100;
1319 
1320  // Alternative: return 0;
1321 }
1322 
1323 } // namespace dw
dw::core::style::VALIGN_SUPER
Definition: style.hh:260
dw::Textblock::Line::lastWord
int lastWord
Definition: textblock.hh:309
dw::Textblock::Line::maxLineWidth
int maxLineWidth
Definition: textblock.hh:325
dw::Textblock::Line::contentDescent
int contentDescent
Definition: textblock.hh:313
dw::core::style::TEXT_ALIGN_LEFT
Definition: style.hh:247
dw::core::style::isPerLength
bool isPerLength(Length l)
Returns true if l is a percentage.
Definition: style.hh:406
dw::core::style::absLengthVal
int absLengthVal(Length l)
Returns the value of a length in pixels, as an integer.
Definition: style.hh:412
dw::core::Extremes::maxWidth
int maxWidth
Definition: types.hh:182
dw::Textblock::Paragraph
Definition: textblock.hh:278
dw::core::Requisition
Definition: types.hh:172
dw::Textblock::BadnessAndPenalty::setPenalties
void setPenalties(int penalty1, int penalty2)
Definition: textblock_linebreaking.cc:128
dw::Textblock::BadnessAndPenalty::badnessValue
int badnessValue(int infLevel)
Definition: textblock_linebreaking.cc:35
dw::core::Requisition::descent
int descent
Definition: types.hh:176
dw::core::style::StyleAttrs::margin
Box margin
Definition: style.hh:510
dw::core::style::StyleAttrs::x_lang
char x_lang[2]
Definition: style.hh:524
dw::core::Extremes::minWidth
int minWidth
Definition: types.hh:181
dw::Textblock::Anchor::wordIndex
int wordIndex
Definition: textblock.hh:406
dw::Textblock::BadnessAndPenalty::lineCanBeBroken
bool lineCanBeBroken(int penaltyIndex)
Definition: textblock_linebreaking.cc:173
dw::Textblock::Word::origSpace
short origSpace
Definition: textblock.hh:361
dw::Textblock::BadnessAndPenalty::penaltyValue
int penaltyValue(int index, int infLevel)
Definition: textblock_linebreaking.cc:56
dw::Textblock::Paragraph::parMax
int parMax
Definition: textblock.hh:296
dw::Textblock::BadnessAndPenalty::print
void print()
Definition: textblock_linebreaking.cc:193
lout::misc::assertNotReached
void assertNotReached()
Definition: misc.hh:35
dw::Textblock::Word::maxAscent
int maxAscent
Definition: textblock.hh:382
dw::Textblock::Line::firstWord
int firstWord
Definition: textblock.hh:308
dw::Textblock::Paragraph::lastWord
int lastWord
Definition: textblock.hh:281
dw::core::Content::space
bool space
Definition: types.hh:202
dw::core::Widget::parentRef
int parentRef
This value is defined by the parent widget, and used for incremential resizing.
Definition: widget.hh:143
dw::core::style::TEXT_ALIGN_CENTER
Definition: style.hh:249
dw::Textblock::Paragraph::maxParMax
int maxParMax
Definition: textblock.hh:302
dw::core::Content::text
const char * text
Definition: types.hh:204
dw::core::Widget::getStyle
style::Style * getStyle()
Definition: widget.hh:268
dw::Textblock::Word::totalSpaceShrinkability
int totalSpaceShrinkability
Definition: textblock.hh:384
dw::Textblock::Word
Definition: textblock.hh:328
dw::Textblock::Word::totalSpaceStretchability
int totalSpaceStretchability
Definition: textblock.hh:383
dw::Textblock::Word::maxDescent
int maxDescent
Definition: textblock.hh:382
dw::Textblock::Word::badnessAndPenalty
BadnessAndPenalty badnessAndPenalty
Definition: textblock.hh:385
dw::Textblock::Paragraph::firstWord
int firstWord
Definition: textblock.hh:280
dw::Textblock::Line::contentAscent
int contentAscent
Definition: textblock.hh:313
dw::core::Widget::blockLevel
bool blockLevel()
Definition: widget.hh:264
dw::Textblock::BadnessAndPenalty::lineMustBeBroken
bool lineMustBeBroken(int penaltyIndex)
Definition: textblock_linebreaking.cc:168
lout::misc::max
T max(T a, T b)
Definition: misc.hh:20
lout::misc::min
T min(T a, T b)
Definition: misc.hh:19
dw::core::style::TEXT_ALIGN_RIGHT
Definition: style.hh:248
dw::core::style::Font::ascent
int ascent
Definition: style.hh:673
dw::core::style::multiplyWithPerLengthRounded
int multiplyWithPerLengthRounded(int x, Length l)
Like multiplyWithPerLength, but rounds to nearest integer instead of down.
Definition: style.hh:443
textblock.hh
dw::Textblock::WordImgRenderer::setData
void setData(int xWordWidget, int lineNo)
Definition: textblock.cc:60
dw::Textblock::Line::boxDescent
int boxDescent
Definition: textblock.hh:313
dw::Textblock::Word::style
core::style::Style * style
Definition: textblock.hh:388
dw::Textblock::Paragraph::maxParMin
int maxParMin
Definition: textblock.hh:300
dw::Textblock::Line::marginDescent
int marginDescent
Definition: textblock.hh:318
dw::Textblock::Word::content
core::Content content
Definition: textblock.hh:371
lout::identity::IdentifiableObject::getClassName
const char * getClassName()
Return the name, under which the class of this object was registered.
Definition: identity.hh:138
dw::Textblock::Word::spaceStyle
core::style::Style * spaceStyle
Definition: textblock.hh:389
dw::Textblock::BadnessAndPenalty::calcBadness
void calcBadness(int totalWidth, int idealWidth, int totalStretchability, int totalShrinkability)
Definition: textblock_linebreaking.cc:66
dw::core::Requisition::ascent
int ascent
Definition: types.hh:175
lout
Definition: container.cc:26
dw::Textblock::Word::totalWidth
int totalWidth
Definition: textblock.hh:374
dw::core::style::StyleAttrs::textAlign
TextAlignType textAlign
Definition: style.hh:502
dw::Textblock::BadnessAndPenalty::lineLoose
bool lineLoose()
Definition: textblock_linebreaking.cc:149
dw::Textblock::Line
Definition: textblock.hh:306
dw::core::Requisition::width
int width
Definition: types.hh:174
dw::Textblock::Word::flags
short flags
Definition: textblock.hh:370
dw::Textblock::Line::leftOffset
int leftOffset
Definition: textblock.hh:313
dw::core::style::Style::unref
void unref()
Definition: style.hh:599
dw::Textblock::Word::effSpace
short effSpace
Definition: textblock.hh:362
dw::core::Extremes
Definition: types.hh:179
dw::Hyphenator
Definition: hyphenator.hh:86
dw::core::style::VALIGN_SUB
Definition: style.hh:259
dw::core::Content::breakSpace
int breakSpace
Definition: types.hh:206
dw::core::style::Font::descent
int descent
Definition: style.hh:673
dw::core::style::Box::top
int top
Definition: style.hh:467
dw::core::Content::widget
Widget * widget
Definition: types.hh:205
dw::Textblock::Word::size
core::Requisition size
Definition: textblock.hh:359
dw::Textblock::BadnessAndPenalty::compareTo
int compareTo(int penaltyIndex, BadnessAndPenalty *other)
Definition: textblock_linebreaking.cc:178
dw::core::style::StyleAttrs::font
Font * font
Definition: style.hh:492
hyphenator.hh
dw::Textblock::Line::boxAscent
int boxAscent
Definition: textblock.hh:313
dw::Textblock::Line::top
int top
Definition: textblock.hh:313
dw::Hyphenator::hyphenateWord
int * hyphenateWord(core::Platform *platform, const char *word, int *numBreaks)
Definition: hyphenator.cc:244
dw::Textblock::BadnessAndPenalty
Definition: textblock.hh:166
dw::core::style::TEXT_ALIGN_STRING
Definition: style.hh:251
dw::Textblock::Word::wordImgRenderer
WordImgRenderer * wordImgRenderer
Definition: textblock.hh:394
dw::Textblock::Line::breakSpace
int breakSpace
Definition: textblock.hh:313
dw::Textblock::Word::spaceImgRenderer
SpaceImgRenderer * spaceImgRenderer
Definition: textblock.hh:395
PRINTF
#define PRINTF(fmt,...)
Definition: textblock.hh:11
dw::core::style::Box::bottom
int bottom
Definition: style.hh:467
dw::Textblock::Paragraph::parMin
int parMin
Definition: textblock.hh:293
dw::Textblock::Word::hyphenWidth
short hyphenWidth
Definition: textblock.hh:364
dw::core::style::TEXT_ALIGN_JUSTIFY
Definition: style.hh:250
dw
Dw is in this namespace, or sub namespaces of this one.
Definition: alignedtextblock.cc:26
dw::core::Content::type
short type
Definition: types.hh:201
dw::Textblock::BadnessAndPenalty::lineTight
bool lineTight()
Definition: textblock_linebreaking.cc:156
dw::Textblock::BadnessAndPenalty::setPenalty
void setPenalty(int penalty)
Definition: textblock.hh:211
dw::Textblock::BadnessAndPenalty::lineTooTight
bool lineTooTight()
Definition: textblock_linebreaking.cc:162
dw::core::style::StyleAttrs::valign
VAlignType valign
Definition: style.hh:503
dw::Textblock::Anchor
Definition: textblock.hh:403