Implement CSS3 support for multiple backgrounds. Also fix a bug with background...
authorhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Nov 2004 01:18:23 +0000 (01:18 +0000)
committerhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Nov 2004 01:18:23 +0000 (01:18 +0000)
happens (from the <body> to the root) for HTML documents.  Fixed background-position to handle a mixture of
keyword and length values.

        Reviewed by darin

        * khtml/css/cssparser.cpp:
        (CSSParser::parseValue):
        (CSSParser::addBackgroundValue):
        (CSSParser::parseBackgroundShorthand):
        (CSSParser::parseBackgroundColor):
        (CSSParser::parseBackgroundImage):
        (CSSParser::parseBackgroundPositionXY):
        (CSSParser::parseBackgroundPosition):
        (CSSParser::parseBackgroundProperty):
        (CSSParser::parseColorFromValue):
        * khtml/css/cssparser.h:
        * khtml/css/cssstyleselector.cpp:
        (khtml::CSSStyleSelector::adjustRenderStyle):
        (khtml::CSSStyleSelector::applyProperty):
        (khtml::CSSStyleSelector::mapBackgroundAttachment):
        (khtml::CSSStyleSelector::mapBackgroundImage):
        (khtml::CSSStyleSelector::mapBackgroundRepeat):
        (khtml::CSSStyleSelector::mapBackgroundXPosition):
        (khtml::CSSStyleSelector::mapBackgroundYPosition):
        * khtml/css/cssstyleselector.h:
        * khtml/rendering/render_box.cpp:
        (RenderBox::paintRootBoxDecorations):
        (RenderBox::paintBoxDecorations):
        (RenderBox::paintBackgrounds):
        (RenderBox::paintBackground):
        (RenderBox::paintBackgroundExtended):
        * khtml/rendering/render_box.h:
        * khtml/rendering/render_form.cpp:
        (RenderFieldset::paintBoxDecorations):
        * khtml/rendering/render_line.cpp:
        (khtml::InlineFlowBox::paintBackgrounds):
        (khtml::InlineFlowBox::paintBackground):
        (khtml::InlineFlowBox::paintBackgroundAndBorder):
        * khtml/rendering/render_line.h:
        * khtml/rendering/render_object.cpp:
        (RenderObject::setStyle):
        (RenderObject::updateBackgroundImages):
        (RenderObject::getVerticalPosition):
        * khtml/rendering/render_object.h:
        (khtml::RenderObject::paintBackgroundExtended):
        * khtml/rendering/render_style.cpp:
        (m_next):
        (BackgroundLayer::BackgroundLayer):
        (BackgroundLayer::~BackgroundLayer):
        (BackgroundLayer::operator=):
        (BackgroundLayer::operator==):
        (BackgroundLayer::fillUnsetProperties):
        (BackgroundLayer::cullEmptyLayers):
        (StyleBackgroundData::StyleBackgroundData):
        (StyleBackgroundData::operator==):
        (RenderStyle::diff):
        (RenderStyle::adjustBackgroundLayers):
        * khtml/rendering/render_style.h:
        (khtml::OutlineValue::operator==):
        (khtml::OutlineValue::operator!=):
        (khtml::BackgroundLayer::backgroundImage):
        (khtml::BackgroundLayer::backgroundXPosition):
        (khtml::BackgroundLayer::backgroundYPosition):
        (khtml::BackgroundLayer::backgroundAttachment):
        (khtml::BackgroundLayer::backgroundRepeat):
        (khtml::BackgroundLayer::next):
        (khtml::BackgroundLayer::isBackgroundImageSet):
        (khtml::BackgroundLayer::isBackgroundXPositionSet):
        (khtml::BackgroundLayer::isBackgroundYPositionSet):
        (khtml::BackgroundLayer::isBackgroundAttachmentSet):
        (khtml::BackgroundLayer::isBackgroundRepeatSet):
        (khtml::BackgroundLayer::setBackgroundImage):
        (khtml::BackgroundLayer::setBackgroundXPosition):
        (khtml::BackgroundLayer::setBackgroundYPosition):
        (khtml::BackgroundLayer::setBackgroundAttachment):
        (khtml::BackgroundLayer::setBackgroundRepeat):
        (khtml::BackgroundLayer::clearBackgroundImage):
        (khtml::BackgroundLayer::clearBackgroundXPosition):
        (khtml::BackgroundLayer::clearBackgroundYPosition):
        (khtml::BackgroundLayer::clearBackgroundAttachment):
        (khtml::BackgroundLayer::clearBackgroundRepeat):
        (khtml::BackgroundLayer::setNext):
        (khtml::BackgroundLayer::operator!=):
        (khtml::BackgroundLayer::containsImage):
        (khtml::BackgroundLayer::hasImage):
        (khtml::BackgroundLayer::hasFixedImage):
        (khtml::RenderStyle::setBitDefaults):
        (khtml::RenderStyle::hasBackground):
        (khtml::RenderStyle::hasFixedBackgroundImage):
        (khtml::RenderStyle::outlineWidth):
        (khtml::RenderStyle::outlineStyle):
        (khtml::RenderStyle::outlineStyleIsAuto):
        (khtml::RenderStyle::outlineColor):
        (khtml::RenderStyle::backgroundColor):
        (khtml::RenderStyle::backgroundImage):
        (khtml::RenderStyle::backgroundRepeat):
        (khtml::RenderStyle::backgroundAttachment):
        (khtml::RenderStyle::backgroundXPosition):
        (khtml::RenderStyle::backgroundYPosition):
        (khtml::RenderStyle::accessBackgroundLayers):
        (khtml::RenderStyle::backgroundLayers):
        (khtml::RenderStyle::outlineOffset):
        (khtml::RenderStyle::resetOutline):
        (khtml::RenderStyle::setBackgroundColor):
        (khtml::RenderStyle::setOutlineWidth):
        (khtml::RenderStyle::setOutlineStyle):
        (khtml::RenderStyle::setOutlineColor):
        (khtml::RenderStyle::clearBackgroundLayers):
        (khtml::RenderStyle::inheritBackgroundLayers):
        (khtml::RenderStyle::setOutlineOffset):
        * khtml/rendering/render_table.cpp:
        (RenderTable::paintBoxDecorations):
        (RenderTableCell::paintBoxDecorations):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@7939 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/khtml/css/cssparser.cpp
WebCore/khtml/css/cssparser.h
WebCore/khtml/css/cssstyleselector.cpp
WebCore/khtml/css/cssstyleselector.h
WebCore/khtml/rendering/render_box.cpp
WebCore/khtml/rendering/render_box.h
WebCore/khtml/rendering/render_form.cpp
WebCore/khtml/rendering/render_line.cpp
WebCore/khtml/rendering/render_line.h
WebCore/khtml/rendering/render_object.cpp
WebCore/khtml/rendering/render_object.h
WebCore/khtml/rendering/render_style.cpp
WebCore/khtml/rendering/render_style.h
WebCore/khtml/rendering/render_table.cpp

index 116831b..57cf1e1 100644 (file)
@@ -1,5 +1,122 @@
 2004-11-04  David Hyatt  <hyatt@apple.com>
 
+       Implement CSS3 support for multiple backgrounds.  Also fix a bug with background propagation so that it only
+       happens (from the <body> to the root) for HTML documents.  Fixed background-position to handle a mixture of
+       keyword and length values.
+
+        Reviewed by darin
+
+        * khtml/css/cssparser.cpp:
+        (CSSParser::parseValue):
+        (CSSParser::addBackgroundValue):
+        (CSSParser::parseBackgroundShorthand):
+        (CSSParser::parseBackgroundColor):
+        (CSSParser::parseBackgroundImage):
+        (CSSParser::parseBackgroundPositionXY):
+        (CSSParser::parseBackgroundPosition):
+        (CSSParser::parseBackgroundProperty):
+        (CSSParser::parseColorFromValue):
+        * khtml/css/cssparser.h:
+        * khtml/css/cssstyleselector.cpp:
+        (khtml::CSSStyleSelector::adjustRenderStyle):
+        (khtml::CSSStyleSelector::applyProperty):
+        (khtml::CSSStyleSelector::mapBackgroundAttachment):
+        (khtml::CSSStyleSelector::mapBackgroundImage):
+        (khtml::CSSStyleSelector::mapBackgroundRepeat):
+        (khtml::CSSStyleSelector::mapBackgroundXPosition):
+        (khtml::CSSStyleSelector::mapBackgroundYPosition):
+        * khtml/css/cssstyleselector.h:
+        * khtml/rendering/render_box.cpp:
+        (RenderBox::paintRootBoxDecorations):
+        (RenderBox::paintBoxDecorations):
+        (RenderBox::paintBackgrounds):
+        (RenderBox::paintBackground):
+        (RenderBox::paintBackgroundExtended):
+        * khtml/rendering/render_box.h:
+        * khtml/rendering/render_form.cpp:
+        (RenderFieldset::paintBoxDecorations):
+        * khtml/rendering/render_line.cpp:
+        (khtml::InlineFlowBox::paintBackgrounds):
+        (khtml::InlineFlowBox::paintBackground):
+        (khtml::InlineFlowBox::paintBackgroundAndBorder):
+        * khtml/rendering/render_line.h:
+        * khtml/rendering/render_object.cpp:
+        (RenderObject::setStyle):
+        (RenderObject::updateBackgroundImages):
+        (RenderObject::getVerticalPosition):
+        * khtml/rendering/render_object.h:
+        (khtml::RenderObject::paintBackgroundExtended):
+        * khtml/rendering/render_style.cpp:
+        (m_next):
+        (BackgroundLayer::BackgroundLayer):
+        (BackgroundLayer::~BackgroundLayer):
+        (BackgroundLayer::operator=):
+        (BackgroundLayer::operator==):
+        (BackgroundLayer::fillUnsetProperties):
+        (BackgroundLayer::cullEmptyLayers):
+        (StyleBackgroundData::StyleBackgroundData):
+        (StyleBackgroundData::operator==):
+        (RenderStyle::diff):
+        (RenderStyle::adjustBackgroundLayers):
+        * khtml/rendering/render_style.h:
+        (khtml::OutlineValue::operator==):
+        (khtml::OutlineValue::operator!=):
+        (khtml::BackgroundLayer::backgroundImage):
+        (khtml::BackgroundLayer::backgroundXPosition):
+        (khtml::BackgroundLayer::backgroundYPosition):
+        (khtml::BackgroundLayer::backgroundAttachment):
+        (khtml::BackgroundLayer::backgroundRepeat):
+        (khtml::BackgroundLayer::next):
+        (khtml::BackgroundLayer::isBackgroundImageSet):
+        (khtml::BackgroundLayer::isBackgroundXPositionSet):
+        (khtml::BackgroundLayer::isBackgroundYPositionSet):
+        (khtml::BackgroundLayer::isBackgroundAttachmentSet):
+        (khtml::BackgroundLayer::isBackgroundRepeatSet):
+        (khtml::BackgroundLayer::setBackgroundImage):
+        (khtml::BackgroundLayer::setBackgroundXPosition):
+        (khtml::BackgroundLayer::setBackgroundYPosition):
+        (khtml::BackgroundLayer::setBackgroundAttachment):
+        (khtml::BackgroundLayer::setBackgroundRepeat):
+        (khtml::BackgroundLayer::clearBackgroundImage):
+        (khtml::BackgroundLayer::clearBackgroundXPosition):
+        (khtml::BackgroundLayer::clearBackgroundYPosition):
+        (khtml::BackgroundLayer::clearBackgroundAttachment):
+        (khtml::BackgroundLayer::clearBackgroundRepeat):
+        (khtml::BackgroundLayer::setNext):
+        (khtml::BackgroundLayer::operator!=):
+        (khtml::BackgroundLayer::containsImage):
+        (khtml::BackgroundLayer::hasImage):
+        (khtml::BackgroundLayer::hasFixedImage):
+        (khtml::RenderStyle::setBitDefaults):
+        (khtml::RenderStyle::hasBackground):
+        (khtml::RenderStyle::hasFixedBackgroundImage):
+        (khtml::RenderStyle::outlineWidth):
+        (khtml::RenderStyle::outlineStyle):
+        (khtml::RenderStyle::outlineStyleIsAuto):
+        (khtml::RenderStyle::outlineColor):
+        (khtml::RenderStyle::backgroundColor):
+        (khtml::RenderStyle::backgroundImage):
+        (khtml::RenderStyle::backgroundRepeat):
+        (khtml::RenderStyle::backgroundAttachment):
+        (khtml::RenderStyle::backgroundXPosition):
+        (khtml::RenderStyle::backgroundYPosition):
+        (khtml::RenderStyle::accessBackgroundLayers):
+        (khtml::RenderStyle::backgroundLayers):
+        (khtml::RenderStyle::outlineOffset):
+        (khtml::RenderStyle::resetOutline):
+        (khtml::RenderStyle::setBackgroundColor):
+        (khtml::RenderStyle::setOutlineWidth):
+        (khtml::RenderStyle::setOutlineStyle):
+        (khtml::RenderStyle::setOutlineColor):
+        (khtml::RenderStyle::clearBackgroundLayers):
+        (khtml::RenderStyle::inheritBackgroundLayers):
+        (khtml::RenderStyle::setOutlineOffset):
+        * khtml/rendering/render_table.cpp:
+        (RenderTable::paintBoxDecorations):
+        (RenderTableCell::paintBoxDecorations):
+
+2004-11-04  David Hyatt  <hyatt@apple.com>
+
        Make sure the text decoder returns empty strings rather than null strings when the utf8 char ptr is non-null.
        Ensures that <a href=""> works with libxml (which returns data in utf-8 buffers).
 
