Bug 944246 - Make getComputedStyle pass in anonymous content when resolving pseudo-element style. r=bz
authorCameron McCormack <cam@mcc.id.au>
Tue, 03 Dec 2013 10:57:50 +1100
changeset 173077 01b2208631534b2fea48d847a625734532de8c22
parent 173076 b7e96ff87420ae219bf4de16e5798705c5b432f5
child 173078 75eedf5dfb51e80e8dbacbb23ab5cb18c55c9d6c
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs944246
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 944246 - Make getComputedStyle pass in anonymous content when resolving pseudo-element style. r=bz
layout/forms/nsColorControlFrame.cpp
layout/forms/nsColorControlFrame.h
layout/forms/nsMeterFrame.cpp
layout/forms/nsMeterFrame.h
layout/forms/nsNumberControlFrame.cpp
layout/forms/nsNumberControlFrame.h
layout/forms/nsProgressFrame.cpp
layout/forms/nsProgressFrame.h
layout/forms/nsRangeFrame.cpp
layout/forms/nsRangeFrame.h
layout/forms/nsTextControlFrame.cpp
layout/forms/nsTextControlFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/style/nsComputedDOMStyle.cpp
layout/style/test/test_pseudoelement_state.html
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -130,8 +130,18 @@ nsColorControlFrame::AttributeChanged(in
                                                     aModType);
 }
 
 nsIFrame*
 nsColorControlFrame::GetContentInsertionFrame()
 {
   return this;
 }
