diff options
author | sgeerken <devnull@localhost> | 2012-06-27 16:12:17 +0200 |
---|---|---|
committer | sgeerken <devnull@localhost> | 2012-06-27 16:12:17 +0200 |
commit | d3dd7eb3379c495cfd9a138d36e40a410188f202 (patch) | |
tree | 28506b276d4705780475af1a9dd611f04f157822 /dw | |
parent | 8549cdf4519e800fb0f56ebb48490a6e202418cf (diff) |
First version of automatic hyphenation. (Still a large number of bugs.)
Diffstat (limited to 'dw')
-rw-r--r-- | dw/hyphenator.cc | 4 | ||||
-rw-r--r-- | dw/layout.hh | 5 | ||||
-rw-r--r-- | dw/textblock.hh | 1 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 226 |
4 files changed, 179 insertions, 57 deletions
diff --git a/dw/hyphenator.cc b/dw/hyphenator.cc index 998b7975..b617993a 100644 --- a/dw/hyphenator.cc +++ b/dw/hyphenator.cc @@ -134,7 +134,7 @@ Vector <String> *Hyphenator::hyphenateWord(const char *word) { Vector <String> *pieces = new Vector <String> (1, true); - if (!isHyphenationCandidate (word) <= 4) { + if (!isHyphenationCandidate (word)) { pieces->put (new String (word)); return pieces; } @@ -184,7 +184,7 @@ Vector <String> *Hyphenator::hyphenateWord(const char *word) points.put (new Integer (0), 2); points.put (new Integer (0), points.size () - 2); points.put (new Integer (0), points.size () - 3); - + // Examine the points to build the pieces list. char temp[strlen (word) + 1], *ptemp = temp; diff --git a/dw/layout.hh b/dw/layout.hh index 45187490..4b80456b 100644 --- a/dw/layout.hh +++ b/dw/layout.hh @@ -290,6 +290,11 @@ public: void scrollPosChanged (View *view, int x, int y); void viewportSizeChanged (View *view, int width, int height); + inline Platform *getPlatform () + { + return platform; + } + /* delegated */ inline int textWidth (style::Font *font, const char *text, int len) diff --git a/dw/textblock.hh b/dw/textblock.hh index b06bc3c7..124f81be 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -435,6 +435,7 @@ protected: void accumulateWordExtremees (int firstWord, int lastWord, int *maxOfMinWidth, int *sumOfMaxWidth); virtual void wordWrap (int wordIndex, bool wrapAll); + void hyphenateWord (int wordIndex); void accumulateWordForLine (int lineIndex, int wordIndex); void accumulateWordData(int wordIndex); int calcAvailWidth (); diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index 430f51aa..3d612097 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -398,71 +398,187 @@ void Textblock::wordWrap (int wordIndex, bool wrapAll) accumulateWordData (wordIndex); - int breakPos = -1; - for (int i = firstIndex; i <= searchUntil; i++) { - Word *w = words->getRef(i); - - if(word->content.type && core::Content::REAL_CONTENT) { - PRINTF (" %d (of %d): ", i, words->size ()); - - switch(w->content.type) { - case core::Content::TEXT: - PRINTF ("\"%s\"", w->content.text); - break; - case core::Content::WIDGET: - PRINTF ("<widget: %p>\n", w->content.widget); - break; - case core::Content::BREAK: - PRINTF ("<break>\n"); - break; - default: - PRINTF ("<?>\n"); - break; + bool lineAdded; + do { + int breakPos = -1; + for (int i = firstIndex; i <= searchUntil; i++) { + Word *w = words->getRef(i); + + if(word->content.type && core::Content::REAL_CONTENT) { + PRINTF (" %d (of %d): ", i, words->size ()); + + switch(w->content.type) { + case core::Content::TEXT: + PRINTF ("\"%s\"", w->content.text); + break; + case core::Content::WIDGET: + PRINTF ("<widget: %p>\n", w->content.widget); + break; + case core::Content::BREAK: + PRINTF ("<break>\n"); + break; + default: + PRINTF ("<?>\n"); + break; + } + + PRINTF (" [%d / %d + %d - %d] => ", + w->size.width, w->origSpace, w->stretchability, + w->shrinkability); + w->badnessAndPenalty.print (); + PRINTF ("\n"); } + + + // TODO: is this condition needed: + // if(w->badnessAndPenalty.lineCanBeBroken ()) ? + + if (breakPos == -1 || + w->badnessAndPenalty.compareTo + (&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. + breakPos = i; + } + + if (wrapAll && searchUntil == words->size () - 1) { + // Since no break and no space is added, the last word + // will have a penalty of inf. Actually, it should be -inf, + // since it is the last word. However, since more words may + // follow, the penalty is not changesd, but here, the search + // is corrected (maybe only temporary). + Word *lastWord = words->getRef (searchUntil); + BadnessAndPenalty correctedBap = lastWord->badnessAndPenalty; + correctedBap.setPenaltyForceBreak (); + if (correctedBap.compareTo + (&words->getRef(breakPos)->badnessAndPenalty) <= 0) + breakPos = searchUntil; + } - PRINTF (" [%d / %d + %d - %d] => ", - w->size.width, w->origSpace, w->stretchability, - w->shrinkability); - w->badnessAndPenalty.print (); - PRINTF ("\n"); + PRINTF ("breakPos = %d\n", breakPos); + + int hyphenatedWord = -1; + Word *word1 = words->getRef(breakPos); + if (word1->badnessAndPenalty.lineTight () && + word1->canBeHyphenated && + word1->content.type == core::Content::TEXT && + Hyphenator::isHyphenationCandidate (word1->content.text)) + hyphenatedWord = breakPos; + + if (word1->badnessAndPenalty.lineLoose () && + breakPos + 1 < words->size ()) { + Word *word2 = words->getRef(breakPos + 1); + if (word2->canBeHyphenated && + word2->content.type == core::Content::TEXT && + Hyphenator::isHyphenationCandidate (word2->content.text)) + hyphenatedWord = breakPos + 1; + } + + if(hyphenatedWord == -1) { + PRINTF (" new line from %d to %d\n", firstIndex, breakPos); + addLine (firstIndex, breakPos, tempNewLine); + lineAdded = true; + PRINTF (" accumulating again from %d to %d\n", + breakPos + 1, wordIndex); + } else { + hyphenateWord (hyphenatedWord); + lineAdded = false; } + for(int i = breakPos + 1; i <= wordIndex; i++) + accumulateWordData (i); + + } while(!lineAdded); + } + } while (newLine); +} - // TODO: is this condition needed: - // if(w->badnessAndPenalty.lineCanBeBroken ()) ? +void Textblock::hyphenateWord (int wordIndex) +{ + Word *word = words->getRef(wordIndex); + printf (" considering to hyphenate word %d: '%s'\n", + wordIndex, word->content.text); - if (breakPos == -1 || - w->badnessAndPenalty.compareTo - (&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. - breakPos = i; + Hyphenator *hyphenator = + Hyphenator::getHyphenator (layout->getPlatform (), "de"); // TODO lang + + // TODO Change interface of Hyphenator. + container::typed::Vector <object::String> *pieces = + hyphenator->hyphenateWord (word->content.text); + if (pieces->size () > 1) { + int numBreaks = pieces->size () - 1; + int breakPos[numBreaks]; + for (int i = 0; i < numBreaks; i++) + breakPos[i] = + strlen (pieces->get(i)->chars()) + (i == 0 ? 0 : breakPos[i - 1]); + + for (int i = 0; i < numBreaks; i++) + printf (" breakPos[%d]: %d\n", i, breakPos[i]); + + // TODO unref also spaceStyle and hyphenStyle + + const char *origText = word->content.text; + int lenOrigText = strlen (origText); + core::style::Style *origStyle = word->style; + core::Requisition wordSize[numBreaks + 1]; + + calcTextSizes (origText, lenOrigText, origStyle, numBreaks, breakPos, + wordSize); + + printf (" ... %d words ...\n", words->size ()); + words->insert (wordIndex, numBreaks); + printf (" ... -> %d words.\n", words->size ()); + + for (int i = 0; i < numBreaks + 1; i++) { + Word *w = words->getRef (wordIndex + i); + + fillWord (w, wordSize[i].width, wordSize[i].ascent, + wordSize[i].descent, false, origStyle); + + // TODO There should be a method fillText0. + w->content.type = core::Content::TEXT; + + int start = (i == 0 ? 0 : breakPos[i - 1]); + int end = (i == numBreaks ? lenOrigText : breakPos[i]); + w->content.text = + layout->textZone->strndup(origText + start, end - start); + //printf (" '%s' from %d to %d => '%s'\n", + // origText, start, end, w->content.text); + + printf (" [%d] -> '%s'\n", wordIndex + i, w->content.text); + + if (i < numBreaks - 1) { + // TODO There should be a method fillHyphen. + w->badnessAndPenalty.setPenalty (HYPHEN_BREAK); + w->hyphenWidth = layout->textWidth (origStyle->font, "\xc2\xad", 2); + } else { + // TODO There should be a method fillSpace. + // TODO Add original space. +#if 0 + w->badnessAndPenalty.setPenalty (0); + w->content.space = true; + w->effSpace = word->origSpace = origStyle->font->spaceWidth + + origStyle->wordSpacing; + w->stretchability = w->origSpace / 2; + if(origStyle->textAlign == core::style::TEXT_ALIGN_JUSTIFY) + w->shrinkability = w->origSpace / 3; + else + w->shrinkability = 0; +#endif } - if (wrapAll && searchUntil == words->size () - 1) { - // Since no break and no space is added, the last word - // will have a penalty of inf. Actually, it should be -inf, - // since it is the last word. However, since more words may - // follow, the penalty is not changesd, but here, the search - // is corrected (maybe only temporary). - Word *lastWord = words->getRef (searchUntil); - BadnessAndPenalty correctedBap = lastWord->badnessAndPenalty; - correctedBap.setPenaltyForceBreak (); - if (correctedBap.compareTo - (&words->getRef(breakPos)->badnessAndPenalty) <= 0) - breakPos = searchUntil; - } + accumulateWordData (wordIndex + i); + } - PRINTF (" new line from %d to %d\n", firstIndex, breakPos); - addLine (firstIndex, breakPos, tempNewLine); - PRINTF (" accumulating again from %d to %d\n", - breakPos + 1, wordIndex); + printf (" finished\n"); + + //delete origText; TODO: Via textZone? + origStyle->unref (); + } else + word->canBeHyphenated = false; - for(int i = breakPos + 1; i <= wordIndex; i++) - accumulateWordData (i); - } - } while (newLine); + delete pieces; } void Textblock::accumulateWordForLine (int lineIndex, int wordIndex) |