diff options
author | Sebastian Geerken <devnull@localhost> | 2013-02-16 21:29:19 +0100 |
---|---|---|
committer | Sebastian Geerken <devnull@localhost> | 2013-02-16 21:29:19 +0100 |
commit | 8ab7e93fc073a82ecb65884190ff1e21a22625b6 (patch) | |
tree | e0971271330dee9cd7dbf5bc5720908e844f235f | |
parent | 896e8781c2b9ee3ab733c60ba574e750b3a6ee09 (diff) |
'text-transform: capitalize' and hyphenation now play together. (Comments are missing.)
-rw-r--r-- | dw/textblock.cc | 171 | ||||
-rw-r--r-- | dw/textblock.hh | 10 | ||||
-rw-r--r-- | dw/textblock_iterator.cc | 11 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 20 |
4 files changed, 141 insertions, 71 deletions
diff --git a/dw/textblock.cc b/dw/textblock.cc index f7774971..769263aa 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -687,13 +687,24 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, } if (word->content.type == core::Content::TEXT) { int glyphX = wordStartX; + int isStartWord = word->flags & Word::WORD_START; + int isEndWord = word->flags & Word::WORD_END; while (1) { int nextCharPos = layout->nextGlyph (word->content.text, charPos); + // TODO The width of a text is not the sum + // of the widths of the glyphs, because of + // ligatures, kerning etc., so textWidth + // should be applied to the text from 0 to + // nextCharPos. (Or not? See comment below.) + int glyphWidth = textWidth (word->content.text, charPos, - nextCharPos - charPos, word->style); + nextCharPos - charPos, word->style, + isStartWord && charPos == 0, + isEndWord && + word->content.text[nextCharPos] == 0); if (event->xWidget > glyphX + glyphWidth) { glyphX += glyphWidth; charPos = nextCharPos; @@ -708,7 +719,11 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, charPos); if (textWidth (word->content.text, charPos, nextCharPos - charPos, - word->style)) + word->style, + isStartWord && charPos == 0, + isEndWord && + word->content.text[nextCharPos] + == 0)) break; charPos = nextCharPos; } @@ -839,7 +854,8 @@ void Textblock::decorateText(core::View *view, core::style::Style *style, */ void Textblock::drawText(core::View *view, core::style::Style *style, core::style::Color::Shading shading, int x, int y, - const char *text, int start, int len) + const char *text, int start, int len, bool isStart, + bool isEnd) { if (len > 0) { char *str = NULL; @@ -855,34 +871,34 @@ void Textblock::drawText(core::View *view, core::style::Style *style, str = layout->textToLower(text + start, len); break; case core::style::TEXT_TRANSFORM_CAPITALIZE: - { - /* \bug No way to know about non-ASCII punctuation. */ - bool initial_seen = false; - - for (int i = 0; i < start; i++) - if (!ispunct(text[i])) - initial_seen = true; - if (initial_seen) - break; - - int after = 0; - text += start; - while (ispunct(text[after])) - after++; - if (text[after]) - after = layout->nextGlyph(text, after); - if (after > len) - after = len; - - char *initial = layout->textToUpper(text, after); - int newlen = strlen(initial) + len-after; - str = (char *)malloc(newlen + 1); - strcpy(str, initial); - strncpy(str + strlen(str), text+after, len-after); - str[newlen] = '\0'; - free(initial); + if (isStart) { + /* \bug No way to know about non-ASCII punctuation. */ + bool initial_seen = false; + + for (int i = 0; i < start; i++) + if (!ispunct(text[i])) + initial_seen = true; + if (initial_seen) + break; + + int after = 0; + text += start; + while (ispunct(text[after])) + after++; + if (text[after]) + after = layout->nextGlyph(text, after); + if (after > len) + after = len; + + char *initial = layout->textToUpper(text, after); + int newlen = strlen(initial) + len-after; + str = (char *)malloc(newlen + 1); + strcpy(str, initial); + strncpy(str + strlen(str), text+after, len-after); + str[newlen] = '\0'; + free(initial); + } break; - } } view->drawText(style->font, style->color, shading, x, y, @@ -969,8 +985,10 @@ void Textblock::drawWord0 (int wordIndex1, int wordIndex2, } yWorldBase = yWidgetBase + allocation.y; + bool isStartTotal = words->getRef(wordIndex1)->flags & Word::WORD_START; + bool isEndTotal = words->getRef(wordIndex2)->flags & Word::WORD_START; drawText (view, style, core::style::Color::SHADING_NORMAL, xWorld, - yWorldBase, text, 0, strlen (text)); + yWorldBase, text, 0, strlen (text), isStartTotal, isEndTotal); if (style->textDecoration) decorateText(view, style, core::style::Color::SHADING_NORMAL, xWorld, @@ -1012,14 +1030,18 @@ void Textblock::drawWord0 (int wordIndex1, int wordIndex2, xStart = xWorld; if (firstCharIdx) - xStart += textWidth (text, 0, firstCharIdx, style); + xStart += textWidth (text, 0, firstCharIdx, style, + isStartTotal, + isEndTotal && text[firstCharIdx] == 0); // With a hyphen, the width is a bit longer than totalWidth, // and so, the optimization to use totalWidth is not correct. if (!drawHyphen && firstCharIdx == 0 && lastCharIdx == wordLen) width = totalWidth; else width = textWidth (text, firstCharIdx, - lastCharIdx - firstCharIdx, style); + lastCharIdx - firstCharIdx, style, + isStartTotal && firstCharIdx == 0, + isEndTotal && text[lastCharIdx] == 0); if (width > 0) { /* Highlight text */ core::style::Color *wordBgColor; @@ -1036,7 +1058,9 @@ void Textblock::drawWord0 (int wordIndex1, int wordIndex2, /* Highlight the text. */ drawText (view, style, core::style::Color::SHADING_INVERSE, xStart, yWorldBase, text, firstCharIdx, - lastCharIdx - firstCharIdx); + lastCharIdx - firstCharIdx, + isStartTotal && firstCharIdx == 0, + isEndTotal && lastCharIdx == wordLen); if (style->textDecoration) decorateText(view, style, core::style::Color::SHADING_INVERSE, @@ -1341,7 +1365,7 @@ void Textblock::fillWord (Word *word, int width, int ascent, int descent, * Get the width of a string of text. */ int Textblock::textWidth(const char *text, int start, int len, - core::style::Style *style) + core::style::Style *style, bool isStart, bool isEnd) { int ret = 0; @@ -1362,35 +1386,38 @@ int Textblock::textWidth(const char *text, int start, int len, ret = layout->textWidth(style->font, str, strlen(str)); break; case core::style::TEXT_TRANSFORM_CAPITALIZE: - { - /* \bug No way to know about non-ASCII punctuation. */ - bool initial_seen = false; - - for (int i = 0; i < start; i++) - if (!ispunct(text[i])) - initial_seen = true; - if (initial_seen) { - ret = layout->textWidth(style->font, text+start, len); - } else { - int after = 0; - - text += start; - while (ispunct(text[after])) - after++; - if (text[after]) - after = layout->nextGlyph(text, after); - if (after > len) - after = len; - str = layout->textToUpper(text, after); - ret = layout->textWidth(style->font, str, strlen(str)) + + if (isStart) { + /* \bug No way to know about non-ASCII punctuation. */ + bool initial_seen = false; + + for (int i = 0; i < start; i++) + if (!ispunct(text[i])) + initial_seen = true; + if (initial_seen) { + ret = layout->textWidth(style->font, text+start, len); + } else { + int after = 0; + + text += start; + while (ispunct(text[after])) + after++; + if (text[after]) + after = layout->nextGlyph(text, after); + if (after > len) + after = len; + str = layout->textToUpper(text, after); + ret = layout->textWidth(style->font, str, strlen(str)) + layout->textWidth(style->font, text+after, len-after); - } + } + } else + ret = layout->textWidth(style->font, text+start, len); break; - } } + if (str) free(str); } + return ret; } @@ -1399,9 +1426,9 @@ int Textblock::textWidth(const char *text, int start, int len, */ void Textblock::calcTextSize (const char *text, size_t len, core::style::Style *style, - core::Requisition *size) + core::Requisition *size, bool isStart, bool isEnd) { - size->width = textWidth (text, 0, len, style); + size->width = textWidth (text, 0, len, style, isStart, isEnd); size->ascent = style->font->ascent; size->descent = style->font->descent; @@ -1479,8 +1506,14 @@ void Textblock::addText (const char *text, size_t len, // Simple (and common) case: no dividing characters. May still // be hyphenated automatically. core::Requisition size; - calcTextSize (text, len, style, &size); - addText0 (text, len, Word::CAN_BE_HYPHENATED, style, &size); + calcTextSize (text, len, style, &size, true, true); + addText0 (text, len, + Word::CAN_BE_HYPHENATED | Word::WORD_START | Word::WORD_END, + style, &size); + + //printf ("[%p] %d: added simple word: ", this, words->size() - 1); + //printWordWithFlags (words->getLastRef()); + //printf ("\n"); } else { PRINTF ("HYPHENATION: '"); for (size_t i = 0; i < len; i++) @@ -1612,10 +1645,19 @@ void Textblock::addText (const char *text, size_t len, flags |= Word::DRAW_AS_ONE_TEXT; } + + if (i == 0) + flags |= Word::WORD_START; + if (i == numParts - 1) + flags |= Word::WORD_END; addText0 (text + partStart[i], partEnd[i] - partStart[i], flags, style, &wordSize[i]); + //printf ("[%p] %d: added word part: ", this, words->size() - 1); + //printWordWithFlags (words->getLastRef()); + //printf ("\n"); + //PRINTF("H... [%d] '", i); //for (int j = partStart[i]; j < partEnd[i]; j++) // PUTCHAR(text[j]); @@ -1653,7 +1695,7 @@ void Textblock::calcTextSizes (const char *text, size_t textLen, // The size of the last part is calculated in a simple way. int lastStart = breakPos[numBreaks - 1]; calcTextSize (text + lastStart, textLen - lastStart, style, - &wordSize[numBreaks]); + &wordSize[numBreaks], true, true); PRINTF("H... [%d] '", numBreaks); for (size_t i = 0; i < textLen - lastStart; i++) @@ -1664,7 +1706,8 @@ void Textblock::calcTextSizes (const char *text, size_t textLen, // "Hyphens". for (int i = numBreaks - 1; i >= 0; i--) { int start = (i == 0) ? 0 : breakPos[i - 1]; - calcTextSize (text + start, textLen - start, style, &wordSize[i]); + calcTextSize (text + start, textLen - start, style, &wordSize[i], + i == 0, i == numBreaks - 1); PRINTF("H... [%d] '", i); for (size_t j = 0; j < textLen - start; j++) diff --git a/dw/textblock.hh b/dw/textblock.hh index 7f435e6b..d3b158d2 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -309,6 +309,9 @@ protected: * do not consider this word as breakable. This flag is * ignored when the line is actually broken. */ UNBREAKABLE_FOR_MIN_WIDTH = 1 << 4, + + WORD_START = 1 << 5, + WORD_END = 1 << 6 }; /* TODO: perhaps add a xLeft? */ @@ -453,7 +456,8 @@ protected: int x, int yBase, int width); void drawText (core::View *view, core::style::Style *style, core::style::Color::Shading shading, int x, int y, - const char *text, int start, int len); + const char *text, int start, int len, bool isStart, + bool isEnd); void drawWord (Line *line, int wordIndex1, int wordIndex2, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase); void drawWord0 (int wordIndex1, int wordIndex2, @@ -475,9 +479,9 @@ protected: void fillSpace (Word *word, core::style::Style *style); void setBreakOption (Word *word, core::style::Style *style); int textWidth (const char *text, int start, int len, - core::style::Style *style); + core::style::Style *style, bool isStart, bool isEnd); void calcTextSize (const char *text, size_t len, core::style::Style *style, - core::Requisition *size); + core::Requisition *size, bool isStart, bool isEnd); /** * \brief Returns the x offset (the indentation plus any offset needed for diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc index 245df374..c6aaab57 100644 --- a/dw/textblock_iterator.cc +++ b/dw/textblock_iterator.cc @@ -189,7 +189,10 @@ void Textblock::TextblockIterator::getAllocation (int start, int end, } if (start > 0 && word->content.type == core::Content::TEXT) { allocation->x += textblock->textWidth (word->content.text, 0, start, - word->style); + word->style, + word->flags & Word::WORD_START, + (word->flags & Word::WORD_END) + && word->content.text[start] == 0); } allocation->y = textblock->lineYOffsetCanvas (line) + line->boxAscent - word->size.ascent; @@ -202,7 +205,11 @@ void Textblock::TextblockIterator::getAllocation (int start, int end, end = misc::min(end, wordEnd); /* end could be INT_MAX */ allocation->width = textblock->textWidth (word->content.text, start, end - start, - word->style); + word->style, + (word->flags & Word::WORD_START) + && start == 0, + (word->flags & Word::WORD_END) + && word->content.text[end] == 0); } } allocation->ascent = word->size.ascent; diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index 35273565..2375c988 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -229,12 +229,14 @@ void Textblock::printWordShort (Word *word) void Textblock::printWordFlags (short flags) { - printf ("%s:%s:%s:%s:%s", + printf ("%s:%s:%s:%s:%s:%s:%s", (flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--", (flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--", (flags & Word::PERM_DIV_CHAR) ? "dp" : "--", (flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--", - (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--"); + (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--", + (flags & Word::WORD_START) ? "st" : "--", + (flags & Word::WORD_END) ? "en" : "--"); } void Textblock::printWordWithFlags (Word *word) @@ -797,6 +799,16 @@ int Textblock::hyphenateWord (int wordIndex) PRINTF (" [%d] -> '%s'\n", wordIndex + i, w->content.text); // Note: there are numBreaks + 1 word parts. + if (i == 0) + w->flags |= Word::WORD_START; + else + w->flags &= ~Word::WORD_START; + + if (i == numBreaks) + w->flags |= Word::WORD_END; + else + w->flags &= ~Word::WORD_END; + if (i < numBreaks) { // TODO There should be a method fillHyphen. w->badnessAndPenalty.setPenalties (penalties[PENALTY_HYPHEN][0], @@ -819,6 +831,10 @@ int Textblock::hyphenateWord (int wordIndex) } accumulateWordData (wordIndex + i); + + //printf ("[%p] %d: hyphenated word part: ", this, wordIndex + i); + //printWordWithFlags (w); + //printf ("\n"); } PRINTF (" finished\n"); |