https://bugs.webkit.org/show_bug.cgi?id=68040
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Sep 2011 00:17:09 +0000 (00:17 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Sep 2011 00:17:09 +0000 (00:17 +0000)
Make sure border image sub-properties can be specified in any order.

Reviewed by Beth Dakin.

Source/WebCore:

New tests in fast/borders.

* css/CSSParser.cpp:
(WebCore::BorderImageParseContext::BorderImageParseContext):
(WebCore::BorderImageParseContext::canAdvance):
(WebCore::BorderImageParseContext::setCanAdvance):
(WebCore::BorderImageParseContext::allowCommit):
(WebCore::BorderImageParseContext::allowImage):
(WebCore::BorderImageParseContext::allowImageSlice):
(WebCore::BorderImageParseContext::allowSlash):
(WebCore::BorderImageParseContext::requireWidth):
(WebCore::BorderImageParseContext::requireOutset):
(WebCore::BorderImageParseContext::commitImage):
(WebCore::BorderImageParseContext::commitImageSlice):
(WebCore::BorderImageParseContext::commitSlash):
(WebCore::BorderImageParseContext::commitBorderWidth):
(WebCore::BorderImageParseContext::commitBorderOutset):
(WebCore::BorderImageParseContext::commitRepeat):
(WebCore::CSSParser::parseBorderImage):
(WebCore::CSSParser::parseBorderImageRepeat):
(WebCore::CSSParser::parseBorderImageSlice):
(WebCore::CSSParser::parseBorderImageQuad):
* css/CSSParserValues.h:
(WebCore::CSSParserValueList::previous):

LayoutTests:

* fast/borders/border-image-scrambled.html: Added.
* platform/mac/fast/borders/border-image-scrambled-expected.png: Added.
* platform/mac/fast/borders/border-image-scrambled-expected.txt: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/borders/border-image-scrambled.html [new file with mode: 0644]
LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.txt [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParserValues.h

index df6f72c..00f6c80 100644 (file)
@@ -1,3 +1,15 @@
+2011-09-13  David Hyatt  <hyatt@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=68040
+        
+        Make sure border image sub-properties can be specified in any order.
+
+        Reviewed by Beth Dakin.
+
+        * fast/borders/border-image-scrambled.html: Added.
+        * platform/mac/fast/borders/border-image-scrambled-expected.png: Added.
+        * platform/mac/fast/borders/border-image-scrambled-expected.txt: Added.
+
 2011-09-12  Jon Honeycutt  <jhoneycutt@apple.com>
 
         MSAA: WebKit reports the document state as disabled
diff --git a/LayoutTests/fast/borders/border-image-scrambled.html b/LayoutTests/fast/borders/border-image-scrambled.html
new file mode 100644 (file)
index 0000000..9dca501
--- /dev/null
@@ -0,0 +1,36 @@
+<html>
+<head>
+    <style>
+        div {
+            border-width: 21px 30px 30px 21px;
+            width: 75px;
+            height: 75px;
+            margin: 10px;
+            display: inline-block;
+        }
+
+        div.rr {
+            -webkit-border-image: url("resources/border-image.png") 21 30 30 21 repeat repeat;
+        }
+
+        div.rs {
+            -webkit-border-image: 21 30 30 21 url("resources/border-image.png") repeat stretch;
+        }
+
+        div.sr {
+            -webkit-border-image: stretch repeat 21 30 30 21 url("resources/border-image.png");
+        }
+
+        div.ss {
+            -webkit-border-image: url("resources/border-image.png") stretch stretch 21 30 30 21;
+        }
+    </style>
+</head>
+<body>
+    <div class="rr"></div>
+    <div class="rs"></div>
+    <br>
+    <div class="sr"></div>
+    <div class="ss"></div>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png b/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png
new file mode 100644 (file)
index 0000000..3807c6d
Binary files /dev/null and b/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.png differ
diff --git a/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.txt b/LayoutTests/platform/mac/fast/borders/border-image-scrambled-expected.txt
new file mode 100644 (file)
index 0000000..37927aa
--- /dev/null
@@ -0,0 +1,17 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {DIV} at (10,10) size 126x126 [border: (21px none #000000) (30px none #000000) (21px none #000000)]
+      RenderText {#text} at (146,132) size 4x18
+        text run at (146,132) width 4: " "
+      RenderBlock {DIV} at (160,10) size 126x126 [border: (21px none #000000) (30px none #000000) (21px none #000000)]
+      RenderText {#text} at (296,132) size 4x18
+        text run at (296,132) width 4: " "
+      RenderBR {BR} at (0,0) size 0x0
+      RenderBlock {DIV} at (10,160) size 126x126 [border: (21px none #000000) (30px none #000000) (21px none #000000)]
+      RenderText {#text} at (146,282) size 4x18
+        text run at (146,282) width 4: " "
+      RenderBlock {DIV} at (160,160) size 126x126 [border: (21px none #000000) (30px none #000000) (21px none #000000)]
+      RenderText {#text} at (0,0) size 0x0
index 20ad018..7543828 100644 (file)
@@ -1,3 +1,36 @@
+2011-09-13  David Hyatt  <hyatt@apple.com>
+
+        https://bugs.webkit.org/show_bug.cgi?id=68040
+        
+        Make sure border image sub-properties can be specified in any order.
+
+        Reviewed by Beth Dakin.
+
+        New tests in fast/borders.
+
+        * css/CSSParser.cpp:
+        (WebCore::BorderImageParseContext::BorderImageParseContext):
+        (WebCore::BorderImageParseContext::canAdvance):
+        (WebCore::BorderImageParseContext::setCanAdvance):
+        (WebCore::BorderImageParseContext::allowCommit):
+        (WebCore::BorderImageParseContext::allowImage):
+        (WebCore::BorderImageParseContext::allowImageSlice):
+        (WebCore::BorderImageParseContext::allowSlash):
+        (WebCore::BorderImageParseContext::requireWidth):
+        (WebCore::BorderImageParseContext::requireOutset):
+        (WebCore::BorderImageParseContext::commitImage):
+        (WebCore::BorderImageParseContext::commitImageSlice):
+        (WebCore::BorderImageParseContext::commitSlash):
+        (WebCore::BorderImageParseContext::commitBorderWidth):
+        (WebCore::BorderImageParseContext::commitBorderOutset):
+        (WebCore::BorderImageParseContext::commitRepeat):
+        (WebCore::CSSParser::parseBorderImage):
+        (WebCore::CSSParser::parseBorderImageRepeat):
+        (WebCore::CSSParser::parseBorderImageSlice):
+        (WebCore::CSSParser::parseBorderImageQuad):
+        * css/CSSParserValues.h:
+        (WebCore::CSSParserValueList::previous):
+
 2011-09-13  Jeff Miller  <jeffm@apple.com>
 
         WebCore::Cursor::ensurePlatformCursor() should always set a valid platform cursor on Windows
index e21f7d8..f88b985 100644 (file)
@@ -5158,51 +5158,103 @@ bool CSSParser::parseFlex(int propId, bool important)
 struct BorderImageParseContext {
     BorderImageParseContext(CSSPrimitiveValueCache* primitiveValueCache)
     : m_primitiveValueCache(primitiveValueCache)
-    , m_allowBreak(false)
+    , m_canAdvance(false)
+    , m_allowCommit(true)
+    , m_allowImage(true)
+    , m_allowImageSlice(true)
+    , m_allowRepeat(true)
     , m_allowSlash(false)
-    , m_allowWidth(false)
-    , m_allowOutset(false)
-    , m_allowRepeat(false)
+    , m_requireWidth(false)
+    , m_requireOutset(false)    
     {}
 
-    bool allowBreak() const { return m_allowBreak; }
-    bool allowSlash() const { return m_allowSlash; }
-    bool allowWidth() const { return m_allowWidth; }
-    bool allowOutset() const { return m_allowOutset; }
+    bool canAdvance() const { return m_canAdvance; }
+    void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; }
+
+    bool allowCommit() const { return m_allowCommit; }
+    bool allowImage() const { return m_allowImage; }
+    bool allowImageSlice() const { return m_allowImageSlice; }
     bool allowRepeat() const { return m_allowRepeat; }
+    bool allowSlash() const { return m_allowSlash; }
 
-    void commitImage(PassRefPtr<CSSValue> image) { m_image = image; }
+    bool requireWidth() const { return m_requireWidth; }
+    bool requireOutset() const { return m_requireOutset; }
+    
+    void commitImage(PassRefPtr<CSSValue> image)
+    {
+        m_image = image;
+        m_canAdvance = true;
+        m_allowCommit = true;
+        m_allowImage = false;
+        m_allowSlash = false;
+        m_requireWidth = false;
+        m_requireOutset = false;
+        m_allowImageSlice = !m_imageSlice;
+        m_allowRepeat = !m_repeat;
+    }
     void commitImageSlice(PassRefPtr<CSSBorderImageSliceValue> slice)
     {
         m_imageSlice = slice;
-        m_allowBreak = m_allowSlash = m_allowRepeat = true;
+        m_canAdvance = true;
+        m_allowCommit = true;
+        m_allowSlash = true;
+        m_allowImageSlice = false;
+        m_requireWidth = false;
+        m_requireOutset = false;
+        m_allowImage = !m_image;
+        m_allowRepeat = !m_repeat;
     }
     void commitSlash()
     {
-        m_allowBreak = m_allowSlash = m_allowRepeat = false;
-        if (!m_borderSlice)
-            m_allowWidth = true;
-        else
-            m_allowOutset = true;
+        m_canAdvance = true;
+        m_allowCommit = false;
+        m_allowImage = false;
+        m_allowImageSlice = false;
+        m_allowRepeat = false;
+        m_allowSlash = false;
+        if (!m_borderSlice) {
+            m_requireWidth = true;
+            m_requireOutset = false;
+        } else {
+            m_requireOutset = true;
+            m_requireWidth = false;
+        }
     }
     void commitBorderWidth(PassRefPtr<CSSPrimitiveValue> slice)
     {
         m_borderSlice = slice;
-        m_allowBreak = m_allowRepeat = true;
-        m_allowWidth = false;
+        m_canAdvance = true;
+        m_allowCommit = true;
         m_allowSlash = true;
+        m_allowImageSlice = false;
+        m_requireWidth = false;
+        m_requireOutset = false;
+        m_allowImage = !m_image;
+        m_allowRepeat = !m_repeat;
     }
     void commitBorderOutset(PassRefPtr<CSSPrimitiveValue> outset)
     {
         m_outset = outset;
-        m_allowBreak = m_allowRepeat = true;
-        m_allowWidth = m_allowOutset = m_allowSlash = false;
+        m_canAdvance = true;
+        m_allowCommit = true;
+        m_allowImageSlice = false;
+        m_allowSlash = false;
+        m_requireWidth = false;
+        m_requireOutset = false;
+        m_allowImage = !m_image;
+        m_allowRepeat = !m_repeat;
     }
     void commitRepeat(PassRefPtr<CSSValue> repeat)
     {
         m_repeat = repeat;
-        m_allowRepeat = m_allowSlash = m_allowWidth = m_allowOutset = false;
-        m_allowBreak = true;
+        m_canAdvance = true;
+        m_allowCommit = true;
+        m_allowRepeat = false;
+        m_allowSlash = false;
+        m_requireWidth = false;
+        m_requireOutset = false;
+        m_allowImageSlice = !m_imageSlice;
+        m_allowImage = !m_image;
     }
 
     PassRefPtr<CSSValue> commitBorderImage()
@@ -5213,11 +5265,16 @@ struct BorderImageParseContext {
     
     CSSPrimitiveValueCache* m_primitiveValueCache;
 
-    bool m_allowBreak;
-    bool m_allowSlash;
-    bool m_allowWidth;
-    bool m_allowOutset;
+    bool m_canAdvance;
+
+    bool m_allowCommit;
+    bool m_allowImage;
+    bool m_allowImageSlice;
     bool m_allowRepeat;
+    bool m_allowSlash;
+    
+    bool m_requireWidth;
+    bool m_requireOutset;
 
     RefPtr<CSSValue> m_image;
     RefPtr<CSSBorderImageSliceValue> m_imageSlice;
@@ -5229,59 +5286,58 @@ struct BorderImageParseContext {
 
 bool CSSParser::parseBorderImage(int propId, RefPtr<CSSValue>& result)
 {
-    // Look for an image initially. If the first value is not a URI or the keyword "none", then we're done.
     ShorthandScope scope(this, propId);
     BorderImageParseContext context(primitiveValueCache());
-    CSSParserValue* val = m_valueList->current();
-    if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
-        // FIXME: The completeURL call should be done when using the CSSImageValue,
-        // not when creating it.
-        context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string)));
-    } else if (isGeneratedImageValue(val)) {
-        RefPtr<CSSValue> value;
-        if (parseGeneratedImage(value))
-            context.commitImage(value);
-        else
-            return false;
-    } else if (val->id == CSSValueNone)
-        context.commitImage(CSSImageValue::create());
-    else
-        return false;
-
-    // Parse the slice next.
-    m_valueList->next();
-    RefPtr<CSSBorderImageSliceValue> imageSlice;
-    if (!parseBorderImageSlice(propId, imageSlice))
-        return false;
-    context.commitImageSlice(imageSlice.release());
-
-    while ((val = m_valueList->current())) {
-        if (context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/') {
+    while (CSSParserValue* val = m_valueList->current()) {
+        if (!context.canAdvance() && context.allowSlash() && val->unit == CSSParserValue::Operator && val->iValue == '/')
             context.commitSlash();
-        } else if (context.allowWidth()) {
-            RefPtr<CSSPrimitiveValue> borderSlice;
-            if (!parseBorderImageWidth(borderSlice))
-                return false;
-            context.commitBorderWidth(borderSlice.release());
-            continue;
-        } else if (context.allowOutset()) {
-            RefPtr<CSSPrimitiveValue> borderOutset;
-            if (!parseBorderImageOutset(borderOutset))
-                return false;
-            context.commitBorderOutset(borderOutset.release());
-            continue;
-        } else if (context.allowRepeat()) {
+        
+        if (!context.canAdvance() && context.allowImage()) {
+            if (val->unit == CSSPrimitiveValue::CSS_URI && m_styleSheet) {
+                // FIXME: The completeURL call should be done when using the CSSImageValue,
+                // not when creating it.
+                context.commitImage(CSSImageValue::create(m_styleSheet->completeURL(val->string)));
+            } else if (isGeneratedImageValue(val)) {
+                RefPtr<CSSValue> value;
+                if (parseGeneratedImage(value))
+                    context.commitImage(value);
+                else
+                    return false;
+            } else if (val->id == CSSValueNone)
+                context.commitImage(CSSImageValue::create());
+        }
+        
+        if (!context.canAdvance() && context.allowImageSlice()) {
+            RefPtr<CSSBorderImageSliceValue> imageSlice;
+            if (parseBorderImageSlice(propId, imageSlice))
+                context.commitImageSlice(imageSlice.release());
+        } 
+        
+        if (!context.canAdvance() && context.allowRepeat()) {
             RefPtr<CSSValue> repeat;
             if (parseBorderImageRepeat(repeat))
                 context.commitRepeat(repeat);
-        } else {
-            // Something invalid was encountered.
-            return false;
         }
-        m_valueList->next();
+        
+        if (!context.canAdvance() && context.requireWidth()) {
+            RefPtr<CSSPrimitiveValue> borderSlice;
+            if (parseBorderImageWidth(borderSlice))
+                context.commitBorderWidth(borderSlice.release());
+        } 
+        
+        if (!context.canAdvance() && context.requireOutset()) {
+            RefPtr<CSSPrimitiveValue> borderOutset;
+            if (parseBorderImageOutset(borderOutset))
+                context.commitBorderOutset(borderOutset.release());
+        } 
+        
+        if (context.canAdvance()) {
+            m_valueList->next();
+            context.setCanAdvance(false);
+        }
     }
 
-    if (context.allowBreak()) {
+    if (context.allowCommit()) {
         // Need to fully commit as a single value.
         result = context.commitBorderImage();
         return true;
@@ -5309,8 +5365,14 @@ bool CSSParser::parseBorderImageRepeat(RefPtr<CSSValue>& result)
     if (val) {
         if (isBorderImageRepeatKeyword(val->id))
             secondValue = primitiveValueCache()->createIdentifierValue(val->id);
-        else
+        else if (!inShorthand()) {
+            // If we're not parsing a shorthand then we are invalid.
             return false;
+        } else {
+            // We need to rewind the value list, so that when its advanced we'll
+            // end up back at this value.
+            m_valueList->previous();
+        }
     } else
         secondValue = firstValue;
 
@@ -5408,11 +5470,16 @@ bool CSSParser::parseBorderImageSlice(int propId, RefPtr<CSSBorderImageSliceValu
             context.commitNumber(val);
         } else if (context.allowFill() && val->id == CSSValueFill)
             context.commitFill();
-        else if (propId == CSSPropertyBorderImageSlice || propId == CSSPropertyWebkitMaskBoxImageSlice) {
+        else if (!inShorthand()) {
             // If we're not parsing a shorthand then we are invalid.
             return false;
-        } else
+        } else {
+            if (context.allowFinalCommit()) {
+                // We're going to successfully parse, but we don't want to consume this token.
+                m_valueList->previous();
+            }
             break;
+        }
         m_valueList->next();
     }
 
@@ -5523,8 +5590,11 @@ bool CSSParser::parseBorderImageQuad(Units validUnits, RefPtr<CSSPrimitiveValue>
         } else if (!inShorthand()) {
             // If we're not parsing a shorthand then we are invalid.
             return false;
-        } else
+        } else {
+            if (context.allowFinalCommit())
+                m_valueList->previous(); // The shorthand loop will advance back to this point.
             break;
+        }
         m_valueList->next();
     }
 
index cf6c07b..49f01d0 100644 (file)
@@ -78,6 +78,13 @@ public:
     unsigned size() const { return m_values.size(); }
     CSSParserValue* current() { return m_current < m_values.size() ? &m_values[m_current] : 0; }
     CSSParserValue* next() { ++m_current; return current(); }
+    CSSParserValue* previous()
+    {
+        if (!m_current)
+            return 0;
+        --m_current;
+        return current();
+    }
 
     CSSParserValue* valueAt(unsigned i) { return i < m_values.size() ? &m_values[i] : 0; }