index 4445082..f215a1e 100644 (file)
@@ -634,108 +634,6 @@ bool CSSParser::parseValue( int propId, bool important )
        }
        break;
 
-    case CSS_PROP_BACKGROUND_REPEAT:    // repeat | repeat-x | repeat-y | no-repeat | inherit
-       if ( id >= CSS_VAL_REPEAT && id <= CSS_VAL_NO_REPEAT )
-           valid_primitive = true;
-       break;
-
-    case CSS_PROP_BACKGROUND_ATTACHMENT: // scroll | fixed
-       if ( id == CSS_VAL_SCROLL || id == CSS_VAL_FIXED )
-           valid_primitive = true;
-       break;
-
-    case CSS_PROP_BACKGROUND_POSITION:
-       if ( id ) {
-           /* Problem: center is ambigous
-            * In case of 'center' center defines X and Y coords
-            * In case of 'center top', center defines the Y coord
-            * in case of 'center left', center defines the X coord
-            */
-           int pos[2];
-           pos[0] = -1;
-           pos[1] = -1;
-           bool invalid = false;
-           switch( id ) {
-           case CSS_VAL_TOP:
-               pos[1] = 0;
-               break;
-           case CSS_VAL_BOTTOM:
-               pos[1] = 100;
-               break;
-           case CSS_VAL_LEFT:
-               pos[0] = 0;
-               break;
-           case CSS_VAL_RIGHT:
-               pos[0] = 100;
-               break;
-           case  CSS_VAL_CENTER:
-               break;
-           default:
-               invalid = true;
-           }
-           if ( invalid )
-               break;
-           value = valueList->next();
-           if ( value ) {
-               id = value->id;
-               switch( id ) {
-               case CSS_VAL_TOP:
-                   if ( pos[1] != -1 )
-                       invalid = true;
-                   pos[1] = 0;
-                   break;
-               case CSS_VAL_BOTTOM:
-                   if ( pos[1] != -1 )
-                       invalid = true;
-                   pos[1] = 100;
-                   break;
-               case CSS_VAL_LEFT:
-                   if ( pos[0] != -1 )
-                       invalid = true;
-                   pos[0] = 0;
-                   break;
-               case CSS_VAL_RIGHT:
-                   if ( pos[0] != -1 )
-                       invalid = true;
-                   pos[0] = 100;
-                   break;
-               case  CSS_VAL_CENTER:
-                   break;
-               default:
-                   invalid = true;
-               }
-               if ( !invalid )
-                   value = valueList->next();
-           }
-           if ( pos[0] == -1 )
-               pos[0] = 50;
-           if ( pos[1] == -1 )
-               pos[1] = 50;
-           addProperty( CSS_PROP_BACKGROUND_POSITION_X,
-                        new CSSPrimitiveValueImpl( pos[0], CSSPrimitiveValue::CSS_PERCENTAGE ),
-                        important );
-           addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
-                        new CSSPrimitiveValueImpl( pos[1], CSSPrimitiveValue::CSS_PERCENTAGE ),
-                        important );
-       } else {
-           bool ok = parseValue( CSS_PROP_BACKGROUND_POSITION_X, important );
-           if ( !ok )
-               break;
-           value = valueList->current();
-           if ( value )
-               ok = parseValue( CSS_PROP_BACKGROUND_POSITION_Y, important );
-           if ( !ok )
-               addProperty( CSS_PROP_BACKGROUND_POSITION_Y,
-                            new CSSPrimitiveValueImpl( 50, CSSPrimitiveValue::CSS_PERCENTAGE ),
-                            important );
-       }
-       return true;
-
-    case CSS_PROP_BACKGROUND_POSITION_X:
-    case CSS_PROP_BACKGROUND_POSITION_Y:
-       valid_primitive = validUnit( value, FPercent|FLength, strict );
-       break;
-
     case CSS_PROP_BORDER_SPACING: {
         const int properties[2] = { CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING,
                                     CSS_PROP__KHTML_BORDER_VERTICAL_SPACING };
@@ -774,11 +672,11 @@ bool CSSParser::parseValue( int propId, bool important )
             break;
        }
        /* nobreak */
-    case CSS_PROP_BACKGROUND_COLOR:     // <color> | transparent | inherit
-    case CSS_PROP_BORDER_TOP_COLOR:     // <color> | transparent | inherit
-    case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | transparent | inherit
-    case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | transparent | inherit
-    case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | transparent | inherit
+    case CSS_PROP_BACKGROUND_COLOR:     // <color> | inherit
+    case CSS_PROP_BORDER_TOP_COLOR:     // <color> | inherit
+    case CSS_PROP_BORDER_RIGHT_COLOR:   // <color> | inherit
+    case CSS_PROP_BORDER_BOTTOM_COLOR:  // <color> | inherit
+    case CSS_PROP_BORDER_LEFT_COLOR:    // <color> | inherit
     case CSS_PROP_COLOR:                // <color> | inherit
     case CSS_PROP_TEXT_LINE_THROUGH_COLOR: // CSS3 text decoration colors
     case CSS_PROP_TEXT_UNDERLINE_COLOR:
@@ -808,29 +706,37 @@ bool CSSParser::parseValue( int propId, bool important )
            valid_primitive = true;
        break;
 
-    case CSS_PROP_BACKGROUND_IMAGE:     // <uri> | none | inherit
+    case CSS_PROP_BACKGROUND_ATTACHMENT:
+    case CSS_PROP_BACKGROUND_IMAGE:
+    case CSS_PROP_BACKGROUND_POSITION:
+    case CSS_PROP_BACKGROUND_POSITION_X:
+    case CSS_PROP_BACKGROUND_POSITION_Y:
+    case CSS_PROP_BACKGROUND_REPEAT: {
+        CSSValueImpl *val1 = 0, *val2 = 0;
+        int propId1, propId2;
+        if (parseBackgroundProperty(propId, propId1, propId2, val1, val2)) {
+            addProperty(propId1, val1, important);
+            if (val2)
+                addProperty(propId2, val2, important);
+            return true;
+        }
+        return false;
+    }
     case CSS_PROP_LIST_STYLE_IMAGE:     // <uri> | none | inherit
-
-       if ( id == CSS_VAL_NONE ) {
+        if (id == CSS_VAL_NONE) {
            parsedValue = new CSSImageValueImpl();
-           valueList->next();
-#ifdef CSS_DEBUG
-           kdDebug( 6080 ) << "empty image " << endl;
-#endif
-       } else if ( value->unit == CSSPrimitiveValue::CSS_URI ) {
+            valueList->next();
+        }
+        else if (value->unit == CSSPrimitiveValue::CSS_URI) {
            // ### allow string in non strict mode?
            DOMString uri = khtml::parseURL( domString( value->string ) );
-           if ( !uri.isEmpty() ) {
+           if (!uri.isEmpty()) {
                parsedValue = new CSSImageValueImpl(
                    DOMString(KURL( styleElement->baseURL().string(), uri.string()).url()),
-                   styleElement );
-               valueList->next();
-#ifdef CSS_DEBUG
-               kdDebug( 6080 ) << "image, url=" << uri.string() << " base=" << styleElement->baseURL().string() << endl;
-#endif
+                   styleElement);
            }
        }
-       break;
+        break;
 
     case CSS_PROP_OUTLINE_WIDTH:        // <border-width> | inherit
     case CSS_PROP_BORDER_TOP_WIDTH:     //// <border-width> | inherit
@@ -1226,15 +1132,7 @@ bool CSSParser::parseValue( int propId, bool important )
     case CSS_PROP_BACKGROUND:
        // ['background-color' || 'background-image' ||'background-repeat' ||
        // 'background-attachment' || 'background-position'] | inherit
-    {
-#ifdef CSS_DEBUG_BCKGR
-       kdDebug(6080) << "CSS_PROP_BACKGROUND" << endl;
-#endif
-       const int properties[5] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
-                                   CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_POSITION,
-                                   CSS_PROP_BACKGROUND_COLOR };
-       return parseShortHand(properties, 5, important);
-    }
+       return parseBackgroundShorthand(important);
     case CSS_PROP_BORDER:
        // [ 'border-width' || 'border-style' || <color> ] | inherit
     {
@@ -1278,7 +1176,7 @@ bool CSSParser::parseValue( int propId, bool important )
        return parseShortHand(properties, 3, important);
     }
     case CSS_PROP_BORDER_COLOR:
-       // <color>{1,4} | transparent | inherit
+       // <color>{1,4} | inherit
     {
        const int properties[4] = { CSS_PROP_BORDER_TOP_COLOR, CSS_PROP_BORDER_RIGHT_COLOR,
                                    CSS_PROP_BORDER_BOTTOM_COLOR, CSS_PROP_BORDER_LEFT_COLOR };
@@ -1358,6 +1256,112 @@ bool CSSParser::parseValue( int propId, bool important )
     return false;
 }
 
