diff options
Diffstat (limited to 'dw/textblock_linebreaking.cc')
-rw-r--r-- | dw/textblock_linebreaking.cc | 179 |
1 files changed, 130 insertions, 49 deletions
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index 3a719086..19927b7e 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -342,56 +342,18 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord, Word *word = words->getRef (i); lineWidth += (word->effSpace - word->origSpace); } - - int lastMaxParMax; // maxParMax of the last line - + if (lines->size () == 1) { // first line line->top = 0; - line->maxLineWidth = lineWidth; - line->maxParMin = maxOfMinWidth; - line->parMax = sumOfMaxWidth; - - lastMaxParMax = 0; } else { Line *prevLine = lines->getRef (lines->size () - 2); - line->top = prevLine->top + prevLine->boxAscent + prevLine->boxDescent + prevLine->breakSpace; - line->maxLineWidth = misc::max (lineWidth, prevLine->maxLineWidth); - line->maxParMin = misc::max (maxOfMinWidth, prevLine->maxParMin); - - Word *lastWordOfPrevLine = words->getRef (prevLine->lastWord); - // 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 - // This line continues the paragraph from prevLine. - line->parMax = prevLine->parMax + sumOfMaxWidth; - - lastMaxParMax = prevLine->maxParMax; } - - // "maxParMax" is only set, when this line is the last line of the - // paragraph. - Word *lastWordOfThisLine = words->getRef (line->lastWord); - // 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, - // parMax includes the last space, which we ignore here - line->parMax - lastWordOfThisLine->origSpace - + lastWordOfThisLine->hyphenWidth); - else - // Paragraph continues: simply copy the last value of "maxParMax". - line->maxParMax = lastMaxParMax; - + for(int i = line->firstWord; i <= line->lastWord; i++) accumulateWordForLine (lineIndex, i); @@ -406,11 +368,6 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord, PRINTF (" line[%d].maxLineWidth = %d\n", lines->size () - 1, line->maxLineWidth); - PRINTF (" line[%d].maxParMin = %d\n", - lines->size () - 1, line->maxParMin); - PRINTF (" line[%d].maxParMax = %d\n", - lines->size () - 1, line->maxParMax); - PRINTF (" line[%d].parMax = %d\n", lines->size () - 1, line->parMax); mustQueueResize = true; @@ -462,6 +419,12 @@ void Textblock::accumulateWordExtremes (int firstWord, int lastWord, } } +void Textblock::processWord (int wordIndex) +{ + wordWrap (wordIndex, false); + handleWordExtremes (wordIndex); +} + /* * This method is called in two cases: (i) when a word is added * (ii) when a page has to be (partially) rewrapped. It does word wrap, @@ -666,6 +629,88 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll) } } +void Textblock::handleWordExtremes (int wordIndex) +{ + // TODO Overall, clarify penalty index. + + Word *word = words->getRef (wordIndex); + core::Extremes wordExtremes; + getWordExtremes (word, &wordExtremes); + + PRINTF ("[%p] HANDLE_WORD_EXTREMES (%d):", this, wordIndex); + //printWord (word); + PRINTF ("=> %d / %d\n", wordExtremes.minWidth, wordExtremes.maxWidth); + + if (wordIndex == 0) { + wordExtremes.minWidth += line1Offset; + wordExtremes.maxWidth += line1Offset; + } + + if (paragraphs->size() == 0 || + words->getRef(paragraphs->getLastRef()->lastWord) + ->badnessAndPenalty.lineMustBeBroken (1)) { + // Add a new paragraph. + Paragraph *prevPar = + paragraphs->size() == 0 ? NULL : paragraphs->getLastRef(); + paragraphs->increase (); + Paragraph *par = paragraphs->getLastRef(); + + par->firstWord = par->lastWord = wordIndex; + par->parMin = par->parMax = 0; + + if (prevPar) { + par->maxParMin = prevPar->maxParMin; + par->maxParMax = prevPar->maxParMax; + } else + par->maxParMin = par->maxParMax = 0; + } + + Paragraph *lastPar = paragraphs->getLastRef(); + + int corrDiffMin, corrDiffMax; + if (wordIndex - 1 >= lastPar->firstWord) { + Word *lastWord = words->getRef (wordIndex - 1); + if (lastWord->badnessAndPenalty.lineCanBeBroken (1)) + corrDiffMin = 0; + else + corrDiffMin = lastWord->origSpace - lastWord->hyphenWidth; + + corrDiffMax = lastWord->origSpace - lastWord->hyphenWidth; + } else + corrDiffMin = corrDiffMax = 0; + + PRINTF (" (lastPar from %d to %d; corrDiffMin = %d, corDiffMax = %d)\n", + lastPar->firstWord, lastPar->lastWord, corrDiffMin, corrDiffMax); + + // Minimum: between two *possible* breaks. + // Shrinkability could be considered, but really does not play a role. + lastPar->parMin += wordExtremes.minWidth + word->hyphenWidth + corrDiffMin; + lastPar->maxParMin = misc::max (lastPar->maxParMin, lastPar->parMin); + if (word->badnessAndPenalty.lineCanBeBroken (1)) + lastPar->parMin = 0; + + // Maximum: between two *necessary* breaks. + lastPar->parMax += wordExtremes.maxWidth + word->hyphenWidth + corrDiffMax; + lastPar->maxParMax = misc::max (lastPar->maxParMax, lastPar->parMax); + + PRINTF (" => parMin = %d, parMax = %d\n", + lastPar->parMin, lastPar->parMax); + + lastPar->lastWord = wordIndex; +} + +void Textblock::correctLastWordExtremes () +{ + if (paragraphs->size() > 0) { + if (words->getLastRef()->badnessAndPenalty.lineCanBeBroken (1)) { + paragraphs->getLastRef()->parMin = 0; + PRINTF (" => corrected; parMin = %d\n", + paragraphs->getLastRef()->parMin); + } + } +} + + int Textblock::hyphenateWord (int wordIndex) { Word *hyphenatedWord = words->getRef(wordIndex); @@ -965,14 +1010,14 @@ void Textblock::rewrap () { PRINTF ("[%p] REWRAP: wrapRef = %d\n", this, wrapRef); - if (wrapRef == -1) + if (wrapRefLines == -1) /* page does not have to be rewrapped */ return; /* All lines up from wrapRef will be rebuild from the word list, * the line list up from this position is rebuild. */ - lines->setSize (wrapRef); - nonTemporaryLines = misc::min (nonTemporaryLines, wrapRef); + lines->setSize (wrapRefLines); + nonTemporaryLines = misc::min (nonTemporaryLines, wrapRefLines); int firstWord; if (lines->size () > 0) @@ -999,7 +1044,43 @@ void Textblock::rewrap () } /* Next time, the page will not have to be rewrapped. */ - wrapRef = -1; + wrapRefLines = -1; +} + +void Textblock::fillParagraphs () +{ + if (wrapRefParagraphs == -1) + return; + + // Notice that wrapRefParagraphs refers to the lines, not to the paragraphs. + int firstWordOfLine; + if (lines->size () > 0 && wrapRefParagraphs > 0) + firstWordOfLine = lines->getRef(wrapRefParagraphs - 1)->lastWord + 1; + else + firstWordOfLine = 0; + + // Binary search would be faster, but there should not be many paragraphs + // in a text block (so that binary search may be even slower). + int parNo = 0; + while (paragraphs->size() - 1 > parNo && + paragraphs->getRef(parNo)->lastWord <= firstWordOfLine) + parNo++; + + paragraphs->setSize (parNo); + + int firstWord; + if (paragraphs->size () > 0) + firstWord = paragraphs->getLastRef()->lastWord + 1; + else + firstWord = 0; + + PRINTF ("[%p] FILL_PARAGRAPHS: now %d paragraphs; starting from word %d\n", + this, parNo, firstWord); + + for (int i = firstWord; i < words->size (); i++) + handleWordExtremes (i); + + wrapRefParagraphs = -1; } void Textblock::showMissingLines () |