+
+nsIContent*
+nsColorControlFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  if (aType == nsCSSPseudoElements::ePseudo_mozColorSwatch) {
+    return mColorContent;
+  }
+
+  return nsContainerFrame::GetPseudoElementContent(aType);
+}
--- a/layout/forms/nsColorControlFrame.h
+++ b/layout/forms/nsColorControlFrame.h
@@ -39,16 +39,18 @@ public:
 
   // nsIFrame
   NS_IMETHOD AttributeChanged(int32_t  aNameSpaceID,
                               nsIAtom* aAttribute,
                               int32_t  aModType) MOZ_OVERRIDE;
   virtual bool IsLeaf() const MOZ_OVERRIDE { return true; }
   virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE;
 
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
+
 private:
   nsColorControlFrame(nsStyleContext* aContext);
 
   // Update the color swatch
   nsresult UpdateColor();
 
   nsCOMPtr<nsIContent> mColorContent;
 };
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -273,8 +273,17 @@ nsMeterFrame::ShouldUseNativeStyle() con
   return StyleDisplay()->mAppearance == NS_THEME_METERBAR &&
          mBarDiv->GetPrimaryFrame()->StyleDisplay()->mAppearance == NS_THEME_METERBAR_CHUNK &&
          !PresContext()->HasAuthorSpecifiedRules(const_cast<nsMeterFrame*>(this),
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
          !PresContext()->HasAuthorSpecifiedRules(mBarDiv->GetPrimaryFrame(),
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
 }
 
+nsIContent*
+nsMeterFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  if (aType == nsCSSPseudoElements::ePseudo_mozMeterBar) {
+    return mBarDiv;
+  }
+
+  return nsContainerFrame::GetPseudoElementContent(aType);
+}
--- a/layout/forms/nsMeterFrame.h
+++ b/layout/forms/nsMeterFrame.h
@@ -61,16 +61,18 @@ public:
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
    * Returns whether the frame and its child should use the native style.
    */
   bool ShouldUseNativeStyle() const;
 
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
+
 protected:
   // Helper function which reflow the anonymous div frame.
   void ReflowBarFrame(nsIFrame*                aBarFrame,
                       nsPresContext*           aPresContext,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus);
   /**
    * The div used to show the meter bar.
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -373,8 +373,34 @@ nsNumberControlFrame::UpdateForValueChan
     return;
   }
   // We need to update the value of our anonymous text control here. Note that
   // this must be its value, and not its 'value' attribute (the default value),
   // since the default value is ignored once a user types into the text
   // control.
   HTMLInputElement::FromContent(mTextField)->SetValue(aValue);
 }
+
+nsIContent*
+nsNumberControlFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  if (aType == nsCSSPseudoElements::ePseudo_mozNumberWrapper) {
+    return mOuterWrapper;
+  }
+
+  if (aType == nsCSSPseudoElements::ePseudo_mozNumberText) {
+    return mTextField;
+  }
+
+  if (aType == nsCSSPseudoElements::ePseudo_mozNumberSpinBox) {
+    return mSpinBox;
+  }
+
+  if (aType == nsCSSPseudoElements::ePseudo_mozNumberSpinUp) {
+    return mSpinUp;
+  }
+
+  if (aType == nsCSSPseudoElements::ePseudo_mozNumberSpinDown) {
+    return mSpinDown;
+  }
+
+  return nsContainerFrame::GetPseudoElementContent(aType);
+}
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -100,16 +100,18 @@ public:
    * Returns one of the SpinButtonEnum values to depending on whether the
    * pointer event is over the spin-up button, the spin-down button, or
    * neither.
    */
   int32_t GetSpinButtonForPointerEvent(WidgetGUIEvent* aEvent) const;
 
   void HandleFocusEvent(WidgetEvent* aEvent);
 
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
+
 private:
 
   nsresult MakeAnonymousElement(nsIContent** aResult,
                                 nsTArray<ContentInfo>& aElements,
                                 nsIAtom* aTagName,
                                 nsCSSPseudoElements::Type aPseudoType,
                                 nsStyleContext* aParentContext);
 
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -283,8 +283,17 @@ nsProgressFrame::ShouldUseNativeStyle() 
   return StyleDisplay()->mAppearance == NS_THEME_PROGRESSBAR &&
          mBarDiv->GetPrimaryFrame()->StyleDisplay()->mAppearance == NS_THEME_PROGRESSBAR_CHUNK &&
          !PresContext()->HasAuthorSpecifiedRules(const_cast<nsProgressFrame*>(this),
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
          !PresContext()->HasAuthorSpecifiedRules(mBarDiv->GetPrimaryFrame(),
                                                  NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
 }
 
+nsIContent*
+nsProgressFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  if (aType == nsCSSPseudoElements::ePseudo_mozProgressBar) {
+    return mBarDiv;
+  }
+
+  return nsContainerFrame::GetPseudoElementContent(aType);
+}
--- a/layout/forms/nsProgressFrame.h
+++ b/layout/forms/nsProgressFrame.h
@@ -66,16 +66,18 @@ public:
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   /**
    * Returns whether the frame and its child should use the native style.
    */
   bool ShouldUseNativeStyle() const;
 
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
+
 protected:
   // Helper function which reflow the anonymous div frame.
   void ReflowBarFrame(nsIFrame*                aBarFrame,
                       nsPresContext*           aPresContext,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus);
 
   /**
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -827,8 +827,26 @@ nsRangeFrame::ShouldUseNativeStyle() con
                                                   NS_AUTHOR_SPECIFIED_BACKGROUND)) &&
          !PresContext()->HasAuthorSpecifiedRules(mTrackDiv->GetPrimaryFrame(),
                                                  STYLES_DISABLING_NATIVE_THEMING) &&
          !PresContext()->HasAuthorSpecifiedRules(mProgressDiv->GetPrimaryFrame(),
                                                  STYLES_DISABLING_NATIVE_THEMING) &&
          !PresContext()->HasAuthorSpecifiedRules(mThumbDiv->GetPrimaryFrame(),
                                                  STYLES_DISABLING_NATIVE_THEMING);
 }
+
+nsIContent*
+nsRangeFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  if (aType == nsCSSPseudoElements::ePseudo_mozRangeTrack) {
+    return mTrackDiv;
+  }
+
+  if (aType == nsCSSPseudoElements::ePseudo_mozRangeThumb) {
+    return mThumbDiv;
+  }
+
+  if (aType == nsCSSPseudoElements::ePseudo_mozRangeProgress) {
+    return mProgressDiv;
+  }
+
+  return nsContainerFrame::GetPseudoElementContent(aType);
+}
--- a/layout/forms/nsRangeFrame.h
+++ b/layout/forms/nsRangeFrame.h
@@ -117,16 +117,18 @@ public:
    * Helper that's used when the value of the range changes to reposition the
    * thumb, resize the range-progress element, and schedule a repaint. (This
    * does not reflow, since the position and size of the thumb and
    * range-progress element do not affect the position or size of any other
    * frames.)
    */
   void UpdateForValueChange();
 
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
+
 private:
 
   nsresult MakeAnonymousDiv(nsIContent** aResult,
                             nsCSSPseudoElements::Type aPseudoType,
                             nsTArray<ContentInfo>& aElements);
 
   // Helper function which reflows the anonymous div frames.
   nsresult ReflowAnonymousContent(nsPresContext*           aPresContext,
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -1427,16 +1427,27 @@ nsTextControlFrame::BuildDisplayList(nsD
     if (kid->GetContent() != txtCtrl->GetPlaceholderNode() ||
         txtCtrl->GetPlaceholderVisibility()) {
       BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, 0);
     }
     kid = kid->GetNextSibling();
   }
 }
 
