aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dw/table.cc3
-rw-r--r--dw/textblock.cc183
-rw-r--r--dw/textblock.hh15
-rw-r--r--dw/textblock_iterator.cc12
-rw-r--r--dw/textblock_linebreaking.cc20
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