Bug 1258286: Part 1 - add layer types to nsStyleImageLayers and layer initialization. r=heycam
☠☠ backed out by c2b9ede08259 ☠ ☠
authorAstley Chen <aschen@mozilla.com>
Wed, 01 Jun 2016 11:00:58 +0800
changeset 324335 a9db7e5634d7a6aa9e1c32f6722a010c27c1d55f
parent 324334 d7246e5a52b1f3e6f5f3a51fce569dec1072fe63
child 324336 d5832177887d706bd0d8c86576eb40e535f15512
push id9671
push userraliiev@mozilla.com
push dateMon, 06 Jun 2016 20:27:52 +0000
treeherdermozilla-aurora@cea65ca3d0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1258286
milestone49.0a1
Bug 1258286: Part 1 - add layer types to nsStyleImageLayers and layer initialization. r=heycam MozReview-Commit-ID: ENLXAEA62Bm
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -6099,20 +6099,20 @@ nsComputedDOMStyle::DoGetMask()
   // need to support computed style for the cases where it used  to be
   // a longhand.
   if (svg->mMask.mImageCount > 1 ||
       firstLayer.mClip != NS_STYLE_IMAGELAYER_CLIP_BORDER ||
       firstLayer.mOrigin != NS_STYLE_IMAGELAYER_ORIGIN_PADDING ||
       firstLayer.mComposite != NS_STYLE_MASK_COMPOSITE_ADD ||
       firstLayer.mMaskMode != NS_STYLE_MASK_MODE_MATCH_SOURCE ||
       !firstLayer.mPosition.IsInitialValue() ||
-      !firstLayer.mRepeat.IsInitialValue() ||
+      !firstLayer.mRepeat.IsInitialValue(nsStyleImageLayers::LayerType::Mask) ||
       !firstLayer.mSize.IsInitialValue() ||
       !(firstLayer.mImage.GetType() == eStyleImageType_Null ||
-          firstLayer.mImage.GetType() == eStyleImageType_Image)){
+        firstLayer.mImage.GetType() == eStyleImageType_Image)) {
     return nullptr;
   }
 
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   if (firstLayer.mSourceURI) {
     val->SetURI(firstLayer.mSourceURI);
   } else {
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7083,17 +7083,17 @@ nsRuleNode::ComputeBackgroundData(void* 
                     parentBG->mImage.mLayers,
                     &nsStyleImageLayers::Layer::mImage,
                     initialImage, parentBG->mImage.mImageCount,
                     bg->mImage.mImageCount,
                     maxItemCount, rebuild, conditions);
 
   // background-repeat: enum, inherit, initial [pair list]
   nsStyleImageLayers::Repeat initialRepeat;
-  initialRepeat.SetInitialValues();
+  initialRepeat.SetInitialValues(nsStyleImageLayers::LayerType::Background);
   SetImageLayerPairList(aContext, *aRuleData->ValueForBackgroundRepeat(),
                         bg->mImage.mLayers,
                         parentBG->mImage.mLayers,
                         &nsStyleImageLayers::Layer::mRepeat,
                         initialRepeat, parentBG->mImage.mRepeatCount,
                         bg->mImage.mRepeatCount, maxItemCount, rebuild,
                         conditions);
 
@@ -9892,17 +9892,17 @@ nsRuleNode::ComputeSVGResetData(void* aS
                     parentSVGReset->mMask.mLayers,
                     &nsStyleImageLayers::Layer::mSourceURI,
                     nsCOMPtr<nsIURI>(), parentSVGReset->mMask.mImageCount,
                     svgReset->mMask.mImageCount,
                     maxItemCount, rebuild, conditions);
 
   // mask-repeat: enum, inherit, initial [pair list]
   nsStyleImageLayers::Repeat initialRepeat;
-  initialRepeat.SetInitialValues();
+  initialRepeat.SetInitialValues(nsStyleImageLayers::LayerType::Mask);
   SetImageLayerPairList(aContext, *aRuleData->ValueForMaskRepeat(),
                         svgReset->mMask.mLayers,
                         parentSVGReset->mMask.mLayers,
                         &nsStyleImageLayers::Layer::mRepeat,
                         initialRepeat, parentSVGReset->mMask.mRepeatCount,
                         svgReset->mMask.mRepeatCount, maxItemCount, rebuild,
                         conditions);
 
@@ -9916,17 +9916,17 @@ nsRuleNode::ComputeSVGResetData(void* aS
                     svgReset->mMask.mClipCount, maxItemCount, rebuild,
                     conditions);
 
   // mask-origin: enum, inherit, initial [list]
   SetImageLayerList(aContext, *aRuleData->ValueForMaskOrigin(),
                     svgReset->mMask.mLayers,
                     parentSVGReset->mMask.mLayers,
                     &nsStyleImageLayers::Layer::mOrigin,
-                    uint8_t(NS_STYLE_IMAGELAYER_ORIGIN_PADDING),
+                    uint8_t(NS_STYLE_IMAGELAYER_ORIGIN_BORDER),
                     parentSVGReset->mMask.mOriginCount,
                     svgReset->mMask.mOriginCount, maxItemCount, rebuild,
                     conditions);
 
   // mask-position-x/y: enum, length, percent (flags), inherit [list]
   nsStyleImageLayers::Position::PositionCoord initialPositionCoord;
   initialPositionCoord.mPercent = 0.0f;
   initialPositionCoord.mLength = 0;
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -42,49 +42,53 @@ static_assert((((1 << nsStyleStructID_Le
                ~(NS_STYLE_INHERIT_MASK)) == 0,
               "Not enough bits in NS_STYLE_INHERIT_MASK");
 
 // These are the limits that we choose to clamp grid line numbers to.
 // http://dev.w3.org/csswg/css-grid/#overlarge-grids
 const int32_t nsStyleGridLine::kMinLine = -10000;
 const int32_t nsStyleGridLine::kMaxLine = 10000;
 
-static bool EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
+static bool
+EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
 {
   bool eq;
   return aURI1 == aURI2 ||    // handle null==null, and optimize
          (aURI1 && aURI2 &&
           NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
           eq);
 }
 
-static bool EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2)
+static bool
+EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2)
 {
   return aURI1 == aURI2 ||    // handle null==null, and optimize
          (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
 }
 
-static bool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
+static bool
+EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
 {
   if (aImage1 == aImage2) {
     return true;
   }
 
   if (!aImage1 || !aImage2) {
     return false;
   }
 
   nsCOMPtr<nsIURI> uri1, uri2;
   aImage1->GetURI(getter_AddRefs(uri1));
   aImage2->GetURI(getter_AddRefs(uri2));
   return EqualURIs(uri1, uri2);
 }
 
 // A nullsafe wrapper for strcmp. We depend on null-safety.
-static int safe_strcmp(const char16_t* a, const char16_t* b)
+static int
+safe_strcmp(const char16_t* a, const char16_t* b)
 {
   if (!a || !b) {
     return (int)(a - b);
   }
   return NS_strcmp(a, b);
 }
 
 int32_t
@@ -98,18 +102,17 @@ StyleStructContext::HackilyFindSomeDevic
 {
   nsCOMPtr<nsIAppShellService> appShell(do_GetService("@mozilla.org/appshell/appShellService;1"));
   MOZ_ASSERT(appShell);
   nsCOMPtr<mozIDOMWindowProxy> win;
   appShell->GetHiddenDOMWindow(getter_AddRefs(win));
   return nsLayoutUtils::GetDeviceContextForScreenInfo(static_cast<nsPIDOMWindowOuter*>(win.get()));
 }
 
-static bool AreShadowArraysEqual(nsCSSShadowArray* lhs,
-                                 nsCSSShadowArray* rhs);
+static bool AreShadowArraysEqual(nsCSSShadowArray* lhs, nsCSSShadowArray* rhs);
 
 // --------------------
 // nsStyleFont
 //
 nsStyleFont::nsStyleFont(const nsFont& aFont, StyleStructContext aContext)
   : mFont(aFont)
   , mSize(nsStyleFont::ZoomText(aContext, mFont.size))
   , mGenericID(kGenericFont_NONE)
@@ -175,17 +178,18 @@ nsStyleFont::EnableZoom(nsPresContext* a
   } else {
     mSize = nsStyleFont::UnZoomText(aContext, mSize);
     mFont.size = nsStyleFont::UnZoomText(aContext, mFont.size);
     mScriptUnconstrainedSize =
       nsStyleFont::UnZoomText(aContext, mScriptUnconstrainedSize);
   }
 }
 
-nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aOther) const
+nsChangeHint
+nsStyleFont::CalcDifference(const nsStyleFont& aOther) const
 {
   MOZ_ASSERT(mAllowZoom == aOther.mAllowZoom,
              "expected mAllowZoom to be the same on both nsStyleFonts");
   if (mSize != aOther.mSize ||
       mFont != aOther.mFont ||
       mLanguage != aOther.mLanguage ||
       mExplicitLanguage != aOther.mExplicitLanguage ||
       mMathVariant != aOther.mMathVariant ||
@@ -232,19 +236,18 @@ nsStyleFont::GetLanguage(StyleStructCont
     // NOTE this should not be used elsewhere, because we want websites
     // to use UTF-8 with proper language tag, instead of relying on
     // deriving language from charset. See bug 1040668 comment 67.
     language = aContext.GetLanguageFromCharset();
   }
   return language.forget();
 }
 
-static nscoord CalcCoord(const nsStyleCoord& aCoord, 
-                         const nscoord* aEnumTable, 
-                         int32_t aNumEnums)
+static nscoord
+CalcCoord(const nsStyleCoord& aCoord, const nscoord* aEnumTable, int32_t aNumEnums)
 {
   if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
     MOZ_ASSERT(aEnumTable, "must have enum table");
     int32_t value = aCoord.GetIntValue();
     if (0 <= value && value < aNumEnums) {
       return aEnumTable[aCoord.GetIntValue()];
     }
     NS_NOTREACHED("unexpected enum value");
@@ -271,17 +274,18 @@ nsStyleMargin::nsStyleMargin(const nsSty
 
 void 
 nsStyleMargin::Destroy(nsPresContext* aContext) {
   this->~nsStyleMargin();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStyleMargin, this);
 }
 
-nsChangeHint nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const
+nsChangeHint
+nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const
 {
   if (mMargin == aOther.mMargin) {
     return NS_STYLE_HINT_NONE;
   }
   // Margin differences can't affect descendant intrinsic sizes and
   // don't need to force children to reflow.
   return nsChangeHint_NeedReflow |
          nsChangeHint_ReflowChangesSizeOrPosition |
@@ -305,36 +309,37 @@ nsStylePadding::nsStylePadding(const nsS
 
 void 
 nsStylePadding::Destroy(nsPresContext* aContext) {
   this->~nsStylePadding();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStylePadding, this);
 }
 
-nsChangeHint nsStylePadding::CalcDifference(const nsStylePadding& aOther) const
+nsChangeHint
+nsStylePadding::CalcDifference(const nsStylePadding& aOther) const
 {
   if (mPadding == aOther.mPadding) {
     return NS_STYLE_HINT_NONE;
   }
   // Padding differences can't affect descendant intrinsic sizes, but do need
   // to force children to reflow so that we can reposition them, since their
   // offsets are from our frame bounds but our content rect's position within
   // those bounds is moving.
   return NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
 }
 
 nsStyleBorder::nsStyleBorder(StyleStructContext aContext)
-  : mBorderColors(nullptr),
-    mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
-    mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
-    mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
-    mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT_BOX),
-    mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE),
-    mComputedBorder(0, 0, 0, 0)
+  : mBorderColors(nullptr)
+  , mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL)
+  , mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
+  , mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
+  , mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT_BOX)
+  , mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE)
+  , mComputedBorder(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   NS_FOR_CSS_HALF_CORNERS (corner) {
     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
   }
 
   nscoord medium =
@@ -364,30 +369,30 @@ nsBorderColors::Clone(bool aDeep) const
   if (MOZ_UNLIKELY(!result))
     return result;
   if (aDeep)
     NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false));
   return result;
 }
 
 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
