2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
5 * Copyright (C) 2004 Apple Computer, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 // #define TOKEN_DEBUG
30 #include "cssparser.h"
31 #include "css_valueimpl.h"
32 #include "css_ruleimpl.h"
33 #include "css_stylesheetimpl.h"
34 #include "cssproperties.h"
35 #include "cssvalues.h"
36 #include "misc/helper.h"
37 #include "xml/dom_docimpl.h"
38 #include "csshelper.h"
44 void qFatal ( const char * msg ) {}
47 ValueList::ValueList()
49 values = (Value *) malloc( 16 * sizeof ( Value ) );
55 ValueList::~ValueList()
57 for ( int i = 0; i < numValues; i++ ) {
59 kdDebug( 6080 ) << " value: (unit=" << values[i].unit <<")"<< endl;
61 if ( values[i].unit == Value::Function )
62 delete values[i].function;
67 void ValueList::addValue( const Value &val )
69 if ( numValues >= maxValues ) {
71 values = (Value *) realloc( values, maxValues*sizeof( Value ) );
73 values[numValues++] = val;
80 extern int cssyydebug;
83 extern int cssyyparse( void * parser );
85 CSSParser *CSSParser::currentParser = 0;
87 CSSParser::CSSParser( bool strictParsing )
90 kdDebug( 6080 ) << "CSSParser::CSSParser this=" << this << endl;
92 strict = strictParsing;
94 parsedProperties = (CSSProperty **) malloc( 32 * sizeof( CSSProperty * ) );
95 numParsedProperties = 0;
96 maxParsedProperties = 32;
103 inParseShortHand = false;
105 defaultNamespace = anyNamespace;
115 CSSParser::~CSSParser()
117 if ( numParsedProperties )
119 free( parsedProperties );
124 kdDebug( 6080 ) << "CSSParser::~CSSParser this=" << this << endl;
131 void ParseString::lower()
133 for (int i = 0; i < length; i++)
134 string[i] = QChar(string[i]).lower().unicode();
137 void CSSParser::setupParser(const char *prefix, const DOMString &string, const char *suffix)
139 int length = string.length() + strlen(prefix) + strlen(suffix) + 2;
141 data = (unsigned short *)malloc( length *sizeof( unsigned short ) );
142 for ( unsigned int i = 0; i < strlen(prefix); i++ )
145 memcpy( data + strlen( prefix ), string.unicode(), string.length()*sizeof( unsigned short) );
147 unsigned int start = strlen( prefix ) + string.length();
148 unsigned int end = start + strlen(suffix);
149 for ( unsigned int i = start; i < end; i++ )
150 data[i] = suffix[i-start];
157 yytext = yy_c_buf_p = data;
158 yy_hold_char = *yy_c_buf_p;
161 void CSSParser::parseSheet( CSSStyleSheetImpl *sheet, const DOMString &string )
163 styleElement = sheet;
164 defaultNamespace = anyNamespace; // Reset the default namespace.
166 setupParser ("", string, "");
169 kdDebug( 6080 ) << ">>>>>>> start parsing style sheet" << endl;
171 CSSParser *old = currentParser;
172 currentParser = this;
176 kdDebug( 6080 ) << "<<<<<<< done parsing style sheet" << endl;
183 CSSRuleImpl *CSSParser::parseRule( DOM::CSSStyleSheetImpl *sheet, const DOM::DOMString &string )
185 styleElement = sheet;
187 setupParser ("@-khtml-rule{", string, "} ");
189 CSSParser *old = currentParser;
190 currentParser = this;
194 CSSRuleImpl *result = rule;
200 bool CSSParser::parseValue( CSSMutableStyleDeclarationImpl *declaration, int _id, const DOMString &string,
204 kdDebug( 6080 ) << "CSSParser::parseValue: id=" << _id << " important=" << _important
205 << " value='" << string.string() << "'" << endl;
208 styleElement = declaration->stylesheet();
210 setupParser ("@-khtml-value{", string, "} ");
213 important = _important;
215 CSSParser *old = currentParser;
216 currentParser = this;
224 if ( numParsedProperties ) {
226 declaration->addParsedProperties(parsedProperties, numParsedProperties);
233 QRgb CSSParser::parseColor( const DOM::DOMString &string )
236 CSSMutableStyleDeclarationImpl *dummyStyleDeclaration = new CSSMutableStyleDeclarationImpl;
238 dummyStyleDeclaration->ref();
240 DOM::CSSParser parser(true);
242 // First try creating a color specified by name or the "#" syntax.
243 if (!parser.parseColor(string.string(), color)) {
245 // Now try to create a color from the rgb() or rgba() syntax.
246 bool ok = parser.parseColor(dummyStyleDeclaration, string);
248 CSSValueImpl *value = parser.parsedProperties[0]->value();
249 if (value->cssValueType() == DOM::CSSValue::CSS_PRIMITIVE_VALUE) {
250 DOM::CSSPrimitiveValueImpl *primitiveValue = static_cast<DOM::CSSPrimitiveValueImpl *>(value);
251 color = primitiveValue->getRGBColorValue();
257 dummyStyleDeclaration->deref();
262 bool CSSParser::parseColor( CSSMutableStyleDeclarationImpl *declaration, const DOMString &string )
264 styleElement = declaration->stylesheet();
266 setupParser ( "@-khtml-decls{color:", string, "} ");
268 CSSParser *old = currentParser;
269 currentParser = this;
277 if ( numParsedProperties && parsedProperties[0]->m_id == CSS_PROP_COLOR) {
284 bool CSSParser::parseDeclaration( CSSMutableStyleDeclarationImpl *declaration, const DOMString &string )
287 kdDebug( 6080 ) << "CSSParser::parseDeclaration:value='" << string.string() << "'" << endl;
290 styleElement = declaration->stylesheet();
292 setupParser ( "@-khtml-decls{", string, "} ");
294 CSSParser *old = currentParser;
295 currentParser = this;
303 if ( numParsedProperties ) {
305 declaration->addParsedProperties(parsedProperties, numParsedProperties);
313 void CSSParser::addProperty( int propId, CSSValueImpl *value, bool important )
315 CSSProperty *prop = new CSSProperty;
317 prop->setValue( value );
318 prop->m_bImportant = important;
320 if ( numParsedProperties >= maxParsedProperties ) {
321 maxParsedProperties += 32;
322 parsedProperties = (CSSProperty **) realloc( parsedProperties,
323 maxParsedProperties*sizeof( CSSProperty * ) );
325 parsedProperties[numParsedProperties++] = prop;
328 CSSMutableStyleDeclarationImpl *CSSParser::createStyleDeclaration( CSSStyleRuleImpl *rule )
330 CSSMutableStyleDeclarationImpl *result = new CSSMutableStyleDeclarationImpl(rule, parsedProperties, numParsedProperties);
335 void CSSParser::clearProperties()
337 for ( int i = 0; i < numParsedProperties; i++ )
338 delete parsedProperties[i];
339 numParsedProperties = 0;
342 DOM::DocumentImpl *CSSParser::document() const
344 StyleBaseImpl *root = styleElement;
345 DocumentImpl *doc = 0;
346 while (root->parent())
347 root = root->parent();
348 if (root->isCSSStyleSheet())
349 doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
354 // defines units allowed for a certain property, used in parseUnit
359 FNumber = 0x0002, // Real Numbers
369 static bool validUnit( Value *value, int unitflags, bool strict )
371 if ( unitflags & FNonNeg && value->fValue < 0 )
375 switch( value->unit ) {
376 case CSSPrimitiveValue::CSS_NUMBER:
377 b = (unitflags & FNumber);
378 if ( !b && ( (unitflags & FLength) && (value->fValue == 0 || !strict ) ) ) {
379 value->unit = CSSPrimitiveValue::CSS_PX;
382 if ( !b && ( unitflags & FInteger ) &&
383 (value->fValue - (int)value->fValue) < 0.001 )
386 case CSSPrimitiveValue::CSS_PERCENTAGE:
387 b = (unitflags & FPercent);
390 case CSSPrimitiveValue::CSS_EMS:
391 case CSSPrimitiveValue::CSS_EXS:
392 case CSSPrimitiveValue::CSS_PX:
393 case CSSPrimitiveValue::CSS_CM:
394 case CSSPrimitiveValue::CSS_MM:
395 case CSSPrimitiveValue::CSS_IN:
396 case CSSPrimitiveValue::CSS_PT:
397 case CSSPrimitiveValue::CSS_PC:
398 b = (unitflags & FLength);
400 case CSSPrimitiveValue::CSS_MS:
401 case CSSPrimitiveValue::CSS_S:
402 b = (unitflags & FTime);
404 case CSSPrimitiveValue::CSS_DEG:
405 case CSSPrimitiveValue::CSS_RAD:
406 case CSSPrimitiveValue::CSS_GRAD:
407 case CSSPrimitiveValue::CSS_HZ:
408 case CSSPrimitiveValue::CSS_KHZ:
409 case CSSPrimitiveValue::CSS_DIMENSION:
416 bool CSSParser::parseValue( int propId, bool important )
418 if ( !valueList ) return false;
420 Value *value = valueList->current();
428 if (id == CSS_VAL_INHERIT) {
429 addProperty(propId, new CSSInheritedValueImpl(), important);
432 else if (id == CSS_VAL_INITIAL) {
433 addProperty(propId, new CSSInitialValueImpl(), important);
437 bool valid_primitive = false;
438 CSSValueImpl *parsedValue = 0;
441 /* The comment to the left defines all valid value of this properties as defined
442 * in CSS 2, Appendix F. Property index
445 /* All the CSS properties are not supported by the renderer at the moment.
446 * Note that all the CSS2 Aural properties are only checked, if CSS_AURAL is defined
447 * (see parseAuralValues). As we don't support them at all this seems reasonable.
450 case CSS_PROP_SIZE: // <length>{1,2} | auto | portrait | landscape | inherit
451 case CSS_PROP_QUOTES: // [<string> <string>]+ | none | inherit
452 // case CSS_PROP_PAGE: // <identifier> | auto // ### CHECK
455 valid_primitive = true;
457 case CSS_PROP_UNICODE_BIDI: // normal | embed | bidi-override | inherit
458 if ( id == CSS_VAL_NORMAL ||
459 id == CSS_VAL_EMBED ||
460 id == CSS_VAL_BIDI_OVERRIDE )
461 valid_primitive = true;
464 case CSS_PROP_POSITION: // static | relative | absolute | fixed | inherit
465 if ( id == CSS_VAL_STATIC ||
466 id == CSS_VAL_RELATIVE ||
467 id == CSS_VAL_ABSOLUTE ||
468 id == CSS_VAL_FIXED )
469 valid_primitive = true;
472 case CSS_PROP_PAGE_BREAK_AFTER: // auto | always | avoid | left | right | inherit
473 case CSS_PROP_PAGE_BREAK_BEFORE: // auto | always | avoid | left | right | inherit
474 if ( id == CSS_VAL_AUTO ||
475 id == CSS_VAL_ALWAYS ||
476 id == CSS_VAL_AVOID ||
477 id == CSS_VAL_LEFT ||
478 id == CSS_VAL_RIGHT )
479 valid_primitive = true;
482 case CSS_PROP_PAGE_BREAK_INSIDE: // avoid | auto | inherit
483 if ( id == CSS_VAL_AUTO ||
484 id == CSS_VAL_AVOID )
485 valid_primitive = true;
488 case CSS_PROP_EMPTY_CELLS: // show | hide | inherit
489 if ( id == CSS_VAL_SHOW ||
491 valid_primitive = true;
494 case CSS_PROP_CONTENT: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
495 // close-quote | no-open-quote | no-close-quote ]+ | inherit
496 return parseContent( propId, important );
499 case CSS_PROP_WHITE_SPACE: // normal | pre | nowrap | inherit
500 if ( id == CSS_VAL_NORMAL ||
502 id == CSS_VAL_NOWRAP )
503 valid_primitive = true;
506 case CSS_PROP_CLIP: // <shape> | auto | inherit
507 if ( id == CSS_VAL_AUTO )
508 valid_primitive = true;
509 else if ( value->unit == Value::Function )
510 return parseShape( propId, important );
514 case CSS_PROP__KHTML_DASHBOARD_REGION: // <dashboard-region> | <dashboard-region>
515 if ( value->unit == Value::Function || id == CSS_VAL_NONE)
516 return parseDashboardRegions( propId, important );
520 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
521 * correctly and allows optimization in khtml::applyRule(..)
523 case CSS_PROP_CAPTION_SIDE: // top | bottom | left | right | inherit
524 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
525 id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM)
526 valid_primitive = true;
529 case CSS_PROP_BORDER_COLLAPSE: // collapse | separate | inherit
530 if ( id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE )
531 valid_primitive = true;
534 case CSS_PROP_VISIBILITY: // visible | hidden | collapse | inherit
535 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_COLLAPSE)
536 valid_primitive = true;
539 case CSS_PROP_OVERFLOW: // visible | hidden | scroll | auto | marquee | overlay | inherit
540 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
541 id == CSS_VAL_MARQUEE || id == CSS_VAL_OVERLAY)
542 valid_primitive = true;
545 case CSS_PROP_LIST_STYLE_POSITION: // inside | outside | inherit
546 if ( id == CSS_VAL_INSIDE || id == CSS_VAL_OUTSIDE )
547 valid_primitive = true;
550 case CSS_PROP_LIST_STYLE_TYPE:
551 // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
552 // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
553 // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
554 // katakana | hiragana-iroha | katakana-iroha | none | inherit
555 if ((id >= CSS_VAL_DISC && id <= CSS_VAL_KATAKANA_IROHA) || id == CSS_VAL_NONE)
556 valid_primitive = true;
559 case CSS_PROP_DISPLAY:
560 // inline | block | list-item | run-in | inline-block | table |
561 // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
562 // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
563 if ((id >= CSS_VAL_INLINE && id <= CSS_VAL__KHTML_INLINE_BOX) || id == CSS_VAL_NONE)
564 valid_primitive = true;
567 case CSS_PROP_DIRECTION: // ltr | rtl | inherit
568 if ( id == CSS_VAL_LTR || id == CSS_VAL_RTL )
569 valid_primitive = true;
572 case CSS_PROP_TEXT_TRANSFORM: // capitalize | uppercase | lowercase | none | inherit
573 if ((id >= CSS_VAL_CAPITALIZE && id <= CSS_VAL_LOWERCASE) || id == CSS_VAL_NONE)
574 valid_primitive = true;
577 case CSS_PROP_FLOAT: // left | right | none | inherit + center for buggy CSS
578 if ( id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT ||
579 id == CSS_VAL_NONE || id == CSS_VAL_CENTER)
580 valid_primitive = true;
583 case CSS_PROP_CLEAR: // none | left | right | both | inherit
584 if ( id == CSS_VAL_NONE || id == CSS_VAL_LEFT ||
585 id == CSS_VAL_RIGHT|| id == CSS_VAL_BOTH)
586 valid_primitive = true;
589 case CSS_PROP_TEXT_ALIGN:
590 // left | right | center | justify | khtml_left | khtml_right | khtml_center | <string> | inherit
591 if ( ( id >= CSS_VAL__KHTML_AUTO && id <= CSS_VAL__KHTML_CENTER ) ||
592 value->unit == CSSPrimitiveValue::CSS_STRING )
593 valid_primitive = true;
596 case CSS_PROP_OUTLINE_STYLE: // <border-style> | auto | inherit
597 if (id == CSS_VAL_AUTO) {
598 valid_primitive = true;
601 case CSS_PROP_BORDER_TOP_STYLE: //// <border-style> | inherit
602 case CSS_PROP_BORDER_RIGHT_STYLE: // Defined as: none | hidden | dotted | dashed |
603 case CSS_PROP_BORDER_BOTTOM_STYLE: // solid | double | groove | ridge | inset | outset
604 case CSS_PROP_BORDER_LEFT_STYLE: ////
605 if (id >= CSS_VAL_NONE && id <= CSS_VAL_DOUBLE)
606 valid_primitive = true;
609 case CSS_PROP_FONT_WEIGHT: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
610 // 500 | 600 | 700 | 800 | 900 | inherit
611 if (id >= CSS_VAL_NORMAL && id <= CSS_VAL_900) {
612 // Allready correct id
613 valid_primitive = true;
614 } else if ( validUnit( value, FInteger|FNonNeg, false ) ) {
615 int weight = (int)value->fValue;
616 if ( (weight % 100) )
619 if ( weight >= 1 && weight <= 9 ) {
620 id = CSS_VAL_100 + weight - 1;
621 valid_primitive = true;
626 case CSS_PROP_BORDER_SPACING: {
627 const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
628 CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
629 int num = valueList->numValues;
631 if (!parseValue(properties[0], important)) return false;
632 CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
633 addProperty(properties[1], value, important);
637 if (!parseValue(properties[0], important)) return false;
638 if (!parseValue(properties[1], important)) return false;
643 case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING:
644 case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING:
645 valid_primitive = validUnit(value, FLength|FNonNeg, strict);
647 case CSS_PROP_SCROLLBAR_FACE_COLOR: // IE5.5
648 case CSS_PROP_SCROLLBAR_SHADOW_COLOR: // IE5.5
649 case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR: // IE5.5
650 case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR: // IE5.5
651 case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR: // IE5.5
652 case CSS_PROP_SCROLLBAR_TRACK_COLOR: // IE5.5
653 case CSS_PROP_SCROLLBAR_ARROW_COLOR: // IE5.5
657 case CSS_PROP_OUTLINE_COLOR: // <color> | invert | inherit
658 // outline has "invert" as additional keyword.
659 if ( propId == CSS_PROP_OUTLINE_COLOR && id == CSS_VAL_INVERT ) {
660 valid_primitive = true;
664 case CSS_PROP_BACKGROUND_COLOR: // <color> | inherit
665 case CSS_PROP_BORDER_TOP_COLOR: // <color> | inherit
666 case CSS_PROP_BORDER_RIGHT_COLOR: // <color> | inherit
667 case CSS_PROP_BORDER_BOTTOM_COLOR: // <color> | inherit
668 case CSS_PROP_BORDER_LEFT_COLOR: // <color> | inherit
669 case CSS_PROP_COLOR: // <color> | inherit
670 case CSS_PROP_TEXT_LINE_THROUGH_COLOR: // CSS3 text decoration colors
671 case CSS_PROP_TEXT_UNDERLINE_COLOR:
672 case CSS_PROP_TEXT_OVERLINE_COLOR:
673 if (id == CSS_VAL__KHTML_TEXT)
674 valid_primitive = true; // Always allow this, even when strict parsing is on,
675 // since we use this in our UA sheets.
676 else if ( id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT || id == CSS_VAL_MENU ||
677 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict) ) {
678 valid_primitive = true;
680 parsedValue = parseColor();
686 case CSS_PROP_CURSOR:
687 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
688 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text |
689 // wait | help ] ] | inherit
690 // MSIE 5 compatibility :/
691 if ( !strict && id == CSS_VAL_HAND ) {
692 id = CSS_VAL_POINTER;
693 valid_primitive = true;
694 } else if ( id >= CSS_VAL_AUTO && id <= CSS_VAL_HELP )
695 valid_primitive = true;
698 case CSS_PROP_BACKGROUND_ATTACHMENT:
699 case CSS_PROP_BACKGROUND_IMAGE:
700 case CSS_PROP_BACKGROUND_POSITION:
701 case CSS_PROP_BACKGROUND_POSITION_X:
702 case CSS_PROP_BACKGROUND_POSITION_Y:
703 case CSS_PROP_BACKGROUND_REPEAT: {
704 CSSValueImpl *val1 = 0, *val2 = 0;
705 int propId1, propId2;
706 if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
707 addProperty(propId1, val1, important);
709 addProperty(propId2, val2, important);
714 case CSS_PROP_LIST_STYLE_IMAGE: // <uri> | none | inherit
715 if (id == CSS_VAL_NONE) {
716 parsedValue = new CSSImageValueImpl();
719 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
720 // ### allow string in non strict mode?
721 DOMString uri = khtml::parseURL( domString( value->string ) );
722 if (!uri.isEmpty()) {
723 parsedValue = new CSSImageValueImpl(
724 DOMString(KURL( styleElement->baseURL().string(), uri.string()).url()),
731 case CSS_PROP_OUTLINE_WIDTH: // <border-width> | inherit
732 case CSS_PROP_BORDER_TOP_WIDTH: //// <border-width> | inherit
733 case CSS_PROP_BORDER_RIGHT_WIDTH: // Which is defined as
734 case CSS_PROP_BORDER_BOTTOM_WIDTH: // thin | medium | thick | <length>
735 case CSS_PROP_BORDER_LEFT_WIDTH: ////
736 if (id == CSS_VAL_THIN || id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
737 valid_primitive = true;
739 valid_primitive = ( validUnit( value, FLength, strict ) );
742 case CSS_PROP_LETTER_SPACING: // normal | <length> | inherit
743 case CSS_PROP_WORD_SPACING: // normal | <length> | inherit
744 if ( id == CSS_VAL_NORMAL )
745 valid_primitive = true;
747 valid_primitive = validUnit( value, FLength, strict );
750 case CSS_PROP_WORD_WRAP: // normal | break-word
751 if (id == CSS_VAL_NORMAL || id == CSS_VAL_BREAK_WORD)
752 valid_primitive = true;
755 case CSS_PROP__KHTML_FONT_SIZE_DELTA: // <length>
756 valid_primitive = validUnit( value, FLength, strict );
759 case CSS_PROP__KHTML_NBSP_MODE: // normal | space
760 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SPACE)
761 valid_primitive = true;
764 case CSS_PROP__KHTML_LINE_BREAK: // normal | after-white-space
765 if (id == CSS_VAL_NORMAL || id == CSS_VAL_AFTER_WHITE_SPACE)
766 valid_primitive = true;
769 case CSS_PROP__KHTML_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR: // normal | match
770 if (id == CSS_VAL_NORMAL || id == CSS_VAL_MATCH)
771 valid_primitive = true;
774 case CSS_PROP_TEXT_INDENT: // <length> | <percentage> | inherit
775 case CSS_PROP_PADDING_TOP: //// <padding-width> | inherit
776 case CSS_PROP_PADDING_RIGHT: // Which is defined as
777 case CSS_PROP_PADDING_BOTTOM: // <length> | <percentage>
778 case CSS_PROP_PADDING_LEFT: ////
779 case CSS_PROP__KHTML_PADDING_START:
780 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict ) );
783 case CSS_PROP_MAX_HEIGHT: // <length> | <percentage> | none | inherit
784 case CSS_PROP_MAX_WIDTH: // <length> | <percentage> | none | inherit
785 if (id == CSS_VAL_NONE || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC) {
786 valid_primitive = true;
790 case CSS_PROP_MIN_HEIGHT: // <length> | <percentage> | inherit
791 case CSS_PROP_MIN_WIDTH: // <length> | <percentage> | inherit
792 if (id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
793 valid_primitive = true;
795 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict ) );
798 case CSS_PROP_FONT_SIZE:
799 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
800 if (id >= CSS_VAL_XX_SMALL && id <= CSS_VAL_LARGER)
801 valid_primitive = true;
803 valid_primitive = ( validUnit( value, FLength|FPercent, strict ) );
806 case CSS_PROP_FONT_STYLE: // normal | italic | oblique | inherit
807 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE)
808 valid_primitive = true;
811 case CSS_PROP_FONT_VARIANT: // normal | small-caps | inherit
812 if ( id == CSS_VAL_NORMAL || id == CSS_VAL_SMALL_CAPS)
813 valid_primitive = true;
816 case CSS_PROP_VERTICAL_ALIGN:
817 // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
818 // <percentage> | <length> | inherit
820 if ( id >= CSS_VAL_BASELINE && id <= CSS_VAL__KHTML_BASELINE_MIDDLE )
821 valid_primitive = true;
823 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict ) );
826 case CSS_PROP_HEIGHT: // <length> | <percentage> | auto | inherit
827 case CSS_PROP_WIDTH: // <length> | <percentage> | auto | inherit
828 if (id == CSS_VAL_AUTO || id == CSS_VAL_INTRINSIC || id == CSS_VAL_MIN_INTRINSIC)
829 valid_primitive = true;
831 // ### handle multilength case where we allow relative units
832 valid_primitive = ( !id && validUnit( value, FLength|FPercent|FNonNeg, strict ) );
835 case CSS_PROP_BOTTOM: // <length> | <percentage> | auto | inherit
836 case CSS_PROP_LEFT: // <length> | <percentage> | auto | inherit
837 case CSS_PROP_RIGHT: // <length> | <percentage> | auto | inherit
838 case CSS_PROP_TOP: // <length> | <percentage> | auto | inherit
839 case CSS_PROP_MARGIN_TOP: //// <margin-width> | inherit
840 case CSS_PROP_MARGIN_RIGHT: // Which is defined as
841 case CSS_PROP_MARGIN_BOTTOM: // <length> | <percentage> | auto | inherit
842 case CSS_PROP_MARGIN_LEFT: ////
843 case CSS_PROP__KHTML_MARGIN_START:
844 if ( id == CSS_VAL_AUTO )
845 valid_primitive = true;
847 valid_primitive = ( !id && validUnit( value, FLength|FPercent, strict ) );
850 case CSS_PROP_Z_INDEX: // auto | <integer> | inherit
851 // qDebug("parsing z-index: id=%d, fValue=%f", id, value->fValue );
852 if ( id == CSS_VAL_AUTO ) {
853 valid_primitive = true;
857 case CSS_PROP_ORPHANS: // <integer> | inherit
858 case CSS_PROP_WIDOWS: // <integer> | inherit
859 // ### not supported later on
860 valid_primitive = ( !id && validUnit( value, FInteger, false ) );
863 case CSS_PROP_LINE_HEIGHT: // normal | <number> | <length> | <percentage> | inherit
864 if ( id == CSS_VAL_NORMAL )
865 valid_primitive = true;
867 valid_primitive = ( !id && validUnit( value, FNumber|FLength|FPercent, strict ) );
870 // removed from CSS 2.1
871 case CSS_PROP_COUNTER_INCREMENT: // [ <identifier> <integer>? ]+ | none | inherit
872 case CSS_PROP_COUNTER_RESET: // [ <identifier> <integer>? ]+ | none | inherit
873 if ( id == CSS_VAL_NONE )
874 valid_primitive = true;
876 CSSValueListImpl *list = new CSSValueListImpl;
880 pos2 = value.find(',', pos);
881 QString face = value.mid(pos, pos2-pos);
882 face = face.stripWhiteSpace();
883 if(face.length() == 0) break;
884 // ### single quoted is missing...
885 if(face[0] == '\"') face.remove(0, 1);
886 if(face[face.length()-1] == '\"') face = face.left(face.length()-1);
887 //kdDebug( 6080 ) << "found face '" << face << "'" << endl;
888 list->append(new CSSPrimitiveValueImpl(DOMString(face), CSSPrimitiveValue::CSS_STRING));
890 if(pos2 == -1) break;
892 //kdDebug( 6080 ) << "got " << list->length() << " faces" << endl;
901 case CSS_PROP_FONT_FAMILY:
902 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
904 parsedValue = parseFontFamily();
908 case CSS_PROP_TEXT_DECORATION:
909 case CSS_PROP__KHTML_TEXT_DECORATIONS_IN_EFFECT:
910 // none | [ underline || overline || line-through || blink ] | inherit
911 if (id == CSS_VAL_NONE) {
912 valid_primitive = true;
914 CSSValueListImpl *list = new CSSValueListImpl;
915 bool is_valid = true;
916 while( is_valid && value ) {
917 switch ( value->id ) {
920 case CSS_VAL_UNDERLINE:
921 case CSS_VAL_OVERLINE:
922 case CSS_VAL_LINE_THROUGH:
923 list->append( new CSSPrimitiveValueImpl( value->id ) );
928 value = valueList->next();
930 //kdDebug( 6080 ) << "got " << list->length() << "d decorations" << endl;
931 if(list->length() && is_valid) {
940 case CSS_PROP_TABLE_LAYOUT: // auto | fixed | inherit
941 if ( id == CSS_VAL_AUTO || id == CSS_VAL_FIXED )
942 valid_primitive = true;
945 /* CSS3 properties */
946 case CSS_PROP__KHTML_BINDING:
948 if (id == CSS_VAL_NONE)
949 valid_primitive = true;
951 CSSValueListImpl* values = new CSSValueListImpl();
953 CSSValueImpl* parsedValue = 0;
954 while ((val = valueList->current())) {
955 if (val->unit == CSSPrimitiveValue::CSS_URI) {
956 DOMString value = khtml::parseURL(domString(val->string));
957 parsedValue = new CSSPrimitiveValueImpl(
958 DOMString(KURL(styleElement->baseURL().string(), value.string()).url()),
959 CSSPrimitiveValue::CSS_URI);
963 values->append(parsedValue);
968 if ( values->length() ) {
969 addProperty( propId, values, important );
978 case CSS_PROP_OUTLINE_OFFSET:
979 valid_primitive = validUnit(value, FLength, strict);
981 case CSS_PROP_TEXT_SHADOW: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
982 if (id == CSS_VAL_NONE)
983 valid_primitive = true;
985 return parseShadow(propId, important);
987 case CSS_PROP_OPACITY:
988 valid_primitive = validUnit(value, FNumber, strict);
990 case CSS_PROP__KHTML_BOX_ALIGN:
991 if (id == CSS_VAL_STRETCH || id == CSS_VAL_START || id == CSS_VAL_END ||
992 id == CSS_VAL_CENTER || id == CSS_VAL_BASELINE)
993 valid_primitive = true;
995 case CSS_PROP__KHTML_BOX_DIRECTION:
996 if (id == CSS_VAL_NORMAL || id == CSS_VAL_REVERSE)
997 valid_primitive = true;
999 case CSS_PROP__KHTML_BOX_LINES:
1000 if (id == CSS_VAL_SINGLE || id == CSS_VAL_MULTIPLE)
1001 valid_primitive = true;
1003 case CSS_PROP__KHTML_BOX_ORIENT:
1004 if (id == CSS_VAL_HORIZONTAL || id == CSS_VAL_VERTICAL ||
1005 id == CSS_VAL_INLINE_AXIS || id == CSS_VAL_BLOCK_AXIS)
1006 valid_primitive = true;
1008 case CSS_PROP__KHTML_BOX_PACK:
1009 if (id == CSS_VAL_START || id == CSS_VAL_END ||
1010 id == CSS_VAL_CENTER || id == CSS_VAL_JUSTIFY)
1011 valid_primitive = true;
1013 case CSS_PROP__KHTML_BOX_FLEX:
1014 valid_primitive = validUnit(value, FNumber, strict);
1016 case CSS_PROP__KHTML_BOX_FLEX_GROUP:
1017 case CSS_PROP__KHTML_BOX_ORDINAL_GROUP:
1018 valid_primitive = validUnit(value, FInteger|FNonNeg, true);
1020 case CSS_PROP__KHTML_MARQUEE: {
1021 const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
1022 CSS_PROP__KHTML_MARQUEE_REPETITION,
1023 CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED };
1024 return parseShortHand(properties, 5, important);
1026 case CSS_PROP__KHTML_MARQUEE_DIRECTION:
1027 if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
1028 id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
1029 id == CSS_VAL_UP || id == CSS_VAL_AUTO)
1030 valid_primitive = true;
1032 case CSS_PROP__KHTML_MARQUEE_INCREMENT:
1033 if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
1034 valid_primitive = true;
1036 valid_primitive = validUnit(value, FLength|FPercent, strict);
1038 case CSS_PROP__KHTML_MARQUEE_STYLE:
1039 if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE ||
1040 id == CSS_VAL_UNFURL)
1041 valid_primitive = true;
1043 case CSS_PROP__KHTML_MARQUEE_REPETITION:
1044 if (id == CSS_VAL_INFINITE)
1045 valid_primitive = true;
1047 valid_primitive = validUnit(value, FInteger|FNonNeg, strict);
1049 case CSS_PROP__KHTML_MARQUEE_SPEED:
1050 if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
1051 valid_primitive = true;
1053 valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict);
1055 case CSS_PROP__KHTML_USER_DRAG: // auto | none | element
1056 if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_ELEMENT)
1057 valid_primitive = true;
1059 case CSS_PROP__KHTML_USER_MODIFY: // read-only | read-write
1060 if (id == CSS_VAL_READ_ONLY || id == CSS_VAL_READ_WRITE)
1061 valid_primitive = true;
1063 case CSS_PROP__KHTML_USER_SELECT: // auto | none | text
1064 if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE || id == CSS_VAL_TEXT)
1065 valid_primitive = true;
1067 case CSS_PROP_TEXT_OVERFLOW: // clip | ellipsis
1068 if (id == CSS_VAL_CLIP || id == CSS_VAL_ELLIPSIS)
1069 valid_primitive = true;
1071 case CSS_PROP__KHTML_MARGIN_COLLAPSE: {
1072 const int properties[2] = { CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE,
1073 CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE };
1074 int num = valueList->numValues;
1076 if (!parseValue(properties[0], important)) return false;
1077 CSSValueImpl* value = parsedProperties[numParsedProperties-1]->value();
1078 addProperty(properties[1], value, important);
1081 else if (num == 2) {
1082 if (!parseValue(properties[0], important)) return false;
1083 if (!parseValue(properties[1], important)) return false;
1088 case CSS_PROP__KHTML_MARGIN_TOP_COLLAPSE:
1089 case CSS_PROP__KHTML_MARGIN_BOTTOM_COLLAPSE:
1090 if (id == CSS_VAL_COLLAPSE || id == CSS_VAL_SEPARATE || id == CSS_VAL_DISCARD)
1091 valid_primitive = true;
1093 case CSS_PROP_TEXT_LINE_THROUGH_MODE:
1094 case CSS_PROP_TEXT_OVERLINE_MODE:
1095 case CSS_PROP_TEXT_UNDERLINE_MODE:
1096 if (id == CSS_VAL_CONTINUOUS || id == CSS_VAL_SKIP_WHITE_SPACE)
1097 valid_primitive = true;
1099 case CSS_PROP_TEXT_LINE_THROUGH_STYLE:
1100 case CSS_PROP_TEXT_OVERLINE_STYLE:
1101 case CSS_PROP_TEXT_UNDERLINE_STYLE:
1102 if (id == CSS_VAL_NONE || id == CSS_VAL_SOLID || id == CSS_VAL_DOUBLE ||
1103 id == CSS_VAL_DASHED || id == CSS_VAL_DOT_DASH || id == CSS_VAL_DOT_DOT_DASH ||
1105 valid_primitive = true;
1107 case CSS_PROP_TEXT_LINE_THROUGH_WIDTH:
1108 case CSS_PROP_TEXT_OVERLINE_WIDTH:
1109 case CSS_PROP_TEXT_UNDERLINE_WIDTH:
1110 if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL || id == CSS_VAL_THIN ||
1111 id == CSS_VAL_MEDIUM || id == CSS_VAL_THICK)
1112 valid_primitive = true;
1114 valid_primitive = !id && validUnit(value, FNumber|FLength|FPercent, strict);
1117 // End of CSS3 properties
1120 // Apple specific properties. These will never be standardized and are purely to
1121 // support custom WebKit-based Apple applications.
1122 case CSS_PROP__KHTML_LINE_CLAMP:
1123 valid_primitive = (!id && validUnit(value, FPercent, false));
1125 case CSS_PROP__KHTML_TEXT_SIZE_ADJUST:
1126 if (id == CSS_VAL_AUTO || id == CSS_VAL_NONE)
1127 valid_primitive = true;
1131 /* shorthand properties */
1132 case CSS_PROP_BACKGROUND:
1133 // ['background-color' || 'background-image' ||'background-repeat' ||
1134 // 'background-attachment' || 'background-position'] | inherit
1135 return parseBackgroundShorthand(important);
1136 case CSS_PROP_BORDER:
1137 // [ 'border-width' || 'border-style' || <color> ] | inherit
1139 const int properties[3] = { CSS_PROP_BORDER_WIDTH, CSS_PROP_BORDER_STYLE,
1140 CSS_PROP_BORDER_COLOR };
1141 return parseShortHand(properties, 3, important);
1143 case CSS_PROP_BORDER_TOP:
1144 // [ 'border-top-width' || 'border-style' || <color> ] | inherit
1146 const int properties[3] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_TOP_STYLE,
1147 CSS_PROP_BORDER_TOP_COLOR};
1148 return parseShortHand(properties, 3, important);
1150 case CSS_PROP_BORDER_RIGHT:
1151 // [ 'border-right-width' || 'border-style' || <color> ] | inherit
1153 const int properties[3] = { CSS_PROP_BORDER_RIGHT_WIDTH, CSS_PROP_BORDER_RIGHT_STYLE,
1154 CSS_PROP_BORDER_RIGHT_COLOR };
1155 return parseShortHand(properties, 3, important);
1157 case CSS_PROP_BORDER_BOTTOM:
1158 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
1160 const int properties[3] = { CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_BOTTOM_STYLE,
1161 CSS_PROP_BORDER_BOTTOM_COLOR };
1162 return parseShortHand(properties, 3, important);
1164 case CSS_PROP_BORDER_LEFT:
1165 // [ 'border-left-width' || 'border-style' || <color> ] | inherit
1167 const int properties[3] = { CSS_PROP_BORDER_LEFT_WIDTH, CSS_PROP_BORDER_LEFT_STYLE,
1168 CSS_PROP_BORDER_LEFT_COLOR };
1169 return parseShortHand(properties, 3, important);
1171 case CSS_PROP_OUTLINE:
1172 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit
1174 const int properties[3] = { CSS_PROP_OUTLINE_WIDTH, CSS_PROP_OUTLINE_STYLE,
1175 CSS_PROP_OUTLINE_COLOR };
1176 return parseShortHand(properties, 3, important);
1178 case CSS_PROP_BORDER_COLOR:
1179 // <color>{1,4} | inherit
1181 const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
1182 CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
1183 return parse4Values(properties, important);
1185 case CSS_PROP_BORDER_WIDTH:
1186 // <border-width>{1,4} | inherit
1188 const int properties[4] = { CSS_PROP_BORDER_TOP_WIDTH, CSS_PROP_BORDER_RIGHT_WIDTH,
1189 CSS_PROP_BORDER_BOTTOM_WIDTH, CSS_PROP_BORDER_LEFT_WIDTH };
1190 return parse4Values(properties, important);
1192 case CSS_PROP_BORDER_STYLE:
1193 // <border-style>{1,4} | inherit
1195 const int properties[4] = { CSS_PROP_BORDER_TOP_STYLE, CSS_PROP_BORDER_RIGHT_STYLE,
1196 CSS_PROP_BORDER_BOTTOM_STYLE, CSS_PROP_BORDER_LEFT_STYLE };
1197 return parse4Values(properties, important);
1199 case CSS_PROP_MARGIN:
1200 // <margin-width>{1,4} | inherit
1202 const int properties[4] = { CSS_PROP_MARGIN_TOP, CSS_PROP_MARGIN_RIGHT,
1203 CSS_PROP_MARGIN_BOTTOM, CSS_PROP_MARGIN_LEFT };
1204 return parse4Values(properties, important);
1206 case CSS_PROP_PADDING:
1207 // <padding-width>{1,4} | inherit
1209 const int properties[4] = { CSS_PROP_PADDING_TOP, CSS_PROP_PADDING_RIGHT,
1210 CSS_PROP_PADDING_BOTTOM, CSS_PROP_PADDING_LEFT };
1211 return parse4Values(properties, important);
1214 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
1215 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
1216 if ( id >= CSS_VAL_CAPTION && id <= CSS_VAL_STATUS_BAR )
1217 valid_primitive = true;
1219 return parseFont(important);
1221 case CSS_PROP_LIST_STYLE:
1223 const int properties[3] = { CSS_PROP_LIST_STYLE_TYPE, CSS_PROP_LIST_STYLE_POSITION,
1224 CSS_PROP_LIST_STYLE_IMAGE };
1225 return parseShortHand(properties, 3, important);
1229 // kdDebug( 6080 ) << "illegal or CSS2 Aural property: " << val << endl;
1234 if ( valid_primitive ) {
1236 // qDebug(" new value: id=%d", id );
1237 parsedValue = new CSSPrimitiveValueImpl( id );
1238 } else if ( value->unit == CSSPrimitiveValue::CSS_STRING )
1239 parsedValue = new CSSPrimitiveValueImpl( domString( value->string ),
1240 (CSSPrimitiveValue::UnitTypes) value->unit );
1241 else if ( value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
1242 value->unit <= CSSPrimitiveValue::CSS_KHZ ) {
1243 // qDebug(" new value: value=%.2f, unit=%d", value->fValue, value->unit );
1244 parsedValue = new CSSPrimitiveValueImpl( value->fValue,
1245 (CSSPrimitiveValue::UnitTypes) value->unit );
1246 } else if ( value->unit >= Value::Q_EMS ) {
1247 // qDebug(" new quirks value: value=%.2f, unit=%d", value->fValue, value->unit );
1248 parsedValue = new CSSQuirkPrimitiveValueImpl( value->fValue, CSSPrimitiveValue::CSS_EMS );
1252 if ( parsedValue ) {
1253 addProperty( propId, parsedValue, important );
1259 void CSSParser::addBackgroundValue(CSSValueImpl*& lval, CSSValueImpl* rval)
1262 if (lval->isValueList())
1263 static_cast<CSSValueListImpl*>(lval)->append(rval);
1265 CSSValueImpl* oldVal = lval;
1266 CSSValueListImpl* list = new CSSValueListImpl();
1268 list->append(oldVal);
1276 bool CSSParser::parseBackgroundShorthand(bool important)
1278 // Position must come before color in this array because a plain old "0" is a legal color
1279 // in quirks mode but it's usually the X coordinate of a position.
1280 const int numProperties = 5;
1281 const int properties[numProperties] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
1282 CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION, CSS_PROP_BACKGROUND_COLOR };
1284 inParseShortHand = true;
1286 bool parsedProperty[numProperties] = { false }; // compiler will repeat false as necessary
1287 CSSValueImpl* values[numProperties] = { 0 }; // compiler will repeat 0 as necessary
1288 CSSValueImpl* positionYValue = 0;
1291 while (valueList->current()) {
1292 Value* val = valueList->current();
1293 if (val->unit == Value::Operator && val->iValue == ',') {
1294 // We hit the end. Fill in all remaining values with the initial value.
1296 for (i = 0; i < numProperties; ++i) {
1297 if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i])
1298 // Color is not allowed except as the last item in a list. Reject the entire
1302 if (!parsedProperty[i] && properties[i] != CSS_PROP_BACKGROUND_COLOR) {
1303 addBackgroundValue(values[i], new CSSInitialValueImpl());
1304 if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1305 addBackgroundValue(positionYValue, new CSSInitialValueImpl());
1307 parsedProperty[i] = false;
1309 if (!valueList->current())
1314 for (i = 0; !found && i < numProperties; ++i) {
1315 if (!parsedProperty[i]) {
1316 CSSValueImpl *val1 = 0, *val2 = 0;
1317 int propId1, propId2;
1318 if (parseBackgroundProperty(properties[i], propId1, propId2, val1, val2)) {
1319 parsedProperty[i] = found = true;
1320 addBackgroundValue(values[i], val1);
1321 if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1322 addBackgroundValue(positionYValue, val2);
1327 // if we didn't find at least one match, this is an
1328 // invalid shorthand and we have to ignore it
1333 // Fill in any remaining properties with the initial value.
1334 for (i = 0; i < numProperties; ++i) {
1335 if (!parsedProperty[i]) {
1336 addBackgroundValue(values[i], new CSSInitialValueImpl());
1337 if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
1338 addBackgroundValue(positionYValue, new CSSInitialValueImpl());
1342 // Now add all of the properties we found.
1343 for (i = 0; i < numProperties; i++) {
1344 if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
1345 addProperty(CSS_PROP_BACKGROUND_POSITION_X, values[i], important);
1346 addProperty(CSS_PROP_BACKGROUND_POSITION_Y, positionYValue, important);
1349 addProperty(properties[i], values[i], important);
1352 inParseShortHand = false;
1356 inParseShortHand = false;
1357 for (int k = 0; k < numProperties; k++)
1359 delete positionYValue;
1363 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important )
1365 /* We try to match as many properties as possible
1366 * We setup an array of booleans to mark which property has been found,
1367 * and we try to search for properties until it makes no longer any sense
1369 inParseShortHand = true;
1372 bool fnd[6]; //Trust me ;)
1373 for( int i = 0; i < numProperties; i++ )
1377 kdDebug(6080) << "PSH: numProperties=" << numProperties << endl;
1380 while ( valueList->current() ) {
1382 // qDebug("outer loop" );
1383 for (int propIndex = 0; !found && propIndex < numProperties; ++propIndex) {
1384 if (!fnd[propIndex]) {
1386 kdDebug(6080) << "LOOKING FOR: " << getPropertyName(properties[propIndex]).string() << endl;
1388 if ( parseValue( properties[propIndex], important ) ) {
1389 fnd[propIndex] = found = true;
1391 kdDebug(6080) << "FOUND: " << getPropertyName(properties[propIndex]).string() << endl;
1396 // if we didn't find at least one match, this is an
1397 // invalid shorthand and we have to ignore it
1400 qDebug("didn't find anything" );
1402 inParseShortHand = false;
1407 // Fill in any remaining properties with the initial value.
1408 for (int i = 0; i < numProperties; ++i) {
1410 addProperty(properties[i], new CSSInitialValueImpl(), important);
1413 inParseShortHand = false;
1415 kdDebug( 6080 ) << "parsed shorthand" << endl;
1420 bool CSSParser::parse4Values( const int *properties, bool important )
1422 /* From the CSS 2 specs, 8.3
1423 * If there is only one value, it applies to all sides. If there are two values, the top and
1424 * bottom margins are set to the first value and the right and left margins are set to the second.
1425 * If there are three values, the top is set to the first value, the left and right are set to the
1426 * second, and the bottom is set to the third. If there are four values, they apply to the top,
1427 * right, bottom, and left, respectively.
1430 int num = inParseShortHand ? 1 : valueList->numValues;
1431 // qDebug("parse4Values: num=%d", num );
1433 // the order is top, right, bottom, left
1436 if( !parseValue( properties[0], important ) ) return false;
1437 CSSValueImpl *value = parsedProperties[numParsedProperties-1]->value();
1438 addProperty( properties[1], value, important );
1439 addProperty( properties[2], value, important );
1440 addProperty( properties[3], value, important );
1445 if( !parseValue( properties[0], important ) ) return false;
1446 if( !parseValue( properties[1], important ) ) return false;
1447 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
1448 addProperty( properties[2], value, important );
1449 value = parsedProperties[numParsedProperties-2]->value();
1450 addProperty( properties[3], value, important );
1454 if( !parseValue( properties[0], important ) ) return false;
1455 if( !parseValue( properties[1], important ) ) return false;
1456 if( !parseValue( properties[2], important ) ) return false;
1457 CSSValueImpl *value = parsedProperties[numParsedProperties-2]->value();
1458 addProperty( properties[3], value, important );
1462 if( !parseValue( properties[0], important ) ) return false;
1463 if( !parseValue( properties[1], important ) ) return false;
1464 if( !parseValue( properties[2], important ) ) return false;
1465 if( !parseValue( properties[3], important ) ) return false;
1473 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1474 // in CSS 2.1 this got somewhat reduced:
1475 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
1476 bool CSSParser::parseContent( int propId, bool important )
1478 CSSValueListImpl* values = new CSSValueListImpl();
1481 CSSValueImpl *parsedValue = 0;
1482 while ( (val = valueList->current()) ) {
1483 if ( val->unit == CSSPrimitiveValue::CSS_URI ) {
1485 DOMString value = khtml::parseURL(domString(val->string));
1486 parsedValue = new CSSImageValueImpl(
1487 DOMString(KURL( styleElement->baseURL().string(), value.string()).url() ), styleElement );
1489 kdDebug( 6080 ) << "content, url=" << value.string() << " base=" << styleElement->baseURL().string() << endl;
1491 } else if ( val->unit == Value::Function ) {
1493 ValueList *args = val->function->args;
1494 QString fname = qString( val->function->name ).lower();
1495 if ( fname != "attr(" || !args )
1497 if ( args->numValues != 1)
1499 Value *a = args->current();
1500 parsedValue = new CSSPrimitiveValueImpl(domString(a->string), CSSPrimitiveValue::CSS_ATTR);
1501 } else if ( val->unit == CSSPrimitiveValue::CSS_IDENT ) {
1506 } else if ( val->unit == CSSPrimitiveValue::CSS_STRING ) {
1507 parsedValue = new CSSPrimitiveValueImpl(domString(val->string), CSSPrimitiveValue::CSS_STRING);
1510 values->append(parsedValue);
1515 if ( values->length() ) {
1516 addProperty( propId, values, important );
1524 CSSValueImpl* CSSParser::parseBackgroundColor()
1526 int id = valueList->current()->id;
1527 if (id == CSS_VAL__KHTML_TEXT || (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
1528 (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict))
1529 return new CSSPrimitiveValueImpl(id);
1530 return parseColor();
1533 CSSValueImpl* CSSParser::parseBackgroundImage()
1535 if (valueList->current()->id == CSS_VAL_NONE)
1536 return new CSSImageValueImpl();
1537 if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
1538 DOMString uri = khtml::parseURL(domString(valueList->current()->string));
1540 return new CSSImageValueImpl(DOMString(KURL(styleElement->baseURL().string(), uri.string()).url()),
1546 CSSValueImpl* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
1548 int id = valueList->current()->id;
1549 if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
1551 if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
1555 if (id == CSS_VAL_RIGHT)
1558 else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
1562 if (id == CSS_VAL_BOTTOM)
1565 else if (id == CSS_VAL_CENTER)
1566 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
1568 return new CSSPrimitiveValueImpl(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
1570 if (validUnit(valueList->current(), FPercent|FLength, strict))
1571 return new CSSPrimitiveValueImpl(valueList->current()->fValue,
1572 (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
1577 void CSSParser::parseBackgroundPosition(CSSValueImpl*& value1, CSSValueImpl*& value2)
1579 value1 = value2 = 0;
1580 Value* value = valueList->current();
1582 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length.
1583 bool value1IsX = false, value1IsY = false;
1584 value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
1588 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
1589 // can assume that any other values belong to the rest of the shorthand). If we're not parsing a shorthand, though, the
1590 // value was explicitly specified for our property.
1591 value = valueList->next();
1593 // First check for the comma. If so, we are finished parsing this value or value pair.
1594 if (value && value->unit == Value::Operator && value->iValue == ',')
1597 bool value2IsX = false, value2IsY = false;
1599 value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
1603 if (!inParseShortHand) {
1612 // Only one value was specified. If that value was not a keyword, then it sets the x position, and the y position
1613 // is simply 50%. This is our default.
1614 // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
1615 // For left/right/center, the default of 50% in the y is still correct.
1616 value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
1618 if (value1IsY || value2IsX) {
1619 // Swap our two values.
1620 CSSValueImpl* val = value2;
1626 bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2,
1627 CSSValueImpl*& retValue1, CSSValueImpl*& retValue2)
1629 CSSValueListImpl *values = 0, *values2 = 0;
1631 CSSValueImpl *value = 0, *value2 = 0;
1632 bool allowComma = false;
1634 retValue1 = retValue2 = 0;
1637 if (propId == CSS_PROP_BACKGROUND_POSITION) {
1638 propId1 = CSS_PROP_BACKGROUND_POSITION_X;
1639 propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
1642 while ((val = valueList->current())) {
1643 CSSValueImpl *currValue = 0, *currValue2 = 0;
1645 if (val->unit != Value::Operator || val->iValue != ',')
1652 case CSS_PROP_BACKGROUND_ATTACHMENT:
1653 if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
1654 currValue = new CSSPrimitiveValueImpl(val->id);
1658 case CSS_PROP_BACKGROUND_COLOR:
1659 currValue = parseBackgroundColor();
1663 case CSS_PROP_BACKGROUND_IMAGE:
1664 currValue = parseBackgroundImage();
1668 case CSS_PROP_BACKGROUND_POSITION:
1669 parseBackgroundPosition(currValue, currValue2);
1670 // unlike the other functions, parseBackgroundPosition advances the valueList pointer
1672 case CSS_PROP_BACKGROUND_POSITION_X: {
1673 bool xFound = false, yFound = true;
1674 currValue = parseBackgroundPositionXY(xFound, yFound);
1679 case CSS_PROP_BACKGROUND_POSITION_Y: {
1680 bool xFound = true, yFound = false;
1681 currValue = parseBackgroundPositionXY(xFound, yFound);
1686 case CSS_PROP_BACKGROUND_REPEAT:
1687 if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
1688 currValue = new CSSPrimitiveValueImpl(val->id);
1697 if (value && !values) {
1698 values = new CSSValueListImpl();
1699 values->append(value);
1703 if (value2 && !values2) {
1704 values2 = new CSSValueListImpl();
1705 values2->append(value2);
1710 values->append(currValue);
1715 values2->append(currValue2);
1717 value2 = currValue2;
1722 // When parsing the 'background' shorthand property, we let it handle building up the lists for all
1724 if (inParseShortHand)
1728 if (values && values->length()) {
1730 if (values2 && values2->length())
1731 retValue2 = values2;
1741 delete values; delete values2;
1742 delete value; delete value2;
1746 #define DASHBOARD_REGION_NUM_PARAMETERS 6
1747 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS 2
1749 static Value *skipCommaInDashboardRegion (ValueList *args)
1751 if ( args->numValues == (DASHBOARD_REGION_NUM_PARAMETERS*2-1) ||
1752 args->numValues == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
1753 Value *current = args->current();
1754 if (current->unit == Value::Operator && current->iValue == ',' )
1755 return args->next();
1757 return args->current();
1761 bool CSSParser::parseDashboardRegions( int propId, bool important )
1765 Value *value = valueList->current();
1767 if (value->id == CSS_VAL_NONE) {
1768 addProperty( propId, new CSSPrimitiveValueImpl( value->id ), important );
1772 DashboardRegionImpl *firstRegion = new DashboardRegionImpl(), *region = 0;
1776 region = firstRegion;
1779 DashboardRegionImpl *nextRegion = new DashboardRegionImpl();
1780 region->setNext (nextRegion);
1781 region = nextRegion;
1784 if ( value->unit != Value::Function) {
1789 // Commas count as values, so allow:
1790 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
1791 // dashboard-region(label, type, t, r, b, l) or dashboard-region(label type t r b l)
1793 // dashboard-region(label, type) or dashboard-region(label type)
1794 // dashboard-region(label, type) or dashboard-region(label type)
1795 ValueList *args = value->function->args;
1796 int numArgs = value->function->args->numValues;
1797 if ((numArgs != DASHBOARD_REGION_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_NUM_PARAMETERS*2-1)) &&
1798 (numArgs != DASHBOARD_REGION_SHORT_NUM_PARAMETERS && numArgs != (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1))){
1803 QString fname = qString( value->function->name ).lower();
1804 if (fname != "dashboard-region(" ) {
1809 // First arg is a label.
1810 Value *arg = args->current();
1811 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
1816 region->m_label = qString(arg->string);
1818 // Second arg is a type.
1820 arg = skipCommaInDashboardRegion (args);
1821 if (arg->unit != CSSPrimitiveValue::CSS_IDENT) {
1826 QString geometryType = qString(arg->string).lower();
1827 if (geometryType == "circle")
1828 region->m_isCircle = true;
1829 else if (geometryType == "rectangle")
1830 region->m_isRectangle = true;
1836 region->m_geometryType = qString(arg->string);
1838 if (numArgs == DASHBOARD_REGION_SHORT_NUM_PARAMETERS || numArgs == (DASHBOARD_REGION_SHORT_NUM_PARAMETERS*2-1)) {
1839 CSSPrimitiveValueImpl *amount = arg->id == CSS_VAL_AUTO ?
1840 new CSSPrimitiveValueImpl(CSS_VAL_AUTO) :
1841 new CSSPrimitiveValueImpl((double)0, (CSSPrimitiveValue::UnitTypes) arg->unit );
1843 region->setTop( amount );
1844 region->setRight( amount );
1845 region->setBottom( amount );
1846 region->setLeft( amount );
1849 // Next four arguments must be offset numbers
1851 for (i = 0; i < 4; i++) {
1853 arg = skipCommaInDashboardRegion (args);
1855 valid = arg->id == CSS_VAL_AUTO || validUnit( arg, FLength, strict );
1859 CSSPrimitiveValueImpl *amount = arg->id == CSS_VAL_AUTO ?
1860 new CSSPrimitiveValueImpl(CSS_VAL_AUTO) :
1861 new CSSPrimitiveValueImpl(arg->fValue, (CSSPrimitiveValue::UnitTypes) arg->unit );
1864 region->setTop( amount );
1866 region->setRight( amount );
1868 region->setBottom( amount );
1870 region->setLeft( amount );
1874 value = valueList->next();
1878 addProperty( propId, new CSSPrimitiveValueImpl( firstRegion ), important );
1886 bool CSSParser::parseShape( int propId, bool important )
1888 Value *value = valueList->current();
1889 ValueList *args = value->function->args;
1890 QString fname = qString( value->function->name ).lower();
1891 if ( fname != "rect(" || !args )
1894 // rect( t, r, b, l ) || rect( t r b l )
1895 if ( args->numValues != 4 && args->numValues != 7 )
1897 RectImpl *rect = new RectImpl();
1900 Value *a = args->current();
1902 valid = a->id == CSS_VAL_AUTO || validUnit( a, FLength, strict );
1905 CSSPrimitiveValueImpl *length = a->id == CSS_VAL_AUTO ?
1906 new CSSPrimitiveValueImpl(CSS_VAL_AUTO) :
1907 new CSSPrimitiveValueImpl( a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit );
1909 rect->setTop( length );
1911 rect->setRight( length );
1913 rect->setBottom( length );
1915 rect->setLeft( length );
1917 if ( a && args->numValues == 7 ) {
1918 if ( a->unit == Value::Operator && a->iValue == ',' ) {
1928 addProperty( propId, new CSSPrimitiveValueImpl( rect ), important );
1936 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family'
1937 bool CSSParser::parseFont( bool important )
1939 // kdDebug(6080) << "parsing font property current=" << valueList->currentValue << endl;
1941 Value *value = valueList->current();
1942 FontValueImpl *font = new FontValueImpl;
1943 // optional font-style, font-variant and font-weight
1945 // kdDebug( 6080 ) << "got value " << value->id << " / " << (value->unit == CSSPrimitiveValue::CSS_STRING ||
1946 // value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
1950 if ( id == CSS_VAL_NORMAL ) {
1951 // do nothing, it's the inital value for all three
1954 else if ( id == CSS_VAL_INHERIT ) {
1955 // set all non set ones to inherit
1956 // This is not that simple as the inherit could also apply to the following font-size.
1957 // very ahrd to tell without looking ahead.
1960 else if ( id == CSS_VAL_ITALIC || id == CSS_VAL_OBLIQUE ) {
1963 font->style = new CSSPrimitiveValueImpl( id );
1964 } else if ( id == CSS_VAL_SMALL_CAPS ) {
1965 if ( font->variant )
1967 font->variant = new CSSPrimitiveValueImpl( id );
1968 } else if ( id >= CSS_VAL_BOLD && id <= CSS_VAL_LIGHTER ) {
1971 font->weight = new CSSPrimitiveValueImpl( id );
1975 } else if ( !font->weight && validUnit( value, FInteger|FNonNeg, true ) ) {
1976 int weight = (int)value->fValue;
1978 if ( weight == 100 )
1980 else if ( weight == 200 )
1982 else if ( weight == 300 )
1984 else if ( weight == 400 )
1986 else if ( weight == 500 )
1988 else if ( weight == 600 )
1990 else if ( weight == 700 )
1992 else if ( weight == 800 )
1994 else if ( weight == 900 )
1998 font->weight = new CSSPrimitiveValueImpl( val );
2006 value = valueList->next();
2011 // set undefined values to default
2013 font->style = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
2014 if ( !font->variant )
2015 font->variant = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
2016 if ( !font->weight )
2017 font->weight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
2019 // kdDebug( 6080 ) << " got style, variant and weight current=" << valueList->currentValue << endl;
2021 // now a font size _must_ come
2022 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
2023 if ( value->id >= CSS_VAL_XX_SMALL && value->id <= CSS_VAL_LARGER )
2024 font->size = new CSSPrimitiveValueImpl( value->id );
2025 else if ( validUnit( value, FLength|FPercent, strict ) ) {
2026 font->size = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
2028 value = valueList->next();
2029 if ( !font->size || !value )
2032 // kdDebug( 6080 ) << " got size" << endl;
2034 if ( value->unit == Value::Operator && value->iValue == '/' ) {
2036 value = valueList->next();
2039 if ( value->id == CSS_VAL_NORMAL ) {
2040 // default value, nothing to do
2041 } else if ( validUnit( value, FNumber|FLength|FPercent, strict ) ) {
2042 font->lineHeight = new CSSPrimitiveValueImpl( value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit );
2046 value = valueList->next();
2051 if (!font->lineHeight)
2052 font->lineHeight = new CSSPrimitiveValueImpl( CSS_VAL_NORMAL );
2054 // kdDebug( 6080 ) << " got line height current=" << valueList->currentValue << endl;
2055 // font family must come now
2056 font->family = parseFontFamily();
2058 if ( valueList->current() || !font->family )
2060 // kdDebug( 6080 ) << " got family, parsing ok!" << endl;
2062 addProperty( CSS_PROP_FONT, font, important );
2066 // kdDebug(6080) << " -> invalid" << endl;
2071 CSSValueListImpl *CSSParser::parseFontFamily()
2073 // kdDebug( 6080 ) << "CSSParser::parseFontFamily current=" << valueList->currentValue << endl;
2074 CSSValueListImpl *list = new CSSValueListImpl;
2075 Value *value = valueList->current();
2076 FontFamilyValueImpl* currFamily = 0;
2078 // kdDebug( 6080 ) << "got value " << value->id << " / "
2079 // << (value->unit == CSSPrimitiveValue::CSS_STRING ||
2080 // value->unit == CSSPrimitiveValue::CSS_IDENT ? qString( value->string ) : QString::null )
2082 Value* nextValue = valueList->next();
2083 bool nextValBreaksFont = !nextValue ||
2084 (nextValue->unit == Value::Operator && nextValue->iValue == ',');
2085 bool nextValIsFontName = nextValue &&
2086 ((nextValue->id >= CSS_VAL_SERIF && nextValue->id <= CSS_VAL__KHTML_BODY) ||
2087 (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
2089 if (value->id >= CSS_VAL_SERIF && value->id <= CSS_VAL__KHTML_BODY) {
2091 currFamily->parsedFontName += ' ';
2092 currFamily->parsedFontName += qString(value->string);
2094 else if (nextValBreaksFont || !nextValIsFontName)
2095 list->append(new CSSPrimitiveValueImpl(value->id));
2097 list->append(currFamily = new FontFamilyValueImpl(qString(value->string)));
2099 else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
2100 // Strings never share in a family name.
2102 list->append(new FontFamilyValueImpl(qString( value->string)));
2104 else if (value->unit == CSSPrimitiveValue::CSS_IDENT) {
2106 currFamily->parsedFontName += ' ';
2107 currFamily->parsedFontName += qString(value->string);
2109 else if (nextValBreaksFont || !nextValIsFontName)
2110 list->append(new FontFamilyValueImpl(qString( value->string)));
2112 list->append(currFamily = new FontFamilyValueImpl(qString(value->string)));
2115 // kdDebug( 6080 ) << "invalid family part" << endl;
2122 if (nextValBreaksFont) {
2123 value = valueList->next();
2126 else if (nextValIsFontName)
2131 if ( !list->length() ) {
2139 bool CSSParser::parseColor(const QString &name, QRgb& rgb)
2141 int len = name.length();
2149 if ( len == 3 || len == 6 ) {
2150 int val = name.toInt(&ok, 16);
2153 rgb = (0xff << 24) | val;
2156 else if ( len == 3 ) {
2157 // #abc converts to #aabbcc according to the specs
2158 rgb = (0xff << 24) |
2159 (val&0xf00)<<12 | (val&0xf00)<<8 |
2160 (val&0xf0)<<8 | (val&0xf0)<<4 |
2161 (val&0xf)<<4 | (val&0xf);
2167 // try a little harder
2169 tc.setNamedColor(name.lower());
2179 CSSPrimitiveValueImpl *CSSParser::parseColor()
2181 return parseColorFromValue(valueList->current());
2184 CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value* value)
2186 QRgb c = khtml::transparentColor;
2187 if ( !strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
2188 value->fValue >= 0. && value->fValue < 1000000. ) {
2190 str.sprintf( "%06d", (int)(value->fValue+.5) );
2191 if (!CSSParser::parseColor( str, c ))
2193 } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
2194 value->unit == CSSPrimitiveValue::CSS_IDENT ||
2195 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
2196 if (!CSSParser::parseColor( qString( value->string ), c))
2199 else if ( value->unit == Value::Function &&
2200 value->function->args != 0 &&
2201 value->function->args->numValues == 5 /* rgb + two commas */ &&
2202 qString( value->function->name ).lower() == "rgb(" ) {
2203 ValueList *args = value->function->args;
2204 Value *v = args->current();
2205 if ( !validUnit( v, FInteger|FPercent, true ) )
2207 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
2209 if ( v->unit != Value::Operator && v->iValue != ',' )
2212 if ( !validUnit( v, FInteger|FPercent, true ) )
2214 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
2216 if ( v->unit != Value::Operator && v->iValue != ',' )
2219 if ( !validUnit( v, FInteger|FPercent, true ) )
2221 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
2222 r = kMax( 0, kMin( 255, r ) );
2223 g = kMax( 0, kMin( 255, g ) );
2224 b = kMax( 0, kMin( 255, b ) );
2225 c = qRgb( r, g, b );
2227 else if ( value->unit == Value::Function &&
2228 value->function->args != 0 &&
2229 value->function->args->numValues == 7 /* rgba + three commas */ &&
2230 qString( value->function->name ).lower() == "rgba(" ) {
2231 ValueList *args = value->function->args;
2232 Value *v = args->current();
2233 if ( !validUnit( v, FInteger|FPercent, true ) )
2235 int r = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
2237 if ( v->unit != Value::Operator && v->iValue != ',' )
2240 if ( !validUnit( v, FInteger|FPercent, true ) )
2242 int g = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
2244 if ( v->unit != Value::Operator && v->iValue != ',' )
2247 if ( !validUnit( v, FInteger|FPercent, true ) )
2249 int b = (int) ( v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.) );
2251 if ( v->unit != Value::Operator && v->iValue != ',' )
2254 if ( !validUnit( v, FNumber, true ) )
2256 r = kMax( 0, kMin( 255, r ) );
2257 g = kMax( 0, kMin( 255, g ) );
2258 b = kMax( 0, kMin( 255, b ) );
2259 int a = (int)(kMax( 0.0, kMin( 1.0, v->fValue ) ) * 255);
2260 c = qRgba( r, g, b, a );
2265 return new CSSPrimitiveValueImpl(c);
2268 // This class tracks parsing state for shadow values. If it goes out of scope (e.g., due to an early return)
2269 // without the allowBreak bit being set, then it will clean up all of the objects and destroy them.
2270 struct ShadowParseContext {
2271 ShadowParseContext()
2272 :values(0), x(0), y(0), blur(0), color(0),
2273 allowX(true), allowY(false), allowBlur(false), allowColor(true),
2277 ~ShadowParseContext() {
2287 bool allowLength() { return allowX || allowY || allowBlur; }
2289 bool failed() { return allowBreak = false; }
2291 void commitValue() {
2292 // Handle the ,, case gracefully by doing nothing.
2293 if (x || y || blur || color) {
2295 values = new CSSValueListImpl();
2297 // Construct the current shadow value and add it to the list.
2298 values->append(new ShadowValueImpl(x, y, blur, color));
2301 // Now reset for the next shadow value.
2302 x = y = blur = color = 0;
2303 allowX = allowColor = allowBreak = true;
2304 allowY = allowBlur = false;
2307 void commitLength(Value* v) {
2308 CSSPrimitiveValueImpl* val = new CSSPrimitiveValueImpl(v->fValue,
2309 (CSSPrimitiveValue::UnitTypes)v->unit);
2312 allowX = false; allowY = true; allowColor = false; allowBreak = false;
2316 allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
2318 else if (allowBlur) {
2324 void commitColor(CSSPrimitiveValueImpl* val) {
2333 CSSValueListImpl* values;
2334 CSSPrimitiveValueImpl* x;
2335 CSSPrimitiveValueImpl* y;
2336 CSSPrimitiveValueImpl* blur;
2337 CSSPrimitiveValueImpl* color;
2346 bool CSSParser::parseShadow(int propId, bool important)
2348 ShadowParseContext context;
2350 while ((val = valueList->current())) {
2351 // Check for a comma break first.
2352 if (val->unit == Value::Operator) {
2353 if (val->iValue != ',' || !context.allowBreak)
2354 // Other operators aren't legal or we aren't done with the current shadow
2355 // value. Treat as invalid.
2356 return context.failed();
2358 // The value is good. Commit it.
2359 context.commitValue();
2361 // Check to see if we're a length.
2362 else if (validUnit(val, FLength, true)) {
2363 // We required a length and didn't get one. Invalid.
2364 if (!context.allowLength())
2365 return context.failed();
2367 // A length is allowed here. Construct the value and add it.
2368 context.commitLength(val);
2371 // The only other type of value that's ok is a color value.
2372 CSSPrimitiveValueImpl* parsedColor = 0;
2373 bool isColor = (val->id >= CSS_VAL_AQUA && val->id <= CSS_VAL_WINDOWTEXT || val->id == CSS_VAL_MENU ||
2374 (val->id >= CSS_VAL_GREY && val->id <= CSS_VAL__KHTML_TEXT && !strict));
2376 if (!context.allowColor)
2377 return context.failed();
2378 parsedColor = new CSSPrimitiveValueImpl(val->id);
2382 // It's not built-in. Try to parse it as a color.
2383 parsedColor = parseColorFromValue(val);
2385 if (!parsedColor || !context.allowColor)
2386 return context.failed(); // This value is not a color or length and is invalid or
2387 // it is a color, but a color isn't allowed at this point.
2389 context.commitColor(parsedColor);
2395 if (context.allowBreak) {
2396 context.commitValue();
2397 if (context.values->length()) {
2398 addProperty(propId, context.values, important);
2404 return context.failed();
2407 static inline int yyerror( const char *str ) {
2409 kdDebug( 6080 ) << "CSS parse error " << str << endl;
2420 int DOM::CSSParser::lex( void *_yylval ) {
2421 YYSTYPE *yylval = (YYSTYPE *)_yylval;
2424 unsigned short *t = text( &length );
2427 qDebug("CSSTokenizer: got token %d: '%s'", token, token == END ? "" : QString( (QChar *)t, length ).latin1() );
2443 yylval->string.string = t;
2444 yylval->string.length = length;
2480 yylval->val = QString( (QChar *)t, length ).toDouble();
2481 //qDebug("value = %s, converted=%.2f", QString( (QChar *)t, length ).latin1(), yylval->val );
2491 static inline int toHex( char c ) {
2492 if ( '0' <= c && c <= '9' )
2494 if ( 'a' <= c && c <= 'f' )
2495 return c - 'a' + 10;
2496 if ( 'A' <= c && c<= 'F' )
2497 return c - 'A' + 10;
2501 unsigned short *DOM::CSSParser::text(int *length)
2503 unsigned short *start = yytext;
2514 // "url("{w}{string}{w}")"
2515 // "url("{w}{url}{w}")"
2517 // strip "url(" and ")"
2522 (*start == ' ' || *start == '\t' || *start == '\r' ||
2523 *start == '\n' || *start == '\f' ) ) {
2526 if ( *start == '"' || *start == '\'' ) {
2530 (start[l-1] == ' ' || start[l-1] == '\t' || start[l-1] == '\r' ||
2531 start[l-1] == '\n' || start[l-1] == '\f' ) ) {
2534 if ( l && (start[l-1] == '\"' || start[l-1] == '\'' ) )
2542 unsigned short *out = start;
2543 unsigned short *escape = 0;
2545 for ( int i = 0; i < l; i++ ) {
2546 unsigned short *current = start+i;
2547 if ( escape == current - 1 ) {
2548 if ( ( *current >= '0' && *current <= '9' ) ||
2549 ( *current >= 'a' && *current <= 'f' ) ||
2550 ( *current >= 'A' && *current <= 'F' ) )
2552 if ( yyTok == STRING &&
2553 ( *current == '\n' || *current == '\r' || *current == '\f' ) ) {
2554 // ### handle \r\n case
2555 if ( *current != '\r' )
2559 // in all other cases copy the char to output
2565 if ( escape == current - 2 && yyTok == STRING &&
2566 *(current-1) == '\r' && *current == '\n' ) {
2570 if ( escape > current - 7 &&
2571 ( ( *current >= '0' && *current <= '9' ) ||
2572 ( *current >= 'a' && *current <= 'f' ) ||
2573 ( *current >= 'A' && *current <= 'F' ) ) )
2579 while ( escape < current ) {
2580 // qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
2582 uc += toHex( *escape );
2585 // qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
2586 // can't handle chars outside ucs2
2589 *(out++) = (unsigned short)uc;
2591 if ( *current == ' ' ||
2598 if ( !escape && *current == '\\' ) {
2602 *(out++) = *current;
2608 while ( escape < start+l ) {
2609 // qDebug("toHex( %c = %x", (char)*escape, toHex( *escape ) );
2611 uc += toHex( *escape );
2614 // qDebug(" converting escape: string='%s', value=0x%x", QString( (QChar *)e, current-e ).latin1(), uc );
2615 // can't handle chars outside ucs2
2618 *(out++) = (unsigned short)uc;
2621 *length = out - start;
2626 #define YY_DECL int DOM::CSSParser::lex()
2627 #define yyconst const
2628 typedef int yy_state_type;
2629 typedef unsigned int YY_CHAR;
2630 // this line makes sure we treat all Unicode chars correctly.
2631 #define YY_SC_TO_UI(c) (c > 0xff ? 0xff : c)
2632 #define YY_DO_BEFORE_ACTION \
2634 yyleng = (int) (yy_cp - yy_bp); \
2635 yy_hold_char = *yy_cp; \
2638 #define YY_BREAK break;
2639 #define ECHO qDebug( "%s", QString( (QChar *)yytext, yyleng ).latin1() )
2640 #define YY_RULE_SETUP
2642 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
2643 #define yyterminate() yyTok = END; return yyTok
2644 #define YY_FATAL_ERROR(a) qFatal(a)
2645 #define BEGIN yy_start = 1 + 2 *
2648 #include "tokenizer.cpp"