aboutsummaryrefslogtreecommitdiff
path: root/dw/textblock_linebreaking.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/textblock_linebreaking.cc')
-rw-r--r--dw/textblock_linebreaking.cc142
1 files changed, 79 insertions, 63 deletions
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc
index 09f7edf2..63d482ee 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -31,22 +31,14 @@ int Textblock::BadnessAndPenalty::badnessValue (int infLevel)
return 0;
}
-int Textblock::BadnessAndPenalty::penaltyValue (int infLevel)
+int Textblock::BadnessAndPenalty::penaltyValue (int index, int infLevel)
{
- switch (penaltyState) {
- case FORCE_BREAK:
+ if (penalty[index] == INT_MIN)
return infLevel == INF_PENALTIES ? -1 : 0;
-
- case PROHIBIT_BREAK:
+ else if (penalty[index] == INT_MAX)
return infLevel == INF_PENALTIES ? 1 : 0;
-
- case PENALTY_VALUE:
- return infLevel == INF_VALUE ? penalty : 0;
- }
-
- // compiler happiness
- lout::misc::assertNotReached ();
- return 0;
+ else
+ return infLevel == INF_VALUE ? penalty[index] : 0;
}
void Textblock::BadnessAndPenalty::calcBadness (int totalWidth, int idealWidth,
@@ -98,6 +90,9 @@ void Textblock::BadnessAndPenalty::calcBadness (int totalWidth, int idealWidth,
* to deal with fractional numbers, without having to use floating
* point numbers. So, to set a penalty to 0.5, pass 50.
*
+ * INT_MAX and INT_MIN (representing inf and -inf, respectively) are
+ * also allowed.
+ *
* The definition of penalties depends on the definition of badness,
* which adheres to the description in \ref dw-line-breaking, section
* "Criteria for Line-Breaking". The exact calculation may vary, but
@@ -105,27 +100,28 @@ void Textblock::BadnessAndPenalty::calcBadness (int totalWidth, int idealWidth,
* fitting line has a badness of 0. (ii) A line, where all spaces
* are extended by exactly the stretchability, as well as a line, where
* all spaces are reduced by the shrinkability, have a badness of 1.
+ *
+ * (TODO plural: penalties, not penalty. Correct above comment)
*/
-void Textblock::BadnessAndPenalty::setPenalty (int penalty)
-{
- // This factor consists of: (i) 100^3, since in calcBadness(), the
- // ratio is multiplied with 100 (again, to use integer numbers for
- // fractional numbers), and the badness (which has to be compared
- // to the penalty!) is the third power or it; (ii) the denominator
- // 100, of course, since 100 times the penalty is passed to this
- // method.
- this->penalty = penalty * (100 * 100 * 100 / 100);
- penaltyState = PENALTY_VALUE;
-}
-
-void Textblock::BadnessAndPenalty::setPenaltyProhibitBreak ()
+void Textblock::BadnessAndPenalty::setPenalties (int penalty1, int penalty2)
{
- penaltyState = PROHIBIT_BREAK;
+ // TODO Check here some cases, e.g. both or no penalty INT_MIN.
+ setSinglePenalty(0, penalty1);
+ setSinglePenalty(1, penalty2);
}
-void Textblock::BadnessAndPenalty::setPenaltyForceBreak ()
+void Textblock::BadnessAndPenalty::setSinglePenalty (int index, int penalty)
{
- penaltyState = FORCE_BREAK;
+ if (penalty == INT_MAX || penalty == INT_MIN)
+ this->penalty[index] = penalty;
+ else
+ // This factor consists of: (i) 100^3, since in calcBadness(), the
+ // ratio is multiplied with 100 (again, to use integer numbers for
+ // fractional numbers), and the badness (which has to be compared
+ // to the penalty!) is the third power or it; (ii) the denominator
+ // 100, of course, since 100 times the penalty is passed to this
+ // method.
+ this->penalty[index] = penalty * (100 * 100 * 100 / 100);
}
bool Textblock::BadnessAndPenalty::lineLoose ()
@@ -147,21 +143,23 @@ bool Textblock::BadnessAndPenalty::lineTooTight ()
}
-bool Textblock::BadnessAndPenalty::lineMustBeBroken ()
+bool Textblock::BadnessAndPenalty::lineMustBeBroken (int penaltyIndex)
{
- return penaltyState == FORCE_BREAK;
+ return penalty[penaltyIndex] == PENALTY_FORCE_BREAK;
}
-bool Textblock::BadnessAndPenalty::lineCanBeBroken ()
+bool Textblock::BadnessAndPenalty::lineCanBeBroken (int penaltyIndex)
{
- return penaltyState != PROHIBIT_BREAK;
+ return penalty[penaltyIndex] != PENALTY_PROHIBIT_BREAK;
}
-int Textblock::BadnessAndPenalty::compareTo (BadnessAndPenalty *other)
+int Textblock::BadnessAndPenalty::compareTo (int penaltyIndex,
+ BadnessAndPenalty *other)
{
for (int l = INF_MAX; l >= 0; l--) {
- int thisValue = badnessValue (l) + penaltyValue (l);
- int otherValue = other->badnessValue (l) + other->penaltyValue (l);
+ int thisValue = badnessValue (l) + penaltyValue (penaltyIndex, l);
+ int otherValue =
+ other->badnessValue (l) + other->penaltyValue (penaltyIndex, l);
if (thisValue != otherValue)
return thisValue - otherValue;
@@ -197,19 +195,19 @@ void Textblock::BadnessAndPenalty::print ()
printf (" <no debug> + ");
#endif
- switch (penaltyState) {
- case FORCE_BREAK:
- printf ("-inf");
- break;
-
- case PROHIBIT_BREAK:
- printf ("inf");
- break;
+ printf ("(");
+ for (int i = 0; i < 2; i++) {
+ if (penalty[i] == INT_MIN)
+ printf ("-inf");
+ else if (penalty[i] == INT_MAX)
+ printf ("inf");
+ else
+ printf ("%d", penalty[i]);
- case PENALTY_VALUE:
- printf ("%d", penalty);
- break;
+ if (i == 0)
+ printf (", ");
}
+ printf (")");
}
void Textblock::printWord (Word *word)
@@ -219,15 +217,17 @@ void Textblock::printWord (Word *word)
printf ("\"%s\"", word->content.text);
break;
case core::Content::WIDGET:
- printf ("<widget: %p>\n", word->content.widget);
+ printf ("<widget: %p>", word->content.widget);
break;
case core::Content::BREAK:
- printf ("<break>\n");
+ printf ("<break>");
break;
default:
- printf ("<?>\n");
+ printf ("<?>");
break;
}
+
+ printf (" (flags = %d)", word->flags);
printf (" [%d / %d + %d - %d => %d + %d - %d] => ",
word->size.width, word->origSpace, word->stretchability,
@@ -356,7 +356,9 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
line->maxParMin = misc::max (maxOfMinWidth, prevLine->maxParMin);
Word *lastWordOfPrevLine = words->getRef (prevLine->lastWord);
- if (lastWordOfPrevLine->badnessAndPenalty.lineMustBeBroken ())
+ // TODO: lineMustBeBroken should be independent of the penalty
+ // index? Otherwise, examine the last line.
+ if (lastWordOfPrevLine->badnessAndPenalty.lineMustBeBroken (0))
// This line starts a new paragraph.
line->parMax = sumOfMaxWidth;
else
@@ -369,7 +371,9 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
// "maxParMax" is only set, when this line is the last line of the
// paragraph.
Word *lastWordOfThisLine = words->getRef (line->lastWord);
- if (lastWordOfThisLine->badnessAndPenalty.lineMustBeBroken ())
+ // TODO: lineMustBeBroken should be independent of the penalty
+ // index? Otherwise, examine the last line.
+ if (lastWordOfThisLine->badnessAndPenalty.lineMustBeBroken (0))
// Paragraph ends here.
line->maxParMax =
misc::max (lastMaxParMax,
@@ -420,7 +424,8 @@ void Textblock::accumulateWordExtremes (int firstWord, int lastWord,
// Minimum: between two *possible* breaks (or at the end).
// TODO This is redundant to getExtremesImpl().
- if (word->badnessAndPenalty.lineCanBeBroken () || atLastWord) {
+ // TODO: Again, index 1 is used for lineCanBeBroken(). See getExtremes().
+ if (word->badnessAndPenalty.lineCanBeBroken (1) || atLastWord) {
parMin += extremes.minWidth + word->hyphenWidth;
*maxOfMinWidth = misc::max (*maxOfMinWidth, parMin);
parMin = 0;
@@ -465,6 +470,8 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
accumulateWordData (wordIndex);
+ int penaltyIndex = calcPenaltyIndexForNewLine ();
+
bool newLine;
do {
bool tempNewLine = false;
@@ -478,14 +485,16 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
tempNewLine = true;
PRINTF (" NEW LINE: last word\n");
} else if (wordIndex >= firstIndex &&
- word->badnessAndPenalty.lineMustBeBroken ()) {
+ // TODO: lineMustBeBroken should be independent of
+ // the penalty index?
+ word->badnessAndPenalty.lineMustBeBroken (penaltyIndex)) {
newLine = true;
searchUntil = wordIndex;
PRINTF (" NEW LINE: forced break\n");
} else if (wordIndex > firstIndex &&
word->badnessAndPenalty.lineTooTight () &&
words->getRef(wordIndex- 1)
- ->badnessAndPenalty.lineCanBeBroken ()) {
+ ->badnessAndPenalty.lineCanBeBroken (penaltyIndex)) {
// TODO Comment the last condition (also below where the minimum is
// searched for)
newLine = true;
@@ -524,7 +533,8 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
if (breakPos == -1 ||
w->badnessAndPenalty.compareTo
- (&words->getRef(breakPos)->badnessAndPenalty) <= 0)
+ (penaltyIndex,
+ &words->getRef(breakPos)->badnessAndPenalty) <= 0)
// "<=" instead of "<" in the next lines tends to result in
// more words per line -- theoretically. Practically, the
// case "==" will never occur.
@@ -548,7 +558,8 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
BadnessAndPenalty correctedBap = lastWord->badnessAndPenalty;
correctedBap.setPenalty (0);
if (correctedBap.compareTo
- (&words->getRef(breakPos)->badnessAndPenalty) <= 0) {
+ (penaltyIndex,
+ &words->getRef(breakPos)->badnessAndPenalty) <= 0) {
breakPos = searchUntil;
PRINTF (" corrected: breakPos = %d\n", breakPos);
}
@@ -561,7 +572,7 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
PRINTF ("\n");
if (word1->badnessAndPenalty.lineTight () &&
- word1->canBeHyphenated &&
+ (word1->flags & Word::CAN_BE_HYPHENATED) &&
word1->style->x_lang[0] &&
word1->content.type == core::Content::TEXT &&
Hyphenator::isHyphenationCandidate (word1->content.text))
@@ -570,7 +581,7 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
if (word1->badnessAndPenalty.lineLoose () &&
breakPos + 1 < words->size ()) {
Word *word2 = words->getRef(breakPos + 1);
- if (word2->canBeHyphenated &&
+ if ((word2->flags & Word::CAN_BE_HYPHENATED) &&
word2->style->x_lang[0] &&
word2->content.type == core::Content::TEXT &&
Hyphenator::isHyphenationCandidate (word2->content.text))
@@ -587,6 +598,7 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll)
tempNewLine ? "temporally" : "permanently",
firstIndex, breakPos);
lineAdded = true;
+ penaltyIndex = calcPenaltyIndexForNewLine ();
} else {
// TODO hyphenateWord() should return whether something has
// changed at all. So that a second run, with
@@ -690,10 +702,15 @@ int Textblock::hyphenateWord (int wordIndex)
// Note: there are numBreaks + 1 word parts.
if (i < numBreaks) {
// TODO There should be a method fillHyphen.
- w->badnessAndPenalty.setPenalty (HYPHEN_BREAK);
+ w->badnessAndPenalty.setPenalties (penalties[PENALTY_HYPHEN][0],
+ penalties[PENALTY_HYPHEN][1]);
+ // "\xe2\x80\x90" is an unconditional hyphen.
w->hyphenWidth =
layout->textWidth (w->style->font, hyphenDrawChar,
strlen (hyphenDrawChar));
+ w->flags |= (Word::DRAW_AS_ONE_TEXT | Word::DIV_CHAR_AT_EOL |
+ Word::UNBREAKABLE_FOR_MIN_WIDTH);
+
PRINTF (" [%d] + hyphen\n", wordIndex + i);
} else {
if (origWord.content.space) {
@@ -714,9 +731,8 @@ int Textblock::hyphenateWord (int wordIndex)
origWord.spaceStyle->unref ();
free (breakPos);
- } else {
- words->getRef(wordIndex)->canBeHyphenated = false;
- }
+ } else
+ words->getRef(wordIndex)->flags &= ~Word::CAN_BE_HYPHENATED;
return numBreaks;
}