2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
5 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
6 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 #include "cssparser.h"
27 #include "CSSBorderImageValue.h"
28 #include "CSSCursorImageValue.h"
29 #include "CSSImageValue.h"
30 #include "CSSCharsetRule.h"
31 #include "CSSImportRule.h"
32 #include "CSSInheritedValue.h"
33 #include "CSSInitialValue.h"
34 #include "CSSMediaRule.h"
35 #include "CSSMutableStyleDeclaration.h"
36 #include "CSSPrimitiveValue.h"
37 #include "CSSProperty.h"
38 #include "CSSPropertyNames.h"
39 #include "CSSRuleList.h"
40 #include "CSSSelector.h"
41 #include "CSSStyleRule.h"
42 #include "CSSStyleSheet.h"
43 #include "CSSQuirkPrimitiveValue.h"
44 #include "CSSValueKeywords.h"
45 #include "CSSValueList.h"
47 #include "DashboardRegion.h"
49 #include "FontFamilyValue.h"
50 #include "FontValue.h"
52 #include "MediaList.h"
54 #include "ShadowValue.h"
55 #include "csshelper.h"
56 #include "MediaQueryExp.h"
61 extern int cssyydebug;
64 extern int cssyyparse(void* parser);
71 ValueList::~ValueList()
73 size_t numValues = m_values.size();
74 for (size_t i = 0; i < numValues; i++)
75 if (m_values[i].unit == Value::Function)
76 delete m_values[i].function;
80 class ShorthandScope {
82 ShorthandScope(CSSParser* parser, int propId) : m_parser(parser)
84 if (!(m_parser->m_inParseShorthand++))
85 m_parser->m_currentShorthand = propId;
89 if (!(--m_parser->m_inParseShorthand))
90 m_parser->m_currentShorthand = 0;
98 CSSParser* CSSParser::currentParser = 0;
100 CSSParser::CSSParser(bool strictParsing)
101 : m_floatingMediaQuery(0)
102 , m_floatingMediaQueryExp(0)
103 , m_floatingMediaQueryExpList(0)
106 kdDebug(6080) << "CSSParser::CSSParser this=" << this << endl;
108 strict = strictParsing;
110 parsedProperties = (CSSProperty **)fastMalloc(32 * sizeof(CSSProperty *));
111 numParsedProperties = 0;
112 maxParsedProperties = 32;
118 m_inParseShorthand = 0;
119 m_currentShorthand = 0;
120 m_implicitShorthand = false;
122 defaultNamespace = starAtom;
131 CSSParser::~CSSParser()
134 fastFree(parsedProperties);
140 if (m_floatingMediaQueryExpList) {
141 deleteAllValues(*m_floatingMediaQueryExpList);
142 delete m_floatingMediaQueryExpList;
144 delete m_floatingMediaQueryExp;
145 delete m_floatingMediaQuery;
146 deleteAllValues(m_floatingSelectors);
147 deleteAllValues(m_floatingValueLists);
148 deleteAllValues(m_floatingFunctions);
151 void ParseString::lower()
153 // Fast case for all-ASCII.
155 for (int i = 0; i < length; i++)
156 ored |= characters[i];
158 for (int i = 0; i < length; i++)
159 characters[i] = Unicode::toLower(characters[i]);
161 for (int i = 0; i < length; i++)
162 characters[i] = tolower(characters[i]);
165 void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix)
167 int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
172 data = static_cast<UChar*>(fastMalloc(length * sizeof(UChar)));
173 for (unsigned i = 0; i < strlen(prefix); i++)
176 memcpy(data + strlen(prefix), string.characters(), string.length() * sizeof(UChar));
178 unsigned start = strlen(prefix) + string.length();
179 unsigned end = start + strlen(suffix);
180 for (unsigned i = start; i < end; i++)
181 data[i] = suffix[i - start];
183 data[length - 1] = 0;
184 data[length - 2] = 0;
188 yytext = yy_c_buf_p = data;
189 yy_hold_char = *yy_c_buf_p;
192 void CSSParser::parseSheet(CSSStyleSheet* sheet, const String& string)
194 styleElement = sheet;
195 defaultNamespace = starAtom; // Reset the default namespace.
197 setupParser("", string, "");
199 CSSParser* old = currentParser;
200 currentParser = this;
207 PassRefPtr<CSSRule> CSSParser::parseRule(CSSStyleSheet *sheet, const String &string)
209 styleElement = sheet;
211 setupParser("@-webkit-rule{", string, "} ");
213 CSSParser* old = currentParser;
214 currentParser = this;
218 return rule.release();
221 bool CSSParser::parseValue(CSSMutableStyleDeclaration *declaration, int _id, const String &string, bool _important)
223 styleElement = declaration->stylesheet();
225 setupParser("@-webkit-value{", string, "} ");
228 important = _important;
230 CSSParser* old = currentParser;
231 currentParser = this;
238 if (numParsedProperties) {
240 declaration->addParsedProperties(parsedProperties, numParsedProperties);
247 RGBA32 CSSParser::parseColor(const String &string, bool strict)
250 RefPtr<CSSMutableStyleDeclaration>dummyStyleDeclaration = new CSSMutableStyleDeclaration;
252 CSSParser parser(true);
254 // First try creating a color specified by name or the "#" syntax.
255 if (!parser.parseColor(string, color, strict)) {
257 // Now try to create a color from the rgb() or rgba() syntax.
258 if (parser.parseColor(dummyStyleDeclaration.get(), string)) {
259 CSSValue* value = parser.parsedProperties[0]->value();
260 if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
261 CSSPrimitiveValue *primitiveValue = static_cast<CSSPrimitiveValue *>(value);
262 color = primitiveValue->getRGBColorValue();
270 bool CSSParser::parseColor(CSSMutableStyleDeclaration *declaration, const String &string)
272 styleElement = declaration->stylesheet();
274 setupParser("@-webkit-decls{color:", string, "} ");
276 CSSParser* old = currentParser;
277 currentParser = this;
284 if (numParsedProperties && parsedProperties[0]->m_id == CSS_PROP_COLOR)
290 bool CSSParser::parseDeclaration(CSSMutableStyleDeclaration *declaration, const String &string)
292 styleElement = declaration->stylesheet();
294 setupParser("@-webkit-decls{", string, "} ");
296 CSSParser* old = currentParser;
297 currentParser = this;
304 if (numParsedProperties) {
306 declaration->addParsedProperties(parsedProperties, numParsedProperties);
313 bool CSSParser::parseMediaQuery(MediaList* queries, const String& string)
315 if (string.isEmpty() || string.isNull()) {
320 // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
321 // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
322 setupParser ("@-webkit-mediaquery ", string, "} ");
324 CSSParser* old = currentParser;
325 currentParser = this;
332 queries->appendMediaQuery(mediaQuery);
340 void CSSParser::addProperty(int propId, PassRefPtr<CSSValue> value, bool important)
342 CSSProperty *prop = new CSSProperty(propId, value, important, m_currentShorthand, m_implicitShorthand);
343 if (numParsedProperties >= maxParsedProperties) {
344 maxParsedProperties += 32;
345 parsedProperties = (CSSProperty **)fastRealloc(parsedProperties,
346 maxParsedProperties*sizeof(CSSProperty *));
348 parsedProperties[numParsedProperties++] = prop;
351 void CSSParser::rollbackLastProperties(int num)
354 ASSERT(numParsedProperties >= num);
356 for (int i = 0; i < num; ++i)
357 delete parsedProperties[--numParsedProperties];
360 void CSSParser::clearProperties()
362 for (int i = 0; i < numParsedProperties; i++)
363 delete parsedProperties[i];
364 numParsedProperties = 0;
367 Document *CSSParser::document() const
369 StyleBase *root = styleElement;
371 while (root->parent())
372 root = root->parent();
373 if (root->isCSSStyleSheet())
374 doc = static_cast<CSSStyleSheet*>(root)->doc();
378 bool CSSParser::validUnit(Value* value, Units unitflags, bool strict)
380 if (unitflags & FNonNeg && value->fValue < 0)
384 switch(value->unit) {
385 case CSSPrimitiveValue::CSS_NUMBER:
386 b = (unitflags & FNumber);
387 if (!b && ((unitflags & FLength) && (value->fValue == 0 || !strict))) {
388 value->unit = CSSPrimitiveValue::CSS_PX;
391 if (!b && (unitflags & FInteger) && value->isInt)
394 case CSSPrimitiveValue::CSS_PERCENTAGE:
395 b = (unitflags & FPercent);
398 case CSSPrimitiveValue::CSS_EMS:
399 case CSSPrimitiveValue::CSS_EXS:
400 case CSSPrimitiveValue::CSS_PX:
401 case CSSPrimitiveValue::CSS_CM:
402 case CSSPrimitiveValue::CSS_MM:
403 case CSSPrimitiveValue::CSS_IN:
404 case CSSPrimitiveValue::CSS_PT:
405 case CSSPrimitiveValue::CSS_PC:
406 b = (unitflags & FLength);
408 case CSSPrimitiveValue::CSS_MS:
409 case CSSPrimitiveValue::CSS_S:
410 b = (unitflags & FTime);
412 case CSSPrimitiveValue::CSS_DEG:
413 case CSSPrimitiveValue::CSS_RAD:
414 case CSSPrimitiveValue::CSS_GRAD:
415 case CSSPrimitiveValue::CSS_HZ:
416 case CSSPrimitiveValue::CSS_KHZ:
417 case CSSPrimitiveValue::CSS_DIMENSION:
424 static int unitFromString(Value* value)
426 if (value->unit != CSSPrimitiveValue::CSS_IDENT || value->id)
429 String str = domString(value->string);
431 return CSSPrimitiveValue::CSS_EMS;
433 return CSSPrimitiveValue::CSS_EXS;
435 return CSSPrimitiveValue::CSS_PX;
437 return CSSPrimitiveValue::CSS_CM;
439 return CSSPrimitiveValue::CSS_MM;
441 return CSSPrimitiveValue::CSS_IN;
443 return CSSPrimitiveValue::CSS_PT;
445 return CSSPrimitiveValue::CSS_PC;
447 return CSSPrimitiveValue::CSS_DEG;
449 return CSSPrimitiveValue::CSS_RAD;
451 return CSSPrimitiveValue::CSS_GRAD;
453 return CSSPrimitiveValue::CSS_MS;
455 return CSSPrimitiveValue::CSS_S;
457 return CSSPrimitiveValue::CSS_HZ;
459 return CSSPrimitiveValue::CSS_KHZ;
464 void CSSParser::checkForOrphanedUnits()
466 if (strict || inShorthand())
469 // The purpose of this code is to implement the WinIE quirk that allows unit types to be separated from their numeric values
470 // by whitespace, so e.g., width: 20 px instead of width:20px. This is invalid CSS, so we don't do this in strict mode.
471 Value* numericVal = 0;
472 unsigned size = valueList->size();
473 for (unsigned i = 0; i < size; i++) {
474 Value* value = valueList->valueAt(i);
476 // Change the unit type of the numeric val to match.
477 int unit = unitFromString(value);
479 numericVal->unit = unit;
482 // Now delete the bogus unit value.
483 valueList->deleteValueAt(i);
484 i--; // We're safe even though |i| is unsigned, since we only hit this code if we had a previous numeric value (so |i| is always > 0 here).
490 numericVal = (value->unit == CSSPrimitiveValue::CSS_NUMBER) ? value : 0;
494 bool CSSParser::parseValue(int propId, bool important)
499 Value *value = valueList->current();
506 int num = inShorthand() ? 1 : valueList->size();
508 if (id == CSS_VAL_INHERIT) {
511 addProperty(propId, new CSSInheritedValue(), important);
514 else if (id == CSS_VAL_INITIAL) {
517 addProperty(propId, new CSSInitialValue(false), important);
521 bool valid_primitive = false;
522 CSSValue *parsedValue = 0;
524 // In quirks mode, we will look for units that have been incorrectly separated from the number they belong to
525 // by a space. We go ahead and associate the unit with the number even though it is invalid CSS.
526 checkForOrphanedUnits();
528 switch (static_cast<CSSPropertyID>(propId)) {
529 /* The comment to the left defines all valid value of this properties as defined
530 * in CSS 2, Appendix F. Property index
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.
538 case CSS_PROP_SIZE: // <length>{1,2} | auto | portrait | landscape | inherit
539 case CSS_PROP_QUOTES: // [<string> <string>]+ | none | inherit
541 valid_primitive = true;
543 case CSS_PROP_UNICODE_BIDI: // normal | embed | bidi-override | inherit
544 if (id == CSS_VAL_NORMAL ||
545 id == CSS_VAL_EMBED ||
546 id == CSS_VAL_BIDI_OVERRIDE)
547 valid_primitive = true;
550 case CSS_PROP_POSITION: // static | relative | absolute | fixed | inherit
551 if (id == CSS_VAL_STATIC ||
552 id == CSS_VAL_RELATIVE ||
553 id == CSS_VAL_ABSOLUTE ||
555 valid_primitive = true;
558 case CSS_PROP_PAGE_BREAK_AFTER: // auto | always | avoid | left | right | inherit
559 case CSS_PROP_PAGE_BREAK_BEFORE:
560 case CSS_PROP__WEBKIT_COLUMN_BREAK_AFTER:
561 case CSS_PROP__WEBKIT_COLUMN_BREAK_BEFORE:
562 if (id == CSS_VAL_AUTO ||
563 id == CSS_VAL_ALWAYS ||
564 id == CSS_VAL_AVOID ||
565 id == CSS_VAL_LEFT ||
567 valid_primitive = true;
570 case CSS_PROP_PAGE_BREAK_INSIDE: // avoid | auto | inherit
571 case CSS_PROP__WEBKIT_COLUMN_BREAK_INSIDE:
572 if (id == CSS_VAL_AUTO || id == CSS_VAL_AVOID)
573 valid_primitive = true;
576 case CSS_PROP_EMPTY_CELLS: // show | hide | inherit
577 if (id == CSS_VAL_SHOW ||
579 valid_primitive = true;
582 case CSS_PROP_CONTENT: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
583 // close-quote | no-open-quote | no-close-quote ]+ | inherit
584 return parseContent(propId, important);
587 case CSS_PROP_WHITE_SPACE: // normal | pre | nowrap | inherit
588 if (id == CSS_VAL_NORMAL ||
590 id == CSS_VAL_PRE_WRAP ||
591 id == CSS_VAL_PRE_LINE ||
592 id == CSS_VAL_NOWRAP)
593 valid_primitive = true;
596 case CSS_PROP_CLIP: // <shape> | auto | inherit
597 if (id == CSS_VAL_AUTO)
598 valid_primitive = true;
599 else if (value->unit == Value::Function)
600 return parseShape(propId, important);
603 /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
604 * correctly and allows optimization in WebCore::applyRule(..)
606 case CSS_PROP_CAPTION_SIDE: // top | bottom | left | right | inherit
607 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
608 id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
609 valid_primitive = true;
612 case CSS_PROP_BORDER_COLLAPSE: // collapse | separate | inherit
613 if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE)
614 valid_primitive = true;
617 case CSS_PROP_VISIBILITY: // visible | hidden | collapse | inherit
618 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
619 valid_primitive = true;
622 case CSS_PROP_OVERFLOW: {
623 ShorthandScope scope(this, propId);
624 if (num != 1 || !parseValue(CSS_PROP_OVERFLOW_X, important))
626 CSSValue* value = parsedProperties[numParsedProperties - 1]->value();
627 addProperty(CSS_PROP_OVERFLOW_Y, value, important);
630 case CSS_PROP_OVERFLOW_X:
631 case CSS_PROP_OVERFLOW_Y: // visible | hidden | scroll | auto | marquee | overlay | inherit
632 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
633 id == CSS_VAL_OVERLAY || id == CSS_VAL__WEBKIT_MARQUEE)
634 valid_primitive = true;
637 case CSS_PROP_LIST_STYLE_POSITION: // inside | outside | inherit
638 if (id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE)
639 valid_primitive = true;
642 case CSS_PROP_LIST_STYLE_TYPE:
643 // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
644 // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
645 // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
646 // katakana | hiragana-iroha | katakana-iroha | none | inherit
647 if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
648 valid_primitive = true;
651 case CSS_PROP_DISPLAY:
652 // inline | block | list-item | run-in | inline-block | table |
653 // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
654 // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
655 if ((id >= CSS_VAL_INLINE && id <= CSS_VAL__WEBKIT_INLINE_BOX) || id == CSS_VAL_NONE)
656 valid_primitive = true;
659 case CSS_PROP_DIRECTION: // ltr | rtl | inherit
660 if (id == CSS_VAL_LTR || id == CSS_VAL_RTL)
661 valid_primitive = true;
664 case CSS_PROP_TEXT_TRANSFORM: // capitalize | uppercase | lowercase | none | inherit
665 if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
666 valid_primitive = true;
669 case CSS_PROP_FLOAT: // left | right | none | inherit + center for buggy CSS
670 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
671 id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
672 valid_primitive = true;
675 case CSS_PROP_CLEAR: // none | left | right | both | inherit
676 if (id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
677 id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
678 valid_primitive = true;
681 case CSS_PROP_TEXT_ALIGN:
682 // left | right | center | justify | webkit_left | webkit_right | webkit_center | <string> | inherit
683 if ((id >= CSS_VAL__WEBKIT_AUTO && id <= CSS_VAL__WEBKIT_CENTER) ||
684 value->unit == CSSPrimitiveValue::CSS_STRING)
685 valid_primitive = true;
688 case CSS_PROP_OUTLINE_STYLE: // <border-style> | auto | inherit
689 if (id == CSS_VAL_AUTO) {
690 valid_primitive = true;
693 case CSS_PROP_BORDER_TOP_STYLE: //// <border-style> | inherit
694 case CSS_PROP_BORDER_RIGHT_STYLE: // Defined as: none | hidden | dotted | dashed |
695 case CSS_PROP_BORDER_BOTTOM_STYLE: // solid | double | groove | ridge | inset | outset
696 case CSS_PROP_BORDER_LEFT_STYLE:
697 case CSS_PROP__WEBKIT_COLUMN_RULE_STYLE:
698 if (id >= CSS_VAL_NONE && id <= CSS_VAL_DOUBLE)
699 valid_primitive = true;
702 case CSS_PROP_FONT_WEIGHT: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
703 // 500 | 600 | 700 | 800 | 900 | inherit
704 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
705 // Allready correct id
706 valid_primitive = true;
707 } else if (validUnit(value, FInteger|FNonNeg, false)) {
708 int weight = (int)value->fValue;
712 if (weight >= 1 && weight <= 9) {
713 id = CSS_VAL_100 + weight - 1;
714 valid_primitive = true;
719 case CSS_PROP_BORDER_SPACING: {
720 const int properties[2] = { CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING,
721 CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING };
723 ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
724 if (!parseValue(properties[0], important))
726 CSSValue* value = parsedProperties[numParsedProperties-1]->value();
727 addProperty(properties[1], value, important);
731 ShorthandScope scope(this, CSS_PROP_BORDER_SPACING);
732 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
738 case CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING:
739 case CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING:
740 valid_primitive = validUnit(value, FLength|FNonNeg, strict);
742 case CSS_PROP_SCROLLBAR_FACE_COLOR: // IE5.5
743 case CSS_PROP_SCROLLBAR_SHADOW_COLOR: // IE5.5
744 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR: // IE5.5
745 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR: // IE5.5
746 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR: // IE5.5
747 case CSS_PROP_SCROLLBAR_TRACK_COLOR: // IE5.5
748 case CSS_PROP_SCROLLBAR_ARROW_COLOR: // IE5.5
752 case CSS_PROP_OUTLINE_COLOR: // <color> | invert | inherit
753 // Outline color has "invert" as additional keyword.
754 // Also, we want to allow the special focus color even in strict parsing mode.
755 if (propId == CSS_PROP_OUTLINE_COLOR && (id == CSS_VAL_INVERT || id == CSS_VAL__WEBKIT_FOCUS_RING_COLOR)) {
756 valid_primitive = true;
760 case CSS_PROP_BACKGROUND_COLOR: // <color> | inherit
761 case CSS_PROP_BORDER_TOP_COLOR: // <color> | inherit
762 case CSS_PROP_BORDER_RIGHT_COLOR: // <color> | inherit
763 case CSS_PROP_BORDER_BOTTOM_COLOR: // <color> | inherit
764 case CSS_PROP_BORDER_LEFT_COLOR: // <color> | inherit
765 case CSS_PROP_COLOR: // <color> | inherit
766 case CSS_PROP_TEXT_LINE_THROUGH_COLOR: // CSS3 text decoration colors
767 case CSS_PROP_TEXT_UNDERLINE_COLOR:
768 case CSS_PROP_TEXT_OVERLINE_COLOR:
769 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
770 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR:
771 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
772 if (id == CSS_VAL__WEBKIT_TEXT)
773 valid_primitive = true; // Always allow this, even when strict parsing is on,
774 // since we use this in our UA sheets.
775 else if (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT || id == CSS_VAL_MENU ||
776 (id >= CSS_VAL__WEBKIT_FOCUS_RING_COLOR && id < CSS_VAL__WEBKIT_TEXT && !strict)) {
777 valid_primitive = true;
779 parsedValue = parseColor();
785 case CSS_PROP_CURSOR: {
786 // [<uri>,]* [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
787 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
788 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help ] ] | inherit
789 CSSValueList* list = 0;
790 while (value && value->unit == CSSPrimitiveValue::CSS_URI) {
792 list = new CSSValueList;
793 String uri = parseURL(domString(value->string));
795 value = valueList->next();
796 while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
797 coords.append(int(value->fValue));
798 value = valueList->next();
801 int nrcoords = coords.size();
802 if (nrcoords > 0 && nrcoords != 2) {
803 if (strict) { // only support hotspot pairs in strict mode
807 } else if(strict && nrcoords == 2)
808 hotspot = IntPoint(coords[0], coords[1]);
809 if (strict || coords.size() == 0) {
811 if (uri.startsWith("#"))
812 list->append(new CSSPrimitiveValue(uri, CSSPrimitiveValue::CSS_URI));
815 if (!uri.isEmpty()) {
816 list->append(new CSSCursorImageValue(
817 String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
818 hotspot, styleElement));
821 if ((strict && !value) || (value && !(value->unit == Value::Operator && value->iValue == ','))) {
825 value = valueList->next(); // comma
828 if (!value) { // no value after url list (MSIE 5 compatibility)
829 if (list->length() != 1) {
833 } else if (!strict && value->id == CSS_VAL_HAND) // MSIE 5 compatibility :/
834 list->append(new CSSPrimitiveValue(CSS_VAL_POINTER));
835 else if (value && ((value->id >= CSS_VAL_AUTO && value->id <= CSS_VAL_ALL_SCROLL) || value->id == CSS_VAL_COPY || value->id == CSS_VAL_NONE))
836 list->append(new CSSPrimitiveValue(value->id));
842 if (!strict && value->id == CSS_VAL_HAND) { // MSIE 5 compatibility :/
843 id = CSS_VAL_POINTER;
844 valid_primitive = true;
845 } else if ((value->id >= CSS_VAL_AUTO && value->id <= CSS_VAL_ALL_SCROLL) || value->id == CSS_VAL_COPY || value->id == CSS_VAL_NONE)
846 valid_primitive = true;
850 case CSS_PROP_BACKGROUND_ATTACHMENT:
851 case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
852 case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
853 case CSS_PROP_BACKGROUND_IMAGE:
854 case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
855 case CSS_PROP_BACKGROUND_POSITION:
856 case CSS_PROP_BACKGROUND_POSITION_X:
857 case CSS_PROP_BACKGROUND_POSITION_Y:
858 case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
859 case CSS_PROP_BACKGROUND_REPEAT: {
860 CSSValue *val1 = 0, *val2 = 0;
861 int propId1, propId2;
862 if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
863 addProperty(propId1, val1, important);
865 addProperty(propId2, val2, important);
870 case CSS_PROP_LIST_STYLE_IMAGE: // <uri> | none | inherit
871 if (id == CSS_VAL_NONE) {
872 parsedValue = new CSSImageValue();
875 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
876 // ### allow string in non strict mode?
877 String uri = parseURL(domString(value->string));
878 if (!uri.isEmpty()) {
879 parsedValue = new CSSImageValue(
880 String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
887 case CSS_PROP__WEBKIT_TEXT_STROKE_WIDTH:
888 case CSS_PROP_OUTLINE_WIDTH: // <border-width> | inherit
889 case CSS_PROP_BORDER_TOP_WIDTH: //// <border-width> | inherit
890 case CSS_PROP_BORDER_RIGHT_WIDTH: // Which is defined as
891 case CSS_PROP_BORDER_BOTTOM_WIDTH: // thin | medium | thick | <length>
892 case CSS_PROP_BORDER_LEFT_WIDTH:
893 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
894 if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
895 valid_primitive = true;
897 valid_primitive = validUnit(value, FLength, strict);
900 case CSS_PROP_LETTER_SPACING: // normal | <length> | inherit
901 case CSS_PROP_WORD_SPACING: // normal | <length> | inherit
902 if (id == CSS_VAL_NORMAL)
903 valid_primitive = true;
905 valid_primitive = validUnit(value, FLength, strict);
908 case CSS_PROP_WORD_BREAK: // normal | break-all | break-word (this is a custom extension)
909 if (id == CSS_VAL_NORMAL || id == CSS_VAL_BREAK_ALL || id == CSS_VAL_BREAK_WORD)
910 valid_primitive = true;
913 case CSS_PROP_WORD_WRAP: // normal | break-word
914 if (id == CSS_VAL_NORMAL || id == CSS_VAL_BREAK_WORD)
915 valid_primitive = true;
918 case CSS_PROP_TEXT_INDENT: // <length> | <percentage> | inherit
919 case CSS_PROP_PADDING_TOP: //// <padding-width> | inherit
920 case CSS_PROP_PADDING_RIGHT: // Which is defined as
921 case CSS_PROP_PADDING_BOTTOM: // <length> | <percentage>
922 case CSS_PROP_PADDING_LEFT: ////
923 case CSS_PROP__WEBKIT_PADDING_START:
924 valid_primitive = (!id && validUnit(value, FLength|FPercent, strict));
927 case CSS_PROP_MAX_HEIGHT: // <length> | <percentage> | none | inherit
928 case CSS_PROP_MAX_WIDTH: // <length> | <percentage> | none | inherit
929 if (id == CSS_VAL_NONE || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC) {
930 valid_primitive = true;
934 case CSS_PROP_MIN_HEIGHT: // <length> | <percentage> | inherit
935 case CSS_PROP_MIN_WIDTH: // <length> | <percentage> | inherit
936 if (id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
937 valid_primitive = true;
939 valid_primitive = (!id && validUnit(value, FLength|FPercent|FNonNeg, strict));
942 case CSS_PROP_FONT_SIZE:
943 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
944 if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
945 valid_primitive = true;
947 valid_primitive = (validUnit(value, FLength|FPercent, strict));
950 case CSS_PROP_FONT_STYLE: // normal | italic | oblique | inherit
951 if (id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
952 valid_primitive = true;
955 case CSS_PROP_FONT_VARIANT: // normal | small-caps | inherit
956 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
957 valid_primitive = true;
960 case CSS_PROP_VERTICAL_ALIGN:
961 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
962 // <percentage> | <length> | inherit
964 if (id >= CSS_VAL_BASELINE && id <= CSS_VAL__WEBKIT_BASELINE_MIDDLE)
965 valid_primitive = true;
967 valid_primitive = (!id && validUnit(value, FLength|FPercent, strict));
970 case CSS_PROP_HEIGHT: // <length> | <percentage> | auto | inherit
971 case CSS_PROP_WIDTH: // <length> | <percentage> | auto | inherit
972 if (id == CSS_VAL_AUTO || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
973 valid_primitive = true;
975 // ### handle multilength case where we allow relative units
976 valid_primitive = (!id && validUnit(value, FLength|FPercent|FNonNeg, strict));
979 case CSS_PROP_BOTTOM: // <length> | <percentage> | auto | inherit
980 case CSS_PROP_LEFT: // <length> | <percentage> | auto | inherit
981 case CSS_PROP_RIGHT: // <length> | <percentage> | auto | inherit
982 case CSS_PROP_TOP: // <length> | <percentage> | auto | inherit
983 case CSS_PROP_MARGIN_TOP: //// <margin-width> | inherit
984 case CSS_PROP_MARGIN_RIGHT: // Which is defined as
985 case CSS_PROP_MARGIN_BOTTOM: // <length> | <percentage> | auto | inherit
986 case CSS_PROP_MARGIN_LEFT: ////
987 case CSS_PROP__WEBKIT_MARGIN_START:
988 if (id == CSS_VAL_AUTO)
989 valid_primitive = true;
991 valid_primitive = (!id && validUnit(value, FLength|FPercent, strict));
994 case CSS_PROP_Z_INDEX: // auto | <integer> | inherit
995 if (id == CSS_VAL_AUTO) {
996 valid_primitive = true;
1000 case CSS_PROP_ORPHANS: // <integer> | inherit
1001 case CSS_PROP_WIDOWS: // <integer> | inherit
1002 // ### not supported later on
1003 valid_primitive = (!id && validUnit(value, FInteger, false));
1006 case CSS_PROP_LINE_HEIGHT: // normal | <number> | <length> | <percentage> | inherit
1007 if (id == CSS_VAL_NORMAL)
1008 valid_primitive = true;
1010 valid_primitive = (!id && validUnit(value, FNumber|FLength|FPercent, strict));
1012 case CSS_PROP_COUNTER_INCREMENT: // [ <identifier> <integer>? ]+ | none | inherit
1013 if (id != CSS_VAL_NONE)
1014 return parseCounter(propId, 1, important);
1015 valid_primitive = true;
1017 case CSS_PROP_COUNTER_RESET: // [ <identifier> <integer>? ]+ | none | inherit
1018 if (id != CSS_VAL_NONE)
1019 return parseCounter(propId, 0, important);
1020 valid_primitive = true;
1022 case CSS_PROP_FONT_FAMILY:
1023 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
1025 parsedValue = parseFontFamily();
1029 case CSS_PROP_TEXT_DECORATION:
1030 case CSS_PROP__WEBKIT_TEXT_DECORATIONS_IN_EFFECT:
1031 // none | [ underline || overline || line-through || blink ] | inherit
1032 if (id == CSS_VAL_NONE) {
1033 valid_primitive = true;
1035 CSSValueList *list = new CSSValueList;
1036 bool is_valid = true;
1037 while(is_valid && value) {
1038 switch (value->id) {
1041 case CSS_VAL_UNDERLINE:
1042 case CSS_VAL_OVERLINE:
1043 case CSS_VAL_LINE_THROUGH:
1044 list->append(new CSSPrimitiveValue(value->id));
1049 value = valueList->next();
1051 if(list->length() && is_valid) {
1059 case CSS_PROP_TABLE_LAYOUT: // auto | fixed | inherit
1060 if (id == CSS_VAL_AUTO || id == CSS_VAL_FIXED)
1061 valid_primitive = true;
1064 /* CSS3 properties */
1065 case CSS_PROP__WEBKIT_APPEARANCE:
1066 if ((id >= CSS_VAL_CHECKBOX && id <= CSS_VAL_TEXTAREA) || id == CSS_VAL_NONE)
1067 valid_primitive = true;
1070 case CSS_PROP__WEBKIT_BINDING:
1072 if (id == CSS_VAL_NONE)
1073 valid_primitive = true;
1075 CSSValueList* values = new CSSValueList();
1077 CSSValue* parsedValue = 0;
1078 while ((val = valueList->current())) {
1079 if (val->unit == CSSPrimitiveValue::CSS_URI) {
1080 String value = parseURL(domString(val->string));
1081 parsedValue = new CSSPrimitiveValue(
1082 String(KURL(styleElement->baseURL().deprecatedString(), value.deprecatedString()).url()),
1083 CSSPrimitiveValue::CSS_URI);
1087 values->append(parsedValue);
1092 if (values->length()) {
1093 addProperty(propId, values, important);
1102 case CSS_PROP__WEBKIT_BORDER_IMAGE:
1103 if (id == CSS_VAL_NONE)
1104 valid_primitive = true;
1106 return parseBorderImage(propId, important);
1108 case CSS_PROP__WEBKIT_BORDER_TOP_RIGHT_RADIUS:
1109 case CSS_PROP__WEBKIT_BORDER_TOP_LEFT_RADIUS:
1110 case CSS_PROP__WEBKIT_BORDER_BOTTOM_LEFT_RADIUS:
1111 case CSS_PROP__WEBKIT_BORDER_BOTTOM_RIGHT_RADIUS:
1112 case CSS_PROP__WEBKIT_BORDER_RADIUS: {
1113 if (num != 1 && num != 2)
1115 valid_primitive = validUnit(value, FLength, strict);
1116 if (!valid_primitive)
1118 CSSPrimitiveValue* parsedValue1 = new CSSPrimitiveValue(value->fValue,
1119 (CSSPrimitiveValue::UnitTypes)value->unit);
1120 CSSPrimitiveValue* parsedValue2 = parsedValue1;
1122 value = valueList->next();
1123 valid_primitive = validUnit(value, FLength, strict);
1124 if (!valid_primitive) {
1125 delete parsedValue1;
1128 parsedValue2 = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1131 Pair* pair = new Pair(parsedValue1, parsedValue2);
1132 CSSPrimitiveValue* val = new CSSPrimitiveValue(pair);
1133 if (propId == CSS_PROP__WEBKIT_BORDER_RADIUS) {
1134 const int properties[4] = { CSS_PROP__WEBKIT_BORDER_TOP_RIGHT_RADIUS,
1135 CSS_PROP__WEBKIT_BORDER_TOP_LEFT_RADIUS,
1136 CSS_PROP__WEBKIT_BORDER_BOTTOM_LEFT_RADIUS,
1137 CSS_PROP__WEBKIT_BORDER_BOTTOM_RIGHT_RADIUS };
1138 for (int i = 0; i < 4; i++)
1139 addProperty(properties[i], val, important);
1141 addProperty(propId, val, important);
1144 case CSS_PROP_OUTLINE_OFFSET:
1145 valid_primitive = validUnit(value, FLength, strict);
1147 case CSS_PROP_TEXT_SHADOW: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
1148 case CSS_PROP__WEBKIT_BOX_SHADOW:
1149 if (id == CSS_VAL_NONE)
1150 valid_primitive = true;
1152 return parseShadow(propId, important);
1154 case CSS_PROP_OPACITY:
1155 valid_primitive = validUnit(value, FNumber, strict);
1157 case CSS_PROP__WEBKIT_BOX_ALIGN:
1158 if (id == CSS_VAL_STRETCH || id == CSS_VAL_START || id == CSS_VAL_END ||
1159 id == CSS_VAL_CENTER || id == CSS_VAL_BASELINE)
1160 valid_primitive = true;
1162 case CSS_PROP__WEBKIT_BOX_DIRECTION:
1163 if (id == CSS_VAL_NORMAL || id == CSS_VAL_REVERSE)
1164 valid_primitive = true;
1166 case CSS_PROP__WEBKIT_BOX_LINES:
1167 if (id == CSS_VAL_SINGLE || id == CSS_VAL_MULTIPLE)
1168 valid_primitive = true;
1170 case CSS_PROP__WEBKIT_BOX_ORIENT:
1171 if (id == CSS_VAL_HORIZONTAL || id == CSS_VAL_VERTICAL ||
1172 id == CSS_VAL_INLINE_AXIS || id == CSS_VAL_BLOCK_AXIS)
1173 valid_primitive = true;
1175 case CSS_PROP__WEBKIT_BOX_PACK:
1176 if (id == CSS_VAL_START || id == CSS_VAL_END ||
1177 id == CSS_VAL_CENTER || id == CSS_VAL_JUSTIFY)
1178 valid_primitive = true;
1180 case CSS_PROP__WEBKIT_BOX_FLEX:
1181 valid_primitive = validUnit(value, FNumber, strict);
1183 case CSS_PROP__WEBKIT_BOX_FLEX_GROUP:
1184 case CSS_PROP__WEBKIT_BOX_ORDINAL_GROUP:
1185 valid_primitive = validUnit(value, FInteger|FNonNeg, true);
1187 case CSS_PROP__WEBKIT_BOX_SIZING:
1188 valid_primitive = id == CSS_VAL_BORDER_BOX || id == CSS_VAL_CONTENT_BOX;
1190 case CSS_PROP__WEBKIT_MARQUEE: {
1191 const int properties[5] = { CSS_PROP__WEBKIT_MARQUEE_DIRECTION, CSS_PROP__WEBKIT_MARQUEE_INCREMENT,
1192 CSS_PROP__WEBKIT_MARQUEE_REPETITION,
1193 CSS_PROP__WEBKIT_MARQUEE_STYLE, CSS_PROP__WEBKIT_MARQUEE_SPEED };
1194 return parseShorthand(propId, properties, 5, important);
1196 case CSS_PROP__WEBKIT_MARQUEE_DIRECTION:
1197 if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
1198 id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
1199 id == CSS_VAL_UP || id == CSS_VAL_AUTO)
1200 valid_primitive = true;
1202 case CSS_PROP__WEBKIT_MARQUEE_INCREMENT:
1203 if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
1204 valid_primitive = true;
1206 valid_primitive = validUnit(value, FLength|FPercent, strict);
1208 case CSS_PROP__WEBKIT_MARQUEE_STYLE:
1209 if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE)
1210 valid_primitive = true;
1212 case CSS_PROP__WEBKIT_MARQUEE_REPETITION:
1213 if (id == CSS_VAL_INFINITE)
1214 valid_primitive = true;
1216 valid_primitive = validUnit(value, FInteger|FNonNeg, strict);
1218 case CSS_PROP__WEBKIT_MARQUEE_SPEED:
1219 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
1220 valid_primitive = true;
1222 valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict);
1224 case CSS_PROP__WEBKIT_USER_DRAG: // auto | none | element
1225 if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_ELEMENT)
1226 valid_primitive = true;
1228 case CSS_PROP__WEBKIT_USER_MODIFY: // read-only | read-write
1229 if (id == CSS_VAL_READ_ONLY || id == CSS_VAL_READ_WRITE || id == CSS_VAL_READ_WRITE_PLAINTEXT_ONLY)
1230 valid_primitive = true;
1232 case CSS_PROP__WEBKIT_USER_SELECT: // auto | none | text
1233 if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_TEXT || id == CSS_VAL_IGNORE)
1234 valid_primitive = true;
1236 case CSS_PROP_TEXT_OVERFLOW: // clip | ellipsis
1237 if (id == CSS_VAL_CLIP || id == CSS_VAL_ELLIPSIS)
1238 valid_primitive = true;
1240 case CSS_PROP__WEBKIT_MARGIN_COLLAPSE: {
1241 const int properties[2] = { CSS_PROP__WEBKIT_MARGIN_TOP_COLLAPSE,
1242 CSS_PROP__WEBKIT_MARGIN_BOTTOM_COLLAPSE };
1244 ShorthandScope scope(this, CSS_PROP__WEBKIT_MARGIN_COLLAPSE);
1245 if (!parseValue(properties[0], important))
1247 CSSValue* value = parsedProperties[numParsedProperties-1]->value();
1248 addProperty(properties[1], value, important);
1251 else if (num == 2) {
1252 ShorthandScope scope(this, CSS_PROP__WEBKIT_MARGIN_COLLAPSE);
1253 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1259 case CSS_PROP__WEBKIT_MARGIN_TOP_COLLAPSE:
1260 case CSS_PROP__WEBKIT_MARGIN_BOTTOM_COLLAPSE:
1261 if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE || id == CSS_VAL_DISCARD)
1262 valid_primitive = true;
1264 case CSS_PROP_TEXT_LINE_THROUGH_MODE:
1265 case CSS_PROP_TEXT_OVERLINE_MODE:
1266 case CSS_PROP_TEXT_UNDERLINE_MODE:
1267 if (id == CSS_VAL_CONTINUOUS || id == CSS_VAL_SKIP_WHITE_SPACE)
1268 valid_primitive = true;
1270 case CSS_PROP_TEXT_LINE_THROUGH_STYLE:
1271 case CSS_PROP_TEXT_OVERLINE_STYLE:
1272 case CSS_PROP_TEXT_UNDERLINE_STYLE:
1273 if (id == CSS_VAL_NONE || id == CSS_VAL_SOLID || id == CSS_VAL_DOUBLE ||
1274 id == CSS_VAL_DASHED || id == CSS_VAL_DOT_DASH || id == CSS_VAL_DOT_DOT_DASH ||
1276 valid_primitive = true;
1278 case CSS_PROP_TEXT_LINE_THROUGH_WIDTH:
1279 case CSS_PROP_TEXT_OVERLINE_WIDTH:
1280 case CSS_PROP_TEXT_UNDERLINE_WIDTH:
1281 if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL || id == CSS_VAL_THIN ||
1282 id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
1283 valid_primitive = true;
1285 valid_primitive = !id && validUnit(value, FNumber|FLength|FPercent, strict);
1287 case CSS_PROP_RESIZE: // none | both | horizontal | vertical | auto
1288 if (id == CSS_VAL_NONE || id == CSS_VAL_BOTH || id == CSS_VAL_HORIZONTAL || id == CSS_VAL_VERTICAL || id == CSS_VAL_AUTO)
1289 valid_primitive = true;
1291 case CSS_PROP__WEBKIT_COLUMN_COUNT:
1292 if (id == CSS_VAL_AUTO)
1293 valid_primitive = true;
1295 valid_primitive = !id && validUnit(value, FInteger | FNonNeg, false);
1297 case CSS_PROP__WEBKIT_COLUMN_GAP: // normal | <length>
1298 if (id == CSS_VAL_NORMAL)
1299 valid_primitive = true;
1301 valid_primitive = validUnit(value, FLength, strict);
1303 case CSS_PROP__WEBKIT_COLUMN_WIDTH: // auto | <length>
1304 if (id == CSS_VAL_AUTO)
1305 valid_primitive = true;
1306 else // Always parse this property in strict mode, since it would be ambiguous otherwise when used in the 'columns' shorthand property.
1307 valid_primitive = validUnit(value, FLength, true);
1309 // End of CSS3 properties
1311 // Apple specific properties. These will never be standardized and are purely to
1312 // support custom WebKit-based Apple applications.
1313 case CSS_PROP__WEBKIT_LINE_CLAMP:
1314 valid_primitive = (!id && validUnit(value, FPercent, false));
1316 case CSS_PROP__WEBKIT_TEXT_SIZE_ADJUST:
1317 if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE)
1318 valid_primitive = true;
1320 case CSS_PROP__WEBKIT_RTL_ORDERING:
1321 if (id == CSS_VAL_LOGICAL || id == CSS_VAL_VISUAL)
1322 valid_primitive = true;
1325 case CSS_PROP__WEBKIT_FONT_SIZE_DELTA: // <length>
1326 valid_primitive = validUnit(value, FLength, strict);
1329 case CSS_PROP__WEBKIT_NBSP_MODE: // normal | space
1330 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SPACE)
1331 valid_primitive = true;
1334 case CSS_PROP__WEBKIT_LINE_BREAK: // normal | after-white-space
1335 if (id == CSS_VAL_NORMAL || id == CSS_VAL_AFTER_WHITE_SPACE)
1336 valid_primitive = true;
1339 case CSS_PROP__WEBKIT_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR: // normal | match
1340 if (id == CSS_VAL_NORMAL || id == CSS_VAL_MATCH)
1341 valid_primitive = true;
1344 case CSS_PROP__WEBKIT_HIGHLIGHT:
1345 if (id == CSS_VAL_NONE || value->unit == CSSPrimitiveValue::CSS_STRING)
1346 valid_primitive = true;
1349 case CSS_PROP__WEBKIT_BORDER_FIT:
1350 if (id == CSS_VAL_BORDER || id == CSS_VAL_LINES)
1351 valid_primitive = true;
1354 case CSS_PROP__WEBKIT_TEXT_SECURITY:
1355 // disc | circle | square | none | inherit
1356 if (id == CSS_VAL_DISC || id == CSS_VAL_CIRCLE || id == CSS_VAL_SQUARE|| id == CSS_VAL_NONE)
1357 valid_primitive = true;
1360 case CSS_PROP__WEBKIT_DASHBOARD_REGION: // <dashboard-region> | <dashboard-region>
1361 if (value->unit == Value::Function || id == CSS_VAL_NONE)
1362 return parseDashboardRegions(propId, important);
1364 // End Apple-specific properties
1366 /* shorthand properties */
1367 case CSS_PROP_BACKGROUND:
1368 // ['background-color' || 'background-image' || 'background-size' || 'background-repeat' ||
1369 // 'background-attachment' || 'background-position'] | inherit
1370 return parseBackgroundShorthand(important);
1371 case CSS_PROP_BORDER:
1372 // [ 'border-width' || 'border-style' || <color> ] | inherit
1374 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
1375 CSS_PROP_BORDER_COLOR };
1376 return parseShorthand(propId, properties, 3, important);
1378 case CSS_PROP_BORDER_TOP:
1379 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1381 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
1382 CSS_PROP_BORDER_TOP_COLOR};
1383 return parseShorthand(propId, properties, 3, important);
1385 case CSS_PROP_BORDER_RIGHT:
1386 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1388 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
1389 CSS_PROP_BORDER_RIGHT_COLOR };
1390 return parseShorthand(propId, properties, 3, important);
1392 case CSS_PROP_BORDER_BOTTOM:
1393 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1395 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
1396 CSS_PROP_BORDER_BOTTOM_COLOR };
1397 return parseShorthand(propId, properties, 3, important);
1399 case CSS_PROP_BORDER_LEFT:
1400 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1402 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
1403 CSS_PROP_BORDER_LEFT_COLOR };
1404 return parseShorthand(propId, properties, 3, important);
1406 case CSS_PROP_OUTLINE:
1407 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1409 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
1410 CSS_PROP_OUTLINE_COLOR };
1411 return parseShorthand(propId, properties, 3, important);
1413 case CSS_PROP_BORDER_COLOR:
1414 // <color>{1,4} | inherit
1416 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
1417 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
1418 return parse4Values(propId, properties, important);
1420 case CSS_PROP_BORDER_WIDTH:
1421 // <border-width>{1,4} | inherit
1423 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
1424 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
1425 return parse4Values(propId, properties, important);
1427 case CSS_PROP_BORDER_STYLE:
1428 // <border-style>{1,4} | inherit
1430 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
1431 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
1432 return parse4Values(propId, properties, important);
1434 case CSS_PROP_MARGIN:
1435 // <margin-width>{1,4} | inherit
1437 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
1438 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
1439 return parse4Values(propId, properties, important);
1441 case CSS_PROP_PADDING:
1442 // <padding-width>{1,4} | inherit
1444 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
1445 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
1446 return parse4Values(propId, properties, important);
1449 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1450 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1451 if (id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR)
1452 valid_primitive = true;
1454 return parseFont(important);
1456 case CSS_PROP_LIST_STYLE:
1458 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
1459 CSS_PROP_LIST_STYLE_IMAGE };
1460 return parseShorthand(propId, properties, 3, important);
1462 case CSS_PROP__WEBKIT_COLUMNS: {
1463 const int properties[2] = { CSS_PROP__WEBKIT_COLUMN_WIDTH, CSS_PROP__WEBKIT_COLUMN_COUNT };
1464 return parseShorthand(propId, properties, 2, important);
1466 case CSS_PROP__WEBKIT_COLUMN_RULE: {
1467 const int properties[3] = { CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, CSS_PROP__WEBKIT_COLUMN_RULE_STYLE,
1468 CSS_PROP__WEBKIT_COLUMN_RULE_COLOR };
1469 return parseShorthand(propId, properties, 3, important);
1471 case CSS_PROP__WEBKIT_TEXT_STROKE: {
1472 const int properties[2] = { CSS_PROP__WEBKIT_TEXT_STROKE_WIDTH, CSS_PROP__WEBKIT_TEXT_STROKE_COLOR };
1473 return parseShorthand(propId, properties, 2, important);
1475 case CSS_PROP_INVALID:
1477 case CSS_PROP_FONT_STRETCH:
1479 case CSS_PROP_TEXT_LINE_THROUGH:
1480 case CSS_PROP_TEXT_OVERLINE:
1481 case CSS_PROP_TEXT_UNDERLINE:
1485 if (valid_primitive) {
1487 parsedValue = new CSSPrimitiveValue(id);
1488 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
1489 parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
1490 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
1491 parsedValue = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
1492 else if (value->unit >= Value::Q_EMS)
1493 parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS);
1497 if (!valueList->current() || inShorthand()) {
1498 addProperty(propId, parsedValue, important);
1504 if (parseSVGValue(propId, important))
1510 void CSSParser::addBackgroundValue(CSSValue*& lval, CSSValue* rval)
1513 if (lval->isValueList())
1514 static_cast<CSSValueList*>(lval)->append(rval);
1516 CSSValue* oldVal = lval;
1517 CSSValueList* list = new CSSValueList();
1519 list->append(oldVal);
1527 bool CSSParser::parseBackgroundShorthand(bool important)
1529 // Position must come before color in this array because a plain old "0" is a legal color
1530 // in quirks mode but it's usually the X coordinate of a position.
1531 // FIXME: Add CSS_PROP__KHTML_BACKGROUND_SIZE to the shorthand.
1532 const int properties[] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
1533 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION, CSS_PROP__WEBKIT_BACKGROUND_CLIP,
1534 CSS_PROP__WEBKIT_BACKGROUND_ORIGIN, CSS_PROP_BACKGROUND_COLOR };
1535 const int numProperties = sizeof(properties) / sizeof(properties[0]);
1537 ShorthandScope scope(this, CSS_PROP_BACKGROUND);
1539 bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
1540 CSSValue* values[numProperties] = { 0 }; // compiler will repeat 0 as necessary
1541 CSSValue* positionYValue = 0;
1544 while (valueList->current()) {
1545 Value* val = valueList->current();
1546 if (val->unit == Value::Operator && val->iValue == ',') {
1547 // We hit the end. Fill in all remaining values with the initial value.
1549 for (i = 0; i < numProperties; ++i) {
1550 if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i])
1551 // Color is not allowed except as the last item in a list. Reject the entire
1555 if (!parsedProperty[i] && properties[i] != CSS_PROP_BACKGROUND_COLOR) {
1556 addBackgroundValue(values[i], new CSSInitialValue(true));
1557 if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1558 addBackgroundValue(positionYValue, new CSSInitialValue(true));
1560 parsedProperty[i] = false;
1562 if (!valueList->current())
1567 for (i = 0; !found && i < numProperties; ++i) {
1568 if (!parsedProperty[i]) {
1569 CSSValue *val1 = 0, *val2 = 0;
1570 int propId1, propId2;
1571 if (parseBackgroundProperty(properties[i], propId1, propId2, val1, val2)) {
1572 parsedProperty[i] = found = true;
1573 addBackgroundValue(values[i], val1);
1574 if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1575 addBackgroundValue(positionYValue, val2);
1580 // if we didn't find at least one match, this is an
1581 // invalid shorthand and we have to ignore it
1586 // Fill in any remaining properties with the initial value.
1587 for (i = 0; i < numProperties; ++i) {
1588 if (!parsedProperty[i]) {
1589 addBackgroundValue(values[i], new CSSInitialValue(true));
1590 if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1591 addBackgroundValue(positionYValue, new CSSInitialValue(true));
1595 // Now add all of the properties we found.
1596 for (i = 0; i < numProperties; i++) {
1597 if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1598 addProperty(CSS_PROP_BACKGROUND_POSITION_X, values[i], important);
1599 addProperty(CSS_PROP_BACKGROUND_POSITION_Y, positionYValue, important);
1602 addProperty(properties[i], values[i], important);
1608 for (int k = 0; k < numProperties; k++)
1610 delete positionYValue;
1614 bool CSSParser::parseShorthand(int propId, const int *properties, int numProperties, bool important)
1616 // We try to match as many properties as possible
1617 // We set up an array of booleans to mark which property has been found,
1618 // and we try to search for properties until it makes no longer any sense.
1619 ShorthandScope scope(this, propId);
1622 bool fnd[6]; // Trust me ;)
1623 for (int i = 0; i < numProperties; i++)
1626 while (valueList->current()) {
1628 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
1629 if (!fnd[propIndex]) {
1630 if (parseValue(properties[propIndex], important))
1631 fnd[propIndex] = found = true;
1635 // if we didn't find at least one match, this is an
1636 // invalid shorthand and we have to ignore it
1641 // Fill in any remaining properties with the initial value.
1642 m_implicitShorthand = true;
1643 for (int i = 0; i < numProperties; ++i) {
1645 addProperty(properties[i], new CSSInitialValue(true), important);
1647 m_implicitShorthand = false;
1652 bool CSSParser::parse4Values(int propId, const int *properties, bool important)
1654 /* From the CSS 2 specs, 8.3
1655 * If there is only one value, it applies to all sides. If there are two values, the top and
1656 * bottom margins are set to the first value and the right and left margins are set to the second.
1657 * If there are three values, the top is set to the first value, the left and right are set to the
1658 * second, and the bottom is set to the third. If there are four values, they apply to the top,
1659 * right, bottom, and left, respectively.
1662 int num = inShorthand() ? 1 : valueList->size();
1664 ShorthandScope scope(this, propId);
1666 // the order is top, right, bottom, left
1669 if (!parseValue(properties[0], important))
1671 CSSValue *value = parsedProperties[numParsedProperties-1]->value();
1672 m_implicitShorthand = true;
1673 addProperty(properties[1], value, important);
1674 addProperty(properties[2], value, important);
1675 addProperty(properties[3], value, important);
1676 m_implicitShorthand = false;
1680 if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
1682 CSSValue *value = parsedProperties[numParsedProperties-2]->value();
1683 m_implicitShorthand = true;
1684 addProperty(properties[2], value, important);
1685 value = parsedProperties[numParsedProperties-2]->value();
1686 addProperty(properties[3], value, important);
1687 m_implicitShorthand = false;
1691 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
1693 CSSValue *value = parsedProperties[numParsedProperties-2]->value();
1694 m_implicitShorthand = true;
1695 addProperty(properties[3], value, important);
1696 m_implicitShorthand = false;
1700 if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
1701 !parseValue(properties[2], important) || !parseValue(properties[3], important))
1713 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1714 // in CSS 2.1 this got somewhat reduced:
1715 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1716 bool CSSParser::parseContent(int propId, bool important)
1718 RefPtr<CSSValueList> values = new CSSValueList;
1720 while (Value* val = valueList->current()) {
1721 RefPtr<CSSValue> parsedValue;
1722 if (val->unit == CSSPrimitiveValue::CSS_URI) {
1724 String value = parseURL(domString(val->string));
1725 parsedValue = new CSSImageValue(
1726 String(KURL(styleElement->baseURL().deprecatedString(), value.deprecatedString()).url()), styleElement);
1727 } else if (val->unit == Value::Function) {
1728 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z])
1729 ValueList *args = val->function->args;
1730 String fname = domString(val->function->name).lower();
1733 if (fname == "attr(") {
1734 if (args->size() != 1)
1736 Value* a = args->current();
1737 String attrName = domString(a->string);
1738 if (document()->isHTMLDocument())
1739 attrName = attrName.lower();
1740 parsedValue = new CSSPrimitiveValue(attrName, CSSPrimitiveValue::CSS_ATTR);
1741 } else if (fname == "counter(") {
1742 parsedValue = parseCounterContent(args, false);
1743 if (!parsedValue) return false;
1744 } else if (fname == "counters(") {
1745 parsedValue = parseCounterContent(args, true);
1750 } else if (val->unit == CSSPrimitiveValue::CSS_IDENT) {
1755 // FIXME: These are not yet implemented (http://bugs.webkit.org/show_bug.cgi?id=6503).
1756 } else if (val->unit == CSSPrimitiveValue::CSS_STRING) {
1757 parsedValue = new CSSPrimitiveValue(domString(val->string), CSSPrimitiveValue::CSS_STRING);
1761 values->append(parsedValue.release());
1765 if (values->length()) {
1766 addProperty(propId, values.release(), important);
1774 CSSValue* CSSParser::parseBackgroundColor()
1776 int id = valueList->current()->id;
1777 if (id == CSS_VAL__WEBKIT_TEXT || (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
1778 (id >= CSS_VAL_GREY && id < CSS_VAL__WEBKIT_TEXT && !strict))
1779 return new CSSPrimitiveValue(id);
1780 return parseColor();
1783 CSSValue* CSSParser::parseBackgroundImage()
1785 if (valueList->current()->id == CSS_VAL_NONE)
1786 return new CSSImageValue();
1787 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
1788 String uri = parseURL(domString(valueList->current()->string));
1790 return new CSSImageValue(String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
1796 CSSValue* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
1798 int id = valueList->current()->id;
1799 if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
1801 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
1805 if (id == CSS_VAL_RIGHT)
1808 else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
1812 if (id == CSS_VAL_BOTTOM)
1815 else if (id == CSS_VAL_CENTER)
1816 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
1818 return new CSSPrimitiveValue(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
1820 if (validUnit(valueList->current(), FPercent|FLength, strict))
1821 return new CSSPrimitiveValue(valueList->current()->fValue,
1822 (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
1827 void CSSParser::parseBackgroundPosition(CSSValue*& value1, CSSValue*& value2)
1829 value1 = value2 = 0;
1830 Value* value = valueList->current();
1832 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
1833 bool value1IsX = false, value1IsY = false;
1834 value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
1838 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
1839 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
1840 // value was explicitly specified for our property.
1841 value = valueList->next();
1843 // First check for the comma. If so, we are finished parsing this value or value pair.
1844 if (value && value->unit == Value::Operator && value->iValue == ',')
1847 bool value2IsX = false, value2IsY = false;
1849 value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
1853 if (!inShorthand()) {
1862 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
1863 // is simply 50%. This is our default.
1864 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
1865 // For left/right/center, the default of 50% in the y is still correct.
1866 value2 = new CSSPrimitiveValue(50, CSSPrimitiveValue::CSS_PERCENTAGE);
1868 if (value1IsY || value2IsX) {
1869 // Swap our two values.
1870 CSSValue* val = value2;
1876 CSSValue* CSSParser::parseBackgroundSize()
1878 Value* value = valueList->current();
1879 CSSPrimitiveValue* parsedValue1;
1881 if (value->id == CSS_VAL_AUTO)
1882 parsedValue1 = new CSSPrimitiveValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
1884 if (!validUnit(value, FLength|FPercent, strict))
1886 parsedValue1 = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1889 CSSPrimitiveValue* parsedValue2 = parsedValue1;
1890 if ((value = valueList->next())) {
1891 if (value->id == CSS_VAL_AUTO)
1892 parsedValue2 = new CSSPrimitiveValue(0, CSSPrimitiveValue::CSS_UNKNOWN);
1894 if (!validUnit(value, FLength|FPercent, strict)) {
1895 delete parsedValue1;
1898 parsedValue2 = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
1902 Pair* pair = new Pair(parsedValue1, parsedValue2);
1903 return new CSSPrimitiveValue(pair);
1906 bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2,
1907 CSSValue*& retValue1, CSSValue*& retValue2)
1909 CSSValueList *values = 0, *values2 = 0;
1911 CSSValue *value = 0, *value2 = 0;
1912 bool allowComma = false;
1914 retValue1 = retValue2 = 0;
1917 if (propId == CSS_PROP_BACKGROUND_POSITION) {
1918 propId1 = CSS_PROP_BACKGROUND_POSITION_X;
1919 propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
1922 while ((val = valueList->current())) {
1923 CSSValue *currValue = 0, *currValue2 = 0;
1925 if (val->unit != Value::Operator || val->iValue != ',')
1932 case CSS_PROP_BACKGROUND_ATTACHMENT:
1933 if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
1934 currValue = new CSSPrimitiveValue(val->id);
1938 case CSS_PROP_BACKGROUND_COLOR:
1939 currValue = parseBackgroundColor();
1943 case CSS_PROP_BACKGROUND_IMAGE:
1944 currValue = parseBackgroundImage();
1948 case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
1949 case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
1950 if (val->id == CSS_VAL_BORDER || val->id == CSS_VAL_PADDING || val->id == CSS_VAL_CONTENT) {
1951 currValue = new CSSPrimitiveValue(val->id);
1955 case CSS_PROP_BACKGROUND_POSITION:
1956 parseBackgroundPosition(currValue, currValue2);
1957 // unlike the other functions, parseBackgroundPosition advances the valueList pointer
1959 case CSS_PROP_BACKGROUND_POSITION_X: {
1960 bool xFound = false, yFound = true;
1961 currValue = parseBackgroundPositionXY(xFound, yFound);
1966 case CSS_PROP_BACKGROUND_POSITION_Y: {
1967 bool xFound = true, yFound = false;
1968 currValue = parseBackgroundPositionXY(xFound, yFound);
1973 case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
1974 if ((val->id >= CSS_VAL_CLEAR && val->id <= CSS_VAL_PLUS_LIGHTER) || val->id == CSS_VAL_HIGHLIGHT) {
1975 currValue = new CSSPrimitiveValue(val->id);
1979 case CSS_PROP_BACKGROUND_REPEAT:
1980 if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
1981 currValue = new CSSPrimitiveValue(val->id);
1985 case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
1986 currValue = parseBackgroundSize();
1995 if (value && !values) {
1996 values = new CSSValueList();
1997 values->append(value);
2001 if (value2 && !values2) {
2002 values2 = new CSSValueList();
2003 values2->append(value2);
2008 values->append(currValue);
2013 values2->append(currValue2);
2015 value2 = currValue2;
2020 // When parsing the 'background' shorthand property, we let it handle building up the lists for all
2026 if (values && values->length()) {
2028 if (values2 && values2->length())
2029 retValue2 = values2;
2039 delete values; delete values2;
2040 delete value; delete value2;
2044 #define DASHBOARD_REGION_NUM_PARAMETERS 6
2045 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2
2047 static Value *skipCommaInDashboardRegion (ValueList *args)
2049 if (args->size() == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
2050 args->size() == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
2051 Value *current = args->current();
2052 if (current->unit == Value::Operator && current->iValue == ',')
2053 return args->next();
2055 return args->current();
2058 bool CSSParser::parseDashboardRegions(int propId, bool important)
2062 Value *value = valueList->current();
2064 if (value->id == CSS_VAL_NONE) {
2065 if (valueList->next())
2067 addProperty(propId, new CSSPrimitiveValue(value->id), important);
2071 RefPtr<DashboardRegion> firstRegion = new DashboardRegion;
2072 DashboardRegion* region = 0;
2076 region = firstRegion.get();
2078 RefPtr<DashboardRegion> nextRegion = new DashboardRegion();
2079 region->m_next = nextRegion;
2080 region = nextRegion.get();
2083 if (value->unit != Value::Function) {
2088 // Commas count as values, so allow:
2089 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
2090 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
2092 // dashboard-region(label, type) or dashboard-region(label type)
2093 // dashboard-region(label, type) or dashboard-region(label type)
2094 ValueList* args = value->function->args;
2095 String fname = domString(value->function->name).lower();
2096 if (fname != "dashboard-region(" || !args) {
2101 int numArgs = args->size();
2102 if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
2103 (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))){
2108 // First arg is a label.
2109 Value* arg = args->current();
2110 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
2115 region->m_label = domString(arg->string);
2117 // Second arg is a type.
2119 arg = skipCommaInDashboardRegion (args);
2120 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
2125 String geometryType = domString(arg->string).lower();
2126 if (geometryType == "circle")
2127 region->m_isCircle = true;
2128 else if (geometryType == "rectangle")
2129 region->m_isRectangle = true;
2135 region->m_geometryType = domString(arg->string);
2137 if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
2138 // This originally used CSS_VAL_INVALID by accident. It might be more logical to use something else.
2139 CSSPrimitiveValue *amount = new CSSPrimitiveValue(CSS_VAL_INVALID);
2141 region->setTop(amount);
2142 region->setRight(amount);
2143 region->setBottom(amount);
2144 region->setLeft(amount);
2147 // Next four arguments must be offset numbers
2149 for (i = 0; i < 4; i++) {
2151 arg = skipCommaInDashboardRegion (args);
2153 valid = arg->id == CSS_VAL_AUTO || validUnit(arg, FLength, strict);
2157 CSSPrimitiveValue *amount = arg->id == CSS_VAL_AUTO ?
2158 new CSSPrimitiveValue(CSS_VAL_AUTO) :
2159 new CSSPrimitiveValue(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit);
2162 region->setTop(amount);
2164 region->setRight(amount);
2166 region->setBottom(amount);
2168 region->setLeft(amount);
2175 value = valueList->next();
2179 addProperty(propId, new CSSPrimitiveValue(firstRegion.release()), important);
2184 PassRefPtr<CSSValue> CSSParser::parseCounterContent(ValueList* args, bool counters)
2186 unsigned numArgs = args->size();
2187 if (counters && numArgs != 3 && numArgs != 5)
2189 if (!counters && numArgs != 1 && numArgs != 3)
2192 Value* i = args->current();
2193 RefPtr<CSSPrimitiveValue> identifier = new CSSPrimitiveValue(domString(i->string),
2194 CSSPrimitiveValue::CSS_STRING);
2196 RefPtr<CSSPrimitiveValue> separator;
2198 separator = new CSSPrimitiveValue(String(), CSSPrimitiveValue::CSS_STRING);
2201 if (i->unit != Value::Operator || i->iValue != ',')
2205 if (i->unit != CSSPrimitiveValue::CSS_STRING)
2208 separator = new CSSPrimitiveValue(domString(i->string), (CSSPrimitiveValue::UnitTypes) i->unit);
2211 RefPtr<CSSPrimitiveValue> listStyle;
2213 if (!i) // Make the list style default decimal
2214 listStyle = new CSSPrimitiveValue(CSS_VAL_DECIMAL - CSS_VAL_DISC, CSSPrimitiveValue::CSS_NUMBER);
2216 if (i->unit != Value::Operator || i->iValue != ',')
2220 if (i->unit != CSSPrimitiveValue::CSS_IDENT)
2224 if (i->id == CSS_VAL_NONE)
2225 ls = CSS_VAL_KATAKANA_IROHA - CSS_VAL_DISC + 1;
2226 else if (i->id >= CSS_VAL_DISC && i->id <= CSS_VAL_KATAKANA_IROHA)
2227 ls = i->id - CSS_VAL_DISC;
2231 listStyle = new CSSPrimitiveValue(ls, (CSSPrimitiveValue::UnitTypes) i->unit);
2234 return new CSSPrimitiveValue(new Counter(identifier.release(), listStyle.release(), separator.release()));
2237 bool CSSParser::parseShape(int propId, bool important)
2239 Value *value = valueList->current();
2240 ValueList *args = value->function->args;
2241 String fname = domString(value->function->name).lower();
2242 if (fname != "rect(" || !args)
2245 // rect(t, r, b, l) || rect(t r b l)
2246 if (args->size() != 4 && args->size() != 7)
2248 Rect *rect = new Rect();
2251 Value *a = args->current();
2253 valid = a->id == CSS_VAL_AUTO || validUnit(a, FLength, strict);
2256 CSSPrimitiveValue *length = a->id == CSS_VAL_AUTO ?
2257 new CSSPrimitiveValue(CSS_VAL_AUTO) :
2258 new CSSPrimitiveValue(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
2260 rect->setTop(length);
2262 rect->setRight(length);
2264 rect->setBottom(length);
2266 rect->setLeft(length);
2268 if (a && args->size() == 7) {
2269 if (a->unit == Value::Operator && a->iValue == ',') {
2279 addProperty(propId, new CSSPrimitiveValue(rect), important);
2287 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
2288 bool CSSParser::parseFont(bool important)
2291 Value *value = valueList->current();
2292 FontValue *font = new FontValue;
2293 // optional font-style, font-variant and font-weight
2297 if (id == CSS_VAL_NORMAL) {
2298 // do nothing, it's the inital value for all three
2299 } else if (id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE) {
2302 font->style = new CSSPrimitiveValue(id);
2303 } else if (id == CSS_VAL_SMALL_CAPS) {
2306 font->variant = new CSSPrimitiveValue(id);
2307 } else if (id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER) {
2310 font->weight = new CSSPrimitiveValue(id);
2314 } else if (!font->weight && validUnit(value, FInteger|FNonNeg, true)) {
2315 int weight = (int)value->fValue;
2319 else if (weight == 200)
2321 else if (weight == 300)
2323 else if (weight == 400)
2325 else if (weight == 500)
2327 else if (weight == 600)
2329 else if (weight == 700)
2331 else if (weight == 800)
2333 else if (weight == 900)
2337 font->weight = new CSSPrimitiveValue(val);
2345 value = valueList->next();
2350 // set undefined values to default
2352 font->style = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2354 font->variant = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2356 font->weight = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2358 // now a font size _must_ come
2359 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
2360 if (value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER)
2361 font->size = new CSSPrimitiveValue(value->id);
2362 else if (validUnit(value, FLength|FPercent, strict))
2363 font->size = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2364 value = valueList->next();
2365 if (!font->size || !value)
2368 if (value->unit == Value::Operator && value->iValue == '/') {
2370 value = valueList->next();
2373 if (value->id == CSS_VAL_NORMAL) {
2374 // default value, nothing to do
2375 } else if (validUnit(value, FNumber|FLength|FPercent, strict))
2376 font->lineHeight = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
2379 value = valueList->next();
2384 if (!font->lineHeight)
2385 font->lineHeight = new CSSPrimitiveValue(CSS_VAL_NORMAL);
2387 // font family must come now
2388 font->family = parseFontFamily();
2390 if (valueList->current() || !font->family)
2393 addProperty(CSS_PROP_FONT, font, important);
2401 CSSValueList* CSSParser::parseFontFamily()
2403 CSSValueList* list = new CSSValueList;
2404 Value* value = valueList->current();
2405 FontFamilyValue* currFamily = 0;
2407 Value* nextValue = valueList->next();
2408 bool nextValBreaksFont = !nextValue ||
2409 (nextValue->unit == Value::Operator && nextValue->iValue == ',');
2410 bool nextValIsFontName = nextValue &&
2411 ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL__WEBKIT_BODY) ||
2412 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
2414 if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL__WEBKIT_BODY) {
2416 currFamily->parsedFontName += ' ';
2417 currFamily->parsedFontName += deprecatedString(value->string);
2419 else if (nextValBreaksFont || !nextValIsFontName)
2420 list->append(new CSSPrimitiveValue(value->id));
2422 list->append(currFamily = new FontFamilyValue(deprecatedString(value->string)));
2424 else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
2425 // Strings never share in a family name.
2427 list->append(new FontFamilyValue(deprecatedString(value->string)));
2429 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2431 currFamily->parsedFontName += ' ';
2432 currFamily->parsedFontName += deprecatedString(value->string);
2434 else if (nextValBreaksFont || !nextValIsFontName)
2435 list->append(new FontFamilyValue(deprecatedString(value->string)));
2437 list->append(currFamily = new FontFamilyValue(deprecatedString(value->string)));
2446 if (nextValBreaksFont) {
2447 value = valueList->next();
2450 else if (nextValIsFontName)
2455 if (!list->length()) {
2462 bool CSSParser::parseColor(const String &name, RGBA32& rgb, bool strict)
2464 if (!strict && Color::parseHexColor(name, rgb))
2467 // try a little harder
2469 tc.setNamedColor(name.lower());
2478 bool CSSParser::parseColorParameters(Value* value, int* colorArray, bool parseAlpha)
2480 ValueList* args = value->function->args;
2481 Value* v = args->current();
2482 // Get the first value
2483 if (!validUnit(v, FInteger | FPercent, true))
2485 colorArray[0] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
2486 for (int i = 1; i < 3; i++) {
2488 if (v->unit != Value::Operator && v->iValue != ',')
2491 if (!validUnit(v, FInteger | FPercent, true))
2493 colorArray[i] = static_cast<int>(v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256.0 / 100.0 : 1.0));
2497 if (v->unit != Value::Operator && v->iValue != ',')
2500 if (!validUnit(v, FNumber, true))
2502 colorArray[3] = static_cast<int>(max(0.0, min(1.0, v->fValue)) * 255);
2507 // CSS3 sepcification defines the format of a HSL color as
2508 // hsl(<number>, <percent>, <percent>)
2509 // and with alpha, the format is
2510 // hsla(<number>, <percent>, <percent>, <number>)
2511 // The first value, HUE, is in an angle with a value between 0 and 360
2512 bool CSSParser::parseHSLParameters(Value* value, double* colorArray, bool parseAlpha)
2514 ValueList* args = value->function->args;
2515 Value* v = args->current();
2516 // Get the first value
2517 if (!validUnit(v, FInteger, true))
2519 // normalize the Hue value and change it to be between 0 and 1.0
2520 colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0;
2521 for (int i = 1; i < 3; i++) {
2523 if (v->unit != Value::Operator && v->iValue != ',')
2526 if (!validUnit(v, FPercent, true))
2528 colorArray[i] = max(0.0, min(100.0, v->fValue)) / 100.0; // needs to be value between 0 and 1.0
2532 if (v->unit != Value::Operator && v->iValue != ',')
2535 if (!validUnit(v, FNumber, true))
2537 colorArray[3] = max(0.0, min(1.0, v->fValue));
2542 CSSPrimitiveValue *CSSParser::parseColor(Value* value)
2544 RGBA32 c = Color::transparent;
2545 if (!parseColorFromValue(value ? value : valueList->current(), c))
2547 return new CSSPrimitiveValue(c);
2550 bool CSSParser::parseColorFromValue(Value* value, RGBA32& c, bool svg)
2552 if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
2553 value->fValue >= 0. && value->fValue < 1000000.) {
2554 String str = String::format("%06d", (int)(value->fValue+.5));
2555 if (!CSSParser::parseColor(str, c, strict))
2557 } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
2558 value->unit == CSSPrimitiveValue::CSS_IDENT ||
2559 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
2560 if (!CSSParser::parseColor(domString(value->string), c, strict && value->unit == CSSPrimitiveValue::CSS_IDENT))
2562 } else if (value->unit == Value::Function &&
2563 value->function->args != 0 &&
2564 value->function->args->size() == 5 /* rgb + two commas */ &&
2565 domString(value->function->name).lower() == "rgb(") {
2567 if (!parseColorParameters(value, colorValues, false))
2569 c = makeRGB(colorValues[0], colorValues[1], colorValues[2]);
2571 if (value->unit == Value::Function &&
2572 value->function->args != 0 &&
2573 value->function->args->size() == 7 /* rgba + three commas */ &&
2574 domString(value->function->name).lower() == "rgba(") {
2576 if (!parseColorParameters(value, colorValues, true))
2578 c = makeRGBA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
2579 } else if (value->unit == Value::Function &&
2580 value->function->args != 0 &&
2581 value->function->args->size() == 5 /* hsl + two commas */ &&
2582 domString(value->function->name).lower() == "hsl(") {
2583 double colorValues[3];
2584 if (!parseHSLParameters(value, colorValues, false))
2586 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], 1.0);
2587 } else if (value->unit == Value::Function &&
2588 value->function->args != 0 &&
2589 value->function->args->size() == 7 /* hsla + three commas */ &&
2590 domString(value->function->name).lower() == "hsla(") {
2591 double colorValues[4];
2592 if (!parseHSLParameters(value, colorValues, true))
2594 c = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
2603 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
2604 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
2605 struct ShadowParseContext {
2606 ShadowParseContext()
2607 :values(0), x(0), y(0), blur(0), color(0),
2608 allowX(true), allowY(false), allowBlur(false), allowColor(true),
2612 ~ShadowParseContext() {
2622 bool allowLength() { return allowX || allowY || allowBlur; }
2624 bool failed() { return allowBreak = false; }
2626 void commitValue() {
2627 // Handle the ,, case gracefully by doing nothing.
2628 if (x || y || blur || color) {
2630 values = new CSSValueList();
2632 // Construct the current shadow value and add it to the list.
2633 values->append(new ShadowValue(x, y, blur, color));
2636 // Now reset for the next shadow value.
2637 x = y = blur = color = 0;
2638 allowX = allowColor = allowBreak = true;
2639 allowY = allowBlur = false;
2642 void commitLength(Value* v) {
2643 CSSPrimitiveValue* val = new CSSPrimitiveValue(v->fValue,
2644 (CSSPrimitiveValue::UnitTypes)v->unit);
2647 allowX = false; allowY = true; allowColor = false; allowBreak = false;
2651 allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
2653 else if (allowBlur) {
2659 void commitColor(CSSPrimitiveValue* val) {
2668 CSSValueList* values;
2669 CSSPrimitiveValue* x;
2670 CSSPrimitiveValue* y;
2671 CSSPrimitiveValue* blur;
2672 CSSPrimitiveValue* color;
2681 bool CSSParser::parseShadow(int propId, bool important)
2683 ShadowParseContext context;
2685 while ((val = valueList->current())) {
2686 // Check for a comma break first.
2687 if (val->unit == Value::Operator) {
2688 if (val->iValue != ',' || !context.allowBreak)
2689 // Other operators aren't legal or we aren't done with the current shadow
2690 // value. Treat as invalid.
2691 return context.failed();
2693 // The value is good. Commit it.
2694 context.commitValue();
2696 // Check to see if we're a length.
2697 else if (validUnit(val, FLength, true)) {
2698 // We required a length and didn't get one. Invalid.
2699 if (!context.allowLength())
2700 return context.failed();
2702 // A length is allowed here. Construct the value and add it.
2703 context.commitLength(val);
2706 // The only other type of value that's ok is a color value.
2707 CSSPrimitiveValue* parsedColor = 0;
2708 bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
2709 (val->id >= CSS_VAL__WEBKIT_FOCUS_RING_COLOR && val->id <= CSS_VAL__WEBKIT_TEXT && !strict));
2711 if (!context.allowColor)
2712 return context.failed();
2713 parsedColor = new CSSPrimitiveValue(val->id);
2717 // It's not built-in. Try to parse it as a color.
2718 parsedColor = parseColor(val);
2720 if (!parsedColor || !context.allowColor)
2721 return context.failed(); // This value is not a color or length and is invalid or
2722 // it is a color, but a color isn't allowed at this point.
2724 context.commitColor(parsedColor);
2730 if (context.allowBreak) {
2731 context.commitValue();
2732 if (context.values->length()) {
2733 addProperty(propId, context.values, important);
2739 return context.failed();
2742 struct BorderImageParseContext
2744 BorderImageParseContext()
2745 :m_allowBreak(false), m_allowNumber(false), m_allowSlash(false), m_allowWidth(false),
2746 m_allowRule(false), m_image(0), m_top(0), m_right(0), m_bottom(0), m_left(0), m_borderTop(0), m_borderRight(0), m_borderBottom(0),
2747 m_borderLeft(0), m_horizontalRule(0), m_verticalRule(0)
2750 ~BorderImageParseContext() {
2751 if (!m_allowBreak) {
2753 delete m_top; delete m_right; delete m_bottom; delete m_left;
2754 delete m_borderTop; delete m_borderRight; delete m_borderBottom; delete m_borderLeft;
2758 bool failed() { return m_allowBreak = false; }
2759 bool allowBreak() const { return m_allowBreak; }
2760 bool allowNumber() const { return m_allowNumber; }
2761 bool allowSlash() const { return m_allowSlash; }
2762 bool allowWidth() const { return m_allowWidth; }
2763 bool allowRule() const { return m_allowRule; }
2765 void commitImage(CSSImageValue* image) { m_image = image; m_allowNumber = true; }
2766 void commitNumber(Value* v) {
2767 CSSPrimitiveValue* val = new CSSPrimitiveValue(v->fValue,
2768 (CSSPrimitiveValue::UnitTypes)v->unit);
2780 m_allowBreak = m_allowSlash = m_allowRule = true;
2781 m_allowNumber = !m_left;
2783 void commitSlash() { m_allowBreak = m_allowSlash = m_allowNumber = false; m_allowWidth = true; }
2784 void commitWidth(Value* val) {
2787 else if (!m_borderRight)
2788 m_borderRight = val;
2789 else if (!m_borderBottom)
2790 m_borderBottom = val;
2792 ASSERT(!m_borderLeft);
2796 m_allowBreak = m_allowRule = true;
2797 m_allowWidth = !m_borderLeft;
2799 void commitRule(int keyword) {
2800 if (!m_horizontalRule)
2801 m_horizontalRule = keyword;
2802 else if (!m_verticalRule)
2803 m_verticalRule = keyword;
2804 m_allowRule = !m_verticalRule;
2806 void commitBorderImage(CSSParser* p, int propId, bool important) {
2807 // We need to clone and repeat values for any omissions.
2809 m_right = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2810 m_bottom = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2811 m_left = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2814 m_bottom = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2815 m_left = new CSSPrimitiveValue(m_right->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_right->primitiveType());
2818 m_left = new CSSPrimitiveValue(m_top->getFloatValue(), (CSSPrimitiveValue::UnitTypes)m_top->primitiveType());
2820 // Now build a rect value to hold all four of our primitive values.
2821 Rect* rect = new Rect;
2822 rect->setTop(m_top); rect->setRight(m_right); rect->setBottom(m_bottom); rect->setLeft(m_left);
2824 // Fill in STRETCH as the default if it wasn't specified.
2825 if (!m_horizontalRule)
2826 m_horizontalRule = CSS_VAL_STRETCH;
2828 // The vertical rule should match the horizontal rule if unspecified.
2829 if (!m_verticalRule)
2830 m_verticalRule = m_horizontalRule;
2832 // Make our new border image value now and add it as the result.
2833 CSSBorderImageValue* borderImage = new CSSBorderImageValue(m_image, rect, m_horizontalRule, m_verticalRule);
2834 p->addProperty(propId, borderImage, important);
2836 // Now we have to deal with the border widths. The best way to deal with these is to actually put these values into a value
2837 // list and then make our parsing machinery do the parsing.
2840 newList.addValue(*m_borderTop);
2842 newList.addValue(*m_borderRight);
2844 newList.addValue(*m_borderBottom);
2846 newList.addValue(*m_borderLeft);
2847 p->valueList = &newList;
2848 p->parseValue(CSS_PROP_BORDER_WIDTH, important);
2859 CSSImageValue* m_image;
2861 CSSPrimitiveValue* m_top;
2862 CSSPrimitiveValue* m_right;
2863 CSSPrimitiveValue* m_bottom;
2864 CSSPrimitiveValue* m_left;
2867 Value* m_borderRight;
2868 Value* m_borderBottom;
2869 Value* m_borderLeft;
2871 int m_horizontalRule;
2875 bool CSSParser::parseBorderImage(int propId, bool important)
2877 // Look for an image initially. If the first value is not a URI, then we're done.
2878 BorderImageParseContext context;
2879 Value* val = valueList->current();
2880 if (val->unit != CSSPrimitiveValue::CSS_URI)
2881 return context.failed();
2883 String uri = parseURL(domString(val->string));
2885 return context.failed();
2887 context.commitImage(new CSSImageValue(String(KURL(styleElement->baseURL().deprecatedString(), uri.deprecatedString()).url()),
2889 while ((val = valueList->next())) {
2890 if (context.allowNumber() && validUnit(val, FInteger|FNonNeg|FPercent, true)) {
2891 context.commitNumber(val);
2892 } else if (context.allowSlash() && val->unit == Value::Operator && val->iValue == '/') {
2893 context.commitSlash();
2894 } else if (context.allowWidth() &&
2895 (val->id == CSS_VAL_THIN || val->id == CSS_VAL_MEDIUM || val->id == CSS_VAL_THICK || validUnit(val, FLength, strict))) {
2896 context.commitWidth(val);
2897 } else if (context.allowRule() &&
2898 (val->id == CSS_VAL_STRETCH || val->id == CSS_VAL_ROUND || val->id == CSS_VAL_REPEAT)) {
2899 context.commitRule(val->id);
2901 // Something invalid was encountered.
2902 return context.failed();
2906 if (context.allowBreak()) {
2907 // Need to fully commit as a single value.
2908 context.commitBorderImage(this, propId, important);
2912 return context.failed();
2915 bool CSSParser::parseCounter(int propId, int defaultValue, bool important)
2917 enum { ID, VAL } state = ID;
2919 RefPtr<CSSValueList> list = new CSSValueList;
2920 RefPtr<CSSPrimitiveValue> counterName;
2923 Value* val = valueList->current();
2926 if (val && val->unit == CSSPrimitiveValue::CSS_IDENT) {
2927 counterName = new CSSPrimitiveValue(domString(val->string), CSSPrimitiveValue::CSS_STRING);
2934 int i = defaultValue;
2935 if (val && val->unit == CSSPrimitiveValue::CSS_NUMBER) {
2936 i = (int)val->fValue;
2940 list->append(new CSSPrimitiveValue(new Pair(counterName.release(),
2941 new CSSPrimitiveValue(i, CSSPrimitiveValue::CSS_NUMBER))));
2949 if (list->length() > 0) {
2950 addProperty(propId, list.release(), important);
2959 static inline int yyerror(const char *str)
2961 kdDebug(6080) << "CSS parse error " << str << endl;
2967 static inline int yyerror(const char*) { return 1; }
2973 #include "CSSGrammar.h"
2975 int CSSParser::lex(void* yylvalWithoutType)
2977 YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
2980 UChar* t = text(&length);
2998 yylval->string.characters = t;
2999 yylval->string.length = length;
3036 yylval->val = DeprecatedString((DeprecatedChar *)t, length).toDouble();
3046 static inline int toHex(char c)
3048 if ('0' <= c && c <= '9')
3050 if ('a' <= c && c <= 'f')
3051 return c - 'a' + 10;
3052 if ('A' <= c && c<= 'F')
3053 return c - 'A' + 10;
3057 UChar* CSSParser::text(int *length)
3059 UChar* start = yytext;
3071 // "url("{w}{string}{w}")"
3072 // "url("{w}{url}{w}")"
3074 // strip "url(" and ")"
3079 (*start == ' ' || *start == '\t' || *start == '\r' ||
3080 *start == '\n' || *start == '\f')) {
3083 if (*start == '"' || *start == '\'') {
3087 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
3088 start[l-1] == '\n' || start[l-1] == '\f')) {
3091 if (l && (start[l-1] == '\"' || start[l-1] == '\''))
3102 for (int i = 0; i < l; i++) {
3103 UChar* current = start + i;
3104 if (escape == current - 1) {
3105 if ((*current >= '0' && *current <= '9') ||
3106 (*current >= 'a' && *current <= 'f') ||
3107 (*current >= 'A' && *current <= 'F'))
3109 if (yyTok == STRING &&
3110 (*current == '\n' || *current == '\r' || *current == '\f')) {
3111 // ### handle \r\n case
3112 if (*current != '\r')
3116 // in all other cases copy the char to output
3122 if (escape == current - 2 && yyTok == STRING &&
3123 *(current-1) == '\r' && *current == '\n') {
3127 if (escape > current - 7 &&
3128 ((*current >= '0' && *current <= '9') ||
3129 (*current >= 'a' && *current <= 'f') ||
3130 (*current >= 'A' && *current <= 'F')))
3136 while (escape < current) {
3138 uc += toHex(*escape);
3141 // can't handle chars outside ucs2
3146 if (*current == ' ' ||
3153 if (!escape && *current == '\\') {
3163 while (escape < start+l) {
3165 uc += toHex(*escape);
3168 // can't handle chars outside ucs2
3174 *length = out - start;
3178 CSSSelector* CSSParser::createFloatingSelector()
3180 CSSSelector* selector = new CSSSelector;
3181 m_floatingSelectors.add(selector);
3185 CSSSelector* CSSParser::sinkFloatingSelector(CSSSelector* selector)
3188 ASSERT(m_floatingSelectors.contains(selector));
3189 m_floatingSelectors.remove(selector);
3194 ValueList* CSSParser::createFloatingValueList()
3196 ValueList* list = new ValueList;
3197 m_floatingValueLists.add(list);
3201 ValueList* CSSParser::sinkFloatingValueList(ValueList* list)
3204 ASSERT(m_floatingValueLists.contains(list));
3205 m_floatingValueLists.remove(list);
3210 Function* CSSParser::createFloatingFunction()
3212 Function* function = new Function;
3213 m_floatingFunctions.add(function);
3217 Function* CSSParser::sinkFloatingFunction(Function* function)
3220 ASSERT(m_floatingFunctions.contains(function));
3221 m_floatingFunctions.remove(function);
3226 Value& CSSParser::sinkFloatingValue(Value& value)
3228 if (value.unit == Value::Function) {
3229 ASSERT(m_floatingFunctions.contains(value.function));
3230 m_floatingFunctions.remove(value.function);
3235 MediaQueryExp* CSSParser::createFloatingMediaQueryExp(const AtomicString& mediaFeature, ValueList* values)
3237 delete m_floatingMediaQueryExp;
3238 m_floatingMediaQueryExp = new MediaQueryExp(mediaFeature, values);
3239 return m_floatingMediaQueryExp;
3242 MediaQueryExp* CSSParser::sinkFloatingMediaQueryExp(MediaQueryExp* e)
3244 ASSERT(e == m_floatingMediaQueryExp);
3245 m_floatingMediaQueryExp = 0;
3249 Vector<MediaQueryExp*>* CSSParser::createFloatingMediaQueryExpList()
3251 if (m_floatingMediaQueryExpList) {
3252 deleteAllValues(*m_floatingMediaQueryExpList);
3253 delete m_floatingMediaQueryExpList;
3255 m_floatingMediaQueryExpList = new Vector<MediaQueryExp*>;
3256 return m_floatingMediaQueryExpList;
3259 Vector<MediaQueryExp*>* CSSParser::sinkFloatingMediaQueryExpList(Vector<MediaQueryExp*>* l)
3261 ASSERT(l == m_floatingMediaQueryExpList);
3262 m_floatingMediaQueryExpList = 0;
3266 MediaQuery* CSSParser::createFloatingMediaQuery(MediaQuery::Restrictor r, const String& mediaType, Vector<MediaQueryExp*>* exprs)
3268 delete m_floatingMediaQuery;
3269 m_floatingMediaQuery = new MediaQuery(r, mediaType, exprs);
3270 return m_floatingMediaQuery;
3273 MediaQuery* CSSParser::sinkFloatingMediaQuery(MediaQuery* mq)
3275 ASSERT(mq == m_floatingMediaQuery);
3276 m_floatingMediaQuery = 0;
3280 MediaList* CSSParser::createMediaList()
3282 MediaList* list = new MediaList;
3283 m_parsedStyleObjects.append(list);
3287 CSSRule* CSSParser::createCharsetRule(const ParseString& charset)
3291 if (!styleElement->isCSSStyleSheet())
3293 CSSCharsetRule* rule = new CSSCharsetRule(styleElement, domString(charset));
3294 m_parsedStyleObjects.append(rule);
3298 CSSRule* CSSParser::createImportRule(const ParseString& URL, MediaList* media)
3304 if (!styleElement->isCSSStyleSheet())
3306 CSSImportRule* rule = new CSSImportRule(styleElement, domString(URL), media);
3307 m_parsedStyleObjects.append(rule);
3311 CSSRule* CSSParser::createMediaRule(MediaList* media, CSSRuleList* rules)
3319 if (!styleElement->isCSSStyleSheet())
3321 CSSMediaRule* rule = new CSSMediaRule(styleElement, media, rules);
3322 m_parsedStyleObjects.append(rule);
3326 CSSRuleList* CSSParser::createRuleList()
3328 CSSRuleList* list = new CSSRuleList;
3329 m_parsedRuleLists.append(list);
3333 CSSRule* CSSParser::createStyleRule(CSSSelector* selector)
3335 CSSStyleRule* rule = 0;
3337 rule = new CSSStyleRule(styleElement);
3338 m_parsedStyleObjects.append(rule);
3339 rule->setSelector(sinkFloatingSelector(selector));
3340 rule->setDeclaration(new CSSMutableStyleDeclaration(rule, parsedProperties, numParsedProperties));
3346 DeprecatedString deprecatedString(const ParseString& ps)
3348 return DeprecatedString(reinterpret_cast<const DeprecatedChar*>(ps.characters), ps.length);
3351 #define YY_DECL int CSSParser::lex()
3352 #define yyconst const
3353 typedef int yy_state_type;
3354 typedef unsigned YY_CHAR;
3355 // this line makes sure we treat all Unicode chars correctly.
3356 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
3357 #define YY_DO_BEFORE_ACTION \
3359 yyleng = (int) (yy_cp - yy_bp); \
3360 yy_hold_char = *yy_cp; \
3363 #define YY_BREAK break;
3365 #define YY_RULE_SETUP
3367 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
3368 #define yyterminate() yyTok = END_TOKEN; return yyTok
3369 #define YY_FATAL_ERROR(a)
3370 // The line below is needed to build the tokenizer with conditon stack.
3371 // The macro is used in the tokenizer grammar with lines containing
3372 // BEGIN(mediaqueries) and BEGIN(initial). yy_start acts as index to
3373 // tokenizer transition table, and 'mediaqueries' and 'initial' are
3374 // offset multipliers that specify which transitions are active
3375 // in the tokenizer during in each condition (tokenizer state)
3376 #define BEGIN yy_start = 1 + 2 *
3378 #include "tokenizer.cpp"