+void CSSParser::addBackgroundValue(CSSValueImpl*& lval, CSSValueImpl* rval)
+{
+    if (lval) {
+        if (lval->isValueList())
+            static_cast<CSSValueListImpl*>(lval)->append(rval);
+        else {
+            CSSValueImpl* oldVal = lval;
+            CSSValueListImpl* list = new CSSValueListImpl();
+            lval = list;
+            list->append(oldVal);
+            list->append(rval);
+        }
+    }
+    else
+        lval = rval;
+}
+
+bool CSSParser::parseBackgroundShorthand(bool important)
+{
+    const int numProperties = 5;
+    const int numValues = numProperties + 1;
+    const int properties[numProperties] = { CSS_PROP_BACKGROUND_IMAGE, CSS_PROP_BACKGROUND_REPEAT,
+        CSS_PROP_BACKGROUND_ATTACHMENT, CSS_PROP_BACKGROUND_COLOR, CSS_PROP_BACKGROUND_POSITION };
+    
+    inParseShortHand = true;
+    
+    bool found = false;
+    bool parsedProperty[numProperties] = { false }; // C compiler will repeat as necessary
+    CSSValueImpl* values[numValues] = { 0 }; // C compiler will repeat as necessary
+    int i;
+
+    while (valueList->current()) {
+        Value* val = valueList->current();
+        if (val->unit == Value::Operator && val->iValue == ',') {
+            // We hit the end.  Fill in all remaining values with the initial value.
+            valueList->next();
+            for (i = 0; i < numProperties; ++i) {
+                if (properties[i] == CSS_PROP_BACKGROUND_COLOR && parsedProperty[i]) {
+                    // Color is not allowed except as the last item in a list.  Reject the entire
+                    // property.
+                    inParseShortHand = false;
+                    for (int k = 0; k < numValues; k++)
+                        delete values[k];
+                    return false;
+                }
+
+                if (!parsedProperty[i] && properties[i] != CSS_PROP_BACKGROUND_COLOR) {
+                    addBackgroundValue(values[i], new CSSInitialValueImpl());
+                    if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
+                        addBackgroundValue(values[i+1], new CSSInitialValueImpl());
+                }
+                parsedProperty[i] = false;
+            }
+            if (!valueList->current())
+                break;
+        }
+        
+        found = false;
+        for (i = 0; !found && i < numProperties; ++i) {
+            if (!parsedProperty[i]) {
+                CSSValueImpl *val1 = 0, *val2 = 0;
+                int propId1, propId2;
+               if (parseBackgroundProperty(properties[i], propId1, propId2, val1, val2)) {
+                   parsedProperty[i] = found = true;
+                    addBackgroundValue(values[i], val1);
+                    if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
+                        i++;
+                        addBackgroundValue(values[i], val2);
+                    }
+               }
+           }
+       }
+
+        // if we didn't find at least one match, this is an
+        // invalid shorthand and we have to ignore it
+        if (!found) {
+           inParseShortHand = false;
+            for (int k = 0; k < numValues; k++)
+                delete values[k];
+           return false;
+       }
+    }
+    
+    // Fill in any remaining properties with the initial value.
+    for (i = 0; i < numProperties; ++i) {
+        if (!parsedProperty[i]) {
+            addBackgroundValue(values[i], new CSSInitialValueImpl());
+            if (properties[i] == CSS_PROP_BACKGROUND_POSITION)
+                addBackgroundValue(values[i+1], new CSSInitialValueImpl());
+        }
+    }
+    
+    // Now add all of the properties we found.
+    for (i = 0; i < numProperties; i++) {
+        if (properties[i] == CSS_PROP_BACKGROUND_POSITION) {
+            addProperty(CSS_PROP_BACKGROUND_POSITION_X, values[i], important);
+            addProperty(CSS_PROP_BACKGROUND_POSITION_Y, values[i+1], important);
+        }
+        else
+            addProperty(properties[i], values[i], important);
+    }
+    
+    inParseShortHand = false;
+    return true;
+}
+
 bool CSSParser::parseShortHand( const int *properties, int numProperties, bool important )
 {
     /* We try to match as many properties as possible
@@ -1519,6 +1523,228 @@ bool CSSParser::parseContent( int propId, bool important )
     return false;
 }
 
+CSSValueImpl* CSSParser::parseBackgroundColor()
+{
+    int id = valueList->current()->id;
+    if (id == CSS_VAL__KHTML_TEXT || (id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) || id == CSS_VAL_MENU ||
+        (id >= CSS_VAL_GREY && id < CSS_VAL__KHTML_TEXT && !strict))
+       return new CSSPrimitiveValueImpl(id);
+    return parseColor();
+}
+
+CSSValueImpl* CSSParser::parseBackgroundImage()
+{
+    if (valueList->current()->id == CSS_VAL_NONE)
+        return new CSSImageValueImpl();
+    if (valueList->current()->unit == CSSPrimitiveValue::CSS_URI) {
+        DOMString uri = khtml::parseURL(domString(valueList->current()->string));
+        if (!uri.isEmpty())
+            return new CSSImageValueImpl(DOMString(KURL(styleElement->baseURL().string(), uri.string()).url()), 
+                                         styleElement);
+    }
+    return 0;
+}
+
+CSSValueImpl* CSSParser::parseBackgroundPositionXY(bool& xFound, bool& yFound)
+{
+    int id = valueList->current()->id;
+    if (id == CSS_VAL_LEFT || id == CSS_VAL_TOP || id == CSS_VAL_RIGHT || id == CSS_VAL_BOTTOM || id == CSS_VAL_CENTER) {
+        int percent = 0;
+        if (id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT) {
+            if (xFound)
+                return 0;
+            xFound = true;
+            if (id == CSS_VAL_RIGHT)
+                percent = 100;
+        }
+        else if (id == CSS_VAL_TOP || id == CSS_VAL_BOTTOM) {
+            if (yFound)
+                return 0;
+            yFound = true;
+            if (id == CSS_VAL_BOTTOM)
+                percent = 100;
+        }
+        else if (id == CSS_VAL_CENTER)
+            // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
+            percent = 50;
+        return new CSSPrimitiveValueImpl(percent, CSSPrimitiveValue::CSS_PERCENTAGE);
+    }
+    if (validUnit(valueList->current(), FPercent|FLength, strict))
+        return new CSSPrimitiveValueImpl(valueList->current()->fValue,
+                                         (CSSPrimitiveValue::UnitTypes)valueList->current()->unit);
+                
+    return 0;
+}
+
+void CSSParser::parseBackgroundPosition(CSSValueImpl*& value1, CSSValueImpl*& value2)
+{
+    value1 = value2 = 0;
+    Value* value = valueList->current();
+    
+    // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
+    bool value1IsX = false, value1IsY = false;
+    value1 = parseBackgroundPositionXY(value1IsX, value1IsY);
+    if (!value1)
+        return;
+    
+    // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
+    // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
+    // value was explicitly specified for our property.
+    value = valueList->next();
+    
+    // First check for the comma.  If so, we are finished parsing this value or value pair.
+    if (value && value->unit == Value::Operator && value->iValue == ',')
+        value = 0;
+    
+    bool value2IsX = false, value2IsY = false;
+    if (value) {
+        value2 = parseBackgroundPositionXY(value2IsX, value2IsY);
+        if (value2)
+            valueList->next();
+        else {
+            if (!inParseShortHand) {
+                delete value1;
+                value1 = 0;
+                return;
+            }
+        }
+    }
+    
+    if (!value2)
+        // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
+        // is simply 50%.  This is our default.
+        // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
+        // For left/right/center, the default of 50% in the y is still correct.
+        value2 = new CSSPrimitiveValueImpl(50, CSSPrimitiveValue::CSS_PERCENTAGE);
+
+    if (value1IsY || value2IsX) {
+        // Swap our two values.
+        CSSValueImpl* val = value2;
+        value2 = value1;
+        value1 = val;
+    }
+}
+
+bool CSSParser::parseBackgroundProperty(int propId, int& propId1, int& propId2, 
+                                        CSSValueImpl*& retValue1, CSSValueImpl*& retValue2)
+{
+    CSSValueListImpl *values = 0, *values2 = 0;
+    Value* val;
+    CSSValueImpl *value = 0, *value2 = 0;
+    bool allowComma = false;
+    
+    retValue1 = retValue2 = 0;
+    propId1 = propId;
+    propId2 = propId;
+    if (propId == CSS_PROP_BACKGROUND_POSITION) {
+        propId1 = CSS_PROP_BACKGROUND_POSITION_X;
+        propId2 = CSS_PROP_BACKGROUND_POSITION_Y;
+    }
+
+    while ((val = valueList->current())) {
+        CSSValueImpl *currValue = 0, *currValue2 = 0;
+        if (allowComma) {
+            if (val->unit != Value::Operator || val->iValue != ',')
+                goto failed;
+            valueList->next();
+            allowComma = false;
+        }
+        else {
+            switch (propId) {
+                case CSS_PROP_BACKGROUND_ATTACHMENT:
+                    if (val->id == CSS_VAL_SCROLL || val->id == CSS_VAL_FIXED) {
+                        currValue = new CSSPrimitiveValueImpl(val->id);
+                        valueList->next();
+                    }
+                    break;
+                case CSS_PROP_BACKGROUND_COLOR:
+                    currValue = parseBackgroundColor();
+                    if (currValue)
+                        valueList->next();
+                    break;
+                case CSS_PROP_BACKGROUND_IMAGE:
+                    currValue = parseBackgroundImage();
+                    if (currValue)
+                        valueList->next();
+                    break;
+                case CSS_PROP_BACKGROUND_POSITION:
+                    parseBackgroundPosition(currValue, currValue2);
+                    // unlike the other functions, parseBackgroundPosition advances the valueList pointer
+                    break;
+                case CSS_PROP_BACKGROUND_POSITION_X: {
+                    bool xFound = false, yFound = true;
+                    currValue = parseBackgroundPositionXY(xFound, yFound);
+                    if (currValue)
+                        valueList->next();
+                    break;
+                }
+                case CSS_PROP_BACKGROUND_POSITION_Y: {
+                    bool xFound = true, yFound = false;
+                    currValue = parseBackgroundPositionXY(xFound, yFound);
+                    if (currValue)
+                        valueList->next();
+                    break;
+                }
+                case CSS_PROP_BACKGROUND_REPEAT:
+                    if (val->id >= CSS_VAL_REPEAT && val->id <= CSS_VAL_NO_REPEAT) {
+                        currValue = new CSSPrimitiveValueImpl(val->id);
+                        valueList->next();
+                    }
+                    break;
+            }
+            
+            if (!currValue)
+                goto failed;
+            
+            if (value && !values) {
+                values = new CSSValueListImpl();
+                values->append(value);
+                value = 0;
+            }
+            
+            if (value2 && !values2) {
+                values2 = new CSSValueListImpl();
+                values2->append(value2);
+                value2 = 0;
+            }
+            
+            if (values)
+                values->append(currValue);
+            else
+                value = currValue;
+            if (currValue2) {
+                if (values2)
+                    values2->append(currValue2);
+                else
+                    value2 = currValue2;
+            }
+            allowComma = true;
+        }
+        
+        // When parsing the 'background' shorthand property, we let it handle building up the lists for all
+        // properties.
+        if (inParseShortHand)
+            break;
+    }
+    
+    if (values && values->length()) {
+        retValue1 = values;
+        if (values2 && values2->length())
+            retValue2 = values2;
+        return true;
+    }
+    if (value) {
+        retValue1 = value;
+        retValue2 = value2;
+        return true;
+    }
+
+failed:
+    delete values; delete values2;
+    delete value; delete value2;
+    return false;
+}
+
 #define DASHBOARD_REGION_NUM_PARAMETERS  6
 #define DASHBOARD_REGION_SHORT_NUM_PARAMETERS  2
 
@@ -1966,9 +2192,9 @@ CSSPrimitiveValueImpl *CSSParser::parseColorFromValue(Value* value)
         str.sprintf( "%06d", (int)(value->fValue+.5) );
         if (!CSSParser::parseColor( str, c ))
             return 0;
-    } else if ( value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
+    } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR ||
                 value->unit == CSSPrimitiveValue::CSS_IDENT ||
-                value->unit == CSSPrimitiveValue::CSS_DIMENSION ) {
+                (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION)) {
        if (!CSSParser::parseColor( qString( value->string ), c))
             return 0;
     }
index 11e370c..7e9b45b 100644 (file)
@@ -129,6 +129,17 @@ namespace DOM {
        bool parseShortHand( const int *properties, int numProperties, bool important );
        bool parse4Values( const int *properties, bool important );
        bool parseContent( int propId, bool important );
+
+        CSSValueImpl* parseBackgroundColor();
+        CSSValueImpl* parseBackgroundImage();
+        CSSValueImpl* parseBackgroundPositionXY(bool& xFound, bool& yFound);
+        void parseBackgroundPosition(CSSValueImpl*& value1, CSSValueImpl*& value2);
+        
+        bool parseBackgroundProperty(int propId, int& propId1, int& propId2, CSSValueImpl*& retValue1, CSSValueImpl*& retValue2);
+        bool parseBackgroundShorthand(bool important);
+
+        void addBackgroundValue(CSSValueImpl*& lval, CSSValueImpl* rval);
+        
        bool parseDashboardRegions( int propId, bool important );
        bool parseShape( int propId, bool important );
        bool parseFont(bool important);
index 5c2e70e..9f29649 100644 (file)
@@ -92,6 +92,68 @@ else if (isInitial) \
     return;\
 }
 
+#define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
+if (isInherit) { \
+    BackgroundLayer* currChild = style->accessBackgroundLayers(); \
+    BackgroundLayer* prevChild = 0; \
+    const BackgroundLayer* currParent = parentStyle->backgroundLayers(); \
+    while (currParent && currParent->is##Prop##Set()) { \
+        if (!currChild) { \
+            /* Need to make a new layer.*/ \
+            currChild = new BackgroundLayer(); \
+            prevChild->setNext(currChild); \
+        } \
+        currChild->set##Prop(currParent->prop()); \
+        prevChild = currChild; \
+        currChild = prevChild->next(); \
+        currParent = currParent->next(); \
+    } \
+    \
+    while (currChild) { \
+        /* Reset any remaining layers to not have the property set. */ \
+        currChild->clear##Prop(); \
+        currChild = currChild->next(); \
+    } \
+    return; \
+} \
+if (isInitial) { \
+    BackgroundLayer* currChild = style->accessBackgroundLayers(); \
+    currChild->set##Prop(RenderStyle::initial##Prop()); \
+    for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
+        currChild->clear##Prop(); \
+    return; \
+}
+
+#define HANDLE_BACKGROUND_VALUE(prop, Prop, value) { \
+HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
+if (!value->isPrimitiveValue() && !value->isValueList()) \
+    return; \
+BackgroundLayer* currChild = style->accessBackgroundLayers(); \
+BackgroundLayer* prevChild = 0; \
+if (value->isPrimitiveValue()) { \
+    map##Prop(currChild, value); \
+    currChild = currChild->next(); \
+} \
+else { \
+    /* Walk each value and put it into a layer, creating new layers as needed. */ \
+    CSSValueListImpl* valueList = static_cast<CSSValueListImpl*>(value); \
+    for (unsigned int i = 0; i < valueList->length(); i++) { \
+        if (!currChild) { \
+            /* Need to make a new layer to hold this value */ \
+            currChild = new BackgroundLayer(); \
+            prevChild->setNext(currChild); \
+        } \
+        map##Prop(currChild, valueList->item(i)); \
+        prevChild = currChild; \
+        currChild = currChild->next(); \
+    } \
+} \
+while (currChild) { \
+    /* Reset all remaining layers to not have the property set. */ \
+    currChild->clear##Prop(); \
+    currChild = currChild->next(); \
+} }
+
 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
 if (id == propID) \
 {\
@@ -913,11 +975,14 @@ void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, DOM::ElementImpl *e
         style->setTextDecorationsInEffect(style->textDecoration());
     else
         style->addToTextDecorationsInEffect(style->textDecoration());
-        
+    
+    // Cull out any useless layers and also repeat patterns into additional layers.
+    style->adjustBackgroundLayers();
+
     // Only use slow repaints if we actually have a background image.
     // FIXME: We only need to invalidate the fixed regions when scrolling.  It's total overkill to
     // prevent the entire view from blitting on a scroll.
-    if (!style->backgroundAttachment() && style->backgroundImage() && view)
+    if (style->hasFixedBackgroundImage() && view)
         view->useSlowRepaints();
 }
 
