LayoutTests:
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 31 Jul 2006 06:52:06 +0000 (06:52 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 31 Jul 2006 06:52:06 +0000 (06:52 +0000)
        - test that displays all computed style -- demonstrates bug fixes I just
          made to the computed style class and also acts as a regression test for
          the existence of all of them and the basic format for a default object

        * fast/css/computed-style-expected.txt: Added.
        * fast/css/computed-style.html: Added.

WebCore:

        Reviewed by Tim Hatcher.

        - some improvements for the benefit of the style pane of the inspector

        * css/CSSComputedStyleDeclaration.cpp: Removed background-position
        and border-spacing from the list of properties that show up in
        computed style, because of background-position-x, background-position-y,
        -webkit-border-horizontal-spacing and -webkit-border-vertical-spacing.
        (WebCore::valueForLength): Added handling for undefinedLength, intrinsic,
        and min-intrinsic.
        (WebCore::primitiveValueFromLength): Removed code that would add a
        space to the string for no good reason.
        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Added a
        special case for a line clamp of -1, which should come back as "none"
        rather than an actual "-1".
        (WebCore::CSSComputedStyleDeclaration::length): Return 0 if the
        declaration has no corresponding node or no renderer.
        (WebCore::CSSComputedStyleDeclaration::item): Check against length()
        so that the two stay consistent rather than using a constant.

        * css/CSSPrimitiveValue.cpp:
        (WebCore::isCSSTokenizerIdentifier): Added.
        (WebCore::isCSSTokenizerURL): Added.
        (WebCore::quoteString): Added.
        (WebCore::quoteStringIfNeeded): Changed to quote strings in many more
        cases -- any cases where they would not parse in the CSS parser otherwise.
        The main case this affects is font names with spaces in them.
        (WebCore::quoteURLIfNeeded): Added.
        (WebCore::CSSPrimitiveValue::cssText): Use quoteURLIfNeeded in the case
        where we're making the text form of a URI.

        * css/tokenizer.flex: Whitespace tweaks to line things up better.

WebKit:

        Reviewed by Tim Hatcher.

        - some improvements for the inspector

        * WebInspector/WebInspector.m:
        (+[WebInspector sharedWebInspector:]): Fixed bug that could cause the inspector
        to be garbage collected if used in an application with GC enabled.
        (-[WebInspector dealloc]): Removed a call to a non-existent close method.
        (-[WebInspector window]): Added a custom WebPreferences object and called
        setPrivateBrowsingEnabled:YES so the inspector won't appear in the history menu.
        Also call setProhibitsMainFrameScrolling:YES to try to get rid of trouble where
        the inspector scrolls when dragging.

        * WebInspector/webInspector/inspector.css: Added style for the new color swatch,
        and JavaScript properties. More of the style should be shared between the panes,
        but this should be OK for now.

        * WebInspector/webInspector/inspector.html: Added a first cut at a JavaScript
        properties pane. Needs work, but better than nothing.

        * WebInspector/webInspector/inspector.js: Lots of improvements:
        - Omit "typical" property values from computed style display, making it much shorter.
        - Use the words "black", "white", and "transparent" when appropriate for color values.
        - Refactored the loaded() function to get rid of repetitive scrollbar setup.
        - Added a new scrollarea for the JavaScript properties pane.
        - Simplified refreshScrollbars() -- we now refresh all scrollbars every time, which does no harm.
        - Removed unused resultsWithXpathQuery().
        - Use [] instead of "new Array()" and {} instead of "new Object()".
        - Removed unused xpathForNode().
        - Changed style pane to display the style for a text node's parent instead of saying
          it can't display the style for text.
        - Fixed regression I caused a while back by checking the length of a computed style
          and not trying to display anything if its length is 0. Before this change and the
          corresponding change in WebCore, we'd see a complete list of all styles with the
          empty string as the value for each one.
        - Changed the name of the computedStyle flag on the style rules array to isComputedStyle
          to make it easier to understand it's a boolean.
        - Fixed an error in the code that does !important scanning where it was trying to
          do a special case for computed style, but was checking the computed style flag on
          the wrong object.
        - Added populateStyleListItem() function to factor out things in common between the
          items in the top level list and the expanded tree for shorthand properties.
        - Added code to make a color swatch next to the textual representation for any
          property that contains a color.
        - Implemented a first cut at a simple JavaScript properties pane.

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

12 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/computed-style-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/computed-style.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/css/CSSComputedStyleDeclaration.cpp
WebCore/css/CSSPrimitiveValue.cpp
WebCore/css/tokenizer.flex
WebKit/ChangeLog
WebKit/WebInspector/WebInspector.m
WebKit/WebInspector/webInspector/inspector.css
WebKit/WebInspector/webInspector/inspector.html
WebKit/WebInspector/webInspector/inspector.js

index c288cde..072a1e0 100644 (file)
@@ -1,3 +1,12 @@
+2006-07-30  Darin Adler  <darin@apple.com>
+
+        - test that displays all computed style -- demonstrates bug fixes I just
+          made to the computed style class and also acts as a regression test for
+          the existence of all of them and the basic format for a default object
+
+        * fast/css/computed-style-expected.txt: Added.
+        * fast/css/computed-style.html: Added.
+
 2006-07-29  Rob Buis  <buis@kde.org>
 
         Reviewed by Geoff.
diff --git a/LayoutTests/fast/css/computed-style-expected.txt b/LayoutTests/fast/css/computed-style-expected.txt
new file mode 100644 (file)
index 0000000..5cc0e61
--- /dev/null
@@ -0,0 +1,116 @@
+Attributes that are exposed in the CSS computed style object:
+
+background-color: rgba(0, 0, 0, 0);
+background-image: none;
+-webkit-background-size: auto auto;
+background-repeat: repeat;
+-webkit-background-composite: source-over;
+background-attachment: scroll;
+-webkit-background-clip: border;
+-webkit-background-origin: padding;
+background-position-x: auto;
+background-position-y: auto;
+border-collapse: separate;
+-webkit-border-horizontal-spacing: 0px;
+-webkit-border-vertical-spacing: 0px;
+border-top-color: rgba(0, 0, 0, 0);
+border-right-color: rgba(0, 0, 0, 0);
+border-bottom-color: rgba(0, 0, 0, 0);
+border-left-color: rgba(0, 0, 0, 0);
+border-top-style: none;
+border-right-style: none;
+border-bottom-style: none;
+border-left-style: none;
+border-top-width: 0px;
+border-right-width: 0px;
+border-bottom-width: 0px;
+border-left-width: 0px;
+bottom: auto;
+-webkit-box-align: stretch;
+-webkit-box-direction: normal;
+-webkit-box-flex: 0;
+-webkit-box-flex-group: 1;
+-webkit-box-lines: single;
+-webkit-box-ordinal-group: 1;
+-webkit-box-orient: horizontal;
+-webkit-box-pack: start;
+caption-side: top;
+clear: none;
+color: rgb(0, 0, 0);
+cursor: auto;
+-webkit-dashboard-region: null;
+direction: ltr;
+display: block;
+empty-cells: show;
+float: none;
+font-family: Times;
+font-size: 16px;
+font-style: normal;
+font-variant: normal;
+font-weight: normal;
+height: 576px;
+-webkit-highlight: none;
+left: auto;
+letter-spacing: normal;
+-webkit-line-break: normal;
+-webkit-line-clamp: none;
+line-height: normal;
+list-style-image: none;
+list-style-position: outside;
+list-style-type: disc;
+margin-top: 8px;
+margin-right: 8px;
+margin-bottom: 8px;
+margin-left: 8px;
+-webkit-marquee-direction: auto;
+-webkit-marquee-increment: 6px;
+-webkit-marquee-repetition: infinite;
+-webkit-marquee-style: scroll;
+max-height: none;
+max-width: none;
+min-height: 0px;
+min-width: 0px;
+-webkit-nbsp-mode: normal;
+opacity: 1;
+orphans: 2;
+outline-style: none;
+overflow-x: visible;
+overflow-y: visible;
+padding-top: 0px;
+padding-right: 0px;
+padding-bottom: 0px;
+padding-left: 0px;
+page-break-after: auto;
+page-break-before: auto;
+page-break-inside: auto;
+position: static;
+resize: none;
+right: auto;
+table-layout: auto;
+text-align: auto;
+text-decoration: none;
+-webkit-text-decorations-in-effect: none;
+text-indent: 0px;
+text-shadow: none;
+text-transform: none;
+top: auto;
+unicode-bidi: normal;
+-webkit-user-modify: read-only;
+vertical-align: baseline;
+visibility: visible;
+white-space: normal;
+widows: 2;
+width: 784px;
+word-spacing: 0px;
+word-wrap: normal;
+z-index: normal;
+
+Other attributes that the computed style class supports:
+
+background-position: '0 0';
+border-spacing: '0px 0px';
+overflow: visible;
+-webkit-match-nearest-mail-blockquote-color: normal;
+-webkit-text-size-adjust: auto;
+
+
diff --git a/LayoutTests/fast/css/computed-style.html b/LayoutTests/fast/css/computed-style.html
new file mode 100644 (file)
index 0000000..b043e69
--- /dev/null
@@ -0,0 +1,63 @@
+<script>
+function test() {
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+    var style = document.defaultView.getComputedStyle(document.body);
+    var text = "";
+    for (var i = 0; i != style.length; ++i) {
+        var name = style[i];
+        var value = style.getPropertyValue(name);
+        text += name + ": " + value + ";\n";
+    }
+    document.getElementById("exposed").textContent = text;
+    var others = [
+        "background-position",
+        "border-spacing",
+        "overflow",
+        "-webkit-match-nearest-mail-blockquote-color",
+        "-webkit-text-size-adjust",
+    ];
+    var unimplemented = [
+        "background",
+        "border",
+        "border-bottom",
+        "border-color",
+        "border-left",
+        "border-right",
+        "border-style",
+        "border-top",
+        "border-width",
+        "clip",
+        "content",
+        "counter-increment",
+        "counter-reset",
+        "font",
+        "font-stretch",
+        "list-style",
+        "margin",
+        "-webkit-marquee",
+        "-webkit-marquee-speed",
+        "outline",
+        "outline-color",
+        "outline-offset",
+        "outline-width",
+        "padding",
+        "page",
+        "quotes",
+        "size",
+    ];
+    text = "";
+    for (var i = 0; i != others.length; ++i) {
+        var name = others[i];
+        var value = style.getPropertyValue(name);
+        text += name + ": " + value + ";\n";
+    }
+    document.getElementById("hidden").textContent = text;
+}
+</script>
+<body onload="test()">
+<p>Attributes that are exposed in the CSS computed style object:</p>
+<p id="exposed" style="white-space: pre"></p>
+<p>Other attributes that the computed style class supports:</p>
+<p id="hidden" style="white-space: pre"></p>
+</body>
index 70a605c..68eee46 100644 (file)
@@ -1,3 +1,38 @@
+2006-07-30  Darin Adler  <darin@apple.com>
+
+        Reviewed by Tim Hatcher.
+
+        - some improvements for the benefit of the style pane of the inspector
+
+        * css/CSSComputedStyleDeclaration.cpp: Removed background-position
+        and border-spacing from the list of properties that show up in
+        computed style, because of background-position-x, background-position-y,
+        -webkit-border-horizontal-spacing and -webkit-border-vertical-spacing.
+        (WebCore::valueForLength): Added handling for undefinedLength, intrinsic,
+        and min-intrinsic.
+        (WebCore::primitiveValueFromLength): Removed code that would add a
+        space to the string for no good reason.
+        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue): Added a
+        special case for a line clamp of -1, which should come back as "none"
+        rather than an actual "-1".
+        (WebCore::CSSComputedStyleDeclaration::length): Return 0 if the
+        declaration has no corresponding node or no renderer.
+        (WebCore::CSSComputedStyleDeclaration::item): Check against length()
+        so that the two stay consistent rather than using a constant.
+
+        * css/CSSPrimitiveValue.cpp:
+        (WebCore::isCSSTokenizerIdentifier): Added.
+        (WebCore::isCSSTokenizerURL): Added.
+        (WebCore::quoteString): Added.
+        (WebCore::quoteStringIfNeeded): Changed to quote strings in many more
+        cases -- any cases where they would not parse in the CSS parser otherwise.
+        The main case this affects is font names with spaces in them.
+        (WebCore::quoteURLIfNeeded): Added.
+        (WebCore::CSSPrimitiveValue::cssText): Use quoteURLIfNeeded in the case
+        where we're making the text form of a URI.
+
+        * css/tokenizer.flex: Whitespace tweaks to line things up better.
+
 2006-07-30  Eric Seidel  <eric@eseidel.com>
 
         Reviewed by gramps!
