diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | dw/fltkplatform.cc | 30 | ||||
-rw-r--r-- | dw/fltkplatform.hh | 2 | ||||
-rw-r--r-- | dw/layout.hh | 10 | ||||
-rw-r--r-- | dw/platform.hh | 10 | ||||
-rw-r--r-- | dw/style.cc | 4 | ||||
-rw-r--r-- | dw/style.hh | 8 | ||||
-rw-r--r-- | dw/textblock.cc | 162 | ||||
-rw-r--r-- | dw/textblock.hh | 8 | ||||
-rw-r--r-- | src/cssparser.cc | 7 | ||||
-rw-r--r-- | src/styleengine.cc | 3 |
11 files changed, 215 insertions, 31 deletions
@@ -6,6 +6,8 @@ dillo-3.0.2 [not released yet] +- Digest authentication Patch: Justus Winter, corvid ++- text-transform property + Patch: corvid ----------------------------------------------------------------------------- diff --git a/dw/fltkplatform.cc b/dw/fltkplatform.cc index 68819c91..cc093d37 100644 --- a/dw/fltkplatform.cc +++ b/dw/fltkplatform.cc @@ -553,6 +553,36 @@ int FltkPlatform::textWidth (core::style::Font *font, const char *text, return width; } +char *FltkPlatform::textToUpper (const char *text, int len) +{ + char *newstr = NULL; + + if (len > 0) { + int newlen; + + newstr = (char*) malloc(3 * len + 1); + newlen = fl_utf_toupper((const unsigned char*)text, len, newstr); + assert(newlen <= 3 * len); + newstr[newlen] = '\0'; + } + return newstr; +} + +char *FltkPlatform::textToLower (const char *text, int len) +{ + char *newstr = NULL; + + if (len > 0) { + int newlen; + + newstr = (char*) malloc(3 * len + 1); + newlen = fl_utf_tolower((const unsigned char*)text, len, newstr); + assert(newlen <= 3 * len); + newstr[newlen] = '\0'; + } + return newstr; +} + int FltkPlatform::nextGlyph (const char *text, int idx) { return fl_utf8fwd (&text[idx + 1], text, &text[strlen (text)]) - text; diff --git a/dw/fltkplatform.hh b/dw/fltkplatform.hh index db4bc794..7b4272eb 100644 --- a/dw/fltkplatform.hh +++ b/dw/fltkplatform.hh @@ -153,6 +153,8 @@ public: void detachView (core::View *view); int textWidth (core::style::Font *font, const char *text, int len); + char *textToUpper (const char *text, int len); + char *textToLower (const char *text, int len); int nextGlyph (const char *text, int idx); int prevGlyph (const char *text, int idx); float dpiX (); diff --git a/dw/layout.hh b/dw/layout.hh index d08eb363..45187490 100644 --- a/dw/layout.hh +++ b/dw/layout.hh @@ -297,6 +297,16 @@ public: return platform->textWidth (font, text, len); } + inline char *textToUpper (const char *text, int len) + { + return platform->textToUpper (text, len); + } + + inline char *textToLower (const char *text, int len) + { + return platform->textToLower (text, len); + } + inline int nextGlyph (const char *text, int idx) { return platform->nextGlyph (text, idx); diff --git a/dw/platform.hh b/dw/platform.hh index b79b5346..cb714583 100644 --- a/dw/platform.hh +++ b/dw/platform.hh @@ -58,6 +58,16 @@ public: virtual int textWidth (style::Font *font, const char *text, int len) = 0; /** + * \brief Return the string resulting from transforming text to uppercase. + */ + virtual char *textToUpper (const char *text, int len) = 0; + + /** + * \brief Return the string resulting from transforming text to lowercase. + */ + virtual char *textToLower (const char *text, int len) = 0; + + /** * \brief Return the index of the next glyph in string text. */ virtual int nextGlyph (const char *text, int idx) = 0; diff --git a/dw/style.cc b/dw/style.cc index b5549d3f..4a37801e 100644 --- a/dw/style.cc +++ b/dw/style.cc @@ -42,6 +42,7 @@ void StyleAttrs::initValues () textDecoration = TEXT_DECORATION_NONE; textAlign = TEXT_ALIGN_LEFT; textAlignChar = '.'; + textTransform = TEXT_TRANSFORM_NONE; listStylePosition = LIST_STYLE_POSITION_OUTSIDE; listStyleType = LIST_STYLE_TYPE_DISC; valign = VALIGN_BASELINE; @@ -117,6 +118,7 @@ bool StyleAttrs::equals (object::Object *other) { textAlign == otherAttrs->textAlign && valign == otherAttrs->valign && textAlignChar == otherAttrs->textAlignChar && + textTransform == otherAttrs->textTransform && hBorderSpacing == otherAttrs->hBorderSpacing && vBorderSpacing == otherAttrs->vBorderSpacing && wordSpacing == otherAttrs->wordSpacing && @@ -154,6 +156,7 @@ int StyleAttrs::hashValue () { textAlign + valign + textAlignChar + + textTransform + hBorderSpacing + vBorderSpacing + wordSpacing + @@ -244,6 +247,7 @@ void Style::copyAttrs (StyleAttrs *attrs) textAlign = attrs->textAlign; valign = attrs->valign; textAlignChar = attrs->textAlignChar; + textTransform = attrs->textTransform; hBorderSpacing = attrs->hBorderSpacing; vBorderSpacing = attrs->vBorderSpacing; wordSpacing = attrs->wordSpacing; diff --git a/dw/style.hh b/dw/style.hh index 4ebb7bb5..dffb84bb 100644 --- a/dw/style.hh +++ b/dw/style.hh @@ -247,6 +247,13 @@ enum VAlignType { VALIGN_TEXT_BOTTOM, }; +enum TextTransform { + TEXT_TRANSFORM_NONE, + TEXT_TRANSFORM_CAPITALIZE, + TEXT_TRANSFORM_UPPERCASE, + TEXT_TRANSFORM_LOWERCASE, +}; + /** * \todo Incomplete. Has to be completed for a CSS implementation. */ @@ -441,6 +448,7 @@ public: TextAlignType textAlign; VAlignType valign; char textAlignChar; /* In future, strings will be supported. */ + TextTransform textTransform; int hBorderSpacing, vBorderSpacing, wordSpacing; Length width, height, lineHeight, textIndent; diff --git a/dw/textblock.cc b/dw/textblock.cc index 38e22fa3..ac7b93fc 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -661,9 +661,9 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, // nextWordX is the right side of this character. charPos = 0; while ((nextWordX = wordStartX + - layout->textWidth (word->style->font, - word->content.text, - charPos)) + textWidth (word->content.text, 0, + charPos, + word->style)) <= event->xWidget) charPos = layout->nextGlyph (word->content.text, charPos); @@ -671,10 +671,8 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType, prevPos = layout->prevGlyph (word->content.text, charPos); wordX = wordStartX + - layout->textWidth (word->style->font, - word->content.text, - prevPos); - + textWidth (word->content.text, 0, prevPos, + word->style); // If the mouse pointer is left from the middle, use // the left position, otherwise, use the right one. if (event->xWidget <= (wordX + nextWordX) / 2) @@ -1257,9 +1255,66 @@ void Textblock::decorateText(core::View *view, core::style::Style *style, } /* + * Draw a string of text + */ +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) +{ + if (len > 0) { + char *str = NULL; + + switch (style->textTransform) { + case core::style::TEXT_TRANSFORM_NONE: + default: + break; + case core::style::TEXT_TRANSFORM_UPPERCASE: + str = layout->textToUpper(text + start, len); + break; + case core::style::TEXT_TRANSFORM_LOWERCASE: + 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); + break; + } + } + view->drawText(style->font, style->color, shading, x, y, + str ? str : text + start, str ? strlen(str) : len); + if (str) + free(str); + } +} + +/* * Draw a word of text. */ -void Textblock::drawText(int wordIndex, core::View *view,core::Rectangle *area, +void Textblock::drawWord(int wordIndex, core::View *view,core::Rectangle *area, int xWidget, int yWidgetBase) { Word *word = words->getRef(wordIndex); @@ -1275,9 +1330,8 @@ void Textblock::drawText(int wordIndex, core::View *view,core::Rectangle *area, } yWorldBase = yWidgetBase + allocation.y; - view->drawText (style->font, style->color, - core::style::Color::SHADING_NORMAL, xWorld, yWorldBase, - word->content.text, strlen (word->content.text)); + drawText (view, style, core::style::Color::SHADING_NORMAL, xWorld, + yWorldBase, word->content.text, 0, strlen (word->content.text)); if (style->textDecoration) decorateText(view, style, core::style::Color::SHADING_NORMAL, xWorld, @@ -1299,14 +1353,12 @@ void Textblock::drawText(int wordIndex, core::View *view,core::Rectangle *area, xStart = xWorld; if (firstCharIdx) - xStart += layout->textWidth (style->font, word->content.text, - firstCharIdx); + xStart += textWidth (word->content.text, 0, firstCharIdx, style); if (firstCharIdx == 0 && lastCharIdx == wordLen) width = word->size.width; else - width = layout->textWidth (style->font, - word->content.text + firstCharIdx, - lastCharIdx - firstCharIdx); + width = textWidth (word->content.text, firstCharIdx, + lastCharIdx - firstCharIdx, style); if (width > 0) { /* Highlight text */ core::style::Color *wordBgColor; @@ -1321,10 +1373,9 @@ void Textblock::drawText(int wordIndex, core::View *view,core::Rectangle *area, style->font->ascent + style->font->descent); /* Highlight the text. */ - view->drawText (style->font, style->color, - core::style::Color::SHADING_INVERSE, xStart, - yWorldBase, word->content.text + firstCharIdx, - lastCharIdx - firstCharIdx); + drawText (view, style, core::style::Color::SHADING_INVERSE, xStart, + yWorldBase, word->content.text, firstCharIdx, + lastCharIdx - firstCharIdx); if (style->textDecoration) decorateText(view, style, core::style::Color::SHADING_INVERSE, @@ -1422,7 +1473,7 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area) yWidgetBase - line->boxAscent, word->size.width, line->boxAscent + line->boxDescent, false); } - drawText(wordIndex, view, area, xWidget, yWidgetBase); + drawWord(wordIndex, view, area, xWidget, yWidgetBase); } } if (word->effSpace > 0 && wordIndex < line->lastWord && @@ -1591,6 +1642,63 @@ Textblock::Word *Textblock::addWord (int width, int ascent, int descent, return word; } +/* + * Get the width of a string of text. + */ +int Textblock::textWidth(const char *text, int start, int len, + core::style::Style *style) +{ + int ret = 0; + + if (len > 0) { + char *str = NULL; + + switch (style->textTransform) { + case core::style::TEXT_TRANSFORM_NONE: + default: + ret = layout->textWidth(style->font, text+start, len); + break; + case core::style::TEXT_TRANSFORM_UPPERCASE: + str = layout->textToUpper(text+start, len); + ret = layout->textWidth(style->font, str, strlen(str)); + break; + case core::style::TEXT_TRANSFORM_LOWERCASE: + str = layout->textToLower(text+start, 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)) + + layout->textWidth(style->font, text+after, len-after); + } + break; + } + } + if (str) + free(str); + } + return ret; +} + /** * Calculate the size of a text word. */ @@ -1598,7 +1706,7 @@ void Textblock::calcTextSize (const char *text, size_t len, core::style::Style *style, core::Requisition *size) { - size->width = layout->textWidth (style->font, text, len); + size->width = textWidth (text, 0, len, style); size->ascent = style->font->ascent; size->descent = style->font->descent; @@ -2179,9 +2287,8 @@ void Textblock::TextblockIterator::getAllocation (int start, int end, allocation->x += w->size.width + w->effSpace; } if (start > 0 && word->content.type == core::Content::TEXT) { - allocation->x += textblock->layout->textWidth (word->style->font, - word->content.text, - start); + allocation->x += textblock->textWidth (word->content.text, 0, start, + word->style); } allocation->y = textblock->lineYOffsetCanvas (line) + line->boxAscent - word->size.ascent; @@ -2193,9 +2300,8 @@ void Textblock::TextblockIterator::getAllocation (int start, int end, if (start > 0 || end < wordEnd) { end = misc::min(end, wordEnd); /* end could be INT_MAX */ allocation->width = - textblock->layout->textWidth (word->style->font, - word->content.text + start, - end - start); + textblock->textWidth (word->content.text, start, end - start, + word->style); } } allocation->ascent = word->size.ascent; diff --git a/dw/textblock.hh b/dw/textblock.hh index d64f65ee..3f98f878 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -266,7 +266,10 @@ protected: void decorateText(core::View *view, core::style::Style *style, core::style::Color::Shading shading, int x, int yBase, int width); - void drawText(int wordIndex, core::View *view, core::Rectangle *area, + 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); + void drawWord(int wordIndex, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase); void drawSpace(int wordIndex, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase); @@ -277,10 +280,11 @@ protected: Word *addWord (int width, int ascent, int descent, core::style::Style *style); + int textWidth (const char *text, int start, int len, + core::style::Style *style); void calcTextSize (const char *text, size_t len, core::style::Style *style, core::Requisition *size); - /** * \brief Returns the x offset (the indentation plus any offset needed for * centering or right justification) for the line. diff --git a/src/cssparser.cc b/src/cssparser.cc index 73b4331a..e58a52e1 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -121,6 +121,10 @@ static const char *const Css_text_decoration_enum_vals[] = { "underline", "overline", "line-through", "blink", NULL }; +static const char *const Css_text_transform_enum_vals[] = { + "none", "capitalize", "uppercase", "lowercase", NULL +}; + static const char *const Css_vertical_align_vals[] = { "top", "bottom", "middle", "baseline", "sub", "super", "text-top", "text-bottom", NULL @@ -228,7 +232,8 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { Css_text_decoration_enum_vals}, {"text-indent", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL}, {"text-shadow", {CSS_TYPE_UNUSED}, NULL}, - {"text-transform", {CSS_TYPE_UNUSED}, NULL}, + {"text-transform", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, + Css_text_transform_enum_vals}, {"top", {CSS_TYPE_UNUSED}, NULL}, {"unicode-bidi", {CSS_TYPE_UNUSED}, NULL}, {"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals}, diff --git a/src/styleengine.cc b/src/styleengine.cc index d1d8e969..6f07b4b4 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -565,6 +565,9 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) { case CSS_PROPERTY_TEXT_INDENT: computeLength (&attrs->textIndent, p->value.intVal, attrs->font); break; + case CSS_PROPERTY_TEXT_TRANSFORM: + attrs->textTransform = (TextTransform) p->value.intVal; + break; case CSS_PROPERTY_VERTICAL_ALIGN: attrs->valign = (VAlignType) p->value.intVal; break; |