diff options
-rw-r--r-- | dw/table.cc | 3 | ||||
-rw-r--r-- | dw/textblock.cc | 183 | ||||
-rw-r--r-- | dw/textblock.hh | 15 | ||||
-rw-r--r-- | dw/textblock_iterator.cc | 12 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 20 |
5 files changed, 161 insertions, 72 deletions
diff --git a/dw/table.cc b/dw/table.cc index c4108e47..ee9762fe 100644 --- a/dw/table.cc +++ b/dw/table.cc @@ -877,7 +877,8 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth) int curNewWidth = minAutoWidth; for (int col = 0; col < numCols; col++) { _MSG("app2, col %d, minWidth=%d maxWidth=%d\n", - col,extremes->get(col).minWidth, colExtremes->get(col).maxWidth); + col, colExtremes->getRef(col)->minWidth, + colExtremes->get(col).maxWidth); if (colPercents->get(col) != LEN_AUTO) continue; diff --git a/dw/textblock.cc b/dw/textblock.cc index 46530785..82ef715f 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -791,13 +791,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; @@ -812,7 +823,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; } @@ -941,10 +956,16 @@ void Textblock::decorateText(core::View *view, core::style::Style *style, /* * Draw a string of text + * + * Arguments: ... "isStart" and "isEnd" are true, when the text + * start/end represents the start/end of a "real" text word (before + * hyphenation). This has an effect on text transformation. ("isEnd" + * is not used yet, but here for symmetry.) */ 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; @@ -960,34 +981,37 @@ 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" is false, the first letter of "text" is + // not the first letter of the "real" text word, so no + // transformation is necessary. + 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, @@ -1074,8 +1098,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, @@ -1117,14 +1143,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; @@ -1141,7 +1171,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, @@ -1447,9 +1479,11 @@ void Textblock::fillWord (Word *word, int width, int ascent, int descent, /* * Get the width of a string of text. + * + * For "isStart" and "isEnd" see drawText. */ 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; @@ -1470,46 +1504,51 @@ 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; } /** * Calculate the size of a text word. + * + * For "isStart" and "isEnd" see textWidth and drawText. */ 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; @@ -1587,8 +1626,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++) @@ -1720,10 +1765,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]); @@ -1761,7 +1815,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++) @@ -1772,7 +1826,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 3d3ae14b..f0f8347f 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -316,6 +316,14 @@ protected: * do not consider this word as breakable. This flag is * ignored when the line is actually broken. */ UNBREAKABLE_FOR_MIN_WIDTH = 1 << 4, + /* If a word represents a "real" text word, or (after + * hyphenation) the first part of a "real" text word, this + * flag is set. Plays a role for text transformation. */ + WORD_START = 1 << 5, + /* If a word represents a "real" text word, or (after + * hyphenation) the last part of a "real" text word, this + * flag is set. Analogue to WORD_START. */ + WORD_END = 1 << 6 }; /* TODO: perhaps add a xLeft? */ @@ -465,7 +473,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, @@ -487,9 +496,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); /** * Of nested text blocks, only the most inner one must regard the diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc index 285921b2..0956ef29 100644 --- a/dw/textblock_iterator.cc +++ b/dw/textblock_iterator.cc @@ -295,7 +295,11 @@ 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; @@ -308,7 +312,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 cc396515..ad792504 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -215,12 +215,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) @@ -922,6 +924,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], @@ -942,6 +954,10 @@ int Textblock::hyphenateWord (int wordIndex) PRINTF (" [%d] + nothing\n", wordIndex + i); } } + + //printf ("[%p] %d: hyphenated word part: ", this, wordIndex + i); + //printWordWithFlags (w); + //printf ("\n"); } // AccumulateWordData() will calculate the width, which depends |