@@ -1720,40 +1785,11 @@ void CSSStyleSelector::applyProperty( int id, DOM::CSSValueImpl *value )
     {
 // ident only properties
     case CSS_PROP_BACKGROUND_ATTACHMENT:
-        HANDLE_INHERIT_AND_INITIAL(backgroundAttachment, BackgroundAttachment)
-        if(!primitiveValue) break;
-        switch (primitiveValue->getIdent()) {
-        case CSS_VAL_FIXED:
-            style->setBackgroundAttachment(false);
-            break;
-        case CSS_VAL_SCROLL:
-            style->setBackgroundAttachment(true);
-            break;
-        default:
-            return;
-        }
+        HANDLE_BACKGROUND_VALUE(backgroundAttachment, BackgroundAttachment, value)
+        break;
     case CSS_PROP_BACKGROUND_REPEAT:
-    {
-        HANDLE_INHERIT_AND_INITIAL(backgroundRepeat, BackgroundRepeat)
-        if(!primitiveValue) return;
-       switch(primitiveValue->getIdent())
-       {
-       case CSS_VAL_REPEAT:
-           style->setBackgroundRepeat( REPEAT );
-           break;
-       case CSS_VAL_REPEAT_X:
-           style->setBackgroundRepeat( REPEAT_X );
-           break;
-       case CSS_VAL_REPEAT_Y:
-           style->setBackgroundRepeat( REPEAT_Y );
-           break;
-       case CSS_VAL_NO_REPEAT:
-           style->setBackgroundRepeat( NO_REPEAT );
-           break;
-       default:
-           return;
-       }
-    }
+        HANDLE_BACKGROUND_VALUE(backgroundRepeat, BackgroundRepeat, value)
+        break;
     case CSS_PROP_BORDER_COLLAPSE:
         HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
         if(!primitiveValue) break;
@@ -2225,41 +2261,15 @@ void CSSStyleSelector::applyProperty( int id, DOM::CSSValueImpl *value )
         break;
 
     case CSS_PROP_BACKGROUND_POSITION:
-        if (isInherit) {
-            style->setBackgroundXPosition(parentStyle->backgroundXPosition());
-            style->setBackgroundYPosition(parentStyle->backgroundYPosition());
-        }
-        else if (isInitial) {
-            style->setBackgroundXPosition(RenderStyle::initialBackgroundXPosition());
-            style->setBackgroundYPosition(RenderStyle::initialBackgroundYPosition());
-        }
+        HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition);
+        HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition);
         break;
     case CSS_PROP_BACKGROUND_POSITION_X: {
-        HANDLE_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition)
-        if(!primitiveValue) break;
-        Length l;
-        int type = primitiveValue->primitiveType();
-        if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
-        l = Length(primitiveValue->computeLength(style, paintDeviceMetrics), Fixed);
-        else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
-        l = Length((int)primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
-        else
-        return;
-        style->setBackgroundXPosition(l);
+        HANDLE_BACKGROUND_VALUE(backgroundXPosition, BackgroundXPosition, value)
         break;
     }
     case CSS_PROP_BACKGROUND_POSITION_Y: {
-        HANDLE_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition)
-        if(!primitiveValue) break;
-        Length l;
-        int type = primitiveValue->primitiveType();
-        if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
-        l = Length(primitiveValue->computeLength(style, paintDeviceMetrics), Fixed);
-        else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
-        l = Length((int)primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
-        else
-        return;
-        style->setBackgroundYPosition(l);
+        HANDLE_BACKGROUND_VALUE(backgroundYPosition, BackgroundYPosition, value)
         break;
     }
     case CSS_PROP_BORDER_SPACING: {
@@ -2392,14 +2402,8 @@ void CSSStyleSelector::applyProperty( int id, DOM::CSSValueImpl *value )
     break;
 // uri || inherit
     case CSS_PROP_BACKGROUND_IMAGE:
-    {
-        HANDLE_INHERIT_AND_INITIAL(backgroundImage, BackgroundImage)
-       if (!primitiveValue) return;
-       style->setBackgroundImage(static_cast<CSSImageValueImpl *>(primitiveValue)
-                                  ->image(element->getDocument()->docLoader()));
-        //kdDebug( 6080 ) << "setting image in style to " << image->image() << endl;
+        HANDLE_BACKGROUND_VALUE(backgroundImage, BackgroundImage, value)
         break;
-    }
     case CSS_PROP_LIST_STYLE_IMAGE:
     {
         HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
@@ -3187,21 +3191,16 @@ void CSSStyleSelector::applyProperty( int id, DOM::CSSValueImpl *value )
 
 // shorthand properties
     case CSS_PROP_BACKGROUND:
-        if (isInherit) {
-            style->setBackgroundColor(parentStyle->backgroundColor());
-            style->setBackgroundImage(parentStyle->backgroundImage());
-            style->setBackgroundRepeat(parentStyle->backgroundRepeat());
-            style->setBackgroundAttachment(parentStyle->backgroundAttachment());
-            style->setBackgroundXPosition(parentStyle->backgroundXPosition());
-            style->setBackgroundYPosition(parentStyle->backgroundYPosition());
+        if (isInitial) {
+            style->clearBackgroundLayers();
+            return;
         }
-        else if (isInitial) {
-            style->setBackgroundColor(QColor());
-            style->setBackgroundImage(RenderStyle::initialBackgroundImage());
-            style->setBackgroundRepeat(RenderStyle::initialBackgroundRepeat());
-            style->setBackgroundAttachment(RenderStyle::initialBackgroundAttachment());
-            style->setBackgroundXPosition(RenderStyle::initialBackgroundXPosition());
-            style->setBackgroundYPosition(RenderStyle::initialBackgroundYPosition());
+        else if (isInherit) {
+            if (parentStyle)
+                style->inheritBackgroundLayers(*parentStyle->backgroundLayers());
+            else
+                style->clearBackgroundLayers();
+            return;
         }
         break;
     case CSS_PROP_BORDER:
@@ -3826,6 +3825,106 @@ void CSSStyleSelector::applyProperty( int id, DOM::CSSValueImpl *value )
     }
 }
 
+void CSSStyleSelector::mapBackgroundAttachment(BackgroundLayer* layer, DOM::CSSValueImpl* value)
+{
+    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
+        layer->setBackgroundAttachment(RenderStyle::initialBackgroundAttachment());
+        return;
+    }
+
+    if (!value->isPrimitiveValue()) return;
+    CSSPrimitiveValueImpl* primitiveValue = static_cast<CSSPrimitiveValueImpl*>(value);
+    switch (primitiveValue->getIdent()) {
+        case CSS_VAL_FIXED:
+            layer->setBackgroundAttachment(false);
+            break;
+        case CSS_VAL_SCROLL:
+            layer->setBackgroundAttachment(true);
+            break;
+        default:
+            return;
+    }
+}
+
+void CSSStyleSelector::mapBackgroundImage(BackgroundLayer* layer, DOM::CSSValueImpl* value)
+{
+    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
+        layer->setBackgroundImage(RenderStyle::initialBackgroundImage());
+        return;
+    }
+    
+    if (!value->isPrimitiveValue()) return;
+    CSSPrimitiveValueImpl* primitiveValue = static_cast<CSSPrimitiveValueImpl*>(value);
+    layer->setBackgroundImage(static_cast<CSSImageValueImpl *>(primitiveValue)->image(element->getDocument()->docLoader()));
+}
+
+void CSSStyleSelector::mapBackgroundRepeat(BackgroundLayer* layer, DOM::CSSValueImpl* value)
+{
+    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
+        layer->setBackgroundRepeat(RenderStyle::initialBackgroundRepeat());
+        return;
+    }
+    
+    if (!value->isPrimitiveValue()) return;
+    CSSPrimitiveValueImpl* primitiveValue = static_cast<CSSPrimitiveValueImpl*>(value);
+    switch(primitiveValue->getIdent()) {
+       case CSS_VAL_REPEAT:
+           layer->setBackgroundRepeat(REPEAT);
+           break;
+       case CSS_VAL_REPEAT_X:
+           layer->setBackgroundRepeat(REPEAT_X);
+           break;
+       case CSS_VAL_REPEAT_Y:
+           layer->setBackgroundRepeat(REPEAT_Y);
+           break;
+       case CSS_VAL_NO_REPEAT:
+           layer->setBackgroundRepeat(NO_REPEAT);
+           break;
+       default:
+           return;
+    }
+}
+
+void CSSStyleSelector::mapBackgroundXPosition(BackgroundLayer* layer, DOM::CSSValueImpl* value)
+{
+    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
+        layer->setBackgroundXPosition(RenderStyle::initialBackgroundXPosition());
+        return;
+    }
+    
+    if (!value->isPrimitiveValue()) return;
+    CSSPrimitiveValueImpl* primitiveValue = static_cast<CSSPrimitiveValueImpl*>(value);
+    Length l;
+    int type = primitiveValue->primitiveType();
+    if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
+        l = Length(primitiveValue->computeLength(style, paintDeviceMetrics), Fixed);
+    else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
+        l = Length((int)primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
+    else
+        return;
+    layer->setBackgroundXPosition(l);
+}
+
+void CSSStyleSelector::mapBackgroundYPosition(BackgroundLayer* layer, DOM::CSSValueImpl* value)
+{
+    if (value->cssValueType() == CSSValue::CSS_INITIAL) {
+        layer->setBackgroundYPosition(RenderStyle::initialBackgroundYPosition());
+        return;
+    }
+    
+    if (!value->isPrimitiveValue()) return;
+    CSSPrimitiveValueImpl* primitiveValue = static_cast<CSSPrimitiveValueImpl*>(value);
+    Length l;
+    int type = primitiveValue->primitiveType();
+    if(type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
+        l = Length(primitiveValue->computeLength(style, paintDeviceMetrics), Fixed);
+    else if(type == CSSPrimitiveValue::CSS_PERCENTAGE)
+        l = Length((int)primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
+    else
+        return;
+    layer->setBackgroundYPosition(l);
+}
+
 #if APPLE_CHANGES
 void CSSStyleSelector::checkForTextSizeAdjust()
 {
index 4ef9ee6..e235510 100644 (file)
@@ -179,7 +179,13 @@ public:
  
     private:
         void init();
-
+        
+        void mapBackgroundAttachment(BackgroundLayer* layer, DOM::CSSValueImpl* value);
+        void mapBackgroundImage(BackgroundLayer* layer, DOM::CSSValueImpl* value);
+        void mapBackgroundRepeat(BackgroundLayer* layer, DOM::CSSValueImpl* value);
+        void mapBackgroundXPosition(BackgroundLayer* layer, DOM::CSSValueImpl* value);
+        void mapBackgroundYPosition(BackgroundLayer* layer, DOM::CSSValueImpl* value);
+        
     protected:
         // We collect the set of decls that match in |m_matchedDecls|.  We then walk the
         // set of matched decls four times, once for those properties that others depend on (like font-size),
index a6d2437..f1cd636 100644 (file)
@@ -37,6 +37,8 @@
 #include "misc/htmlhashes.h"
 #include "xml/dom_nodeimpl.h"
 #include "xml/dom_docimpl.h"
+#include "html/html_elementimpl.h"
+
 #include "render_line.h"
 
 #include <khtmlview.h>
@@ -213,49 +215,21 @@ void RenderBox::paint(PaintInfo& i, int _tx, int _ty)
 void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
 {
     //kdDebug( 6040 ) << renderName() << "::paintBoxDecorations()" << _tx << "/" << _ty << endl;
-    QColor c = style()->backgroundColor();
-    CachedImage *bg = style()->backgroundImage();
-
-    bool canBeTransparent = true;
-    if (!c.isValid() && !bg) {
+    const BackgroundLayer* bgLayer = style()->backgroundLayers();
+    QColor bgColor = style()->backgroundColor();
+    if (document()->isHTMLDocument() && !style()->hasBackground()) {
         // Locate the <body> element using the DOM.  This is easier than trying
         // to crawl around a render tree with potential :before/:after content and
         // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
         // render object very easily via the DOM.
-        RenderObject* bodyObject = 0;
-        for (DOM::NodeImpl* elt = element()->firstChild(); elt; elt = elt->nextSibling()) {
-            if (elt->id() == ID_BODY) {
-                bodyObject = elt->renderer();
-                break;
-            }
-            else if (elt->id() == ID_FRAMESET) {
-                canBeTransparent = false; // Can't scroll a frameset document anyway.
-                break;
-            }
-        }
-
+        HTMLElementImpl* body = document()->body();
+        RenderObject* bodyObject = (body && body->id() == ID_BODY) ? body->renderer() : 0;
         if (bodyObject) {
-            c = bodyObject->style()->backgroundColor();
-            bg = bodyObject->style()->backgroundImage();
+            bgLayer = bodyObject->style()->backgroundLayers();
+            bgColor = bodyObject->style()->backgroundColor();
         }
     }
 
-    // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
-    // no background in the child document should show the parent's background.
-    if ((!c.isValid() || qAlpha(c.rgb()) == 0) && canvas()->view()) {
-        bool isTransparent;
-        DOM::NodeImpl* elt = element()->getDocument()->ownerElement();
-        if (elt)
-            isTransparent = canBeTransparent && elt->id() != ID_FRAME; // Frames are never transparent.
-        else
-            isTransparent = canvas()->view()->isTransparent();
-
-        if (isTransparent)
-            canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
-        else
-            c = canvas()->view()->palette().active().color(QColorGroup::Base);
-    }
-    
     int w = width();
     int h = height();
 
@@ -284,7 +258,7 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty)
     // I just love these little inconsistencies .. :-( (Dirk)
     int my = kMax(by, i.r.y());
 
-    paintBackground(i.p, c, bg, my, i.r.height(), bx, by, bw, bh);
+    paintBackgrounds(i.p, bgColor, bgLayer, my, i.r.height(), bx, by, bw, bh);
 
     if (style()->hasBorder() && style()->display() != INLINE)
         paintBorder( i.p, _tx, _ty, w, h, style() );
@@ -313,54 +287,79 @@ void RenderBox::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
     // The <body> only paints its background if the root element has defined a background
     // independent of the body.  Go through the DOM to get to the root element's render object,
     // since the root could be inline and wrapped in an anonymous block.
-    if (!isBody()
-        || element()->getDocument()->documentElement()->renderer()->style()->backgroundColor().isValid()
-        || element()->getDocument()->documentElement()->renderer()->style()->backgroundImage())
-        paintBackground(i.p, style()->backgroundColor(), style()->backgroundImage(), my, mh, _tx, _ty, w, h);
+    if (!isBody() || !document()->isHTMLDocument() || document()->documentElement()->renderer()->style()->hasBackground())
+        paintBackgrounds(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
    
     if (style()->hasBorder())
         paintBorder(i.p, _tx, _ty, w, h, style());
 }
 
-void RenderBox::paintBackground(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph, int _tx, int _ty, int w, int height)
+void RenderBox::paintBackgrounds(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
 {
-    paintBackgroundExtended(p, c, bg, clipy, cliph, _tx, _ty, w, height,
+    if (!bgLayer) return;
+    paintBackgrounds(p, c, bgLayer->next(), clipy, cliph, _tx, _ty, w, height);
+    paintBackground(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height);
+}
+
+void RenderBox::paintBackground(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int height)
+{
+    paintBackgroundExtended(p, c, bgLayer, clipy, cliph, _tx, _ty, w, height,
                             borderLeft(), borderRight());
 }
 
-void RenderBox::paintBackgroundExtended(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph,
+void RenderBox::paintBackgroundExtended(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
                                         int _tx, int _ty, int w, int h,
                                         int bleft, int bright)
 {
-    if (c.isValid() && qAlpha(c.rgb()) > 0) {
+    CachedImage* bg = bgLayer->backgroundImage();
+    QColor bgColor = c;
+
+    // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
+    // no background in the child document should show the parent's background.
+    if (!bgLayer->next() && isRoot() && !(bgColor.isValid() && qAlpha(bgColor.rgb()) > 0) && canvas()->view()) {
+        bool isTransparent;
+        DOM::NodeImpl* elt = document()->ownerElement();
+        if (elt) {
+            if (elt->id() == ID_FRAME)
+                isTransparent = false;
+            else {
+                // Locate the <body> element using the DOM.  This is easier than trying
+                // to crawl around a render tree with potential :before/:after content and
+                // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
+                // render object very easily via the DOM.
+                HTMLElementImpl* body = document()->body();
+                isTransparent = !body || body->id() != ID_FRAMESET; // Can't scroll a frameset document anyway.
+            }
+        } else
+            isTransparent = canvas()->view()->isTransparent();
+        
+        if (isTransparent)
+            canvas()->view()->useSlowRepaints(); // The parent must show behind the child.
+        else
+            bgColor = canvas()->view()->palette().active().color(QColorGroup::Base);
+    }
+
+    // Paint the color first underneath all images.
+    if (!bgLayer->next() && bgColor.isValid() && qAlpha(bgColor.rgb()) > 0) {
         // If we have an alpha and we are painting the root element, go ahead and blend with our default
         // background color (typically white).
-        if (qAlpha(c.rgb()) < 0xFF && isRoot() && !canvas()->view()->isTransparent())
+        if (qAlpha(bgColor.rgb()) < 0xFF && isRoot() && !canvas()->view()->isTransparent())
             p->fillRect(_tx, clipy, w, cliph, canvas()->view()->palette().active().color(QColorGroup::Base));
-        p->fillRect(_tx, clipy, w, cliph, c);
+        p->fillRect(_tx, clipy, w, cliph, bgColor);
     }
     
     // no progressive loading of the background image
-    if(bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage()) {
-        //kdDebug( 6040 ) << "painting bgimage at " << _tx << "/" << _ty << endl;
-        // ### might need to add some correct offsets
-        // ### use paddingX/Y
-
-        // for propagation of <body> up to <html>
-        RenderStyle* sptr = style();
-        if ((isRoot() && element() && element()->id() == ID_HTML) && firstChild() && !style()->backgroundImage())
-            sptr = firstChild()->style();
-
+    if (bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage()) {
         int sx = 0;
         int sy = 0;
-           int cw,ch;
+        int cw,ch;
         int cx,cy;
         int vpab = bleft + bright;
         int hpab = borderTop() + borderBottom();
         
         // CSS2 chapter 14.2.1
 
-        if (sptr->backgroundAttachment())
+        if (bgLayer->backgroundAttachment())
         {
             //scroll
             int pw = w - vpab;
@@ -368,10 +367,10 @@ void RenderBox::paintBackgroundExtended(QPainter *p, const QColor &c, CachedImag
             
             int pixw = bg->pixmap_size().width();
             int pixh = bg->pixmap_size().height();
-            EBackgroundRepeat bgr = sptr->backgroundRepeat();
+            EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
             if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && w > pixw ) {
                 cw = pixw;
-                int xPosition = sptr->backgroundXPosition().minWidth(pw-pixw);
+                int xPosition = bgLayer->backgroundXPosition().minWidth(pw-pixw);
                 if (xPosition >= 0)
                     cx = _tx + xPosition;
                 else {
@@ -390,14 +389,14 @@ void RenderBox::paintBackgroundExtended(QPainter *p, const QColor &c, CachedImag
                 if (pixw == 0)
                     sx = 0;
                 else {
-                    sx =  pixw - ((sptr->backgroundXPosition().minWidth(pw-pixw)) % pixw );
+                    sx =  pixw - ((bgLayer->backgroundXPosition().minWidth(pw-pixw)) % pixw );
                     sx -= bleft % pixw;
                 }
             }
 
             if( (bgr == NO_REPEAT || bgr == REPEAT_X) && h > pixh ) {
                 ch = pixh;
-                int yPosition = sptr->backgroundYPosition().minWidth(ph-pixh);
+                int yPosition = bgLayer->backgroundYPosition().minWidth(ph-pixh);
                 if (yPosition >= 0)
                     cy = _ty + yPosition;
                 else {
@@ -417,7 +416,7 @@ void RenderBox::paintBackgroundExtended(QPainter *p, const QColor &c, CachedImag
                 if(pixh == 0){
                     sy = 0;
                 }else{
-                    sy = pixh - ((sptr->backgroundYPosition().minWidth(ph-pixh)) % pixh );
+                    sy = pixh - ((bgLayer->backgroundYPosition().minWidth(ph-pixh)) % pixh );
                     sy -= borderTop() % pixh;
                 }
             }
@@ -431,30 +430,30 @@ void RenderBox::paintBackgroundExtended(QPainter *p, const QColor &c, CachedImag
 
             int pixw = bg->pixmap_size().width();
             int pixh = bg->pixmap_size().height();
-            EBackgroundRepeat bgr = sptr->backgroundRepeat();
+            EBackgroundRepeat bgr = bgLayer->backgroundRepeat();
             if( (bgr == NO_REPEAT || bgr == REPEAT_Y) && pw > pixw ) {
                 cw = pixw;
-                cx = vr.x() + sptr->backgroundXPosition().minWidth(pw-pixw);
+                cx = vr.x() + bgLayer->backgroundXPosition().minWidth(pw-pixw);
             } else {
                 cw = pw;
                 cx = vr.x();
                 if(pixw == 0){
                     sx = 0;
                 }else{
-                    sx =  pixw - ((sptr->backgroundXPosition().minWidth(pw-pixw)) % pixw );
+                    sx =  pixw - ((bgLayer->backgroundXPosition().minWidth(pw-pixw)) % pixw );
                 }
             }
 
             if( (bgr == NO_REPEAT || bgr == REPEAT_X) && ph > pixh ) {
                 ch = pixh;
-                cy = vr.y() + sptr->backgroundYPosition().minWidth(ph-pixh);
+                cy = vr.y() + bgLayer->backgroundYPosition().minWidth(ph-pixh);
             } else {
                 ch = ph;
                 cy = vr.y();
                 if(pixh == 0){
                     sy = 0;
                 }else{
-                    sy = pixh - ((sptr->backgroundYPosition().minWidth(ph-pixh)) % pixh );
+                    sy = pixh - ((bgLayer->backgroundYPosition().minWidth(ph-pixh)) % pixh );
                 }
             }
 
index 079cbb3..2dd3100 100644 (file)
@@ -132,7 +132,7 @@ public:
     
     virtual QRect caretRect(int offset, EAffinity affinity = UPSTREAM, int *extraWidthToEndOfLine = 0);
 
-    virtual void paintBackgroundExtended(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph,
+    virtual void paintBackgroundExtended(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
                                          int _tx, int _ty, int w, int height,
                                          int bleft, int bright);
 
@@ -143,7 +143,8 @@ protected:
     virtual void paintBoxDecorations(PaintInfo& i, int _tx, int _ty);
     void paintRootBoxDecorations(PaintInfo& i, int _tx, int _ty);
 
-    void paintBackground(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph, int _tx, int _ty, int w, int h);
+    void paintBackgrounds(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int h);
+    void paintBackground(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph, int _tx, int _ty, int w, int h);
     void outlineBox(QPainter *p, int _tx, int _ty, const char *color = "red");
 
     virtual int borderTopExtra() { return 0; }
index d7aadd0..f30948c 100644 (file)
@@ -779,7 +779,7 @@ void RenderFieldset::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
     int end = kMin(i.r.y() + i.r.height(),  _ty + h);
     int mh = end - my;
 
-    paintBackground(i.p, style()->backgroundColor(), style()->backgroundImage(), my, mh, _tx, _ty, w, h);
+    paintBackground(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
 
     if (style()->hasBorder())
         paintBorderMinusLegend(i.p, _tx, _ty, w, h, style(), legend->xPos(), legend->width());
index abdd38a..dbb07b9 100644 (file)
@@ -695,6 +695,44 @@ void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos)
     }
 }
 
+void InlineFlowBox::paintBackgrounds(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
+                                     int my, int mh, int _tx, int _ty, int w, int h, int xoff)
+{
+    if (!bgLayer)
+        return;
+    paintBackgrounds(p, c, bgLayer->next(), my, mh, _tx, _ty, w, h, xoff);
+    paintBackground(p, c, bgLayer, my, mh, _tx, _ty, w, h, xoff);
+}
+
+void InlineFlowBox::paintBackground(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
+                                    int my, int mh, int _tx, int _ty, int w, int h, int xOffsetOnLine)
+{
+    CachedImage* bg = bgLayer->backgroundImage();
+    bool hasBackgroundImage = bg && (bg->pixmap_size() == bg->valid_rect().size()) &&
+                              !bg->isTransparent() && !bg->isErrorImage();
+    if (!hasBackgroundImage || (!prevLineBox() && !nextLineBox()) || !parent())
+        object()->paintBackgroundExtended(p, c, bgLayer, my, mh, _tx, _ty, w, h, borderLeft(), borderRight());
+    else {
+        // We have a background image that spans multiple lines.
+        // We need to adjust _tx and _ty by the width of all previous lines.
+        // Think of background painting on inlines as though you had one long line, a single continuous
+        // strip.  Even though that strip has been broken up across multiple lines, you still paint it
+        // as though you had one single line.  This means each line has to pick up the background where
+        // the previous line left off.
+        int startX = _tx - xOffsetOnLine;
+        int totalWidth = xOffsetOnLine;
+        for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
+            totalWidth += curr->width();
+        QRect clipRect(_tx, _ty, width(), height());
+        clipRect = p->xForm(clipRect);
+        p->save();
+        p->addClip(clipRect);
+        object()->paintBackgroundExtended(p, c, bgLayer, my, mh, startX, _ty,
+                                          totalWidth, h, borderLeft(), borderRight());
+        p->restore();
+    }
+}
+
 void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty, int xOffsetOnLine)
 {
     // Move x/y to our coordinates.
@@ -718,34 +756,8 @@ void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx
     RenderStyle* styleToUse = object()->style(m_firstLine);
     if ((!parent() && m_firstLine && styleToUse != object()->style()) || 
         (parent() && object()->shouldPaintBackgroundOrBorder())) {
-        CachedImage* bg = styleToUse->backgroundImage();
-        bool hasBackgroundImage = bg && (bg->pixmap_size() == bg->valid_rect().size()) &&
-                                  !bg->isTransparent() && !bg->isErrorImage();
-        if (!hasBackgroundImage || (!prevLineBox() && !nextLineBox()) || !parent())
-            object()->paintBackgroundExtended(p, styleToUse->backgroundColor(),
-                                              bg, my, mh, _tx, _ty, w, h,
-                                              borderLeft(), borderRight());
-        else {
-            // We have a background image that spans multiple lines.
-            // We need to adjust _tx and _ty by the width of all previous lines.
-            // Think of background painting on inlines as though you had one long line, a single continuous
-            // strip.  Even though that strip has been broken up across multiple lines, you still paint it
-            // as though you had one single line.  This means each line has to pick up the background where
-            // the previous line left off.
-            int startX = _tx - xOffsetOnLine;
-            int totalWidth = xOffsetOnLine;
-            for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
-                totalWidth += curr->width();
-            QRect clipRect(_tx, _ty, width(), height());
-            clipRect = p->xForm(clipRect);
-            p->save();
-            p->addClip(clipRect);
-            object()->paintBackgroundExtended(p, object()->style()->backgroundColor(),
-                                              object()->style()->backgroundImage(), my, mh, startX, _ty,
-                                              totalWidth, h,
-                                              borderLeft(), borderRight());
-            p->restore();
-        }
+        QColor c = styleToUse->backgroundColor();
+        paintBackgrounds(p, c, styleToUse->backgroundLayers(), my, mh, _tx, _ty, w, h, xOffsetOnLine);
 
         // :first-line cannot be used to put borders on a line. Always paint borders with our
         // non-first-line style.
index 4840216..5bacc64 100644 (file)
@@ -232,6 +232,10 @@ public:
     virtual void clearTruncation();
     
     virtual void paintBackgroundAndBorder(RenderObject::PaintInfo& i, int _tx, int _ty, int xOffsetOnLine);
+    void paintBackgrounds(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
+                          int my, int mh, int _tx, int _ty, int w, int h, int xoff);
+    void paintBackground(QPainter* p, const QColor& c, const BackgroundLayer* bgLayer,
+                         int my, int mh, int _tx, int _ty, int w, int h, int xoff);
     virtual void paintDecorations(RenderObject::PaintInfo& i, int _tx, int _ty, bool paintedChildren = false);
     
     int marginBorderPaddingLeft();
index 775a0b3..9151c32 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2003 Apple Computer, Inc.
+ * Copyright (C) 2004 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -1585,27 +1585,16 @@ void RenderObject::setStyle(RenderStyle *style)
     RenderStyle *oldStyle = m_style;
     m_style = style;
 
-    CachedImage* ob = 0;
-    CachedImage* nb = 0;
-
-    if (m_style) {
+    updateBackgroundImages(oldStyle);
+    
+    if (m_style)
         m_style->ref();
-        nb = m_style->backgroundImage();
-    }
-    if (oldStyle) {
-        ob = oldStyle->backgroundImage();
+    
+    if (oldStyle)
         oldStyle->deref(renderArena());
-    }
 
-    if (ob != nb) {
-        if (ob) ob->deref(this);
-        if (nb) nb->ref(this);
-    }
+    setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground());
 
-    setShouldPaintBackgroundOrBorder((m_style->backgroundColor().isValid() &&
-                                      qAlpha(m_style->backgroundColor().rgb()) > 0) || 
-                                     m_style->hasBorder() || nb );
-    
     if (affectsParentBlock)
         handleDynamicFloatPositionChange();
     
@@ -1630,6 +1619,21 @@ void RenderObject::setStyleInternal(RenderStyle* st)
         m_style->ref();
 }
 
+void RenderObject::updateBackgroundImages(RenderStyle* oldStyle)
+{
+    // FIXME: This will be slow when a large number of images is used.  Fix by using a dict.
+    const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0;
+    const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0;
+    for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
+        if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage())))
+            currOld->backgroundImage()->deref(this);
+    }
+    for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
+        if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage())))
+            currNew->backgroundImage()->ref(this);
+    }
+}
+
 QRect RenderObject::viewRect() const
 {
     return canvas()->viewRect();
@@ -1983,28 +1987,17 @@ short RenderObject::getVerticalPosition( bool firstLine ) const
         const QFont &f = parent()->font( firstLine );
         int fontsize = f.pixelSize();
     
-        if ( va == SUB )
+        if (va == SUB)
             vpos += fontsize/5 + 1;
-        else if ( va == SUPER )
+        else if (va == SUPER)
             vpos -= fontsize/3 + 1;
-        else if ( va == TEXT_TOP ) {
-//                 qDebug( "got TEXT_TOP vertical pos hint" );
-//                 qDebug( "parent:" );
-//                 qDebug( "CSSLH: %d, CSS_FS: %d, basepos: %d", fontheight, fontsize, parent()->baselinePosition( firstLine ) );
-//                 qDebug( "this:" );
-//                 qDebug( "CSSLH: %d, CSS_FS: %d, basepos: %d", lineHeight( firstLine ), style()->font().pixelSize(), baselinePosition( firstLine ) );
-            vpos += ( baselinePosition( firstLine ) -
-                      parent()->baselinePosition( firstLine, !checkParent ) );
-        } else if ( va == MIDDLE ) {
-#if APPLE_CHANGES
+        else if (va == TEXT_TOP)
+            vpos += baselinePosition( firstLine ) - QFontMetrics(f).ascent();
+        else if (va == MIDDLE)
             vpos += - (int)(QFontMetrics(f).xHeight()/2) - lineHeight( firstLine )/2 + baselinePosition( firstLine );
-#else
-            QRect b = QFontMetrics(f).boundingRect('x');
-            vpos += -b.height()/2 - lineHeight( firstLine )/2 + baselinePosition( firstLine );
-#endif
-        } else if ( va == TEXT_BOTTOM ) {
+        else if (va == TEXT_BOTTOM) {
             vpos += QFontMetrics(f).descent();
-            if ( !isReplaced() )
+            if (!isReplaced())
                 vpos -= fontMetrics(firstLine).descent();
         } else if ( va == BASELINE_MIDDLE )
             vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
index 7b4e146..2a78d4c 100644 (file)
@@ -354,6 +354,8 @@ public:
 
     void scheduleRelayout();
     
+    void updateBackgroundImages(RenderStyle* oldStyle);
+
     virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun=false);
     virtual void dirtyLineBoxes(bool fullLayout, bool isRootLineBox=false);
     
@@ -393,7 +395,7 @@ public:
     // RenderBox implements this.
     virtual void paintBoxDecorations(PaintInfo& i, int _tx, int _ty) {};
 
-    virtual void paintBackgroundExtended(QPainter *p, const QColor &c, CachedImage *bg, int clipy, int cliph,
+    virtual void paintBackgroundExtended(QPainter *p, const QColor& c, const BackgroundLayer* bgLayer, int clipy, int cliph,
                                          int _tx, int _ty, int w, int height,
                                          int bleft, int bright) {};
 
index 809a2cd..de9f077 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the DOM implementation for KDE.
  *
  * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003 Apple Computer, Inc.
+ * Copyright (C) 2004 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -106,29 +106,148 @@ StyleVisualData::StyleVisualData(const StyleVisualData& o )
 {
 }
 
+BackgroundLayer::BackgroundLayer()
+:m_image(RenderStyle::initialBackgroundImage()),
+ m_bgAttachment(RenderStyle::initialBackgroundAttachment()),
+ m_bgRepeat(RenderStyle::initialBackgroundRepeat()),
+ m_next(0)
+{
+    m_imageSet = m_attachmentSet = m_repeatSet = m_xPosSet = m_yPosSet = false;     
+}
 
+BackgroundLayer::BackgroundLayer(const BackgroundLayer& o)
+{
+    m_next = o.m_next ? new BackgroundLayer(*o.m_next) : 0;
+    m_image = o.m_image;
+    m_xPosition = o.m_xPosition;
+    m_yPosition = o.m_yPosition;
+    m_bgAttachment = o.m_bgAttachment;
+    m_bgRepeat = o.m_bgRepeat;
+    m_imageSet = o.m_imageSet;
+    m_attachmentSet = o.m_attachmentSet;
+    m_repeatSet = o.m_repeatSet;
+    m_xPosSet = o.m_xPosSet;
+    m_yPosSet = o.m_yPosSet;
+}
+
+BackgroundLayer::~BackgroundLayer()
+{
+    delete m_next;
+}
 
-StyleBackgroundData::StyleBackgroundData()
-    : image( RenderStyle::initialBackgroundImage() )
+BackgroundLayer& BackgroundLayer::operator=(const BackgroundLayer& o) {
+    if (m_next != o.m_next) {
+        delete m_next;
+        m_next = o.m_next ? new BackgroundLayer(*o.m_next) : 0;
+    }
+    
+    m_image = o.m_image;
+    m_xPosition = o.m_xPosition;
+    m_yPosition = o.m_yPosition;
+    m_bgAttachment = o.m_bgAttachment;
+    m_bgRepeat = o.m_bgRepeat;
+    
+    m_imageSet = o.m_imageSet;
+    m_attachmentSet = o.m_attachmentSet;
+    m_repeatSet = o.m_repeatSet;
+    m_xPosSet = o.m_xPosSet;
+    m_yPosSet = o.m_yPosSet;
+    
+    return *this;
+}
+
+bool BackgroundLayer::operator==(const BackgroundLayer& o) const {
+    return m_image == o.m_image && m_xPosition == o.m_xPosition && m_yPosition == o.m_yPosition &&
+           m_bgAttachment == o.m_bgAttachment && m_bgRepeat == o.m_bgRepeat && 
+           m_imageSet == o.m_imageSet && m_attachmentSet == o.m_attachmentSet && m_repeatSet == o.m_repeatSet &&
+           m_xPosSet == o.m_xPosSet && m_yPosSet == o.m_yPosSet &&
+           ((m_next && o.m_next) ? *m_next == *o.m_next : m_next == o.m_next);
+}
+
+void BackgroundLayer::fillUnsetProperties()
 {
+    BackgroundLayer* curr;
+    for (curr = this; curr && curr->isBackgroundImageSet(); curr = curr->next());
+    if (curr && curr != this) {
+        // We need to fill in the remaining values with the pattern specified.
+        for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+            curr->m_image = pattern->m_image;
+            pattern = pattern->next();
+            if (pattern == curr || !pattern)
+                pattern = this;
+        }
+    }
+    
+    for (curr = this; curr && curr->isBackgroundXPositionSet(); curr = curr->next());
+    if (curr && curr != this) {
+        // We need to fill in the remaining values with the pattern specified.
+        for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+            curr->m_xPosition = pattern->m_xPosition;
+            pattern = pattern->next();
+            if (pattern == curr || !pattern)
+                pattern = this;
+        }
+    }
+    
+    for (curr = this; curr && curr->isBackgroundYPositionSet(); curr = curr->next());
+    if (curr && curr != this) {
+        // We need to fill in the remaining values with the pattern specified.
+        for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+            curr->m_yPosition = pattern->m_yPosition;
+            pattern = pattern->next();
+            if (pattern == curr || !pattern)
+                pattern = this;
+        }
+    }
+    
+    for (curr = this; curr && curr->isBackgroundAttachmentSet(); curr = curr->next());
+    if (curr && curr != this) {
+        // We need to fill in the remaining values with the pattern specified.
+        for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+            curr->m_bgAttachment = pattern->m_bgAttachment;
+            pattern = pattern->next();
+            if (pattern == curr || !pattern)
+                pattern = this;
+        }
+    }
+    
+    for (curr = this; curr && curr->isBackgroundRepeatSet(); curr = curr->next());
+    if (curr && curr != this) {
+        // We need to fill in the remaining values with the pattern specified.
+        for (BackgroundLayer* pattern = this; curr; curr = curr->next()) {
+            curr->m_bgRepeat = pattern->m_bgRepeat;
+            pattern = pattern->next();
+            if (pattern == curr || !pattern)
+                pattern = this;
+        }
+    }
 }
 
-StyleBackgroundData::StyleBackgroundData(const StyleBackgroundData& o )
-    : Shared<StyleBackgroundData>(),
-      color( o.color ), image( o.image ),
-      x_position( o.x_position ), y_position( o.y_position ),
-      outline( o.outline )
+void BackgroundLayer::cullEmptyLayers()
 {
+    BackgroundLayer *next;
+    for (BackgroundLayer *p = this; p; p = next) {
+        next = p->m_next;
+        if (!next->isBackgroundImageSet() &&
+            !next->isBackgroundXPositionSet() && !next->isBackgroundYPositionSet() &&
+            !next->isBackgroundAttachmentSet() && !next->isBackgroundRepeatSet()) {
+            delete next;
+            p->m_next = 0;
+            break;
+        }
+    }
 }
 
+StyleBackgroundData::StyleBackgroundData()
+{}
+
+StyleBackgroundData::StyleBackgroundData(const StyleBackgroundData& o)
+    : Shared<StyleBackgroundData>(), m_background(o.m_background), m_outline(o.m_outline)
+{}
+
 bool StyleBackgroundData::operator==(const StyleBackgroundData& o) const
 {
-    return
-       color == o.color &&
-       image == o.image &&
-       x_position == o.x_position &&
-       y_position == o.y_position &&
-       outline == o.outline;
+    return m_background == o.m_background && m_color == o.m_color && m_outline == o.m_outline;
 }
 
 StyleMarqueeData::StyleMarqueeData()
@@ -677,15 +796,11 @@ RenderStyle::Diff RenderStyle::diff( const RenderStyle *other ) const
     // Repaint:
 //     EVisibility _visibility : 2;
 //     EOverflow _overflow : 4 ;
-//     EBackgroundRepeat _bg_repeat : 2;
-//     bool _bg_attachment : 1;
 //     int _text_decoration : 4;
 //     DataRef<StyleBackgroundData> background;
     if (inherited->color != other->inherited->color ||
         !(inherited_flags._visibility == other->inherited_flags._visibility) ||
         !(noninherited_flags._overflow == other->noninherited_flags._overflow) ||
-        !(noninherited_flags._bg_repeat == other->noninherited_flags._bg_repeat) ||
-        !(noninherited_flags._bg_attachment == other->noninherited_flags._bg_attachment) ||
         !(inherited_flags._text_decorations == other->inherited_flags._text_decorations) ||
         !(inherited_flags._should_correct_text_color == other->inherited_flags._should_correct_text_color) ||
         !(surround->border == other->surround->border) ||
@@ -726,6 +841,17 @@ void RenderStyle::setPaletteColor(QPalette::ColorGroup g, QColorGroup::ColorRole
 
 #endif
 
+void RenderStyle::adjustBackgroundLayers()
+{
+    if (backgroundLayers()->next()) {
+        // First we cull out layers that have no properties set.
+        accessBackgroundLayers()->cullEmptyLayers();
+        
+        // Next we repeat patterns into layers that don't have some properties set.
+        accessBackgroundLayers()->fillUnsetProperties();
+    }
+}
+
 void RenderStyle::setClip( Length top, Length right, Length bottom, Length left )
 {
     StyleVisualData *data = visual.access();
index cd0f62f..0d260b2 100644 (file)
@@ -193,7 +193,6 @@ enum EBorderStyle {
     BNONE, BHIDDEN, INSET, GROOVE, RIDGE, OUTSET, DOTTED, DASHED, SOLID, DOUBLE
 };
 
-
 class BorderValue
 {
 public:
@@ -236,6 +235,16 @@ public:
         _auto = false;
     }
     
+    bool operator==(const OutlineValue& o) const
+    {
+       return width==o.width && style==o.style && color==o.color && _offset == o._offset && _auto == o._auto;
+    }
+    
+    bool operator!=(const OutlineValue& o) const
+    {
+        return !(*this == o);
+    }
+    
     int _offset;
     bool _auto;
 };
@@ -429,7 +438,79 @@ enum EBackgroundRepeat {
     REPEAT, REPEAT_X, REPEAT_Y, NO_REPEAT
 };
 
+struct BackgroundLayer {
+public:
+    BackgroundLayer();
+    ~BackgroundLayer();
+
+    CachedImage* backgroundImage() const { return m_image; }
+    Length backgroundXPosition() const { return m_xPosition; }
+    Length backgroundYPosition() const { return m_yPosition; }
+    bool backgroundAttachment() const { return m_bgAttachment; }
+    EBackgroundRepeat backgroundRepeat() const { return m_bgRepeat; }
+    BackgroundLayer* next() const { return m_next; }
+    BackgroundLayer* next() { return m_next; }
+
+    bool isBackgroundImageSet() const { return m_imageSet; }
+    bool isBackgroundXPositionSet() const { return m_xPosSet; }
+    bool isBackgroundYPositionSet() const { return m_yPosSet; }
+    bool isBackgroundAttachmentSet() const { return m_attachmentSet; }
+    bool isBackgroundRepeatSet() const { return m_repeatSet; }
+
+    void setBackgroundImage(CachedImage* i) { m_image = i; m_imageSet = true; }
+    void setBackgroundXPosition(const Length& l) { m_xPosition = l; m_xPosSet = true; }
+    void setBackgroundYPosition(const Length& l) { m_yPosition = l; m_yPosSet = true; }
+    void setBackgroundAttachment(bool b) { m_bgAttachment = b; m_attachmentSet = true; }
+    void setBackgroundRepeat(EBackgroundRepeat r) { m_bgRepeat = r; m_repeatSet = true; }
+    
+    void clearBackgroundImage() { m_imageSet = false; }
+    void clearBackgroundXPosition() { m_xPosSet = false; }
+    void clearBackgroundYPosition() { m_yPosSet = false; }
+    void clearBackgroundAttachment() { m_attachmentSet = false; }
+    void clearBackgroundRepeat() { m_repeatSet = false; }
+
+    void setNext(BackgroundLayer* n) { if (m_next != n) { delete m_next; m_next = n; } }
+
+    BackgroundLayer& operator=(const BackgroundLayer& o);    
+    BackgroundLayer(const BackgroundLayer& o);
+
+    bool operator==(const BackgroundLayer& o) const;
+    bool operator!=(const BackgroundLayer& o) const {
+        return !(*this == o);
+    }
+
+    bool containsImage(CachedImage* c) const { if (c == m_image) return true; if (m_next) return m_next->containsImage(c); return false; }
+    
+    bool hasImage() const {
+        if (m_image)
+            return true;
+        return m_next ? m_next->hasImage() : false;
+    }
+    bool hasFixedImage() const {
+        if (m_image && !m_bgAttachment)
+            return true;
+        return m_next ? m_next->hasFixedImage() : false;
+    }
+
+    void fillUnsetProperties();
+    void cullEmptyLayers();
+
+    CachedImage* m_image;
+
+    Length m_xPosition;
+    Length m_yPosition;
 
+    bool m_bgAttachment : 1;
+    EBackgroundRepeat m_bgRepeat : 2;
+
+    bool m_imageSet : 1;
+    bool m_attachmentSet : 1;
+    bool m_repeatSet : 1;
+    bool m_xPosSet : 1;
+    bool m_yPosSet : 1;
+
+    BackgroundLayer* m_next;
+};
 
 class StyleBackgroundData : public Shared<StyleBackgroundData>
 {
@@ -443,12 +524,9 @@ public:
        return !(*this == o);
     }
 
-    QColor color;
-    CachedImage *image;
-
-    Length x_position;
-    Length y_position;
-    OutlineValue outline;
+    BackgroundLayer m_background;
+    QColor m_color;
+    OutlineValue m_outline;
 };
 
 //------------------------------------------------
@@ -877,7 +955,6 @@ protected:
         EDisplay _effectiveDisplay : 5;
         EDisplay _originalDisplay : 5;
         EBackgroundRepeat _bg_repeat : 2;
-        bool _bg_attachment : 1;
         EOverflow _overflow : 4 ;
         EVerticalAlign _vertical_align : 4;
         EClear _clear : 2;
@@ -945,8 +1022,6 @@ protected:
         inherited_flags._should_correct_text_color = false;
         
        noninherited_flags._effectiveDisplay = noninherited_flags._originalDisplay = initialDisplay();
-       noninherited_flags._bg_repeat = initialBackgroundRepeat();
-       noninherited_flags._bg_attachment = initialBackgroundAttachment();
        noninherited_flags._overflow = initialOverflow();
        noninherited_flags._vertical_align = initialVerticalAlign();
        noninherited_flags._clear = initialClear();
@@ -993,6 +1068,11 @@ public:
     bool        hasBorder() const { return surround->border.hasBorder(); }
     bool        hasOffset() const { return surround->offset.nonZero(); }
 
+    bool hasBackground() const { if (backgroundColor().isValid() && qAlpha(backgroundColor().rgb()) > 0)
+                                    return true;
+                                 return background->m_background.hasImage(); }
+    bool hasFixedBackgroundImage() const { return background->m_background.hasFixedImage(); }
+
     bool visuallyOrdered() const { return inherited_flags._visuallyOrdered; }
     void setVisuallyOrdered(bool b) {  inherited_flags._visuallyOrdered = b; }
 
@@ -1048,10 +1128,10 @@ public:
     bool borderBottomIsTransparent() const { return surround->border.bottom.isTransparent(); }
     
     unsigned short outlineSize() const { return outlineWidth() + outlineOffset(); }
-    unsigned short outlineWidth() const { if (background->outline.style == BNONE || background->outline.style == BHIDDEN) return 0; return background->outline.width; }
-    EBorderStyle    outlineStyle() const {  return background->outline.style; }
-    bool outlineStyleIsAuto() const { return background->outline._auto; }
-    const QColor &         outlineColor() const {  return background->outline.color; }
+    unsigned short outlineWidth() const { if (background->m_outline.style == BNONE || background->m_outline.style == BHIDDEN) return 0; return background->m_outline.width; }
+    EBorderStyle    outlineStyle() const {  return background->m_outline.style; }
+    bool outlineStyleIsAuto() const { return background->m_outline._auto; }
+    const QColor &         outlineColor() const {  return background->m_outline.color; }
 
     EOverflow overflow() const { return  noninherited_flags._overflow; }
     EVisibility visibility() const { return inherited_flags._visibility; }
@@ -1091,13 +1171,14 @@ public:
 
     EWhiteSpace whiteSpace() const { return inherited_flags._white_space; }
 
-
-    const QColor & backgroundColor() const { return background->color; }
-    CachedImage *backgroundImage() const { return background->image; }
-    EBackgroundRepeat backgroundRepeat() const { return  noninherited_flags._bg_repeat; }
-    bool backgroundAttachment() const { return  noninherited_flags._bg_attachment; }
-    Length backgroundXPosition() const { return background->x_position; }
-    Length backgroundYPosition() const { return background->y_position; }
+    const QColor & backgroundColor() const { return background->m_color; }
+    CachedImage *backgroundImage() const { return background->m_background.m_image; }
+    EBackgroundRepeat backgroundRepeat() const { return background->m_background.m_bgRepeat; }
+    bool backgroundAttachment() const { return background->m_background.m_bgAttachment; }
+    Length backgroundXPosition() const { return background->m_background.m_xPosition; }
+    Length backgroundYPosition() const { return background->m_background.m_yPosition; }
+    BackgroundLayer* accessBackgroundLayers() { return &(background.access()->m_background); }
+    const BackgroundLayer* backgroundLayers() const { return &(background->m_background); }
 
     // returns true for collapsing borders, false for separate borders
     bool borderCollapse() const { return inherited_flags._border_collapse; }
@@ -1138,7 +1219,7 @@ public:
     BindingURI* bindingURIs() const { return css3NonInheritedData->bindingURI; }
 #endif
     int outlineOffset() const { 
-        if (background->outline.style == BNONE || background->outline.style == BHIDDEN) return 0; return background->outline._offset;
+        if (background->m_outline.style == BNONE || background->m_outline.style == BHIDDEN) return 0; return background->m_outline._offset;
     }
     ShadowData* textShadow() const { return css3InheritedData->textShadow; }
     float opacity() const { return css3NonInheritedData->opacity; }
@@ -1214,8 +1295,10 @@ public:
     void resetBorderRight() { SET_VAR(surround, border.right, BorderValue()) }
     void resetBorderBottom() { SET_VAR(surround, border.bottom, BorderValue()) }
     void resetBorderLeft() { SET_VAR(surround, border.left, BorderValue()) }
-    void resetOutline() { SET_VAR(background, outline, OutlineValue()) }
+    void resetOutline() { SET_VAR(background, m_outline, OutlineValue()) }
     
+    void setBackgroundColor(const QColor& v)    { SET_VAR(background, m_color, v) }
+
     void setBorderLeftWidth(unsigned short v)   {  SET_VAR(surround,border.left.width,v) }
     void setBorderLeftStyle(EBorderStyle v)     {  SET_VAR(surround,border.left.style,v) }
     void setBorderLeftColor(const QColor & v)   {  SET_VAR(surround,border.left.color,v) }
@@ -1228,13 +1311,13 @@ public:
     void setBorderBottomWidth(unsigned short v) {  SET_VAR(surround,border.bottom.width,v) }
     void setBorderBottomStyle(EBorderStyle v)   {  SET_VAR(surround,border.bottom.style,v) }
     void setBorderBottomColor(const QColor & v) {  SET_VAR(surround,border.bottom.color,v) }
-    void setOutlineWidth(unsigned short v) {  SET_VAR(background,outline.width,v) }
+    void setOutlineWidth(unsigned short v) {  SET_VAR(background,m_outline.width,v) }
     void setOutlineStyle(EBorderStyle v, bool isAuto = false)   
     {  
-        SET_VAR(background,outline.style,v)
-        SET_VAR(background,outline._auto, isAuto)
+        SET_VAR(background,m_outline.style,v)
+        SET_VAR(background,m_outline._auto, isAuto)
     }
-    void setOutlineColor(const QColor & v) {  SET_VAR(background,outline.color,v) }
+    void setOutlineColor(const QColor & v) {  SET_VAR(background,m_outline.color,v) }
 
     void setOverflow(EOverflow v) {  noninherited_flags._overflow = v; }
     void setVisibility(EVisibility v) { inherited_flags._visibility = v; }
@@ -1278,12 +1361,9 @@ public:
     void setWordSpacing(int v) { SET_VAR(inherited,font.wordSpacing,v) }
     void setLetterSpacing(int v) { SET_VAR(inherited,font.letterSpacing,v) }
 
-    void setBackgroundColor(const QColor & v) {  SET_VAR(background,color,v) }
-    void setBackgroundImage(CachedImage *v) {  SET_VAR(background,image,v) }
-    void setBackgroundRepeat(EBackgroundRepeat v) {  noninherited_flags._bg_repeat = v; }
-    void setBackgroundAttachment(bool scroll) {  noninherited_flags._bg_attachment = scroll; }
-    void setBackgroundXPosition(Length v) {  SET_VAR(background,x_position,v) }
-    void setBackgroundYPosition(Length v) {  SET_VAR(background,y_position,v) }
+    void clearBackgroundLayers() { background.access()->m_background = BackgroundLayer(); }
+    void inheritBackgroundLayers(const BackgroundLayer& parent) { background.access()->m_background = parent; }
+    void adjustBackgroundLayers();
 
     void setBorderCollapse(bool collapse) { inherited_flags._border_collapse = collapse; }
     void setHorizontalBorderSpacing(short v) { SET_VAR(inherited,horizontal_border_spacing,v) }
@@ -1342,7 +1422,7 @@ public:
     }
     void addBindingURI(DOM::DOMStringImpl* uri);
 #endif
-    void setOutlineOffset(unsigned short v) {  SET_VAR(background,outline._offset,v) }
+    void setOutlineOffset(unsigned short v) { SET_VAR(background, m_outline._offset, v) }
     void setTextShadow(ShadowData* val, bool add=false);
     void setOpacity(float f) { SET_VAR(css3NonInheritedData, opacity, f); }
     void setBoxAlign(EBoxAlignment a) { SET_VAR(css3NonInheritedData.access()->flexibleBox, align, a); }
index f49370c..5415606 100644 (file)
@@ -438,7 +438,7 @@ void RenderTable::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
     else
         mh = kMin(i.r.height(), h);
     
-    paintBackground(i.p, style()->backgroundColor(), style()->backgroundImage(), my, mh, _tx, _ty, w, h);
+    paintBackground(i.p, style()->backgroundColor(), style()->backgroundLayers(), my, mh, _tx, _ty, w, h);
     
     if (style()->hasBorder() && !collapseBorders())
         paintBorder(i.p, _tx, _ty, w, h, style());
@@ -2225,22 +2225,24 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
        }
     }
 
+    // FIXME: This code is just plain wrong.  Rows and columns should paint their backgrounds
+    // independent from the cell.
     // ### get offsets right in case the bgimage is inherited.
-    CachedImage *bg = style()->backgroundImage();
-    if ( !bg && parent() )
-        bg = parent()->style()->backgroundImage();
-    if ( !bg && parent() && parent()->parent() )
-        bg = parent()->parent()->style()->backgroundImage();
-    if ( !bg ) {
+    const BackgroundLayer* bgLayer = style()->backgroundLayers();
+    if (!bgLayer->hasImage() && parent())
+        bgLayer = parent()->style()->backgroundLayers();
+    if (!bgLayer->hasImage() && parent() && parent()->parent())
+        bgLayer = parent()->parent()->style()->backgroundLayers();
+    if (!bgLayer->hasImage()) {
        // see if we have a col or colgroup for this
-       RenderTableCol *col = table()->colElement( _col );
-       if ( col ) {
-           bg = col->style()->backgroundImage();
-           if ( !bg ) {
+       RenderTableCol* col = table()->colElement(_col);
+       if (col) {
+           bgLayer = col->style()->backgroundLayers();
+           if (!bgLayer->hasImage()) {
                // try column group
                RenderStyle *style = col->parent()->style();
-               if ( style->display() == TABLE_COLUMN_GROUP )
-                   bg = style->backgroundImage();
+               if (style->display() == TABLE_COLUMN_GROUP)
+                   bgLayer = style->backgroundLayers();
            }
        }
     }
@@ -2249,8 +2251,8 @@ void RenderTableCell::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
     int end = kMin(i.r.y() + i.r.height(), _ty + h);
     int mh = end - my;
 
-    if ( bg || c.isValid() )
-       paintBackground(i.p, c, bg, my, mh, _tx, _ty, w, h);
+    if (bgLayer->hasImage() || c.isValid())
+       paintBackground(i.p, c, bgLayer, my, mh, _tx, _ty, w, h);
 
     if (style()->hasBorder() && !tableElt->collapseBorders())
         paintBorder(i.p, _tx, _ty, w, h, style());