aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcorvid <corvid@lavabit.com>2011-10-22 21:47:13 +0000
committercorvid <corvid@lavabit.com>2011-10-22 21:47:13 +0000
commit4052822efdebbf56500204bbbd526673acc04841 (patch)
treecc8e180e851fd82ae9b6bd31be814d2e29e34f64
parent1f0c79090620e09aa281ff9ee14f816efb7d6f4f (diff)
text-transform property
-rw-r--r--ChangeLog2
-rw-r--r--dw/fltkplatform.cc30
-rw-r--r--dw/fltkplatform.hh2
-rw-r--r--dw/layout.hh10
-rw-r--r--dw/platform.hh10
-rw-r--r--dw/style.cc4
-rw-r--r--dw/style.hh8
-rw-r--r--dw/textblock.cc162
-rw-r--r--dw/textblock.hh8
-rw-r--r--src/cssparser.cc7
-rw-r--r--src/styleengine.cc3
11 files changed, 215 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index bd10ba9a..8bb967a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;