index e4acbeb..2021fdd 100644 (file)
@@ -50,11 +50,9 @@ static const int computedProperties[] = {
     CSS_PROP_BACKGROUND_ATTACHMENT,
     CSS_PROP__WEBKIT_BACKGROUND_CLIP,
     CSS_PROP__WEBKIT_BACKGROUND_ORIGIN,
-    CSS_PROP_BACKGROUND_POSITION,
     CSS_PROP_BACKGROUND_POSITION_X,
     CSS_PROP_BACKGROUND_POSITION_Y,
     CSS_PROP_BORDER_COLLAPSE,
-    CSS_PROP_BORDER_SPACING,
     CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING,
     CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING,
     CSS_PROP_BORDER_TOP_COLOR,
@@ -120,7 +118,6 @@ static const int computedProperties[] = {
     CSS_PROP_OPACITY,
     CSS_PROP_ORPHANS,
     CSS_PROP_OUTLINE_STYLE,
-    CSS_PROP_OVERFLOW,
     CSS_PROP_OVERFLOW_X,
     CSS_PROP_OVERFLOW_Y,
     CSS_PROP_PADDING_TOP,
@@ -131,6 +128,7 @@ static const int computedProperties[] = {
     CSS_PROP_PAGE_BREAK_BEFORE,
     CSS_PROP_PAGE_BREAK_INSIDE,
     CSS_PROP_POSITION,
+    CSS_PROP_RESIZE,
     CSS_PROP_RIGHT,
     CSS_PROP_TABLE_LAYOUT,
     CSS_PROP_TEXT_ALIGN,
@@ -154,16 +152,28 @@ static const int computedProperties[] = {
 
 const unsigned numComputedProperties = sizeof(computedProperties) / sizeof(computedProperties[0]);
 
-static CSSValue* valueForLength(const Length &length)
+static CSSValue* valueForLength(const Lengthlength)
 {
     switch (length.type()) {
-        case Percent:
-            return new CSSPrimitiveValue(length.value(), CSSPrimitiveValue::CSS_PERCENTAGE);
+        case Auto:
+            return new CSSPrimitiveValue(CSS_VAL_AUTO);
         case WebCore::Fixed:
+            if (length.value() == undefinedLength)
+                return new CSSPrimitiveValue(CSS_VAL_NONE);
             return new CSSPrimitiveValue(length.value(), CSSPrimitiveValue::CSS_PX);
-        default: // FIXME: Intrinsic and MinIntrinsic should probably return keywords.
-            return new CSSPrimitiveValue(CSS_VAL_AUTO);
+        case Intrinsic:
+            return new CSSPrimitiveValue(CSS_VAL_INTRINSIC);
+        case MinIntrinsic:
+            return new CSSPrimitiveValue(CSS_VAL_MIN_INTRINSIC);
+        case Percent:
+            return new CSSPrimitiveValue(length.value(), CSSPrimitiveValue::CSS_PERCENTAGE);
+        case Relative:
+        case Static:
+            // Should never be reached.
+            break;
     }
+    // Should never be reached, but if we do, just return "auto".
+    return new CSSPrimitiveValue(CSS_VAL_AUTO);
 }
 
 static CSSValue *valueForBorderStyle(EBorderStyle style)
@@ -322,8 +332,7 @@ CSSPrimitiveValue* primitiveValueFromLength(Length length, RenderObject* rendere
     else if (length.isFixed())
         string = numberAsString(length.calcMinValue(0));
     else if (length.isAuto())
-        string += "auto";
-    string += " ";
+        string = "auto";
     return new CSSPrimitiveValue(string, CSSPrimitiveValue::CSS_STRING);
 }
 
@@ -770,6 +779,8 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(int proper
             return new CSSPrimitiveValue(CSS_VAL_NORMAL);
         return new CSSPrimitiveValue(style->letterSpacing(), CSSPrimitiveValue::CSS_PX);
     case CSS_PROP__WEBKIT_LINE_CLAMP:
+        if (style->lineClamp() == -1)
+            return new CSSPrimitiveValue(CSS_VAL_NONE);
         return new CSSPrimitiveValue(style->lineClamp(), CSSPrimitiveValue::CSS_PERCENTAGE);
     case CSS_PROP_LINE_HEIGHT: {
         Length length(style->lineHeight());
@@ -1343,12 +1354,21 @@ void CSSComputedStyleDeclaration::setProperty(int, const String&, bool, Exceptio
 
 unsigned CSSComputedStyleDeclaration::length() const
 {
+    Node* node = m_node.get();
+    if (!node)
+        return 0;
+    RenderObject* renderer = node->renderer();
+    if (!renderer)
+        return 0;
+    RenderStyle* style = renderer->style();
+    if (!style)
+        return 0;
     return numComputedProperties;
 }
 
 String CSSComputedStyleDeclaration::item(unsigned i) const
 {
-    if (i >= numComputedProperties)
+    if (i >= length())
         return String();
     
     return getPropertyName(computedProperties[i]);
@@ -1359,7 +1379,8 @@ String CSSComputedStyleDeclaration::item(unsigned i) const
 // properties for which we have a computed implementation in this file.
 const int inheritableProperties[] = {
     CSS_PROP_BORDER_COLLAPSE,
-    CSS_PROP_BORDER_SPACING,
+    CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING,
+    CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING,
     CSS_PROP_COLOR,
     CSS_PROP_FONT_FAMILY,
     CSS_PROP_FONT_SIZE,
index 64b621f..f1da2cf 100644 (file)
 
 namespace WebCore {
 
-// Quotes the string if it needs quoting.
-// We use single quotes for now beause markup.cpp uses double quotes.
-static String quoteStringIfNeeded(const String &string)
+// "ident" from the CSS tokenizer, minus backslash-escape sequences
+static bool isCSSTokenizerIdentifier(const String& string)
 {
-    // For now, just do this for strings that start with "#" to fix Korean font names that start with "#".
-    // Post-Tiger, we should isLegalIdentifier instead after working out all the ancillary issues.
-    if (string[0] != '#')
-        return string;
+    const UChar* p = string.characters();
+    const UChar* end = p + string.length();
 
-    // FIXME: Also need to transform control characters into \ sequences.
+    // -?
+    if (p != end && p[0] == '-')
+        ++p;
+
+    // {nmstart}
+    if (p == end || !(p[0] == '_' || isalpha(p[0]) || p[0] >= 128))
+        return false;
+    ++p;
+
+    // {nmchar}*
+    for (; p != end; ++p)
+        if (!(p[0] == '_' || p[0] == '-' || isalnum(p[0]) || p[0] >= 128))
+            return false;
+
+    return true;
+}
+
+// "url" from the CSS tokenizer, minus backslash-escape sequences
+static bool isCSSTokenizerURL(const String& string)
+{
+    const UChar* p = string.characters();
+    const UChar* end = p + string.length();
+
+    for (; p != end; ++p)
+        switch (p[0]) {
+            case '!':
+            case '#':
+            case '$':
+            case '%':
+            case '&':
+            case '*':
+            case '-':
+            case '~':
+                break;
+            default:
+                if (p[0] < 128)
+                    return false;
+        }
+
+    return true;
+}
+
+// We use single quotes for now because markup.cpp uses double quotes.
+static String quoteString(const String& string)
+{
+    // FIXME: Also need to escape characters like '\n'.
     String s = string;
     s.replace('\\', "\\\\");
     s.replace('\'', "\\'");
     return "'" + s + "'";
 }
 
+static String quoteStringIfNeeded(const String& string)
+{
+    return isCSSTokenizerIdentifier(string) ? string : quoteString(string);
+}
+
+static String quoteURLIfNeeded(const String& string)
+{
+    return isCSSTokenizerURL(string) ? string : quoteString(string);
+}
+
 CSSPrimitiveValue::CSSPrimitiveValue()
 {
     m_type = 0;
@@ -458,7 +510,7 @@ String CSSPrimitiveValue::cssText() const
             text = quoteStringIfNeeded(m_value.string);
             break;
         case CSS_URI:
-            text = "url(" + String(m_value.string) + ")";
+            text = "url(" + quoteURLIfNeeded(m_value.string) + ")";
             break;
         case CSS_IDENT:
             text = getValueName(m_value.ident);
index 2d21f99..94e957d 100644 (file)
@@ -52,12 +52,12 @@ range           \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|
 "@font-face"            {yyTok = FONT_FACE_SYM; return yyTok;}
 "@charset"              {yyTok = CHARSET_SYM; return yyTok;}
 "@namespace"            {yyTok = NAMESPACE_SYM; return yyTok; }
-"@-webkit-rule"    {yyTok = WEBKIT_RULE_SYM; return yyTok; }
-"@-webkit-decls"   {yyTok = WEBKIT_DECLS_SYM; return yyTok; }
-"@-webkit-value"   {yyTok = WEBKIT_VALUE_SYM; return yyTok; }
+"@-webkit-rule"         {yyTok = WEBKIT_RULE_SYM; return yyTok; }
+"@-webkit-decls"        {yyTok = WEBKIT_DECLS_SYM; return yyTok; }
+"@-webkit-value"        {yyTok = WEBKIT_VALUE_SYM; return yyTok; }
 "@-webkit-mediaquery"   {BEGIN(mediaquery); yyTok = WEBKIT_MEDIAQUERY_SYM; return yyTok; }
 
-"!"{w}"important"         {yyTok = IMPORTANT_SYM; return yyTok;}
+"!"{w}"important"       {yyTok = IMPORTANT_SYM; return yyTok;}
 
 {num}em                 {yyTok = EMS; return yyTok;}
 {num}__qem              {yyTok = QEMS; return yyTok;} /* quirky ems */
@@ -93,4 +93,3 @@ U\+{h}{1,6}-{h}{1,6}    {yyTok = UNICODERANGE; return yyTok;}
 .                       {yyTok = *yytext; return yyTok;}
 
 %%
-
index d6ef1c9..2623356 100644 (file)
@@ -1,3 +1,51 @@
+2006-07-30  Darin Adler  <darin@apple.com>
+
+        Reviewed by Tim Hatcher.
+
+        - some improvements for the inspector
+
+        * WebInspector/WebInspector.m:
+        (+[WebInspector sharedWebInspector:]): Fixed bug that could cause the inspector
+        to be garbage collected if used in an application with GC enabled.
+        (-[WebInspector dealloc]): Removed a call to a non-existent close method.
+        (-[WebInspector window]): Added a custom WebPreferences object and called
+        setPrivateBrowsingEnabled:YES so the inspector won't appear in the history menu.
+        Also call setProhibitsMainFrameScrolling:YES to try to get rid of trouble where
+        the inspector scrolls when dragging.
+
+        * WebInspector/webInspector/inspector.css: Added style for the new color swatch,
+        and JavaScript properties. More of the style should be shared between the panes,
+        but this should be OK for now.
+
+        * WebInspector/webInspector/inspector.html: Added a first cut at a JavaScript
+        properties pane. Needs work, but better than nothing.
+
+        * WebInspector/webInspector/inspector.js: Lots of improvements:
+        - Omit "typical" property values from computed style display, making it much shorter.
+        - Use the words "black", "white", and "transparent" when appropriate for color values.
+        - Refactored the loaded() function to get rid of repetitive scrollbar setup.
+        - Added a new scrollarea for the JavaScript properties pane.
+        - Simplified refreshScrollbars() -- we now refresh all scrollbars every time, which does no harm.
+        - Removed unused resultsWithXpathQuery().
+        - Use [] instead of "new Array()" and {} instead of "new Object()".
+        - Removed unused xpathForNode().
+        - Changed style pane to display the style for a text node's parent instead of saying
+          it can't display the style for text.
+        - Fixed regression I caused a while back by checking the length of a computed style
+          and not trying to display anything if its length is 0. Before this change and the
+          corresponding change in WebCore, we'd see a complete list of all styles with the
+          empty string as the value for each one.
+        - Changed the name of the computedStyle flag on the style rules array to isComputedStyle
+          to make it easier to understand it's a boolean.
+        - Fixed an error in the code that does !important scanning where it was trying to
+          do a special case for computed style, but was checking the computed style flag on
+          the wrong object.
+        - Added populateStyleListItem() function to factor out things in common between the
+          items in the top level list and the expanded tree for shorthand properties.
+        - Added code to make a color swatch next to the textual representation for any
+          property that contains a color.
+        - Implemented a first cut at a simple JavaScript properties pane.
+
 2006-07-29  Darin Adler  <darin@apple.com>
 
         - Removed tabs from these source files that still had them.
index 7a7b1f4..776c9f6 100644 (file)
 #import "WebInspector.h"
 #import "WebInspectorInternal.h"
 
-#import "WebInspectorPanel.h"
-#import "WebInspectorOutlineView.h"
-#import "WebNodeHighlight.h"
-#import "WebView.h"
-#import "WebViewPrivate.h"
-#import "WebHTMLView.h"
 #import "WebFrame.h"
 #import "WebFrameInternal.h"
-#import "WebLocalizableStrings.h"
+#import "WebHTMLView.h"
+#import "WebInspectorOutlineView.h"
+#import "WebInspectorPanel.h"
 #import "WebKitNSStringExtras.h"
+#import "WebLocalizableStrings.h"
+#import "WebNodeHighlight.h"
+#import "WebPreferences.h"
 #import "WebTypesInternal.h"
+#import "WebView.h"
+#import "WebViewPrivate.h"
 
 #import <WebKit/DOMCore.h>
 #import <WebKit/DOMHTML.h>
@@ -58,11 +59,13 @@ static NSMapTable *lastChildIgnoringWhitespaceCache = NULL;
 #pragma mark -
 
 @implementation WebInspector
+
 + (WebInspector *)sharedWebInspector
 {
     static WebInspector *_sharedWebInspector = nil;
     if (!_sharedWebInspector) {
-        _sharedWebInspector = [[self alloc] initWithWebFrame:nil];
+        _sharedWebInspector = [[[self alloc] init] autorelease];
+        CFRetain(_sharedWebInspector);
         _sharedWebInspector->_private->isSharedInspector = YES;
     }
     return _sharedWebInspector;
@@ -93,7 +96,6 @@ static NSMapTable *lastChildIgnoringWhitespaceCache = NULL;
 
 - (void)dealloc
 {
-    [self close];
     [_private release];
     [super dealloc];
 }
@@ -104,7 +106,8 @@ static NSMapTable *lastChildIgnoringWhitespaceCache = NULL;
 {
     NSWindow *window = [super window];
     if (!window) {
-        NSPanel *window = [[WebInspectorPanel alloc] initWithContentRect:NSMakeRect(60.0, 200.0, 350.0, 550.0) styleMask:(NSBorderlessWindowMask | NSUtilityWindowMask) backing:NSBackingStoreBuffered defer:YES];
+        NSPanel *window = [[WebInspectorPanel alloc] initWithContentRect:NSMakeRect(60.0, 200.0, 350.0, 550.0)\
+            styleMask:(NSBorderlessWindowMask | NSUtilityWindowMask) backing:NSBackingStoreBuffered defer:YES];
         [window setBackgroundColor:[NSColor clearColor]];
         [window setOpaque:NO];
         [window setHasShadow:YES];
@@ -119,14 +122,23 @@ static NSMapTable *lastChildIgnoringWhitespaceCache = NULL;
         [window setDelegate:self];
         [window setMinSize:NSMakeSize(280.0, 450.0)];
 
+        // Keep preferences separate from the rest of the client.
+        // One reason this is good is that it keeps the inspector out of history via "private browsing".
+        WebPreferences *preferences = [[WebPreferences alloc] init];
+        [preferences setPrivateBrowsingEnabled:YES];
+
         _private->webView = [[WebView alloc] initWithFrame:[[window contentView] frame] frameName:nil groupName:nil];
+        [_private->webView setPreferences:preferences];
         [_private->webView setFrameLoadDelegate:self];
         [_private->webView setUIDelegate:self];
         [_private->webView setDrawsBackground:NO];
+        [_private->webView setProhibitsMainFrameScrolling:YES];
         [_private->webView _setDashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows to:YES];
         [_private->webView _setDashboardBehavior:WebDashboardBehaviorAlwaysAcceptsFirstMouse to:YES];
         [[_private->webView windowScriptObject] setValue:self forKey:@"Inspector"];
 
+        [preferences release];
+
         [window setContentView:_private->webView];
 
         NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"inspector" ofType:@"html" inDirectory:@"webInspector"];
@@ -247,7 +259,7 @@ static NSMapTable *lastChildIgnoringWhitespaceCache = NULL;
 
             // only scroll if the bounds isn't in the visible rect and dosen't contain the visible rect
             if (needsScroll) {
-                // scroll to the parent element if we arn't focued on an element
+                // scroll to the parent element if we aren't focused on an element
                 DOMElement *element = (DOMElement *)_private->focusedNode;
                 if (![element isKindOfClass:[DOMElement class]])
                     element = (DOMElement *)[element parentNode];
index 17da28d..06830d6 100644 (file)
@@ -60,7 +60,7 @@ button {
     left: 0;
     right: 0;
     color: white;
-    font-family: Lucida Grande, sans-serif;
+    font-family: 'Lucida Grande', sans-serif;
     font-size: 12px;
     text-shadow: black 0px 1px 2px;
 }
@@ -826,3 +826,52 @@ button.toggle.right {
 .treeList li.overloaded {
     text-decoration: line-through;
 }
+
+.colorSwatch {
+    display: inline-block;
+    margin-left: 4px;
+    width: 7px;
+    height: 7px;
+    border: 1px solid rgb(180,180,112);
+}
+
+#propertiesPane {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+}
+
+#jsProperties {
+    -webkit-box-flex: 1;
+    -webkit-dashboard-region: dashboard-region(control rectangle);
+}
+
+.propertyList {
+    padding: 0;
+    margin: 0;
+    list-style-type: none;
+    white-space: nowrap;
+}
+
+.propertyList ul {
+    list-style-type: none;
+    -webkit-padding-start: 10px;
+}
+
+.propertyList li {
+    line-height: 14px;
+    height: 16px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.propertyList li span {
+    -webkit-user-select: text;
+}
+
+.propertyList li .property::after {
+    content: ": ";
+}
+
+.propertyList li .value {
+    color: rgb(255,255,180);
+}
index 1a4447c..77de9a0 100644 (file)
@@ -96,7 +96,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
             </div>
         </div>
     </div>
-    <div id="metricsPane" class="pane" style="display: none; text-align: center"><br /><br /><br />(not finished)</div>
     <div id="stylePane" class="pane" style="display: none">
         <div id="noStyle" style="display: none"></div>
         <div id="styleRules" class="scrollArea">
@@ -108,7 +107,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
             <div id="stylePropertiesScrollbar" class="scrollbar"></div>
         </div>
     </div>
-    <div id="propertiesPane" class="pane" style="display: none; text-align: center"><br /><br /><br />(not finished)</div>
+    <div id="metricsPane" class="pane" style="display: none; text-align: center"><br /><br /><br />(not finished)</div>
+    <div id="propertiesPane" class="pane" style="display: none">
+        <div id="jsProperties" class="scrollArea">
+            <div class="view"><div id="jsPropertiesScrollview"><ul class="propertyList" id="jsPropertiesList"></ul></div></div>
+            <div id="jsPropertiesScrollbar" class="scrollbar"></div>
+        </div>
+    </div>
 </div>
 <div id="resize"></div>
 </div>
index 1ee468b..3c8b6bf 100644 (file)
 
 var Inspector = null;
 
+// Property values to omit in the computed style list.
+// If a property has this value, it will be omitted.
+// Note we do not provide a value for "display", "height", or "width", for example,
+// since we always want to display those.
+var typicalStylePropertyValue = {
+    "-webkit-background-clip": "border",
+    "-webkit-background-composite": "source-over",
+    "-webkit-background-origin": "padding",
+    "-webkit-background-size": "auto auto",
+    "-webkit-border-horizontal-spacing": "0px",
+    "-webkit-border-vertical-spacing": "0px",
+    "-webkit-box-align": "stretch",
+    "-webkit-box-direction": "normal",
+    "-webkit-box-flex": "0",
+    "-webkit-box-flex-group": "1",
+    "-webkit-box-lines": "single",
+    "-webkit-box-ordinal-group": "1",
+    "-webkit-box-orient": "horizontal",
+    "-webkit-box-pack": "start",
+    "-webkit-highlight": "none",
+    "-webkit-line-break": "normal",
+    "-webkit-line-clamp": "none",
+    "-webkit-marquee-direction": "auto",
+    "-webkit-marquee-increment": "6px",
+    "-webkit-marquee-repetition": "infinite",
+    "-webkit-marquee-style": "scroll",
+    "-webkit-nbsp-mode": "normal",
+    "-webkit-text-decorations-in-effect": "none",
+    "-webkit-user-modify": "read-only",
+    "background-attachment": "scroll",
+    "background-color": "rgba(0, 0, 0, 0)",
+    "background-image": "none",
+    "background-position-x": "auto",
+    "background-position-y": "auto",
+    "background-repeat": "repeat",
+    "border-bottom-color": "rgba(0, 0, 0, 0)",
+    "border-bottom-style": "none",
+    "border-bottom-width": "0px",
+    "border-collapse": "separate",
+    "border-left-color": "rgba(0, 0, 0, 0)",
+    "border-left-style": "none",
+    "border-left-width": "0px",
+    "border-right-color": "rgba(0, 0, 0, 0)",
+    "border-right-style": "none",
+    "border-right-width": "0px",
+    "border-top-color": "rgba(0, 0, 0, 0)",
+    "border-top-style": "none",
+    "border-top-width": "0px",
+    "bottom": "auto",
+    "caption-side": "top",
+    "clear": "none",
+    "color": "rgb(0, 0, 0)",
+    "cursor": "auto",
+    "direction": "ltr",
+    "empty-cells": "show",
+    "float": "none",
+    "font-style": "normal",
+    "font-variant": "normal",
+    "font-weight": "normal",
+    "left": "auto",
+    "letter-spacing": "normal",
+    "line-height": "normal",
+    "list-style-image": "none",
+    "list-style-position": "outside",
+    "list-style-type": "disc",
+    "margin-bottom": "0px",
+    "margin-left": "0px",
+    "margin-right": "0px",
+    "margin-top": "0px",
+    "max-height": "none",
+    "max-width": "none",
+    "min-height": "0px",
+    "min-width": "0px",
+    "opacity": "1",
+    "orphans": "2",
+    "outline-style": "none",
+    "overflow": "visible",
+    "overflow-x": "visible",
+    "overflow-y": "visible",
+    "padding-bottom": "0px",
+    "padding-left": "0px",
+    "padding-right": "0px",
+    "padding-top": "0px",
+    "page-break-after": "auto",
+    "page-break-before": "auto",
+    "page-break-inside": "auto",
+    "position": "static",
+    "right": "auto",
+    "table-layout": "auto",
+    "text-align": "auto",
+    "text-decoration": "none",
+    "text-indent": "0px",
+    "text-shadow": "none",
+    "text-transform": "none",
+    "top": "auto",
+    "unicode-bidi": "normal",
+    "vertical-align": "baseline",
+    "visibility": "visible",
+    "white-space": "normal",
+    "widows": "2",
+    "word-spacing": "0px",
+    "word-wrap": "normal",
+    "z-index": "normal",
+};
+
+// "Nicknames" for some common values that are easier to read.
+var valueNickname = {
+    "rgb(0, 0, 0)": "black",
+    "rgb(255, 255, 255)": "white",
+    "rgba(0, 0, 0, 0)": "transparent",
+};
+
+function setUpScrollbar(id)
+{
+    var bar = new AppleVerticalScrollbar(document.getElementById(id));
+
+    bar.setTrackStart("Images/scrollTrackTop.png", 18);
+    bar.setTrackMiddle("Images/scrollTrackMiddle.png");
+    bar.setTrackEnd("Images/scrollTrackBottom.png", 18);
+    bar.setThumbStart("Images/scrollThumbTop.png", 9);
+    bar.setThumbMiddle("Images/scrollThumbMiddle.png");
+    bar.setThumbEnd("Images/scrollThumbBottom.png", 9);
+
+    return bar;
+}
+
 function loaded()
 {
-    treeScrollbar = new AppleVerticalScrollbar(document.getElementById("treeScrollbar"));
-
-    treeScrollbar.setTrackStart("Images/scrollTrackTop.png", 18);
-    treeScrollbar.setTrackMiddle("Images/scrollTrackMiddle.png");
-    treeScrollbar.setTrackEnd("Images/scrollTrackBottom.png", 18);
-    treeScrollbar.setThumbStart("Images/scrollThumbTop.png", 9);
-    treeScrollbar.setThumbMiddle("Images/scrollThumbMiddle.png");
-    treeScrollbar.setThumbEnd("Images/scrollThumbBottom.png", 9);
-
-    nodeContentsScrollbar = new AppleVerticalScrollbar(document.getElementById("nodeContentsScrollbar"));
-    nodeContentsScrollArea = new AppleScrollArea(document.getElementById("nodeContentsScrollview"), nodeContentsScrollbar);
-
-    nodeContentsScrollbar.setTrackStart("Images/scrollTrackTop.png", 18);
-    nodeContentsScrollbar.setTrackMiddle("Images/scrollTrackMiddle.png");
-    nodeContentsScrollbar.setTrackEnd("Images/scrollTrackBottom.png", 18);
-    nodeContentsScrollbar.setThumbStart("Images/scrollThumbTop.png", 9);
-    nodeContentsScrollbar.setThumbMiddle("Images/scrollThumbMiddle.png");
-    nodeContentsScrollbar.setThumbEnd("Images/scrollThumbBottom.png", 9);
-
-    elementAttributesScrollbar = new AppleVerticalScrollbar(document.getElementById("elementAttributesScrollbar"));
-    elementAttributesScrollArea = new AppleScrollArea(document.getElementById("elementAttributesScrollview"), elementAttributesScrollbar);
-    
-    elementAttributesScrollbar.setTrackStart("Images/scrollTrackTop.png", 18);
-    elementAttributesScrollbar.setTrackMiddle("Images/scrollTrackMiddle.png");
-    elementAttributesScrollbar.setTrackEnd("Images/scrollTrackBottom.png", 18);
-    elementAttributesScrollbar.setThumbStart("Images/scrollThumbTop.png", 9);
-    elementAttributesScrollbar.setThumbMiddle("Images/scrollThumbMiddle.png");
-    elementAttributesScrollbar.setThumbEnd("Images/scrollThumbBottom.png", 9);
+    treeScrollbar = setUpScrollbar("treeScrollbar");
+
+    nodeContentsScrollArea = new AppleScrollArea(document.getElementById("nodeContentsScrollview"),
+        setUpScrollbar("nodeContentsScrollbar"));
+    elementAttributesScrollArea = new AppleScrollArea(document.getElementById("elementAttributesScrollview"),
+        setUpScrollbar("elementAttributesScrollbar"));
     
-    styleRulesScrollbar = new AppleVerticalScrollbar(document.getElementById("styleRulesScrollbar"));
-    styleRulesScrollArea = new AppleScrollArea(document.getElementById("styleRulesScrollview"), styleRulesScrollbar);
-
-    styleRulesScrollbar.setTrackStart("Images/scrollTrackTop.png", 18);
-    styleRulesScrollbar.setTrackMiddle("Images/scrollTrackMiddle.png");
-    styleRulesScrollbar.setTrackEnd("Images/scrollTrackBottom.png", 18);
-    styleRulesScrollbar.setThumbStart("Images/scrollThumbTop.png", 9);
-    styleRulesScrollbar.setThumbMiddle("Images/scrollThumbMiddle.png");
-    styleRulesScrollbar.setThumbEnd("Images/scrollThumbBottom.png", 9);
-
-    stylePropertiesScrollbar = new AppleVerticalScrollbar(document.getElementById("stylePropertiesScrollbar"));
-    stylePropertiesScrollArea = new AppleScrollArea(document.getElementById("stylePropertiesScrollview"), stylePropertiesScrollbar);
-
-    stylePropertiesScrollbar.setTrackStart("Images/scrollTrackTop.png", 18);
-    stylePropertiesScrollbar.setTrackMiddle("Images/scrollTrackMiddle.png");
-    stylePropertiesScrollbar.setTrackEnd("Images/scrollTrackBottom.png", 18);
-    stylePropertiesScrollbar.setThumbStart("Images/scrollThumbTop.png", 9);
-    stylePropertiesScrollbar.setThumbMiddle("Images/scrollThumbMiddle.png");
-    stylePropertiesScrollbar.setThumbEnd("Images/scrollThumbBottom.png", 9);
+    styleRulesScrollArea = new AppleScrollArea(document.getElementById("styleRulesScrollview"),
+        setUpScrollbar("styleRulesScrollbar"));
+    stylePropertiesScrollArea = new AppleScrollArea(document.getElementById("stylePropertiesScrollview"),
+        setUpScrollbar("stylePropertiesScrollbar"));
+
+    jsPropertiesScrollArea = new AppleScrollArea(document.getElementById("jsPropertiesScrollview"),
+        setUpScrollbar("jsPropertiesScrollbar"));
 
     treeScrollbar._getViewToContentRatio = function() {
         var contentHeight = Inspector.treeViewScrollHeight();
@@ -134,14 +226,13 @@ function loaded()
             this.horizontalScrollTo(offsetX);
     }
 
-    // Change the standard show/hide to include the parentNode.
-    // This lets out content reflow when hidden.
+    // Change the standard show/hide to include the entire scrollbar.
+    // This lets the content reflow to use the additional space when the scrollbar is hidden.
     AppleScrollbar.prototype.hide = function() {
         this._track.style.display = "none";
         this.scrollbar.style.display = "none";
         this.hidden = true;
     }
-
     AppleScrollbar.prototype.show = function() {
         this._track.style.display = "block";
         this.scrollbar.style.display = null;
@@ -156,13 +247,11 @@ function loaded()
 
 function refreshScrollbars()
 {
-    if (currentPane == "node") {
-        nodeContentsScrollArea.refresh();
-        elementAttributesScrollArea.refresh();
-    } else if (currentPane == "style") {
-        styleRulesScrollArea.refresh();
-        stylePropertiesScrollArea.refresh();
-    }
+    elementAttributesScrollArea.refresh();
+    jsPropertiesScrollArea.refresh();
+    nodeContentsScrollArea.refresh();
+    stylePropertiesScrollArea.refresh();
+    styleRulesScrollArea.refresh();
 }
 
 var searchActive = false;
@@ -188,21 +277,9 @@ function performSearch(query)
     Inspector.searchPerformed(query);
 }
 
-function resultsWithXpathQuery(query)
-{
-    var nodeList = null;
-    try {
-        var focusedNode = Inspector.focusedDOMNode();
-        nodeList = focusedNode.document.evaluate(query, focusedNode.document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
-    } catch(err) {
-        // ignore any exceptions. the query might be malformed, but we allow that
-    }
-    return nodeList;
-}
-
 var tabNames = ["node","metrics","style","properties"];
 var currentPane = "node";
-var paneUpdateState = new Array();
+var paneUpdateState = [];
 var noSelection = false;
 
 function toggleNoSelection(state)
@@ -262,40 +339,6 @@ function nodeTypeName(node)
     return "(unknown)";
 }
 
-function xpathForNode(node)
-{
-    var path = "";
-    while (node) {
-        if (node.nodeType == Node.DOCUMENT_NODE) {
-            path = "/" + path;
-        } else {
-            if (node.nodeName == "HTML" || node.nodeName == "BODY") {
-                path = node.nodeName.toLowerCase() + (path.length ? "/" + path : "");
-            } else {
-                var index = 1;
-                var child = (node.parentNode ? node.parentNode.firstChild : null);
-                while (child) {
-                    if (node == child)
-                        break;
-                    if (child.nodeName == node.nodeName)
-                        index++;
-                    child = child.nextSibling;
-                }
-                
-                var name = node.nodeName.toLowerCase();
-                if (node.nodeType == Node.TEXT_NODE)
-                    name = "text()";
-
-                path = name + "[" + index + "]" + (path.length ? "/" + path : "");
-            }
-        }
-
-        node = node.parentNode;
-    }
-
-    return path;
-}
-
 function updatePanes()
 {
     for (var i = 0; i < tabNames.length; i++)
@@ -346,7 +389,8 @@ function updateElementAttributes()
     elementAttributesScrollArea.refresh();
 }
 
-function updateNodePane() {
+function updateNodePane()
+{
     var focusedNode = Inspector.focusedDOMNode();
 
     if (focusedNode.nodeType == Node.TEXT_NODE || focusedNode.nodeType == Node.COMMENT_NODE) {
@@ -384,33 +428,36 @@ function updateNodePane() {
 var styleRules = null;
 var selectedStyleRuleIndex = 0;
 var styleProperties = null;
-var expandedStyleShorthands = new Array();
+var expandedStyleShorthands = [];
 
 function updateStylePane()
 {
     var focusedNode = Inspector.focusedDOMNode();
+    if (focusedNode.nodeType == Node.TEXT_NODE && focusedNode.parentNode && focusedNode.parentNode.nodeType == Node.ELEMENT_NODE)
+        focusedNode = focusedNode.parentNode;
     var rulesArea = document.getElementById("styleRulesScrollview");
     var propertiesArea = document.getElementById("stylePropertiesTree");
 
     rulesArea.innerHTML = "";
     propertiesArea.innerHTML = "";
-    styleRules = new Array();
-    styleProperties = new Array();
+    styleRules = [];
+    styleProperties = [];
 
     if (focusedNode.nodeType == Node.ELEMENT_NODE) {
         document.getElementById("styleRules").style.display = null;
         document.getElementById("styleProperties").style.display = null;
         document.getElementById("noStyle").style.display = "none";
 
-        var propertyCount = new Array();
+        var propertyCount = [];
 
         var computedStyle = focusedNode.ownerDocument.defaultView.getComputedStyle(focusedNode, "");
-        if (computedStyle) {
-            var computedObj = new Object();
-            computedObj.computedStyle = true;
-            computedObj.selectorText = "Computed Style";
-            computedObj.style = computedStyle;
-            computedObj.subtitle = "";
+        if (computedStyle && computedStyle.length) {
+            var computedObj = {
+                isComputedStyle: true,
+                selectorText: "Computed Style",
+                style: computedStyle,
+                subtitle: "",
+            };
             styleRules.push(computedObj);
         }
 
@@ -418,14 +465,15 @@ function updateStylePane()
         for (var i = 0; i < focusedNode.attributes.length; i++) {
             var attr = focusedNode.attributes[i];
             if (attr.style) {
-                var attrStyle = new Object();
-                attrStyle.attr = attr.name;
+                var attrStyle = {
+                    attrName: attr.name,
+                    style: attr.style,
+                    subtitle: "element\u2019s \u201C" + attr.name + "\u201D attribute",
+                };
                 attrStyle.selectorText = focusedNodeName + "[" + attr.name;
                 if (attr.value.length)
                     attrStyle.selectorText += "=" + attr.value;
                 attrStyle.selectorText += "]";
-                attrStyle.style = attr.style;
-                attrStyle.subtitle = "element's \"" + attr.name + "\" attribute";
                 styleRules.push(attrStyle);
             }
         }
@@ -438,10 +486,11 @@ function updateStylePane()
         }
 
         if (focusedNode.style.length) {
-            var inlineStyle = new Object();
-            inlineStyle.selectorText = "Inline Style Attribute";
-            inlineStyle.style = focusedNode.style;
-            inlineStyle.subtitle = "element's \"style\" attribute";
+            var inlineStyle = {
+                selectorText: "Inline Style Attribute",
+                style: focusedNode.style,
+                subtitle: "element\u2019s \u201Cstyle\u201D attribute",
+            };
             styleRules.push(inlineStyle);
         }
 
@@ -450,13 +499,13 @@ function updateStylePane()
 
         var priorityUsed = false;
         for (var i = (styleRules.length - 1); i >= 0; --i) {
-            styleProperties[i] = new Array();
+            styleProperties[i] = [];
 
             var row = document.createElement("div");
             row.className = "row";
             if (i == selectedStyleRuleIndex)
                 row.className += " focused";
-            if (styleRules[i].computedStyle)
+            if (styleRules[i].isComputedStyle)
                 row.className += " computedStyle";
 
             var cell = document.createElement("div");
@@ -480,7 +529,7 @@ function updateStylePane()
             row.addEventListener("click", styleRuleSelect, true);
 
             var style = styleRules[i].style;
-            var styleShorthandLookup = new Array();
+            var styleShorthandLookup = [];
             for (var j = 0; j < style.length; j++) {
                 var prop = null;
                 var name = style[j];
@@ -494,11 +543,12 @@ function updateStylePane()
                 if (prop) {
                     prop.subProperties.push(name);
                 } else {
-                    prop = new Object();
-                    prop.style = style;
-                    prop.subProperties = new Array(name);
-                    prop.unusedProperties = new Array();
-                    prop.name = (shorthand ? shorthand : name);
+                    prop = {
+                        style: style,
+                        subProperties: [name],
+                        unusedProperties: [],
+                        name: (shorthand ? shorthand : name),
+                    };
                     styleProperties[i].push(prop);
                     if (shorthand) {
                         styleShorthandLookup[shorthand] = prop;
@@ -511,7 +561,7 @@ function updateStylePane()
                     }
                 }
 
-                if (styleRules[i].computedStyle)
+                if (styleRules[i].isComputedStyle)
                     continue;
 
                 if (!propertyCount[name]) {
@@ -522,7 +572,7 @@ function updateStylePane()
                 }
             }
 
-            if (styleRules[i].computedStyle && styleRules.length > 1) {
+            if (styleRules[i].isComputedStyle && styleRules.length > 1) {
                 var divider = document.createElement("hr");
                 divider.className = "divider";
                 rulesArea.insertBefore(divider, rulesArea.firstChild);
@@ -536,11 +586,11 @@ function updateStylePane()
 
         if (priorityUsed) {
             // walk the properties again and account for !important
-            var priorityCount = new Array();
+            var priorityCount = [];
             for (var i = 0; i < styleRules.length; i++) {
-                var style = styleRules[i].style;
-                if (style.computedStyle)
+                if (styleRules[i].isComputedStyle)
                     continue;
+                var style = styleRules[i].style;
                 for (var j = 0; j < styleProperties[i].length; j++) {
                     var prop = styleProperties[i][j];
                     for (var k = 0; k < prop.subProperties.length; k++) {
@@ -589,6 +639,35 @@ function styleRuleSelect(event)
     updateStyleProperties();
 }
 
+function populateStyleListItem(li, prop, name)
+{
+    var value = prop.style.getPropertyValue(name);
+
+    var span = document.createElement("span");
+    span.className = "property";
+    span.textContent = name;
+    li.appendChild(span);
+
+    span = document.createElement("span");
+    span.className = "value";
+    var textValue = valueNickname[value] ? valueNickname[value] : value;
+    var priority = prop.style.getPropertyPriority(name);
+    if (priority.length)
+        textValue += " !" + priority;
+    span.textContent = textValue;
+    li.appendChild(span);
+
+    var colors = value.match(/(rgb\([0-9]+, [0-9]+, [0-9]+\))|(rgba\([0-9]+, [0-9]+, [0-9]+, [0-9]+\))/g);
+    if (colors) {
+        for (var k = 0; k < colors.length; k++) {
+            var swatch = document.createElement("span");
+            swatch.className = "colorSwatch";
+            swatch.style.backgroundColor = colors[k];
+            li.appendChild(swatch);
+        }
+    }
+}
+
 function updateStyleProperties()
 {
     var focusedNode = Inspector.focusedDOMNode();
@@ -601,38 +680,31 @@ function updateStyleProperties()
     }
 
     var properties = styleProperties[selectedStyleRuleIndex];
+    var omitTypicalValues = styleRules[selectedStyleRuleIndex].isComputedStyle;
     for (var i = 0; i < properties.length; i++) {
         var prop = properties[i];
+        var name = prop.name;
+        if (omitTypicalValues && typicalStylePropertyValue[name] == prop.style.getPropertyValue(name))
+            continue;
+
         var mainli = document.createElement("li");
         if (prop.subProperties.length > 1) {
             mainli.className = "hasChildren";
-            if (expandedStyleShorthands[prop.name])
+            if (expandedStyleShorthands[name])
                 mainli.className += " expanded";
-            mainli.shorthand = prop.name;
+            mainli.shorthand = name;
             var button = document.createElement("button");
             button.addEventListener("click", toggleStyleShorthand, false);
             mainli.appendChild(button);
         }
 
-        var span = document.createElement("span");
-        span.className = "property";
-        span.textContent = prop.name;
-        mainli.appendChild(span);
-
-        span = document.createElement("span");
-        span.className = "value";
-        span.title = prop.style.getPropertyValue(prop.name);
-        if (prop.style.getPropertyPriority(prop.name).length)
-            span.title += " !" + prop.style.getPropertyPriority(prop.name);
-        span.textContent = span.title;
-        mainli.appendChild(span);
-
+        populateStyleListItem(mainli, prop, name);
         propertiesTree.appendChild(mainli);
 
         var overloadCount = 0;
         if (prop.subProperties && prop.subProperties.length > 1) {
             var subTree = document.createElement("ul");
-            if (!expandedStyleShorthands[prop.name])
+            if (!expandedStyleShorthands[name])
                 subTree.style.display = "none";
 
             for (var j = 0; j < prop.subProperties.length; j++) {
@@ -641,31 +713,19 @@ function updateStyleProperties()
                 if (prop.style.isPropertyImplicit(name) || prop.style.getPropertyValue(name) == "initial")
                     li.className = "implicit";
 
-                if (prop.unusedProperties[name] || prop.unusedProperties[prop.name]) {
+                if (prop.unusedProperties[name] || prop.unusedProperties[name]) {
                     li.className += " overloaded";
                     overloadCount++;
                 }
 
-                var span = document.createElement("span");
-                span.className = "property";
-                span.textContent = name;
-                li.appendChild(span);
-
-                span = document.createElement("span");
-                span.className = "value";
-                span.title = prop.style.getPropertyValue(name);
-                if (prop.style.getPropertyPriority(name).length)
-                    span.title += " !" + prop.style.getPropertyPriority(name);
-                span.textContent = span.title;
-                li.appendChild(span);
-
+                populateStyleListItem(li, prop, name);
                 subTree.appendChild(li);
             }
 
             propertiesTree.appendChild(subTree);
         }
 
-        if (prop.unusedProperties[prop.name] || overloadCount == prop.subProperties.length)
+        if (prop.unusedProperties[name] || overloadCount == prop.subProperties.length)
             mainli.className += " overloaded";
     }
 
@@ -694,7 +754,7 @@ function selectMappedStyleRule(attrName)
         updateStylePane();
 
     for (var i = 0; i < styleRules.length; i++)
-        if (styleRules[i].attr == attrName)
+        if (styleRules[i].attrName == attrName)
             break;
 
     selectedStyleRuleIndex = i;
@@ -722,4 +782,31 @@ function updateMetricsPane()
 
 function updatePropertiesPane()
 {
+    // FIXME: Like the style pane, this should have a top item that's "all properties"
+    // and separate items for each item in the prototype chain. For now, we implement
+    // only the "all properties" part, and only for enumerable properties.
+
+    var focusedNode = Inspector.focusedDOMNode();
+    var list = document.getElementById("jsPropertiesList");
+    list.innerHTML = "";
+
+    for (var name in focusedNode) {
+        var li = document.createElement("li");
+
+        var span = document.createElement("span");
+        span.className = "property";
+        span.textContent = name;
+        li.appendChild(span);
+
+        var value = focusedNode[name];
+
+        span = document.createElement("span");
+        span.className = "value";
+        span.textContent = value;
+        li.appendChild(span);
+
+        list.appendChild(li);
+    }
+
+    jsPropertiesScrollArea.refresh();
 }