File indexing completed on 2024-04-28 11:37:32

0001 /*
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright 2003 Lars Knoll (knoll@kde.org)
0005  * Copyright 2005 Allan Sandfeld Jensen (kde@carewolf.com)
0006  * Copyright (C) 2004, 2005, 2006, 2007 Apple Computer, Inc.
0007  * Copyright (C) 2008 Maksim Orlovich <maksim@kde.org>
0008  *
0009  * This library is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU Library General Public
0011  * License as published by the Free Software Foundation; either
0012  * version 2 of the License, or (at your option) any later version.
0013  *
0014  * This library is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017  * Library General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Library General Public License
0020  * along with this library; see the file COPYING.LIB.  If not, write to
0021  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022  * Boston, MA 02110-1301, USA.
0023  */
0024 
0025 // #define CSS_DEBUG
0026 // #define TOKEN_DEBUG
0027 #define YYDEBUG 0
0028 
0029 #include "cssparser.h"
0030 
0031 #include "khtml_debug.h"
0032 #include <QUrl>
0033 #include <QScopedPointer>
0034 
0035 #include "css_valueimpl.h"
0036 #include "css_ruleimpl.h"
0037 #include "css_stylesheetimpl.h"
0038 #include "css_mediaquery.h"
0039 #include "cssproperties.h"
0040 #include "cssvalues.h"
0041 
0042 #include <stdlib.h>
0043 #include <assert.h>
0044 
0045 using namespace DOM;
0046 
0047 // used to promote background: left to left center
0048 #define BACKGROUND_SKIP_CENTER( num ) \
0049     if ( !pos_ok[ num ] && expected != 1 ) {    \
0050         pos_ok[num] = true; \
0051         pos[num] = 0; \
0052         skip_next = false; \
0053     }
0054 
0055 ValueList::~ValueList()
0056 {
0057     const int numValues = m_values.size();
0058     for (int i = 0; i < numValues; i++)
0059         if (m_values[i].unit == Value::Function) {
0060             delete m_values[i].function;
0061         }
0062 }
0063 
0064 namespace
0065 {
0066 class ShorthandScope
0067 {
0068 public:
0069     ShorthandScope(CSSParser *parser, int propId) : m_parser(parser)
0070     {
0071         if (!(m_parser->m_inParseShorthand++)) {
0072             m_parser->m_currentShorthand = propId;
0073         }
0074     }
0075     ~ShorthandScope()
0076     {
0077         if (!(--m_parser->m_inParseShorthand)) {
0078             m_parser->m_currentShorthand = 0;
0079         }
0080     }
0081 
0082 private:
0083     CSSParser *m_parser;
0084 };
0085 }
0086 
0087 using namespace DOM;
0088 
0089 #if YYDEBUG > 0
0090 extern int cssyydebug;
0091 #endif
0092 
0093 extern int cssyyparse(void *parser);
0094 
0095 CSSParser *CSSParser::currentParser = nullptr;
0096 
0097 CSSParser::CSSParser(bool strictParsing)
0098 {
0099 #ifdef CSS_DEBUG
0100     qCDebug(KHTML_LOG) << "CSSParser::CSSParser this=" << this;
0101 #endif
0102     strict = strictParsing;
0103 
0104     parsedProperties = (CSSProperty **) malloc(32 * sizeof(CSSProperty *));
0105     numParsedProperties = 0;
0106     maxParsedProperties = 32;
0107 
0108     data = nullptr;
0109     valueList = nullptr;
0110     rule = nullptr;
0111     id = 0;
0112     important = false;
0113 
0114     m_inParseShorthand = 0;
0115     m_currentShorthand = 0;
0116     m_implicitShorthand = false;
0117 
0118     yy_start = 1;
0119 
0120 #if YYDEBUG > 0
0121     cssyydebug = 1;
0122 #endif
0123 
0124 }
0125 
0126 CSSParser::~CSSParser()
0127 {
0128     if (numParsedProperties) {
0129         clearProperties();
0130     }
0131     free(parsedProperties);
0132 
0133     delete valueList;
0134 
0135 #ifdef CSS_DEBUG
0136     qCDebug(KHTML_LOG) << "CSSParser::~CSSParser this=" << this;
0137 #endif
0138 
0139     free(data);
0140 
0141 }
0142 
0143 unsigned int CSSParser::defaultNamespace()
0144 {
0145     if (styleElement && styleElement->isCSSStyleSheet()) {
0146         return static_cast<CSSStyleSheetImpl *>(styleElement)->defaultNamespace();
0147     } else {
0148         return anyNamespace;
0149     }
0150 }
0151 
0152 void CSSParser::runParser()
0153 {
0154     CSSParser *old = currentParser;
0155     currentParser = this;
0156     cssyyparse(this);
0157     currentParser = old;
0158     boundLocalNames.clear();
0159 }
0160 
0161 void CSSParser::setupParser(const char *prefix, const DOMString &string, const char *suffix)
0162 {
0163     unsigned preflen = strlen(prefix);
0164     unsigned sufflen = strlen(suffix);
0165     int length = string.length() + preflen + sufflen + 8;
0166 
0167     free(data);
0168 
0169     data = (unsigned short *)malloc(length * sizeof(unsigned short));
0170     for (unsigned i = 0; i < preflen; i++) {
0171         data[i] = prefix[i];
0172     }
0173 
0174     memcpy(data + preflen, string.unicode(), string.length()*sizeof(unsigned short));
0175 
0176     unsigned start = preflen + string.length();
0177     unsigned end = start + sufflen;
0178     for (unsigned i = start; i < end; i++) {
0179         data[i] = suffix[i - start];
0180     }
0181 
0182     // the flex scanner sometimes give invalid reads for any
0183     // smaller padding - try e.g. css/invalid-rules-005.html or see #167318
0184     data[length - 1] = 0;
0185     data[length - 2] = 0;
0186     data[length - 3] = 0;
0187     data[length - 4] = 0;
0188     data[length - 5] = 0;
0189     data[length - 6] = 0;
0190     data[length - 7] = 0;
0191     data[length - 8] = 0;
0192 
0193     yyTok = -1;
0194     block_nesting = 0;
0195     yy_hold_char = 0;
0196     yyleng = 0;
0197     yytext = yy_c_buf_p = data;
0198     yy_hold_char = *yy_c_buf_p;
0199 }
0200 
0201 void CSSParser::parseSheet(CSSStyleSheetImpl *sheet, const DOMString &string)
0202 {
0203     styleElement  = sheet;
0204     styleDocument = nullptr;
0205 
0206     setupParser("", string, "");
0207 
0208 #ifdef CSS_DEBUG
0209     qCDebug(KHTML_LOG) << ">>>>>>> start parsing style sheet";
0210 #endif
0211     runParser();
0212 #ifdef CSS_DEBUG
0213     qCDebug(KHTML_LOG) << "<<<<<<< done parsing style sheet";
0214 #endif
0215 
0216     delete rule;
0217     rule = nullptr;
0218 }
0219 
0220 CSSRuleImpl *CSSParser::parseRule(DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string)
0221 {
0222     styleElement  = sheet;
0223     styleDocument = nullptr;
0224 
0225     setupParser("@-khtml-rule{", string, "} ");
0226     runParser();
0227 
0228     CSSRuleImpl *result = rule;
0229     rule = nullptr;
0230 
0231     return result;
0232 }
0233 
0234 static void addParsedProperties(DOM::CSSStyleDeclarationImpl *declaration, CSSProperty **parsedProperties,
0235                                 int numProperties)
0236 {
0237     for (int i = 0; i < numProperties; i++) {
0238         // Only add properties that have no !important counterpart present
0239         if (!declaration->getPropertyPriority(parsedProperties[i]->id()) || parsedProperties[i]->isImportant()) {
0240             declaration->removeProperty(parsedProperties[i]->m_id);
0241             declaration->values()->append(parsedProperties[i]);
0242         }
0243     }
0244 }
0245 
0246 bool CSSParser::parseValue(DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string,
0247                            bool _important)
0248 {
0249 #ifdef CSS_DEBUG
0250     qCDebug(KHTML_LOG) << "CSSParser::parseValue: id=" << _id << " important=" << _important
0251              << " value='" << string.string() << "'";
0252 #endif
0253 
0254     styleElement  = declaration->stylesheet();
0255     styleDocument = nullptr;
0256 
0257     setupParser("@-khtml-value{", string, "} ");
0258 
0259     id = _id;
0260     important = _important;
0261 
0262     runParser();
0263 
0264     delete rule;
0265     rule = nullptr;
0266 
0267     bool ok = false;
0268     if (numParsedProperties) {
0269         ok = true;
0270         addParsedProperties(declaration, parsedProperties, numParsedProperties);
0271         numParsedProperties = 0;
0272     }
0273 
0274     return ok;
0275 }
0276 
0277 bool CSSParser::parseDeclaration(DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string)
0278 {
0279 #ifdef CSS_DEBUG
0280     qCDebug(KHTML_LOG) << "CSSParser::parseDeclaration:"
0281              << " value='" << string.string() << "'";
0282 #endif
0283 
0284     styleElement  = declaration->stylesheet();
0285     styleDocument = nullptr;
0286 
0287     setupParser("@-khtml-decls{", string, "} ");
0288     runParser();
0289 
0290     delete rule;
0291     rule = nullptr;
0292 
0293     bool ok = false;
0294     if (numParsedProperties) {
0295         ok = true;
0296         addParsedProperties(declaration, parsedProperties, numParsedProperties);
0297         numParsedProperties = 0;
0298     }
0299 
0300     return ok;
0301 }
0302 
0303 bool CSSParser::parseMediaQuery(DOM::MediaListImpl *queries, const DOM::DOMString &string)
0304 {
0305     if (string.isEmpty() || string.isNull()) {
0306         return true;
0307     }
0308 
0309     mediaQuery = nullptr;
0310     // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
0311     // instead insert one " " (which is S in parser.y)
0312     setupParser("@-khtml-mediaquery ", string, "} ");
0313     runParser();
0314 
0315     bool ok = false;
0316     if (mediaQuery) {
0317         ok = true;
0318         queries->appendMediaQuery(mediaQuery);
0319         mediaQuery = nullptr;
0320     }
0321 
0322     return ok;
0323 }
0324 
0325 QList<DOM::CSSSelector *> CSSParser::parseSelectorList(DOM::DocumentImpl *doc, const DOM::DOMString &string)
0326 {
0327     styleElement  = nullptr;
0328     styleDocument = doc;
0329     selectors.clear();
0330     setupParser("@-khtml-selectors{", string, "} ");
0331     runParser();
0332 
0333     // Make sure to detect problems with pseudos, too
0334     bool ok = true;
0335     for (int i = 0; i < selectors.size(); ++i) {
0336         // we need to check not only us, but also other things we're connected to via
0337         // combinators
0338         for (DOM::CSSSelector *sel = selectors[i]; sel; sel = sel->tagHistory) {
0339             if (sel->match == CSSSelector::PseudoClass || sel->match == CSSSelector::PseudoElement) {
0340                 if (sel->pseudoType() == CSSSelector::PseudoOther) {
0341                     ok = false;
0342                     break;
0343                 }
0344             }
0345         }
0346     }
0347 
0348     if (!ok) {
0349         qDeleteAll(selectors);
0350         selectors.clear();
0351     }
0352 
0353     return selectors;
0354 }
0355 
0356 void CSSParser::addProperty(int propId, CSSValueImpl *value, bool important)
0357 {
0358     CSSProperty *prop = new CSSProperty;
0359     prop->m_id = propId;
0360     prop->setValue(value);
0361     prop->m_important = important;
0362     prop->m_implicit = m_implicitShorthand;
0363 
0364     if (numParsedProperties >= maxParsedProperties) {
0365         maxParsedProperties += 32;
0366         parsedProperties = (CSSProperty **) realloc(parsedProperties,
0367                            maxParsedProperties * sizeof(CSSProperty *));
0368     }
0369     parsedProperties[numParsedProperties++] = prop;
0370 }
0371 
0372 void CSSParser::rollbackParsedProperties(int toNumParsedProperties)
0373 {
0374     while (numParsedProperties > toNumParsedProperties) {
0375             --numParsedProperties;
0376             delete parsedProperties[numParsedProperties];
0377         }
0378 }
0379 
0380 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration(CSSStyleRuleImpl *rule)
0381 {
0382     QList<CSSProperty *> *propList = new QList<CSSProperty *>;
0383     for (int i = 0; i < numParsedProperties; i++) {
0384         propList->append(parsedProperties[i]);
0385     }
0386 
0387     numParsedProperties = 0;
0388     return new CSSStyleDeclarationImpl(rule, propList);
0389 }
0390 
0391 CSSStyleDeclarationImpl *CSSParser::createFontFaceStyleDeclaration(CSSFontFaceRuleImpl *rule)
0392 {
0393     QList<CSSProperty *> *propList = new QList<CSSProperty *>;
0394     CSSProperty *overriddenSrcProperty = nullptr;
0395     for (int i = 0; i < numParsedProperties; i++) {
0396         CSSProperty *property = parsedProperties[i];
0397         int id = property->id();
0398         if ((id == CSS_PROP_FONT_WEIGHT || id == CSS_PROP_FONT_STYLE || id == CSS_PROP_FONT_VARIANT) && property->value()->isPrimitiveValue()) {
0399             // change those to a list of values containing a single value, so that we may always cast to a list in the CSSFontSelector.
0400             CSSValueImpl *value = property->value();
0401             value->ref();
0402             property->setValue(new CSSValueListImpl(CSSValueListImpl::Comma));
0403             static_cast<CSSValueListImpl *>(property->value())->append(value);
0404             value->deref();
0405         } else if (id == CSS_PROP_SRC) {
0406             overriddenSrcProperty = property;
0407             continue;
0408         }
0409 
0410         propList->append(property);
0411     }
0412 
0413     if (overriddenSrcProperty) {
0414         propList->append(overriddenSrcProperty);
0415     }
0416 
0417     numParsedProperties = 0;
0418     return new CSSStyleDeclarationImpl(rule, propList);
0419 }
0420 
0421 void CSSParser::clearProperties()
0422 {
0423     for (int i = 0; i < numParsedProperties; i++) {
0424         delete parsedProperties[i];
0425     }
0426     numParsedProperties = 0;
0427 }
0428 
0429 DOM::DocumentImpl *CSSParser::document() const
0430 {
0431     if (!styleDocument) {
0432         const StyleBaseImpl *root = styleElement;
0433         while (root->parent()) {
0434             root = root->parent();
0435         }
0436         if (root->isCSSStyleSheet()) {
0437             styleDocument = static_cast<const CSSStyleSheetImpl *>(root)->doc();
0438         }
0439     }
0440     return styleDocument;
0441 }
0442 
0443 bool CSSParser::validUnit(Value *value, int unitflags, bool strict)
0444 {
0445     if (unitflags & FNonNeg && value->fValue < 0) {
0446         return false;
0447     }
0448 
0449     bool b = false;
0450     switch (value->unit) {
0451     case CSSPrimitiveValue::CSS_NUMBER:
0452         b = (unitflags & FNumber);
0453         if (!b && ((unitflags & FLength) && (value->fValue == 0 || !strict))) {
0454             value->unit = CSSPrimitiveValue::CSS_PX;
0455             b = true;
0456         }
0457         if (!b && (unitflags & FInteger) && value->isInt) {
0458             b = true;
0459         }
0460         break;
0461     case CSSPrimitiveValue::CSS_PERCENTAGE:
0462         b = (unitflags & FPercent);
0463         break;
0464     case Value::Q_EMS:
0465     case CSSPrimitiveValue::CSS_EMS:
0466     case CSSPrimitiveValue::CSS_EXS:
0467     case CSSPrimitiveValue::CSS_CHS:
0468     case CSSPrimitiveValue::CSS_REMS:
0469     case CSSPrimitiveValue::CSS_PX:
0470     case CSSPrimitiveValue::CSS_CM:
0471     case CSSPrimitiveValue::CSS_MM:
0472     case CSSPrimitiveValue::CSS_IN:
0473     case CSSPrimitiveValue::CSS_PT:
0474     case CSSPrimitiveValue::CSS_PC:
0475         b = (unitflags & FLength);
0476         break;
0477     case CSSPrimitiveValue::CSS_MS:
0478     case CSSPrimitiveValue::CSS_S:
0479         b = (unitflags & FTime);
0480         break;
0481     case CSSPrimitiveValue::CSS_DEG:
0482     case CSSPrimitiveValue::CSS_RAD:
0483     case CSSPrimitiveValue::CSS_GRAD:
0484     case CSSPrimitiveValue::CSS_HZ:
0485     case CSSPrimitiveValue::CSS_KHZ:
0486     case CSSPrimitiveValue::CSS_DPI:
0487     case CSSPrimitiveValue::CSS_DPCM:
0488     case CSSPrimitiveValue::CSS_DIMENSION:
0489     default:
0490         break;
0491     }
0492     return b;
0493 }
0494 
0495 bool CSSParser::parseValue(int propId, bool important)
0496 {
0497     if (!valueList) {
0498         return false;
0499     }
0500 
0501     Value *value = valueList->current();
0502 
0503     if (!value) {
0504         return false;
0505     }
0506 
0507     int id = value->id;
0508 
0509     const int num = inShorthand() ? 1 : valueList->size();
0510 
0511     if (id == CSS_VAL_INHERIT) {
0512         if (num != 1) {
0513             return false;
0514         }
0515         addProperty(propId, new CSSInheritedValueImpl(), important);
0516         return true;
0517     } else if (id == CSS_VAL_INITIAL) {
0518         if (num != 1) {
0519             return false;
0520         }
0521         addProperty(propId, new CSSInitialValueImpl(false/*implicit initial*/), important);
0522         return true;
0523     }
0524 
0525     bool valid_primitive = false;
0526     CSSValueImpl *parsedValue = nullptr;
0527 
0528     switch (propId) {
0529     /* The comment to the left defines all valid value of this properties as defined
0530      * in CSS 2, Appendix F. Property index
0531      */
0532 
0533     /* All the CSS properties are not supported by the renderer at the moment.
0534      * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
0535      * (see parseAuralValues). As we don't support them at all this seems reasonable.
0536      */
0537 
0538     case CSS_PROP_SIZE:                 // <length>{1,2} | auto | portrait | landscape | inherit
0539 //     case CSS_PROP_PAGE:                 // <identifier> | auto // ### CHECK
0540         // ### To be done
0541         if (id) {
0542             valid_primitive = true;
0543         }
0544         break;
0545     case CSS_PROP_UNICODE_BIDI:         // normal | embed | bidi-override | inherit
0546         if (id == CSS_VAL_NORMAL ||
0547                 id == CSS_VAL_EMBED ||
0548                 id == CSS_VAL_BIDI_OVERRIDE) {
0549             valid_primitive = true;
0550         }
0551         break;
0552 
0553     case CSS_PROP_POSITION:             // static | relative | absolute | fixed | inherit
0554         if (id == CSS_VAL_STATIC ||
0555                 id == CSS_VAL_RELATIVE ||
0556                 id == CSS_VAL_ABSOLUTE ||
0557                 id == CSS_VAL_FIXED) {
0558             valid_primitive = true;
0559         }
0560         break;
0561 
0562     case CSS_PROP_PAGE_BREAK_AFTER:     // auto | always | avoid | left | right | inherit
0563     case CSS_PROP_PAGE_BREAK_BEFORE:    // auto | always | avoid | left | right | inherit
0564         if (id == CSS_VAL_AUTO ||
0565                 id == CSS_VAL_ALWAYS ||
0566                 id == CSS_VAL_AVOID ||
0567                 id == CSS_VAL_LEFT ||
0568                 id == CSS_VAL_RIGHT) {
0569             valid_primitive = true;
0570         }
0571         break;
0572 
0573     case CSS_PROP_PAGE_BREAK_INSIDE:    // avoid | auto | inherit
0574         if (id == CSS_VAL_AUTO ||
0575                 id == CSS_VAL_AVOID) {
0576             valid_primitive = true;
0577         }
0578         break;
0579 
0580     case CSS_PROP_EMPTY_CELLS:          // show | hide | inherit
0581         if (id == CSS_VAL_SHOW ||
0582                 id == CSS_VAL_HIDE) {
0583             valid_primitive = true;
0584         }
0585         break;
0586 
0587     case CSS_PROP_QUOTES:               // [<string> <string>]+ | none | inherit
0588         if (id == CSS_VAL_NONE) {
0589             valid_primitive = true;
0590         } else {
0591             QuotesValueImpl *quotes = new QuotesValueImpl;
0592             bool is_valid = true;
0593             QString open, close;
0594             Value *val = valueList->current();
0595             while (val) {
0596                 if (val->unit == CSSPrimitiveValue::CSS_STRING) {
0597                     open = qString(val->string);
0598                 } else {
0599                     is_valid = false;
0600                     break;
0601                 }
0602                 valueList->next();
0603                 val = valueList->current();
0604                 if (val && val->unit == CSSPrimitiveValue::CSS_STRING) {
0605                     close = qString(val->string);
0606                 } else {
0607                     is_valid = false;
0608                     break;
0609                 }
0610                 quotes->addLevel(open, close);
0611                 valueList->next();
0612                 val = valueList->current();
0613             }
0614             if (is_valid) {
0615                 parsedValue = quotes;
0616             } else {
0617                 delete quotes;
0618             }
0619         }
0620         break;
0621 
0622     case CSS_PROP_CONTENT:     //  normal | none | inherit |
0623         // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+
0624         if (id == CSS_VAL_NORMAL || id == CSS_VAL_NONE) {
0625             valid_primitive = true;
0626         } else {
0627             return parseContent(propId, important);
0628         }
0629         break;
0630 
0631     case CSS_PROP_WHITE_SPACE:          // normal | pre | nowrap | pre-wrap | pre-line | inherit
0632         if (id == CSS_VAL_NORMAL ||
0633                 id == CSS_VAL_PRE ||
0634                 id == CSS_VAL_PRE_WRAP ||
0635                 id == CSS_VAL_PRE_LINE ||
0636                 id == CSS_VAL_NOWRAP) {
0637             valid_primitive = true;
0638         }
0639         break;
0640 
0641     case CSS_PROP_CLIP:                 // <shape> | auto | inherit
0642         if (id == CSS_VAL_AUTO) {
0643             valid_primitive = true;
0644         } else if (value->unit == Value::Function) {
0645             return parseShape(propId, important);
0646         }
0647         break;
0648 
0649     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
0650      * correctly and allows optimization in khtml::applyRule(..)
0651      */
0652     case CSS_PROP_CAPTION_SIDE:         // top | bottom | left | right | inherit
0653         // Left and right were deprecated in CSS 2.1 and never supported by KHTML
0654         if ( /* id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || */
0655             id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
0656             valid_primitive = true;
0657         }
0658         break;
0659 
0660     case CSS_PROP_BORDER_COLLAPSE:      // collapse | separate | inherit
0661         if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE) {
0662             valid_primitive = true;
0663         }
0664         break;
0665 
0666     case CSS_PROP_VISIBILITY:           // visible | hidden | collapse | inherit
0667         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE) {
0668             valid_primitive = true;
0669         }
0670         break;
0671 
0672     case CSS_PROP_OVERFLOW:             // visible | hidden | scroll | auto | marquee | inherit
0673     case CSS_PROP_OVERFLOW_X:
0674     case CSS_PROP_OVERFLOW_Y:
0675         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
0676                 id == CSS_VAL_MARQUEE) {
0677             valid_primitive = true;
0678         }
0679         break;
0680 
0681     case CSS_PROP_LIST_STYLE_POSITION:  // inside | outside | inherit
0682         if (id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE) {
0683             valid_primitive = true;
0684         }
0685         break;
0686 
0687     case CSS_PROP_LIST_STYLE_TYPE:
0688         // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
0689         // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
0690         // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
0691         // katakana | hiragana-iroha | katakana-iroha | none | inherit
0692         if ((id >= CSS_VAL_DISC && id <= CSS_VAL__KHTML_CLOSE_QUOTE) || id == CSS_VAL_NONE) {
0693             valid_primitive = true;
0694         }
0695         break;
0696 
0697     case CSS_PROP_DISPLAY:
0698         // inline | block | list-item | run-in | inline-block | -khtml-ruler | table |
0699         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
0700         // table-column-group | table-column | table-cell | table-caption | none | inherit
0701         if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE) {
0702             valid_primitive = true;
0703         }
0704         break;
0705 
0706     case CSS_PROP_DIRECTION:            // ltr | rtl | inherit
0707         if (id == CSS_VAL_LTR || id == CSS_VAL_RTL) {
0708             valid_primitive = true;
0709         }
0710         break;
0711 
0712     case CSS_PROP_TEXT_TRANSFORM:       // capitalize | uppercase | lowercase | none | inherit
0713         if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE) {
0714             valid_primitive = true;
0715         }
0716         break;
0717 
0718     case CSS_PROP_FLOAT:                // left | right | none | khtml_left | khtml_right | inherit + center for buggy CSS
0719         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL__KHTML_LEFT ||
0720                 id == CSS_VAL__KHTML_RIGHT || id == CSS_VAL_NONE || id == CSS_VAL_CENTER) {
0721             valid_primitive = true;
0722         }
0723         break;
0724 
0725     case CSS_PROP_CLEAR:                // none | left | right | both | inherit
0726         if (id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
0727                 id == CSS_VAL_RIGHT || id == CSS_VAL_BOTH) {
0728             valid_primitive = true;
0729         }
0730         break;
0731 
0732     case CSS_PROP_TEXT_ALIGN:
0733         // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
0734         if ((id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER) ||
0735                 value->unit == CSSPrimitiveValue::CSS_STRING) {
0736             valid_primitive = true;
0737         }
0738         break;
0739 
0740     case CSS_PROP_OUTLINE_STYLE:        // <border-style> | inherit
0741     case CSS_PROP_BORDER_TOP_STYLE:     //// <border-style> | inherit
0742     case CSS_PROP_BORDER_RIGHT_STYLE:   //   Defined as:    none | hidden | dotted | dashed |
0743     case CSS_PROP_BORDER_BOTTOM_STYLE:  //   solid | double | groove | ridge | inset | outset | -khtml-native
0744     case CSS_PROP_BORDER_LEFT_STYLE:    ////
0745         if (id >= CSS_VAL__KHTML_NATIVE && id <= CSS_VAL_DOUBLE) {
0746             valid_primitive = true;
0747         }
0748         break;
0749 
0750     case CSS_PROP_FONT_WEIGHT: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
0751         id = parseFontWeight(value, false);
0752         if (id) {
0753             valid_primitive = true;
0754         }
0755         break;
0756     case CSS_PROP_BORDER_TOP_RIGHT_RADIUS:
0757     case CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS:
0758     case CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS:
0759     case CSS_PROP_BORDER_TOP_LEFT_RADIUS: {
0760         //<length> <length>?
0761         if (num < 1 || num > 2) {
0762             return false;
0763         }
0764 
0765         if (!validUnit(value, FLength | FPercent | FNonNeg, strict)) {
0766             return false;
0767         }
0768 
0769         CSSPrimitiveValueImpl *horiz = new CSSPrimitiveValueImpl(value->fValue,
0770                 (CSSPrimitiveValue::UnitTypes) value->unit);
0771         CSSPrimitiveValueImpl *vert;
0772 
0773         if (num == 2) {
0774             value = valueList->next();
0775             if (!validUnit(value, FLength | FPercent | FNonNeg, strict)) {
0776                 delete horiz;
0777                 return false;
0778             }
0779             vert = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
0780         } else {
0781             vert = horiz;
0782         }
0783 
0784         addProperty(propId, new CSSPrimitiveValueImpl(new PairImpl(horiz, vert)), important);
0785         return true;
0786     }
0787 
0788     case CSS_PROP_BORDER_RADIUS:
0789         return parseBorderRadius(important);
0790 
0791     case CSS_PROP_BORDER_SPACING: {
0792         const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
0793                                     CSS_PROP__KHTML_BORDER_VERTICAL_SPACING
0794                                   };
0795         if (num == 1) {
0796             ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
0797             if (!parseValue(properties[0], important)) {
0798                 return false;
0799             }
0800             CSSValueImpl *value = parsedProperties[numParsedProperties - 1]->value();
0801             addProperty(properties[1], value, important);
0802             return true;
0803         } else if (num == 2) {
0804             ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
0805             const int oldNumParsedProperties = numParsedProperties;
0806             if (!parseValue(properties[0], important)) {
0807                 return false;
0808             }
0809             if (!parseValue(properties[1], important)) {
0810                 rollbackParsedProperties(oldNumParsedProperties);
0811                 return false;
0812             }
0813             return true;
0814         }
0815         return false;
0816     }
0817     case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
0818     case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
0819         valid_primitive = validUnit(value, FLength | FNonNeg, strict);
0820         break;
0821 
0822     case CSS_PROP_SCROLLBAR_FACE_COLOR:         // IE5.5
0823     case CSS_PROP_SCROLLBAR_SHADOW_COLOR:       // IE5.5
0824     case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:    // IE5.5
0825     case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:      // IE5.5
0826     case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:   // IE5.5
0827     case CSS_PROP_SCROLLBAR_TRACK_COLOR:        // IE5.5
0828     case CSS_PROP_SCROLLBAR_ARROW_COLOR:        // IE5.5
0829     case CSS_PROP_SCROLLBAR_BASE_COLOR:         // IE5.5
0830         if (strict) {
0831             break;
0832         }
0833     /* nobreak */
0834     case CSS_PROP_OUTLINE_COLOR:        // <color> | invert | inherit
0835         // outline has "invert" as additional keyword.
0836         if (propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT) {
0837             valid_primitive = true;
0838             break;
0839         }
0840     /* nobreak */
0841     case CSS_PROP_BACKGROUND_COLOR:     // <color> | inherit
0842     case CSS_PROP_BORDER_TOP_COLOR:     // <color> | inherit
0843     case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | inherit
0844     case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | inherit
0845     case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | inherit
0846     case CSS_PROP_COLOR:                // <color> | inherit
0847         if (id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU ||
0848                 (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
0849                 id == CSS_VAL_TRANSPARENT ||
0850                 id == CSS_VAL_CURRENTCOLOR ||
0851                 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict)) {
0852             valid_primitive = true;
0853         } else {
0854             parsedValue = parseColor();
0855             if (parsedValue) {
0856                 valueList->next();
0857             }
0858         }
0859         break;
0860 
0861     case CSS_PROP_CURSOR:
0862         //  [ auto | default | none |
0863         //  context-menu | help | pointer | progress | wait |
0864         //  cell | crosshair | text | vertical-text |
0865         //  alias | copy | move | no-drop | not-allowed |
0866         //  e-resize | ne-resize | nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize |
0867         //  ew-resize | ns-resize | nesw-resize | nwse-resize |
0868         //  col-resize | row-resize | all-scroll
0869         // ] ] | inherit
0870         // MSIE 5 compatibility :/
0871         if (!strict && id == CSS_VAL_HAND) {
0872             id = CSS_VAL_POINTER;
0873             valid_primitive = true;
0874         } else if ((id >= CSS_VAL_AUTO && id <= CSS_VAL_ALL_SCROLL) || id == CSS_VAL_NONE) {
0875             valid_primitive = true;
0876         }
0877         break;
0878 
0879     case CSS_PROP_BACKGROUND_ATTACHMENT:
0880     case CSS_PROP_BACKGROUND_CLIP:
0881     case CSS_PROP_BACKGROUND_IMAGE:
0882     case CSS_PROP_BACKGROUND_ORIGIN:
0883     case CSS_PROP_BACKGROUND_POSITION:
0884     case CSS_PROP_BACKGROUND_POSITION_X:
0885     case CSS_PROP_BACKGROUND_POSITION_Y:
0886     case CSS_PROP_BACKGROUND_SIZE:
0887     case CSS_PROP_BACKGROUND_REPEAT: {
0888         CSSValueImpl *val1 = nullptr, *val2 = nullptr;
0889         int propId1, propId2;
0890         if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
0891             addProperty(propId1, val1, important);
0892             if (val2) {
0893                 addProperty(propId2, val2, important);
0894             }
0895             return true;
0896         }
0897         return false;
0898     }
0899     case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
0900         if (id == CSS_VAL_NONE) {
0901             parsedValue = new CSSImageValueImpl();
0902             valueList->next();
0903         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
0904             // ### allow string in non strict mode?
0905             if (styleElement) {
0906                 const DOMString uri = domString(value->string);
0907                 parsedValue = new CSSImageValueImpl(uri, styleElement);
0908                 valueList->next();
0909             }
0910         }
0911         break;
0912 
0913     case CSS_PROP_OUTLINE_WIDTH:        // <border-width> | inherit
0914     case CSS_PROP_BORDER_TOP_WIDTH:     //// <border-width> | inherit
0915     case CSS_PROP_BORDER_RIGHT_WIDTH:   //   Which is defined as
0916     case CSS_PROP_BORDER_BOTTOM_WIDTH:  //   thin | medium | thick | <length>
0917     case CSS_PROP_BORDER_LEFT_WIDTH:    ////
0918         if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK) {
0919             valid_primitive = true;
0920         } else {
0921             valid_primitive = validUnit(value, FLength|FNonNeg, strict);
0922         }
0923         break;
0924 
0925     case CSS_PROP_LETTER_SPACING:       // normal | <length> | inherit
0926     case CSS_PROP_WORD_SPACING:         // normal | <length> | inherit
0927         if (id == CSS_VAL_NORMAL) {
0928             valid_primitive = true;
0929         } else {
0930             valid_primitive = validUnit(value, FLength, strict);
0931         }
0932         break;
0933 
0934     case CSS_PROP_TEXT_INDENT:          //  <length> | <percentage> | inherit
0935         valid_primitive = (!id && validUnit(value, FLength | FPercent, strict));
0936         break;
0937 
0938     case CSS_PROP_PADDING_TOP:          //  <length> | <percentage> | inherit
0939     case CSS_PROP_PADDING_RIGHT:        //  <padding-width> | inherit
0940     case CSS_PROP_PADDING_BOTTOM:       //   Which is defined as
0941     case CSS_PROP_PADDING_LEFT:         //   <length> | <percentage>
0942     case CSS_PROP__KHTML_PADDING_START:
0943         valid_primitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, strict));
0944         break;
0945 
0946     case CSS_PROP_MAX_HEIGHT:           // <length> | <percentage> | none | inherit
0947     case CSS_PROP_MAX_WIDTH:            // <length> | <percentage> | none | inherit
0948         if (id == CSS_VAL_NONE) {
0949             valid_primitive = true;
0950             break;
0951         }
0952     /* nobreak */
0953     case CSS_PROP_MIN_HEIGHT:           // <length> | <percentage> | inherit
0954     case CSS_PROP_MIN_WIDTH:            // <length> | <percentage> | inherit
0955         valid_primitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, strict));
0956         break;
0957 
0958     case CSS_PROP_FONT_SIZE:
0959         // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
0960         if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER) {
0961             valid_primitive = true;
0962         } else {
0963             valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, strict);
0964         }
0965         break;
0966 
0967     case CSS_PROP_FONT_STYLE:           // normal | italic | oblique | inherit
0968         if (id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) {
0969             valid_primitive = true;
0970         }
0971         break;
0972 
0973     case CSS_PROP_FONT_VARIANT:         // normal | small-caps | inherit
0974         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS) {
0975             valid_primitive = true;
0976         }
0977         break;
0978 
0979     case CSS_PROP_VERTICAL_ALIGN:
0980         // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
0981         // <percentage> | <length> | inherit
0982 
0983         if (id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE) {
0984             valid_primitive = true;
0985         } else {
0986             valid_primitive = (!id && validUnit(value, FLength | FPercent, strict));
0987         }
0988         break;
0989 
0990     case CSS_PROP_HEIGHT:               // <length> | <percentage> | auto | inherit
0991     case CSS_PROP_WIDTH:                // <length> | <percentage> | auto | inherit
0992         if (id == CSS_VAL_AUTO) {
0993             valid_primitive = true;
0994         } else
0995             // ### handle multilength case where we allow relative units
0996         {
0997             valid_primitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, strict));
0998         }
0999         break;
1000 
1001     case CSS_PROP_BOTTOM:               // <length> | <percentage> | auto | inherit
1002     case CSS_PROP_LEFT:                 // <length> | <percentage> | auto | inherit
1003     case CSS_PROP_RIGHT:                // <length> | <percentage> | auto | inherit
1004     case CSS_PROP_TOP:                  // <length> | <percentage> | auto | inherit
1005     case CSS_PROP_MARGIN_TOP:           //// <margin-width> | inherit
1006     case CSS_PROP_MARGIN_RIGHT:         //   Which is defined as
1007     case CSS_PROP_MARGIN_BOTTOM:        //   <length> | <percentage> | auto | inherit
1008     case CSS_PROP_MARGIN_LEFT:          ////
1009     case CSS_PROP__KHTML_MARGIN_START:
1010         if (id == CSS_VAL_AUTO) {
1011             valid_primitive = true;
1012         } else {
1013             valid_primitive = (!id && validUnit(value, FLength | FPercent, strict));
1014         }
1015         break;
1016 
1017     case CSS_PROP_Z_INDEX:              // auto | <integer> | inherit
1018         // qDebug("parsing z-index: id=%d, fValue=%f", id, value->fValue );
1019         if (id == CSS_VAL_AUTO) {
1020             valid_primitive = true;
1021             break;
1022         }
1023     /* nobreak */
1024     case CSS_PROP_ORPHANS:              // <integer> | inherit
1025     case CSS_PROP_WIDOWS:               // <integer> | inherit
1026         // ### not supported later on
1027         valid_primitive = (!id && validUnit(value, FInteger, false));
1028         break;
1029 
1030     case CSS_PROP_LINE_HEIGHT:          // normal | <number> | <length> | <percentage> | inherit
1031         if (id == CSS_VAL_NORMAL) {
1032             valid_primitive = true;
1033         } else {
1034             valid_primitive = (!id && validUnit(value, FNumber | FLength | FPercent | FNonNeg, strict));
1035         }
1036         break;
1037     case CSS_PROP_COUNTER_INCREMENT:    // [ <identifier> <integer>? ]+ | none | inherit
1038         if (id == CSS_VAL_NONE) {
1039             valid_primitive = true;
1040         } else {
1041             return parseCounter(propId, true, important);
1042         }
1043         break;
1044     case CSS_PROP_COUNTER_RESET:        // [ <identifier> <integer>? ]+ | none | inherit
1045         if (id == CSS_VAL_NONE) {
1046             valid_primitive = true;
1047         } else {
1048             return parseCounter(propId, false, important);
1049         }
1050         break;
1051 
1052     case CSS_PROP_FONT_FAMILY:
1053         // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
1054     {
1055         parsedValue = parseFontFamily();
1056         break;
1057     }
1058 
1059     case CSS_PROP_TEXT_DECORATION:
1060         // none | [ underline || overline || line-through || blink ] | inherit
1061         if (id == CSS_VAL_NONE) {
1062             valid_primitive = true;
1063         } else {
1064             CSSValueListImpl *list = new CSSValueListImpl;
1065             bool is_valid = true;
1066             while (is_valid && value) {
1067                 switch (value->id) {
1068                 case CSS_VAL_BLINK:
1069                     break;
1070                 case CSS_VAL_UNDERLINE:
1071                 case CSS_VAL_OVERLINE:
1072                 case CSS_VAL_LINE_THROUGH:
1073                     list->append(new CSSPrimitiveValueImpl(value->id));
1074                     break;
1075                 default:
1076                     is_valid = false;
1077                 }
1078                 value = valueList->next();
1079             }
1080             //qCDebug(KHTML_LOG) << "got " << list->length() << "d decorations";
1081             if (list->length() && is_valid) {
1082                 parsedValue = list;
1083                 valueList->next();
1084             } else {
1085                 delete list;
1086             }
1087         }
1088         break;
1089 
1090     case CSS_PROP_TABLE_LAYOUT:         // auto | fixed | inherit
1091         if (id == CSS_VAL_AUTO || id == CSS_VAL_FIXED) {
1092             valid_primitive = true;
1093         }
1094         break;
1095 
1096     case CSS_PROP_SRC:  // Only used within @font-face, so cannot use inherit | initial or be !important.  This is a list of urls or local references.
1097         return parseFontFaceSrc();
1098 
1099     case CSS_PROP_UNICODE_RANGE:
1100         // return parseFontFaceUnicodeRange();
1101         break;
1102 
1103     case CSS_PROP__KHTML_FLOW_MODE:
1104         if (id == CSS_VAL__KHTML_NORMAL || id == CSS_VAL__KHTML_AROUND_FLOATS) {
1105             valid_primitive = true;
1106         }
1107         break;
1108 
1109     /* CSS3 properties */
1110     case CSS_PROP_BOX_SIZING:        // border-box | content-box | inherit
1111         if (id == CSS_VAL_BORDER_BOX || id == CSS_VAL_CONTENT_BOX) {
1112             valid_primitive = true;
1113         }
1114         break;
1115     case CSS_PROP_OUTLINE_OFFSET:
1116         valid_primitive = validUnit(value, FLength, strict);
1117         break;
1118     case CSS_PROP_TEXT_SHADOW:  // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1119         if (id == CSS_VAL_NONE) {
1120             valid_primitive = true;
1121         } else {
1122             return parseShadow(propId, important);
1123         }
1124         break;
1125     case CSS_PROP_OPACITY:
1126         valid_primitive = validUnit(value, FNumber, strict);
1127         break;
1128     case CSS_PROP__KHTML_USER_INPUT:        // none | enabled | disabled | inherit
1129         if (id == CSS_VAL_NONE || id == CSS_VAL_ENABLED || id == CSS_VAL_DISABLED) {
1130             valid_primitive = true;
1131         }
1132 //        qCDebug(KHTML_LOG) << "CSS_PROP__KHTML_USER_INPUT: " << valid_primitive;
1133         break;
1134     case CSS_PROP__KHTML_MARQUEE: {
1135         const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
1136                                     CSS_PROP__KHTML_MARQUEE_REPETITION,
1137                                     CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED
1138                                   };
1139         return parseShortHand(propId, properties, 5, important);
1140     }
1141     case CSS_PROP__KHTML_MARQUEE_DIRECTION:
1142         if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
1143                 id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
1144                 id == CSS_VAL_UP || id == CSS_VAL_AUTO) {
1145             valid_primitive = true;
1146         }
1147         break;
1148     case CSS_PROP__KHTML_MARQUEE_INCREMENT:
1149         if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM) {
1150             valid_primitive = true;
1151         } else {
1152             valid_primitive = validUnit(value, FLength | FPercent, strict);
1153         }
1154         break;
1155     case CSS_PROP__KHTML_MARQUEE_STYLE:
1156         if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE ||
1157                 id == CSS_VAL_UNFURL) {
1158             valid_primitive = true;
1159         }
1160         break;
1161     case CSS_PROP__KHTML_MARQUEE_REPETITION:
1162         if (id == CSS_VAL_INFINITE) {
1163             valid_primitive = true;
1164         } else {
1165             valid_primitive = validUnit(value, FInteger | FNonNeg, strict);
1166         }
1167         break;
1168     case CSS_PROP__KHTML_MARQUEE_SPEED:
1169         if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST) {
1170             valid_primitive = true;
1171         } else {
1172             valid_primitive = validUnit(value, FTime | FInteger | FNonNeg, strict);
1173         }
1174         break;
1175     case CSS_PROP_TEXT_OVERFLOW: // clip | ellipsis
1176         if (id == CSS_VAL_CLIP || id == CSS_VAL_ELLIPSIS) {
1177             valid_primitive = true;
1178         }
1179         break;
1180     // End of CSS3 properties
1181 
1182     /* shorthand properties */
1183     case CSS_PROP_BACKGROUND:
1184         // ['background-color' || 'background-image' ||'background-repeat' ||
1185         // 'background-attachment' || 'background-position'] | inherit
1186         return parseBackgroundShorthand(important);
1187     case CSS_PROP_BORDER:
1188         // [ 'border-width' || 'border-style' || <color> ] | inherit
1189     {
1190         const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
1191                                     CSS_PROP_BORDER_COLOR
1192                                   };
1193         return parseShortHand(propId, properties, 3, important);
1194     }
1195     case CSS_PROP_BORDER_TOP:
1196         // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1197     {
1198         const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
1199                                     CSS_PROP_BORDER_TOP_COLOR
1200                                   };
1201         return parseShortHand(propId, properties, 3, important);
1202     }
1203     case CSS_PROP_BORDER_RIGHT:
1204         // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1205     {
1206         const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
1207                                     CSS_PROP_BORDER_RIGHT_COLOR
1208                                   };
1209         return parseShortHand(propId, properties, 3, important);
1210     }
1211     case CSS_PROP_BORDER_BOTTOM:
1212         // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1213     {
1214         const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
1215                                     CSS_PROP_BORDER_BOTTOM_COLOR
1216                                   };
1217         return parseShortHand(propId, properties, 3, important);
1218     }
1219     case CSS_PROP_BORDER_LEFT:
1220         // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1221     {
1222         const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
1223                                     CSS_PROP_BORDER_LEFT_COLOR
1224                                   };
1225         return parseShortHand(propId, properties, 3, important);
1226     }
1227     case CSS_PROP_OUTLINE:
1228         // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1229     {
1230         const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
1231                                     CSS_PROP_OUTLINE_COLOR
1232                                   };
1233         return parseShortHand(propId, properties, 3, important);
1234     }
1235     case CSS_PROP_BORDER_COLOR:
1236         // <color>{1,4} | inherit
1237     {
1238         const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
1239                                     CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR
1240                                   };
1241         return parse4Values(propId, properties, important);
1242     }
1243     case CSS_PROP_BORDER_WIDTH:
1244         // <border-width>{1,4} | inherit
1245     {
1246         const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
1247                                     CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH
1248                                   };
1249         return parse4Values(propId, properties, important);
1250     }
1251     case CSS_PROP_BORDER_STYLE:
1252         // <border-style>{1,4} | inherit
1253     {
1254         const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
1255                                     CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE
1256                                   };
1257         return parse4Values(propId, properties, important);
1258     }
1259     case CSS_PROP_MARGIN:
1260         // <margin-width>{1,4} | inherit
1261     {
1262         const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
1263                                     CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT
1264                                   };
1265         return parse4Values(propId, properties, important);
1266     }
1267     case CSS_PROP_PADDING:
1268         // <padding-width>{1,4} | inherit
1269     {
1270         const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
1271                                     CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT
1272                                   };
1273         return parse4Values(propId, properties, important);
1274     }
1275     case CSS_PROP_FONT: {
1276         return parseFontShorthand(important);
1277     }
1278     case CSS_PROP_LIST_STYLE: {
1279         return parseListStyleShorthand(important);
1280     }
1281     case CSS_PROP_WORD_WRAP:
1282         // normal | break-word
1283         if (id == CSS_VAL_NORMAL || id == CSS_VAL_BREAK_WORD) {
1284             valid_primitive = true;
1285         }
1286         break;
1287 
1288     default:
1289         return parseSVGValue(propId, important);
1290 // #ifdef CSS_DEBUG
1291 //         qCDebug(KHTML_LOG) << "illegal or CSS2 Aural property: " << val;
1292 // #endif
1293         //break;
1294     }
1295 
1296     if (valid_primitive) {
1297 
1298         if (id != 0) {
1299             parsedValue = new CSSPrimitiveValueImpl(id);
1300         } else if (value->unit == CSSPrimitiveValue::CSS_STRING)
1301             parsedValue = new CSSPrimitiveValueImpl(domString(value->string),
1302                                                     (CSSPrimitiveValue::UnitTypes) value->unit);
1303         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
1304                  value->unit <= CSSPrimitiveValue::CSS_KHZ) {
1305             parsedValue = new CSSPrimitiveValueImpl(value->fValue,
1306                                                     (CSSPrimitiveValue::UnitTypes) value->unit);
1307         } else if (value->unit >= Value::Q_EMS) {
1308             parsedValue = new CSSQuirkPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_EMS);
1309         }
1310         valueList->next();
1311     }
1312     if (parsedValue) {
1313         if (!valueList->current() || inShorthand()) {
1314             addProperty(propId, parsedValue, important);
1315             return true;
1316         }
1317         delete parsedValue;
1318     }
1319     return false;
1320 }
1321 
1322 void CSSParser::addBackgroundValue(CSSValueImpl *&lval, CSSValueImpl *rval)
1323 {
1324     if (lval) {
1325         if (lval->isValueList()) {
1326             static_cast<CSSValueListImpl *>(lval)->append(rval);
1327         } else {
1328             CSSValueImpl *oldVal = lval;
1329             CSSValueListImpl *list = new CSSValueListImpl(CSSValueListImpl::Comma);
1330             lval = list;
1331             list->append(oldVal);
1332             list->append(rval);
1333         }
1334     } else {
1335         lval = rval;
1336     }
1337 }
1338 
1339 bool CSSParser::parseBackgroundShorthand(bool important)
1340 {
1341     // Order is important in this array:
1342     // 'position' must come before color because a plain old "0" is a legal color in quirks mode
1343     //  but it's usually the X coordinate of a position.
1344     // 'size' must be the next property after 'position' in order to correctly parse '/size'.
1345     // 'origin' must come before 'clip' because the first <box> value found belongs to 'origin',
1346     //  the second (if any) to 'clip'.
1347     const int numProperties = 8;
1348     const int properties[numProperties] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
1349                                             CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION, CSS_PROP_BACKGROUND_SIZE,
1350                                             CSS_PROP_BACKGROUND_ORIGIN, CSS_PROP_BACKGROUND_CLIP, CSS_PROP_BACKGROUND_COLOR
1351                                           };
1352 
1353     ShorthandScope scope(this, CSS_PROP_BACKGROUND);
1354 
1355     bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
1356     CSSValueImpl *values[numProperties] = { nullptr }; // compiler will repeat 0 as necessary
1357     CSSValueImpl *positionYValue = nullptr;
1358     int parsedOriginIdent = 0;
1359     int i;
1360 
1361     while (valueList->current()) {
1362         Value *val = valueList->current();
1363         if (val->unit == Value::Operator && val->iValue == ',') {
1364             // We hit the end.  Fill in all remaining values with the initial value.
1365             valueList->next();
1366             for (i = 0; i < numProperties; ++i) {
1367                 if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i])
1368                     // Color is not allowed except as the last item in a list.  Reject the entire
1369                     // property.
1370                 {
1371                     goto fail;
1372                 }
1373 
1374                 if (!parsedProperty[i] && properties[i] != CSS_PROP_BACKGROUND_COLOR) {
1375                     if (properties[i] == CSS_PROP_BACKGROUND_CLIP && parsedOriginIdent != 0) {
1376                         addBackgroundValue(values[i], new CSSPrimitiveValueImpl(parsedOriginIdent));
1377                     } else {
1378                         addBackgroundValue(values[i], new CSSInitialValueImpl(true/*implicit initial*/));
1379                         if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1380                             addBackgroundValue(positionYValue, new CSSInitialValueImpl(true/*implicit initial*/));
1381                         }
1382                     }
1383                 }
1384                 parsedProperty[i] = false;
1385             }
1386             parsedOriginIdent = 0;
1387             if (!valueList->current()) {
1388                 break;
1389             }
1390         }
1391 
1392         bool found = false;
1393         for (i = 0; !found && i < numProperties; ++i) {
1394             if (!parsedProperty[i]) {
1395                 CSSValueImpl *val1 = nullptr, *val2 = nullptr;
1396                 int propId1, propId2;
1397                 if (parseBackgroundProperty(properties[i], propId1, propId2, val1, val2)) {
1398                     parsedProperty[i] = found = true;
1399                     addBackgroundValue(values[i], val1);
1400                     if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1401                         addBackgroundValue(positionYValue, val2);
1402                         // after 'position' there could be '/size', check for it
1403                         const Value *v = valueList->current();
1404                         if (v && v->unit == Value::Operator && v->iValue == '/') {
1405                             // next property _must_ be 'size'
1406                             valueList->next();
1407                             ++i; // 'size' is at the next position in properties[] array
1408                             CSSValueImpl *retVal1 = nullptr, *retVal2 = nullptr;
1409                             if (parseBackgroundProperty(properties[i], propId1, propId2, retVal1, retVal2)) {
1410                                 parsedProperty[i] = true;
1411                                 addBackgroundValue(values[i], retVal1);
1412                             } else {
1413                                 goto fail;
1414                             }
1415                         }
1416                     } else if (properties[i] == CSS_PROP_BACKGROUND_ORIGIN) {
1417                         parsedOriginIdent = static_cast<CSSPrimitiveValueImpl *>(val1)->getIdent();
1418                     } else if (properties[i] == CSS_PROP_BACKGROUND_SIZE) {
1419                         // we caught an invalid length|percent as background-size
1420                         goto fail;
1421                     }
1422                 }
1423             }
1424         }
1425 
1426         // if we didn't find at least one match, this is an
1427         // invalid shorthand and we have to ignore it
1428         if (!found) {
1429             goto fail;
1430         }
1431 
1432     } // end of while loop
1433 
1434     // Fill in any remaining properties with the initial value.
1435     for (i = 0; i < numProperties; ++i) {
1436         if (!parsedProperty[i]) {
1437             if (properties[i] == CSS_PROP_BACKGROUND_CLIP && parsedOriginIdent != 0) {
1438                 addBackgroundValue(values[i], new CSSPrimitiveValueImpl(parsedOriginIdent));
1439             } else {
1440                 addBackgroundValue(values[i], new CSSInitialValueImpl(true/*implicit initial*/));
1441                 if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1442                     addBackgroundValue(positionYValue, new CSSInitialValueImpl(true/*implicit initial*/));
1443                 }
1444             }
1445         }
1446     }
1447 
1448     // Now add all of the properties we found.
1449     for (i = 0; i < numProperties; i++) {
1450         if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1451             addProperty(CSS_PROP_BACKGROUND_POSITION_X, values[i], important);
1452             addProperty(CSS_PROP_BACKGROUND_POSITION_Y, positionYValue, important);
1453         } else {
1454             addProperty(properties[i], values[i], important);
1455         }
1456     }
1457 
1458     return true;
1459 
1460 fail:
1461     for (int k = 0; k < numProperties; k++) {
1462         delete values[k];
1463     }
1464     delete positionYValue;
1465     return false;
1466 }
1467 
1468 static void completeMissingRadii(SharedPtr<CSSPrimitiveValueImpl> *array)
1469 {
1470     if (!array[1]) {
1471         array[1] = array[0];    // top-left => top-right
1472     }
1473     if (!array[2]) {
1474         array[2] = array[0];    // top-left => bottom-right
1475     }
1476     if (!array[3]) {
1477         array[3] = array[1];    // top-left => bottom-right
1478     }
1479 }
1480 
1481 bool CSSParser::parseBorderRadius(bool important)
1482 {
1483     const int properties[4] = { CSS_PROP_BORDER_TOP_LEFT_RADIUS,
1484                                 CSS_PROP_BORDER_TOP_RIGHT_RADIUS,
1485                                 CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS,
1486                                 CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS
1487                               };
1488     SharedPtr<CSSPrimitiveValueImpl> horiz[4], vert[4];
1489 
1490     for (int c = 0; c < 4; ++c) {
1491         horiz[c] = nullptr;
1492         vert [c] = nullptr;
1493     }
1494 
1495     Value *value;
1496 
1497     // Parse horizontal ones until / or done.
1498     for (int c = 0; c < 4; ++c) {
1499         value = valueList->current();
1500         if (!value || (value->unit == Value::Operator && value->iValue == '/')) {
1501             break;    //Saw slash -- exit w/o consuming as we'll use it below.
1502         }
1503 
1504         if (!validUnit(value, FLength | FPercent | FNonNeg, strict)) {
1505             return false;
1506         }
1507 
1508         horiz[c] = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1509         value = valueList->next();
1510     }
1511 
1512     if (!horiz[0]) {
1513         return false;
1514     }
1515 
1516     completeMissingRadii(horiz);
1517 
1518     // Do we have vertical radii afterwards?
1519     if (value && value->unit == Value::Operator && value->iValue == '/') {
1520         valueList->next();
1521 
1522         for (int c = 0; c < 4; ++c) {
1523             // qCDebug(KHTML_LOG) << c;
1524             value = valueList->current();
1525             if (!value) {
1526                 break;
1527             }
1528 
1529             if (!validUnit(value, FLength | FPercent | FNonNeg, strict)) {
1530                 return false;
1531             }
1532 
1533             vert[c] = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1534             value = valueList->next();
1535         }
1536 
1537         // If we didn't parse anything, or there is stuff remaining, this is malformed
1538         if (!vert[0] || valueList->current()) {
1539             return false;
1540         }
1541 
1542         completeMissingRadii(vert);
1543     } else {
1544         // Nope -- we better be at the end.
1545         if (valueList->current()) {
1546             return false;
1547         }
1548 
1549         for (int c = 0; c < 4; ++c) {
1550             vert[c] = horiz[c];
1551         }
1552     }
1553 
1554     // All OK parsing, add properties
1555     for (int c = 0; c < 4; ++c)
1556         addProperty(properties[c], new CSSPrimitiveValueImpl(
1557                         new PairImpl(horiz[c].get(), vert[c].get())), important);
1558     return true;
1559 }
1560 
1561 bool CSSParser::parseShortHand(int propId, const int *properties, const int numProperties, bool important)
1562 {
1563     if (valueList->size() > numProperties) {
1564         // discard
1565         return false;
1566     }
1567 
1568     ShorthandScope scope(this, propId);
1569 
1570     // Store current numParsedProperties, we need it in case we should rollback later
1571     const int oldNumParsedProperties = numParsedProperties;
1572 
1573     // Setup an array of booleans to mark which property has been found
1574     bool fnd[6]; //Trust me ;)
1575     for (int i = 0; i < numProperties; i++) {
1576         fnd[i] = false;
1577     }
1578 
1579     bool discard = false;
1580     unsigned short numValidProperties = 0;
1581     bool foundValid = false;
1582     while (valueList->current()) {
1583         foundValid = false;
1584         for (int propIndex = 0; propIndex < numProperties; ++propIndex) {
1585             if (parseValue(properties[propIndex], important)) {
1586                 foundValid = true;
1587                 ++numValidProperties;
1588                 if (fnd[propIndex]) { // found a duplicate
1589                     discard = true;
1590                 } else {
1591                     fnd[propIndex] = true;
1592                 }
1593 
1594                 break;
1595             }
1596         }
1597 
1598         // if we didn't find at least one match, this is an
1599         // invalid shorthand and we have to ignore it
1600         if (!foundValid) {
1601             discard = true;
1602         }
1603 
1604         if (discard) {
1605             break;
1606         }
1607     }
1608 
1609     if (discard) {
1610         // Remove valid properties previously added by parseValue(), if any
1611         rollbackParsedProperties(oldNumParsedProperties);
1612         return false;
1613     }
1614 
1615     if (numValidProperties == numProperties) {
1616         return true;
1617     }
1618 
1619     // Fill in any remaining properties with the initial value.
1620     m_implicitShorthand = true;
1621     for (int i = 0; i < numProperties; ++i) {
1622         if (!fnd[i]) {
1623             addProperty(properties[i], new CSSInitialValueImpl(true/*implicit initial*/), important);
1624         }
1625     }
1626     m_implicitShorthand = false;
1627 
1628     return true;
1629 }
1630 
1631 bool CSSParser::parse4Values(int propId, const int *properties,  bool important)
1632 {
1633     /* From the CSS 2 specs, 8.3
1634      * If there is only one value, it applies to all sides. If there are two values, the top and
1635      * bottom margins are set to the first value and the right and left margins are set to the second.
1636      * If there are three values, the top is set to the first value, the left and right are set to the
1637      * second, and the bottom is set to the third. If there are four values, they apply to the top,
1638      * right, bottom, and left, respectively.
1639      */
1640 
1641     const int num = inShorthand() ? 1 : valueList->size();
1642     //qDebug("parse4Values: num=%d %d", num,  valueList->numValues );
1643 
1644     ShorthandScope scope(this, propId);
1645 
1646     const int oldNumParsedProperties = numParsedProperties;
1647     // the order is top, right, bottom, left
1648     switch (num) {
1649     case 1: {
1650         if (!parseValue(properties[0], important)) {
1651             return false;
1652         }
1653         CSSValueImpl *value = parsedProperties[numParsedProperties - 1]->value();
1654         m_implicitShorthand = true;
1655         addProperty(properties[1], value, important);
1656         addProperty(properties[2], value, important);
1657         addProperty(properties[3], value, important);
1658         m_implicitShorthand = false;
1659         break;
1660     }
1661     case 2: {
1662         if (!parseValue(properties[0], important) || !parseValue(properties[1], important)) {
1663             rollbackParsedProperties(oldNumParsedProperties);
1664             return false;
1665         }
1666         CSSValueImpl *value = parsedProperties[numParsedProperties - 2]->value();
1667         m_implicitShorthand = true;
1668         addProperty(properties[2], value, important);
1669         value = parsedProperties[numParsedProperties - 2]->value();
1670         addProperty(properties[3], value, important);
1671         m_implicitShorthand = false;
1672         break;
1673     }
1674     case 3: {
1675         if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important)) {
1676             rollbackParsedProperties(oldNumParsedProperties);
1677             return false;
1678         }
1679         CSSValueImpl *value = parsedProperties[numParsedProperties - 2]->value();
1680         m_implicitShorthand = true;
1681         addProperty(properties[3], value, important);
1682         m_implicitShorthand = false;
1683         break;
1684     }
1685     case 4: {
1686         if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
1687                 !parseValue(properties[2], important) || !parseValue(properties[3], important)) {
1688             rollbackParsedProperties(oldNumParsedProperties);
1689             return false;
1690         }
1691         break;
1692     }
1693     default: {
1694         return false;
1695     }
1696     }
1697 
1698     return true;
1699 }
1700 
1701 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1702 // in CSS 2.1 this got somewhat reduced:
1703 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1704 bool CSSParser::parseContent(int propId, bool important)
1705 {
1706     QScopedPointer<CSSValueListImpl> values(
1707             new CSSValueListImpl(CSSValueListImpl::Comma));
1708 
1709     bool isValid = true;
1710     Value *val;
1711     CSSValueImpl *parsedValue = nullptr;
1712     while ((val = valueList->current())) {
1713         parsedValue = nullptr;
1714         if (val->unit == CSSPrimitiveValue::CSS_URI) {
1715             if (styleElement) {
1716                 const DOMString uri = domString(val->string);
1717                 parsedValue = new CSSImageValueImpl(uri, styleElement);
1718 #ifdef CSS_DEBUG
1719                 qCDebug(KHTML_LOG) << "content, url=" << uri.string() << " base=" << styleElement->baseURL().url();
1720 #endif
1721             }
1722         } else if (val->unit == Value::Function) {
1723             // attr( X ) | counter( X [,Y] ) | counters( X, Y, [,Z] )
1724             ValueList *args = val->function->args;
1725             QString fname = qString(val->function->name).toLower();
1726             if (!args) {
1727                 return false;
1728             }
1729             if (fname == "attr(") {
1730                 if (args->size() != 1) {
1731                     return false;
1732                 }
1733                 Value *a = args->current();
1734                 if (a->unit != CSSPrimitiveValue::CSS_IDENT) {
1735                     isValid = false;
1736                     break;
1737                 }
1738                 if (qString(a->string)[0] == '-') {
1739                     isValid = false;
1740                     break;
1741                 }
1742                 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
1743             } else if (fname == "counter(") {
1744                 parsedValue = parseCounterContent(args, false);
1745                 if (!parsedValue) {
1746                     return false;
1747                 }
1748             } else if (fname == "counters(") {
1749                 parsedValue = parseCounterContent(args, true);
1750                 if (!parsedValue) {
1751                     return false;
1752                 }
1753             } else {
1754                 return false;
1755             }
1756 
1757         } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
1758             // open-quote | close-quote | no-open-quote | no-close-quote
1759             if (val->id == CSS_VAL_OPEN_QUOTE ||
1760                     val->id == CSS_VAL_CLOSE_QUOTE ||
1761                     val->id == CSS_VAL_NO_OPEN_QUOTE ||
1762                     val->id == CSS_VAL_NO_CLOSE_QUOTE) {
1763                 parsedValue = new CSSPrimitiveValueImpl(val->id);
1764             }
1765         } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
1766             parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
1767         }
1768 
1769         if (parsedValue) {
1770             values->append(parsedValue);
1771         } else {
1772             isValid = false;
1773             break;
1774         }
1775         valueList->next();
1776     }
1777     if (isValid && values->length()) {
1778         addProperty(propId, values.take(), important);
1779         valueList->next();
1780         return true;
1781     }
1782 
1783     return false;
1784 }
1785 
1786 CSSValueImpl *CSSParser::parseCounterContent(ValueList *args, bool counters)
1787 {
1788     const int argsSize = args->size();
1789     if (counters || (argsSize != 1 && argsSize != 3))
1790         if (!counters || (argsSize != 3 && argsSize != 5)) {
1791             return nullptr;
1792         }
1793 
1794     CounterImpl *counter = new CounterImpl;
1795     Value *i = args->current();
1796     if (i->unit != CSSPrimitiveValue::CSS_IDENT) {
1797         goto invalid;
1798     }
1799     if (qString(i->string)[0] == '-') {
1800         goto invalid;
1801     }
1802     counter->m_identifier = domString(i->string);
1803     if (counters) {
1804         i = args->next();
1805         if (i->unit != Value::Operator || i->iValue != ',') {
1806             goto invalid;
1807         }
1808         i = args->next();
1809         if (i->unit != CSSPrimitiveValue::CSS_STRING) {
1810             goto invalid;
1811         }
1812         counter->m_separator = domString(i->string);
1813     }
1814     counter->m_listStyle = CSS_VAL_DECIMAL - CSS_VAL_DISC;
1815     i = args->next();
1816     if (i) {
1817         if (i->unit != Value::Operator || i->iValue != ',') {
1818             goto invalid;
1819         }
1820         i = args->next();
1821         if (i->unit != CSSPrimitiveValue::CSS_IDENT) {
1822             goto invalid;
1823         }
1824         if (i->id < CSS_VAL_DISC || i->id > CSS_VAL__KHTML_CLOSE_QUOTE) {
1825             goto invalid;
1826         }
1827         counter->m_listStyle = i->id - CSS_VAL_DISC;
1828     }
1829     return new CSSPrimitiveValueImpl(counter);
1830 invalid:
1831     delete counter;
1832     return nullptr;
1833 }
1834 
1835 CSSValueImpl *CSSParser::parseBackgroundColor()
1836 {
1837     int id = valueList->current()->id;
1838     if (id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_TRANSPARENT || id == CSS_VAL_CURRENTCOLOR ||
1839             (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
1840             (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict)) {
1841         return new CSSPrimitiveValueImpl(id);
1842     }
1843     return parseColor();
1844 }
1845 
1846 CSSValueImpl *CSSParser::parseBackgroundImage(bool &didParse)
1847 {
1848     const Value *v = valueList->current();
1849     if (v->id == CSS_VAL_NONE) {
1850         didParse = true;
1851         return new CSSImageValueImpl();
1852     } else if (v->unit == CSSPrimitiveValue::CSS_URI) {
1853         didParse = true;
1854         if (styleElement) {
1855             const DOMString uri = domString(v->string);
1856             return new CSSImageValueImpl(uri, styleElement);
1857         } else {
1858             return nullptr;
1859         }
1860     } else {
1861         didParse = false;
1862         return nullptr;
1863     }
1864 }
1865 
1866 CSSValueImpl *CSSParser::parseBackgroundPositionXY(BackgroundPosKind &kindOut)
1867 {
1868     int id = valueList->current()->id;
1869     if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
1870         int percent = 0;
1871         if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
1872             kindOut = BgPos_X;
1873             if (id == CSS_VAL_RIGHT) {
1874                 percent = 100;
1875             }
1876         } else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
1877             kindOut = BgPos_Y;
1878             if (id == CSS_VAL_BOTTOM) {
1879                 percent = 100;
1880             }
1881         } else if (id == CSS_VAL_CENTER) {
1882             // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
1883             kindOut = BgPos_Center;
1884             percent = 50;
1885         }
1886         return new CSSPrimitiveValueImpl(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
1887     }
1888 
1889     if (validUnit(valueList->current(), FPercent | FLength, strict)) {
1890         kindOut = BgPos_NonKW;
1891         return new CSSPrimitiveValueImpl(valueList->current()->fValue,
1892                                          (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
1893     }
1894 
1895     return nullptr;
1896 }
1897 
1898 void CSSParser::parseBackgroundPosition(CSSValueImpl *&value1, CSSValueImpl *&value2)
1899 {
1900     value1 = value2 = nullptr;
1901 
1902     // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
1903     BackgroundPosKind value1pos;
1904     value1 = parseBackgroundPositionXY(value1pos);
1905     if (!value1) {
1906         return;
1907     }
1908 
1909     // Parse the second value, if any.
1910     Value *value = valueList->next();
1911 
1912     // First check for the comma.  If so, we are finished parsing this value or value pair.
1913     if (value && value->unit == Value::Operator && value->iValue == ',') {
1914         value = nullptr;
1915     }
1916 
1917     bool secondValueSpecifiedAndValid = false;
1918     BackgroundPosKind value2pos = BgPos_Center; // true if not specified.
1919     if (value) {
1920         value2 = parseBackgroundPositionXY(value2pos);
1921         if (value2) {
1922             secondValueSpecifiedAndValid = true;
1923         } else {
1924             if (!inShorthand()) {
1925                 delete value1;
1926                 value1 = nullptr;
1927                 return;
1928             }
1929         }
1930     }
1931 
1932     if (!value2)
1933         // Only one value was specified.  The other direction is always 50%.
1934         // If the one given was not a keyword, it should be viewed as 'x',
1935         // and so setting value2 would set y, as desired.
1936         // If the one value was a keyword, the swap below would put things in order
1937         // if needed.
1938     {
1939         value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
1940     }
1941 
1942     // Check for various failures
1943     bool ok = true;
1944 
1945     // Two keywords on the same axis.
1946     if (value1pos == BgPos_X && value2pos == BgPos_X) {
1947         ok = false;
1948     }
1949     if (value1pos == BgPos_Y && value2pos == BgPos_Y) {
1950         ok = false;
1951     }
1952 
1953     // Will we need to swap them?
1954     bool swap = (value1pos == BgPos_Y || value2pos == BgPos_X);
1955 
1956     // If we had a non-KW value and a keyword value that's in the "wrong" position,
1957     // this is malformed (#169612)
1958     if (swap && (value1pos == BgPos_NonKW || value2pos == BgPos_NonKW)) {
1959         ok = false;
1960     }
1961 
1962     if (!ok) {
1963         delete value1;
1964         delete value2;
1965         value1 = nullptr;
1966         value2 = nullptr;
1967         return;
1968     }
1969 
1970     if (swap) {
1971         // Swap our two values.
1972         CSSValueImpl *val = value2;
1973         value2 = value1;
1974         value1 = val;
1975     }
1976 
1977     if (secondValueSpecifiedAndValid) {
1978         valueList->next();
1979     }
1980 }
1981 
1982 CSSValueImpl *CSSParser::parseBackgroundSize()
1983 {
1984     Value *value = valueList->current();
1985 
1986     // Parse the first value.
1987     CSSPrimitiveValueImpl *parsedValue1;
1988 
1989     if (value->id == CSS_VAL_COVER || value->id == CSS_VAL_CONTAIN) {
1990         valueList->next();
1991         return new CSSPrimitiveValueImpl(value->id);
1992     }
1993 
1994     if (value->id == CSS_VAL_AUTO) {
1995         parsedValue1 = new CSSPrimitiveValueImpl(CSS_VAL_AUTO);
1996     } else if (validUnit(value, FLength | FPercent | FNonNeg, strict)) {
1997         parsedValue1 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1998     } else {
1999         return nullptr;
2000     }
2001 
2002     // Parse the second value, if any.
2003     value = valueList->next();
2004 
2005     // First check for the comma.  If so, we are finished parsing this value or value pair.
2006     if (value && value->unit == Value::Operator && value->iValue == ',') {
2007         value = nullptr;
2008     }
2009 
2010     CSSPrimitiveValueImpl *parsedValue2 = nullptr;
2011     if (value) {
2012         if (value->id == CSS_VAL_AUTO) {
2013             parsedValue2 = new CSSPrimitiveValueImpl(CSS_VAL_AUTO);
2014         } else if (validUnit(value, FLength | FPercent | FNonNeg, strict)) {
2015             parsedValue2 = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
2016         } else if (!inShorthand()) {
2017             delete parsedValue1;
2018             return nullptr;
2019         }
2020     }
2021 
2022     if (parsedValue2) {
2023         valueList->next();
2024     } else {
2025         // If only one value is given the second is assumed to be ‘auto’
2026         parsedValue2 = new CSSPrimitiveValueImpl(CSS_VAL_AUTO);
2027     }
2028 
2029     PairImpl *pair = new PairImpl(parsedValue1, parsedValue2);
2030     return new CSSPrimitiveValueImpl(pair);
2031 }
2032 
2033 bool CSSParser::parseBackgroundProperty(int propId, int &propId1, int &propId2,
2034                                         CSSValueImpl *&retValue1, CSSValueImpl *&retValue2)
2035 {
2036 #ifdef CSS_DEBUG
2037     qCDebug(KHTML_LOG) << "parseBackgroundProperty()";
2038     qCDebug(KHTML_LOG) << "LOOKING FOR: " << getPropertyName(propId).string();
2039 #endif
2040     Value *val;
2041     CSSValueListImpl *value  = new CSSValueListImpl(CSSValueListImpl::Comma);
2042     CSSValueListImpl *value2 = new CSSValueListImpl(CSSValueListImpl::Comma);
2043     bool expectComma = false;
2044 
2045     retValue1 = retValue2 = nullptr;
2046     propId1 = propId;
2047     propId2 = propId;
2048     if (propId == CSS_PROP_BACKGROUND_POSITION) {
2049         propId1 = CSS_PROP_BACKGROUND_POSITION_X;
2050         propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
2051     }
2052 
2053     while ((val = valueList->current())) {
2054         CSSValueImpl *currValue = nullptr, *currValue2 = nullptr;
2055         if (expectComma) {
2056             if (val->unit != Value::Operator || val->iValue != ',') {
2057                 goto failed;
2058             }
2059             valueList->next();
2060             expectComma = false;
2061         } else {
2062             switch (propId) {
2063             case CSS_PROP_BACKGROUND_ATTACHMENT:
2064                 if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED || val->id == CSS_VAL_LOCAL) {
2065                     currValue = new CSSPrimitiveValueImpl(val->id);
2066                     valueList->next();
2067                 }
2068                 break;
2069             case CSS_PROP_BACKGROUND_COLOR:
2070                 currValue = parseBackgroundColor();
2071                 if (currValue) {
2072                     valueList->next();
2073                 }
2074                 break;
2075             case CSS_PROP_BACKGROUND_IMAGE: {
2076                 bool didParse = false;
2077                 currValue = parseBackgroundImage(didParse);
2078                 if (didParse) {
2079                     valueList->next();
2080                 }
2081                 break;
2082             }
2083             case CSS_PROP_BACKGROUND_CLIP:
2084             case CSS_PROP_BACKGROUND_ORIGIN:
2085                 if (val->id == CSS_VAL_BORDER_BOX || val->id == CSS_VAL_PADDING_BOX || val->id == CSS_VAL_CONTENT_BOX) {
2086                     currValue = new CSSPrimitiveValueImpl(val->id);
2087                     valueList->next();
2088                 }
2089                 break;
2090             case CSS_PROP_BACKGROUND_POSITION:
2091                 parseBackgroundPosition(currValue, currValue2);
2092                 // parseBackgroundPosition advances the valueList pointer
2093                 break;
2094             case CSS_PROP_BACKGROUND_POSITION_X: {
2095                 BackgroundPosKind pos;
2096                 currValue = parseBackgroundPositionXY(pos);
2097                 if (currValue) {
2098                     if (pos == BgPos_Y) {
2099                         delete currValue;
2100                         currValue = nullptr;
2101                     } else {
2102                         valueList->next();
2103                     }
2104                 }
2105                 break;
2106             }
2107             case CSS_PROP_BACKGROUND_POSITION_Y: {
2108                 BackgroundPosKind pos;
2109                 currValue = parseBackgroundPositionXY(pos);
2110                 if (currValue) {
2111                     if (pos == BgPos_X) {
2112                         delete currValue;
2113                         currValue = nullptr;
2114                     } else {
2115                         valueList->next();
2116                     }
2117                 }
2118                 break;
2119             }
2120             case CSS_PROP_BACKGROUND_REPEAT:
2121                 if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
2122                     currValue = new CSSPrimitiveValueImpl(val->id);
2123                     valueList->next();
2124                 }
2125                 break;
2126             case CSS_PROP_BACKGROUND_SIZE:
2127                 currValue = parseBackgroundSize();
2128                 // parseBackgroundSize advances the valueList pointer
2129                 break;
2130             }
2131 
2132             if (!currValue) {
2133                 goto failed;
2134             }
2135 
2136             // When parsing the 'background' shorthand property return the parsed value...
2137             if (inShorthand()) {
2138                 retValue1 = currValue;
2139                 if (currValue2) {
2140                     retValue2 = currValue2;
2141                 }
2142                 delete value; delete value2;
2143                 return true;
2144             }
2145 
2146             // ...if not in shorthand, append to the list of value for the property
2147             // and expect a comma for the next value (if any)
2148             value->append(currValue);
2149             if (currValue2) {
2150                 value2->append(currValue2);
2151             }
2152             expectComma = true;
2153         }
2154     }
2155 
2156     // Now return the value list
2157     if (value->length() > 0) {
2158         retValue1 = value;
2159         if (value2->length() > 0) {
2160             retValue2 = value2;
2161         } else {
2162             delete value2;
2163         }
2164         return true;
2165     }
2166 
2167 failed:
2168     delete value; delete value2;
2169     return false;
2170 }
2171 
2172 bool CSSParser::parseShape(int propId, bool important)
2173 {
2174     Value *value = valueList->current();
2175     ValueList *args = value->function->args;
2176     QString fname = qString(value->function->name).toLower();
2177     //qDebug( "parseShape: fname: %d", fname.toLatin1().constData() );
2178     if (fname != "rect(" || !args) {
2179         return false;
2180     }
2181 
2182     const int argsSize = args->size();
2183     // rect( t, r, b, l ) || rect( t r b l )
2184     if (argsSize != 4 && argsSize != 7) {
2185         return false;
2186     }
2187     RectImpl *rect = new RectImpl();
2188     bool valid = true;
2189     int i = 0;
2190     Value *a = args->current();
2191     while (a) {
2192         CSSPrimitiveValueImpl *length;
2193         if (a->id == CSS_VAL_AUTO) {
2194             length = new CSSPrimitiveValueImpl(CSS_VAL_AUTO);
2195         } else {
2196             valid  = validUnit(a, FLength, strict);
2197             if (!valid) {
2198                 break;
2199             }
2200             length = new CSSPrimitiveValueImpl(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
2201         }
2202 
2203         if (i == 0) {
2204             rect->setTop(length);
2205         } else if (i == 1) {
2206             rect->setRight(length);
2207         } else if (i == 2) {
2208             rect->setBottom(length);
2209         } else {
2210             rect->setLeft(length);
2211         }
2212         a = args->next();
2213         if (a && argsSize == 7) {
2214             if (a->unit == Value::Operator && a->iValue == ',') {
2215                 a = args->next();
2216             } else {
2217                 valid = false;
2218                 break;
2219             }
2220         }
2221         i++;
2222     }
2223     if (valid) {
2224         addProperty(propId, new CSSPrimitiveValueImpl(rect), important);
2225         valueList->next();
2226         return true;
2227     }
2228     delete rect;
2229     return false;
2230 }
2231 
2232 // [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] |
2233 // caption | icon | menu | message-box | small-caption | status-bar
2234 bool CSSParser::parseFontShorthand(bool important)
2235 {
2236     Value *value = valueList->current();
2237     if (valueList->size() == 1) {
2238         // Must be a system font identifier
2239         if (value->id >= CSS_VAL_CAPTION && value->id <= CSS_VAL_STATUS_BAR) {
2240             addProperty(CSS_PROP_FONT, new CSSPrimitiveValueImpl(value->id), important);
2241             return true;
2242         }
2243         return false;
2244     }
2245     CSSValueListImpl *family = nullptr;
2246     CSSPrimitiveValueImpl *style = nullptr, *variant = nullptr, *weight = nullptr, *size = nullptr, *lineHeight = nullptr;
2247 
2248     ShorthandScope scope(this, CSS_PROP_FONT);
2249 
2250     // optional font-style, font-variant and font-weight
2251     while (value) {
2252         //qCWarning(KHTML_LOG) << "got value" << value->id << "/" <<
2253         //(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT ? qString(value->string) : QString());
2254         const int id = value->id;
2255 
2256         if (id == CSS_VAL_NORMAL) {
2257             // do nothing, it's the initial value for all three
2258         } else if (id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) {
2259             if (style) {
2260                 goto invalid;
2261             }
2262             style = new CSSPrimitiveValueImpl(id);
2263         } else if (id == CSS_VAL_SMALL_CAPS) {
2264             if (variant) {
2265                 goto invalid;
2266             }
2267             variant = new CSSPrimitiveValueImpl(id);
2268         } else if (int weightValueId = parseFontWeight(value, true)) {
2269             if (weight) {
2270                 goto invalid;
2271             }
2272             weight = new CSSPrimitiveValueImpl(weightValueId);
2273         } else {
2274             break;
2275         }
2276 
2277         value = valueList->next();
2278     }
2279 
2280     if (!value) {
2281         goto invalid;
2282     }
2283 
2284     // set undefined values to default
2285     if (!style) {
2286         style = new CSSPrimitiveValueImpl(CSS_VAL_NORMAL);
2287     }
2288     if (!variant) {
2289         variant = new CSSPrimitiveValueImpl(CSS_VAL_NORMAL);
2290     }
2291     if (!weight) {
2292         weight = new CSSPrimitiveValueImpl(CSS_VAL_NORMAL);
2293     }
2294 
2295     //qCWarning(KHTML_LOG) << "parsed style, variant, weight:" << style->cssText() << variant->cssText() << weight->cssText();
2296 
2297     // now a font-size _must_ come
2298     // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
2299     if (value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER) {
2300         size = new CSSPrimitiveValueImpl(value->id);
2301     } else if (validUnit(value, FLength | FPercent | FNonNeg, strict)) {
2302         size = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2303     }
2304     if (!size) {
2305         goto invalid;
2306     }
2307     //qCWarning(KHTML_LOG) << "parsed size:" << size->cssText();
2308 
2309     // now /line-height could come, next font-family _must_ come
2310     value = valueList->next();
2311     if (!value) {
2312         goto invalid;
2313     }
2314 
2315     if (value->unit == Value::Operator && value->iValue == '/') {
2316         // line-height
2317         value = valueList->next();
2318         if (!value) {
2319             goto invalid;
2320         }
2321         if (value->id == CSS_VAL_NORMAL) {
2322             // default value, nothing to do
2323         } else if (validUnit(value, FNumber | FLength | FPercent | FNonNeg, strict)) {
2324             lineHeight = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2325         } else {
2326             goto invalid;
2327         }
2328         value = valueList->next();
2329         if (!value) {
2330             goto invalid;
2331         }
2332     }
2333     // if undefined set to default
2334     if (!lineHeight) {
2335         lineHeight = new CSSPrimitiveValueImpl(CSS_VAL_NORMAL);
2336     }
2337     //qCWarning(KHTML_LOG) << "parsed line-height:" << lineHeight->cssText();
2338 
2339     // font-family _must_ come now
2340     family = parseFontFamily();
2341 
2342     if (valueList->current() || !family) {
2343         goto invalid;
2344     }
2345     //qCWarning(KHTML_LOG) << "parsed family:" << family->cssText();
2346 
2347     addProperty(CSS_PROP_FONT_FAMILY,  family,     important);
2348     addProperty(CSS_PROP_FONT_STYLE,   style,      important);
2349     addProperty(CSS_PROP_FONT_VARIANT, variant,    important);
2350     addProperty(CSS_PROP_FONT_WEIGHT,  weight,     important);
2351     addProperty(CSS_PROP_FONT_SIZE,    size,       important);
2352     addProperty(CSS_PROP_LINE_HEIGHT,  lineHeight, important);
2353     return true;
2354 
2355 invalid:
2356     //qCWarning(KHTML_LOG) << " -> invalid";
2357     delete family;
2358     delete style;
2359     delete variant;
2360     delete weight;
2361     delete size;
2362     delete lineHeight;
2363 
2364     return false;
2365 }
2366 
2367 int CSSParser::parseFontWeight(Value *val, bool strict)
2368 {
2369     const int valId = val->id;
2370     if (valId >= CSS_VAL_NORMAL && valId <= CSS_VAL_900) {
2371         // Valid primitive
2372         return valId;
2373     }
2374     if (validUnit(val, FInteger | FNonNeg, strict)) {
2375         int weight = static_cast<int>(val->fValue);
2376         if ((weight % 100)) {
2377             // Invalid
2378             return 0;
2379         }
2380         weight /= 100;
2381         if (weight >= 1 && weight <= 9) {
2382             return (CSS_VAL_100 + weight - 1);
2383         }
2384     }
2385     return 0;
2386 }
2387 
2388 CSSValueListImpl *CSSParser::parseFontFamily()
2389 {
2390 //     qCDebug(KHTML_LOG) << "CSSParser::parseFontFamily current=" << valueList->currentValue;
2391     CSSValueListImpl *list = new CSSValueListImpl(CSSValueListImpl::Comma);
2392     Value *value = valueList->current();
2393     QString currFace;
2394 
2395     while (value) {
2396 //         qCDebug(KHTML_LOG) << "got value " << value->id << " / "
2397 //                         << (value->unit == CSSPrimitiveValue::CSS_STRING ||
2398 //                             value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString() );
2399         Value *nextValue = valueList->next();
2400         bool nextValBreaksFont = !nextValue || (nextValue->unit == Value::Operator && nextValue->iValue == ',');
2401         bool nextValIsFontName = nextValue &&
2402                                  ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL_MONOSPACE) ||
2403                                   (nextValue->unit == CSSPrimitiveValue::CSS_STRING ||
2404                                    nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
2405 
2406         if (value->id == CSS_VAL_INHERIT && inShorthand() && currFace.isNull() && nextValBreaksFont) {
2407             // fail (#169610)
2408             delete list;
2409             return nullptr;
2410         }
2411 
2412         if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL_MONOSPACE) {
2413             if (!currFace.isNull()) {
2414                 currFace += ' ';
2415                 currFace += qString(value->string);
2416             } else if (nextValBreaksFont || !nextValIsFontName) {
2417                 if (!currFace.isNull()) {
2418                     list->append(new FontFamilyValueImpl(currFace));
2419                     currFace.clear();
2420                 }
2421                 list->append(new CSSPrimitiveValueImpl(value->id));
2422             } else {
2423                 currFace = qString(value->string);
2424             }
2425         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
2426             // Strings never share in a family name.
2427             currFace.clear();
2428             list->append(new FontFamilyValueImpl(qString(value->string)));
2429         } else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2430             if (!currFace.isNull()) {
2431                 currFace += ' ';
2432                 currFace += qString(value->string);
2433             } else if (nextValBreaksFont || !nextValIsFontName) {
2434                 if (!currFace.isNull()) {
2435                     list->append(new FontFamilyValueImpl(currFace));
2436                     currFace.clear();
2437                 }
2438                 list->append(new FontFamilyValueImpl(qString(value->string)));
2439             } else {
2440                 currFace = qString(value->string);
2441             }
2442         } else {
2443             //qCDebug(KHTML_LOG) << "invalid family part";
2444             break;
2445         }
2446 
2447         if (!nextValue) {
2448             break;
2449         }
2450 
2451         if (nextValBreaksFont) {
2452             value = valueList->next();
2453             if (!currFace.isNull()) {
2454                 list->append(new FontFamilyValueImpl(currFace));
2455             }
2456             currFace.clear();
2457         } else if (nextValIsFontName) {
2458             value = nextValue;
2459         } else {
2460             break;
2461         }
2462     }
2463 
2464     if (!currFace.isNull()) {
2465         list->append(new FontFamilyValueImpl(currFace));
2466     }
2467 
2468     if (!list->length()) {
2469         delete list;
2470         list = nullptr;
2471     }
2472     return list;
2473 }
2474 
2475 bool CSSParser::parseFontFaceSrc()
2476 {
2477     CSSValueListImpl *values = new CSSValueListImpl(CSSValueListImpl::Comma);
2478     Value *val;
2479     bool expectComma = false;
2480     bool allowFormat = false;
2481     bool failed = false;
2482     CSSFontFaceSrcValueImpl *uriValue = nullptr;
2483     while ((val = valueList->current())) {
2484         CSSFontFaceSrcValueImpl *parsedValue = nullptr;
2485         if (val->unit == CSSPrimitiveValue::CSS_URI && !expectComma && styleElement) {
2486             const DOMString uri = domString(val->string).trimSpaces();
2487             parsedValue = new CSSFontFaceSrcValueImpl(DOMString(QUrl(styleElement->baseURL()).resolved(QUrl(uri.string())).toString()), false /*local*/);
2488             uriValue = parsedValue;
2489             allowFormat = true;
2490             expectComma = true;
2491         } else if (val->unit == Value::Function) {
2492             // There are two allowed functions: local() and format().
2493             // For both we expect a string argument
2494             ValueList *args = val->function->args;
2495             if (args && args->size() == 1 &&
2496                     (args->current()->unit == CSSPrimitiveValue::CSS_STRING ||
2497                      args->current()->unit == CSSPrimitiveValue::CSS_IDENT)) {
2498                 if (!strcasecmp(domString(val->function->name), "local(") && !expectComma) {
2499                     expectComma = true;
2500                     allowFormat = false;
2501                     Value *a = args->current();
2502                     uriValue = nullptr;
2503                     parsedValue = new CSSFontFaceSrcValueImpl(domString(a->string), true /*local src*/);
2504                 } else if (!strcasecmp(domString(val->function->name), "format(") && allowFormat && uriValue) {
2505                     expectComma = true;
2506                     allowFormat = false;
2507                     uriValue->setFormat(domString(args->current()->string));
2508                     uriValue = nullptr;
2509                     valueList->next();
2510                     continue;
2511                 }
2512             }
2513         } else if (val->unit == Value::Operator && val->iValue == ',' && expectComma) {
2514             expectComma = false;
2515             allowFormat = false;
2516             uriValue = nullptr;
2517             valueList->next();
2518             continue;
2519         }
2520 
2521         if (parsedValue) {
2522             values->append(parsedValue);
2523         } else {
2524             failed = true;
2525             break;
2526         }
2527         valueList->next();
2528     }
2529 
2530     if (values->length() && !failed) {
2531         addProperty(CSS_PROP_SRC, values, important);
2532         valueList->next();
2533         return true;
2534     } else {
2535         delete values;
2536     }
2537 
2538     return false;
2539 }
2540 
2541 // [ <list-style-type> || <list-style-position> || <list-style-image> ]
2542 bool CSSParser::parseListStyleShorthand(bool important)
2543 {
2544     if (valueList->size() > 3) {
2545         // discard
2546         return false;
2547     }
2548 
2549     CSSValueImpl *type = nullptr;
2550     CSSValueImpl *position = nullptr;
2551     CSSValueImpl *image = nullptr;
2552 
2553     int numberOfNone = 0;
2554     Value *value = valueList->current();
2555     while (value) {
2556         const int valId = value->id;
2557         if (valId == CSS_VAL_NONE) {
2558             // just count
2559             ++numberOfNone;
2560         } else if (valId >= CSS_VAL_DISC && valId <= CSS_VAL__KHTML_CLOSE_QUOTE) {
2561             if (!type) {
2562                 type = new CSSPrimitiveValueImpl(valId);
2563             } else {
2564                 goto invalid;
2565             }
2566         } else if (valId == CSS_VAL_INSIDE || valId == CSS_VAL_OUTSIDE) {
2567             if (!position) {
2568                 position = new CSSPrimitiveValueImpl(valId);
2569             } else {
2570                 goto invalid;
2571             }
2572         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
2573             if (!image) {
2574                 // ### allow string in non strict mode?
2575                 if (styleElement) {
2576                     const DOMString uri = domString(value->string);
2577                     image = new CSSImageValueImpl(uri, styleElement);
2578                 }
2579             } else {
2580                 goto invalid;
2581             }
2582         } else {
2583             goto invalid;
2584         }
2585         value = valueList->next();
2586     }
2587 
2588     // Set whichever of 'list-style-type' and 'list-style-image' are not otherwise specified, to 'none'
2589     switch (numberOfNone) {
2590         case 0: {
2591             break;
2592         }
2593         case 1: {
2594             if (image && type) {
2595                 goto invalid;
2596             }
2597             if (!image) {
2598                 image = new CSSImageValueImpl();
2599             }
2600             if (!type) {
2601                 type = new CSSPrimitiveValueImpl(CSS_VAL_NONE);
2602             }
2603             break;
2604         }
2605         case 2: {
2606             if (image || type) {
2607                 goto invalid;
2608             } else {
2609                 image = new CSSImageValueImpl();
2610                 type = new CSSPrimitiveValueImpl(CSS_VAL_NONE);
2611             }
2612             break;
2613         }
2614         default: // numberOfNone == 3
2615             goto invalid;
2616     }
2617 
2618     // The shorthand is valid: fill-in any remaining properties with default value
2619     if (!type) {
2620         type = new CSSPrimitiveValueImpl(CSS_VAL_DISC);
2621     }
2622     if (!position) {
2623         position = new CSSPrimitiveValueImpl(CSS_VAL_OUTSIDE);
2624     }
2625     if (!image) {
2626         image = new CSSImageValueImpl();
2627     }
2628     addProperty(CSS_PROP_LIST_STYLE_TYPE, type, important);
2629     addProperty(CSS_PROP_LIST_STYLE_POSITION, position, important);
2630     addProperty(CSS_PROP_LIST_STYLE_IMAGE, image, important);
2631 
2632     return true;
2633 
2634 invalid:
2635     delete type;
2636     delete position;
2637     delete image;
2638 
2639     return false;
2640 }
2641 
2642 bool CSSParser::parseColorParameters(Value *value, int *colorArray, bool parseAlpha)
2643 {
2644     ValueList *args = value->function->args;
2645     Value *v = args->current();
2646 
2647     // Get the first value
2648     if (!validUnit(v, FInteger | FPercent, true)) {
2649         return false;
2650     }
2651     bool isPercent = (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE);
2652     colorArray[0] = static_cast<int>(v->fValue * (isPercent ? 256.0 / 100.0 : 1.0));
2653     for (int i = 1; i < 3; i++) {
2654         v = args->next();
2655         if (v->unit != Value::Operator && v->iValue != ',') {
2656             return false;
2657         }
2658         v = args->next();
2659         if (!validUnit(v, (isPercent ? FPercent : FInteger), true)) {
2660             return false;
2661         }
2662         colorArray[i] = static_cast<int>(v->fValue * (isPercent ? 256.0 / 100.0 : 1.0));
2663     }
2664     if (parseAlpha) {
2665         v = args->next();
2666         if (v->unit != Value::Operator && v->iValue != ',') {
2667             return false;
2668         }
2669         v = args->next();
2670         if (!validUnit(v, FNumber, true)) {
2671             return false;
2672         }
2673         colorArray[3] = static_cast<int>(qMax(0.0, qMin(1.0, v->fValue)) * 255); //krazy:exclude=qminmax
2674     }
2675     return true;
2676 }
2677 
2678 // CSS3 specification defines the format of a HSL color as
2679 // hsl(<number>, <percent>, <percent>)
2680 // and with alpha, the format is
2681 // hsla(<number>, <percent>, <percent>, <number>)
2682 // The first value, HUE, is in an angle with a value between 0 and 360
2683 bool CSSParser::parseHSLParameters(Value *value, double *colorArray, bool parseAlpha)
2684 {
2685     ValueList *args = value->function->args;
2686     Value *v = args->current();
2687     // Get the first value
2688     if (!validUnit(v, FInteger, true)) {
2689         return false;
2690     }
2691     // normalize the Hue value and change it to be between 0 and 1.0
2692     colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
2693     for (int i = 1; i < 3; i++) {
2694         v = args->next();
2695         if (v->unit != Value::Operator && v->iValue != ',') {
2696             return false;
2697         }
2698         v = args->next();
2699         if (!validUnit(v, FPercent, true)) {
2700             return false;
2701         }
2702         colorArray[i] = qMax(0.0, qMin(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0, krazy:exclude=qminmax
2703     }
2704     if (parseAlpha) {
2705         v = args->next();
2706         if (v->unit != Value::Operator && v->iValue != ',') {
2707             return false;
2708         }
2709         v = args->next();
2710         if (!validUnit(v, FNumber, true)) {
2711             return false;
2712         }
2713         colorArray[3] = qMax(0.0, qMin(1.0, v->fValue)); //krazy:exclude=qminmax
2714     }
2715     return true;
2716 }
2717 
2718 static int hex2int(unsigned short c, bool *error)
2719 {
2720     if (c >= '0' && c <= '9') {
2721         return c - '0';
2722     } else if (c >= 'A' && c <= 'F') {
2723         return 10 + c - 'A';
2724     } else if (c >= 'a' && c <= 'f') {
2725         return 10 + c - 'a';
2726     } else {
2727         *error = true;
2728         return -1;
2729     }
2730 }
2731 
2732 static bool parseColor(int unit, const QString &name, QRgb &rgb, bool strict)
2733 {
2734     int len = name.length();
2735 
2736     if (!len) {
2737         return false;
2738     }
2739 
2740     if (unit == CSSPrimitiveValue::CSS_RGBCOLOR || !strict) {
2741         const unsigned short *c =
2742             reinterpret_cast<const unsigned short *>(name.unicode());
2743 
2744         rgb = 0xff; // fixed alpha
2745         if (len == 6) {
2746             // RRGGBB
2747             bool error = false;
2748             for (int i = 0; i < 6; ++i, ++c) {
2749                 rgb = rgb << 4 | hex2int(*c, &error);
2750             }
2751             if (!error) {
2752                 return true;
2753             }
2754         } else if (len == 3) {
2755             // RGB, shortcut for RRGGBB
2756             bool error = false;
2757             for (int i = 0; i < 3; ++i, ++c) {
2758                 rgb = rgb << 8 | 0x11 * hex2int(*c, &error);
2759             }
2760             if (!error) {
2761                 return true;
2762             }
2763         }
2764     }
2765 
2766     if (unit == CSSPrimitiveValue::CSS_IDENT) {
2767         // try a little harder
2768         QColor tc;
2769         tc.setNamedColor(name.toLower());
2770         if (tc.isValid()) {
2771             rgb = tc.rgba();
2772             return true;
2773         }
2774     }
2775 
2776     return false;
2777 }
2778 
2779 CSSPrimitiveValueImpl *CSSParser::parseColor()
2780 {
2781     return parseColorFromValue(valueList->current());
2782 }
2783 
2784 CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value *value)
2785 {
2786     QRgb c = khtml::transparentColor;
2787     if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&             // color: 000000 (quirk)
2788             value->fValue >= 0. && value->fValue < 1000000.) {
2789         QString str;
2790         str.sprintf("%06d", (int)(value->fValue + .5));
2791         if (!::parseColor(CSSPrimitiveValue::CSS_RGBCOLOR, str, c, strict)) {
2792             return nullptr;
2793         }
2794     } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||               // color: #ff0000
2795                value->unit == CSSPrimitiveValue::CSS_IDENT ||                    // color: red || color: ff0000 (quirk)
2796                (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {   // color: 00ffff (quirk)
2797         if (!::parseColor(value->unit, qString(value->string), c, strict)) {
2798             return nullptr;
2799         }
2800     } else if (value->unit == Value::Function &&
2801                value->function->args != nullptr &&
2802                value->function->args->size() == 5 /* rgb + two commas */ &&
2803                qString(value->function->name).toLower() == "rgb(") {
2804         int colorValues[3];
2805         if (!parseColorParameters(value, colorValues, false)) {
2806             return nullptr;
2807         }
2808         colorValues[0] = qMax(0, qMin(255, colorValues[0]));
2809         colorValues[1] = qMax(0, qMin(255, colorValues[1]));
2810         colorValues[2] = qMax(0, qMin(255, colorValues[2]));
2811         c = qRgb(colorValues[0], colorValues[1], colorValues[2]);
2812     } else if (value->unit == Value::Function &&
2813                value->function->args != nullptr &&
2814                value->function->args->size() == 7 /* rgba + three commas */ &&
2815                domString(value->function->name).lower() == "rgba(") {
2816         int colorValues[4];
2817         if (!parseColorParameters(value, colorValues, true)) {
2818             return nullptr;
2819         }
2820         colorValues[0] = qMax(0, qMin(255, colorValues[0]));
2821         colorValues[1] = qMax(0, qMin(255, colorValues[1]));
2822         colorValues[2] = qMax(0, qMin(255, colorValues[2]));
2823         c = qRgba(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
2824     } else if (value->unit == Value::Function &&
2825                value->function->args != nullptr &&
2826                value->function->args->size() == 5 /* hsl + two commas */ &&
2827                domString(value->function->name).lower() == "hsl(") {
2828         double colorValues[3];
2829         if (!parseHSLParameters(value, colorValues, false)) {
2830             return nullptr;
2831         }
2832         c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], 1.0);
2833     } else if (value->unit == Value::Function &&
2834                value->function->args != nullptr &&
2835                value->function->args->size() == 7 /* hsla + three commas */ &&
2836                domString(value->function->name).lower() == "hsla(") {
2837         double colorValues[4];
2838         if (!parseHSLParameters(value, colorValues, true)) {
2839             return nullptr;
2840         }
2841         c = khtml::qRgbaFromHsla(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
2842     } else {
2843         return nullptr;
2844     }
2845 
2846     return new CSSPrimitiveValueImpl(c);
2847 }
2848 
2849 // This class tracks parsing state for shadow values.  If it goes out of scope (e.g., due to an early return)
2850 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
2851 struct ShadowParseContext {
2852     ShadowParseContext()
2853         : values(nullptr), x(nullptr), y(nullptr), blur(nullptr), color(nullptr),
2854           allowX(true), allowY(false), allowBlur(false), allowColor(true),
2855           allowBreak(true)
2856     {}
2857 
2858     ~ShadowParseContext()
2859     {
2860         if (!allowBreak) {
2861             delete values;
2862             delete x;
2863             delete y;
2864             delete blur;
2865             delete color;
2866         }
2867     }
2868 
2869     bool allowLength()
2870     {
2871         return allowX || allowY || allowBlur;
2872     }
2873 
2874     bool failed()
2875     {
2876         return allowBreak = false;
2877     }
2878 
2879     void commitValue()
2880     {
2881         // Handle the ,, case gracefully by doing nothing.
2882         if (x || y || blur || color) {
2883             if (!values) {
2884                 values = new CSSValueListImpl(CSSValueListImpl::Comma);
2885             }
2886 
2887             // Construct the current shadow value and add it to the list.
2888             values->append(new ShadowValueImpl(x, y, blur, color));
2889         }
2890 
2891         // Now reset for the next shadow value.
2892         x = y = blur = color = nullptr;
2893         allowX = allowColor = allowBreak = true;
2894         allowY = allowBlur = false;
2895     }
2896 
2897     void commitLength(Value *v)
2898     {
2899         CSSPrimitiveValueImpl *val = new CSSPrimitiveValueImpl(v->fValue,
2900                 (CSSPrimitiveValue::UnitTypes)v->unit);
2901         if (allowX) {
2902             x = val;
2903             allowX = false; allowY = true; allowColor = false; allowBreak = false;
2904         } else if (allowY) {
2905             y = val;
2906             allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
2907         } else if (allowBlur) {
2908             blur = val;
2909             allowBlur = false;
2910         } else {
2911             delete val;
2912         }
2913     }
2914 
2915     void commitColor(CSSPrimitiveValueImpl *val)
2916     {
2917         color = val;
2918         allowColor = false;
2919         if (allowX) {
2920             allowBreak = false;
2921         } else {
2922             allowBlur = false;
2923         }
2924     }
2925 
2926     CSSValueListImpl *values;
2927     CSSPrimitiveValueImpl *x;
2928     CSSPrimitiveValueImpl *y;
2929     CSSPrimitiveValueImpl *blur;
2930     CSSPrimitiveValueImpl *color;
2931 
2932     bool allowX;
2933     bool allowY;
2934     bool allowBlur;
2935     bool allowColor;
2936     bool allowBreak;
2937 };
2938 
2939 bool CSSParser::parseShadow(int propId, bool important)
2940 {
2941     ShadowParseContext context;
2942     Value *val;
2943     while ((val = valueList->current())) {
2944         // Check for a comma break first.
2945         if (val->unit == Value::Operator) {
2946             if (val->iValue != ',' || !context.allowBreak)
2947                 // Other operators aren't legal or we aren't done with the current shadow
2948                 // value.  Treat as invalid.
2949             {
2950                 return context.failed();
2951             }
2952 
2953             // The value is good.  Commit it.
2954             context.commitValue();
2955         }
2956         // Check to see if we're a length.
2957         else if (validUnit(val, FLength, true)) {
2958             // We required a length and didn't get one. Invalid.
2959             if (!context.allowLength()) {
2960                 return context.failed();
2961             }
2962 
2963             // A length is allowed here.  Construct the value and add it.
2964             context.commitLength(val);
2965         } else {
2966             // The only other type of value that's ok is a color value.
2967             CSSPrimitiveValueImpl *parsedColor = nullptr;
2968             bool isColor = ((val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT) ||
2969                             val->id == CSS_VAL_MENU ||
2970                             (val->id >= CSS_VAL_GREY && val->id <= CSS_VAL__KHTML_TEXT && !strict));
2971             if (!context.allowColor) {
2972                 return context.failed();
2973             }
2974 
2975             if (isColor) {
2976                 parsedColor = new CSSPrimitiveValueImpl(val->id);
2977             }
2978 
2979             if (!parsedColor)
2980                 // It's not built-in. Try to parse it as a color.
2981             {
2982                 parsedColor = parseColorFromValue(val);
2983             }
2984 
2985             if (!parsedColor) {
2986                 return context.failed();
2987             }
2988 
2989             context.commitColor(parsedColor);
2990         }
2991 
2992         valueList->next();
2993     }
2994 
2995     if (context.allowBreak) {
2996         context.commitValue();
2997         if (context.values->length()) {
2998             addProperty(propId, context.values, important);
2999             valueList->next();
3000             return true;
3001         }
3002     }
3003 
3004     return context.failed();
3005 }
3006 
3007 bool CSSParser::parseCounter(int propId, bool increment, bool important)
3008 {
3009     enum { ID, VAL, COMMA } state = ID;
3010 
3011     CSSValueListImpl *list = new CSSValueListImpl;
3012     DOMString c;
3013     Value *val;
3014     while (true) {
3015         val = valueList->current();
3016         switch (state) {
3017         // Commas are not allowed according to the standard, but Opera allows them and being the only
3018         // other browser with counter support we need to match their behavior to work with current use
3019         case COMMA:
3020             state = ID;
3021             if (val && val->unit == Value::Operator && val->iValue == ',') {
3022                 valueList->next();
3023                 continue;
3024             }
3025         // no break
3026         case ID:
3027             if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
3028                 c = qString(val->string);
3029                 state = VAL;
3030                 valueList->next();
3031                 continue;
3032             }
3033             break;
3034         case VAL: {
3035             short i = 0;
3036             if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
3037                 i = (short)val->fValue;
3038                 valueList->next();
3039             } else {
3040                 i = (increment) ? 1 : 0;
3041             }
3042 
3043             CounterActImpl *cv = new CounterActImpl(c, i);
3044             list->append(cv);
3045             state = COMMA;
3046             continue;
3047         }
3048         }
3049         break;
3050     }
3051     if (list->length() > 0) {
3052         addProperty(propId, list, important);
3053         return true;
3054     }
3055     delete list;
3056     return false;
3057 }
3058 
3059 static inline int yyerror(const char *str)
3060 {
3061 //    assert( 0 );
3062 #ifdef CSS_DEBUG
3063     qCDebug(KHTML_LOG) << "CSS parse error " << str;
3064 #else
3065     Q_UNUSED(str);
3066 #endif
3067     return 1;
3068 }
3069 
3070 static const double dIntMax = INT_MAX;
3071 #define END 0
3072 
3073 #include "parser.h"
3074 
3075 int DOM::CSSParser::lex(void *_yylval)
3076 {
3077     YYSTYPE *yylval = (YYSTYPE *)_yylval;
3078     int token = lex();
3079     int length;
3080     unsigned short *t = text(&length);
3081 
3082 #ifdef TOKEN_DEBUG
3083     qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString((QChar *)t, length).toLatin1().constData());
3084 #endif
3085     switch (token) {
3086     case '{':
3087         block_nesting++;
3088         break;
3089     case '}':
3090         if (block_nesting) {
3091             block_nesting--;
3092         }
3093         break;
3094     case END:
3095         if (block_nesting) {
3096             block_nesting--;
3097             return '}';
3098         }
3099         break;
3100     case S:
3101     case SGML_CD:
3102     case INCLUDES:
3103     case DASHMATCH:
3104         break;
3105 
3106     case URI:
3107     case STRING:
3108     case IDENT:
3109     case NTH:
3110     case HASH:
3111     case HEXCOLOR:
3112     case DIMEN:
3113     case UNICODERANGE:
3114     case NOTFUNCTION:
3115     case FUNCTION:
3116         yylval->string.string = t;
3117         yylval->string.length = length;
3118         break;
3119 
3120     case IMPORT_SYM:
3121     case PAGE_SYM:
3122     case MEDIA_SYM:
3123     case FONT_FACE_SYM:
3124     case CHARSET_SYM:
3125     case NAMESPACE_SYM:
3126 
3127     case IMPORTANT_SYM:
3128         break;
3129 
3130     case QEMS:
3131         length--;
3132     case GRADS:
3133     case DPCM:
3134         length--;
3135     case DEGS:
3136     case RADS:
3137     case KHERZ:
3138     case DPI:
3139     case REMS:
3140         length--;
3141     case MSECS:
3142     case HERZ:
3143     case EMS:
3144     case EXS:
3145     case CHS:
3146     case PXS:
3147     case CMS:
3148     case MMS:
3149     case INS:
3150     case PTS:
3151     case PCS:
3152         length--;
3153     case SECS:
3154     case PERCENTAGE:
3155         length--;
3156     case FLOAT:
3157     case INTEGER:
3158         yylval->val = qMin(QString((QChar *)t, length).toDouble(), dIntMax);
3159         //qDebug("value = %s, converted=%.2f", QString((QChar *)t, length).toLatin1().constData(), yylval->val);
3160         break;
3161 
3162     default:
3163         break;
3164     }
3165 
3166     return token;
3167 }
3168 
3169 static inline int toHex(char c)
3170 {
3171     if ('0' <= c && c <= '9') {
3172         return c - '0';
3173     }
3174     if ('a' <= c && c <= 'f') {
3175         return c - 'a' + 10;
3176     }
3177     if ('A' <= c && c <= 'F') {
3178         return c - 'A' + 10;
3179     }
3180     return 0;
3181 }
3182 
3183 unsigned short *DOM::CSSParser::text(int *length)
3184 {
3185     unsigned short *start = yytext;
3186     int l = yyleng;
3187     switch (yyTok) {
3188     case STRING:
3189         l--;
3190     /* nobreak */
3191     case HASH:
3192     case HEXCOLOR:
3193         start++;
3194         l--;
3195         break;
3196     case URI:
3197         // "url("{w}{string}{w}")"
3198         // "url("{w}{url}{w}")"
3199 
3200         // strip "url(" and ")"
3201         start += 4;
3202         l -= 5;
3203         // strip {w}
3204         while (l &&
3205                 (*start == ' ' || *start == '\t' || *start == '\r' ||
3206                  *start == '\n' || *start == '\f')) {
3207             start++; l--;
3208         }
3209         if (*start == '"' || *start == '\'') {
3210             start++; l--;
3211         }
3212         while (l &&
3213                 (start[l - 1] == ' ' || start[l - 1] == '\t' || start[l - 1] == '\r' ||
3214                  start[l - 1] == '\n' || start[l - 1] == '\f')) {
3215             l--;
3216         }
3217         if (l && (start[l - 1] == '\"' || start[l - 1] == '\'')) {
3218             l--;
3219         }
3220 
3221     default:
3222         break;
3223     }
3224 
3225     // process escapes
3226     unsigned short *out = start;
3227     unsigned short *escape = nullptr;
3228 
3229     for (int i = 0; i < l; i++) {
3230         unsigned short *current = start + i;
3231         if (escape == current - 1) {
3232             if ((*current >= '0' && *current <= '9') ||
3233                     (*current >= 'a' && *current <= 'f') ||
3234                     (*current >= 'A' && *current <= 'F')) {
3235                 continue;
3236             }
3237             if (yyTok == STRING &&
3238                     (*current == '\n' || *current == '\r' || *current == '\f')) {
3239                 // ### handle \r\n case
3240                 if (*current != '\r') {
3241                     escape = nullptr;
3242                 }
3243                 continue;
3244             }
3245             // in all other cases copy the char to output
3246             // ###
3247             *out++ = *current;
3248             escape = nullptr;
3249             continue;
3250         }
3251         if (escape == current - 2 && yyTok == STRING &&
3252                 *(current - 1) == '\r' && *current == '\n') {
3253             escape = nullptr;
3254             continue;
3255         }
3256         if (escape > current - 7 &&
3257                 ((*current >= '0' && *current <= '9') ||
3258                  (*current >= 'a' && *current <= 'f') ||
3259                  (*current >= 'A' && *current <= 'F'))) {
3260             continue;
3261         }
3262         if (escape) {
3263             // add escaped char
3264             int uc = 0;
3265             escape++;
3266             while (escape < current) {
3267 //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
3268                 uc *= 16;
3269                 uc += toHex(*escape);
3270                 escape++;
3271             }
3272 //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).toLatin1().constData(), uc );
3273             // can't handle chars outside utf16
3274             if (uc > 0xffff) {
3275                 uc = 0xfffd;
3276             }
3277             *(out++) = (unsigned short)uc;
3278             escape = nullptr;
3279             if (*current == ' ' ||
3280                     *current == '\t' ||
3281                     *current == '\r' ||
3282                     *current == '\n' ||
3283                     *current == '\f') {
3284                 continue;
3285             }
3286         }
3287         if (!escape && *current == '\\') {
3288             escape = current;
3289             continue;
3290         }
3291         *(out++) = *current;
3292     }
3293     if (escape) {
3294         // add escaped char
3295         int uc = 0;
3296         escape++;
3297         while (escape < start + l) {
3298             //                 qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
3299             uc *= 16;
3300             uc += toHex(*escape);
3301             escape++;
3302         }
3303         //             qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).toLatin1().constData(), uc );
3304         // can't handle chars outside utf16
3305         if (uc > 0xffff) {
3306             uc = 0xfffd;
3307         }
3308         *(out++) = (unsigned short)uc;
3309     }
3310 
3311     *length = out - start;
3312     return start;
3313 }
3314 
3315 // When we reach the end of the input we switch over
3316 // the lexer to this alternative buffer and keep it stuck here.
3317 // (and as it contains nulls, flex will keep on reporting
3318 //  end of buffer, and we will keep reseting the input
3319 //  pointer to the beginning of this).
3320 static unsigned short postEofBuf[2];
3321 
3322 #define YY_DECL int DOM::CSSParser::lex()
3323 #define yyconst const
3324 typedef int yy_state_type;
3325 typedef unsigned int YY_CHAR;
3326 // this line makes sure we treat all Unicode chars correctly.
3327 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
3328 #define YY_DO_BEFORE_ACTION \
3329     yytext = yy_bp; \
3330     yyleng = (int) (yy_cp - yy_bp); \
3331     yy_hold_char = *yy_cp; \
3332     *yy_cp = 0; \
3333     yy_c_buf_p = yy_cp;
3334 #define YY_BREAK break;
3335 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).toLatin1().constData() )
3336 #define YY_RULE_SETUP
3337 #define INITIAL 0
3338 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
3339 #define YY_START ((yy_start - 1) / 2)
3340 #define yyterminate()\
3341     do { \
3342         if (yy_act == YY_END_OF_BUFFER) { \
3343             yy_c_buf_p = postEofBuf; \
3344             yy_hold_char = 0; /* first char of the postEndOf to 'restore' */ \
3345         } \
3346         yyTok = END; return yyTok; \
3347     } while (0)
3348 #define YY_FATAL_ERROR(a) qFatal(a)
3349 #define BEGIN yy_start = 1 + 2 *
3350 #define COMMENT 1
3351 
3352 #include "tokenizer.cpp"