summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cssparser.cc105
1 files changed, 97 insertions, 8 deletions
diff --git a/src/cssparser.cc b/src/cssparser.cc
index ed90f275..ce6225dd 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -706,6 +706,14 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
break;
case CSS_TYPE_BACKGROUND_POSITION:
+ if (ttype == CSS_TK_SYMBOL &&
+ (dStrAsciiCasecmp(tval, "center") == 0 ||
+ dStrAsciiCasecmp(tval, "left") == 0 ||
+ dStrAsciiCasecmp(tval, "right") == 0 ||
+ dStrAsciiCasecmp(tval, "top") == 0 ||
+ dStrAsciiCasecmp(tval, "bottom") == 0))
+ return true;
+ // Fall Through (lenght and percentage)
case CSS_TYPE_LENGTH_PERCENTAGE:
case CSS_TYPE_LENGTH_PERCENTAGE_NUMBER:
case CSS_TYPE_LENGTH:
@@ -1033,14 +1041,95 @@ bool CssParser::parseValue(CssPropertyName prop,
break;
case CSS_TYPE_BACKGROUND_POSITION:
- CssPropertyValue posX, posY;
- if (parseValue(prop, CSS_TYPE_LENGTH_PERCENTAGE, &posX) &&
- parseValue(prop, CSS_TYPE_LENGTH_PERCENTAGE, &posY)) {
- CssBackgroundPosition *position = (CssBackgroundPosition *) malloc(sizeof(CssBackgroundPosition));
- position->posX = posX.intVal;
- position->posY = posY.intVal;
- val->posVal = position;
- ret = true;
+ // 'background-position' consists of one or two values: vertical and
+ // horizontal position; in most cases in this order. However, as long it
+ // is unambigous, the order can be switched: "10px left" and "left 10px"
+ // are both possible and have the same effect. For this reason, all
+ // possibilities are tested parrallel.
+
+ bool h[2], v[2];
+ int pos[2];
+ h[0] = v[0] = h[1] = v[1] = false;
+
+ // First: collect values in pos[0] and pos[1], and determine whether
+ // they can be used for a horizontal (h[i]) or vertical (v[i]) position
+ // (or both). When neither h[i] or v[i] is set, pos[i] is undefined.
+ for (i = 0; i < 2; i++) {
+ CssValueType typeTmp;
+ // tokenMatchesProperty will, for CSS_PROPERTY_BACKGROUND_POSITION,
+ // work on both parts, since they are exchangable.
+ if (tokenMatchesProperty (CSS_PROPERTY_BACKGROUND_POSITION,
+ &typeTmp)) {
+ h[i] = ttype != CSS_TK_SYMBOL ||
+ (dStrAsciiCasecmp(tval, "top") != 0 &&
+ dStrAsciiCasecmp(tval, "bottom") != 0);
+ v[i] = ttype != CSS_TK_SYMBOL ||
+ (dStrAsciiCasecmp(tval, "left") != 0 &&
+ dStrAsciiCasecmp(tval, "right") != 0);
+ } else
+ // No match.
+ h[i] = v[i] = false;
+
+ if (h[i] || v[i]) {
+ // Calculate values.
+ if (ttype == CSS_TK_SYMBOL) {
+ if (dStrAsciiCasecmp(tval, "top") == 0 ||
+ dStrAsciiCasecmp(tval, "left") == 0) {
+ pos[i] = CSS_CREATE_LENGTH (0.0, CSS_LENGTH_TYPE_PERCENTAGE);
+ nextToken();
+ } else if (dStrAsciiCasecmp(tval, "center") == 0) {
+ pos[i] = CSS_CREATE_LENGTH (0.5, CSS_LENGTH_TYPE_PERCENTAGE);
+ nextToken();
+ } else if (dStrAsciiCasecmp(tval, "bottom") == 0 ||
+ dStrAsciiCasecmp(tval, "right") == 0) {
+ pos[i] = CSS_CREATE_LENGTH (1.0, CSS_LENGTH_TYPE_PERCENTAGE);
+ nextToken();
+ } else
+ // tokenMatchesProperty should have returned "false" already.
+ lout::misc::assertNotReached ();
+ } else {
+ // We can assume <length> or <percentage> here ...
+ CssPropertyValue valTmp;
+ if (parseValue(prop, CSS_TYPE_LENGTH_PERCENTAGE, &valTmp)) {
+ pos[i] = valTmp.intVal;
+ ret = true;
+ } else
+ // ... but something may still fail.
+ h[i] = v[i] = false;
+ }
+ }
+
+ // If the first value cannot be read, do not read the second.
+ if (!h[i] && !v[i])
+ break;
+ }
+
+ // Second: Create the final value. Order will be determined here.
+ if (v[0] || h[0]) {
+ // If second value is not set, it is set to "center", i. e. 50%, (see
+ // CSS specification), which is suitable for both dimensions.
+ if (!h[1] && !v[1]) {
+ pos[1] = CSS_CREATE_LENGTH (0.5, CSS_LENGTH_TYPE_PERCENTAGE);
+ h[1] = v[1] = true;
+ }
+
+ // Only valid, when a combination h/v or v/h is possible.
+ if ((h[0] && v[1]) || (v[0] && h[1])) {
+ ret = true;
+ CssBackgroundPosition *position =
+ (CssBackgroundPosition *) malloc(sizeof(CssBackgroundPosition));
+ val->posVal = position;
+
+ // Prefer combination h/v:
+ if (h[0] && v[1]) {
+ position->posX = pos[0];
+ position->posY = pos[1];
+ } else {
+ // This should be v/h:
+ position->posX = pos[1];
+ position->posY = pos[0];
+ }
+ }
}
break;