-  : mBorderColors(nullptr),
-    mBorderRadius(aSrc.mBorderRadius),
-    mBorderImageSource(aSrc.mBorderImageSource),
-    mBorderImageSlice(aSrc.mBorderImageSlice),
-    mBorderImageWidth(aSrc.mBorderImageWidth),
-    mBorderImageOutset(aSrc.mBorderImageOutset),
-    mBorderImageFill(aSrc.mBorderImageFill),
-    mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
-    mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
-    mFloatEdge(aSrc.mFloatEdge),
-    mBoxDecorationBreak(aSrc.mBoxDecorationBreak),
-    mComputedBorder(aSrc.mComputedBorder),
-    mBorder(aSrc.mBorder),
-    mTwipsPerPixel(aSrc.mTwipsPerPixel)
+  : mBorderColors(nullptr)
+  , mBorderRadius(aSrc.mBorderRadius)
+  , mBorderImageSource(aSrc.mBorderImageSource)
+  , mBorderImageSlice(aSrc.mBorderImageSlice)
+  , mBorderImageWidth(aSrc.mBorderImageWidth)
+  , mBorderImageOutset(aSrc.mBorderImageOutset)
+  , mBorderImageFill(aSrc.mBorderImageFill)
+  , mBorderImageRepeatH(aSrc.mBorderImageRepeatH)
+  , mBorderImageRepeatV(aSrc.mBorderImageRepeatV)
+  , mFloatEdge(aSrc.mFloatEdge)
+  , mBoxDecorationBreak(aSrc.mBoxDecorationBreak)
+  , mComputedBorder(aSrc.mComputedBorder)
+  , mBorder(aSrc.mBorder)
+  , mTwipsPerPixel(aSrc.mTwipsPerPixel)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
   if (aSrc.mBorderColors) {
     EnsureBorderColors();
     for (int32_t i = 0; i < 4; i++)
       if (aSrc.mBorderColors[i])
         mBorderColors[i] = aSrc.mBorderColors[i]->Clone();
       else
@@ -440,17 +445,18 @@ nsStyleBorder::GetImageOutset() const
 void
 nsStyleBorder::Destroy(nsPresContext* aContext) {
   UntrackImage(aContext);
   this->~nsStyleBorder();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStyleBorder, this);
 }
 
-nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
+nsChangeHint
+nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
 {
   // XXXbz we should be able to return a more specific change hint for
   // at least GetComputedBorder() differences...
   if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
       GetComputedBorder() != aOther.GetComputedBorder() ||
       mFloatEdge != aOther.mFloatEdge ||
       mBorderImageOutset != aOther.mBorderImageOutset ||
       mBoxDecorationBreak != aOther.mBoxDecorationBreak)
@@ -556,17 +562,18 @@ nsStyleOutline::RecalcData()
     mActualOutlineWidth =
       std::max(CalcCoord(mOutlineWidth,
                          StaticPresData::Get()->GetBorderWidthTable(), 3), 0);
     mActualOutlineWidth =
       NS_ROUND_BORDER_TO_PIXELS(mActualOutlineWidth, mTwipsPerPixel);
   }
 }
 
-nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
+nsChangeHint
+nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
 {
   if (mActualOutlineWidth != aOther.mActualOutlineWidth ||
       (mActualOutlineWidth > 0 &&
        mOutlineOffset != aOther.mOutlineOffset)) {
     return nsChangeHint_UpdateOverflow |
            nsChangeHint_SchedulePaint;
   }
 
@@ -587,33 +594,33 @@ nsChangeHint nsStyleOutline::CalcDiffere
 
   return NS_STYLE_HINT_NONE;
 }
 
 // --------------------
 // nsStyleList
 //
 nsStyleList::nsStyleList(StyleStructContext aContext) 
-  : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE),
-    mCounterStyle(aContext.BuildCounterStyle(NS_LITERAL_STRING("disc")))
+  : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)
+  , mCounterStyle(aContext.BuildCounterStyle(NS_LITERAL_STRING("disc")))
 {
   MOZ_COUNT_CTOR(nsStyleList);
   SetQuotesInitial();
 }
 
 nsStyleList::~nsStyleList() 
 {
   MOZ_COUNT_DTOR(nsStyleList);
 }
 
 nsStyleList::nsStyleList(const nsStyleList& aSource)
