KHtml

cssparser.cpp
1 /*
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright 2003 Lars Knoll ([email protected])
5  * Copyright 2005 Allan Sandfeld Jensen ([email protected])
6  * Copyright (C) 2004, 2005, 2006, 2007 Apple Computer, Inc.
7  * Copyright (C) 2008 Maksim Orlovich <[email protected]>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 // #define CSS_DEBUG
26 // #define TOKEN_DEBUG
27 #define YYDEBUG 0
28 
29 #include "cssparser.h"
30 
31 #include "khtml_debug.h"
32 #include <QUrl>
33 #include <QScopedPointer>
34 
35 #include "css_valueimpl.h"
36 #include "css_ruleimpl.h"
37 #include "css_stylesheetimpl.h"
38 #include "css_mediaquery.h"
39 #include "cssproperties.h"
40 #include "cssvalues.h"
41 
42 #include <stdlib.h>
43 #include <assert.h>
44 
45 using namespace DOM;
46 
47 // used to promote background: left to left center
48 #define BACKGROUND_SKIP_CENTER( num ) \
49  if ( !pos_ok[ num ] && expected != 1 ) { \
50  pos_ok[num] = true; \
51  pos[num] = 0; \
52  skip_next = false; \
53  }
54 
55 ValueList::~ValueList()
56 {
57  const int numValues = m_values.size();
58  for (int i = 0; i < numValues; i++)
59  if (m_values[i].unit == Value::Function) {
60  delete m_values[i].function;
61  }
62 }
63 
64 namespace
65 {
66 class ShorthandScope
67 {
68 public:
69  ShorthandScope(CSSParser *parser, int propId) : m_parser(parser)
70  {
71  if (!(m_parser->m_inParseShorthand++)) {
72  m_parser->m_currentShorthand = propId;
73  }
74  }
75  ~ShorthandScope()
76  {
77  if (!(--m_parser->m_inParseShorthand)) {
78  m_parser->m_currentShorthand = 0;
79  }
80  }
81 
82 private:
83  CSSParser *m_parser;
84 };
85 }
86 
87 using namespace DOM;
88 
89 #if YYDEBUG > 0
90 extern int cssyydebug;
91 #endif
92 
93 extern int cssyyparse(void *parser);
94 
95 CSSParser *CSSParser::currentParser = nullptr;
96 
97 CSSParser::CSSParser(bool strictParsing)
98 {
99 #ifdef CSS_DEBUG
100  qCDebug(KHTML_LOG) << "CSSParser::CSSParser this=" << this;
101 #endif
102  strict = strictParsing;
103 
104  parsedProperties = (CSSProperty **) malloc(32 * sizeof(CSSProperty *));
105  numParsedProperties = 0;
106  maxParsedProperties = 32;
107 
108  data = nullptr;
109  valueList = nullptr;
110  rule = nullptr;
111  id = 0;
112  important = false;
113 
114  m_inParseShorthand = 0;
115  m_currentShorthand = 0;
116  m_implicitShorthand = false;
117 
118  yy_start = 1;
119 
120 #if YYDEBUG > 0
121  cssyydebug = 1;
122 #endif
123 
124 }
125 
126 CSSParser::~CSSParser()
127 {
128  if (numParsedProperties) {
129  clearProperties();
130  }
131  free(parsedProperties);
132 
133  delete valueList;
134 
135 #ifdef CSS_DEBUG
136  qCDebug(KHTML_LOG) << "CSSParser::~CSSParser this=" << this;
137 #endif
138 
139  free(data);
140 
141 }
142 
143 unsigned int CSSParser::defaultNamespace()
144 {
145  if (styleElement && styleElement->isCSSStyleSheet()) {
146  return static_cast<CSSStyleSheetImpl *>(styleElement)->defaultNamespace();
147  } else {
148  return anyNamespace;
149  }
150 }
151 
152 void CSSParser::runParser()
153 {
154  CSSParser *old = currentParser;
155  currentParser = this;
156  cssyyparse(this);
157  currentParser = old;
158  boundLocalNames.clear();
159 }
160 
161 void CSSParser::setupParser(const char *prefix, const DOMString &string, const char *suffix)
162 {
163  unsigned preflen = strlen(prefix);
164  unsigned sufflen = strlen(suffix);
165  int length = string.length() + preflen + sufflen + 8;
166 
167  free(data);
168 
169  data = (unsigned short *)malloc(length * sizeof(unsigned short));
170  for (unsigned i = 0; i < preflen; i++) {
171  data[i] = prefix[i];
172  }
173 
174  memcpy(data + preflen, string.unicode(), string.length()*sizeof(unsigned short));
175 
176  unsigned start = preflen + string.length();
177  unsigned end = start + sufflen;
178  for (unsigned i = start; i < end; i++) {
179  data[i] = suffix[i - start];
180  }
181 
182  // the flex scanner sometimes give invalid reads for any
183  // smaller padding - try e.g. css/invalid-rules-005.html or see #167318
184  data[length - 1] = 0;
185  data[length - 2] = 0;
186  data[length - 3] = 0;
187  data[length - 4] = 0;
188  data[length - 5] = 0;
189  data[length - 6] = 0;
190  data[length - 7] = 0;
191  data[length - 8] = 0;
192 
193  yyTok = -1;
194  block_nesting = 0;
195  yy_hold_char = 0;
196  yyleng = 0;
197  yytext = yy_c_buf_p = data;
198  yy_hold_char = *yy_c_buf_p;
199 }
200 
201 void CSSParser::parseSheet(CSSStyleSheetImpl *sheet, const DOMString &string)
202 {
203  styleElement = sheet;
204  styleDocument = nullptr;
205 
206  setupParser("", string, "");
207 
208 #ifdef CSS_DEBUG
209  qCDebug(KHTML_LOG) << ">>>>>>> start parsing style sheet";
210 #endif
211  runParser();
212 #ifdef CSS_DEBUG
213  qCDebug(KHTML_LOG) << "<<<<<<< done parsing style sheet";
214 #endif
215 
216  delete rule;
217  rule = nullptr;
218 }
219 
220 CSSRuleImpl *CSSParser::parseRule(DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string)
221 {
222  styleElement = sheet;
223  styleDocument = nullptr;
224 
225  setupParser("@-khtml-rule{", string, "} ");
226  runParser();
227 
228  CSSRuleImpl *result = rule;
229  rule = nullptr;
230 
231  return result;
232 }
233 
234 static void addParsedProperties(DOM::CSSStyleDeclarationImpl *declaration, CSSProperty **parsedProperties,
235  int numProperties)
236 {
237  for (int i = 0; i < numProperties; i++) {
238  // Only add properties that have no !important counterpart present
239  if (!declaration->getPropertyPriority(parsedProperties[i]->id()) || parsedProperties[i]->isImportant()) {
240  declaration->removeProperty(parsedProperties[i]->m_id);
241  declaration->values()->append(parsedProperties[i]);
242  }
243  }
244 }
245 
246 bool CSSParser::parseValue(DOM::CSSStyleDeclarationImpl *declaration, int _id, const DOM::DOMString &string,
247  bool _important)
248 {
249 #ifdef CSS_DEBUG
250  qCDebug(KHTML_LOG) << "CSSParser::parseValue: id=" << _id << " important=" << _important
251  << " value='" << string.string() << "'";
252 #endif
253 
254  styleElement = declaration->stylesheet();
255  styleDocument = nullptr;
256 
257  setupParser("@-khtml-value{", string, "} ");
258 
259  id = _id;
260  important = _important;
261 
262  runParser();
263 
264  delete rule;
265  rule = nullptr;
266 
267  bool ok = false;
268  if (numParsedProperties) {
269  ok = true;
270  addParsedProperties(declaration, parsedProperties, numParsedProperties);
271  numParsedProperties = 0;
272  }
273 
274  return ok;
275 }
276 
277 bool CSSParser::parseDeclaration(DOM::CSSStyleDeclarationImpl *declaration, const DOM::DOMString &string)
278 {
279 #ifdef CSS_DEBUG
280  qCDebug(KHTML_LOG) << "CSSParser::parseDeclaration:"
281  << " value='" << string.string() << "'";
282 #endif
283 
284  styleElement = declaration->stylesheet();
285  styleDocument = nullptr;
286 
287  setupParser("@-khtml-decls{", string, "} ");
288  runParser();
289 
290  delete rule;
291  rule = nullptr;
292 
293  bool ok = false;
294  if (numParsedProperties) {
295  ok = true;
296  addParsedProperties(declaration, parsedProperties, numParsedProperties);
297  numParsedProperties = 0;
298  }
299 
300  return ok;
301 }
302 
303 bool CSSParser::parseMediaQuery(DOM::MediaListImpl *queries, const DOM::DOMString &string)
304 {
305  if (string.isEmpty() || string.isNull()) {
306  return true;
307  }
308 
309  mediaQuery = nullptr;
310  // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
311  // instead insert one " " (which is S in parser.y)
312  setupParser("@-khtml-mediaquery ", string, "} ");
313  runParser();
314 
315  bool ok = false;
316  if (mediaQuery) {
317  ok = true;
318  queries->appendMediaQuery(mediaQuery);
319  mediaQuery = nullptr;
320  }
321 
322  return ok;
323 }
324 
325 QList<DOM::CSSSelector *> CSSParser::parseSelectorList(DOM::DocumentImpl *doc, const DOM::DOMString &string)
326 {
327  styleElement = nullptr;
328  styleDocument = doc;
329  selectors.clear();
330  setupParser("@-khtml-selectors{", string, "} ");
331  runParser();
332 
333  // Make sure to detect problems with pseudos, too
334  bool ok = true;
335  for (int i = 0; i < selectors.size(); ++i) {
336  // we need to check not only us, but also other things we're connected to via
337  // combinators
338  for (DOM::CSSSelector *sel = selectors[i]; sel; sel = sel->tagHistory) {
339  if (sel->match == CSSSelector::PseudoClass || sel->match == CSSSelector::PseudoElement) {
340  if (sel->pseudoType() == CSSSelector::PseudoOther) {
341  ok = false;
342  break;
343  }
344  }
345  }
346  }
347 
348  if (!ok) {
349  qDeleteAll(selectors);
350  selectors.clear();
351  }
352 
353  return selectors;
354 }
355 
356 void CSSParser::addProperty(int propId, CSSValueImpl *value, bool important)
357 {
358  CSSProperty *prop = new CSSProperty;
359  prop->m_id = propId;
360  prop->setValue(value);
361  prop->m_important = important;
362  prop->m_implicit = m_implicitShorthand;
363 
364  if (numParsedProperties >= maxParsedProperties) {
365  maxParsedProperties += 32;
366  parsedProperties = (CSSProperty **) realloc(parsedProperties,
367  maxParsedProperties * sizeof(CSSProperty *));
368  }
369  parsedProperties[numParsedProperties++] = prop;
370 }
371 
372 void CSSParser::rollbackParsedProperties(int toNumParsedProperties)
373 {
374  while (numParsedProperties > toNumParsedProperties) {
375  --numParsedProperties;
376  delete parsedProperties[numParsedProperties];
377  }
378 }
379 
380 CSSStyleDeclarationImpl *CSSParser::createStyleDeclaration(CSSStyleRuleImpl *rule)
381 {
383  for (int i = 0; i < numParsedProperties; i++) {
384  propList->append(parsedProperties[i]);
385  }
386 
387  numParsedProperties = 0;
388  return new CSSStyleDeclarationImpl(rule, propList);
389 }
390 
391 CSSStyleDeclarationImpl *CSSParser::createFontFaceStyleDeclaration(CSSFontFaceRuleImpl *rule)
392 {
394  CSSProperty *overriddenSrcProperty = nullptr;
395  for (int i = 0; i < numParsedProperties; i++) {
396  CSSProperty *property = parsedProperties[i];
397  int id = property->id();
398  if ((id == CSS_PROP_FONT_WEIGHT || id == CSS_PROP_FONT_STYLE || id == CSS_PROP_FONT_VARIANT) && property->value()->isPrimitiveValue()) {
399  // change those to a list of values containing a single value, so that we may always cast to a list in the CSSFontSelector.
400  CSSValueImpl *value = property->value();
401  value->ref();
402  property->setValue(new CSSValueListImpl(CSSValueListImpl::Comma));
403  static_cast<CSSValueListImpl *>(property->value())->append(value);
404  value->deref();
405  } else if (id == CSS_PROP_SRC) {
406  overriddenSrcProperty = property;
407  continue;
408  }
409 
410  propList->append(property);
411  }
412 
413  if (overriddenSrcProperty) {
414  propList->append(overriddenSrcProperty);
415  }
416 
417  numParsedProperties = 0;
418  return new CSSStyleDeclarationImpl(rule, propList);
419 }
420 
421 void CSSParser::clearProperties()
422 {
423  for (int i = 0; i < numParsedProperties; i++) {
424  delete parsedProperties[i];
425  }
426  numParsedProperties = 0;
427 }
428 
429 DOM::DocumentImpl *CSSParser::document() const
430 {
431  if (!styleDocument) {
432  const StyleBaseImpl *root = styleElement;
433  while (root->parent()) {
434  root = root->parent();
435  }
436  if (root->isCSSStyleSheet()) {
437  styleDocument = static_cast<const CSSStyleSheetImpl *>(root)->doc();
438  }
439  }
440  return styleDocument;
441 }
442 
443 bool CSSParser::validUnit(Value *value, int unitflags, bool strict)
444 {
445  if (unitflags & FNonNeg && value->fValue < 0) {
446  return false;
447  }
448 
449  bool b = false;
450  switch (value->unit) {
451  case CSSPrimitiveValue::CSS_NUMBER:
452  b = (unitflags & FNumber);
453  if (!b && ((unitflags & FLength) && (value->fValue == 0 || !strict))) {
454  value->unit = CSSPrimitiveValue::CSS_PX;
455  b = true;
456  }
457  if (!b && (unitflags & FInteger) && value->isInt) {
458  b = true;
459  }
460  break;
461  case CSSPrimitiveValue::CSS_PERCENTAGE:
462  b = (unitflags & FPercent);
463  break;
464  case Value::Q_EMS:
465  case CSSPrimitiveValue::CSS_EMS:
466  case CSSPrimitiveValue::CSS_EXS:
467  case CSSPrimitiveValue::CSS_CHS:
468  case CSSPrimitiveValue::CSS_REMS:
469  case CSSPrimitiveValue::CSS_PX:
470  case CSSPrimitiveValue::CSS_CM:
471  case CSSPrimitiveValue::CSS_MM:
472  case CSSPrimitiveValue::CSS_IN:
473  case CSSPrimitiveValue::CSS_PT:
474  case CSSPrimitiveValue::CSS_PC:
475  b = (unitflags & FLength);
476  break;
477  case CSSPrimitiveValue::CSS_MS:
478  case CSSPrimitiveValue::CSS_S:
479  b = (unitflags & FTime);
480  break;
481  case CSSPrimitiveValue::CSS_DEG:
482  case CSSPrimitiveValue::CSS_RAD:
483  case CSSPrimitiveValue::CSS_GRAD:
484  case CSSPrimitiveValue::CSS_HZ:
485  case CSSPrimitiveValue::CSS_KHZ:
486  case CSSPrimitiveValue::CSS_DPI:
487  case CSSPrimitiveValue::CSS_DPCM:
488  case CSSPrimitiveValue::CSS_DIMENSION:
489  default:
490  break;
491  }
492  return b;
493 }
494 
495 bool CSSParser::parseValue(int propId, bool important)
496 {
497  if (!valueList) {
498  return false;
499  }
500 
501  Value *value = valueList->current();
502 
503  if (!value) {
504  return false;
505  }
506 
507  int id = value->id;
508 
509  const int num = inShorthand() ? 1 : valueList->size();
510 
511  if (id == CSS_VAL_INHERIT) {
512  if (num != 1) {
513  return false;
514  }
515  addProperty(propId, new CSSInheritedValueImpl(), important);
516  return true;
517  } else if (id == CSS_VAL_INITIAL) {
518  if (num != 1) {
519  return false;
520  }
521  addProperty(propId, new CSSInitialValueImpl(false/*implicit initial*/), important);
522  return true;
523  }
524 
525  bool valid_primitive = false;
526  CSSValueImpl *parsedValue = nullptr;
527 
528  switch (propId) {
529  /* The comment to the left defines all valid value of this properties as defined
530  * in CSS 2, Appendix F. Property index
531  */
532 
533  /* All the CSS properties are not supported by the renderer at the moment.
534  * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
535  * (see parseAuralValues). As we don't support them at all this seems reasonable.
536  */
537 
538  case CSS_PROP_SIZE: // <length>{1,2} | auto | portrait | landscape | inherit
539 // case CSS_PROP_PAGE: // <identifier> | auto // ### CHECK
540  // ### To be done
541  if (id) {
542  valid_primitive = true;
543  }
544  break;
545  case CSS_PROP_UNICODE_BIDI: // normal | embed | bidi-override | inherit
546  if (id == CSS_VAL_NORMAL ||
547  id == CSS_VAL_EMBED ||
548  id == CSS_VAL_BIDI_OVERRIDE) {
549  valid_primitive = true;
550  }
551  break;
552 
553  case CSS_PROP_POSITION: // static | relative | absolute | fixed | inherit
554  if (id == CSS_VAL_STATIC ||
555  id == CSS_VAL_RELATIVE ||
556  id == CSS_VAL_ABSOLUTE ||
557  id == CSS_VAL_FIXED) {
558  valid_primitive = true;
559  }
560  break;
561 
562  case CSS_PROP_PAGE_BREAK_AFTER: // auto | always | avoid | left | right | inherit
563  case CSS_PROP_PAGE_BREAK_BEFORE: // auto | always | avoid | left | right | inherit
564  if (id == CSS_VAL_AUTO ||
565  id == CSS_VAL_ALWAYS ||
566  id == CSS_VAL_AVOID ||
567  id == CSS_VAL_LEFT ||
568  id == CSS_VAL_RIGHT) {
569  valid_primitive = true;
570  }
571  break;
572 
573  case CSS_PROP_PAGE_BREAK_INSIDE: // avoid | auto | inherit
574  if (id == CSS_VAL_AUTO ||
575  id == CSS_VAL_AVOID) {
576  valid_primitive = true;
577  }
578  break;
579 
580  case CSS_PROP_EMPTY_CELLS: // show | hide | inherit
581  if (id == CSS_VAL_SHOW ||
582  id == CSS_VAL_HIDE) {
583  valid_primitive = true;
584  }
585  break;
586 
587  case CSS_PROP_QUOTES: // [<string> <string>]+ | none | inherit
588  if (id == CSS_VAL_NONE) {
589  valid_primitive = true;
590  } else {
591  QuotesValueImpl *quotes = new QuotesValueImpl;
592  bool is_valid = true;
593  QString open, close;
594  Value *val = valueList->current();
595  while (val) {
596  if (val->unit == CSSPrimitiveValue::CSS_STRING) {
597  open = qString(val->string);
598  } else {
599  is_valid = false;
600  break;
601  }
602  valueList->next();
603  val = valueList->current();
604  if (val && val->unit == CSSPrimitiveValue::CSS_STRING) {
605  close = qString(val->string);
606  } else {
607  is_valid = false;
608  break;
609  }
610  quotes->addLevel(open, close);
611  valueList->next();
612  val = valueList->current();
613  }
614  if (is_valid) {
615  parsedValue = quotes;
616  } else {
617  delete quotes;
618  }
619  }
620  break;
621 
622  case CSS_PROP_CONTENT: // normal | none | inherit |
623  // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+
624  if (id == CSS_VAL_NORMAL || id == CSS_VAL_NONE) {
625  valid_primitive = true;
626  } else {
627  return parseContent(propId, important);
628  }
629  break;
630 
631  case CSS_PROP_WHITE_SPACE: // normal | pre | nowrap | pre-wrap | pre-line | inherit
632  if (id == CSS_VAL_NORMAL ||
633  id == CSS_VAL_PRE ||
634  id == CSS_VAL_PRE_WRAP ||
635  id == CSS_VAL_PRE_LINE ||
636  id == CSS_VAL_NOWRAP) {
637  valid_primitive = true;
638  }
639  break;
640 
641  case CSS_PROP_CLIP: // <shape> | auto | inherit
642  if (id == CSS_VAL_AUTO) {
643  valid_primitive = true;
644  } else if (value->unit == Value::Function) {
645  return parseShape(propId, important);
646  }
647  break;
648 
649  /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
650  * correctly and allows optimization in khtml::applyRule(..)
651  */
652  case CSS_PROP_CAPTION_SIDE: // top | bottom | left | right | inherit
653  // Left and right were deprecated in CSS 2.1 and never supported by KHTML
654  if ( /* id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || */
655  id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
656  valid_primitive = true;
657  }
658  break;
659 
660  case CSS_PROP_BORDER_COLLAPSE: // collapse | separate | inherit
661  if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE) {
662  valid_primitive = true;
663  }
664  break;
665 
666  case CSS_PROP_VISIBILITY: // visible | hidden | collapse | inherit
667  if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE) {
668  valid_primitive = true;
669  }
670  break;
671 
672  case CSS_PROP_OVERFLOW: // visible | hidden | scroll | auto | marquee | inherit
673  case CSS_PROP_OVERFLOW_X:
674  case CSS_PROP_OVERFLOW_Y:
675  if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
676  id == CSS_VAL_MARQUEE) {
677  valid_primitive = true;
678  }
679  break;
680 
681  case CSS_PROP_LIST_STYLE_POSITION: // inside | outside | inherit
682  if (id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE) {
683  valid_primitive = true;
684  }
685  break;
686 
687  case CSS_PROP_LIST_STYLE_TYPE:
688  // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
689  // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
690  // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
691  // katakana | hiragana-iroha | katakana-iroha | none | inherit
692  if ((id >= CSS_VAL_DISC && id <= CSS_VAL__KHTML_CLOSE_QUOTE) || id == CSS_VAL_NONE) {
693  valid_primitive = true;
694  }
695  break;
696 
697  case CSS_PROP_DISPLAY:
698  // inline | block | list-item | run-in | inline-block | -khtml-ruler | table |
699  // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
700  // table-column-group | table-column | table-cell | table-caption | none | inherit
701  if ((id >= CSS_VAL_INLINE && id <= CSS_VAL_TABLE_CAPTION) || id == CSS_VAL_NONE) {
702  valid_primitive = true;
703  }
704  break;
705 
706  case CSS_PROP_DIRECTION: // ltr | rtl | inherit
707  if (id == CSS_VAL_LTR || id == CSS_VAL_RTL) {
708  valid_primitive = true;
709  }
710  break;
711 
712  case CSS_PROP_TEXT_TRANSFORM: // capitalize | uppercase | lowercase | none | inherit
713  if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE) {
714  valid_primitive = true;
715  }
716  break;
717 
718  case CSS_PROP_FLOAT: // left | right | none | khtml_left | khtml_right | inherit + center for buggy CSS
719  if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL__KHTML_LEFT ||
720  id == CSS_VAL__KHTML_RIGHT || id == CSS_VAL_NONE || id == CSS_VAL_CENTER) {
721  valid_primitive = true;
722  }
723  break;
724 
725  case CSS_PROP_CLEAR: // none | left | right | both | inherit
726  if (id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
727  id == CSS_VAL_RIGHT || id == CSS_VAL_BOTH) {
728  valid_primitive = true;
729  }
730  break;
731 
732  case CSS_PROP_TEXT_ALIGN:
733  // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
734  if ((id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER) ||
735  value->unit == CSSPrimitiveValue::CSS_STRING) {
736  valid_primitive = true;
737  }
738  break;
739 
740  case CSS_PROP_OUTLINE_STYLE: // <border-style> | inherit
741  case CSS_PROP_BORDER_TOP_STYLE: //// <border-style> | inherit
742  case CSS_PROP_BORDER_RIGHT_STYLE: // Defined as: none | hidden | dotted | dashed |
743  case CSS_PROP_BORDER_BOTTOM_STYLE: // solid | double | groove | ridge | inset | outset | -khtml-native
744  case CSS_PROP_BORDER_LEFT_STYLE: ////
745  if (id >= CSS_VAL__KHTML_NATIVE && id <= CSS_VAL_DOUBLE) {
746  valid_primitive = true;
747  }
748  break;
749 
750  case CSS_PROP_FONT_WEIGHT: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
751  id = parseFontWeight(value, false);
752  if (id) {
753  valid_primitive = true;
754  }
755  break;
756  case CSS_PROP_BORDER_TOP_RIGHT_RADIUS:
757  case CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS:
758  case CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS:
759  case CSS_PROP_BORDER_TOP_LEFT_RADIUS: {
760  //<length> <length>?
761  if (num < 1 || num > 2) {
762  return false;
763  }
764 
765  if (!validUnit(value, FLength | FPercent | FNonNeg, strict)) {
766  return false;
767  }
768 
769  CSSPrimitiveValueImpl *horiz = new CSSPrimitiveValueImpl(value->fValue,
770  (CSSPrimitiveValue::UnitTypes) value->unit);
771  CSSPrimitiveValueImpl *vert;
772 
773  if (num == 2) {
774  value = valueList->next();
775  if (!validUnit(value, FLength | FPercent | FNonNeg, strict)) {
776  delete horiz;
777  return false;
778  }
779  vert = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
780  } else {
781  vert = horiz;
782  }
783 
784  addProperty(propId, new CSSPrimitiveValueImpl(new PairImpl(horiz, vert)), important);
785  return true;
786  }
787 
788  case CSS_PROP_BORDER_RADIUS:
789  return parseBorderRadius(important);
790 
791  case CSS_PROP_BORDER_SPACING: {
792  const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
793  CSS_PROP__KHTML_BORDER_VERTICAL_SPACING
794  };
795  if (num == 1) {
796  ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
797  if (!parseValue(properties[0], important)) {
798  return false;
799  }
800  CSSValueImpl *value = parsedProperties[numParsedProperties - 1]->value();
801  addProperty(properties[1], value, important);
802  return true;
803  } else if (num == 2) {
804  ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
805  const int oldNumParsedProperties = numParsedProperties;
806  if (!parseValue(properties[0], important)) {
807  return false;
808  }
809  if (!parseValue(properties[1], important)) {
810  rollbackParsedProperties(oldNumParsedProperties);
811  return false;
812  }
813  return true;
814  }
815  return false;
816  }
817  case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
818  case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
819  valid_primitive = validUnit(value, FLength | FNonNeg, strict);
820  break;
821 
822  case CSS_PROP_SCROLLBAR_FACE_COLOR: // IE5.5
823  case CSS_PROP_SCROLLBAR_SHADOW_COLOR: // IE5.5
824  case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR: // IE5.5
825  case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR: // IE5.5
826  case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR: // IE5.5
827  case CSS_PROP_SCROLLBAR_TRACK_COLOR: // IE5.5
828  case CSS_PROP_SCROLLBAR_ARROW_COLOR: // IE5.5
829  case CSS_PROP_SCROLLBAR_BASE_COLOR: // IE5.5
830  if (strict) {
831  break;
832  }
833  /* nobreak */
834  case CSS_PROP_OUTLINE_COLOR: // <color> | invert | inherit
835  // outline has "invert" as additional keyword.
836  if (propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT) {
837  valid_primitive = true;
838  break;
839  }
840  /* nobreak */
841  case CSS_PROP_BACKGROUND_COLOR: // <color> | inherit
842  case CSS_PROP_BORDER_TOP_COLOR: // <color> | inherit
843  case CSS_PROP_BORDER_RIGHT_COLOR: // <color> | inherit
844  case CSS_PROP_BORDER_BOTTOM_COLOR: // <color> | inherit
845  case CSS_PROP_BORDER_LEFT_COLOR: // <color> | inherit
846  case CSS_PROP_COLOR: // <color> | inherit
847  if (id == CSS_VAL__KHTML_TEXT || id == CSS_VAL_MENU ||
848  (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
849  id == CSS_VAL_TRANSPARENT ||
850  id == CSS_VAL_CURRENTCOLOR ||
851  (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict)) {
852  valid_primitive = true;
853  } else {
854  parsedValue = parseColor();
855  if (parsedValue) {
856  valueList->next();
857  }
858  }
859  break;
860 
861  case CSS_PROP_CURSOR:
862  // [ auto | default | none |
863  // context-menu | help | pointer | progress | wait |
864  // cell | crosshair | text | vertical-text |
865  // alias | copy | move | no-drop | not-allowed |
866  // e-resize | ne-resize | nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize |
867  // ew-resize | ns-resize | nesw-resize | nwse-resize |
868  // col-resize | row-resize | all-scroll
869  // ] ] | inherit
870  // MSIE 5 compatibility :/
871  if (!strict && id == CSS_VAL_HAND) {
872  id = CSS_VAL_POINTER;
873  valid_primitive = true;
874  } else if ((id >= CSS_VAL_AUTO && id <= CSS_VAL_ALL_SCROLL) || id == CSS_VAL_NONE) {
875  valid_primitive = true;
876  }
877  break;
878 
879  case CSS_PROP_BACKGROUND_ATTACHMENT:
880  case CSS_PROP_BACKGROUND_CLIP:
881  case CSS_PROP_BACKGROUND_IMAGE:
882  case CSS_PROP_BACKGROUND_ORIGIN:
883  case CSS_PROP_BACKGROUND_POSITION:
884  case CSS_PROP_BACKGROUND_POSITION_X:
885  case CSS_PROP_BACKGROUND_POSITION_Y:
886  case CSS_PROP_BACKGROUND_SIZE:
887  case CSS_PROP_BACKGROUND_REPEAT: {
888  CSSValueImpl *val1 = nullptr, *val2 = nullptr;
889  int propId1, propId2;
890  if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
891  addProperty(propId1, val1, important);
892  if (val2) {
893  addProperty(propId2, val2, important);
894  }
895  return true;
896  }
897  return false;
898  }
899  case CSS_PROP_LIST_STYLE_IMAGE: // <uri> | none | inherit
900  if (id == CSS_VAL_NONE) {
901  parsedValue = new CSSImageValueImpl();
902  valueList->next();
903  } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
904  // ### allow string in non strict mode?
905  if (styleElement) {
906  const DOMString uri = domString(value->string);
907  parsedValue = new CSSImageValueImpl(uri, styleElement);
908  valueList->next();
909  }
910  }
911  break;
912 
913  case CSS_PROP_OUTLINE_WIDTH: // <border-width> | inherit
914  case CSS_PROP_BORDER_TOP_WIDTH: //// <border-width> | inherit
915  case CSS_PROP_BORDER_RIGHT_WIDTH: // Which is defined as
916  case CSS_PROP_BORDER_BOTTOM_WIDTH: // thin | medium | thick | <length>
917  case CSS_PROP_BORDER_LEFT_WIDTH: ////
918  if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK) {
919  valid_primitive = true;
920  } else {
921  valid_primitive = validUnit(value, FLength|FNonNeg, strict);
922  }
923  break;
924 
925  case CSS_PROP_LETTER_SPACING: // normal | <length> | inherit
926  case CSS_PROP_WORD_SPACING: // normal | <length> | inherit
927  if (id == CSS_VAL_NORMAL) {
928  valid_primitive = true;
929  } else {
930  valid_primitive = validUnit(value, FLength, strict);
931  }
932  break;
933 
934  case CSS_PROP_TEXT_INDENT: // <length> | <percentage> | inherit
935  valid_primitive = (!id && validUnit(value, FLength | FPercent, strict));
936  break;
937 
938  case CSS_PROP_PADDING_TOP: // <length> | <percentage> | inherit
939  case CSS_PROP_PADDING_RIGHT: // <padding-width> | inherit
940  case CSS_PROP_PADDING_BOTTOM: // Which is defined as
941  case CSS_PROP_PADDING_LEFT: // <length> | <percentage>
942  case CSS_PROP__KHTML_PADDING_START:
943  valid_primitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, strict));
944  break;
945 
946  case CSS_PROP_MAX_HEIGHT: // <length> | <percentage> | none | inherit
947  case CSS_PROP_MAX_WIDTH: // <length> | <percentage> | none | inherit
948  if (id == CSS_VAL_NONE) {
949  valid_primitive = true;
950  break;
951  }
952  /* nobreak */
953  case CSS_PROP_MIN_HEIGHT: // <length> | <percentage> | inherit
954  case CSS_PROP_MIN_WIDTH: // <length> | <percentage> | inherit
955  valid_primitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, strict));
956  break;
957 
958  case CSS_PROP_FONT_SIZE:
959  // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
960  if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER) {
961  valid_primitive = true;
962  } else {
963  valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, strict);
964  }
965  break;
966 
967  case CSS_PROP_FONT_STYLE: // normal | italic | oblique | inherit
968  if (id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) {
969  valid_primitive = true;
970  }
971  break;
972 
973  case CSS_PROP_FONT_VARIANT: // normal | small-caps | inherit
974  if (id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS) {
975  valid_primitive = true;
976  }
977  break;
978 
979  case CSS_PROP_VERTICAL_ALIGN:
980  // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
981  // <percentage> | <length> | inherit
982 
983  if (id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE) {
984  valid_primitive = true;
985  } else {
986  valid_primitive = (!id && validUnit(value, FLength | FPercent, strict));
987  }
988  break;
989 
990  case CSS_PROP_HEIGHT: // <length> | <percentage> | auto | inherit
991  case CSS_PROP_WIDTH: // <length> | <percentage> | auto | inherit
992  if (id == CSS_VAL_AUTO) {
993  valid_primitive = true;
994  } else
995  // ### handle multilength case where we allow relative units
996  {
997  valid_primitive = (!id && validUnit(value, FLength | FPercent | FNonNeg, strict));
998  }
999  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 {
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"
QString escape(const QString &plain)
The CSSNamespaceRule interface represents an.
Definition: css_rule.h:455
int size() const const
URI
const QList< QKeySequence > & close()
void setNamedColor(const QString &name)
QString toString(QUrl::FormattingOptions options) const const
bool isNull() const const
QString & sprintf(const char *cformat,...)
T value(int i) const const
void clear()
QVector< V > values(const QMultiHash< K, V > &c)
void append(const T &value)
KGuiItem properties()
Type type(const QSqlDatabase &db)
UnitTypes
An integer indicating which type of unit applies to the value.
Definition: css_value.h:384
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
QString toLower() const const
KGuiItem discard()
const QChar * unicode() const const
This library provides a full-featured HTML parser and widget.
const QList< QKeySequence > & end()
bool isValid(QStringView ifopt)
int length() const const
KIOCORE_EXPORT FileJob * open(const QUrl &url, QIODevice::OpenMode mode)
QObject * parent() const const
QRgb rgba() const const
bool isValid() const const
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
DOMString trimSpaces() const
Returns a string with Space Characters removed from the start and the end.
Definition: dom_string.cpp:345
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:47:51 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.