Bug 1326209 - Change background-color to use complex color. r?dholbert draft
authorXidorn Quan <me@upsuper.org>
Fri, 30 Dec 2016 01:58:13 +1100
changeset 454481 1956787e4a4ed7fcadbee05006613833a99955a2
parent 454387 df543cecccfd10f91d136e07eb9c21f5ac7f6bef
child 540723 c5df1f5f11f10603fd49d44d6a06754fafcff7ef
push id39946
push userxquan@mozilla.com
push dateThu, 29 Dec 2016 14:58:49 +0000
reviewersdholbert
bugs1326209
milestone53.0a1
Bug 1326209 - Change background-color to use complex color. r?dholbert MozReview-Commit-ID: sSPtxzIf9H
accessible/base/TextAttrs.cpp
accessible/html/HTMLTableAccessible.cpp
accessible/windows/ia2/ia2AccessibleComponent.cpp
layout/base/nsLayoutUtils.cpp
layout/forms/nsListControlFrame.cpp
layout/generic/nsFrame.cpp
layout/mathml/nsMathMLChar.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/test_transitions_per_property.html
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableFrame.cpp
widget/nsNativeTheme.cpp
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -369,20 +369,19 @@ TextAttrsMgr::BGColorTextAttr::
   nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::backgroundColor,
                          formattedValue);
 }
 
 bool
 TextAttrsMgr::BGColorTextAttr::
   GetColor(nsIFrame* aFrame, nscolor* aColor)
 {
-  const nsStyleBackground* styleBackground = aFrame->StyleBackground();
-
-  if (NS_GET_A(styleBackground->mBackgroundColor) > 0) {
-    *aColor = styleBackground->mBackgroundColor;
+  nscolor backgroundColor = aFrame->StyleBackground()->BackgroundColor(aFrame);
+  if (NS_GET_A(backgroundColor) > 0) {
+    *aColor = backgroundColor;
     return true;
   }
 
   nsContainerFrame *parentFrame = aFrame->GetParent();
   if (!parentFrame) {
     *aColor = aFrame->PresContext()->DefaultBackgroundColor();
     return true;
   }
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -1070,17 +1070,17 @@ HTMLTableAccessible::IsProbablyLayoutTab
   uint32_t childCount = ChildCount();
   nscolor rowColor = 0;
   nscolor prevRowColor;
   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
     Accessible* child = GetChildAt(childIdx);
     if (child->Role() == roles::ROW) {
       prevRowColor = rowColor;
       nsIFrame* rowFrame = child->GetFrame();
-      rowColor = rowFrame->StyleBackground()->mBackgroundColor;
+      rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
 
       if (childIdx > 0 && prevRowColor != rowColor)
         RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
     }
   }
 
   // Check for many rows
   const uint32_t kMaxLayoutRows = 20;
--- a/accessible/windows/ia2/ia2AccessibleComponent.cpp
+++ b/accessible/windows/ia2/ia2AccessibleComponent.cpp
@@ -112,16 +112,17 @@ ia2AccessibleComponent::get_background(I
 
   *aBackground = 0;
 
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   nsIFrame* frame = acc->GetFrame();
-  if (frame)
-    *aBackground = frame->StyleBackground()->mBackgroundColor;
+  if (frame) {
+    *aBackground = frame->StyleBackground()->BackgroundColor(frame);
+  }
 
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6846,17 +6846,17 @@ nsLayoutUtils::GetFrameTransparency(nsIF
     return eTransparencyOpaque;
   }
 
   nsStyleContext* bgSC;
   if (!nsCSSRendering::FindBackground(aBackgroundFrame, &bgSC)) {
     return eTransparencyTransparent;
   }
   const nsStyleBackground* bg = bgSC->StyleBackground();
-  if (NS_GET_A(bg->mBackgroundColor) < 255 ||
+  if (NS_GET_A(bg->BackgroundColor(bgSC)) < 255 ||
       // bottom layer's clip is used for the color
       bg->BottomLayer().mClip != StyleGeometryBox::Border)
     return eTransparencyTransparent;
   return eTransparencyOpaque;
 }
 
 static bool IsPopupFrame(nsIFrame* aFrame)
 {
@@ -8793,18 +8793,19 @@ nsLayoutUtils::ComputeScrollMetadata(nsI
   // This is needed for APZ overscrolling support.
   if (aScrollFrame) {
     if (isRootScrollFrame) {
       metadata.SetBackgroundColor(Color::FromABGR(
         presShell->GetCanvasBackground()));
     } else {
       nsStyleContext* backgroundStyle;
       if (nsCSSRendering::FindBackground(aScrollFrame, &backgroundStyle)) {
-        metadata.SetBackgroundColor(Color::FromABGR(
-          backgroundStyle->StyleBackground()->mBackgroundColor));
+        nscolor backgroundColor = backgroundStyle->
+          StyleBackground()->BackgroundColor(backgroundStyle);
+        metadata.SetBackgroundColor(Color::FromABGR(backgroundColor));
       }
     }
   }
 
   if (ShouldDisableApzForElement(aContent)) {
     metadata.SetForceDisableApz(true);
   }
 
@@ -9327,9 +9328,9 @@ nsLayoutUtils::ComputeGeometryBox(nsIFra
   // element, which does have an associated CSS layout box. In this case we
   // should still use ComputeHTMLReferenceRect for region computing.
   nsRect r = aFrame->IsFrameOfType(nsIFrame::eSVG) &&
              (aFrame->GetType() != nsGkAtoms::svgOuterSVGFrame)
              ? ComputeSVGReferenceRect(aFrame, aGeometryBox)
              : ComputeHTMLReferenceRect(aFrame, aGeometryBox);
 
   return r;
-}
\ No newline at end of file
+}
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -1448,17 +1448,17 @@ nsListControlFrame::AboutToDropDown()
   // backgrounds. We compose with the PresContext default background color,
   // which is always opaque, in case we don't end up with an opaque color.
   // This gives us a very poor approximation of translucency.
   nsIFrame* comboboxFrame = do_QueryFrame(mComboboxFrame);
   nsStyleContext* context = comboboxFrame->StyleContext()->GetParent();
   mLastDropdownBackstopColor = NS_RGBA(0,0,0,0);
   while (NS_GET_A(mLastDropdownBackstopColor) < 255 && context) {
     mLastDropdownBackstopColor =
-      NS_ComposeColors(context->StyleBackground()->mBackgroundColor,
+      NS_ComposeColors(context->StyleBackground()->BackgroundColor(context),
                        mLastDropdownBackstopColor);
     context = context->GetParent();
   }
   mLastDropdownBackstopColor =
     NS_ComposeColors(PresContext()->DefaultBackgroundColor(),
                      mLastDropdownBackstopColor);
 
   if (mIsAllContentHere && mIsAllFramesHere && mHasBeenInitialized) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1889,17 +1889,17 @@ bool
 nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
                                         const nsDisplayListSet& aLists,
                                         bool aForceBackground)
 {
   // Here we don't try to detect background propagation. Frames that might
   // receive a propagated background should just set aForceBackground to
   // true.
   if (aBuilder->IsForEventDelivery() || aForceBackground ||
-      !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) {
+      !StyleBackground()->IsTransparent(this) || StyleDisplay()->mAppearance) {
     return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
         aBuilder, this, GetRectRelativeToSelf(), aLists.BorderBackground());
   }
   return false;
 }
 
 void
 nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder*   aBuilder,
@@ -5385,17 +5385,17 @@ nsIFrame::ComputeTightBounds(DrawTarget*
 {
   return GetVisualOverflowRect();
 }
 
 nsRect
 nsFrame::ComputeSimpleTightBounds(DrawTarget* aDrawTarget) const
 {
   if (StyleOutline()->mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE ||
-      StyleBorder()->HasBorder() || !StyleBackground()->IsTransparent() ||
+      StyleBorder()->HasBorder() || !StyleBackground()->IsTransparent(this) ||
       StyleDisplay()->mAppearance) {
     // Not necessarily tight, due to clipping, negative
     // outline-offset, and lots of other issues, but that's OK
     return GetVisualOverflowRect();
   }
 
   nsRect r(0, 0, 0, 0);
   ChildListIterator lists(this);
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1981,19 +1981,19 @@ nsMathMLChar::Display(nsDisplayListBuild
   // color we use it -- this feature is mostly used for testing and debugging
   // purposes. Normally, users will set the background on the container frame.
   // paint the selection background -- beware MathML frames overlap a lot
   if (aSelectedRect && !aSelectedRect->IsEmpty()) {
     aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
       nsDisplayMathMLSelectionRect(aBuilder, aForFrame, *aSelectedRect));
   }
   else if (mRect.width && mRect.height) {
-    const nsStyleBackground* backg = styleContext->StyleBackground();
     if (styleContext != parentContext &&
-        NS_GET_A(backg->mBackgroundColor) > 0) {
+        NS_GET_A(styleContext->StyleBackground()->
+                 BackgroundColor(styleContext)) > 0) {
       nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
         aBuilder, aForFrame, mRect, aLists.BorderBackground(),
         /* aAllowWillPaintBorderOptimization */ true, styleContext);
     }
     //else
     //  our container frame will take care of painting its background
 
 #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1187,18 +1187,19 @@ nsCSSRendering::FindNonTransparentBackgr
   }
   if (!frame) {
     frame = aFrame;
   }
 
   while (frame) {
     // No need to call GetVisitedDependentColor because it always uses
     // this alpha component anyway.
-    if (NS_GET_A(frame->StyleBackground()->mBackgroundColor) > 0)
+    if (NS_GET_A(frame->StyleBackground()->BackgroundColor(frame)) > 0) {
       break;
+    }
 
     if (frame->IsThemed())
       break;
 
     nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
     if (!parent)
       break;
 
@@ -1222,17 +1223,17 @@ nsCSSRendering::IsCanvasFrame(nsIFrame* 
 }
 
 nsIFrame*
 nsCSSRendering::FindBackgroundStyleFrame(nsIFrame* aForFrame)
 {
   const nsStyleBackground* result = aForFrame->StyleBackground();
 
   // Check if we need to do propagation from BODY rather than HTML.
-  if (!result->IsTransparent()) {
+  if (!result->IsTransparent(aForFrame)) {
     return aForFrame;
   }
 
   nsIContent* content = aForFrame->GetContent();
   // The root element content can't be null. We wouldn't know what
   // frame to create for aFrame.
   // Use |OwnerDoc| so it works during destruction.
   if (!content) {
@@ -1328,17 +1329,17 @@ FindElementBackground(nsIFrame* aForFram
 
   // This can be called even when there's no root element yet, during frame
   // construction, via nsLayoutUtils::FrameHasTransparency and
   // nsContainerFrame::SyncFrameViewProperties.
   if (!aRootElementFrame)
     return true;
 
   const nsStyleBackground* htmlBG = aRootElementFrame->StyleBackground();
-  return !htmlBG->IsTransparent();
+  return !htmlBG->IsTransparent(aRootElementFrame);
 }
 
 bool
 nsCSSRendering::FindBackground(nsIFrame* aForFrame,
                                nsStyleContext** aBackgroundSC)
 {
   nsIFrame* rootElementFrame =
     aForFrame->PresContext()->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
@@ -2244,17 +2245,17 @@ nsCSSRendering::DetermineBackgroundColor
       aDrawBackgroundColor = false;
     }
   } else {
     // If GetBackgroundColorDraw() is false, we are still expected to
     // draw color in the background of any frame that's not completely
     // transparent, but we are expected to use white instead of whatever
     // color was specified.
     bgColor = NS_RGB(255, 255, 255);
-    if (aDrawBackgroundImage || !bg->IsTransparent()) {
+    if (aDrawBackgroundImage || !bg->IsTransparent(aStyleContext)) {
       aDrawBackgroundColor = true;
     } else {
       bgColor = NS_RGBA(0,0,0,0);
     }
   }
 
   // We can skip painting the background color if a background image is opaque.
   nsStyleImageLayers::Repeat repeat = bg->BottomLayer().mRepeat;
@@ -4459,27 +4460,27 @@ GetDashInfo(nscoord  aBorderLength,
       nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
       aStartDashLength += half;
       aEndDashLength += (extra - half);
     }
   }
 }
 
 void
-nsCSSRendering::DrawTableBorderSegment(DrawTarget&              aDrawTarget,
-                                       uint8_t                  aBorderStyle,
-                                       nscolor                  aBorderColor,
-                                       const nsStyleBackground* aBGColor,
-                                       const nsRect&            aBorder,
-                                       int32_t                  aAppUnitsPerDevPixel,
-                                       int32_t                  aAppUnitsPerCSSPixel,
-                                       uint8_t                  aStartBevelSide,
-                                       nscoord                  aStartBevelOffset,
-                                       uint8_t                  aEndBevelSide,
-                                       nscoord                  aEndBevelOffset)
+nsCSSRendering::DrawTableBorderSegment(DrawTarget&   aDrawTarget,
+                                       uint8_t       aBorderStyle,
+                                       nscolor       aBorderColor,
+                                       nscolor       aBGColor,
+                                       const nsRect& aBorder,
+                                       int32_t       aAppUnitsPerDevPixel,
+                                       int32_t       aAppUnitsPerCSSPixel,
+                                       uint8_t       aStartBevelSide,
+                                       nscoord       aStartBevelOffset,
+                                       uint8_t       aEndBevelSide,
+                                       nscoord       aEndBevelOffset)
 {
   bool horizontal = ((eSideTop == aStartBevelSide) || (eSideBottom == aStartBevelSide));
   nscoord twipsPerPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerCSSPixel);
   uint8_t ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
 
   if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
       (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
     // no beveling for 1 pixel border, dash or dot
@@ -4559,18 +4560,17 @@ nsCSSRendering::DrawTableBorderSegment(D
       nscoord startBevel = (aStartBevelOffset > 0)
                             ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, true) : 0;
       nscoord endBevel =   (aEndBevelOffset > 0)
                             ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, true) : 0;
       mozilla::Side ridgeGrooveSide = (horizontal) ? eSideTop : eSideLeft;
       // FIXME: In theory, this should use the visited-dependent
       // background color, but I don't care.
       nscolor bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
-                                          aBGColor->mBackgroundColor,
-                                          aBorderColor);
+                                          aBGColor, aBorderColor);
       nsRect rect(aBorder);
       nscoord half;
       if (horizontal) { // top, bottom
         half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
         rect.height = half;
         if (eSideTop == aStartBevelSide) {
           rect.x += startBevel;
           rect.width -= startBevel;
@@ -4599,17 +4599,17 @@ nsCSSRendering::DrawTableBorderSegment(D
                                endBevel);
       }
 
       rect = aBorder;
       ridgeGrooveSide = (eSideTop == ridgeGrooveSide) ? eSideBottom : eSideRight;
       // FIXME: In theory, this should use the visited-dependent
       // background color, but I don't care.
       bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
-                                  aBGColor->mBackgroundColor, aBorderColor);
+                                  aBGColor, aBorderColor);
       if (horizontal) {
         rect.y = rect.y + half;
         rect.height = aBorder.height - half;
         if (eSideBottom == aStartBevelSide) {
           rect.x += startBevel;
           rect.width -= startBevel;
         }
         if (eSideBottom == aEndBevelSide) {
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -709,27 +709,27 @@ struct nsCSSRendering {
    * Called when we've finished using a display list. When all
    * BeginFrameTreeLocked calls have been balanced by an EndFrameTreeLocked,
    * the frame tree may start changing again.
    */
   static void EndFrameTreesLocked();
 
   // Draw a border segment in the table collapsing border model without
   // beveling corners
-  static void DrawTableBorderSegment(DrawTarget&          aDrawTarget,
-                                     uint8_t              aBorderStyle,
-                                     nscolor              aBorderColor,
-                                     const nsStyleBackground* aBGColor,
-                                     const nsRect&        aBorderRect,
-                                     int32_t              aAppUnitsPerDevPixel,
-                                     int32_t              aAppUnitsPerCSSPixel,
-                                     uint8_t              aStartBevelSide = 0,
-                                     nscoord              aStartBevelOffset = 0,
-                                     uint8_t              aEndBevelSide = 0,
-                                     nscoord              aEndBevelOffset = 0);
+  static void DrawTableBorderSegment(DrawTarget&   aDrawTarget,
+                                     uint8_t       aBorderStyle,
+                                     nscolor       aBorderColor,
+                                     nscolor       aBGColor,
+                                     const nsRect& aBorderRect,
+                                     int32_t       aAppUnitsPerDevPixel,
+                                     int32_t       aAppUnitsPerCSSPixel,
+                                     uint8_t       aStartBevelSide = 0,
+                                     nscoord       aStartBevelOffset = 0,
+                                     uint8_t       aEndBevelSide = 0,
+                                     nscoord       aEndBevelOffset = 0);
 
   // NOTE: pt, dirtyRect, lineSize, ascent, offset in the following
   //       structs are non-rounded device pixels, not app units.
   struct DecorationRectParams
   {
     // The width [length] and the height [thickness] of the decoration
     // line. This is a "logical" size in textRun orientation, so that
     // for a vertical textrun, width will actually be a physical height;
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -533,17 +533,17 @@ CSS_PROP_BACKGROUND(
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
         CSS_PROPERTY_HASHLESS_COLOR_QUIRK,
     "",
     VARIANT_HC,
     nullptr,
     offsetof(nsStyleBackground, mBackgroundColor),
-    eStyleAnimType_Color)
+    eStyleAnimType_ComplexColor)
 CSS_PROP_BACKGROUND(
     background-image,
     background_image,
     BackgroundImage,
     CSS_PROPERTY_PARSE_VALUE_LIST |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1865,17 +1865,17 @@ nsComputedDOMStyle::DoGetBackgroundClip(
                            StyleBackground()->mImage,
                            nsCSSProps::kBackgroundClipKTable);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBackgroundColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  SetToRGBAColor(val, StyleBackground()->mBackgroundColor);
+  SetValueFromComplexColor(val, StyleBackground()->mBackgroundColor);
   return val.forget();
 }
 
 static void
 SetValueToCalc(const nsStyleCoord::CalcValue* aCalc,
                nsROCSSPrimitiveValue*         aValue)
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7411,27 +7411,23 @@ nsRuleNode::ComputeBackgroundData(void* 
                                   const nsRuleData* aRuleData,
                                   nsStyleContext* aContext,
                                   nsRuleNode* aHighestNode,
                                   const RuleDetail aRuleDetail,
                                   const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_RESET(Background, bg, parentBG)
 
-  // background-color: color, string, inherit
-  const nsCSSValue* backColorValue = aRuleData->ValueForBackgroundColor();
-  if (eCSSUnit_Initial == backColorValue->GetUnit() ||
-      eCSSUnit_Unset == backColorValue->GetUnit()) {
-    bg->mBackgroundColor = NS_RGBA(0, 0, 0, 0);
-  } else if (!SetColor(*backColorValue, parentBG->mBackgroundColor,
-                       mPresContext, aContext, bg->mBackgroundColor,
-                       conditions)) {
-    NS_ASSERTION(eCSSUnit_Null == backColorValue->GetUnit(),
-                 "unexpected color unit");
-  }
+  // background-color: color, inherit
+  SetComplexColor<eUnsetInitial>(*aRuleData->ValueForBackgroundColor(),
+                                 parentBG->mBackgroundColor,
+                                 StyleComplexColor::FromColor(
+                                     NS_RGBA(0, 0, 0, 0)),
+                                 mPresContext,
+                                 bg->mBackgroundColor, conditions);
 
   uint32_t maxItemCount = 1;
   bool rebuild = false;
 
   // background-image: url (stored as image), none, inherit [list]
   nsStyleImage initialImage;
   SetImageLayerList(aContext, *aRuleData->ValueForBackgroundImage(),
                     bg->mImage.mLayers,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2876,17 +2876,17 @@ nsStyleImageLayers::Layer::CalcDifferenc
 }
 
 // --------------------
 // nsStyleBackground
 //
 
 nsStyleBackground::nsStyleBackground(StyleStructContext aContext)
   : mImage(nsStyleImageLayers::LayerType::Background)
-  , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
+  , mBackgroundColor(StyleComplexColor::FromColor(NS_RGBA(0, 0, 0, 0)))
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
 }
 
 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
   : mImage(aSource.mImage)
   , mBackgroundColor(aSource.mBackgroundColor)
 {
@@ -2938,22 +2938,44 @@ nsStyleBackground::HasFixedBackground(ns
         !layer.mImage.IsEmpty() &&
         !nsLayoutUtils::IsTransformed(aFrame)) {
       return true;
     }
   }
   return false;
 }
 
+nscolor
+nsStyleBackground::BackgroundColor(const nsIFrame* aFrame) const
+{
+  return BackgroundColor(aFrame->StyleContext());
+}
+
+nscolor
+nsStyleBackground::BackgroundColor(nsStyleContext* aContext) const
+{
+  // In majority of cases, background-color should just be a numeric color.
+  // In that case, we can skip resolving StyleColor().
+  return mBackgroundColor.IsNumericColor()
+    ? mBackgroundColor.mColor
+    : aContext->StyleColor()->CalcComplexColor(mBackgroundColor);
+}
+
 bool
-nsStyleBackground::IsTransparent() const
+nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const
+{
+  return IsTransparent(aFrame->StyleContext());
+}
+
+bool
+nsStyleBackground::IsTransparent(nsStyleContext* aContext) const
 {
   return BottomLayer().mImage.IsEmpty() &&
          mImage.mImageCount == 1 &&
-         NS_GET_A(mBackgroundColor) == 0;
+         NS_GET_A(BackgroundColor(aContext)) == 0;
 }
 
 void
 nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
 {
   switch (aTimingFunctionType) {
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
       mType = Type::StepStart;
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -937,33 +937,38 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
            nsChangeHint_NeutralChange;
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants at all.
     return nsChangeHint(0);
   }
 
+  // Return the background color as nscolor.
+  nscolor BackgroundColor(const nsIFrame* aFrame) const;
+  nscolor BackgroundColor(nsStyleContext* aContext) const;
+
   // True if this background is completely transparent.
-  bool IsTransparent() const;
+  bool IsTransparent(const nsIFrame* aFrame) const;
+  bool IsTransparent(nsStyleContext* aContext) const;
 
   // We have to take slower codepaths for fixed background attachment,
   // but we don't want to do that when there's no image.
   // Not inline because it uses an nsCOMPtr<imgIRequest>
   // FIXME: Should be in nsStyleStructInlines.h.
   bool HasFixedBackground(nsIFrame* aFrame) const;
 
   // Checks to see if this has a non-empty image with "local" attachment.
   // This is defined in nsStyleStructInlines.h.
   inline bool HasLocalBackground() const;
 
   const nsStyleImageLayers::Layer& BottomLayer() const { return mImage.BottomLayer(); }
 
   nsStyleImageLayers mImage;
-  nscolor mBackgroundColor;       // [reset]
+  mozilla::StyleComplexColor mBackgroundColor;       // [reset]
 };
 
 #define NS_SPACING_MARGIN   0
 #define NS_SPACING_PADDING  1
 #define NS_SPACING_BORDER   2
 
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -78,17 +78,17 @@ var supported_properties = {
     "column-width": [ test_length_transition,
                       test_length_clamped ],
     "-moz-image-region": [ test_rect_transition ],
     "-moz-outline-radius-bottomleft": [ test_radius_transition ],
     "-moz-outline-radius-bottomright": [ test_radius_transition ],
     "-moz-outline-radius-topleft": [ test_radius_transition ],
     "-moz-outline-radius-topright": [ test_radius_transition ],
     "background-color": [ test_color_transition,
-                          test_currentcolor_transition ],
+                          test_true_currentcolor_transition ],
     "background-position": [ test_background_position_transition,
                              // FIXME: We don't currently test clamping,
                              // since background-position uses calc() as
                              // an intermediate form.
                              /* test_length_percent_pair_unclamped */ ],
     "background-position-x": [ test_background_position_coord_transition,
                                test_length_transition,
                                test_percent_transition,
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -315,21 +315,20 @@ nsTableCellFrame::DecorateForSelection(D
       if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
         bordercolor = NS_RGB(176,176,176);// disabled color
       }
       else {
         bordercolor =
           LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground);
       }
       nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3);
-      if ((mRect.width > threePx) && (mRect.height > threePx))
-      {
-        //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
-        bordercolor = EnsureDifferentColors(bordercolor,
-                                            StyleBackground()->mBackgroundColor);
+      if ((mRect.width > threePx) && (mRect.height > threePx)) {
+        //compare bordercolor to background-color
+        bordercolor = EnsureDifferentColors(
+          bordercolor, StyleBackground()->BackgroundColor(this));
 
         int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
         Point devPixelOffset = NSPointToPoint(aPt, appUnitsPerDevPixel);
 
         AutoRestoreTransform autoRestoreTransform(aDrawTarget);
         aDrawTarget->SetTransform(
           aDrawTarget->GetTransform().PreTranslate(devPixelOffset));
 
@@ -496,17 +495,18 @@ nsTableCellFrame::BuildDisplayList(nsDis
       bool hasBoxShadow = !!StyleEffects()->mBoxShadow;
       if (hasBoxShadow) {
         aLists.BorderBackground()->AppendNewToTop(
           new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
       }
     
       // display background if we need to.
       if (aBuilder->IsForEventDelivery() ||
-          !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) {
+          !StyleBackground()->IsTransparent(this) ||
+          StyleDisplay()->mAppearance) {
         if (!tableFrame->IsBorderCollapse() ||
             aBuilder->IsAtRootOfPseudoStackingContext() ||
             aBuilder->IsForEventDelivery()) {
           // The cell background was not painted by the nsTablePainter,
           // so we need to do it. We have special background processing here
           // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline
           nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder,
               this,
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1280,17 +1280,17 @@ nsTableFrame::DisplayGenericTablePart(ns
 static inline bool FrameHasBorderOrBackground(nsTableFrame* tableFrame, nsIFrame* f)
 {
   if (!f->StyleVisibility()->IsVisible()) {
     return false;
   }
   if (f->StyleBorder()->HasBorder()) {
     return true;
   }
-  if (!f->StyleBackground()->IsTransparent() ||
+  if (!f->StyleBackground()->IsTransparent(f) ||
       f->StyleDisplay()->mAppearance) {
     
     nsTableCellFrame *cellFrame = do_QueryFrame(f);
     // We could also return false here if the current frame is the root
     // of a pseudo stacking context
     if (cellFrame && !tableFrame->IsBorderCollapse()) {
       return false;
     }
@@ -6357,17 +6357,17 @@ public:
   void StoreColumnWidth(int32_t aIndex);
   bool BlockDirSegmentOwnsCorner();
 
   nsTableFrame*         mTable;
   nsTableFrame*         mTableFirstInFlow;
   nsTableCellMap*       mTableCellMap;
   nsCellMap*            mCellMap;
   WritingMode           mTableWM;
-  const nsStyleBackground* mTableBgColor;
+  nscolor               mTableBgColor;
   nsTableFrame::RowGroupArray mRowGroups;
 
   nsTableRowGroupFrame* mPrevRg;
   nsTableRowGroupFrame* mRg;
   bool                  mIsRepeatedHeader;
   bool                  mIsRepeatedFooter;
   nsTableRowGroupFrame* mStartRg; // first row group in the damagearea
   int32_t               mRgIndex; // current row group index in the
@@ -6475,17 +6475,17 @@ BCPaintBorderIterator::BCPaintBorderIter
 
   // Get the ordered row groups
   mTable->OrderRowGroups(mRowGroups);
   // initialize to a non existing index
   mRepeatedHeaderRowIndex = -99;
 
   nsIFrame* bgFrame =
     nsCSSRendering::FindNonTransparentBackgroundFrame(aTable);
-  mTableBgColor = bgFrame->StyleBackground();
+  mTableBgColor = bgFrame->StyleBackground()->BackgroundColor(bgFrame);
 }
 
 bool
 BCPaintBorderIterator::SetDamageArea(const nsRect& aDirtyRect)
 {
   nsSize containerSize = mTable->GetSize();
   LogicalRect dirtyRect(mTableWM, aDirtyRect, containerSize);
   uint32_t startRowIndex, endRowIndex, startColIndex, endColIndex;
--- a/widget/nsNativeTheme.cpp
+++ b/widget/nsNativeTheme.cpp
@@ -754,22 +754,22 @@ nsNativeTheme::IsDarkBackground(nsIFrame
     // color which prevents that of the body frame to propagate to the viewport.
     nsIFrame* bodyFrame = GetBodyFrame(frame);
     if (bodyFrame) {
       frame = bodyFrame;
     }
   }
   nsStyleContext* bgSC = nullptr;
   if (!nsCSSRendering::FindBackground(frame, &bgSC) ||
-      bgSC->StyleBackground()->IsTransparent()) {
+      bgSC->StyleBackground()->IsTransparent(bgSC)) {
     nsIFrame* backgroundFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(frame, true);
     nsCSSRendering::FindBackground(backgroundFrame, &bgSC);
   }
   if (bgSC) {
-    nscolor bgColor = bgSC->StyleBackground()->mBackgroundColor;
+    nscolor bgColor = bgSC->StyleBackground()->BackgroundColor(bgSC);
     // Consider the background color dark if the sum of the r, g and b values is
     // less than 384 in a semi-transparent document.  This heuristic matches what
     // WebKit does, and we can improve it later if needed.
     return NS_GET_A(bgColor) > 127 &&
            NS_GET_R(bgColor) + NS_GET_G(bgColor) + NS_GET_B(bgColor) < 384;
   }
   return false;
 }