-  : mListStylePosition(aSource.mListStylePosition),
-    mCounterStyle(aSource.mCounterStyle),
-    mQuotes(aSource.mQuotes),
-    mImageRegion(aSource.mImageRegion)
+  : mListStylePosition(aSource.mListStylePosition)
+  , mCounterStyle(aSource.mCounterStyle)
+  , mQuotes(aSource.mQuotes)
+  , mImageRegion(aSource.mImageRegion)
 {
   SetListStyleImage(aSource.GetListStyleImage());
   MOZ_COUNT_CTOR(nsStyleList);
 }
 
 void
 nsStyleList::SetQuotesInherit(const nsStyleList* aOther)
 {
@@ -723,17 +730,18 @@ nsStyleXUL::nsStyleXUL(const nsStyleXUL&
   , mBoxDirection(aSource.mBoxDirection)
   , mBoxOrient(aSource.mBoxOrient)
   , mBoxPack(aSource.mBoxPack)
   , mStretchStack(aSource.mStretchStack)
 {
   MOZ_COUNT_CTOR(nsStyleXUL);
 }
 
-nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const
+nsChangeHint
+nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const
 {
   if (mBoxAlign == aOther.mBoxAlign &&
       mBoxDirection == aOther.mBoxDirection &&
       mBoxFlex == aOther.mBoxFlex &&
       mBoxOrient == aOther.mBoxOrient &&
       mBoxPack == aOther.mBoxPack &&
       mBoxOrdinal == aOther.mBoxOrdinal &&
       mStretchStack == aOther.mStretchStack)
@@ -777,17 +785,18 @@ nsStyleColumn::nsStyleColumn(const nsSty
   , mColumnFill(aSource.mColumnFill)
   , mColumnRuleColorIsForeground(aSource.mColumnRuleColorIsForeground)
   , mColumnRuleWidth(aSource.mColumnRuleWidth)
   , mTwipsPerPixel(aSource.mTwipsPerPixel)
 {
   MOZ_COUNT_CTOR(nsStyleColumn);
 }
 
-nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
+nsChangeHint
+nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
 {
   if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
       != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
       mColumnCount != aOther.mColumnCount)
     // We force column count changes to do a reframe, because it's tricky to handle
     // some edge cases where the column count gets smaller and content overflows.
     // XXX not ideal
     return NS_STYLE_HINT_FRAMECHANGE;
@@ -815,18 +824,17 @@ nsChangeHint nsStyleColumn::CalcDifferen
 
 // --------------------
 // nsStyleSVG
 //
 nsStyleSVG::nsStyleSVG(StyleStructContext aContext)
   : mFill(eStyleSVGPaintType_Color) // Will be initialized to NS_RGB(0, 0, 0)
   , mStroke(eStyleSVGPaintType_None)
   , mStrokeDashoffset(0, nsStyleCoord::CoordConstructor)
-  , mStrokeWidth(nsPresContext::CSSPixelsToAppUnits(1),
-                 nsStyleCoord::CoordConstructor)
+  , mStrokeWidth(nsPresContext::CSSPixelsToAppUnits(1), nsStyleCoord::CoordConstructor)
   , mFillOpacity(1.0f)
   , mStrokeMiterlimit(4.0f)
   , mStrokeOpacity(1.0f)
   , mClipRule(NS_STYLE_FILL_RULE_NONZERO)
   , mColorInterpolation(NS_STYLE_COLOR_INTERPOLATION_SRGB)
   , mColorInterpolationFilters(NS_STYLE_COLOR_INTERPOLATION_LINEARRGB)
   , mFillRule(NS_STYLE_FILL_RULE_NONZERO)
   , mPaintOrder(NS_STYLE_PAINT_ORDER_NORMAL)
@@ -873,28 +881,29 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG&
   , mStrokeOpacitySource(aSource.mStrokeOpacitySource)
   , mStrokeDasharrayFromObject(aSource.mStrokeDasharrayFromObject)
   , mStrokeDashoffsetFromObject(aSource.mStrokeDashoffsetFromObject)
   , mStrokeWidthFromObject(aSource.mStrokeWidthFromObject)
 {
   MOZ_COUNT_CTOR(nsStyleSVG);
 }
 
-static bool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
-                            const nsStyleSVGPaint& aPaint2)
+static bool
+PaintURIChanged(const nsStyleSVGPaint& aPaint1, const nsStyleSVGPaint& aPaint2)
 {
   if (aPaint1.mType != aPaint2.mType) {
     return aPaint1.mType == eStyleSVGPaintType_Server ||
            aPaint2.mType == eStyleSVGPaintType_Server;
   }
   return aPaint1.mType == eStyleSVGPaintType_Server &&
     !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
 }
 
-nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
+nsChangeHint
+nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
       !EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
       !EqualURIs(mMarkerStart, aOther.mMarkerStart)) {
     // Markers currently contribute to nsSVGPathGeometryFrame::mRect,
     // so we need a reflow as well as a repaint. No intrinsic sizes need
@@ -1031,17 +1040,16 @@ nsStyleClipPath::operator=(const nsStyle
   } else {
     ReleaseRef();
     mSizingBox = NS_STYLE_CLIP_SHAPE_SIZING_NOBOX;
     mType = NS_STYLE_CLIP_PATH_NONE;
   }
   return *this;
 }
 
-
 bool
 nsStyleClipPath::operator==(const nsStyleClipPath& aOther) const
 {
   if (mType != aOther.mType) {
     return false;
   }
 
   if (mType == NS_STYLE_CLIP_PATH_URL) {
@@ -1145,17 +1153,16 @@ nsStyleFilter::operator=(const nsStyleFi
   } else {
     ReleaseRef();
     mType = NS_STYLE_FILTER_NONE;
   }
 
   return *this;
 }
 
-
 bool
 nsStyleFilter::operator==(const nsStyleFilter& aOther) const
 {
   if (mType != aOther.mType) {
       return false;
   }
 
   if (mType == NS_STYLE_FILTER_URL) {
@@ -1210,17 +1217,18 @@ nsStyleFilter::SetDropShadow(nsCSSShadow
   mDropShadow->AddRef();
   mType = NS_STYLE_FILTER_DROP_SHADOW;
 }
 
 // --------------------
 // nsStyleSVGReset
 //
 nsStyleSVGReset::nsStyleSVGReset(StyleStructContext aContext)
-  : mStopColor(NS_RGB(0, 0, 0))
+  : mMask(nsStyleImageLayers::LayerType::Mask)
+  , mStopColor(NS_RGB(0, 0, 0))
   , mFloodColor(NS_RGB(0, 0, 0))
   , mLightingColor(NS_RGB(255, 255, 255))
   , mStopOpacity(1.0f)
   , mFloodOpacity(1.0f)
   , mDominantBaseline(NS_STYLE_DOMINANT_BASELINE_AUTO)
   , mVectorEffect(NS_STYLE_VECTOR_EFFECT_NONE)
   , mMaskType(NS_STYLE_MASK_TYPE_LUMINANCE)
 {
@@ -1242,25 +1250,28 @@ nsStyleSVGReset::nsStyleSVGReset(const n
   , mFloodOpacity(aSource.mFloodOpacity)
   , mDominantBaseline(aSource.mDominantBaseline)
   , mVectorEffect(aSource.mVectorEffect)
   , mMaskType(aSource.mMaskType)
 {
   MOZ_COUNT_CTOR(nsStyleSVGReset);
 }
 
-void nsStyleSVGReset::Destroy(nsPresContext* aContext) {
+void
+nsStyleSVGReset::Destroy(nsPresContext* aContext)
+{
   mMask.UntrackImages(aContext);
 
   this->~nsStyleSVGReset();
   aContext->PresShell()->
     FreeByObjectID(mozilla::eArenaObjectID_nsStyleSVGReset, this);
 }
 
-nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
+nsChangeHint
+nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (mClipPath != aOther.mClipPath) {
     hint |= nsChangeHint_UpdateEffects |
             nsChangeHint_RepaintFrame;
     // clip-path changes require that we update the PreEffectsBBoxProperty,
     // which is done during overflow computation.
@@ -1334,17 +1345,18 @@ nsStyleSVGPaint::SetType(nsStyleSVGPaint
     NS_IF_RELEASE(mPaint.mPaintServer);
     mPaint.mPaintServer = nullptr;
   } else {
     mPaint.mColor = NS_RGB(0, 0, 0);
   }
   mType = aType;
 }
 
-nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
+nsStyleSVGPaint&
+nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
 {
   if (this == &aOther)
     return *this;
 
   SetType(aOther.mType);
 
   mFallbackColor = aOther.mFallbackColor;
   if (mType == eStyleSVGPaintType_Server) {
@@ -1757,17 +1769,18 @@ nsStyleTableBorder::nsStyleTableBorder(c
   , mBorderSpacingRow(aSource.mBorderSpacingRow)
   , mBorderCollapse(aSource.mBorderCollapse)
   , mCaptionSide(aSource.mCaptionSide)
   , mEmptyCells(aSource.mEmptyCells)
 {
   MOZ_COUNT_CTOR(nsStyleTableBorder);
 }
 
-nsChangeHint nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const
+nsChangeHint
+nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const
 {
   // Border-collapse changes need a reframe, because we use a different frame
   // class for table cells in the collapsed border model.  This is used to
   // conserve memory when using the separated border model (collapsed borders
   // require extra state to be stored).
   if (mBorderCollapse != aOther.mBorderCollapse) {
     return NS_STYLE_HINT_FRAMECHANGE;
   }
@@ -1794,17 +1807,18 @@ nsStyleColor::nsStyleColor(StyleStructCo
 }
 
 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
   : mColor(aSource.mColor)
 {
   MOZ_COUNT_CTOR(nsStyleColor);
 }
 
-nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aOther) const
+nsChangeHint
+nsStyleColor::CalcDifference(const nsStyleColor& aOther) const
 {
   if (mColor == aOther.mColor)
     return NS_STYLE_HINT_NONE;
   return nsChangeHint_RepaintFrame;
 }
 
 // --------------------
 // nsStyleGradient
@@ -2241,31 +2255,34 @@ const nsCSSProperty nsStyleImageLayers::
   eCSSProperty_mask_origin,               // origin
   eCSSProperty_mask_size,                 // size
   eCSSProperty_UNKNOWN,                   // attachment
   eCSSProperty_mask_mode,                 // maskMode
   eCSSProperty_mask_composite             // composite
 };
 #endif
 
-nsStyleImageLayers::nsStyleImageLayers()
+nsStyleImageLayers::nsStyleImageLayers(nsStyleImageLayers::LayerType aType)
   : mAttachmentCount(1)
   , mClipCount(1)
   , mOriginCount(1)
   , mRepeatCount(1)
   , mPositionXCount(1)
   , mPositionYCount(1)
   , mImageCount(1)
   , mSizeCount(1)
   , mMaskModeCount(1)
   , mBlendModeCount(1)
   , mCompositeCount(1)
   , mLayers(nsStyleAutoArray<Layer>::WITH_SINGLE_INITIAL_ELEMENT)
 {
   MOZ_COUNT_CTOR(nsStyleImageLayers);
+
+  // Ensure first layer is initialized as specified layer type
+  mLayers[0].Initialize(aType);
 }
 
 nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource)
   : mAttachmentCount(aSource.mAttachmentCount)
   , mClipCount(aSource.mClipCount)
   , mOriginCount(aSource.mOriginCount)
   , mRepeatCount(aSource.mRepeatCount)
   , mPositionXCount(aSource.mPositionXCount)
@@ -2495,41 +2512,72 @@ nsStyleImageLayers::Size::operator==(con
              "bad mHeightType for aOther");
 
   return mWidthType == aOther.mWidthType &&
          mHeightType == aOther.mHeightType &&
          (mWidthType != eLengthPercentage || mWidth == aOther.mWidth) &&
          (mHeightType != eLengthPercentage || mHeight == aOther.mHeight);
 }
 
-void
-nsStyleImageLayers::Repeat::SetInitialValues()
+bool
+nsStyleImageLayers::Repeat::IsInitialValue(LayerType aType) const
 {
-  mXRepeat = NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
-  mYRepeat = NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
+  if (aType == LayerType::Background ||
+      aType == LayerType::Mask) {
+    // bug 1258623 - mask-repeat initial value should be no-repeat
+    return mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT &&
+           mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
+  }
+
+  MOZ_ASSERT_UNREACHABLE("unsupported layer type.");
+  return false;
+}
+
+void
+nsStyleImageLayers::Repeat::SetInitialValues(LayerType aType)
+{
+  if (aType == LayerType::Background ||
+      aType == LayerType::Mask) {
+    // bug 1258623 - mask-repeat initial value should be no-repeat
+    mXRepeat = NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
+    mYRepeat = NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
+  } else {
+    MOZ_ASSERT_UNREACHABLE("unsupported layer type.");
+  }
 }
 
 nsStyleImageLayers::Layer::Layer()
-: mClip(NS_STYLE_IMAGELAYER_CLIP_BORDER),
-  mOrigin(NS_STYLE_IMAGELAYER_ORIGIN_PADDING),
-  mAttachment(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL),
-  mBlendMode(NS_STYLE_BLEND_NORMAL),
-  mComposite(NS_STYLE_MASK_COMPOSITE_ADD),
-  mMaskMode(NS_STYLE_MASK_MODE_MATCH_SOURCE)
+  : mClip(NS_STYLE_IMAGELAYER_CLIP_BORDER)
+  , mAttachment(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL)
+  , mBlendMode(NS_STYLE_BLEND_NORMAL)
+  , mComposite(NS_STYLE_MASK_COMPOSITE_ADD)
+  , mMaskMode(NS_STYLE_MASK_MODE_MATCH_SOURCE)
 {
   mPosition.SetInitialPercentValues(0.0f); // Initial value is "0% 0%"
   mImage.SetNull();
-  mRepeat.SetInitialValues();
   mSize.SetInitialValues();
 }
 
 nsStyleImageLayers::Layer::~Layer()
 {
 }
 
+void
+nsStyleImageLayers::Layer::Initialize(nsStyleImageLayers::LayerType aType)
+{
+  mRepeat.SetInitialValues(aType);
+
+  if (aType == LayerType::Background) {
+    mOrigin = NS_STYLE_IMAGELAYER_ORIGIN_PADDING;
+  } else {
+    MOZ_ASSERT(aType == LayerType::Mask, "unsupported layer type.");
+    mOrigin = NS_STYLE_IMAGELAYER_ORIGIN_BORDER;
+  }
+}
+
 bool
 nsStyleImageLayers::Layer::RenderingMightDependOnPositioningAreaSizeChange() const
 {
   // Do we even have an image?
   if (mImage.IsEmpty()) {
     return false;
   }
 
@@ -2582,27 +2630,27 @@ nsStyleImageLayers::Layer::CalcDifferenc
   return hint;
 }
 
 // --------------------
 // nsStyleBackground
 //
 
 nsStyleBackground::nsStyleBackground(StyleStructContext aContext)
-  : mBackgroundColor(NS_RGBA(0, 0, 0, 0))
+  : mImage(nsStyleImageLayers::LayerType::Background)
+  , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
 }
 
 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
   : mImage(aSource.mImage)
   , mBackgroundColor(aSource.mBackgroundColor)
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
-
 }
 
 nsStyleBackground::~nsStyleBackground()
 {
   MOZ_COUNT_DTOR(nsStyleBackground);
 }
 
 void
@@ -2611,49 +2659,53 @@ nsStyleBackground::Destroy(nsPresContext
   // Untrack all the images stored in our layers
   mImage.UntrackImages(aContext);
 
   this->~nsStyleBackground();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStyleBackground, this);
 }
 
-nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const
+nsChangeHint
+nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
   if (mBackgroundColor != aOther.mBackgroundColor) {
     hint |= nsChangeHint_RepaintFrame;
   }
 
   hint |= mImage.CalcDifference(aOther.mImage);
 
   return hint;
 }
 
-bool nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const
+bool
+nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const
 {
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) {
     const nsStyleImageLayers::Layer &layer = mImage.mLayers[i];
     if (layer.mAttachment == NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED &&
         !layer.mImage.IsEmpty() &&
         !nsLayoutUtils::IsTransformed(aFrame)) {
       return true;
     }
   }
   return false;
 }
 
-bool nsStyleBackground::IsTransparent() const
+bool
+nsStyleBackground::IsTransparent() const
 {
   return BottomLayer().mImage.IsEmpty() &&
          mImage.mImageCount == 1 &&
          NS_GET_A(mBackgroundColor) == 0;
 }
 
-void nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
+void
+nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
 {
   switch (aTimingFunctionType) {
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
       mType = Type::StepStart;
       mStepSyntax = StepSyntax::Keyword;
       mSteps = 1;
       return;
     default:
@@ -2897,17 +2949,18 @@ nsStyleDisplay::nsStyleDisplay(const nsS
   /* Copy over transform origin. */
   mTransformOrigin[0] = aSource.mTransformOrigin[0];
   mTransformOrigin[1] = aSource.mTransformOrigin[1];
   mTransformOrigin[2] = aSource.mTransformOrigin[2];
   mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0];
   mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
 }
 
-nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
+nsChangeHint
+nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (!EqualURIs(mBinding, aOther.mBinding)
       || mPosition != aOther.mPosition
       || mDisplay != aOther.mDisplay
       || mContain != aOther.mContain
       || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
@@ -3133,17 +3186,18 @@ nsStyleVisibility::nsStyleVisibility(con
   , mImageRendering(aSource.mImageRendering)
   , mWritingMode(aSource.mWritingMode)
   , mTextOrientation(aSource.mTextOrientation)
   , mColorAdjust(aSource.mColorAdjust)
 {
   MOZ_COUNT_CTOR(nsStyleVisibility);
 }
 
-nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
+nsChangeHint
+nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) {
     // It's important that a change in mWritingMode results in frame
     // reconstruction, because it may affect intrinsic size (see
     // nsSubDocumentFrame::GetIntrinsicISize/BSize).
     hint |= nsChangeHint_ReconstructFrame;
@@ -3183,17 +3237,18 @@ nsStyleContentData::~nsStyleContentData(
   } else if (mType == eStyleContentType_Counter ||
              mType == eStyleContentType_Counters) {
     mContent.mCounters->Release();
   } else if (mContent.mString) {
     free(mContent.mString);
   }
 }
 
-nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther)
+nsStyleContentData&
+nsStyleContentData::operator=(const nsStyleContentData& aOther)
 {
   if (this == &aOther)
     return *this;
   this->~nsStyleContentData();
   new (this) nsStyleContentData();
 
   mType = aOther.mType;
   if (mType == eStyleContentType_Image) {
@@ -3206,17 +3261,18 @@ nsStyleContentData& nsStyleContentData::
   } else if (aOther.mContent.mString) {
     mContent.mString = NS_strdup(aOther.mContent.mString);
   } else {
     mContent.mString = nullptr;
   }
   return *this;
 }
 
-bool nsStyleContentData::operator==(const nsStyleContentData& aOther) const
+bool
+nsStyleContentData::operator==(const nsStyleContentData& aOther) const
 {
   if (mType != aOther.mType)
     return false;
   if (mType == eStyleContentType_Image) {
     if (!mContent.mImage || !aOther.mContent.mImage)
       return mContent.mImage == aOther.mContent.mImage;
     bool eq;
     nsCOMPtr<nsIURI> thisURI, otherURI;
@@ -3347,17 +3403,18 @@ nsStyleContent::nsStyleContent(const nsS
     for (index = 0; index < mResetCount; index++) {
       const nsStyleCounterData *data = aSource.GetCounterResetAt(index);
       mResets[index].mCounter = data->mCounter;
       mResets[index].mValue = data->mValue;
     }
   }
 }
 
-nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
+nsChangeHint
+nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
 {
   // In ReResolveStyleContext we assume that if there's no existing
   // ::before or ::after and we don't have to restyle children of the
   // node then we can't end up with a ::before or ::after due to the
   // restyle of the node itself.  That's not quite true, but the only
   // exception to the above is when the 'content' property of the node
   // changes and the pseudo-element inherits the changed value.  Since
   // the code here triggers a frame change on the node in that case,
@@ -3396,17 +3453,18 @@ nsChangeHint nsStyleContent::CalcDiffere
     }
   }
   if (mMarkerOffset != aOther.mMarkerOffset) {
     return NS_STYLE_HINT_REFLOW;
   }
   return NS_STYLE_HINT_NONE;
 }
 
-nsresult nsStyleContent::AllocateContents(uint32_t aCount)
+nsresult
+nsStyleContent::AllocateContents(uint32_t aCount)
 {
   // We need to run the destructors of the elements of mContents, so we
   // delete and reallocate even if aCount == mContentCount.  (If
   // nsStyleContentData had its members private and managed their
   // ownership on setting, we wouldn't need this, but that seems
   // unnecessary at this point.)
   DELETE_ARRAY_IF(mContents);
   if (aCount) {
@@ -3423,18 +3481,17 @@ nsresult nsStyleContent::AllocateContent
 
 // --------------------
 // nsStyleTextReset
 //
 
 nsStyleTextReset::nsStyleTextReset(StyleStructContext aContext)
   : mTextDecorationLine(NS_STYLE_TEXT_DECORATION_LINE_NONE)
   , mUnicodeBidi(NS_STYLE_UNICODE_BIDI_NORMAL)
-  , mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID |
-                         BORDER_COLOR_FOREGROUND)
+  , mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND)
   , mTextDecorationColor(NS_RGB(0, 0, 0))
 {
   MOZ_COUNT_CTOR(nsStyleTextReset);
 }
 
 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
 {
   MOZ_COUNT_CTOR(nsStyleTextReset);
@@ -3578,17 +3635,18 @@ nsStyleText::nsStyleText(const nsStyleTe
   MOZ_COUNT_CTOR(nsStyleText);
 }
 
 nsStyleText::~nsStyleText()
 {
   MOZ_COUNT_DTOR(nsStyleText);
 }
 
-nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
+nsChangeHint
+nsStyleText::CalcDifference(const nsStyleText& aOther) const
 {
   if (WhiteSpaceOrNewlineIsSignificant() !=
       aOther.WhiteSpaceOrNewlineIsSignificant()) {
     // This may require construction of suppressed text frames
     return NS_STYLE_HINT_FRAMECHANGE;
   }
 
   if (mTextCombineUpright != aOther.mTextCombineUpright ||
@@ -3750,17 +3808,18 @@ nsStyleUserInterface::nsStyleUserInterfa
 }
 
 nsStyleUserInterface::~nsStyleUserInterface()
 {
   MOZ_COUNT_DTOR(nsStyleUserInterface);
   delete [] mCursorArray;
 }
 
-nsChangeHint nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const
+nsChangeHint
+nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
   if (mCursor != aOther.mCursor)
     hint |= nsChangeHint_UpdateCursor;
 
   // We could do better. But it wouldn't be worth it, URL-specified cursors are
   // rare.
   if (mCursorArrayLength > 0 || aOther.mCursorArrayLength > 0)
@@ -3832,17 +3891,18 @@ nsStyleUIReset::nsStyleUIReset(const nsS
   MOZ_COUNT_CTOR(nsStyleUIReset);
 }
 
 nsStyleUIReset::~nsStyleUIReset()
 {
   MOZ_COUNT_DTOR(nsStyleUIReset);
 }
 
-nsChangeHint nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const
+nsChangeHint
+nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const
 {
   // ignore mIMEMode
   if (mForceBrokenImageIcon != aOther.mForceBrokenImageIcon)
     return NS_STYLE_HINT_FRAMECHANGE;
   if (mWindowShadow != aOther.mWindowShadow) {
     // We really need just an nsChangeHint_SyncFrameView, except
     // on an ancestor of the frame, so we get that by doing a
     // reflow.
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -467,38 +467,43 @@ public:
   }
 
 private:
   T mFirstElement;
   nsTArray<T> mOtherElements;
 };
 
 struct nsStyleImageLayers {
-  nsStyleImageLayers();
-  nsStyleImageLayers(const nsStyleImageLayers &aSource);
-  ~nsStyleImageLayers() {
-    MOZ_COUNT_DTOR(nsStyleImageLayers);
-  }
-
   // Indices into kBackgroundLayerTable and kMaskLayerTable
   enum {
     shorthand = 0,
     color,
     image,
     repeat,
     positionX,
     positionY,
     clip,
     origin,
     size,
     attachment,
     maskMode,
     composite
   };
 
+  enum class LayerType : uint8_t {
+    Background = 0,
+    Mask
+  };
+
+  explicit nsStyleImageLayers(LayerType aType);
+  nsStyleImageLayers(const nsStyleImageLayers &aSource);
+  ~nsStyleImageLayers() {
+    MOZ_COUNT_DTOR(nsStyleImageLayers);
+  }
+
   struct Position;
   friend struct Position;
   struct Position {
     typedef nsStyleCoord::CalcValue PositionCoord;
     PositionCoord mXPosition, mYPosition;
 
     // Initialize nothing
     Position() {}
@@ -593,23 +598,20 @@ struct nsStyleImageLayers {
   struct Repeat;
   friend struct Repeat;
   struct Repeat {
     uint8_t mXRepeat, mYRepeat;
 
     // Initialize nothing
     Repeat() {}
 
-    bool IsInitialValue() const {
-      return mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT &&
-             mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT;
-    }
+    bool IsInitialValue(LayerType aType) const;
 
     // Initialize to initial values
-    void SetInitialValues();
+    void SetInitialValues(LayerType aType);
 
     bool operator==(const Repeat& aOther) const {
       return mXRepeat == aOther.mXRepeat &&
              mYRepeat == aOther.mYRepeat;
     }
     bool operator!=(const Repeat& aOther) const {
       return !(*this == aOther);
     }
@@ -651,20 +653,24 @@ struct nsStyleImageLayers {
     uint8_t       mMaskMode;      // [reset] See nsStyleConsts.h
                                   // mask-only property
                                   // This property is used for mask layer only.
                                   // For a background layer, it should always
                                   // be the initial value, which is
                                   // NS_STYLE_MASK_MODE_MATCH_SOURCE.
     Repeat        mRepeat;        // [reset] See nsStyleConsts.h
 
-    // Initializes only mImage
+    // This constructor does not initialize mRepeat or mOrigin and Initialize()
+    // must be called to do that.
     Layer();
     ~Layer();
 
+    // Initialize mRepeat and mOrigin by specified layer type
+    void Initialize(LayerType aType);
+
     // Register/unregister images with the document. We do this only
     // after the dust has settled in ComputeBackgroundData.
     void TrackImages(nsPresContext* aContext) {
       if (mImage.GetType() == eStyleImageType_Image)
         mImage.TrackImage(aContext);
     }
     void UntrackImages(nsPresContext* aContext) {
       if (mImage.GetType() == eStyleImageType_Image)
@@ -3536,17 +3542,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
     return mClipPath.GetType() != NS_STYLE_CLIP_PATH_NONE;
   }
 
   bool HasNonScalingStroke() const {
     return mVectorEffect == NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE;
   }
 
   nsStyleImageLayers    mMask;
-  nsStyleClipPath mClipPath;          // [reset]
+  nsStyleClipPath  mClipPath;         // [reset]
   nscolor          mStopColor;        // [reset]
   nscolor          mFloodColor;       // [reset]
   nscolor          mLightingColor;    // [reset]
 
   float            mStopOpacity;      // [reset]
   float            mFloodOpacity;     // [reset]
 
   uint8_t          mDominantBaseline; // [reset] see nsStyleConsts.h
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -6984,18 +6984,18 @@ if (SupportsMaskShorthand()) {
     initial_values: [ "add" ],
     other_values: [ "substract", "intersect", "exclude", "add, add", "substract, intersect", "substract, substract, add"],
     invalid_values: [ "add substract", "intersect exclude" ]
   };
   gCSSProperties["mask-origin"] = {
     domProp: "maskOrigin",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
-    initial_values: [ "padding-box" ],
-    other_values: [ "border-box", "content-box", "border-box, padding-box", "padding-box, padding-box, padding-box", "border-box, border-box" ],
+    initial_values: [ "border-box" ],
+    other_values: [ "padding-box", "content-box", "border-box, padding-box", "padding-box, padding-box, padding-box", "border-box, border-box" ],
     invalid_values: [ "margin-box", "padding-box padding-box" ]
   };
   gCSSProperties["mask-position"] = {
     domProp: "maskPosition",
     inherited: false,
     type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
     initial_values: [ "top 0% left 0%", "top 0% left", "top left", "left top", "0% 0%", "0% top", "left 0%" ],
     other_values: [ "top", "left", "right", "bottom", "center", "center bottom", "bottom center", "center right", "right center", "center top", "top center", "center left", "left center", "right bottom", "bottom right", "50%", "top left, top left", "top left, top right", "top right, top left", "left top, 0% 0%", "10% 20%, 30%, 40%", "top left, bottom right", "right bottom, left top", "0%", "0px", "30px", "0%, 10%, 20%, 30%", "top, top, top, top, top",