+nsIContent*
+nsTextControlFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  if (aType == nsCSSPseudoElements::ePseudo_mozPlaceholder) {
+    nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
+    return txtCtrl->GetPlaceholderNode();
+  }
+
+  return nsContainerFrame::GetPseudoElementContent(aType);
+}
+
 NS_IMETHODIMP
 nsTextControlFrame::EditorInitializer::Run()
 {
   if (!mFrame) {
     return NS_OK;
   }
 
   // Need to block script to avoid bug 669767.
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -89,16 +89,18 @@ public:
 
   NS_IMETHOD SetInitialChildList(ChildListID     aListID,
                                  nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
+
 //==== BEGIN NSIFORMCONTROLFRAME
   virtual void SetFocus(bool aOn , bool aRepaint) MOZ_OVERRIDE; 
   virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE;
 
 //==== END NSIFORMCONTROLFRAME
 
 //==== NSITEXTCONTROLFRAME
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -8100,16 +8100,30 @@ nsIFrame::DestroyRegion(void* aPropertyV
 bool
 nsIFrame::IsPseudoStackingContextFromStyle() {
   const nsStyleDisplay* disp = StyleDisplay();
   return disp->mOpacity != 1.0f ||
          disp->IsPositioned(this) ||
          disp->IsFloating(this);
 }
 
+nsIContent*
+nsIFrame::GetPseudoElementContent(nsCSSPseudoElements::Type aType)
+{
+  nsIFrame* frame = nullptr;
+
+  if (aType == nsCSSPseudoElements::ePseudo_before) {
+    frame = nsLayoutUtils::GetBeforeFrame(this);
+  } else if (aType == nsCSSPseudoElements::ePseudo_after) {
+    frame = nsLayoutUtils::GetAfterFrame(this);
+  }
+
+  return frame ? frame->GetContent() : nullptr;
+}
+
 nsIFrame::ContentOffsets::ContentOffsets()
 {
 }
 
 nsIFrame::ContentOffsets::ContentOffsets(const ContentOffsets& rhs)
   : content(rhs.content),
     offset(rhs.offset),
     secondaryOffset(rhs.secondaryOffset),
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3016,16 +3016,23 @@ NS_PTR_TO_INT32(frame->Properties().Get(
   /**
    * Return whether this is a frame whose width is used when computing
    * the font size inflation of its descendants.
    */
   bool IsContainerForFontSizeInflation() const {
     return GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER;
   }
 
+  /**
+   * Returns the content node within the anonymous content that this frame
+   * generated and which corresponds to the specified pseudo-element type,
+   * or nullptr if there is no such anonymous content.
+   */
+  virtual nsIContent* GetPseudoElementContent(nsCSSPseudoElements::Type aType);
+
 protected:
   // Members
   nsRect           mRect;
   nsIContent*      mContent;
   nsStyleContext*  mStyleContext;
   nsIFrame*        mParent;
 private:
   nsIFrame*        mNextSibling;  // doubly-linked list of frames
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -483,18 +483,26 @@ nsComputedDOMStyle::GetStyleContextForEl
   nsStyleSet *styleSet = presShell->StyleSet();
 
   nsRefPtr<nsStyleContext> sc;
   if (aPseudo) {
     nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo);
     if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) {
       return nullptr;
     }
+    Element* pseudoElement = nullptr;
+    nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
+    if (frame) {
+      nsIContent* pseudoContent = frame->GetPseudoElementContent(type);
+      if (pseudoContent && pseudoContent->IsElement()) {
+        pseudoElement = pseudoContent->AsElement();
+      }
+    }
     sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
-                                             nullptr);
+                                             pseudoElement);
   } else {
     sc = styleSet->ResolveStyleFor(aElement, parentContext);
   }
 
   if (aStyleType == eDefaultOnly) {
     // We really only want the user and UA rules.  Filter out the other ones.
     nsTArray< nsCOMPtr<nsIStyleRule> > rules;
     for (nsRuleNode* ruleNode = sc->RuleNode();
--- a/layout/style/test/test_pseudoelement_state.html
+++ b/layout/style/test/test_pseudoelement_state.html
@@ -8,65 +8,72 @@
 <iframe src="data:text/html,<!DOCTYPE html><style></style><div></div>"></iframe>
 
 <script>
 var gIsAndroid = navigator.appVersion.indexOf("Android") != -1;
 
 var gTests = [
   // Interact with the ::-moz-progress-bar.
   { markup:                 '<progress value="75" max="100"></progress>',
+    pseudoelement:          '::-moz-progress-bar',
     common_style:           'progress { -moz-appearance: none; } progress::-moz-progress-bar { background: black; }',
     hover_test_style:       'progress::-moz-progress-bar:hover { background: green; }',
     hover_reference_style:  'progress::-moz-progress-bar { background: green; }',
     active_test_style:      'progress::-moz-progress-bar:active { background: lime; }',
     active_reference_style: 'progress::-moz-progress-bar { background: lime; }' },
 
   // Interact with the part of the <progress> not covered by the ::-moz-progress-bar.
   { markup:                 '<progress value="25" max="100"></progress>',
-    common_style:           'progress { -moz-appearance: none; }',
+    pseudoelement:          '::-moz-progress-bar',
+    common_style:           'progress { -moz-appearance: none; } progress::-moz-progress-bar { background: black; }',
     hover_test_style:       'progress::-moz-progress-bar { background: green; } progress::-moz-progress-bar:hover { background: red; }',
     hover_reference_style:  'progress::-moz-progress-bar { background: green; }',
     active_test_style:      'progress::-moz-progress-bar { background: lime; } progress::-moz-progress-bar:active { background: red; }',
     active_reference_style: 'progress::-moz-progress-bar { background: lime; }' },
 
   // Interact with the ::-moz-range-thumb.
   { markup:                 '<input type="range" value="50" min="0" max="100">',
+    pseudoelement:          '::-moz-range-thumb',
     common_style:           'input { -moz-appearance: none; } input::-moz-range-thumb { background: black; }',
     hover_test_style:       'input::-moz-range-thumb:hover { background: green; }',
     hover_reference_style:  'input::-moz-range-thumb { background: green; }',
     active_test_style:      'input::-moz-range-thumb:active { background: lime; }',
     active_reference_style: 'input::-moz-range-thumb { background: lime; }' },
 
   // Interact with the part of the <input type="range"> not covered by the ::-moz-range-thumb.
   { markup:                 '<input type="range" value="25" min="0" max="100">',
-    common_style:           'input { -moz-appearance: none; }',
+    pseudoelement:          '::-moz-range-thumb',
+    common_style:           'input { -moz-appearance: none; } input::-moz-range-thumb { background: black; }',
     hover_test_style:       'input::-moz-range-thumb { background: green; } input::-moz-range-thumb:hover { background: red; }',
     hover_reference_style:  'input::-moz-range-thumb { background: green; }',
     active_test_style:      'input::-moz-range-thumb { background: lime; } input::-moz-range-thumb:active { background: red; }',
     active_reference_style: 'input::-moz-range-thumb { background: lime; }' },
 
   // Interact with the ::-moz-meter-bar.
   { markup:                 '<meter value="75" min="0" max="100"></meter>',
+    pseudoelement:          '::-moz-meter-bar',
     common_style:           'meter { -moz-appearance: none; } meter::-moz-meter-bar { background: black; }',
     hover_test_style:       'meter::-moz-meter-bar:hover { background: green; }',
     hover_reference_style:  'meter::-moz-meter-bar { background: green; }',
     active_test_style:      'meter::-moz-meter-bar:active { background: lime; }',
     active_reference_style: 'meter::-moz-meter-bar { background: lime; }' },
 
   // Interact with the part of the <meter> not covered by the ::-moz-meter-bar.
   { markup:                 '<meter value="25" min="0" max="100"></meter>',
-    common_style:           'meter { -moz-appearance: none; }',
+    pseudoelement:          '::-moz-meter-bar',
+    common_style:           'meter { -moz-appearance: none; } meter::-moz-meter-bar { background: black; }',
     hover_test_style:       'meter::-moz-meter-bar { background: green; } meter::-moz-meter-bar:hover { background: red; }',
     hover_reference_style:  'meter::-moz-meter-bar { background: green; }',
     active_test_style:      'meter::-moz-meter-bar { background: lime; } meter::-moz-meter-bar:active { background: red; }',
     active_reference_style: 'meter::-moz-meter-bar { background: lime; }' },
 
   // Do the same as the "Interact with the ::-moz-range-thumb" subtest above,
   // but with selectors that include descendant operators.
   { markup:                 '<input type="range" value="50" min="0" max="100">',
+    pseudoelement:          '::-moz-range-thumb',
     common_style:           'body input { -moz-appearance: none; } input::-moz-range-thumb { background: black; }',
     hover_test_style:       'body input::-moz-range-thumb:hover { background: green; }',
     hover_reference_style:  'body input::-moz-range-thumb { background: green; }',
     active_test_style:      'body input::-moz-range-thumb:active { background: lime; }',
     active_reference_style: 'body input::-moz-range-thumb { background: lime; }' },
 
   // ::-moz-placeholder can't be tested, since the UA style sheet sets it to
   // be pointer-events:none.
@@ -93,31 +100,34 @@ function runTests() {
   var iframe = document.querySelector("iframe");
   var style = iframe.contentDocument.querySelector("style");
   var div = iframe.contentDocument.querySelector("div");
   var canvas1, canvas2;
 
   function runTestPart1(aIndex) {
     var test = gTests[aIndex];
     div.innerHTML = test.markup;
-    style.textContent = test.common_style + test.hover_test_style;
+    style.textContent = test.common_style;
+    is(getComputedStyle(div.firstChild, test.pseudoelement).backgroundColor, "rgb(0, 0, 0)", "subtest #" + aIndex + ", computed style");
+    style.textContent += test.hover_test_style;
     synthesizeMouseAtCenter(div.lastChild, { type: 'mouseover' }, iframe.contentWindow);
   }
 
   function runTestPart2(aIndex) {
     var test = gTests[aIndex];
     canvas1 = SpecialPowers.snapshotWindow(iframe.contentWindow, false);
     style.textContent = test.common_style + test.hover_reference_style;
   }
 
   function runTestPart3(aIndex) {
     var test = gTests[aIndex];
     canvas2 = SpecialPowers.snapshotWindow(iframe.contentWindow, false);
     ok(canvas1.width == canvas2.width && canvas1.height == canvas2.height, "hover subtest #" + aIndex + ", canvas sizes equal");
     is(countPixelDifferences(canvas1, canvas2), 0, "hover subtest #" + aIndex + ", number of different pixels");
+    is(getComputedStyle(div.firstChild, test.pseudoelement).backgroundColor, "rgb(0, 128, 0)", "hover subtest #" + aIndex + ", computed style");
 
     if (!gIsAndroid) {
       style.textContent = test.common_style + test.active_test_style;
       synthesizeMouseAtCenter(div.lastChild, { type: 'mousedown' }, iframe.contentWindow);
     }
   }
 
   function runTestPart4(aIndex) {
@@ -126,19 +136,21 @@ function runTests() {
       canvas1 = SpecialPowers.snapshotWindow(iframe.contentWindow, false);
       synthesizeMouseAtCenter(div.lastChild, { type: 'mouseup' }, iframe.contentWindow);
       style.textContent = test.common_style + test.active_reference_style;
     }
   }
 
   function runTestPart5(aIndex) {
     if (!gIsAndroid) {
+      var test = gTests[aIndex];
       canvas2 = SpecialPowers.snapshotWindow(iframe.contentWindow, false);
       ok(canvas1.width == canvas2.width && canvas1.height == canvas2.height, "active subtest #" + aIndex + ", canvas sizes equal");
       is(countPixelDifferences(canvas1, canvas2), 0, "active subtest #" + aIndex + ", number of different pixels");
+      is(getComputedStyle(div.firstChild, test.pseudoelement).backgroundColor, "rgb(0, 255, 0)", "active subtest #" + aIndex + ", computed style");
     }
   }
 
   for (var i = 0; i < gTests.length; i++) {
     setTimeout(runTestPart1, 0, i);
     setTimeout(runTestPart2, 0, i);
     setTimeout(runTestPart3, 0, i);
     setTimeout(runTestPart4, 0, i);