LCOV - code coverage report
Current view: top level - layout/painting - nsCSSRendering.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 679 1949 34.8 %
Date: 2017-07-14 16:53:18 Functions: 55 98 56.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : // vim:cindent:ts=2:et:sw=2:
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* utility functions for drawing borders and backgrounds */
       8             : 
       9             : #include <ctime>
      10             : 
      11             : #include "gfx2DGlue.h"
      12             : #include "gfxContext.h"
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/DebugOnly.h"
      15             : #include "mozilla/gfx/2D.h"
      16             : #include "mozilla/gfx/Helpers.h"
      17             : #include "mozilla/gfx/PathHelpers.h"
      18             : #include "mozilla/HashFunctions.h"
      19             : #include "mozilla/MathAlgorithms.h"
      20             : 
      21             : #include "BorderConsts.h"
      22             : #include "nsStyleConsts.h"
      23             : #include "nsPresContext.h"
      24             : #include "nsIFrame.h"
      25             : #include "nsIFrameInlines.h"
      26             : #include "nsPoint.h"
      27             : #include "nsRect.h"
      28             : #include "nsIPresShell.h"
      29             : #include "nsFrameManager.h"
      30             : #include "nsStyleContext.h"
      31             : #include "nsGkAtoms.h"
      32             : #include "nsCSSAnonBoxes.h"
      33             : #include "nsIContent.h"
      34             : #include "nsIDocumentInlines.h"
      35             : #include "nsIScrollableFrame.h"
      36             : #include "imgIRequest.h"
      37             : #include "imgIContainer.h"
      38             : #include "ImageOps.h"
      39             : #include "nsCSSRendering.h"
      40             : #include "nsCSSColorUtils.h"
      41             : #include "nsITheme.h"
      42             : #include "nsThemeConstants.h"
      43             : #include "nsLayoutUtils.h"
      44             : #include "nsBlockFrame.h"
      45             : #include "nsStyleStructInlines.h"
      46             : #include "nsCSSFrameConstructor.h"
      47             : #include "nsCSSProps.h"
      48             : #include "nsContentUtils.h"
      49             : #include "nsSVGEffects.h"
      50             : #include "nsSVGIntegrationUtils.h"
      51             : #include "gfxDrawable.h"
      52             : #include "GeckoProfiler.h"
      53             : #include "nsCSSRenderingBorders.h"
      54             : #include "mozilla/css/ImageLoader.h"
      55             : #include "ImageContainer.h"
      56             : #include "mozilla/Telemetry.h"
      57             : #include "gfxUtils.h"
      58             : #include "gfxGradientCache.h"
      59             : #include "nsInlineFrame.h"
      60             : #include "nsRubyTextContainerFrame.h"
      61             : #include <algorithm>
      62             : #include "SVGImageContext.h"
      63             : #include "mozilla/layers/WebRenderDisplayItemLayer.h"
      64             : 
      65             : using namespace mozilla;
      66             : using namespace mozilla::css;
      67             : using namespace mozilla::gfx;
      68             : using namespace mozilla::image;
      69             : using mozilla::CSSSizeOrRatio;
      70             : 
      71             : static int gFrameTreeLockCount = 0;
      72             : 
      73             : // To avoid storing this data on nsInlineFrame (bloat) and to avoid
      74             : // recalculating this for each frame in a continuation (perf), hold
      75             : // a cache of various coordinate information that we need in order
      76             : // to paint inline backgrounds.
      77             : struct InlineBackgroundData
      78             : {
      79           3 :   InlineBackgroundData()
      80           3 :       : mFrame(nullptr), mLineContainer(nullptr)
      81             :   {
      82           3 :   }
      83             : 
      84           0 :   ~InlineBackgroundData()
      85           0 :   {
      86           0 :   }
      87             : 
      88          35 :   void Reset()
      89             :   {
      90          35 :     mBoundingBox.SetRect(0,0,0,0);
      91          35 :     mContinuationPoint = mLineContinuationPoint = mUnbrokenMeasure = 0;
      92          35 :     mFrame = mLineContainer = nullptr;
      93          35 :     mPIStartBorderData.Reset();
      94          35 :   }
      95             : 
      96             :   /**
      97             :    * Return a continuous rect for (an inline) aFrame relative to the
      98             :    * continuation that draws the left-most part of the background.
      99             :    * This is used when painting backgrounds.
     100             :    */
     101           0 :   nsRect GetContinuousRect(nsIFrame* aFrame)
     102             :   {
     103           0 :     MOZ_ASSERT(static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)));
     104             : 
     105           0 :     SetFrame(aFrame);
     106             : 
     107             :     nscoord pos; // an x coordinate if writing-mode is horizontal;
     108             :                  // y coordinate if vertical
     109           0 :     if (mBidiEnabled) {
     110           0 :       pos = mLineContinuationPoint;
     111             : 
     112             :       // Scan continuations on the same line as aFrame and accumulate the widths
     113             :       // of frames that are to the left (if this is an LTR block) or right
     114             :       // (if it's RTL) of the current one.
     115           0 :       bool isRtlBlock = (mLineContainer->StyleVisibility()->mDirection ==
     116           0 :                            NS_STYLE_DIRECTION_RTL);
     117           0 :       nscoord curOffset = mVertical ? aFrame->GetOffsetTo(mLineContainer).y
     118           0 :                                     : aFrame->GetOffsetTo(mLineContainer).x;
     119             : 
     120             :       // If the continuation is fluid we know inlineFrame is not on the same line.
     121             :       // If it's not fluid, we need to test further to be sure.
     122           0 :       nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
     123           0 :       while (inlineFrame && !inlineFrame->GetNextInFlow() &&
     124           0 :              AreOnSameLine(aFrame, inlineFrame)) {
     125           0 :         nscoord frameOffset = mVertical
     126           0 :           ? inlineFrame->GetOffsetTo(mLineContainer).y
     127           0 :           : inlineFrame->GetOffsetTo(mLineContainer).x;
     128           0 :         if (isRtlBlock == (frameOffset >= curOffset)) {
     129           0 :           pos += mVertical
     130           0 :                ? inlineFrame->GetSize().height
     131           0 :                : inlineFrame->GetSize().width;
     132             :         }
     133           0 :         inlineFrame = inlineFrame->GetPrevContinuation();
     134             :       }
     135             : 
     136           0 :       inlineFrame = aFrame->GetNextContinuation();
     137           0 :       while (inlineFrame && !inlineFrame->GetPrevInFlow() &&
     138           0 :              AreOnSameLine(aFrame, inlineFrame)) {
     139           0 :         nscoord frameOffset = mVertical
     140           0 :           ? inlineFrame->GetOffsetTo(mLineContainer).y
     141           0 :           : inlineFrame->GetOffsetTo(mLineContainer).x;
     142           0 :         if (isRtlBlock == (frameOffset >= curOffset)) {
     143           0 :           pos += mVertical
     144           0 :                  ? inlineFrame->GetSize().height
     145           0 :                  : inlineFrame->GetSize().width;
     146             :         }
     147           0 :         inlineFrame = inlineFrame->GetNextContinuation();
     148             :       }
     149           0 :       if (isRtlBlock) {
     150             :         // aFrame itself is also to the right of its left edge, so add its width.
     151           0 :         pos += mVertical ? aFrame->GetSize().height : aFrame->GetSize().width;
     152             :         // pos is now the distance from the left [top] edge of aFrame to the right [bottom] edge
     153             :         // of the unbroken content. Change it to indicate the distance from the
     154             :         // left [top] edge of the unbroken content to the left [top] edge of aFrame.
     155           0 :         pos = mUnbrokenMeasure - pos;
     156             :       }
     157             :     } else {
     158           0 :       pos = mContinuationPoint;
     159             :     }
     160             : 
     161             :     // Assume background-origin: border and return a rect with offsets
     162             :     // relative to (0,0).  If we have a different background-origin,
     163             :     // then our rect should be deflated appropriately by our caller.
     164           0 :     return mVertical
     165           0 :       ? nsRect(0, -pos, mFrame->GetSize().width, mUnbrokenMeasure)
     166           0 :       : nsRect(-pos, 0, mUnbrokenMeasure, mFrame->GetSize().height);
     167             :   }
     168             : 
     169             :   /**
     170             :    * Return a continuous rect for (an inline) aFrame relative to the
     171             :    * continuation that should draw the left[top]-border.  This is used when painting
     172             :    * borders and clipping backgrounds.  This may NOT be the same continuous rect
     173             :    * as for drawing backgrounds; the continuation with the left[top]-border might be
     174             :    * somewhere in the middle of that rect (e.g. BIDI), in those cases we need
     175             :    * the reverse background order starting at the left[top]-border continuation.
     176             :    */
     177           0 :   nsRect GetBorderContinuousRect(nsIFrame* aFrame, nsRect aBorderArea)
     178             :   {
     179             :     // Calling GetContinuousRect(aFrame) here may lead to Reset/Init which
     180             :     // resets our mPIStartBorderData so we save it ...
     181           0 :     PhysicalInlineStartBorderData saved(mPIStartBorderData);
     182           0 :     nsRect joinedBorderArea = GetContinuousRect(aFrame);
     183           0 :     if (!saved.mIsValid || saved.mFrame != mPIStartBorderData.mFrame) {
     184           0 :       if (aFrame == mPIStartBorderData.mFrame) {
     185           0 :         if (mVertical) {
     186           0 :           mPIStartBorderData.SetCoord(joinedBorderArea.y);
     187             :         } else {
     188           0 :           mPIStartBorderData.SetCoord(joinedBorderArea.x);
     189             :         }
     190           0 :       } else if (mPIStartBorderData.mFrame) {
     191           0 :         if (mVertical) {
     192           0 :           mPIStartBorderData.SetCoord(GetContinuousRect(mPIStartBorderData.mFrame).y);
     193             :         } else {
     194           0 :           mPIStartBorderData.SetCoord(GetContinuousRect(mPIStartBorderData.mFrame).x);
     195             :         }
     196             :       }
     197             :     } else {
     198             :       // ... and restore it when possible.
     199           0 :       mPIStartBorderData.mCoord = saved.mCoord;
     200             :     }
     201           0 :     if (mVertical) {
     202           0 :       if (joinedBorderArea.y > mPIStartBorderData.mCoord) {
     203           0 :         joinedBorderArea.y =
     204           0 :           -(mUnbrokenMeasure + joinedBorderArea.y - aBorderArea.height);
     205             :       } else {
     206           0 :         joinedBorderArea.y -= mPIStartBorderData.mCoord;
     207             :       }
     208             :     } else {
     209           0 :       if (joinedBorderArea.x > mPIStartBorderData.mCoord) {
     210           0 :         joinedBorderArea.x =
     211           0 :           -(mUnbrokenMeasure + joinedBorderArea.x - aBorderArea.width);
     212             :       } else {
     213           0 :         joinedBorderArea.x -= mPIStartBorderData.mCoord;
     214             :       }
     215             :     }
     216           0 :     return joinedBorderArea;
     217             :   }
     218             : 
     219             :   nsRect GetBoundingRect(nsIFrame* aFrame)
     220             :   {
     221             :     SetFrame(aFrame);
     222             : 
     223             :     // Move the offsets relative to (0,0) which puts the bounding box into
     224             :     // our coordinate system rather than our parent's.  We do this by
     225             :     // moving it the back distance from us to the bounding box.
     226             :     // This also assumes background-origin: border, so our caller will
     227             :     // need to deflate us if needed.
     228             :     nsRect boundingBox(mBoundingBox);
     229             :     nsPoint point = mFrame->GetPosition();
     230             :     boundingBox.MoveBy(-point.x, -point.y);
     231             : 
     232             :     return boundingBox;
     233             :   }
     234             : 
     235             : protected:
     236             :   // This is a coordinate on the inline axis, but is not a true logical inline-
     237             :   // coord because it is always measured from left to right (if horizontal) or
     238             :   // from top to bottom (if vertical), ignoring any bidi RTL directionality.
     239             :   // We'll call this "physical inline start", or PIStart for short.
     240             :   struct PhysicalInlineStartBorderData {
     241             :     nsIFrame* mFrame;   // the continuation that may have a left-border
     242             :     nscoord   mCoord;   // cached GetContinuousRect(mFrame).x or .y
     243             :     bool      mIsValid; // true if mCoord is valid
     244          35 :     void Reset() { mFrame = nullptr; mIsValid = false; }
     245           0 :     void SetCoord(nscoord aCoord) { mCoord = aCoord; mIsValid = true; }
     246             :   };
     247             : 
     248             :   nsIFrame*      mFrame;
     249             :   nsIFrame*      mLineContainer;
     250             :   nsRect         mBoundingBox;
     251             :   nscoord        mContinuationPoint;
     252             :   nscoord        mUnbrokenMeasure;
     253             :   nscoord        mLineContinuationPoint;
     254             :   PhysicalInlineStartBorderData mPIStartBorderData;
     255             :   bool           mBidiEnabled;
     256             :   bool           mVertical;
     257             : 
     258           0 :   void SetFrame(nsIFrame* aFrame)
     259             :   {
     260           0 :     NS_PRECONDITION(aFrame, "Need a frame");
     261           0 :     NS_ASSERTION(gFrameTreeLockCount > 0,
     262             :                  "Can't call this when frame tree is not locked");
     263             : 
     264           0 :     if (aFrame == mFrame) {
     265           0 :       return;
     266             :     }
     267             : 
     268           0 :     nsIFrame *prevContinuation = GetPrevContinuation(aFrame);
     269             : 
     270           0 :     if (!prevContinuation || mFrame != prevContinuation) {
     271             :       // Ok, we've got the wrong frame.  We have to start from scratch.
     272           0 :       Reset();
     273           0 :       Init(aFrame);
     274           0 :       return;
     275             :     }
     276             : 
     277             :     // Get our last frame's size and add its width to our continuation
     278             :     // point before we cache the new frame.
     279           0 :     mContinuationPoint += mVertical ? mFrame->GetSize().height
     280           0 :                                     : mFrame->GetSize().width;
     281             : 
     282             :     // If this a new line, update mLineContinuationPoint.
     283           0 :     if (mBidiEnabled &&
     284           0 :         (aFrame->GetPrevInFlow() || !AreOnSameLine(mFrame, aFrame))) {
     285           0 :        mLineContinuationPoint = mContinuationPoint;
     286             :     }
     287             : 
     288           0 :     mFrame = aFrame;
     289             :   }
     290             : 
     291           0 :   nsIFrame* GetPrevContinuation(nsIFrame* aFrame)
     292             :   {
     293           0 :     nsIFrame* prevCont = aFrame->GetPrevContinuation();
     294           0 :     if (!prevCont &&
     295           0 :         (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
     296             :       nsIFrame* block =
     297           0 :         aFrame->GetProperty(nsIFrame::IBSplitPrevSibling());
     298           0 :       if (block) {
     299             :         // The {ib} properties are only stored on first continuations
     300           0 :         NS_ASSERTION(!block->GetPrevContinuation(),
     301             :                      "Incorrect value for IBSplitPrevSibling");
     302             :         prevCont =
     303           0 :           block->GetProperty(nsIFrame::IBSplitPrevSibling());
     304           0 :         NS_ASSERTION(prevCont, "How did that happen?");
     305             :       }
     306             :     }
     307           0 :     return prevCont;
     308             :   }
     309             : 
     310           0 :   nsIFrame* GetNextContinuation(nsIFrame* aFrame)
     311             :   {
     312           0 :     nsIFrame* nextCont = aFrame->GetNextContinuation();
     313           0 :     if (!nextCont &&
     314           0 :         (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
     315             :       // The {ib} properties are only stored on first continuations
     316           0 :       aFrame = aFrame->FirstContinuation();
     317           0 :       nsIFrame* block = aFrame->GetProperty(nsIFrame::IBSplitSibling());
     318           0 :       if (block) {
     319           0 :         nextCont = block->GetProperty(nsIFrame::IBSplitSibling());
     320           0 :         NS_ASSERTION(nextCont, "How did that happen?");
     321             :       }
     322             :     }
     323           0 :     return nextCont;
     324             :   }
     325             : 
     326           0 :   void Init(nsIFrame* aFrame)
     327             :   {
     328           0 :     mPIStartBorderData.Reset();
     329           0 :     mBidiEnabled = aFrame->PresContext()->BidiEnabled();
     330           0 :     if (mBidiEnabled) {
     331             :       // Find the line container frame
     332           0 :       mLineContainer = aFrame;
     333           0 :       while (mLineContainer &&
     334           0 :              mLineContainer->IsFrameOfType(nsIFrame::eLineParticipant)) {
     335           0 :         mLineContainer = mLineContainer->GetParent();
     336             :       }
     337             : 
     338           0 :       MOZ_ASSERT(mLineContainer, "Cannot find line containing frame.");
     339           0 :       MOZ_ASSERT(mLineContainer != aFrame, "line container frame "
     340             :                  "should be an ancestor of the target frame.");
     341             :     }
     342             : 
     343           0 :     mVertical = aFrame->GetWritingMode().IsVertical();
     344             : 
     345             :     // Start with the previous flow frame as our continuation point
     346             :     // is the total of the widths of the previous frames.
     347           0 :     nsIFrame* inlineFrame = GetPrevContinuation(aFrame);
     348           0 :     while (inlineFrame) {
     349           0 :       if (!mPIStartBorderData.mFrame &&
     350           0 :           !(mVertical ? inlineFrame->GetSkipSides().Top()
     351           0 :                       : inlineFrame->GetSkipSides().Left())) {
     352           0 :         mPIStartBorderData.mFrame = inlineFrame;
     353             :       }
     354           0 :       nsRect rect = inlineFrame->GetRect();
     355           0 :       mContinuationPoint += mVertical ? rect.height : rect.width;
     356           0 :       if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) {
     357           0 :         mLineContinuationPoint += mVertical ? rect.height : rect.width;
     358             :       }
     359           0 :       mUnbrokenMeasure += mVertical ? rect.height : rect.width;
     360           0 :       mBoundingBox.UnionRect(mBoundingBox, rect);
     361           0 :       inlineFrame = GetPrevContinuation(inlineFrame);
     362             :     }
     363             : 
     364             :     // Next add this frame and subsequent frames to the bounding box and
     365             :     // unbroken width.
     366           0 :     inlineFrame = aFrame;
     367           0 :     while (inlineFrame) {
     368           0 :       if (!mPIStartBorderData.mFrame &&
     369           0 :           !(mVertical ? inlineFrame->GetSkipSides().Top()
     370           0 :                       : inlineFrame->GetSkipSides().Left())) {
     371           0 :         mPIStartBorderData.mFrame = inlineFrame;
     372             :       }
     373           0 :       nsRect rect = inlineFrame->GetRect();
     374           0 :       mUnbrokenMeasure += mVertical ? rect.height : rect.width;
     375           0 :       mBoundingBox.UnionRect(mBoundingBox, rect);
     376           0 :       inlineFrame = GetNextContinuation(inlineFrame);
     377             :     }
     378             : 
     379           0 :     mFrame = aFrame;
     380           0 :   }
     381             : 
     382           0 :   bool AreOnSameLine(nsIFrame* aFrame1, nsIFrame* aFrame2) {
     383           0 :     if (nsBlockFrame* blockFrame = do_QueryFrame(mLineContainer)) {
     384             :       bool isValid1, isValid2;
     385           0 :       nsBlockInFlowLineIterator it1(blockFrame, aFrame1, &isValid1);
     386           0 :       nsBlockInFlowLineIterator it2(blockFrame, aFrame2, &isValid2);
     387           0 :       return isValid1 && isValid2 &&
     388             :         // Make sure aFrame1 and aFrame2 are in the same continuation of
     389             :         // blockFrame.
     390           0 :         it1.GetContainer() == it2.GetContainer() &&
     391             :         // And on the same line in it
     392           0 :         it1.GetLine() == it2.GetLine();
     393             :     }
     394           0 :     if (nsRubyTextContainerFrame* rtcFrame = do_QueryFrame(mLineContainer)) {
     395           0 :       nsBlockFrame* block = nsLayoutUtils::FindNearestBlockAncestor(rtcFrame);
     396             :       // Ruby text container can only hold one line of text, so if they
     397             :       // are in the same continuation, they are in the same line. Since
     398             :       // ruby text containers are bidi isolate, they are never split for
     399             :       // bidi reordering, which means being in different continuation
     400             :       // indicates being in different lines.
     401           0 :       for (nsIFrame* frame = rtcFrame->FirstContinuation();
     402           0 :            frame; frame = frame->GetNextContinuation()) {
     403             :         bool isDescendant1 =
     404           0 :           nsLayoutUtils::IsProperAncestorFrame(frame, aFrame1, block);
     405             :         bool isDescendant2 =
     406           0 :           nsLayoutUtils::IsProperAncestorFrame(frame, aFrame2, block);
     407           0 :         if (isDescendant1 && isDescendant2) {
     408           0 :           return true;
     409             :         }
     410           0 :         if (isDescendant1 || isDescendant2) {
     411           0 :           return false;
     412             :         }
     413             :       }
     414           0 :       MOZ_ASSERT_UNREACHABLE("None of the frames is a descendant of this rtc?");
     415             :     }
     416           0 :     MOZ_ASSERT_UNREACHABLE("Do we have any other type of line container?");
     417             :     return false;
     418             :   }
     419             : };
     420             : 
     421             : /* Local functions */
     422             : static nscolor MakeBevelColor(mozilla::Side whichSide, uint8_t style,
     423             :                               nscolor aBackgroundColor,
     424             :                               nscolor aBorderColor);
     425             : 
     426             : static InlineBackgroundData* gInlineBGData = nullptr;
     427             : 
     428             : // Initialize any static variables used by nsCSSRendering.
     429           3 : void nsCSSRendering::Init()
     430             : {
     431           3 :   NS_ASSERTION(!gInlineBGData, "Init called twice");
     432           3 :   gInlineBGData = new InlineBackgroundData();
     433           3 : }
     434             : 
     435             : // Clean up any global variables used by nsCSSRendering.
     436           0 : void nsCSSRendering::Shutdown()
     437             : {
     438           0 :   delete gInlineBGData;
     439           0 :   gInlineBGData = nullptr;
     440           0 : }
     441             : 
     442             : /**
     443             :  * Make a bevel color
     444             :  */
     445             : static nscolor
     446           0 : MakeBevelColor(mozilla::Side whichSide, uint8_t style,
     447             :                nscolor aBackgroundColor, nscolor aBorderColor)
     448             : {
     449             : 
     450             :   nscolor colors[2];
     451             :   nscolor theColor;
     452             : 
     453             :   // Given a background color and a border color
     454             :   // calculate the color used for the shading
     455           0 :   NS_GetSpecial3DColors(colors, aBackgroundColor, aBorderColor);
     456             : 
     457           0 :   if ((style == NS_STYLE_BORDER_STYLE_OUTSET) ||
     458             :       (style == NS_STYLE_BORDER_STYLE_RIDGE)) {
     459             :     // Flip colors for these two border styles
     460           0 :     switch (whichSide) {
     461           0 :     case eSideBottom: whichSide = eSideTop;    break;
     462           0 :     case eSideRight:  whichSide = eSideLeft;   break;
     463           0 :     case eSideTop:    whichSide = eSideBottom; break;
     464           0 :     case eSideLeft:   whichSide = eSideRight;  break;
     465             :     }
     466             :   }
     467             : 
     468           0 :   switch (whichSide) {
     469             :   case eSideBottom:
     470           0 :     theColor = colors[1];
     471           0 :     break;
     472             :   case eSideRight:
     473           0 :     theColor = colors[1];
     474           0 :     break;
     475             :   case eSideTop:
     476           0 :     theColor = colors[0];
     477           0 :     break;
     478             :   case eSideLeft:
     479             :   default:
     480           0 :     theColor = colors[0];
     481           0 :     break;
     482             :   }
     483           0 :   return theColor;
     484             : }
     485             : 
     486             : static bool
     487         391 : GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
     488             :          const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
     489             :          nscoord aRadii[8])
     490             : {
     491             :   bool haveRoundedCorners;
     492         391 :   nsSize sz = aBorderArea.Size();
     493         391 :   nsSize frameSize = aForFrame->GetSize();
     494        1564 :   if (&aBorder == aForFrame->StyleBorder() &&
     495        1564 :       frameSize == aOrigBorderArea.Size()) {
     496         391 :     haveRoundedCorners = aForFrame->GetBorderRadii(sz, sz, Sides(), aRadii);
     497             :    } else {
     498             :     haveRoundedCorners =
     499           0 :       nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius, frameSize, sz, Sides(), aRadii);
     500             :   }
     501             : 
     502         391 :   return haveRoundedCorners;
     503             : }
     504             : 
     505             : static bool
     506          34 : GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
     507             :          const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
     508             :          RectCornerRadii* aBgRadii)
     509             : {
     510             :   nscoord radii[8];
     511          34 :   bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aOrigBorderArea, aBorderArea, radii);
     512             : 
     513          34 :   if (haveRoundedCorners) {
     514          17 :     auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
     515          17 :     nsCSSRendering::ComputePixelRadii(radii, d2a, aBgRadii);
     516             :   }
     517          34 :   return haveRoundedCorners;
     518             : }
     519             : 
     520             : static nsRect
     521           0 : JoinBoxesForBlockAxisSlice(nsIFrame* aFrame, const nsRect& aBorderArea)
     522             : {
     523             :   // Inflate the block-axis size as if our continuations were laid out
     524             :   // adjacent in that axis.  Note that we don't touch the inline size.
     525           0 :   nsRect borderArea = aBorderArea;
     526           0 :   nscoord bSize = 0;
     527           0 :   auto wm = aFrame->GetWritingMode();
     528           0 :   nsIFrame* f = aFrame->GetNextContinuation();
     529           0 :   for (; f; f = f->GetNextContinuation()) {
     530           0 :     MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
     531             :                "anonymous ib-split block shouldn't have border/background");
     532           0 :     bSize += f->BSize(wm);
     533             :   }
     534           0 :   (wm.IsVertical() ? borderArea.width : borderArea.height) += bSize;
     535           0 :   bSize = 0;
     536           0 :   f = aFrame->GetPrevContinuation();
     537           0 :   for (; f; f = f->GetPrevContinuation()) {
     538           0 :     MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
     539             :                "anonymous ib-split block shouldn't have border/background");
     540           0 :     bSize += f->BSize(wm);
     541             :   }
     542           0 :   (wm.IsVertical() ? borderArea.x : borderArea.y) -= bSize;
     543           0 :   (wm.IsVertical() ? borderArea.width : borderArea.height) += bSize;
     544           0 :   return borderArea;
     545             : }
     546             : 
     547             : /**
     548             :  * Inflate aBorderArea which is relative to aFrame's origin to calculate
     549             :  * a hypothetical non-split frame area for all the continuations.
     550             :  * See "Joining Boxes for 'slice'" in
     551             :  * http://dev.w3.org/csswg/css-break/#break-decoration
     552             :  */
     553             : enum InlineBoxOrder { eForBorder, eForBackground };
     554             : static nsRect
     555           0 : JoinBoxesForSlice(nsIFrame* aFrame, const nsRect& aBorderArea,
     556             :                   InlineBoxOrder aOrder)
     557             : {
     558           0 :   if (static_cast<nsInlineFrame*>(do_QueryFrame(aFrame))) {
     559             :     return (aOrder == eForBorder
     560           0 :             ? gInlineBGData->GetBorderContinuousRect(aFrame, aBorderArea)
     561             :             : gInlineBGData->GetContinuousRect(aFrame)) +
     562           0 :       aBorderArea.TopLeft();
     563             :   }
     564           0 :   return JoinBoxesForBlockAxisSlice(aFrame, aBorderArea);
     565             : }
     566             : 
     567             : static bool
     568         769 : IsBoxDecorationSlice(const nsStyleBorder& aStyleBorder)
     569             : {
     570         769 :   return aStyleBorder.mBoxDecorationBreak == StyleBoxDecorationBreak::Slice;
     571             : }
     572             : 
     573             : static nsRect
     574         479 : BoxDecorationRectForBorder(nsIFrame* aFrame, const nsRect& aBorderArea,
     575             :                            Sides aSkipSides,
     576             :                            const nsStyleBorder* aStyleBorder = nullptr)
     577             : {
     578         479 :   if (!aStyleBorder) {
     579          29 :     aStyleBorder = aFrame->StyleBorder();
     580             :   }
     581             :   // If aSkipSides.IsEmpty() then there are no continuations, or it's
     582             :   // a ::first-letter that wants all border sides on the first continuation.
     583         958 :   return ::IsBoxDecorationSlice(*aStyleBorder) && !aSkipSides.IsEmpty()
     584         479 :            ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBorder)
     585           0 :            : aBorderArea;
     586             : }
     587             : 
     588             : static nsRect
     589         253 : BoxDecorationRectForBackground(nsIFrame* aFrame, const nsRect& aBorderArea,
     590             :                                Sides aSkipSides,
     591             :                                const nsStyleBorder* aStyleBorder = nullptr)
     592             : {
     593         253 :   if (!aStyleBorder) {
     594         194 :     aStyleBorder = aFrame->StyleBorder();
     595             :   }
     596             :   // If aSkipSides.IsEmpty() then there are no continuations, or it's
     597             :   // a ::first-letter that wants all border sides on the first continuation.
     598         506 :   return ::IsBoxDecorationSlice(*aStyleBorder) && !aSkipSides.IsEmpty()
     599         253 :            ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBackground)
     600           0 :            : aBorderArea;
     601             : }
     602             : 
     603             : //----------------------------------------------------------------------
     604             : // Thebes Border Rendering Code Start
     605             : 
     606             : /*
     607             :  * Compute the float-pixel radii that should be used for drawing
     608             :  * this border/outline, given the various input bits.
     609             :  */
     610             : /* static */ void
     611         119 : nsCSSRendering::ComputePixelRadii(const nscoord *aAppUnitsRadii,
     612             :                                   nscoord aAppUnitsPerPixel,
     613             :                                   RectCornerRadii *oBorderRadii)
     614             : {
     615             :   Float radii[8];
     616        1071 :   NS_FOR_CSS_HALF_CORNERS(corner)
     617         952 :     radii[corner] = Float(aAppUnitsRadii[corner]) / aAppUnitsPerPixel;
     618             : 
     619         119 :   (*oBorderRadii)[C_TL] = Size(radii[eCornerTopLeftX],
     620             :                                radii[eCornerTopLeftY]);
     621         119 :   (*oBorderRadii)[C_TR] = Size(radii[eCornerTopRightX],
     622             :                                radii[eCornerTopRightY]);
     623         119 :   (*oBorderRadii)[C_BR] = Size(radii[eCornerBottomRightX],
     624             :                                radii[eCornerBottomRightY]);
     625         119 :   (*oBorderRadii)[C_BL] = Size(radii[eCornerBottomLeftX],
     626             :                                radii[eCornerBottomLeftY]);
     627         119 : }
     628             : 
     629             : DrawResult
     630          37 : nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
     631             :                             gfxContext& aRenderingContext,
     632             :                             nsIFrame* aForFrame,
     633             :                             const nsRect& aDirtyRect,
     634             :                             const nsRect& aBorderArea,
     635             :                             nsStyleContext* aStyleContext,
     636             :                             PaintBorderFlags aFlags,
     637             :                             Sides aSkipSides)
     638             : {
     639          74 :   AUTO_PROFILER_LABEL("nsCSSRendering::PaintBorder", GRAPHICS);
     640             : 
     641          37 :   nsStyleContext *styleIfVisited = aStyleContext->GetStyleIfVisited();
     642          37 :   const nsStyleBorder *styleBorder = aStyleContext->StyleBorder();
     643             :   // Don't check RelevantLinkVisited here, since we want to take the
     644             :   // same amount of time whether or not it's true.
     645          37 :   if (!styleIfVisited) {
     646             :     return PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
     647             :                                       aDirtyRect, aBorderArea, *styleBorder,
     648          37 :                                       aStyleContext, aFlags, aSkipSides);
     649             :   }
     650             : 
     651           0 :   nsStyleBorder newStyleBorder(*styleBorder);
     652             : 
     653           0 :   NS_FOR_CSS_SIDES(side) {
     654             :     nscolor color = aStyleContext->
     655           0 :       GetVisitedDependentColor(nsStyleBorder::BorderColorFieldFor(side));
     656           0 :     newStyleBorder.mBorderColor[side] = StyleComplexColor::FromColor(color);
     657             :   }
     658             :   return PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
     659             :                                     aDirtyRect, aBorderArea, newStyleBorder,
     660           0 :                                     aStyleContext, aFlags, aSkipSides);
     661             : }
     662             : 
     663             : Maybe<nsCSSBorderRenderer>
     664           0 : nsCSSRendering::CreateBorderRenderer(nsPresContext* aPresContext,
     665             :                                      DrawTarget* aDrawTarget,
     666             :                                      nsIFrame* aForFrame,
     667             :                                      const nsRect& aDirtyRect,
     668             :                                      const nsRect& aBorderArea,
     669             :                                      nsStyleContext* aStyleContext,
     670             :                                      Sides aSkipSides)
     671             : {
     672           0 :   nsStyleContext *styleIfVisited = aStyleContext->GetStyleIfVisited();
     673           0 :   const nsStyleBorder *styleBorder = aStyleContext->StyleBorder();
     674             :   // Don't check RelevantLinkVisited here, since we want to take the
     675             :   // same amount of time whether or not it's true.
     676           0 :   if (!styleIfVisited) {
     677             :     return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
     678             :                                                aForFrame, aDirtyRect,
     679             :                                                aBorderArea, *styleBorder,
     680           0 :                                                aStyleContext, aSkipSides);
     681             :   }
     682             : 
     683           0 :   nsStyleBorder newStyleBorder(*styleBorder);
     684             : 
     685           0 :   NS_FOR_CSS_SIDES(side) {
     686             :     nscolor color = aStyleContext->
     687           0 :       GetVisitedDependentColor(nsStyleBorder::BorderColorFieldFor(side));
     688           0 :     newStyleBorder.mBorderColor[side] = StyleComplexColor::FromColor(color);
     689             :   }
     690             :   return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
     691             :                                              aForFrame, aDirtyRect, aBorderArea,
     692             :                                              newStyleBorder, aStyleContext,
     693           0 :                                              aSkipSides);
     694             : }
     695             : 
     696             : nsCSSBorderRenderer
     697          34 : ConstructBorderRenderer(nsPresContext* aPresContext,
     698             :                         nsStyleContext* aStyleContext,
     699             :                         DrawTarget* aDrawTarget,
     700             :                         nsIFrame* aForFrame,
     701             :                         const nsRect& aDirtyRect,
     702             :                         const nsRect& aBorderArea,
     703             :                         const nsStyleBorder& aStyleBorder,
     704             :                         Sides aSkipSides,
     705             :                         bool* aNeedsClip)
     706             : {
     707          34 :   nsMargin border = aStyleBorder.GetComputedBorder();
     708             : 
     709             :   // Get our style context's color struct.
     710          34 :   const nsStyleColor* ourColor = aStyleContext->StyleColor();
     711             : 
     712             :   // In NavQuirks mode we want to use the parent's context as a starting point
     713             :   // for determining the background color.
     714          34 :   bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
     715          34 :   nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(aForFrame, quirks);
     716          34 :   nsStyleContext* bgContext = bgFrame->StyleContext();
     717             :   nscolor bgColor = bgContext->
     718          34 :     GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
     719             : 
     720             :   // Compute the outermost boundary of the area that might be painted.
     721             :   // Same coordinate space as aBorderArea & aBGClipRect.
     722             :   nsRect joinedBorderArea =
     723          68 :     ::BoxDecorationRectForBorder(aForFrame, aBorderArea, aSkipSides, &aStyleBorder);
     724          34 :   RectCornerRadii bgRadii;
     725          34 :   ::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
     726             : 
     727          34 :   PrintAsFormatString(" joinedBorderArea: %d %d %d %d\n", joinedBorderArea.x, joinedBorderArea.y,
     728          34 :      joinedBorderArea.width, joinedBorderArea.height);
     729             : 
     730             :   // start drawing
     731          34 :   if (::IsBoxDecorationSlice(aStyleBorder)) {
     732          34 :     if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
     733             :       // No need for a clip, just skip the sides we don't want.
     734          34 :       border.ApplySkipSides(aSkipSides);
     735             :     } else {
     736             :       // We're drawing borders around the joined continuation boxes so we need
     737             :       // to clip that to the slice that we want for this frame.
     738           0 :       *aNeedsClip = true;
     739             :     }
     740             :   } else {
     741           0 :     MOZ_ASSERT(joinedBorderArea.IsEqualEdges(aBorderArea),
     742             :                "Should use aBorderArea for box-decoration-break:clone");
     743           0 :     MOZ_ASSERT(aForFrame->GetSkipSides().IsEmpty() ||
     744             :                IS_TRUE_OVERFLOW_CONTAINER(aForFrame),
     745             :                "Should not skip sides for box-decoration-break:clone except "
     746             :                "::first-letter/line continuations or other frame types that "
     747             :                "don't have borders but those shouldn't reach this point. "
     748             :                "Overflow containers do reach this point though.");
     749           0 :     border.ApplySkipSides(aSkipSides);
     750             :   }
     751             : 
     752             :   // Convert to dev pixels.
     753          34 :   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
     754          34 :   Rect joinedBorderAreaPx = NSRectToRect(joinedBorderArea, twipsPerPixel);
     755          34 :   Float borderWidths[4] = { Float(border.top) / twipsPerPixel,
     756          34 :                                    Float(border.right) / twipsPerPixel,
     757          34 :                                    Float(border.bottom) / twipsPerPixel,
     758         102 :                                    Float(border.left) / twipsPerPixel };
     759          34 :   Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel);
     760             : 
     761             :   uint8_t borderStyles[4];
     762             :   nscolor borderColors[4];
     763             :   nsBorderColors* compositeColors[4];
     764             : 
     765             :   // pull out styles, colors, composite colors
     766         170 :   NS_FOR_CSS_SIDES (i) {
     767         136 :     borderStyles[i] = aStyleBorder.GetBorderStyle(i);
     768         136 :     borderColors[i] = ourColor->CalcComplexColor(aStyleBorder.mBorderColor[i]);
     769         136 :     aStyleBorder.GetCompositeColors(i, &compositeColors[i]);
     770             :   }
     771             : 
     772          34 :   PrintAsFormatString(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
     773             : 
     774          34 :   nsIDocument* document = nullptr;
     775          34 :   nsIContent* content = aForFrame->GetContent();
     776          34 :   if (content) {
     777          34 :     document = content->OwnerDoc();
     778             :   }
     779             : 
     780             :   return nsCSSBorderRenderer(aPresContext,
     781             :                              document,
     782             :                              aDrawTarget,
     783             :                              dirtyRect,
     784             :                              joinedBorderAreaPx,
     785             :                              borderStyles,
     786             :                              borderWidths,
     787             :                              bgRadii,
     788             :                              borderColors,
     789             :                              compositeColors,
     790          68 :                              bgColor);
     791             : }
     792             : 
     793             : 
     794             : DrawResult
     795          37 : nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
     796             :                                            gfxContext& aRenderingContext,
     797             :                                            nsIFrame* aForFrame,
     798             :                                            const nsRect& aDirtyRect,
     799             :                                            const nsRect& aBorderArea,
     800             :                                            const nsStyleBorder& aStyleBorder,
     801             :                                            nsStyleContext* aStyleContext,
     802             :                                            PaintBorderFlags aFlags,
     803             :                                            Sides aSkipSides)
     804             : {
     805          37 :   DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
     806             : 
     807          37 :   PrintAsStringNewline("++ PaintBorder");
     808             : 
     809             :   // Check to see if we have an appearance defined.  If so, we let the theme
     810             :   // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
     811             :   // may be different!  Always use |aStyleContext|!
     812          37 :   const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
     813          37 :   if (displayData->mAppearance) {
     814           0 :     nsITheme *theme = aPresContext->GetTheme();
     815           0 :     if (theme &&
     816           0 :         theme->ThemeSupportsWidget(aPresContext, aForFrame,
     817           0 :                                    displayData->mAppearance)) {
     818           0 :       return DrawResult::SUCCESS; // Let the theme handle it.
     819             :     }
     820             :   }
     821             : 
     822          37 :   if (!aStyleBorder.mBorderImageSource.IsEmpty()) {
     823           3 :     DrawResult result = DrawResult::SUCCESS;
     824             : 
     825           3 :     uint32_t irFlags = 0;
     826           3 :     if (aFlags & PaintBorderFlags::SYNC_DECODE_IMAGES) {
     827           0 :       irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
     828             :     }
     829             : 
     830             :     // Creating the border image renderer will request a decode, and we rely on
     831             :     // that happening.
     832             :     Maybe<nsCSSBorderImageRenderer> renderer =
     833             :       nsCSSBorderImageRenderer::CreateBorderImageRenderer(aPresContext, aForFrame, aBorderArea,
     834             :                                                           aStyleBorder, aDirtyRect, aSkipSides,
     835           3 :                                                           irFlags, &result);
     836           3 :     if (aStyleBorder.IsBorderImageLoaded()) {
     837           3 :       if (!renderer) {
     838           0 :         return result;
     839             :       }
     840             : 
     841           3 :       return renderer->DrawBorderImage(aPresContext, aRenderingContext,
     842           3 :                                        aForFrame, aDirtyRect);
     843             :     }
     844             :   }
     845             : 
     846          34 :   DrawResult result = DrawResult::SUCCESS;
     847             : 
     848             :   // If we had a border-image, but it wasn't loaded, then we should return
     849             :   // DrawResult::NOT_READY; we'll want to try again if we do a paint with sync
     850             :   // decoding enabled.
     851          34 :   if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
     852           0 :     result = DrawResult::NOT_READY;
     853             :   }
     854             : 
     855          34 :   nsMargin border = aStyleBorder.GetComputedBorder();
     856          41 :   if (0 == border.left && 0 == border.right &&
     857           9 :       0 == border.top  && 0 == border.bottom) {
     858             :     // Empty border area
     859           0 :     return result;
     860             :   }
     861             : 
     862          34 :   bool needsClip = false;
     863             :   nsCSSBorderRenderer br = ConstructBorderRenderer(aPresContext,
     864             :                                                    aStyleContext,
     865             :                                                    &aDrawTarget,
     866             :                                                    aForFrame,
     867             :                                                    aDirtyRect,
     868             :                                                    aBorderArea,
     869             :                                                    aStyleBorder,
     870             :                                                    aSkipSides,
     871          34 :                                                    &needsClip);
     872          34 :   if (needsClip) {
     873             :     aDrawTarget.PushClipRect(
     874           0 :         NSRectToSnappedRect(aBorderArea,
     875           0 :                             aForFrame->PresContext()->AppUnitsPerDevPixel(),
     876           0 :                             aDrawTarget));
     877             :   }
     878             : 
     879          34 :   br.DrawBorders();
     880             : 
     881          34 :   if (needsClip) {
     882           0 :     aDrawTarget.PopClip();
     883             :   }
     884             : 
     885          34 :   PrintAsStringNewline();
     886             : 
     887          34 :   return result;
     888             : }
     889             : 
     890             : Maybe<nsCSSBorderRenderer>
     891           0 : nsCSSRendering::CreateBorderRendererWithStyleBorder(nsPresContext* aPresContext,
     892             :                                                     DrawTarget* aDrawTarget,
     893             :                                                     nsIFrame* aForFrame,
     894             :                                                     const nsRect& aDirtyRect,
     895             :                                                     const nsRect& aBorderArea,
     896             :                                                     const nsStyleBorder& aStyleBorder,
     897             :                                                     nsStyleContext* aStyleContext,
     898             :                                                     Sides aSkipSides)
     899             : {
     900           0 :   const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
     901           0 :   if (displayData->mAppearance) {
     902           0 :     nsITheme *theme = aPresContext->GetTheme();
     903           0 :     if (theme &&
     904           0 :         theme->ThemeSupportsWidget(aPresContext, aForFrame,
     905           0 :                                    displayData->mAppearance)) {
     906           0 :       return Nothing();
     907             :     }
     908             :   }
     909             : 
     910           0 :   if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
     911           0 :     return Nothing();
     912             :   }
     913             : 
     914           0 :   nsMargin border = aStyleBorder.GetComputedBorder();
     915           0 :   if (0 == border.left && 0 == border.right &&
     916           0 :       0 == border.top  && 0 == border.bottom) {
     917             :     // Empty border area
     918           0 :     return Nothing();
     919             :   }
     920             : 
     921           0 :   bool needsClip = false;
     922             :   nsCSSBorderRenderer br = ConstructBorderRenderer(aPresContext,
     923             :                                                    aStyleContext,
     924             :                                                    aDrawTarget,
     925             :                                                    aForFrame,
     926             :                                                    aDirtyRect,
     927             :                                                    aBorderArea,
     928             :                                                    aStyleBorder,
     929             :                                                    aSkipSides,
     930           0 :                                                    &needsClip);
     931           0 :   if (needsClip) {
     932           0 :     return Nothing();
     933             :   }
     934           0 :   return Some(br);
     935             : }
     936             : 
     937             : static nsRect
     938           0 : GetOutlineInnerRect(nsIFrame* aFrame)
     939             : {
     940             :   nsRect* savedOutlineInnerRect =
     941           0 :     aFrame->GetProperty(nsIFrame::OutlineInnerRectProperty());
     942           0 :   if (savedOutlineInnerRect)
     943           0 :     return *savedOutlineInnerRect;
     944           0 :   NS_NOTREACHED("we should have saved a frame property");
     945           0 :   return nsRect(nsPoint(0, 0), aFrame->GetSize());
     946             : }
     947             : 
     948             : Maybe<nsCSSBorderRenderer>
     949           0 : nsCSSRendering::CreateBorderRendererForOutline(nsPresContext* aPresContext,
     950             :                                                gfxContext* aRenderingContext,
     951             :                                                nsIFrame* aForFrame,
     952             :                                                const nsRect& aDirtyRect,
     953             :                                                const nsRect& aBorderArea,
     954             :                                                nsStyleContext* aStyleContext)
     955             : {
     956             :   nscoord             twipsRadii[8];
     957             : 
     958             :   // Get our style context's color struct.
     959           0 :   const nsStyleOutline* ourOutline = aStyleContext->StyleOutline();
     960             : 
     961           0 :   if (!ourOutline->ShouldPaintOutline()) {
     962             :     // Empty outline
     963           0 :     return Nothing();
     964             :   }
     965             : 
     966             :   nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame
     967           0 :     (aForFrame, false);
     968           0 :   nsStyleContext* bgContext = bgFrame->StyleContext();
     969             :   nscolor bgColor = bgContext->
     970           0 :     GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
     971             : 
     972           0 :   nsRect innerRect;
     973           0 :   if (
     974             : #ifdef MOZ_XUL
     975           0 :       aStyleContext->GetPseudoType() == CSSPseudoElementType::XULTree
     976             : #else
     977             :       false
     978             : #endif
     979             :      ) {
     980           0 :     innerRect = aBorderArea;
     981             :   } else {
     982           0 :     innerRect = GetOutlineInnerRect(aForFrame) + aBorderArea.TopLeft();
     983             :   }
     984           0 :   nscoord offset = ourOutline->mOutlineOffset;
     985           0 :   innerRect.Inflate(offset, offset);
     986             :   // If the dirty rect is completely inside the border area (e.g., only the
     987             :   // content is being painted), then we can skip out now
     988             :   // XXX this isn't exactly true for rounded borders, where the inside curves may
     989             :   // encroach into the content area.  A safer calculation would be to
     990             :   // shorten insideRect by the radius one each side before performing this test.
     991           0 :   if (innerRect.Contains(aDirtyRect))
     992           0 :     return Nothing();
     993             : 
     994           0 :   nscoord width = ourOutline->GetOutlineWidth();
     995             : 
     996           0 :   nsRect outerRect = innerRect;
     997           0 :   outerRect.Inflate(width, width);
     998             : 
     999             :   // get the radius for our outline
    1000           0 :   nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(),
    1001           0 :                                outerRect.Size(), Sides(), twipsRadii);
    1002             : 
    1003             :   // Get our conversion values
    1004           0 :   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
    1005             : 
    1006             :   // get the outer rectangles
    1007           0 :   Rect oRect(NSRectToRect(outerRect, twipsPerPixel));
    1008             : 
    1009             :   // convert the radii
    1010           0 :   nsMargin outlineMargin(width, width, width, width);
    1011           0 :   RectCornerRadii outlineRadii;
    1012           0 :   ComputePixelRadii(twipsRadii, twipsPerPixel, &outlineRadii);
    1013             : 
    1014           0 :   uint8_t outlineStyle = ourOutline->mOutlineStyle;
    1015           0 :   if (outlineStyle == NS_STYLE_BORDER_STYLE_AUTO) {
    1016           0 :     if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
    1017           0 :       nsITheme* theme = aPresContext->GetTheme();
    1018           0 :       if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame,
    1019           0 :                                               NS_THEME_FOCUS_OUTLINE)) {
    1020             :         theme->DrawWidgetBackground(aRenderingContext, aForFrame,
    1021             :                                     NS_THEME_FOCUS_OUTLINE, innerRect,
    1022           0 :                                     aDirtyRect);
    1023           0 :         return Nothing();
    1024             :       }
    1025             :     }
    1026           0 :     if (width == 0) {
    1027           0 :       return Nothing(); // empty outline
    1028             :     }
    1029             :     // http://dev.w3.org/csswg/css-ui/#outline
    1030             :     // "User agents may treat 'auto' as 'solid'."
    1031           0 :     outlineStyle = NS_STYLE_BORDER_STYLE_SOLID;
    1032             :   }
    1033             : 
    1034             :   uint8_t outlineStyles[4] = { outlineStyle, outlineStyle,
    1035           0 :                                outlineStyle, outlineStyle };
    1036             : 
    1037             :   // This handles treating the initial color as 'currentColor'; if we
    1038             :   // ever want 'invert' back we'll need to do a bit of work here too.
    1039             :   nscolor outlineColor =
    1040           0 :     aStyleContext->GetVisitedDependentColor(&nsStyleOutline::mOutlineColor);
    1041             :   nscolor outlineColors[4] = { outlineColor,
    1042             :                                outlineColor,
    1043             :                                outlineColor,
    1044           0 :                                outlineColor };
    1045             : 
    1046             :   // convert the border widths
    1047           0 :   Float outlineWidths[4] = { Float(width) / twipsPerPixel,
    1048           0 :                              Float(width) / twipsPerPixel,
    1049           0 :                              Float(width) / twipsPerPixel,
    1050           0 :                              Float(width) / twipsPerPixel };
    1051           0 :   Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel);
    1052             : 
    1053           0 :   nsIDocument* document = nullptr;
    1054           0 :   nsIContent* content = aForFrame->GetContent();
    1055           0 :   if (content) {
    1056           0 :     document = content->OwnerDoc();
    1057             :   }
    1058             : 
    1059           0 :   DrawTarget* dt = aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
    1060             :   nsCSSBorderRenderer br(aPresContext,
    1061             :                          document,
    1062             :                          dt,
    1063             :                          dirtyRect,
    1064             :                          oRect,
    1065             :                          outlineStyles,
    1066             :                          outlineWidths,
    1067             :                          outlineRadii,
    1068             :                          outlineColors,
    1069             :                          nullptr,
    1070           0 :                          bgColor);
    1071             : 
    1072           0 :   return Some(br);
    1073             : }
    1074             : 
    1075             : void
    1076           0 : nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
    1077             :                              gfxContext& aRenderingContext,
    1078             :                              nsIFrame* aForFrame,
    1079             :                              const nsRect& aDirtyRect,
    1080             :                              const nsRect& aBorderArea,
    1081             :                              nsStyleContext* aStyleContext)
    1082             : {
    1083             :   Maybe<nsCSSBorderRenderer> br = CreateBorderRendererForOutline(aPresContext,
    1084             :                                                                  &aRenderingContext,
    1085             :                                                                  aForFrame,
    1086             :                                                                  aDirtyRect,
    1087             :                                                                  aBorderArea,
    1088           0 :                                                                  aStyleContext);
    1089           0 :   if (!br) {
    1090           0 :     return;
    1091             :   }
    1092             : 
    1093             :   // start drawing
    1094           0 :   br->DrawBorders();
    1095             : 
    1096           0 :   PrintAsStringNewline();
    1097             : }
    1098             : 
    1099             : void
    1100           0 : nsCSSRendering::PaintFocus(nsPresContext* aPresContext,
    1101             :                            DrawTarget* aDrawTarget,
    1102             :                            const nsRect& aFocusRect,
    1103             :                            nscolor aColor)
    1104             : {
    1105           0 :   nscoord oneCSSPixel = nsPresContext::CSSPixelsToAppUnits(1);
    1106           0 :   nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
    1107             : 
    1108           0 :   Rect focusRect(NSRectToRect(aFocusRect, oneDevPixel));
    1109             : 
    1110           0 :   RectCornerRadii focusRadii;
    1111             :   {
    1112           0 :     nscoord twipsRadii[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    1113           0 :     ComputePixelRadii(twipsRadii, oneDevPixel, &focusRadii);
    1114             :   }
    1115           0 :   Float focusWidths[4] = { Float(oneCSSPixel) / oneDevPixel,
    1116           0 :                            Float(oneCSSPixel) / oneDevPixel,
    1117           0 :                            Float(oneCSSPixel) / oneDevPixel,
    1118           0 :                            Float(oneCSSPixel) / oneDevPixel };
    1119             : 
    1120             :   uint8_t focusStyles[4] = { NS_STYLE_BORDER_STYLE_DOTTED,
    1121             :                              NS_STYLE_BORDER_STYLE_DOTTED,
    1122             :                              NS_STYLE_BORDER_STYLE_DOTTED,
    1123           0 :                              NS_STYLE_BORDER_STYLE_DOTTED };
    1124           0 :   nscolor focusColors[4] = { aColor, aColor, aColor, aColor };
    1125             : 
    1126             :   // Because this renders a dotted border, the background color
    1127             :   // should not be used.  Therefore, we provide a value that will
    1128             :   // be blatantly wrong if it ever does get used.  (If this becomes
    1129             :   // something that CSS can style, this function will then have access
    1130             :   // to a style context and can use the same logic that PaintBorder
    1131             :   // and PaintOutline do.)
    1132             :   nsCSSBorderRenderer br(aPresContext,
    1133             :                          nullptr,
    1134             :                          aDrawTarget,
    1135             :                          focusRect,
    1136             :                          focusRect,
    1137             :                          focusStyles,
    1138             :                          focusWidths,
    1139             :                          focusRadii,
    1140             :                          focusColors,
    1141             :                          nullptr,
    1142           0 :                          NS_RGB(255, 0, 0));
    1143           0 :   br.DrawBorders();
    1144             : 
    1145           0 :   PrintAsStringNewline();
    1146           0 : }
    1147             : 
    1148             : // Thebes Border Rendering Code End
    1149             : //----------------------------------------------------------------------
    1150             : 
    1151             : 
    1152             : //----------------------------------------------------------------------
    1153             : 
    1154             : /**
    1155             :  * Helper for ComputeObjectAnchorPoint; parameters are the same as for
    1156             :  * that function, except they're for a single coordinate / a single size
    1157             :  * dimension. (so, x/width vs. y/height)
    1158             :  */
    1159             : static void
    1160         912 : ComputeObjectAnchorCoord(const Position::Coord& aCoord,
    1161             :                          const nscoord aOriginBounds,
    1162             :                          const nscoord aImageSize,
    1163             :                          nscoord* aTopLeftCoord,
    1164             :                          nscoord* aAnchorPointCoord)
    1165             : {
    1166         912 :   *aAnchorPointCoord = aCoord.mLength;
    1167         912 :   *aTopLeftCoord = aCoord.mLength;
    1168             : 
    1169         912 :   if (aCoord.mHasPercent) {
    1170             :     // Adjust aTopLeftCoord by the specified % of the extra space.
    1171         912 :     nscoord extraSpace = aOriginBounds - aImageSize;
    1172         912 :     *aTopLeftCoord += NSToCoordRound(aCoord.mPercent * extraSpace);
    1173             : 
    1174             :     // The anchor-point doesn't care about our image's size; just the size
    1175             :     // of the region we're rendering into.
    1176         912 :     *aAnchorPointCoord += NSToCoordRound(aCoord.mPercent * aOriginBounds);
    1177             :   }
    1178         912 : }
    1179             : 
    1180             : void
    1181         456 : nsImageRenderer::ComputeObjectAnchorPoint(
    1182             :   const Position& aPos,
    1183             :   const nsSize& aOriginBounds,
    1184             :   const nsSize& aImageSize,
    1185             :   nsPoint* aTopLeft,
    1186             :   nsPoint* aAnchorPoint)
    1187             : {
    1188         912 :   ComputeObjectAnchorCoord(aPos.mXPosition,
    1189         456 :                            aOriginBounds.width, aImageSize.width,
    1190         456 :                            &aTopLeft->x, &aAnchorPoint->x);
    1191             : 
    1192         912 :   ComputeObjectAnchorCoord(aPos.mYPosition,
    1193         456 :                            aOriginBounds.height, aImageSize.height,
    1194         456 :                            &aTopLeft->y, &aAnchorPoint->y);
    1195         456 : }
    1196             : 
    1197             : nsIFrame*
    1198          35 : nsCSSRendering::FindNonTransparentBackgroundFrame(nsIFrame* aFrame,
    1199             :                                                   bool aStartAtParent /*= false*/)
    1200             : {
    1201          35 :   NS_ASSERTION(aFrame, "Cannot find NonTransparentBackgroundFrame in a null frame");
    1202             : 
    1203          35 :   nsIFrame* frame = nullptr;
    1204          35 :   if (aStartAtParent) {
    1205           0 :     frame = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
    1206             :   }
    1207          35 :   if (!frame) {
    1208          35 :     frame = aFrame;
    1209             :   }
    1210             : 
    1211          63 :   while (frame) {
    1212             :     // No need to call GetVisitedDependentColor because it always uses
    1213             :     // this alpha component anyway.
    1214          49 :     if (NS_GET_A(frame->StyleBackground()->BackgroundColor(frame)) > 0) {
    1215          35 :       break;
    1216             :     }
    1217             : 
    1218          14 :     if (frame->IsThemed())
    1219           0 :       break;
    1220             : 
    1221          14 :     nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
    1222          14 :     if (!parent)
    1223           0 :       break;
    1224             : 
    1225          14 :     frame = parent;
    1226             :   }
    1227          35 :   return frame;
    1228             : }
    1229             : 
    1230             : // Returns true if aFrame is a canvas frame.
    1231             : // We need to treat the viewport as canvas because, even though
    1232             : // it does not actually paint a background, we need to get the right
    1233             : // background style so we correctly detect transparent documents.
    1234             : bool
    1235        1427 : nsCSSRendering::IsCanvasFrame(nsIFrame* aFrame)
    1236             : {
    1237        1427 :   LayoutFrameType frameType = aFrame->Type();
    1238        1387 :   return frameType == LayoutFrameType::Canvas ||
    1239        1288 :          frameType == LayoutFrameType::Root ||
    1240        2715 :          frameType == LayoutFrameType::PageContent ||
    1241        1427 :          frameType == LayoutFrameType::Viewport;
    1242             : }
    1243             : 
    1244             : nsIFrame*
    1245         304 : nsCSSRendering::FindBackgroundStyleFrame(nsIFrame* aForFrame)
    1246             : {
    1247         304 :   const nsStyleBackground* result = aForFrame->StyleBackground();
    1248             : 
    1249             :   // Check if we need to do propagation from BODY rather than HTML.
    1250         304 :   if (!result->IsTransparent(aForFrame)) {
    1251         264 :     return aForFrame;
    1252             :   }
    1253             : 
    1254          40 :   nsIContent* content = aForFrame->GetContent();
    1255             :   // The root element content can't be null. We wouldn't know what
    1256             :   // frame to create for aFrame.
    1257             :   // Use |OwnerDoc| so it works during destruction.
    1258          40 :   if (!content) {
    1259           0 :     return aForFrame;
    1260             :   }
    1261             : 
    1262          40 :   nsIDocument* document = content->OwnerDoc();
    1263             : 
    1264          40 :   dom::Element* bodyContent = document->GetBodyElement();
    1265             :   // We need to null check the body node (bug 118829) since
    1266             :   // there are cases, thanks to the fix for bug 5569, where we
    1267             :   // will reflow a document with no body.  In particular, if a
    1268             :   // SCRIPT element in the head blocks the parser and then has a
    1269             :   // SCRIPT that does "document.location.href = 'foo'", then
    1270             :   // nsParser::Terminate will call |DidBuildModel| methods
    1271             :   // through to the content sink, which will call |StartLayout|
    1272             :   // and thus |Initialize| on the pres shell.  See bug 119351
    1273             :   // for the ugly details.
    1274          40 :   if (!bodyContent) {
    1275          36 :     return aForFrame;
    1276             :   }
    1277             : 
    1278           4 :   nsIFrame *bodyFrame = bodyContent->GetPrimaryFrame();
    1279           4 :   if (!bodyFrame) {
    1280           0 :     return aForFrame;
    1281             :   }
    1282             : 
    1283           4 :   return nsLayoutUtils::GetStyleFrame(bodyFrame);
    1284             : }
    1285             : 
    1286             : /**
    1287             :  * |FindBackground| finds the correct style data to use to paint the
    1288             :  * background.  It is responsible for handling the following two
    1289             :  * statements in section 14.2 of CSS2:
    1290             :  *
    1291             :  *   The background of the box generated by the root element covers the
    1292             :  *   entire canvas.
    1293             :  *
    1294             :  *   For HTML documents, however, we recommend that authors specify the
    1295             :  *   background for the BODY element rather than the HTML element. User
    1296             :  *   agents should observe the following precedence rules to fill in the
    1297             :  *   background: if the value of the 'background' property for the HTML
    1298             :  *   element is different from 'transparent' then use it, else use the
    1299             :  *   value of the 'background' property for the BODY element. If the
    1300             :  *   resulting value is 'transparent', the rendering is undefined.
    1301             :  *
    1302             :  * Thus, in our implementation, it is responsible for ensuring that:
    1303             :  *  + we paint the correct background on the |nsCanvasFrame|,
    1304             :  *    |nsRootBoxFrame|, or |nsPageFrame|,
    1305             :  *  + we don't paint the background on the root element, and
    1306             :  *  + we don't paint the background on the BODY element in *some* cases,
    1307             :  *    and for SGML-based HTML documents only.
    1308             :  *
    1309             :  * |FindBackground| returns true if a background should be painted, and
    1310             :  * the resulting style context to use for the background information
    1311             :  * will be filled in to |aBackground|.
    1312             :  */
    1313             : nsStyleContext*
    1314         106 : nsCSSRendering::FindRootFrameBackground(nsIFrame* aForFrame)
    1315             : {
    1316         106 :   return FindBackgroundStyleFrame(aForFrame)->StyleContext();
    1317             : }
    1318             : 
    1319             : inline bool
    1320         466 : FindElementBackground(nsIFrame* aForFrame, nsIFrame* aRootElementFrame,
    1321             :                       nsStyleContext** aBackgroundSC)
    1322             : {
    1323         466 :   if (aForFrame == aRootElementFrame) {
    1324             :     // We must have propagated our background to the viewport or canvas. Abort.
    1325           0 :     return false;
    1326             :   }
    1327             : 
    1328         466 :   *aBackgroundSC = aForFrame->StyleContext();
    1329             : 
    1330             :   // Return true unless the frame is for a BODY element whose background
    1331             :   // was propagated to the viewport.
    1332             : 
    1333         466 :   nsIContent* content = aForFrame->GetContent();
    1334         466 :   if (!content || content->NodeInfo()->NameAtom() != nsGkAtoms::body)
    1335         466 :     return true; // not frame for a "body" element
    1336             :   // It could be a non-HTML "body" element but that's OK, we'd fail the
    1337             :   // bodyContent check below
    1338             : 
    1339           0 :   if (aForFrame->StyleContext()->GetPseudo())
    1340           0 :     return true; // A pseudo-element frame.
    1341             : 
    1342             :   // We should only look at the <html> background if we're in an HTML document
    1343           0 :   nsIDocument* document = content->OwnerDoc();
    1344             : 
    1345           0 :   dom::Element* bodyContent = document->GetBodyElement();
    1346           0 :   if (bodyContent != content)
    1347           0 :     return true; // this wasn't the background that was propagated
    1348             : 
    1349             :   // This can be called even when there's no root element yet, during frame
    1350             :   // construction, via nsLayoutUtils::FrameHasTransparency and
    1351             :   // nsContainerFrame::SyncFrameViewProperties.
    1352           0 :   if (!aRootElementFrame)
    1353           0 :     return true;
    1354             : 
    1355           0 :   const nsStyleBackground* htmlBG = aRootElementFrame->StyleBackground();
    1356           0 :   return !htmlBG->IsTransparent(aRootElementFrame);
    1357             : }
    1358             : 
    1359             : bool
    1360         519 : nsCSSRendering::FindBackground(nsIFrame* aForFrame,
    1361             :                                nsStyleContext** aBackgroundSC)
    1362             : {
    1363             :   nsIFrame* rootElementFrame =
    1364         519 :     aForFrame->PresContext()->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
    1365         519 :   if (IsCanvasFrame(aForFrame)) {
    1366          53 :     *aBackgroundSC = FindCanvasBackground(aForFrame, rootElementFrame);
    1367          53 :     return true;
    1368             :   } else {
    1369         466 :     return FindElementBackground(aForFrame, rootElementFrame, aBackgroundSC);
    1370             :   }
    1371             : }
    1372             : 
    1373             : void
    1374          53 : nsCSSRendering::BeginFrameTreesLocked()
    1375             : {
    1376          53 :   ++gFrameTreeLockCount;
    1377          53 : }
    1378             : 
    1379             : void
    1380          53 : nsCSSRendering::EndFrameTreesLocked()
    1381             : {
    1382          53 :   NS_ASSERTION(gFrameTreeLockCount > 0, "Unbalanced EndFrameTreeLocked");
    1383          53 :   --gFrameTreeLockCount;
    1384          53 :   if (gFrameTreeLockCount == 0) {
    1385          35 :     gInlineBGData->Reset();
    1386             :   }
    1387          53 : }
    1388             : 
    1389             : bool
    1390           9 : nsCSSRendering::HasBoxShadowNativeTheme(nsIFrame* aFrame,
    1391             :                                         bool& aMaybeHasBorderRadius)
    1392             : {
    1393           9 :   const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
    1394             :   nsITheme::Transparency transparency;
    1395           9 :   if (aFrame->IsThemed(styleDisplay, &transparency)) {
    1396           0 :     aMaybeHasBorderRadius = false;
    1397             :     // For opaque (rectangular) theme widgets we can take the generic
    1398             :     // border-box path with border-radius disabled.
    1399           0 :     return transparency != nsITheme::eOpaque;
    1400             :   }
    1401             : 
    1402           9 :   aMaybeHasBorderRadius = true;
    1403           9 :   return false;
    1404             : }
    1405             : 
    1406             : gfx::Color
    1407          19 : nsCSSRendering::GetShadowColor(nsCSSShadowItem* aShadow,
    1408             :                                nsIFrame* aFrame,
    1409             :                                float aOpacity)
    1410             : {
    1411             :   // Get the shadow color; if not specified, use the foreground color
    1412             :   nscolor shadowColor;
    1413          19 :   if (aShadow->mHasColor)
    1414          19 :     shadowColor = aShadow->mColor;
    1415             :   else
    1416           0 :     shadowColor = aFrame->StyleColor()->mColor;
    1417             : 
    1418          19 :   Color color = Color::FromABGR(shadowColor);
    1419          19 :   color.a *= aOpacity;
    1420          19 :   return color;
    1421             : }
    1422             : 
    1423             : nsRect
    1424           9 : nsCSSRendering::GetShadowRect(const nsRect aFrameArea,
    1425             :                               bool aNativeTheme,
    1426             :                               nsIFrame* aForFrame)
    1427             : {
    1428             :   nsRect frameRect = aNativeTheme ?
    1429           9 :     aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
    1430          18 :     aFrameArea;
    1431           9 :   Sides skipSides = aForFrame->GetSkipSides();
    1432           9 :   frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
    1433             : 
    1434             :   // Explicitly do not need to account for the spread radius here
    1435             :   // Webrender does it for us or PaintBoxShadow will for non-WR
    1436           9 :   return frameRect;
    1437             : }
    1438             : 
    1439             : bool
    1440          10 : nsCSSRendering::GetBorderRadii(const nsRect& aFrameRect,
    1441             :                                const nsRect& aBorderRect,
    1442             :                                nsIFrame* aFrame,
    1443             :                                RectCornerRadii& aOutRadii)
    1444             : {
    1445          10 :   const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
    1446             :   nscoord twipsRadii[8];
    1447          10 :   NS_ASSERTION(aBorderRect.Size() == aFrame->VisualBorderRectRelativeToSelf().Size(),
    1448             :               "unexpected size");
    1449          10 :   nsSize sz = aFrameRect.Size();
    1450          10 :   bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
    1451          10 :   if (hasBorderRadius) {
    1452           0 :     ComputePixelRadii(twipsRadii, twipsPerPixel, &aOutRadii);
    1453             :   }
    1454             : 
    1455          10 :   return hasBorderRadius;
    1456             : }
    1457             : 
    1458             : void
    1459           9 : nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
    1460             :                                     gfxContext& aRenderingContext,
    1461             :                                     nsIFrame* aForFrame,
    1462             :                                     const nsRect& aFrameArea,
    1463             :                                     const nsRect& aDirtyRect,
    1464             :                                     float aOpacity)
    1465             : {
    1466           9 :   DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
    1467           9 :   nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
    1468           9 :   if (!shadows)
    1469           0 :     return;
    1470             : 
    1471             :   bool hasBorderRadius;
    1472             :   // mutually exclusive with hasBorderRadius
    1473           9 :   bool nativeTheme = HasBoxShadowNativeTheme(aForFrame, hasBorderRadius);
    1474           9 :   const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
    1475             : 
    1476          18 :   nsRect frameRect = GetShadowRect(aFrameArea, nativeTheme, aForFrame);
    1477             : 
    1478             :   // Get any border radius, since box-shadow must also have rounded corners if
    1479             :   // the frame does.
    1480           9 :   RectCornerRadii borderRadii;
    1481           9 :   const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
    1482           9 :   if (hasBorderRadius) {
    1483             :     nscoord twipsRadii[8];
    1484           9 :     NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
    1485             :                  "unexpected size");
    1486           9 :     nsSize sz = frameRect.Size();
    1487           9 :     hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
    1488           9 :     if (hasBorderRadius) {
    1489           9 :       ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
    1490             :     }
    1491             :   }
    1492             : 
    1493             : 
    1494             :   // We don't show anything that intersects with the frame we're blurring on. So tell the
    1495             :   // blurrer not to do unnecessary work there.
    1496           9 :   gfxRect skipGfxRect = ThebesRect(NSRectToRect(frameRect, twipsPerPixel));
    1497           9 :   skipGfxRect.Round();
    1498           9 :   bool useSkipGfxRect = true;
    1499           9 :   if (nativeTheme) {
    1500             :     // Optimize non-leaf native-themed frames by skipping computing pixels
    1501             :     // in the padding-box. We assume the padding-box is going to be painted
    1502             :     // opaquely for non-leaf frames.
    1503             :     // XXX this may not be a safe assumption; we should make this go away
    1504             :     // by optimizing box-shadow drawing more for the cases where we don't have a skip-rect.
    1505           0 :     useSkipGfxRect = !aForFrame->IsLeaf();
    1506             :     nsRect paddingRect =
    1507           0 :       aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
    1508           0 :     skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
    1509           9 :   } else if (hasBorderRadius) {
    1510          27 :     skipGfxRect.Deflate(gfxMargin(
    1511           9 :         std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
    1512          18 :         std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
    1513             :   }
    1514             : 
    1515             : 
    1516          18 :   for (uint32_t i = shadows->Length(); i > 0; --i) {
    1517           9 :     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
    1518           9 :     if (shadowItem->mInset)
    1519           0 :       continue;
    1520             : 
    1521          18 :     nsRect shadowRect = frameRect;
    1522           9 :     shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
    1523           9 :     if (!nativeTheme) {
    1524           9 :       shadowRect.Inflate(shadowItem->mSpread, shadowItem->mSpread);
    1525             :     }
    1526             : 
    1527             :     // shadowRect won't include the blur, so make an extra rect here that includes the blur
    1528             :     // for use in the even-odd rule below.
    1529          18 :     nsRect shadowRectPlusBlur = shadowRect;
    1530           9 :     nscoord blurRadius = shadowItem->mRadius;
    1531             :     shadowRectPlusBlur.Inflate(
    1532           9 :       nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel));
    1533             : 
    1534             :     Rect shadowGfxRectPlusBlur =
    1535           9 :       NSRectToRect(shadowRectPlusBlur, twipsPerPixel);
    1536           9 :     shadowGfxRectPlusBlur.RoundOut();
    1537           9 :     MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
    1538             : 
    1539           9 :     Color gfxShadowColor = GetShadowColor(shadowItem, aForFrame, aOpacity);
    1540             : 
    1541           9 :     if (nativeTheme) {
    1542           0 :       nsContextBoxBlur blurringArea;
    1543             : 
    1544             :       // When getting the widget shape from the native theme, we're going
    1545             :       // to draw the widget into the shadow surface to create a mask.
    1546             :       // We need to ensure that there actually *is* a shadow surface
    1547             :       // and that we're not going to draw directly into aRenderingContext.
    1548             :       gfxContext* shadowContext =
    1549           0 :         blurringArea.Init(shadowRect, shadowItem->mSpread, blurRadius,
    1550             :                           twipsPerPixel, &aRenderingContext, aDirtyRect,
    1551             :                           useSkipGfxRect ? &skipGfxRect : nullptr,
    1552           0 :                           nsContextBoxBlur::FORCE_MASK);
    1553           0 :       if (!shadowContext)
    1554           0 :         continue;
    1555             : 
    1556           0 :       MOZ_ASSERT(shadowContext == blurringArea.GetContext());
    1557             : 
    1558           0 :       aRenderingContext.Save();
    1559           0 :       aRenderingContext.SetColor(gfxShadowColor);
    1560             : 
    1561             :       // Draw the shape of the frame so it can be blurred. Recall how nsContextBoxBlur
    1562             :       // doesn't make any temporary surfaces if blur is 0 and it just returns the original
    1563             :       // surface? If we have no blur, we're painting this fill on the actual content surface
    1564             :       // (aRenderingContext == shadowContext) which is why we set up the color and clip
    1565             :       // before doing this.
    1566             : 
    1567             :       // We don't clip the border-box from the shadow, nor any other box.
    1568             :       // We assume that the native theme is going to paint over the shadow.
    1569             : 
    1570             :       // Draw the widget shape
    1571           0 :       gfxContextMatrixAutoSaveRestore save(shadowContext);
    1572             :       gfxPoint devPixelOffset =
    1573           0 :         nsLayoutUtils::PointToGfxPoint(nsPoint(shadowItem->mXOffset,
    1574             :                                                shadowItem->mYOffset),
    1575           0 :                                        aPresContext->AppUnitsPerDevPixel());
    1576             :       shadowContext->SetMatrix(
    1577           0 :         shadowContext->CurrentMatrix().PreTranslate(devPixelOffset));
    1578             : 
    1579           0 :       nsRect nativeRect = aDirtyRect;
    1580           0 :       nativeRect.MoveBy(-nsPoint(shadowItem->mXOffset, shadowItem->mYOffset));
    1581           0 :       nativeRect.IntersectRect(frameRect, nativeRect);
    1582           0 :       aPresContext->GetTheme()->DrawWidgetBackground(shadowContext, aForFrame,
    1583           0 :           styleDisplay->mAppearance, aFrameArea, nativeRect);
    1584             : 
    1585           0 :       blurringArea.DoPaint();
    1586           0 :       aRenderingContext.Restore();
    1587             :     } else {
    1588           9 :       aRenderingContext.Save();
    1589             : 
    1590             :       {
    1591           9 :         Rect innerClipRect = NSRectToRect(frameRect, twipsPerPixel);
    1592           9 :         if (!MaybeSnapToDevicePixels(innerClipRect, aDrawTarget, true)) {
    1593           0 :           innerClipRect.Round();
    1594             :         }
    1595             : 
    1596             :         // Clip out the interior of the frame's border edge so that the shadow
    1597             :         // is only painted outside that area.
    1598             :         RefPtr<PathBuilder> builder =
    1599          18 :           aDrawTarget.CreatePathBuilder(FillRule::FILL_EVEN_ODD);
    1600           9 :         AppendRectToPath(builder, shadowGfxRectPlusBlur);
    1601           9 :         if (hasBorderRadius) {
    1602           9 :           AppendRoundedRectToPath(builder, innerClipRect, borderRadii);
    1603             :         } else {
    1604           0 :           AppendRectToPath(builder, innerClipRect);
    1605             :         }
    1606          18 :         RefPtr<Path> path = builder->Finish();
    1607           9 :         aRenderingContext.Clip(path);
    1608             :       }
    1609             : 
    1610             :       // Clip the shadow so that we only get the part that applies to aForFrame.
    1611          18 :       nsRect fragmentClip = shadowRectPlusBlur;
    1612           9 :       Sides skipSides = aForFrame->GetSkipSides();
    1613           9 :       if (!skipSides.IsEmpty()) {
    1614           0 :         if (skipSides.Left()) {
    1615           0 :           nscoord xmost = fragmentClip.XMost();
    1616           0 :           fragmentClip.x = aFrameArea.x;
    1617           0 :           fragmentClip.width = xmost - fragmentClip.x;
    1618             :         }
    1619           0 :         if (skipSides.Right()) {
    1620           0 :           nscoord xmost = fragmentClip.XMost();
    1621           0 :           nscoord overflow = xmost - aFrameArea.XMost();
    1622           0 :           if (overflow > 0) {
    1623           0 :             fragmentClip.width -= overflow;
    1624             :           }
    1625             :         }
    1626           0 :         if (skipSides.Top()) {
    1627           0 :           nscoord ymost = fragmentClip.YMost();
    1628           0 :           fragmentClip.y = aFrameArea.y;
    1629           0 :           fragmentClip.height = ymost - fragmentClip.y;
    1630             :         }
    1631           0 :         if (skipSides.Bottom()) {
    1632           0 :           nscoord ymost = fragmentClip.YMost();
    1633           0 :           nscoord overflow = ymost - aFrameArea.YMost();
    1634           0 :           if (overflow > 0) {
    1635           0 :             fragmentClip.height -= overflow;
    1636             :           }
    1637             :         }
    1638             :       }
    1639           9 :       fragmentClip = fragmentClip.Intersect(aDirtyRect);
    1640             :       aRenderingContext.
    1641          18 :         Clip(NSRectToSnappedRect(fragmentClip,
    1642           9 :                                  aForFrame->PresContext()->AppUnitsPerDevPixel(),
    1643          18 :                                  aDrawTarget));
    1644             : 
    1645           9 :       RectCornerRadii clipRectRadii;
    1646           9 :       if (hasBorderRadius) {
    1647           9 :         Float spreadDistance = Float(shadowItem->mSpread) / twipsPerPixel;
    1648             : 
    1649             :         Float borderSizes[4];
    1650             : 
    1651           9 :         borderSizes[eSideLeft] = spreadDistance;
    1652           9 :         borderSizes[eSideTop] = spreadDistance;
    1653           9 :         borderSizes[eSideRight] = spreadDistance;
    1654           9 :         borderSizes[eSideBottom] = spreadDistance;
    1655             : 
    1656             :         nsCSSBorderRenderer::ComputeOuterRadii(borderRadii, borderSizes,
    1657           9 :             &clipRectRadii);
    1658             : 
    1659             :       }
    1660           9 :       nsContextBoxBlur::BlurRectangle(&aRenderingContext,
    1661             :                                       shadowRect,
    1662             :                                       twipsPerPixel,
    1663             :                                       hasBorderRadius ? &clipRectRadii : nullptr,
    1664             :                                       blurRadius,
    1665             :                                       gfxShadowColor,
    1666             :                                       aDirtyRect,
    1667           9 :                                       skipGfxRect);
    1668           9 :       aRenderingContext.Restore();
    1669             :     }
    1670             : 
    1671             :   }
    1672             : }
    1673             : 
    1674             : nsRect
    1675          10 : nsCSSRendering::GetBoxShadowInnerPaddingRect(nsIFrame* aFrame,
    1676             :                                              const nsRect& aFrameArea)
    1677             : {
    1678          10 :   Sides skipSides = aFrame->GetSkipSides();
    1679             :   nsRect frameRect =
    1680          20 :     ::BoxDecorationRectForBorder(aFrame, aFrameArea, skipSides);
    1681             : 
    1682          10 :   nsRect paddingRect = frameRect;
    1683          10 :   nsMargin border = aFrame->GetUsedBorder();
    1684          10 :   paddingRect.Deflate(border);
    1685          20 :   return paddingRect;
    1686             : }
    1687             : 
    1688             : bool
    1689          10 : nsCSSRendering::ShouldPaintBoxShadowInner(nsIFrame* aFrame)
    1690             : {
    1691          10 :   nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
    1692          10 :   if (!shadows)
    1693           0 :     return false;
    1694             : 
    1695          10 :   if (aFrame->IsThemed() && aFrame->GetContent() &&
    1696           0 :       !nsContentUtils::IsChromeDoc(aFrame->GetContent()->GetUncomposedDoc())) {
    1697             :     // There's no way of getting hold of a shape corresponding to a
    1698             :     // "padding-box" for native-themed widgets, so just don't draw
    1699             :     // inner box-shadows for them. But we allow chrome to paint inner
    1700             :     // box shadows since chrome can be aware of the platform theme.
    1701           0 :     return false;
    1702             :   }
    1703             : 
    1704          10 :   return true;
    1705             : }
    1706             : 
    1707             : bool
    1708          10 : nsCSSRendering::GetShadowInnerRadii(nsIFrame* aFrame,
    1709             :                                     const nsRect& aFrameArea,
    1710             :                                     RectCornerRadii& aOutInnerRadii)
    1711             : {
    1712             :   // Get any border radius, since box-shadow must also have rounded corners
    1713             :   // if the frame does.
    1714             :   nscoord twipsRadii[8];
    1715             :   nsRect frameRect =
    1716          20 :     ::BoxDecorationRectForBorder(aFrame, aFrameArea, aFrame->GetSkipSides());
    1717          10 :   nsSize sz = frameRect.Size();
    1718          10 :   nsMargin border = aFrame->GetUsedBorder();
    1719          10 :   bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
    1720          10 :   const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
    1721             : 
    1722          10 :   RectCornerRadii borderRadii;
    1723             : 
    1724          10 :   hasBorderRadius = GetBorderRadii(frameRect, aFrameArea, aFrame, borderRadii);
    1725          10 :   if (hasBorderRadius) {
    1726           0 :     ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
    1727             : 
    1728             :     Float borderSizes[4] = {
    1729           0 :       Float(border.top) / twipsPerPixel,
    1730           0 :       Float(border.right) / twipsPerPixel,
    1731           0 :       Float(border.bottom) / twipsPerPixel,
    1732           0 :       Float(border.left) / twipsPerPixel
    1733           0 :     };
    1734             :     nsCSSBorderRenderer::ComputeInnerRadii(borderRadii,
    1735             :                                            borderSizes,
    1736           0 :                                            &aOutInnerRadii);
    1737             :   }
    1738             : 
    1739          20 :   return hasBorderRadius;
    1740             : }
    1741             : 
    1742             : void
    1743          10 : nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
    1744             :                                     gfxContext& aRenderingContext,
    1745             :                                     nsIFrame* aForFrame,
    1746             :                                     const nsRect& aFrameArea)
    1747             : {
    1748          10 :   if (!ShouldPaintBoxShadowInner(aForFrame)) {
    1749           0 :     return;
    1750             :   }
    1751             : 
    1752          10 :   nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
    1753          10 :   NS_ASSERTION(aForFrame->IsFieldSetFrame() ||
    1754             :                aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
    1755             : 
    1756          20 :   nsRect paddingRect = GetBoxShadowInnerPaddingRect(aForFrame, aFrameArea);
    1757             : 
    1758          10 :   RectCornerRadii innerRadii;
    1759             :   bool hasBorderRadius = GetShadowInnerRadii(aForFrame,
    1760             :                                              aFrameArea,
    1761          10 :                                              innerRadii);
    1762             : 
    1763          10 :   const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
    1764             : 
    1765          20 :   for (uint32_t i = shadows->Length(); i > 0; --i) {
    1766          10 :     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
    1767          10 :     if (!shadowItem->mInset)
    1768           0 :       continue;
    1769             : 
    1770             :     // shadowPaintRect: the area to paint on the temp surface
    1771             :     // shadowClipRect: the area on the temporary surface within shadowPaintRect
    1772             :     //                 that we will NOT paint in
    1773          10 :     nscoord blurRadius = shadowItem->mRadius;
    1774             :     nsMargin blurMargin =
    1775          10 :       nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
    1776          20 :     nsRect shadowPaintRect = paddingRect;
    1777          10 :     shadowPaintRect.Inflate(blurMargin);
    1778             : 
    1779             :     // Round the spread radius to device pixels (by truncation).
    1780             :     // This mostly matches what we do for borders, except that we don't round
    1781             :     // up values between zero and one device pixels to one device pixel.
    1782             :     // This way of rounding is symmetric around zero, which makes sense for
    1783             :     // the spread radius.
    1784          10 :     int32_t spreadDistance = shadowItem->mSpread / twipsPerPixel;
    1785          10 :     nscoord spreadDistanceAppUnits = aPresContext->DevPixelsToAppUnits(spreadDistance);
    1786             : 
    1787          20 :     nsRect shadowClipRect = paddingRect;
    1788          10 :     shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
    1789          10 :     shadowClipRect.Deflate(spreadDistanceAppUnits, spreadDistanceAppUnits);
    1790             : 
    1791          10 :     Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, twipsPerPixel);
    1792          10 :     shadowClipGfxRect.Round();
    1793             : 
    1794          10 :     RectCornerRadii clipRectRadii;
    1795          10 :     if (hasBorderRadius) {
    1796             :       // Calculate the radii the inner clipping rect will have
    1797           0 :       Float borderSizes[4] = {0, 0, 0, 0};
    1798             : 
    1799             :       // See PaintBoxShadowOuter and bug 514670
    1800           0 :       if (innerRadii[C_TL].width > 0 || innerRadii[C_BL].width > 0) {
    1801           0 :         borderSizes[eSideLeft] = spreadDistance;
    1802             :       }
    1803             : 
    1804           0 :       if (innerRadii[C_TL].height > 0 || innerRadii[C_TR].height > 0) {
    1805           0 :         borderSizes[eSideTop] = spreadDistance;
    1806             :       }
    1807             : 
    1808           0 :       if (innerRadii[C_TR].width > 0 || innerRadii[C_BR].width > 0) {
    1809           0 :         borderSizes[eSideRight] = spreadDistance;
    1810             :       }
    1811             : 
    1812           0 :       if (innerRadii[C_BL].height > 0 || innerRadii[C_BR].height > 0) {
    1813           0 :         borderSizes[eSideBottom] = spreadDistance;
    1814             :       }
    1815             : 
    1816             :       nsCSSBorderRenderer::ComputeInnerRadii(innerRadii, borderSizes,
    1817           0 :                                              &clipRectRadii);
    1818             :     }
    1819             : 
    1820             :     // Set the "skip rect" to the area within the frame that we don't paint in,
    1821             :     // including after blurring.
    1822          20 :     nsRect skipRect = shadowClipRect;
    1823          10 :     skipRect.Deflate(blurMargin);
    1824          10 :     gfxRect skipGfxRect = nsLayoutUtils::RectToGfxRect(skipRect, twipsPerPixel);
    1825          10 :     if (hasBorderRadius) {
    1826           0 :       skipGfxRect.Deflate(gfxMargin(
    1827           0 :           std::max(clipRectRadii[C_TL].height, clipRectRadii[C_TR].height), 0,
    1828           0 :           std::max(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height), 0));
    1829             :     }
    1830             : 
    1831             :     // When there's a blur radius, gfxAlphaBoxBlur leaves the skiprect area
    1832             :     // unchanged. And by construction the gfxSkipRect is not touched by the
    1833             :     // rendered shadow (even after blurring), so those pixels must be completely
    1834             :     // transparent in the shadow, so drawing them changes nothing.
    1835          10 :     DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
    1836             : 
    1837             :     // Clip the context to the area of the frame's padding rect, so no part of the
    1838             :     // shadow is painted outside. Also cut out anything beyond where the inset shadow
    1839             :     // will be.
    1840          10 :     Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
    1841          10 :     shadowGfxRect.Round();
    1842             : 
    1843          10 :     Color shadowColor = GetShadowColor(shadowItem, aForFrame, 1.0);
    1844          10 :     aRenderingContext.Save();
    1845             : 
    1846             :     // This clips the outside border radius.
    1847             :     // clipRectRadii is the border radius inside the inset shadow.
    1848          10 :     if (hasBorderRadius) {
    1849             :       RefPtr<Path> roundedRect =
    1850           0 :         MakePathForRoundedRect(*drawTarget, shadowGfxRect, innerRadii);
    1851           0 :       aRenderingContext.Clip(roundedRect);
    1852             :     } else {
    1853          10 :       aRenderingContext.Clip(shadowGfxRect);
    1854             :     }
    1855             : 
    1856          20 :     nsContextBoxBlur insetBoxBlur;
    1857          10 :     gfxRect destRect = nsLayoutUtils::RectToGfxRect(shadowPaintRect, twipsPerPixel);
    1858          10 :     Point shadowOffset(shadowItem->mXOffset / twipsPerPixel,
    1859          20 :                        shadowItem->mYOffset / twipsPerPixel);
    1860             : 
    1861          10 :     insetBoxBlur.InsetBoxBlur(&aRenderingContext, ToRect(destRect),
    1862             :                               shadowClipGfxRect, shadowColor,
    1863             :                               blurRadius, spreadDistanceAppUnits,
    1864             :                               twipsPerPixel, hasBorderRadius,
    1865             :                               clipRectRadii, ToRect(skipGfxRect),
    1866          10 :                               shadowOffset);
    1867          10 :     aRenderingContext.Restore();
    1868             :   }
    1869             : }
    1870             : 
    1871             : /* static */
    1872             : nsCSSRendering::PaintBGParams
    1873           0 : nsCSSRendering::PaintBGParams::ForAllLayers(nsPresContext& aPresCtx,
    1874             :                                             const nsRect& aDirtyRect,
    1875             :                                             const nsRect& aBorderArea,
    1876             :                                             nsIFrame *aFrame,
    1877             :                                             uint32_t aPaintFlags,
    1878             :                                             float aOpacity)
    1879             : {
    1880           0 :   MOZ_ASSERT(aFrame);
    1881             : 
    1882             :   PaintBGParams result(aPresCtx, aDirtyRect, aBorderArea,
    1883             :                        aFrame, aPaintFlags, -1, CompositionOp::OP_OVER,
    1884           0 :                        aOpacity);
    1885             : 
    1886           0 :   return result;
    1887             : }
    1888             : 
    1889             : /* static */
    1890             : nsCSSRendering::PaintBGParams
    1891          59 : nsCSSRendering::PaintBGParams::ForSingleLayer(nsPresContext& aPresCtx,
    1892             :                                               const nsRect& aDirtyRect,
    1893             :                                               const nsRect& aBorderArea,
    1894             :                                               nsIFrame *aFrame,
    1895             :                                               uint32_t aPaintFlags,
    1896             :                                               int32_t aLayer,
    1897             :                                               CompositionOp aCompositionOp,
    1898             :                                               float aOpacity)
    1899             : {
    1900          59 :   MOZ_ASSERT(aFrame && (aLayer != -1));
    1901             : 
    1902             :   PaintBGParams result(aPresCtx, aDirtyRect, aBorderArea,
    1903             :                        aFrame, aPaintFlags, aLayer, aCompositionOp,
    1904          59 :                        aOpacity);
    1905             : 
    1906          59 :   return result;
    1907             : }
    1908             : 
    1909             : DrawResult
    1910          56 : nsCSSRendering::PaintStyleImageLayer(const PaintBGParams& aParams,
    1911             :                                      gfxContext& aRenderingCtx)
    1912             : {
    1913         112 :   AUTO_PROFILER_LABEL("nsCSSRendering::PaintStyleImageLayer", GRAPHICS);
    1914             : 
    1915          56 :   NS_PRECONDITION(aParams.frame,
    1916             :                   "Frame is expected to be provided to PaintStyleImageLayer");
    1917             : 
    1918             :   nsStyleContext *sc;
    1919          56 :   if (!FindBackground(aParams.frame, &sc)) {
    1920             :     // We don't want to bail out if moz-appearance is set on a root
    1921             :     // node. If it has a parent content node, bail because it's not
    1922             :     // a root, otherwise keep going in order to let the theme stuff
    1923             :     // draw the background. The canvas really should be drawing the
    1924             :     // bg, but there's no way to hook that up via css.
    1925           0 :     if (!aParams.frame->StyleDisplay()->mAppearance) {
    1926           0 :       return DrawResult::SUCCESS;
    1927             :     }
    1928             : 
    1929           0 :     nsIContent* content = aParams.frame->GetContent();
    1930           0 :     if (!content || content->GetParent()) {
    1931           0 :       return DrawResult::SUCCESS;
    1932             :     }
    1933             : 
    1934           0 :     sc = aParams.frame->StyleContext();
    1935             :   }
    1936             : 
    1937          56 :   return PaintStyleImageLayerWithSC(aParams, aRenderingCtx, sc, *aParams.frame->StyleBorder());
    1938             : }
    1939             : 
    1940             : bool
    1941           0 : nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(LayerManager* aManager,
    1942             :                                                                 nsPresContext& aPresCtx,
    1943             :                                                                 nsIFrame *aFrame,
    1944             :                                                                 const nsStyleBackground* aBackgroundStyle,
    1945             :                                                                 int32_t aLayer)
    1946             : {
    1947           0 :   if (!aBackgroundStyle) {
    1948           0 :     return false;
    1949             :   }
    1950             : 
    1951           0 :   MOZ_ASSERT(aFrame &&
    1952             :              aLayer >= 0 &&
    1953             :              (uint32_t)aLayer < aBackgroundStyle->mImage.mLayers.Length());
    1954             : 
    1955             :   // We cannot draw native themed backgrounds
    1956           0 :   const nsStyleDisplay* displayData = aFrame->StyleDisplay();
    1957           0 :   if (displayData->mAppearance) {
    1958           0 :     nsITheme *theme = aPresCtx.GetTheme();
    1959           0 :     if (theme && theme->ThemeSupportsWidget(&aPresCtx,
    1960             :                                             aFrame,
    1961           0 :                                             displayData->mAppearance)) {
    1962           0 :       return false;
    1963             :     }
    1964             :   }
    1965             : 
    1966             :   // We only support painting gradients and image for a single style image layer
    1967           0 :   const nsStyleImage* styleImage = &aBackgroundStyle->mImage.mLayers[aLayer].mImage;
    1968           0 :   if (styleImage->GetType() == eStyleImageType_Image) {
    1969           0 :     if (styleImage->GetCropRect()) {
    1970           0 :       return false;
    1971             :     }
    1972             : 
    1973           0 :     imgRequestProxy* requestProxy = styleImage->GetImageData();
    1974           0 :     if (!requestProxy) {
    1975           0 :       return false;
    1976             :     }
    1977             : 
    1978           0 :     nsCOMPtr<imgIContainer> srcImage;
    1979           0 :     requestProxy->GetImage(getter_AddRefs(srcImage));
    1980           0 :     if (!srcImage || !srcImage->IsImageContainerAvailable(aManager, imgIContainer::FLAG_NONE)) {
    1981           0 :       return false;
    1982             :     }
    1983             : 
    1984           0 :     return true;
    1985             :   }
    1986             : 
    1987           0 :   if (styleImage->GetType() == eStyleImageType_Gradient) {
    1988           0 :     return true;
    1989             :   }
    1990             : 
    1991           0 :   return false;
    1992             : }
    1993             : 
    1994             : DrawResult
    1995           0 : nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
    1996             :                                                              mozilla::wr::DisplayListBuilder& aBuilder,
    1997             :                                                              const mozilla::layers::StackingContextHelper& aSc,
    1998             :                                                              nsTArray<WebRenderParentCommand>& aParentCommands,
    1999             :                                                              mozilla::layers::WebRenderDisplayItemLayer* aLayer,
    2000             :                                                              mozilla::layers::WebRenderLayerManager* aManager,
    2001             :                                                              nsDisplayItem* aItem)
    2002             : {
    2003           0 :   NS_PRECONDITION(aParams.frame,
    2004             :                   "Frame is expected to be provided to BuildWebRenderDisplayItemsForStyleImageLayer");
    2005             : 
    2006             :   nsStyleContext *sc;
    2007           0 :   if (!FindBackground(aParams.frame, &sc)) {
    2008             :     // We don't want to bail out if moz-appearance is set on a root
    2009             :     // node. If it has a parent content node, bail because it's not
    2010             :     // a root, otherwise keep going in order to let the theme stuff
    2011             :     // draw the background. The canvas really should be drawing the
    2012             :     // bg, but there's no way to hook that up via css.
    2013           0 :     if (!aParams.frame->StyleDisplay()->mAppearance) {
    2014           0 :       return DrawResult::SUCCESS;
    2015             :     }
    2016             : 
    2017           0 :     nsIContent* content = aParams.frame->GetContent();
    2018           0 :     if (!content || content->GetParent()) {
    2019           0 :       return DrawResult::SUCCESS;
    2020             :     }
    2021             : 
    2022           0 :     sc = aParams.frame->StyleContext();
    2023             :   }
    2024           0 :   return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aSc, aParentCommands,
    2025             :                                                             aLayer, aManager, aItem,
    2026           0 :                                                             sc, *aParams.frame->StyleBorder());
    2027             : }
    2028             : 
    2029             : static bool
    2030         356 : IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
    2031             : {
    2032         356 :   if (aBorder.GetComputedBorder().Side(aSide) == 0)
    2033          70 :     return true;
    2034         286 :   switch (aBorder.GetBorderStyle(aSide)) {
    2035             :   case NS_STYLE_BORDER_STYLE_SOLID:
    2036             :   case NS_STYLE_BORDER_STYLE_GROOVE:
    2037             :   case NS_STYLE_BORDER_STYLE_RIDGE:
    2038             :   case NS_STYLE_BORDER_STYLE_INSET:
    2039             :   case NS_STYLE_BORDER_STYLE_OUTSET:
    2040         286 :     break;
    2041             :   default:
    2042           0 :     return false;
    2043             :   }
    2044             : 
    2045             :   // If we're using a border image, assume it's not fully opaque,
    2046             :   // because we may not even have the image loaded at this point, and
    2047             :   // even if we did, checking whether the relevant tile is fully
    2048             :   // opaque would be too much work.
    2049         286 :   if (aBorder.mBorderImageSource.GetType() != eStyleImageType_Null)
    2050           0 :     return false;
    2051             : 
    2052         286 :   StyleComplexColor color = aBorder.mBorderColor[aSide];
    2053             :   // We don't know the foreground color here, so if it's being used
    2054             :   // we must assume it might be transparent.
    2055         286 :   if (!color.IsNumericColor()) {
    2056           0 :     return false;
    2057             :   }
    2058         286 :   return NS_GET_A(color.mColor) == 255;
    2059             : }
    2060             : 
    2061             : /**
    2062             :  * Returns true if all border edges are either missing or opaque.
    2063             :  */
    2064             : static bool
    2065         131 : IsOpaqueBorder(const nsStyleBorder& aBorder)
    2066             : {
    2067         131 :   if (aBorder.mBorderColors)
    2068           0 :     return false;
    2069         415 :   NS_FOR_CSS_SIDES(i) {
    2070         356 :     if (!IsOpaqueBorderEdge(aBorder, i))
    2071          72 :       return false;
    2072             :   }
    2073          59 :   return true;
    2074             : }
    2075             : 
    2076             : static inline void
    2077         413 : SetupDirtyRects(const nsRect& aBGClipArea, const nsRect& aCallerDirtyRect,
    2078             :                 nscoord aAppUnitsPerPixel,
    2079             :                 /* OUT: */
    2080             :                 nsRect* aDirtyRect, gfxRect* aDirtyRectGfx)
    2081             : {
    2082         413 :   aDirtyRect->IntersectRect(aBGClipArea, aCallerDirtyRect);
    2083             : 
    2084             :   // Compute the Thebes equivalent of the dirtyRect.
    2085         413 :   *aDirtyRectGfx = nsLayoutUtils::RectToGfxRect(*aDirtyRect, aAppUnitsPerPixel);
    2086         413 :   NS_WARNING_ASSERTION(aDirtyRect->IsEmpty() || !aDirtyRectGfx->IsEmpty(),
    2087             :                        "converted dirty rect should not be empty");
    2088         413 :   MOZ_ASSERT(!aDirtyRect->IsEmpty() || aDirtyRectGfx->IsEmpty(),
    2089             :              "second should be empty if first is");
    2090         413 : }
    2091             : 
    2092             : static bool
    2093        2004 : IsSVGStyleGeometryBox(StyleGeometryBox aBox)
    2094             : {
    2095        2004 :   return (aBox == StyleGeometryBox::FillBox ||
    2096        4008 :           aBox == StyleGeometryBox::StrokeBox ||
    2097        2004 :           aBox == StyleGeometryBox::ViewBox);
    2098             : }
    2099             : 
    2100             : static bool
    2101           0 : IsHTMLStyleGeometryBox(StyleGeometryBox aBox)
    2102             : {
    2103           0 :   return (aBox == StyleGeometryBox::ContentBox ||
    2104           0 :           aBox == StyleGeometryBox::PaddingBox ||
    2105           0 :           aBox == StyleGeometryBox::BorderBox ||
    2106           0 :           aBox == StyleGeometryBox::MarginBox);
    2107             : }
    2108             : 
    2109             : static StyleGeometryBox
    2110        1002 : ComputeBoxValue(nsIFrame* aForFrame, StyleGeometryBox aBox)
    2111             : {
    2112        1002 :   if (!(aForFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
    2113             :     // For elements with associated CSS layout box, the values fill-box,
    2114             :     // stroke-box and view-box compute to the initial value of mask-clip.
    2115        1002 :     if (IsSVGStyleGeometryBox(aBox)) {
    2116           0 :       return StyleGeometryBox::BorderBox;
    2117             :     }
    2118             :   } else {
    2119             :     // For SVG elements without associated CSS layout box, the values
    2120             :     // content-box, padding-box, border-box and margin-box compute to fill-box.
    2121           0 :     if (IsHTMLStyleGeometryBox(aBox)) {
    2122           0 :       return StyleGeometryBox::FillBox;
    2123             :     }
    2124             :   }
    2125             : 
    2126        1002 :   return aBox;
    2127             : }
    2128             : 
    2129             : bool
    2130         357 : nsCSSRendering::ImageLayerClipState::IsValid() const
    2131             : {
    2132             :   // mDirtyRectInDevPx comes from mDirtyRectInAppUnits. mDirtyRectInAppUnits
    2133             :   // can not be empty if mDirtyRectInDevPx is not.
    2134         357 :   if (!mDirtyRectInDevPx.IsEmpty() && mDirtyRectInAppUnits.IsEmpty()) {
    2135           0 :     return false;
    2136             :   }
    2137             : 
    2138         357 :   if (mHasRoundedCorners == mClippedRadii.IsEmpty()) {
    2139           0 :     return false;
    2140             :   }
    2141             : 
    2142         357 :   return true;
    2143             : }
    2144             : 
    2145             : /* static */ void
    2146         357 : nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
    2147             :                                   nsIFrame* aForFrame, const nsStyleBorder& aBorder,
    2148             :                                   const nsRect& aBorderArea, const nsRect& aCallerDirtyRect,
    2149             :                                   bool aWillPaintBorder, nscoord aAppUnitsPerPixel,
    2150             :                                   /* out */ ImageLayerClipState* aClipState)
    2151             : {
    2152         357 :   aClipState->mHasRoundedCorners = false;
    2153         357 :   aClipState->mHasAdditionalBGClipArea = false;
    2154         357 :   aClipState->mAdditionalBGClipArea.SetEmpty();
    2155         357 :   aClipState->mCustomClip = false;
    2156             : 
    2157         357 :   StyleGeometryBox layerClip = ComputeBoxValue(aForFrame, aLayer.mClip);
    2158         357 :   if (IsSVGStyleGeometryBox(layerClip)) {
    2159           0 :     MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
    2160             :                !aForFrame->IsSVGOuterSVGFrame());
    2161             : 
    2162             :     // The coordinate space of clipArea is svg user space.
    2163             :     nsRect clipArea =
    2164           0 :       nsLayoutUtils::ComputeGeometryBox(aForFrame, layerClip);
    2165             : 
    2166             :     nsRect strokeBox = (layerClip == StyleGeometryBox::StrokeBox)
    2167             :       ? clipArea
    2168           0 :       : nsLayoutUtils::ComputeGeometryBox(aForFrame, StyleGeometryBox::StrokeBox);
    2169           0 :     nsRect clipAreaRelativeToStrokeBox = clipArea - strokeBox.TopLeft();
    2170             : 
    2171             :     // aBorderArea is the stroke-box area in a coordinate space defined by
    2172             :     // the caller. This coordinate space can be svg user space of aForFrame,
    2173             :     // the space of aForFrame's reference-frame, or anything else.
    2174             :     //
    2175             :     // Which coordinate space chosen for aBorderArea is not matter. What
    2176             :     // matter is to ensure returning aClipState->mBGClipArea in the consistent
    2177             :     // coordiante space with aBorderArea. So we evaluate the position of clip
    2178             :     // area base on the position of aBorderArea here.
    2179           0 :     aClipState->mBGClipArea =
    2180           0 :       clipAreaRelativeToStrokeBox + aBorderArea.TopLeft();
    2181             : 
    2182           0 :     SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
    2183             :                     aAppUnitsPerPixel, &aClipState->mDirtyRectInAppUnits,
    2184           0 :                     &aClipState->mDirtyRectInDevPx);
    2185           0 :     MOZ_ASSERT(aClipState->IsValid());
    2186           0 :     return;
    2187             :   }
    2188             : 
    2189         357 :   if (layerClip == StyleGeometryBox::NoClip) {
    2190           0 :     aClipState->mBGClipArea = aCallerDirtyRect;
    2191             : 
    2192           0 :     SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
    2193             :                     aAppUnitsPerPixel, &aClipState->mDirtyRectInAppUnits,
    2194           0 :                     &aClipState->mDirtyRectInDevPx);
    2195           0 :     MOZ_ASSERT(aClipState->IsValid());
    2196           0 :     return;
    2197             :   }
    2198             : 
    2199         357 :   MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
    2200             :              aForFrame->IsSVGOuterSVGFrame());
    2201             : 
    2202             :   // Compute the outermost boundary of the area that might be painted.
    2203             :   // Same coordinate space as aBorderArea.
    2204         357 :   Sides skipSides = aForFrame->GetSkipSides();
    2205             :   nsRect clipBorderArea =
    2206         714 :     ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
    2207             : 
    2208         357 :   bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aBorderArea,
    2209         357 :                                      clipBorderArea, aClipState->mRadii);
    2210             : 
    2211             :   bool isSolidBorder =
    2212         357 :       aWillPaintBorder && IsOpaqueBorder(aBorder);
    2213         357 :   if (isSolidBorder && layerClip == StyleGeometryBox::BorderBox) {
    2214             :     // If we have rounded corners, we need to inflate the background
    2215             :     // drawing area a bit to avoid seams between the border and
    2216             :     // background.
    2217          11 :     layerClip = haveRoundedCorners
    2218          11 :                      ? StyleGeometryBox::MozAlmostPadding
    2219             :                      : StyleGeometryBox::PaddingBox;
    2220             :   }
    2221             : 
    2222         357 :   aClipState->mBGClipArea = clipBorderArea;
    2223             : 
    2224         363 :   if (aForFrame->IsScrollFrame() &&
    2225           6 :       NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment) {
    2226             :     // As of this writing, this is still in discussion in the CSS Working Group
    2227             :     // http://lists.w3.org/Archives/Public/www-style/2013Jul/0250.html
    2228             : 
    2229             :     // The rectangle for 'background-clip' scrolls with the content,
    2230             :     // but the background is also clipped at a non-scrolling 'padding-box'
    2231             :     // like the content. (See below.)
    2232             :     // Therefore, only 'content-box' makes a difference here.
    2233           0 :     if (layerClip == StyleGeometryBox::ContentBox) {
    2234           0 :       nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
    2235             :       // Clip at a rectangle attached to the scrolled content.
    2236           0 :       aClipState->mHasAdditionalBGClipArea = true;
    2237           0 :       aClipState->mAdditionalBGClipArea = nsRect(
    2238           0 :         aClipState->mBGClipArea.TopLeft()
    2239           0 :           + scrollableFrame->GetScrolledFrame()->GetPosition()
    2240             :           // For the dir=rtl case:
    2241           0 :           + scrollableFrame->GetScrollRange().TopLeft(),
    2242           0 :         scrollableFrame->GetScrolledRect().Size());
    2243           0 :       nsMargin padding = aForFrame->GetUsedPadding();
    2244             :       // padding-bottom is ignored on scrollable frames:
    2245             :       // https://bugzilla.mozilla.org/show_bug.cgi?id=748518
    2246           0 :       padding.bottom = 0;
    2247           0 :       padding.ApplySkipSides(skipSides);
    2248           0 :       aClipState->mAdditionalBGClipArea.Deflate(padding);
    2249             :     }
    2250             : 
    2251             :     // Also clip at a non-scrolling, rounded-corner 'padding-box',
    2252             :     // same as the scrolled content because of the 'overflow' property.
    2253           0 :     layerClip = StyleGeometryBox::PaddingBox;
    2254             :   }
    2255             : 
    2256             :   // See the comment of StyleGeometryBox::Margin.
    2257             :   // Hitting this assertion means we decide to turn on margin-box support for
    2258             :   // positioned mask from CSS parser and style system. In this case, you
    2259             :   // should *inflate* mBGClipArea by the margin returning from
    2260             :   // aForFrame->GetUsedMargin() in the code chunk bellow.
    2261         357 :   MOZ_ASSERT(layerClip != StyleGeometryBox::MarginBox,
    2262             :              "StyleGeometryBox::MarginBox rendering is not supported yet.\n");
    2263             : 
    2264         357 :   if (layerClip != StyleGeometryBox::BorderBox &&
    2265             :       layerClip != StyleGeometryBox::Text) {
    2266         203 :     nsMargin border = aForFrame->GetUsedBorder();
    2267         203 :     if (layerClip == StyleGeometryBox::MozAlmostPadding) {
    2268             :       // Reduce |border| by 1px (device pixels) on all sides, if
    2269             :       // possible, so that we don't get antialiasing seams between the
    2270             :       // {background|mask} and border.
    2271           0 :       border.top = std::max(0, border.top - aAppUnitsPerPixel);
    2272           0 :       border.right = std::max(0, border.right - aAppUnitsPerPixel);
    2273           0 :       border.bottom = std::max(0, border.bottom - aAppUnitsPerPixel);
    2274           0 :       border.left = std::max(0, border.left - aAppUnitsPerPixel);
    2275         203 :     } else if (layerClip != StyleGeometryBox::PaddingBox) {
    2276          72 :       NS_ASSERTION(layerClip == StyleGeometryBox::ContentBox,
    2277             :                    "unexpected background-clip");
    2278          72 :       border += aForFrame->GetUsedPadding();
    2279             :     }
    2280         203 :     border.ApplySkipSides(skipSides);
    2281         203 :     aClipState->mBGClipArea.Deflate(border);
    2282             : 
    2283         203 :     if (haveRoundedCorners) {
    2284          72 :       nsIFrame::InsetBorderRadii(aClipState->mRadii, border);
    2285             :     }
    2286             :   }
    2287             : 
    2288         357 :   if (haveRoundedCorners) {
    2289          72 :     auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
    2290          72 :     nsCSSRendering::ComputePixelRadii(aClipState->mRadii, d2a, &aClipState->mClippedRadii);
    2291          72 :     aClipState->mHasRoundedCorners = !aClipState->mClippedRadii.IsEmpty();
    2292             :   }
    2293             : 
    2294             : 
    2295         357 :   if (!haveRoundedCorners && aClipState->mHasAdditionalBGClipArea) {
    2296             :     // Do the intersection here to account for the fast path(?) below.
    2297           0 :     aClipState->mBGClipArea =
    2298           0 :       aClipState->mBGClipArea.Intersect(aClipState->mAdditionalBGClipArea);
    2299           0 :     aClipState->mHasAdditionalBGClipArea = false;
    2300             :   }
    2301             : 
    2302         357 :   SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect, aAppUnitsPerPixel,
    2303             :                   &aClipState->mDirtyRectInAppUnits,
    2304         357 :                   &aClipState->mDirtyRectInDevPx);
    2305             : 
    2306         357 :   MOZ_ASSERT(aClipState->IsValid());
    2307             : }
    2308             : 
    2309             : static void
    2310           3 : SetupImageLayerClip(nsCSSRendering::ImageLayerClipState& aClipState,
    2311             :                     gfxContext *aCtx, nscoord aAppUnitsPerPixel,
    2312             :                     gfxContextAutoSaveRestore* aAutoSR)
    2313             : {
    2314           3 :   if (aClipState.mDirtyRectInDevPx.IsEmpty()) {
    2315             :     // Our caller won't draw anything under this condition, so no need
    2316             :     // to set more up.
    2317           0 :     return;
    2318             :   }
    2319             : 
    2320           3 :   if (aClipState.mCustomClip) {
    2321             :     // We don't support custom clips and rounded corners, arguably a bug, but
    2322             :     // table painting seems to depend on it.
    2323           0 :     return;
    2324             :   }
    2325             : 
    2326             :   // If we have rounded corners, clip all subsequent drawing to the
    2327             :   // rounded rectangle defined by bgArea and bgRadii (we don't know
    2328             :   // whether the rounded corners intrude on the dirtyRect or not).
    2329             :   // Do not do this if we have a caller-provided clip rect --
    2330             :   // as above with bgArea, arguably a bug, but table painting seems
    2331             :   // to depend on it.
    2332             : 
    2333           3 :   if (aClipState.mHasAdditionalBGClipArea) {
    2334             :     gfxRect bgAreaGfx = nsLayoutUtils::RectToGfxRect(
    2335           0 :       aClipState.mAdditionalBGClipArea, aAppUnitsPerPixel);
    2336           0 :     bgAreaGfx.Round();
    2337           0 :     gfxUtils::ConditionRect(bgAreaGfx);
    2338             : 
    2339           0 :     aAutoSR->EnsureSaved(aCtx);
    2340           0 :     aCtx->NewPath();
    2341           0 :     aCtx->Rectangle(bgAreaGfx, true);
    2342           0 :     aCtx->Clip();
    2343             :   }
    2344             : 
    2345           3 :   if (aClipState.mHasRoundedCorners) {
    2346           0 :     Rect bgAreaGfx = NSRectToRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
    2347           0 :     bgAreaGfx.Round();
    2348             : 
    2349           0 :     if (bgAreaGfx.IsEmpty()) {
    2350             :       // I think it's become possible to hit this since
    2351             :       // https://hg.mozilla.org/mozilla-central/rev/50e934e4979b landed.
    2352           0 :       NS_WARNING("converted background area should not be empty");
    2353             :       // Make our caller not do anything.
    2354           0 :       aClipState.mDirtyRectInDevPx.SizeTo(gfxSize(0.0, 0.0));
    2355           0 :       return;
    2356             :     }
    2357             : 
    2358           0 :     aAutoSR->EnsureSaved(aCtx);
    2359             : 
    2360             :     RefPtr<Path> roundedRect =
    2361           0 :       MakePathForRoundedRect(*aCtx->GetDrawTarget(), bgAreaGfx,
    2362           0 :                              aClipState.mClippedRadii);
    2363           0 :     aCtx->Clip(roundedRect);
    2364             :   }
    2365             : }
    2366             : 
    2367             : static void
    2368           0 : DrawBackgroundColor(nsCSSRendering::ImageLayerClipState& aClipState,
    2369             :                     gfxContext *aCtx, nscoord aAppUnitsPerPixel)
    2370             : {
    2371           0 :   if (aClipState.mDirtyRectInDevPx.IsEmpty()) {
    2372             :     // Our caller won't draw anything under this condition, so no need
    2373             :     // to set more up.
    2374           0 :     return;
    2375             :   }
    2376             : 
    2377           0 :   DrawTarget* drawTarget = aCtx->GetDrawTarget();
    2378             : 
    2379             :   // We don't support custom clips and rounded corners, arguably a bug, but
    2380             :   // table painting seems to depend on it.
    2381           0 :   if (!aClipState.mHasRoundedCorners || aClipState.mCustomClip) {
    2382           0 :     aCtx->NewPath();
    2383           0 :     aCtx->Rectangle(aClipState.mDirtyRectInDevPx, true);
    2384           0 :     aCtx->Fill();
    2385           0 :     return;
    2386             :   }
    2387             : 
    2388           0 :   Rect bgAreaGfx = NSRectToRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
    2389           0 :   bgAreaGfx.Round();
    2390             : 
    2391           0 :   if (bgAreaGfx.IsEmpty()) {
    2392             :     // I think it's become possible to hit this since
    2393             :     // https://hg.mozilla.org/mozilla-central/rev/50e934e4979b landed.
    2394           0 :     NS_WARNING("converted background area should not be empty");
    2395             :     // Make our caller not do anything.
    2396           0 :     aClipState.mDirtyRectInDevPx.SizeTo(gfxSize(0.0, 0.0));
    2397           0 :     return;
    2398             :   }
    2399             : 
    2400           0 :   aCtx->Save();
    2401           0 :   gfxRect dirty = ThebesRect(bgAreaGfx).Intersect(aClipState.mDirtyRectInDevPx);
    2402             : 
    2403           0 :   aCtx->NewPath();
    2404           0 :   aCtx->Rectangle(dirty, true);
    2405           0 :   aCtx->Clip();
    2406             : 
    2407           0 :   if (aClipState.mHasAdditionalBGClipArea) {
    2408             :     gfxRect bgAdditionalAreaGfx = nsLayoutUtils::RectToGfxRect(
    2409           0 :       aClipState.mAdditionalBGClipArea, aAppUnitsPerPixel);
    2410           0 :     bgAdditionalAreaGfx.Round();
    2411           0 :     gfxUtils::ConditionRect(bgAdditionalAreaGfx);
    2412           0 :     aCtx->NewPath();
    2413           0 :     aCtx->Rectangle(bgAdditionalAreaGfx, true);
    2414           0 :     aCtx->Clip();
    2415             :   }
    2416             : 
    2417             :   RefPtr<Path> roundedRect =
    2418           0 :     MakePathForRoundedRect(*drawTarget, bgAreaGfx, aClipState.mClippedRadii);
    2419           0 :   aCtx->SetPath(roundedRect);
    2420           0 :   aCtx->Fill();
    2421           0 :   aCtx->Restore();
    2422             : }
    2423             : 
    2424             : nscolor
    2425         506 : nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
    2426             :                                          nsStyleContext* aStyleContext,
    2427             :                                          nsIFrame* aFrame,
    2428             :                                          bool& aDrawBackgroundImage,
    2429             :                                          bool& aDrawBackgroundColor)
    2430             : {
    2431         506 :   aDrawBackgroundImage = true;
    2432         506 :   aDrawBackgroundColor = true;
    2433             : 
    2434         506 :   const nsStyleVisibility* visibility = aStyleContext->StyleVisibility();
    2435             : 
    2436        1012 :   if (visibility->mColorAdjust != NS_STYLE_COLOR_ADJUST_EXACT &&
    2437         506 :       aFrame->HonorPrintBackgroundSettings()) {
    2438         386 :     aDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
    2439         386 :     aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
    2440             :   }
    2441             : 
    2442         506 :   const nsStyleBackground *bg = aStyleContext->StyleBackground();
    2443             :   nscolor bgColor;
    2444         506 :   if (aDrawBackgroundColor) {
    2445             :     bgColor = aStyleContext->
    2446         506 :       GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
    2447         506 :     if (NS_GET_A(bgColor) == 0) {
    2448         279 :       aDrawBackgroundColor = false;
    2449             :     }
    2450             :   } else {
    2451             :     // If GetBackgroundColorDraw() is false, we are still expected to
    2452             :     // draw color in the background of any frame that's not completely
    2453             :     // transparent, but we are expected to use white instead of whatever
    2454             :     // color was specified.
    2455           0 :     bgColor = NS_RGB(255, 255, 255);
    2456           0 :     if (aDrawBackgroundImage || !bg->IsTransparent(aStyleContext)) {
    2457           0 :       aDrawBackgroundColor = true;
    2458             :     } else {
    2459           0 :       bgColor = NS_RGBA(0,0,0,0);
    2460             :     }
    2461             :   }
    2462             : 
    2463             :   // We can skip painting the background color if a background image is opaque.
    2464         506 :   nsStyleImageLayers::Repeat repeat = bg->BottomLayer().mRepeat;
    2465         538 :   bool xFullRepeat = repeat.mXRepeat == StyleImageLayerRepeat::Repeat ||
    2466         538 :                      repeat.mXRepeat == StyleImageLayerRepeat::Round;
    2467         578 :   bool yFullRepeat = repeat.mYRepeat == StyleImageLayerRepeat::Repeat ||
    2468         578 :                      repeat.mYRepeat == StyleImageLayerRepeat::Round;
    2469        1239 :   if (aDrawBackgroundColor &&
    2470         406 :       xFullRepeat && yFullRepeat &&
    2471         689 :       bg->BottomLayer().mImage.IsOpaque() &&
    2472           0 :       bg->BottomLayer().mBlendMode == NS_STYLE_BLEND_NORMAL) {
    2473           0 :     aDrawBackgroundColor = false;
    2474             :   }
    2475             : 
    2476         506 :   return bgColor;
    2477             : }
    2478             : 
    2479             : static CompositionOp
    2480          59 : DetermineCompositionOp(const nsCSSRendering::PaintBGParams& aParams,
    2481             :                        const nsStyleImageLayers& aLayers,
    2482             :                        uint32_t aLayerIndex)
    2483             : {
    2484          59 :   if (aParams.layer >= 0) {
    2485             :     // When drawing a single layer, use the specified composition op.
    2486          59 :     return aParams.compositionOp;
    2487             :   }
    2488             : 
    2489           0 :   const nsStyleImageLayers::Layer& layer = aLayers.mLayers[aLayerIndex];
    2490             :   // When drawing all layers, get the compositon op from each image layer.
    2491           0 :   if (aParams.paintFlags & nsCSSRendering::PAINTBG_MASK_IMAGE) {
    2492             :     // Always using OP_OVER mode while drawing the bottom mask layer.
    2493           0 :     if (aLayerIndex == (aLayers.mImageCount - 1)) {
    2494           0 :       return CompositionOp::OP_OVER;
    2495             :     }
    2496             : 
    2497           0 :     return nsCSSRendering::GetGFXCompositeMode(layer.mComposite);
    2498             :   }
    2499             : 
    2500           0 :   return nsCSSRendering::GetGFXBlendMode(layer.mBlendMode);
    2501             : }
    2502             : 
    2503             : DrawResult
    2504          59 : nsCSSRendering::PaintStyleImageLayerWithSC(const PaintBGParams& aParams,
    2505             :                                            gfxContext& aRenderingCtx,
    2506             :                                            nsStyleContext *aBackgroundSC,
    2507             :                                            const nsStyleBorder& aBorder)
    2508             : {
    2509          59 :   NS_PRECONDITION(aParams.frame,
    2510             :                   "Frame is expected to be provided to PaintStyleImageLayerWithSC");
    2511             : 
    2512             :   // If we're drawing all layers, aCompositonOp is ignored, so make sure that
    2513             :   // it was left at its default value.
    2514          59 :   MOZ_ASSERT(aParams.layer != -1 ||
    2515             :              aParams.compositionOp == CompositionOp::OP_OVER);
    2516             : 
    2517             :   // Check to see if we have an appearance defined.  If so, we let the theme
    2518             :   // renderer draw the background and bail out.
    2519             :   // XXXzw this ignores aParams.bgClipRect.
    2520          59 :   const nsStyleDisplay* displayData = aParams.frame->StyleDisplay();
    2521          59 :   if (displayData->mAppearance) {
    2522           0 :     nsITheme *theme = aParams.presCtx.GetTheme();
    2523           0 :     if (theme && theme->ThemeSupportsWidget(&aParams.presCtx,
    2524           0 :                                             aParams.frame,
    2525           0 :                                             displayData->mAppearance)) {
    2526           0 :       nsRect drawing(aParams.borderArea);
    2527           0 :       theme->GetWidgetOverflow(aParams.presCtx.DeviceContext(),
    2528           0 :                                aParams.frame, displayData->mAppearance,
    2529           0 :                                &drawing);
    2530           0 :       drawing.IntersectRect(drawing, aParams.dirtyRect);
    2531           0 :       theme->DrawWidgetBackground(&aRenderingCtx, aParams.frame,
    2532           0 :                                   displayData->mAppearance, aParams.borderArea,
    2533           0 :                                   drawing);
    2534           0 :       return DrawResult::SUCCESS;
    2535             :     }
    2536             :   }
    2537             : 
    2538             :   // For canvas frames (in the CSS sense) we draw the background color using
    2539             :   // a solid color item that gets added in nsLayoutUtils::PaintFrame,
    2540             :   // or nsSubDocumentFrame::BuildDisplayList (bug 488242). (The solid
    2541             :   // color may be moved into nsDisplayCanvasBackground by
    2542             :   // nsPresShell::AddCanvasBackgroundColorItem, and painted by
    2543             :   // nsDisplayCanvasBackground directly.) Either way we don't need to
    2544             :   // paint the background color here.
    2545          59 :   bool isCanvasFrame = IsCanvasFrame(aParams.frame);
    2546             : 
    2547             :   // Determine whether we are drawing background images and/or
    2548             :   // background colors.
    2549             :   bool drawBackgroundImage;
    2550             :   bool drawBackgroundColor;
    2551             : 
    2552          59 :   nscolor bgColor = DetermineBackgroundColor(&aParams.presCtx,
    2553             :                                              aBackgroundSC,
    2554          59 :                                              aParams.frame,
    2555             :                                              drawBackgroundImage,
    2556          59 :                                              drawBackgroundColor);
    2557             : 
    2558          59 :   bool paintMask = (aParams.paintFlags & PAINTBG_MASK_IMAGE);
    2559             :   const nsStyleImageLayers& layers = paintMask ?
    2560           3 :     aBackgroundSC->StyleSVGReset()->mMask :
    2561          62 :     aBackgroundSC->StyleBackground()->mImage;
    2562             :   // If we're drawing a specific layer, we don't want to draw the
    2563             :   // background color.
    2564          59 :   if ((drawBackgroundColor && aParams.layer >= 0) || paintMask) {
    2565          31 :     drawBackgroundColor = false;
    2566             :   }
    2567             : 
    2568             :   // At this point, drawBackgroundImage and drawBackgroundColor are
    2569             :   // true if and only if we are actually supposed to paint an image or
    2570             :   // color into aDirtyRect, respectively.
    2571          59 :   if (!drawBackgroundImage && !drawBackgroundColor)
    2572           0 :     return DrawResult::SUCCESS;
    2573             : 
    2574             :   // The 'bgClipArea' (used only by the image tiling logic, far below)
    2575             :   // is the caller-provided aParams.bgClipRect if any, or else the area
    2576             :   // determined by the value of 'background-clip' in
    2577             :   // SetupCurrentBackgroundClip.  (Arguably it should be the
    2578             :   // intersection, but that breaks the table painter -- in particular,
    2579             :   // taking the intersection breaks reftests/bugs/403249-1[ab].)
    2580          59 :   nscoord appUnitsPerPixel = aParams.presCtx.AppUnitsPerDevPixel();
    2581         118 :   ImageLayerClipState clipState;
    2582          59 :   if (aParams.bgClipRect) {
    2583          56 :     clipState.mBGClipArea = *aParams.bgClipRect;
    2584          56 :     clipState.mCustomClip = true;
    2585          56 :     clipState.mHasRoundedCorners = false;
    2586          56 :     SetupDirtyRects(clipState.mBGClipArea, aParams.dirtyRect, appUnitsPerPixel,
    2587             :                     &clipState.mDirtyRectInAppUnits,
    2588          56 :                     &clipState.mDirtyRectInDevPx);
    2589             :   } else {
    2590           6 :     GetImageLayerClip(layers.BottomLayer(),
    2591           3 :                       aParams.frame, aBorder, aParams.borderArea,
    2592             :                       aParams.dirtyRect,
    2593           3 :                       (aParams.paintFlags & PAINTBG_WILL_PAINT_BORDER),
    2594             :                       appUnitsPerPixel,
    2595           3 :                       &clipState);
    2596             :   }
    2597             : 
    2598             :   // If we might be using a background color, go ahead and set it now.
    2599          59 :   if (drawBackgroundColor && !isCanvasFrame) {
    2600           0 :     aRenderingCtx.SetColor(Color::FromABGR(bgColor));
    2601             :   }
    2602             : 
    2603             :   // If there is no background image, draw a color.  (If there is
    2604             :   // neither a background image nor a color, we wouldn't have gotten
    2605             :   // this far.)
    2606          59 :   if (!drawBackgroundImage) {
    2607           0 :     if (!isCanvasFrame) {
    2608           0 :       DrawBackgroundColor(clipState, &aRenderingCtx, appUnitsPerPixel);
    2609             :     }
    2610           0 :     return DrawResult::SUCCESS;
    2611             :   }
    2612             : 
    2613          59 :   if (layers.mImageCount < 1) {
    2614             :     // Return if there are no background layers, all work from this point
    2615             :     // onwards happens iteratively on these.
    2616           0 :     return DrawResult::SUCCESS;
    2617             :   }
    2618             : 
    2619          59 :   MOZ_ASSERT((aParams.layer < 0) ||
    2620             :              (layers.mImageCount > uint32_t(aParams.layer)));
    2621          59 :   bool drawAllLayers = (aParams.layer < 0);
    2622             : 
    2623             :   // Ensure we get invalidated for loads of the image.  We need to do
    2624             :   // this here because this might be the only code that knows about the
    2625             :   // association of the style data with the frame.
    2626          59 :   if (aBackgroundSC != aParams.frame->StyleContext()) {
    2627           0 :     uint32_t startLayer = drawAllLayers ? layers.mImageCount - 1
    2628           0 :                                         : aParams.layer;
    2629           0 :     uint32_t count = drawAllLayers ? layers.mImageCount : 1;
    2630           0 :     NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers, startLayer,
    2631             :                                                          count) {
    2632           0 :       aParams.frame->AssociateImage(layers.mLayers[i].mImage,
    2633           0 :                                     &aParams.presCtx);
    2634             :     }
    2635             :   }
    2636             : 
    2637             :   // The background color is rendered over the entire dirty area,
    2638             :   // even if the image isn't.
    2639          59 :   if (drawBackgroundColor && !isCanvasFrame) {
    2640           0 :     DrawBackgroundColor(clipState, &aRenderingCtx, appUnitsPerPixel);
    2641             :   }
    2642             : 
    2643          59 :   if (!drawBackgroundImage) {
    2644           0 :     return DrawResult::SUCCESS; // No need to draw layer image, we can early
    2645             :                                 // return now.
    2646             :   }
    2647             : 
    2648             :   // Compute the outermost boundary of the area that might be painted.
    2649             :   // Same coordinate space as aParams.borderArea & aParams.bgClipRect.
    2650          59 :   Sides skipSides = aParams.frame->GetSkipSides();
    2651             :   nsRect paintBorderArea =
    2652          59 :     ::BoxDecorationRectForBackground(aParams.frame, aParams.borderArea,
    2653         177 :                                      skipSides, &aBorder);
    2654             :   nsRect clipBorderArea =
    2655          59 :     ::BoxDecorationRectForBorder(aParams.frame, aParams.borderArea,
    2656         177 :                                  skipSides, &aBorder);
    2657             : 
    2658          59 :   DrawResult result = DrawResult::SUCCESS;
    2659          59 :   StyleGeometryBox currentBackgroundClip = StyleGeometryBox::BorderBox;
    2660             :   uint32_t count = drawAllLayers
    2661         118 :     ? layers.mImageCount                  // iterate all image layers.
    2662         118 :     : layers.mImageCount - aParams.layer; // iterate from the bottom layer to
    2663             :                                           // the 'aParams.layer-th' layer.
    2664         142 :   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers,
    2665             :                                                        layers.mImageCount - 1,
    2666             :                                                        count) {
    2667             :     // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved(ctx)
    2668             :     // in the cases we need it.
    2669         142 :     gfxContextAutoSaveRestore autoSR;
    2670          83 :     const nsStyleImageLayers::Layer& layer = layers.mLayers[i];
    2671             : 
    2672          83 :     if (!aParams.bgClipRect) {
    2673           3 :       bool isBottomLayer = (i == layers.mImageCount - 1);
    2674           3 :       if (currentBackgroundClip != layer.mClip || isBottomLayer) {
    2675           3 :         currentBackgroundClip = layer.mClip;
    2676             :         // For  the bottom layer, we already called GetImageLayerClip above
    2677             :         // and it stored its results in clipState.
    2678           3 :         if (!isBottomLayer) {
    2679           0 :           GetImageLayerClip(layer, aParams.frame,
    2680             :                             aBorder, aParams.borderArea, aParams.dirtyRect,
    2681           0 :                             (aParams.paintFlags & PAINTBG_WILL_PAINT_BORDER),
    2682           0 :                             appUnitsPerPixel, &clipState);
    2683             :         }
    2684             :         SetupImageLayerClip(clipState, &aRenderingCtx,
    2685           3 :                             appUnitsPerPixel, &autoSR);
    2686           3 :         if (!clipBorderArea.IsEqualEdges(aParams.borderArea)) {
    2687             :           // We're drawing the background for the joined continuation boxes
    2688             :           // so we need to clip that to the slice that we want for this
    2689             :           // frame.
    2690             :           gfxRect clip =
    2691           0 :             nsLayoutUtils::RectToGfxRect(aParams.borderArea, appUnitsPerPixel);
    2692           0 :           autoSR.EnsureSaved(&aRenderingCtx);
    2693           0 :           aRenderingCtx.NewPath();
    2694           0 :           aRenderingCtx.SnappedRectangle(clip);
    2695           0 :           aRenderingCtx.Clip();
    2696             :         }
    2697             :       }
    2698             :     }
    2699             : 
    2700             :     // Skip the following layer preparing and painting code if the current
    2701             :     // layer is not selected for drawing.
    2702          83 :     if (aParams.layer >= 0 && i != (uint32_t)aParams.layer) {
    2703          24 :       continue;
    2704             :     }
    2705             :     nsBackgroundLayerState state =
    2706          59 :       PrepareImageLayer(&aParams.presCtx, aParams.frame,
    2707          59 :                         aParams.paintFlags, paintBorderArea,
    2708         118 :                         clipState.mBGClipArea, layer, nullptr);
    2709          59 :     result &= state.mImageRenderer.PrepareResult();
    2710             : 
    2711             :     // Skip the layer painting code if we found the dirty region is empty.
    2712          59 :     if (clipState.mDirtyRectInDevPx.IsEmpty()) {
    2713           0 :       continue;
    2714             :     }
    2715             : 
    2716          59 :     if (!state.mFillArea.IsEmpty()) {
    2717          59 :       CompositionOp co = DetermineCompositionOp(aParams, layers, i);
    2718          59 :       if (co != CompositionOp::OP_OVER) {
    2719           0 :         NS_ASSERTION(aRenderingCtx.CurrentOp() == CompositionOp::OP_OVER,
    2720             :                      "It is assumed the initial op is OP_OVER, when it is "
    2721             :                      "restored later");
    2722           0 :         aRenderingCtx.SetOp(co);
    2723             :       }
    2724             : 
    2725             :       result &=
    2726          59 :         state.mImageRenderer.DrawLayer(&aParams.presCtx,
    2727             :                                        aRenderingCtx,
    2728             :                                        state.mDestArea, state.mFillArea,
    2729         118 :                                        state.mAnchor + paintBorderArea.TopLeft(),
    2730             :                                        clipState.mDirtyRectInAppUnits,
    2731         118 :                                        state.mRepeatSize, aParams.opacity);
    2732             : 
    2733          59 :       if (co != CompositionOp::OP_OVER) {
    2734           0 :         aRenderingCtx.SetOp(CompositionOp::OP_OVER);
    2735             :       }
    2736             :     }
    2737             :   }
    2738             : 
    2739          59 :   return result;
    2740             : }
    2741             : 
    2742             : DrawResult
    2743           0 : nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
    2744             :                                                                    mozilla::wr::DisplayListBuilder& aBuilder,
    2745             :                                                                    const mozilla::layers::StackingContextHelper& aSc,
    2746             :                                                                    nsTArray<WebRenderParentCommand>& aParentCommands,
    2747             :                                                                    mozilla::layers::WebRenderDisplayItemLayer* aLayer,
    2748             :                                                                    mozilla::layers::WebRenderLayerManager* aManager,
    2749             :                                                                    nsDisplayItem* aItem,
    2750             :                                                                    nsStyleContext *aBackgroundSC,
    2751             :                                                                    const nsStyleBorder& aBorder)
    2752             : {
    2753           0 :   MOZ_ASSERT(!(aParams.paintFlags & PAINTBG_MASK_IMAGE));
    2754             : 
    2755           0 :   nscoord appUnitsPerPixel = aParams.presCtx.AppUnitsPerDevPixel();
    2756           0 :   ImageLayerClipState clipState;
    2757             : 
    2758           0 :   clipState.mBGClipArea = *aParams.bgClipRect;
    2759           0 :   clipState.mCustomClip = true;
    2760           0 :   clipState.mHasRoundedCorners = false;
    2761           0 :   SetupDirtyRects(clipState.mBGClipArea, aParams.dirtyRect, appUnitsPerPixel,
    2762             :                   &clipState.mDirtyRectInAppUnits,
    2763           0 :                   &clipState.mDirtyRectInDevPx);
    2764             : 
    2765             :   // Compute the outermost boundary of the area that might be painted.
    2766             :   // Same coordinate space as aParams.borderArea & aParams.bgClipRect.
    2767           0 :   Sides skipSides = aParams.frame->GetSkipSides();
    2768             :   nsRect paintBorderArea =
    2769           0 :     ::BoxDecorationRectForBackground(aParams.frame, aParams.borderArea,
    2770           0 :                                      skipSides, &aBorder);
    2771             : 
    2772           0 :   const nsStyleImageLayers& layers = aBackgroundSC->StyleBackground()->mImage;
    2773           0 :   const nsStyleImageLayers::Layer& layer = layers.mLayers[aParams.layer];
    2774             : 
    2775             :   // Skip the following layer painting code if we found the dirty region is
    2776             :   // empty or the current layer is not selected for drawing.
    2777           0 :   if (clipState.mDirtyRectInDevPx.IsEmpty()) {
    2778           0 :     return DrawResult::SUCCESS;
    2779             :   }
    2780             : 
    2781           0 :   DrawResult result = DrawResult::SUCCESS;
    2782             :   nsBackgroundLayerState state =
    2783           0 :     PrepareImageLayer(&aParams.presCtx, aParams.frame,
    2784           0 :                       aParams.paintFlags, paintBorderArea,
    2785           0 :                       clipState.mBGClipArea, layer, nullptr);
    2786           0 :   result &= state.mImageRenderer.PrepareResult();
    2787           0 :   if (!state.mFillArea.IsEmpty()) {
    2788           0 :     return state.mImageRenderer.BuildWebRenderDisplayItemsForLayer(&aParams.presCtx,
    2789             :                                      aBuilder, aSc, aParentCommands,
    2790             :                                      aLayer, aManager, aItem,
    2791             :                                      state.mDestArea, state.mFillArea,
    2792           0 :                                      state.mAnchor + paintBorderArea.TopLeft(),
    2793             :                                      clipState.mDirtyRectInAppUnits,
    2794           0 :                                      state.mRepeatSize, aParams.opacity);
    2795             :   }
    2796             : 
    2797           0 :   return result;
    2798             : }
    2799             : 
    2800             : nsRect
    2801         645 : nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
    2802             :                                                  nsIFrame* aForFrame,
    2803             :                                                  const nsRect& aBorderArea,
    2804             :                                                  const nsStyleImageLayers::Layer& aLayer,
    2805             :                                                  nsIFrame** aAttachedToFrame,
    2806             :                                                  bool* aOutIsTransformedFixed)
    2807             : {
    2808             :   // Compute {background|mask} origin area relative to aBorderArea now as we
    2809             :   // may need  it to compute the effective image size for a CSS gradient.
    2810        1290 :   nsRect positionArea;
    2811             : 
    2812             :   StyleGeometryBox layerOrigin =
    2813         645 :     ComputeBoxValue(aForFrame, aLayer.mOrigin);
    2814             : 
    2815         645 :   if (IsSVGStyleGeometryBox(layerOrigin)) {
    2816           0 :     MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
    2817             :                !aForFrame->IsSVGOuterSVGFrame());
    2818           0 :     *aAttachedToFrame = aForFrame;
    2819             : 
    2820           0 :     positionArea =
    2821           0 :       nsLayoutUtils::ComputeGeometryBox(aForFrame, layerOrigin);
    2822             : 
    2823           0 :     nsPoint toStrokeBoxOffset = nsPoint(0, 0);
    2824           0 :     if (layerOrigin != StyleGeometryBox::StrokeBox) {
    2825             :       nsRect strokeBox =
    2826             :         nsLayoutUtils::ComputeGeometryBox(aForFrame,
    2827           0 :                                           StyleGeometryBox::StrokeBox);
    2828           0 :       toStrokeBoxOffset = positionArea.TopLeft() - strokeBox.TopLeft();
    2829             :     }
    2830             : 
    2831             :     // For SVG frames, the return value is relative to the stroke box
    2832           0 :     return nsRect(toStrokeBoxOffset, positionArea.Size());
    2833             :   }
    2834             : 
    2835         645 :   MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
    2836             :              aForFrame->IsSVGOuterSVGFrame());
    2837             : 
    2838         645 :   LayoutFrameType frameType = aForFrame->Type();
    2839         645 :   nsIFrame* geometryFrame = aForFrame;
    2840         645 :   if (MOZ_UNLIKELY(frameType == LayoutFrameType::Scroll &&
    2841             :                    NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment)) {
    2842           0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
    2843           0 :     positionArea = nsRect(
    2844           0 :       scrollableFrame->GetScrolledFrame()->GetPosition()
    2845             :         // For the dir=rtl case:
    2846           0 :         + scrollableFrame->GetScrollRange().TopLeft(),
    2847           0 :       scrollableFrame->GetScrolledRect().Size());
    2848             :     // The ScrolledRect’s size does not include the borders or scrollbars,
    2849             :     // reverse the handling of background-origin
    2850             :     // compared to the common case below.
    2851           0 :     if (layerOrigin == StyleGeometryBox::BorderBox) {
    2852           0 :       nsMargin border = geometryFrame->GetUsedBorder();
    2853           0 :       border.ApplySkipSides(geometryFrame->GetSkipSides());
    2854           0 :       positionArea.Inflate(border);
    2855           0 :       positionArea.Inflate(scrollableFrame->GetActualScrollbarSizes());
    2856           0 :     } else if (layerOrigin != StyleGeometryBox::PaddingBox) {
    2857           0 :       nsMargin padding = geometryFrame->GetUsedPadding();
    2858           0 :       padding.ApplySkipSides(geometryFrame->GetSkipSides());
    2859           0 :       positionArea.Deflate(padding);
    2860           0 :       NS_ASSERTION(layerOrigin == StyleGeometryBox::ContentBox,
    2861             :                    "unknown background-origin value");
    2862             :     }
    2863           0 :     *aAttachedToFrame = aForFrame;
    2864           0 :     return positionArea;
    2865             :   }
    2866             : 
    2867         645 :   if (MOZ_UNLIKELY(frameType == LayoutFrameType::Canvas)) {
    2868           0 :     geometryFrame = aForFrame->PrincipalChildList().FirstChild();
    2869             :     // geometryFrame might be null if this canvas is a page created
    2870             :     // as an overflow container (e.g. the in-flow content has already
    2871             :     // finished and this page only displays the continuations of
    2872             :     // absolutely positioned content).
    2873           0 :     if (geometryFrame) {
    2874           0 :       positionArea = geometryFrame->GetRect();
    2875             :     }
    2876             :   } else {
    2877         645 :     positionArea = nsRect(nsPoint(0,0), aBorderArea.Size());
    2878             :   }
    2879             : 
    2880             :   // See the comment of StyleGeometryBox::MarginBox.
    2881             :   // Hitting this assertion means we decide to turn on margin-box support for
    2882             :   // positioned mask from CSS parser and style system. In this case, you
    2883             :   // should *inflate* positionArea by the margin returning from
    2884             :   // geometryFrame->GetUsedMargin() in the code chunk bellow.
    2885         645 :   MOZ_ASSERT(aLayer.mOrigin != StyleGeometryBox::MarginBox,
    2886             :              "StyleGeometryBox::MarginBox rendering is not supported yet.\n");
    2887             : 
    2888             :   // {background|mask} images are tiled over the '{background|mask}-clip' area
    2889             :   // but the origin of the tiling is based on the '{background|mask}-origin'
    2890             :   // area.
    2891         645 :   if (layerOrigin != StyleGeometryBox::BorderBox && geometryFrame) {
    2892         637 :     nsMargin border = geometryFrame->GetUsedBorder();
    2893         637 :     if (layerOrigin != StyleGeometryBox::PaddingBox) {
    2894           0 :       border += geometryFrame->GetUsedPadding();
    2895           0 :       NS_ASSERTION(layerOrigin == StyleGeometryBox::ContentBox,
    2896             :                    "unknown background-origin value");
    2897             :     }
    2898         637 :     positionArea.Deflate(border);
    2899             :   }
    2900             : 
    2901         645 :   nsIFrame* attachedToFrame = aForFrame;
    2902         645 :   if (NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED == aLayer.mAttachment) {
    2903             :     // If it's a fixed background attachment, then the image is placed
    2904             :     // relative to the viewport, which is the area of the root frame
    2905             :     // in a screen context or the page content frame in a print context.
    2906           0 :     attachedToFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame();
    2907           0 :     NS_ASSERTION(attachedToFrame, "no root frame");
    2908           0 :     nsIFrame* pageContentFrame = nullptr;
    2909           0 :     if (aPresContext->IsPaginated()) {
    2910             :       pageContentFrame = nsLayoutUtils::GetClosestFrameOfType(
    2911           0 :         aForFrame, LayoutFrameType::PageContent);
    2912           0 :       if (pageContentFrame) {
    2913           0 :         attachedToFrame = pageContentFrame;
    2914             :       }
    2915             :       // else this is an embedded shell and its root frame is what we want
    2916             :     }
    2917             : 
    2918             :     // If the background is affected by a transform, treat is as if it
    2919             :     // wasn't fixed.
    2920           0 :     if (nsLayoutUtils::IsTransformed(aForFrame, attachedToFrame)) {
    2921           0 :       attachedToFrame = aForFrame;
    2922           0 :       *aOutIsTransformedFixed = true;
    2923             :     } else {
    2924             :       // Set the background positioning area to the viewport's area
    2925             :       // (relative to aForFrame)
    2926           0 :       positionArea =
    2927           0 :         nsRect(-aForFrame->GetOffsetTo(attachedToFrame), attachedToFrame->GetSize());
    2928             : 
    2929           0 :       if (!pageContentFrame) {
    2930             :         // Subtract the size of scrollbars.
    2931             :         nsIScrollableFrame* scrollableFrame =
    2932           0 :           aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
    2933           0 :         if (scrollableFrame) {
    2934           0 :           nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
    2935           0 :           positionArea.Deflate(scrollbars);
    2936             :         }
    2937             :       }
    2938             :     }
    2939             :   }
    2940         645 :   *aAttachedToFrame = attachedToFrame;
    2941             : 
    2942         645 :   return positionArea;
    2943             : }
    2944             : 
    2945             : /* static */ nscoord
    2946           0 : nsCSSRendering::ComputeRoundedSize(nscoord aCurrentSize, nscoord aPositioningSize)
    2947             : {
    2948           0 :   float repeatCount = NS_roundf(float(aPositioningSize) / float(aCurrentSize));
    2949           0 :   if (repeatCount < 1.0f) {
    2950           0 :     return aPositioningSize;
    2951             :   }
    2952           0 :   return nscoord(NS_lround(float(aPositioningSize) / repeatCount));
    2953             : }
    2954             : 
    2955             : // Apply the CSS image sizing algorithm as it applies to background images.
    2956             : // See http://www.w3.org/TR/css3-background/#the-background-size .
    2957             : // aIntrinsicSize is the size that the background image 'would like to be'.
    2958             : // It can be found by calling nsImageRenderer::ComputeIntrinsicSize.
    2959             : static nsSize
    2960         452 : ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize,
    2961             :                               const nsSize& aBgPositioningArea,
    2962             :                               const nsStyleImageLayers::Size& aLayerSize,
    2963             :                               StyleImageLayerRepeat aXRepeat,
    2964             :                               StyleImageLayerRepeat aYRepeat)
    2965             : {
    2966         452 :   nsSize imageSize;
    2967             : 
    2968             :   // Size is dictated by cover or contain rules.
    2969         904 :   if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eContain ||
    2970         452 :       aLayerSize.mWidthType == nsStyleImageLayers::Size::eCover) {
    2971             :     nsImageRenderer::FitType fitType =
    2972           0 :       aLayerSize.mWidthType == nsStyleImageLayers::Size::eCover
    2973           0 :         ? nsImageRenderer::COVER
    2974           0 :         : nsImageRenderer::CONTAIN;
    2975             :     imageSize = nsImageRenderer::ComputeConstrainedSize(aBgPositioningArea,
    2976             :                                                         aIntrinsicSize.mRatio,
    2977           0 :                                                         fitType);
    2978             :   } else {
    2979             :     // No cover/contain constraint, use default algorithm.
    2980         452 :     CSSSizeOrRatio specifiedSize;
    2981         452 :     if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eLengthPercentage) {
    2982         216 :       specifiedSize.SetWidth(
    2983         216 :         aLayerSize.ResolveWidthLengthPercentage(aBgPositioningArea));
    2984             :     }
    2985         452 :     if (aLayerSize.mHeightType == nsStyleImageLayers::Size::eLengthPercentage) {
    2986         328 :       specifiedSize.SetHeight(
    2987         328 :         aLayerSize.ResolveHeightLengthPercentage(aBgPositioningArea));
    2988             :     }
    2989             : 
    2990             :     imageSize = nsImageRenderer::ComputeConcreteSize(specifiedSize,
    2991             :                                                      aIntrinsicSize,
    2992         452 :                                                      aBgPositioningArea);
    2993             :   }
    2994             : 
    2995             :   // See https://www.w3.org/TR/css3-background/#background-size .
    2996             :   // "If 'background-repeat' is 'round' for one (or both) dimensions, there is a second
    2997             :   //  step. The UA must scale the image in that dimension (or both dimensions) so that
    2998             :   //  it fits a whole number of times in the background positioning area."
    2999             :   // "If 'background-repeat' is 'round' for one dimension only and if 'background-size'
    3000             :   //  is 'auto' for the other dimension, then there is a third step: that other dimension
    3001             :   //  is scaled so that the original aspect ratio is restored."
    3002         452 :   bool isRepeatRoundInBothDimensions = aXRepeat == StyleImageLayerRepeat::Round  &&
    3003         452 :                                        aYRepeat == StyleImageLayerRepeat::Round;
    3004             : 
    3005             :   // Calculate the rounded size only if the background-size computation
    3006             :   // returned a correct size for the image.
    3007         452 :   if (imageSize.width && aXRepeat == StyleImageLayerRepeat::Round) {
    3008           0 :     imageSize.width =
    3009           0 :       nsCSSRendering::ComputeRoundedSize(imageSize.width,
    3010           0 :                                          aBgPositioningArea.width);
    3011           0 :     if (!isRepeatRoundInBothDimensions &&
    3012           0 :         aLayerSize.mHeightType == nsStyleImageLayers::Size::DimensionType::eAuto) {
    3013             :       // Restore intrinsic rato
    3014           0 :       if (aIntrinsicSize.mRatio.width) {
    3015           0 :         float scale = float(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width;
    3016           0 :         imageSize.height = NSCoordSaturatingNonnegativeMultiply(imageSize.width, scale);
    3017             :       }
    3018             :     }
    3019             :   }
    3020             : 
    3021             :   // Calculate the rounded size only if the background-size computation
    3022             :   // returned a correct size for the image.
    3023         452 :   if (imageSize.height && aYRepeat == StyleImageLayerRepeat::Round) {
    3024           0 :     imageSize.height =
    3025           0 :       nsCSSRendering::ComputeRoundedSize(imageSize.height,
    3026           0 :                                          aBgPositioningArea.height);
    3027           0 :     if (!isRepeatRoundInBothDimensions &&
    3028           0 :         aLayerSize.mWidthType == nsStyleImageLayers::Size::DimensionType::eAuto) {
    3029             :       // Restore intrinsic rato
    3030           0 :       if (aIntrinsicSize.mRatio.height) {
    3031           0 :         float scale = float(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height;
    3032           0 :         imageSize.width = NSCoordSaturatingNonnegativeMultiply(imageSize.height, scale);
    3033             :       }
    3034             :     }
    3035             :   }
    3036             : 
    3037         452 :   return imageSize;
    3038             : }
    3039             : 
    3040             : /* ComputeSpacedRepeatSize
    3041             :  * aImageDimension: the image width/height
    3042             :  * aAvailableSpace: the background positioning area width/height
    3043             :  * aRepeat: determine whether the image is repeated
    3044             :  * Returns the image size plus gap size of app units for use as spacing
    3045             :  */
    3046             : static nscoord
    3047           0 : ComputeSpacedRepeatSize(nscoord aImageDimension,
    3048             :                         nscoord aAvailableSpace,
    3049             :                         bool& aRepeat) {
    3050           0 :   float ratio = static_cast<float>(aAvailableSpace) / aImageDimension;
    3051             : 
    3052           0 :   if (ratio < 2.0f) { // If you can't repeat at least twice, then don't repeat.
    3053           0 :     aRepeat = false;
    3054           0 :     return aImageDimension;
    3055             :   } else {
    3056           0 :     aRepeat = true;
    3057           0 :     return (aAvailableSpace - aImageDimension) / (NSToIntFloor(ratio) - 1);
    3058             :   }
    3059             : }
    3060             : 
    3061             : /* static */ nscoord
    3062           0 : nsCSSRendering::ComputeBorderSpacedRepeatSize(nscoord aImageDimension,
    3063             :                                               nscoord aAvailableSpace,
    3064             :                                               nscoord& aSpace)
    3065             : {
    3066           0 :   int32_t count = aAvailableSpace / aImageDimension;
    3067           0 :   aSpace = (aAvailableSpace - aImageDimension * count) / (count + 1);
    3068           0 :   return aSpace + aImageDimension;
    3069             : }
    3070             : 
    3071             : nsBackgroundLayerState
    3072         454 : nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
    3073             :                                   nsIFrame* aForFrame,
    3074             :                                   uint32_t aFlags,
    3075             :                                   const nsRect& aBorderArea,
    3076             :                                   const nsRect& aBGClipRect,
    3077             :                                   const nsStyleImageLayers::Layer& aLayer,
    3078             :                                   bool* aOutIsTransformedFixed)
    3079             : {
    3080             :   /*
    3081             :    * The properties we need to keep in mind when drawing style image
    3082             :    * layers are:
    3083             :    *
    3084             :    *   background-image/ mask-image
    3085             :    *   background-repeat/ mask-repeat
    3086             :    *   background-attachment
    3087             :    *   background-position/ mask-position
    3088             :    *   background-clip/ mask-clip
    3089             :    *   background-origin/ mask-origin
    3090             :    *   background-size/ mask-size
    3091             :    *   background-blend-mode
    3092             :    *   box-decoration-break
    3093             :    *   mask-mode
    3094             :    *   mask-composite
    3095             :    *
    3096             :    * (background-color applies to the entire element and not to individual
    3097             :    * layers, so it is irrelevant to this method.)
    3098             :    *
    3099             :    * These properties have the following dependencies upon each other when
    3100             :    * determining rendering:
    3101             :    *
    3102             :    *   background-image/ mask-image
    3103             :    *     no dependencies
    3104             :    *   background-repeat/ mask-repeat
    3105             :    *     no dependencies
    3106             :    *   background-attachment
    3107             :    *     no dependencies
    3108             :    *   background-position/ mask-position
    3109             :    *     depends upon background-size/mask-size (for the image's scaled size)
    3110             :    *     and background-break (for the background positioning area)
    3111             :    *   background-clip/ mask-clip
    3112             :    *     no dependencies
    3113             :    *   background-origin/ mask-origin
    3114             :    *     depends upon background-attachment (only in the case where that value
    3115             :    *     is 'fixed')
    3116             :    *   background-size/ mask-size
    3117             :    *     depends upon box-decoration-break (for the background positioning area
    3118             :    *     for resolving percentages), background-image (for the image's intrinsic
    3119             :    *     size), background-repeat (if that value is 'round'), and
    3120             :    *     background-origin (for the background painting area, when
    3121             :    *     background-repeat is 'round')
    3122             :    *   background-blend-mode
    3123             :    *     no dependencies
    3124             :    *   mask-mode
    3125             :    *     no dependencies
    3126             :    *   mask-composite
    3127             :    *     no dependencies
    3128             :    *   box-decoration-break
    3129             :    *     no dependencies
    3130             :    *
    3131             :    * As a result of only-if dependencies we don't strictly do a topological
    3132             :    * sort of the above properties when processing, but it's pretty close to one:
    3133             :    *
    3134             :    *   background-clip/mask-clip (by caller)
    3135             :    *   background-image/ mask-image
    3136             :    *   box-decoration-break, background-origin/ mask origin
    3137             :    *   background-attachment (postfix for background-origin if 'fixed')
    3138             :    *   background-size/ mask-size
    3139             :    *   background-position/ mask-position
    3140             :    *   background-repeat/ mask-repeat
    3141             :    */
    3142             : 
    3143         454 :   uint32_t irFlags = 0;
    3144         454 :   if (aFlags & nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES) {
    3145           0 :     irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
    3146             :   }
    3147         454 :   if (aFlags & nsCSSRendering::PAINTBG_TO_WINDOW) {
    3148         446 :     irFlags |= nsImageRenderer::FLAG_PAINTING_TO_WINDOW;
    3149             :   }
    3150             : 
    3151         454 :   nsBackgroundLayerState state(aForFrame, &aLayer.mImage, irFlags);
    3152         454 :   if (!state.mImageRenderer.PrepareImage()) {
    3153             :     // There's no image or it's not ready to be painted.
    3154           2 :     if (aOutIsTransformedFixed) {
    3155           2 :       *aOutIsTransformedFixed = false;
    3156             :     }
    3157           2 :     return state;
    3158             :   }
    3159             : 
    3160             :   // The frame to which the background is attached
    3161         452 :   nsIFrame* attachedToFrame = aForFrame;
    3162             :   // Is the background marked 'fixed', but affected by a transform?
    3163         452 :   bool transformedFixed = false;
    3164             :   // Compute background origin area relative to aBorderArea now as we may need
    3165             :   // it to compute the effective image size for a CSS gradient.
    3166             :   nsRect positionArea =
    3167             :     ComputeImageLayerPositioningArea(aPresContext, aForFrame, aBorderArea,
    3168         904 :                                      aLayer, &attachedToFrame, &transformedFixed);
    3169         452 :   if (aOutIsTransformedFixed) {
    3170         199 :     *aOutIsTransformedFixed = transformedFixed;
    3171             :   }
    3172             : 
    3173             :   // For background-attachment:fixed backgrounds, we'll override the area
    3174             :   // where the background can be drawn to the viewport.
    3175         904 :   nsRect bgClipRect = aBGClipRect;
    3176             : 
    3177         452 :   if (NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED == aLayer.mAttachment &&
    3178           0 :       !transformedFixed &&
    3179           0 :       (aFlags & nsCSSRendering::PAINTBG_TO_WINDOW)) {
    3180           0 :     bgClipRect = positionArea + aBorderArea.TopLeft();
    3181             :   }
    3182             : 
    3183         452 :   StyleImageLayerRepeat repeatX = aLayer.mRepeat.mXRepeat;
    3184         452 :   StyleImageLayerRepeat repeatY = aLayer.mRepeat.mYRepeat;
    3185             : 
    3186             :   // Scale the image as specified for background-size and background-repeat.
    3187             :   // Also as required for proper background positioning when background-position
    3188             :   // is defined with percentages.
    3189         452 :   CSSSizeOrRatio intrinsicSize = state.mImageRenderer.ComputeIntrinsicSize();
    3190         452 :   nsSize bgPositionSize = positionArea.Size();
    3191             :   nsSize imageSize = ComputeDrawnSizeForBackground(intrinsicSize,
    3192             :                                                    bgPositionSize,
    3193             :                                                    aLayer.mSize,
    3194             :                                                    repeatX,
    3195         452 :                                                    repeatY);
    3196             : 
    3197         452 :   if (imageSize.width <= 0 || imageSize.height <= 0)
    3198           0 :     return state;
    3199             : 
    3200         452 :   state.mImageRenderer.SetPreferredSize(intrinsicSize,
    3201         452 :                                         imageSize);
    3202             : 
    3203             :   // Compute the anchor point.
    3204             :   //
    3205             :   // relative to aBorderArea.TopLeft() (which is where the top-left
    3206             :   // of aForFrame's border-box will be rendered)
    3207         452 :   nsPoint imageTopLeft;
    3208             : 
    3209             :   // Compute the position of the background now that the background's size is
    3210             :   // determined.
    3211         452 :   nsImageRenderer::ComputeObjectAnchorPoint(aLayer.mPosition,
    3212             :                                             bgPositionSize, imageSize,
    3213         452 :                                             &imageTopLeft, &state.mAnchor);
    3214         452 :   state.mRepeatSize = imageSize;
    3215         452 :   if (repeatX == StyleImageLayerRepeat::Space) {
    3216             :     bool isRepeat;
    3217           0 :     state.mRepeatSize.width = ComputeSpacedRepeatSize(imageSize.width,
    3218             :                                                       bgPositionSize.width,
    3219             :                                                       isRepeat);
    3220           0 :     if (isRepeat) {
    3221           0 :       imageTopLeft.x = 0;
    3222           0 :       state.mAnchor.x = 0;
    3223             :     } else {
    3224           0 :       repeatX = StyleImageLayerRepeat::NoRepeat;
    3225             :     }
    3226             :   }
    3227             : 
    3228         452 :   if (repeatY == StyleImageLayerRepeat::Space) {
    3229             :     bool isRepeat;
    3230           0 :     state.mRepeatSize.height = ComputeSpacedRepeatSize(imageSize.height,
    3231             :                                                        bgPositionSize.height,
    3232             :                                                        isRepeat);
    3233           0 :     if (isRepeat) {
    3234           0 :       imageTopLeft.y = 0;
    3235           0 :       state.mAnchor.y = 0;
    3236             :     } else {
    3237           0 :       repeatY = StyleImageLayerRepeat::NoRepeat;
    3238             :     }
    3239             :   }
    3240             : 
    3241         452 :   imageTopLeft += positionArea.TopLeft();
    3242         452 :   state.mAnchor += positionArea.TopLeft();
    3243         452 :   state.mDestArea = nsRect(imageTopLeft + aBorderArea.TopLeft(), imageSize);
    3244         452 :   state.mFillArea = state.mDestArea;
    3245             : 
    3246         452 :   ExtendMode repeatMode = ExtendMode::CLAMP;
    3247         452 :   if (repeatX == StyleImageLayerRepeat::Repeat ||
    3248          58 :       repeatX == StyleImageLayerRepeat::Round ||
    3249             :       repeatX == StyleImageLayerRepeat::Space) {
    3250         394 :     state.mFillArea.x = bgClipRect.x;
    3251         394 :     state.mFillArea.width = bgClipRect.width;
    3252         394 :     repeatMode = ExtendMode::REPEAT_X;
    3253             :   }
    3254         452 :   if (repeatY == StyleImageLayerRepeat::Repeat ||
    3255         170 :       repeatY == StyleImageLayerRepeat::Round ||
    3256             :       repeatY == StyleImageLayerRepeat::Space) {
    3257         282 :     state.mFillArea.y = bgClipRect.y;
    3258         282 :     state.mFillArea.height = bgClipRect.height;
    3259             : 
    3260             :     /***
    3261             :      * We're repeating on the X axis already,
    3262             :      * so if we have to repeat in the Y axis,
    3263             :      * we really need to repeat in both directions.
    3264             :      */
    3265         282 :     if (repeatMode == ExtendMode::REPEAT_X) {
    3266         282 :       repeatMode = ExtendMode::REPEAT;
    3267             :     } else {
    3268           0 :       repeatMode = ExtendMode::REPEAT_Y;
    3269             :     }
    3270             :   }
    3271         452 :   state.mImageRenderer.SetExtendMode(repeatMode);
    3272         452 :   state.mImageRenderer.SetMaskOp(aLayer.mMaskMode);
    3273             : 
    3274         452 :   state.mFillArea.IntersectRect(state.mFillArea, bgClipRect);
    3275             : 
    3276         452 :   return state;
    3277             : }
    3278             : 
    3279             : nsRect
    3280         194 : nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
    3281             :                                        nsIFrame* aForFrame,
    3282             :                                        const nsRect& aBorderArea,
    3283             :                                        const nsRect& aClipRect,
    3284             :                                        const nsStyleImageLayers::Layer& aLayer,
    3285             :                                        uint32_t aFlags)
    3286             : {
    3287         194 :   Sides skipSides = aForFrame->GetSkipSides();
    3288             :   nsRect borderArea =
    3289         388 :     ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides);
    3290             :   nsBackgroundLayerState state =
    3291             :       PrepareImageLayer(aPresContext, aForFrame, aFlags, borderArea,
    3292         388 :                              aClipRect, aLayer);
    3293         388 :   return state.mFillArea;
    3294             : }
    3295             : 
    3296             : // Begin table border-collapsing section
    3297             : // These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
    3298             : // At some point, all functions should be unified to include the additional functionality that these provide
    3299             : 
    3300             : static nscoord
    3301           0 : RoundIntToPixel(nscoord aValue,
    3302             :                 nscoord aTwipsPerPixel,
    3303             :                 bool    aRoundDown = false)
    3304             : {
    3305           0 :   if (aTwipsPerPixel <= 0)
    3306             :     // We must be rendering to a device that has a resolution greater than Twips!
    3307             :     // In that case, aValue is as accurate as it's going to get.
    3308           0 :     return aValue;
    3309             : 
    3310           0 :   nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
    3311           0 :   nscoord extra = aValue % aTwipsPerPixel;
    3312           0 :   nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
    3313           0 :   return finalValue;
    3314             : }
    3315             : 
    3316             : static nscoord
    3317           0 : RoundFloatToPixel(float   aValue,
    3318             :                   nscoord aTwipsPerPixel,
    3319             :                   bool    aRoundDown = false)
    3320             : {
    3321           0 :   return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
    3322             : }
    3323             : 
    3324           0 : static void SetPoly(const Rect& aRect, Point* poly)
    3325             : {
    3326           0 :   poly[0].x = aRect.x;
    3327           0 :   poly[0].y = aRect.y;
    3328           0 :   poly[1].x = aRect.x + aRect.width;
    3329           0 :   poly[1].y = aRect.y;
    3330           0 :   poly[2].x = aRect.x + aRect.width;
    3331           0 :   poly[2].y = aRect.y + aRect.height;
    3332           0 :   poly[3].x = aRect.x;
    3333           0 :   poly[3].y = aRect.y + aRect.height;
    3334           0 : }
    3335             : 
    3336             : static void
    3337           0 : DrawDashedSegment(DrawTarget&          aDrawTarget,
    3338             :                   nsRect               aRect,
    3339             :                   nscoord              aDashLength,
    3340             :                   nscolor              aColor,
    3341             :                   int32_t              aAppUnitsPerDevPixel,
    3342             :                   nscoord              aTwipsPerPixel,
    3343             :                   bool                 aHorizontal)
    3344             : {
    3345           0 :   ColorPattern color(ToDeviceColor(aColor));
    3346           0 :   DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE);
    3347           0 :   StrokeOptions strokeOptions;
    3348             : 
    3349             :   Float dash[2];
    3350           0 :   dash[0] = Float(aDashLength) / aAppUnitsPerDevPixel;
    3351           0 :   dash[1] = dash[0];
    3352             : 
    3353           0 :   strokeOptions.mDashPattern = dash;
    3354           0 :   strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
    3355             : 
    3356           0 :   if (aHorizontal) {
    3357           0 :     nsPoint left = (aRect.TopLeft() + aRect.BottomLeft()) / 2;
    3358           0 :     nsPoint right = (aRect.TopRight() + aRect.BottomRight()) / 2;
    3359           0 :     strokeOptions.mLineWidth = Float(aRect.height) / aAppUnitsPerDevPixel;
    3360             :     StrokeLineWithSnapping(left, right,
    3361             :                            aAppUnitsPerDevPixel, aDrawTarget,
    3362           0 :                            color, strokeOptions, drawOptions);
    3363             :   } else {
    3364           0 :     nsPoint top = (aRect.TopLeft() + aRect.TopRight()) / 2;
    3365           0 :     nsPoint bottom = (aRect.BottomLeft() + aRect.BottomRight()) / 2;
    3366           0 :     strokeOptions.mLineWidth = Float(aRect.width) / aAppUnitsPerDevPixel;
    3367             :     StrokeLineWithSnapping(top, bottom,
    3368             :                            aAppUnitsPerDevPixel, aDrawTarget,
    3369           0 :                            color, strokeOptions, drawOptions);
    3370             :   }
    3371           0 : }
    3372             : 
    3373             : static void
    3374           0 : DrawSolidBorderSegment(DrawTarget&          aDrawTarget,
    3375             :                        nsRect               aRect,
    3376             :                        nscolor              aColor,
    3377             :                        int32_t              aAppUnitsPerDevPixel,
    3378             :                        nscoord              aTwipsPerPixel,
    3379             :                        uint8_t              aStartBevelSide = 0,
    3380             :                        nscoord              aStartBevelOffset = 0,
    3381             :                        uint8_t              aEndBevelSide = 0,
    3382             :                        nscoord              aEndBevelOffset = 0)
    3383             : {
    3384           0 :   ColorPattern color(ToDeviceColor(aColor));
    3385           0 :   DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE);
    3386             : 
    3387             :   // We don't need to bevel single pixel borders
    3388           0 :   if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
    3389           0 :       ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
    3390             :     // simple rectangle
    3391           0 :     aDrawTarget.FillRect(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel,
    3392           0 :                                              aDrawTarget),
    3393           0 :                          color, drawOptions);
    3394             :   }
    3395             :   else {
    3396             :     // polygon with beveling
    3397           0 :     Point poly[4];
    3398           0 :     SetPoly(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel, aDrawTarget),
    3399           0 :             poly);
    3400             : 
    3401             :     Float startBevelOffset =
    3402           0 :       NSAppUnitsToFloatPixels(aStartBevelOffset, aAppUnitsPerDevPixel);
    3403           0 :     switch(aStartBevelSide) {
    3404             :     case eSideTop:
    3405           0 :       poly[0].x += startBevelOffset;
    3406           0 :       break;
    3407             :     case eSideBottom:
    3408           0 :       poly[3].x += startBevelOffset;
    3409           0 :       break;
    3410             :     case eSideRight:
    3411           0 :       poly[1].y += startBevelOffset;
    3412           0 :       break;
    3413             :     case eSideLeft:
    3414           0 :       poly[0].y += startBevelOffset;
    3415             :     }
    3416             : 
    3417             :     Float endBevelOffset =
    3418           0 :       NSAppUnitsToFloatPixels(aEndBevelOffset, aAppUnitsPerDevPixel);
    3419           0 :     switch(aEndBevelSide) {
    3420             :     case eSideTop:
    3421           0 :       poly[1].x -= endBevelOffset;
    3422           0 :       break;
    3423             :     case eSideBottom:
    3424           0 :       poly[2].x -= endBevelOffset;
    3425           0 :       break;
    3426             :     case eSideRight:
    3427           0 :       poly[2].y -= endBevelOffset;
    3428           0 :       break;
    3429             :     case eSideLeft:
    3430           0 :       poly[3].y -= endBevelOffset;
    3431             :     }
    3432             : 
    3433           0 :     RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
    3434           0 :     builder->MoveTo(poly[0]);
    3435           0 :     builder->LineTo(poly[1]);
    3436           0 :     builder->LineTo(poly[2]);
    3437           0 :     builder->LineTo(poly[3]);
    3438           0 :     builder->Close();
    3439           0 :     RefPtr<Path> path = builder->Finish();
    3440           0 :     aDrawTarget.Fill(path, color, drawOptions);
    3441             :   }
    3442           0 : }
    3443             : 
    3444             : static void
    3445           0 : GetDashInfo(nscoord  aBorderLength,
    3446             :             nscoord  aDashLength,
    3447             :             nscoord  aTwipsPerPixel,
    3448             :             int32_t& aNumDashSpaces,
    3449             :             nscoord& aStartDashLength,
    3450             :             nscoord& aEndDashLength)
    3451             : {
    3452           0 :   aNumDashSpaces = 0;
    3453           0 :   if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
    3454           0 :     aStartDashLength = aBorderLength;
    3455           0 :     aEndDashLength = 0;
    3456             :   }
    3457             :   else {
    3458           0 :     aNumDashSpaces = (aBorderLength - aDashLength)/ (2 * aDashLength); // round down
    3459           0 :     nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
    3460           0 :     if (extra > 0) {
    3461           0 :       nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
    3462           0 :       aStartDashLength += half;
    3463           0 :       aEndDashLength += (extra - half);
    3464             :     }
    3465             :   }
    3466           0 : }
    3467             : 
    3468             : void
    3469           0 : nsCSSRendering::DrawTableBorderSegment(DrawTarget&   aDrawTarget,
    3470             :                                        uint8_t       aBorderStyle,
    3471             :                                        nscolor       aBorderColor,
    3472             :                                        nscolor       aBGColor,
    3473             :                                        const nsRect& aBorder,
    3474             :                                        int32_t       aAppUnitsPerDevPixel,
    3475             :                                        int32_t       aAppUnitsPerCSSPixel,
    3476             :                                        uint8_t       aStartBevelSide,
    3477             :                                        nscoord       aStartBevelOffset,
    3478             :                                        uint8_t       aEndBevelSide,
    3479             :                                        nscoord       aEndBevelOffset)
    3480             : {
    3481           0 :   bool horizontal = ((eSideTop == aStartBevelSide) || (eSideBottom == aStartBevelSide));
    3482           0 :   nscoord twipsPerPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerCSSPixel);
    3483           0 :   uint8_t ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
    3484             : 
    3485           0 :   if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
    3486           0 :       (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
    3487             :     // no beveling for 1 pixel border, dash or dot
    3488           0 :     aStartBevelOffset = 0;
    3489           0 :     aEndBevelOffset = 0;
    3490             :   }
    3491             : 
    3492           0 :   switch (aBorderStyle) {
    3493             :   case NS_STYLE_BORDER_STYLE_NONE:
    3494             :   case NS_STYLE_BORDER_STYLE_HIDDEN:
    3495             :     //NS_ASSERTION(false, "style of none or hidden");
    3496           0 :     break;
    3497             :   case NS_STYLE_BORDER_STYLE_DOTTED:
    3498             :   case NS_STYLE_BORDER_STYLE_DASHED:
    3499             :     {
    3500           0 :       nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
    3501             :       // make the dash length proportional to the border thickness
    3502           0 :       dashLength *= (horizontal) ? aBorder.height : aBorder.width;
    3503             :       // make the min dash length for the ends 1/2 the dash length
    3504             :       nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle)
    3505           0 :                               ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
    3506           0 :       minDashLength = std::max(minDashLength, twipsPerPixel);
    3507           0 :       nscoord numDashSpaces = 0;
    3508           0 :       nscoord startDashLength = minDashLength;
    3509           0 :       nscoord endDashLength   = minDashLength;
    3510           0 :       if (horizontal) {
    3511           0 :         GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces,
    3512           0 :                     startDashLength, endDashLength);
    3513           0 :         nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
    3514           0 :         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
    3515           0 :                                aAppUnitsPerDevPixel, twipsPerPixel);
    3516             : 
    3517           0 :         rect.x += startDashLength + dashLength;
    3518           0 :         rect.width = aBorder.width
    3519           0 :                      - (startDashLength + endDashLength + dashLength);
    3520           0 :         DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor,
    3521           0 :                           aAppUnitsPerDevPixel, twipsPerPixel, horizontal);
    3522             : 
    3523           0 :         rect.x += rect.width;
    3524           0 :         rect.width = endDashLength;
    3525           0 :         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
    3526           0 :                                aAppUnitsPerDevPixel, twipsPerPixel);
    3527             :       }
    3528             :       else {
    3529           0 :         GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces,
    3530           0 :                     startDashLength, endDashLength);
    3531           0 :         nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
    3532           0 :         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
    3533           0 :                                aAppUnitsPerDevPixel, twipsPerPixel);
    3534             : 
    3535           0 :         rect.y += rect.height + dashLength;
    3536           0 :         rect.height = aBorder.height
    3537           0 :                       - (startDashLength + endDashLength + dashLength);
    3538           0 :         DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor,
    3539           0 :                           aAppUnitsPerDevPixel, twipsPerPixel, horizontal);
    3540             : 
    3541           0 :         rect.y += rect.height;
    3542           0 :         rect.height = endDashLength;
    3543           0 :         DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
    3544           0 :                                aAppUnitsPerDevPixel, twipsPerPixel);
    3545             :       }
    3546             :     }
    3547           0 :     break;
    3548             :   case NS_STYLE_BORDER_STYLE_GROOVE:
    3549           0 :     ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
    3550             :     MOZ_FALLTHROUGH;
    3551             :   case NS_STYLE_BORDER_STYLE_RIDGE:
    3552           0 :     if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
    3553           0 :         (!horizontal && (twipsPerPixel >= aBorder.width))) {
    3554             :       // a one pixel border
    3555           0 :       DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor,
    3556             :                              aAppUnitsPerDevPixel, twipsPerPixel,
    3557             :                              aStartBevelSide, aStartBevelOffset,
    3558           0 :                              aEndBevelSide, aEndBevelOffset);
    3559             :     }
    3560             :     else {
    3561             :       nscoord startBevel = (aStartBevelOffset > 0)
    3562           0 :                             ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, true) : 0;
    3563             :       nscoord endBevel =   (aEndBevelOffset > 0)
    3564           0 :                             ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, true) : 0;
    3565           0 :       mozilla::Side ridgeGrooveSide = (horizontal) ? eSideTop : eSideLeft;
    3566             :       // FIXME: In theory, this should use the visited-dependent
    3567             :       // background color, but I don't care.
    3568           0 :       nscolor bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
    3569           0 :                                           aBGColor, aBorderColor);
    3570           0 :       nsRect rect(aBorder);
    3571             :       nscoord half;
    3572           0 :       if (horizontal) { // top, bottom
    3573           0 :         half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
    3574           0 :         rect.height = half;
    3575           0 :         if (eSideTop == aStartBevelSide) {
    3576           0 :           rect.x += startBevel;
    3577           0 :           rect.width -= startBevel;
    3578             :         }
    3579           0 :         if (eSideTop == aEndBevelSide) {
    3580           0 :           rect.width -= endBevel;
    3581             :         }
    3582           0 :         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
    3583             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3584             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3585           0 :                                endBevel);
    3586             :       }
    3587             :       else { // left, right
    3588           0 :         half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
    3589           0 :         rect.width = half;
    3590           0 :         if (eSideLeft == aStartBevelSide) {
    3591           0 :           rect.y += startBevel;
    3592           0 :           rect.height -= startBevel;
    3593             :         }
    3594           0 :         if (eSideLeft == aEndBevelSide) {
    3595           0 :           rect.height -= endBevel;
    3596             :         }
    3597           0 :         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
    3598             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3599             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3600           0 :                                endBevel);
    3601             :       }
    3602             : 
    3603           0 :       rect = aBorder;
    3604           0 :       ridgeGrooveSide = (eSideTop == ridgeGrooveSide) ? eSideBottom : eSideRight;
    3605             :       // FIXME: In theory, this should use the visited-dependent
    3606             :       // background color, but I don't care.
    3607           0 :       bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
    3608           0 :                                   aBGColor, aBorderColor);
    3609           0 :       if (horizontal) {
    3610           0 :         rect.y = rect.y + half;
    3611           0 :         rect.height = aBorder.height - half;
    3612           0 :         if (eSideBottom == aStartBevelSide) {
    3613           0 :           rect.x += startBevel;
    3614           0 :           rect.width -= startBevel;
    3615             :         }
    3616           0 :         if (eSideBottom == aEndBevelSide) {
    3617           0 :           rect.width -= endBevel;
    3618             :         }
    3619           0 :         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
    3620             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3621             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3622           0 :                                endBevel);
    3623             :       }
    3624             :       else {
    3625           0 :         rect.x = rect.x + half;
    3626           0 :         rect.width = aBorder.width - half;
    3627           0 :         if (eSideRight == aStartBevelSide) {
    3628           0 :           rect.y += aStartBevelOffset - startBevel;
    3629           0 :           rect.height -= startBevel;
    3630             :         }
    3631           0 :         if (eSideRight == aEndBevelSide) {
    3632           0 :           rect.height -= endBevel;
    3633             :         }
    3634           0 :         DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
    3635             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3636             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3637           0 :                                endBevel);
    3638             :       }
    3639             :     }
    3640           0 :     break;
    3641             :   case NS_STYLE_BORDER_STYLE_DOUBLE:
    3642             :     // We can only do "double" borders if the thickness of the border
    3643             :     // is more than 2px.  Otherwise, we fall through to painting a
    3644             :     // solid border.
    3645           0 :     if ((aBorder.width > 2*twipsPerPixel || horizontal) &&
    3646           0 :         (aBorder.height > 2*twipsPerPixel || !horizontal)) {
    3647             :       nscoord startBevel = (aStartBevelOffset > 0)
    3648           0 :                             ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
    3649             :       nscoord endBevel =   (aEndBevelOffset > 0)
    3650           0 :                             ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
    3651           0 :       if (horizontal) { // top, bottom
    3652           0 :         nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
    3653             : 
    3654             :         // draw the top line or rect
    3655           0 :         nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
    3656           0 :         if (eSideTop == aStartBevelSide) {
    3657           0 :           topRect.x += aStartBevelOffset - startBevel;
    3658           0 :           topRect.width -= aStartBevelOffset - startBevel;
    3659             :         }
    3660           0 :         if (eSideTop == aEndBevelSide) {
    3661           0 :           topRect.width -= aEndBevelOffset - endBevel;
    3662             :         }
    3663           0 :         DrawSolidBorderSegment(aDrawTarget, topRect, aBorderColor,
    3664             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3665             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3666           0 :                                endBevel);
    3667             : 
    3668             :         // draw the botom line or rect
    3669           0 :         nscoord heightOffset = aBorder.height - thirdHeight;
    3670           0 :         nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
    3671           0 :         if (eSideBottom == aStartBevelSide) {
    3672           0 :           bottomRect.x += aStartBevelOffset - startBevel;
    3673           0 :           bottomRect.width -= aStartBevelOffset - startBevel;
    3674             :         }
    3675           0 :         if (eSideBottom == aEndBevelSide) {
    3676           0 :           bottomRect.width -= aEndBevelOffset - endBevel;
    3677             :         }
    3678           0 :         DrawSolidBorderSegment(aDrawTarget, bottomRect, aBorderColor,
    3679             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3680             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3681           0 :                                endBevel);
    3682             :       }
    3683             :       else { // left, right
    3684           0 :         nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
    3685             : 
    3686           0 :         nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
    3687           0 :         if (eSideLeft == aStartBevelSide) {
    3688           0 :           leftRect.y += aStartBevelOffset - startBevel;
    3689           0 :           leftRect.height -= aStartBevelOffset - startBevel;
    3690             :         }
    3691           0 :         if (eSideLeft == aEndBevelSide) {
    3692           0 :           leftRect.height -= aEndBevelOffset - endBevel;
    3693             :         }
    3694           0 :         DrawSolidBorderSegment(aDrawTarget, leftRect, aBorderColor,
    3695             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3696             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3697           0 :                                endBevel);
    3698             : 
    3699           0 :         nscoord widthOffset = aBorder.width - thirdWidth;
    3700           0 :         nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
    3701           0 :         if (eSideRight == aStartBevelSide) {
    3702           0 :           rightRect.y += aStartBevelOffset - startBevel;
    3703           0 :           rightRect.height -= aStartBevelOffset - startBevel;
    3704             :         }
    3705           0 :         if (eSideRight == aEndBevelSide) {
    3706           0 :           rightRect.height -= aEndBevelOffset - endBevel;
    3707             :         }
    3708           0 :         DrawSolidBorderSegment(aDrawTarget, rightRect, aBorderColor,
    3709             :                                aAppUnitsPerDevPixel, twipsPerPixel,
    3710             :                                aStartBevelSide, startBevel, aEndBevelSide,
    3711           0 :                                endBevel);
    3712             :       }
    3713           0 :       break;
    3714             :     }
    3715             :     // else fall through to solid
    3716             :     MOZ_FALLTHROUGH;
    3717             :   case NS_STYLE_BORDER_STYLE_SOLID:
    3718           0 :     DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor,
    3719             :                            aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide,
    3720           0 :                            aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
    3721           0 :     break;
    3722             :   case NS_STYLE_BORDER_STYLE_OUTSET:
    3723             :   case NS_STYLE_BORDER_STYLE_INSET:
    3724           0 :     NS_ASSERTION(false, "inset, outset should have been converted to groove, ridge");
    3725           0 :     break;
    3726             :   case NS_STYLE_BORDER_STYLE_AUTO:
    3727           0 :     NS_ASSERTION(false, "Unexpected 'auto' table border");
    3728           0 :     break;
    3729             :   }
    3730           0 : }
    3731             : 
    3732             : // End table border-collapsing section
    3733             : 
    3734             : Rect
    3735           0 : nsCSSRendering::ExpandPaintingRectForDecorationLine(
    3736             :                   nsIFrame* aFrame,
    3737             :                   const uint8_t aStyle,
    3738             :                   const Rect& aClippedRect,
    3739             :                   const Float aICoordInFrame,
    3740             :                   const Float aCycleLength,
    3741             :                   bool aVertical)
    3742             : {
    3743           0 :   switch (aStyle) {
    3744             :     case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
    3745             :     case NS_STYLE_TEXT_DECORATION_STYLE_DASHED:
    3746             :     case NS_STYLE_TEXT_DECORATION_STYLE_WAVY:
    3747           0 :       break;
    3748             :     default:
    3749           0 :       NS_ERROR("Invalid style was specified");
    3750           0 :       return aClippedRect;
    3751             :   }
    3752             : 
    3753           0 :   nsBlockFrame* block = nullptr;
    3754             :   // Note that when we paint the decoration lines in relative positioned
    3755             :   // box, we should paint them like all of the boxes are positioned as static.
    3756           0 :   nscoord framePosInBlockAppUnits = 0;
    3757           0 :   for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
    3758           0 :     block = do_QueryFrame(f);
    3759           0 :     if (block) {
    3760           0 :       break;
    3761             :     }
    3762           0 :     framePosInBlockAppUnits += aVertical ?
    3763           0 :       f->GetNormalPosition().y : f->GetNormalPosition().x;
    3764             :   }
    3765             : 
    3766           0 :   NS_ENSURE_TRUE(block, aClippedRect);
    3767             : 
    3768           0 :   nsPresContext *pc = aFrame->PresContext();
    3769           0 :   Float framePosInBlock = Float(pc->AppUnitsToGfxUnits(framePosInBlockAppUnits));
    3770             :   int32_t rectPosInBlock =
    3771           0 :     int32_t(NS_round(framePosInBlock + aICoordInFrame));
    3772             :   int32_t extraStartEdge =
    3773           0 :     rectPosInBlock - (rectPosInBlock / int32_t(aCycleLength) * aCycleLength);
    3774           0 :   Rect rect(aClippedRect);
    3775           0 :   if (aVertical) {
    3776           0 :     rect.y -= extraStartEdge;
    3777           0 :     rect.height += extraStartEdge;
    3778             :   } else {
    3779           0 :     rect.x -= extraStartEdge;
    3780           0 :     rect.width += extraStartEdge;
    3781             :   }
    3782           0 :   return rect;
    3783             : }
    3784             : 
    3785             : void
    3786           0 : nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame, DrawTarget& aDrawTarget,
    3787             :                                     const PaintDecorationLineParams& aParams)
    3788             : {
    3789           0 :   NS_ASSERTION(aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_NONE,
    3790             :                "aStyle is none");
    3791             : 
    3792           0 :   Rect rect = ToRect(GetTextDecorationRectInternal(aParams.pt, aParams));
    3793           0 :   if (rect.IsEmpty() || !rect.Intersects(aParams.dirtyRect)) {
    3794           0 :     return;
    3795             :   }
    3796             : 
    3797           0 :   if (aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE &&
    3798           0 :       aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_OVERLINE &&
    3799           0 :       aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
    3800           0 :     NS_ERROR("Invalid decoration value!");
    3801           0 :     return;
    3802             :   }
    3803             : 
    3804           0 :   Float lineThickness = std::max(NS_round(aParams.lineSize.height), 1.0);
    3805             : 
    3806           0 :   ColorPattern color(ToDeviceColor(aParams.color));
    3807           0 :   StrokeOptions strokeOptions(lineThickness);
    3808           0 :   DrawOptions drawOptions;
    3809             : 
    3810             :   Float dash[2];
    3811             : 
    3812           0 :   AutoPopClips autoPopClips(&aDrawTarget);
    3813             : 
    3814           0 :   switch (aParams.style) {
    3815             :     case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
    3816             :     case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE:
    3817           0 :       break;
    3818             :     case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: {
    3819           0 :       autoPopClips.PushClipRect(rect);
    3820           0 :       Float dashWidth = lineThickness * DOT_LENGTH * DASH_LENGTH;
    3821           0 :       dash[0] = dashWidth;
    3822           0 :       dash[1] = dashWidth;
    3823           0 :       strokeOptions.mDashPattern = dash;
    3824           0 :       strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
    3825           0 :       strokeOptions.mLineCap = CapStyle::BUTT;
    3826           0 :       rect = ExpandPaintingRectForDecorationLine(aFrame, aParams.style,
    3827           0 :                                                  rect, aParams.icoordInFrame,
    3828             :                                                  dashWidth * 2,
    3829           0 :                                                  aParams.vertical);
    3830             :       // We should continue to draw the last dash even if it is not in the rect.
    3831           0 :       rect.width += dashWidth;
    3832           0 :       break;
    3833             :     }
    3834             :     case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED: {
    3835           0 :       autoPopClips.PushClipRect(rect);
    3836           0 :       Float dashWidth = lineThickness * DOT_LENGTH;
    3837           0 :       if (lineThickness > 2.0) {
    3838           0 :         dash[0] = 0.f;
    3839           0 :         dash[1] = dashWidth * 2.f;
    3840           0 :         strokeOptions.mLineCap = CapStyle::ROUND;
    3841             :       } else {
    3842           0 :         dash[0] = dashWidth;
    3843           0 :         dash[1] = dashWidth;
    3844             :       }
    3845           0 :       strokeOptions.mDashPattern = dash;
    3846           0 :       strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
    3847           0 :       rect = ExpandPaintingRectForDecorationLine(aFrame, aParams.style,
    3848           0 :                                                  rect, aParams.icoordInFrame,
    3849             :                                                  dashWidth * 2,
    3850           0 :                                                  aParams.vertical);
    3851             :       // We should continue to draw the last dot even if it is not in the rect.
    3852           0 :       rect.width += dashWidth;
    3853           0 :       break;
    3854             :     }
    3855             :     case NS_STYLE_TEXT_DECORATION_STYLE_WAVY:
    3856           0 :       autoPopClips.PushClipRect(rect);
    3857           0 :       if (lineThickness > 2.0) {
    3858           0 :         drawOptions.mAntialiasMode = AntialiasMode::SUBPIXEL;
    3859             :       } else {
    3860             :         // Don't use anti-aliasing here.  Because looks like lighter color wavy
    3861             :         // line at this case.  And probably, users don't think the
    3862             :         // non-anti-aliased wavy line is not pretty.
    3863           0 :         drawOptions.mAntialiasMode = AntialiasMode::NONE;
    3864             :       }
    3865           0 :       break;
    3866             :     default:
    3867           0 :       NS_ERROR("Invalid style value!");
    3868           0 :       return;
    3869             :   }
    3870             : 
    3871             :   // The block-direction position should be set to the middle of the line.
    3872           0 :   if (aParams.vertical) {
    3873           0 :     rect.x += lineThickness / 2;
    3874             :   } else {
    3875           0 :     rect.y += lineThickness / 2;
    3876             :   }
    3877             : 
    3878           0 :   switch (aParams.style) {
    3879             :     case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
    3880             :     case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
    3881             :     case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: {
    3882           0 :       Point p1 = rect.TopLeft();
    3883           0 :       Point p2 = aParams.vertical ? rect.BottomLeft() : rect.TopRight();
    3884           0 :       aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
    3885           0 :       return;
    3886             :     }
    3887             :     case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE: {
    3888             :       /**
    3889             :        *  We are drawing double line as:
    3890             :        *
    3891             :        * +-------------------------------------------+
    3892             :        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
    3893             :        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
    3894             :        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
    3895             :        * |                                           |
    3896             :        * |                                           |
    3897             :        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
    3898             :        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
    3899             :        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
    3900             :        * +-------------------------------------------+
    3901             :        */
    3902           0 :       Point p1 = rect.TopLeft();
    3903           0 :       Point p2 = aParams.vertical ? rect.BottomLeft() : rect.TopRight();
    3904           0 :       aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
    3905             : 
    3906           0 :       if (aParams.vertical) {
    3907           0 :         rect.width -= lineThickness;
    3908             :       } else {
    3909           0 :         rect.height -= lineThickness;
    3910             :       }
    3911             : 
    3912           0 :       p1 = aParams.vertical ? rect.TopRight() : rect.BottomLeft();
    3913           0 :       p2 = rect.BottomRight();
    3914           0 :       aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
    3915           0 :       return;
    3916             :     }
    3917             :     case NS_STYLE_TEXT_DECORATION_STYLE_WAVY: {
    3918             :       /**
    3919             :        *  We are drawing wavy line as:
    3920             :        *
    3921             :        *  P: Path, X: Painted pixel
    3922             :        *
    3923             :        *     +---------------------------------------+
    3924             :        *   XX|X            XXXXXX            XXXXXX  |
    3925             :        *   PP|PX          XPPPPPPX          XPPPPPPX |    ^
    3926             :        *   XX|XPX        XPXXXXXXPX        XPXXXXXXPX|    |
    3927             :        *     | XPX      XPX      XPX      XPX      XP|X   |adv
    3928             :        *     |  XPXXXXXXPX        XPXXXXXXPX        X|PX  |
    3929             :        *     |   XPPPPPPX          XPPPPPPX          |XPX v
    3930             :        *     |    XXXXXX            XXXXXX           | XX
    3931             :        *     +---------------------------------------+
    3932             :        *      <---><--->                                ^
    3933             :        *      adv  flatLengthAtVertex                   rightMost
    3934             :        *
    3935             :        *  1. Always starts from top-left of the drawing area, however, we need
    3936             :        *     to draw  the line from outside of the rect.  Because the start
    3937             :        *     point of the line is not good style if we draw from inside it.
    3938             :        *  2. First, draw horizontal line from outside the rect to top-left of
    3939             :        *     the rect;
    3940             :        *  3. Goes down to bottom of the area at 45 degrees.
    3941             :        *  4. Slides to right horizontaly, see |flatLengthAtVertex|.
    3942             :        *  5. Goes up to top of the area at 45 degrees.
    3943             :        *  6. Slides to right horizontaly.
    3944             :        *  7. Repeat from 2 until reached to right-most edge of the area.
    3945             :        *
    3946             :        * In the vertical case, swap horizontal and vertical coordinates and
    3947             :        * directions in the above description.
    3948             :        */
    3949             : 
    3950           0 :       Float& rectICoord = aParams.vertical ? rect.y : rect.x;
    3951           0 :       Float& rectISize = aParams.vertical ? rect.height : rect.width;
    3952           0 :       const Float rectBSize = aParams.vertical ? rect.width : rect.height;
    3953             : 
    3954           0 :       const Float adv = rectBSize - lineThickness;
    3955             :       const Float flatLengthAtVertex =
    3956           0 :         std::max((lineThickness - 1.0) * 2.0, 1.0);
    3957             : 
    3958             :       // Align the start of wavy lines to the nearest ancestor block.
    3959           0 :       const Float cycleLength = 2 * (adv + flatLengthAtVertex);
    3960           0 :       rect = ExpandPaintingRectForDecorationLine(aFrame, aParams.style, rect,
    3961           0 :                                                  aParams.icoordInFrame,
    3962           0 :                                                  cycleLength, aParams.vertical);
    3963             :       // figure out if we can trim whole cycles from the left and right edges
    3964             :       // of the line, to try and avoid creating an unnecessarily long and
    3965             :       // complex path
    3966           0 :       const Float dirtyRectICoord = aParams.vertical ? aParams.dirtyRect.y
    3967           0 :                                                      : aParams.dirtyRect.x;
    3968           0 :       int32_t skipCycles = floor((dirtyRectICoord - rectICoord) / cycleLength);
    3969           0 :       if (skipCycles > 0) {
    3970           0 :         rectICoord += skipCycles * cycleLength;
    3971           0 :         rectISize -= skipCycles * cycleLength;
    3972             :       }
    3973             : 
    3974           0 :       rectICoord += lineThickness / 2.0;
    3975           0 :       Point pt(rect.TopLeft());
    3976           0 :       Float& ptICoord = aParams.vertical ? pt.y : pt.x;
    3977           0 :       Float& ptBCoord = aParams.vertical ? pt.x : pt.y;
    3978           0 :       if (aParams.vertical) {
    3979           0 :         ptBCoord += adv + lineThickness / 2.0;
    3980             :       }
    3981           0 :       Float iCoordLimit = ptICoord + rectISize + lineThickness;
    3982             : 
    3983           0 :       const Float dirtyRectIMost = aParams.vertical ?
    3984           0 :         aParams.dirtyRect.YMost() : aParams.dirtyRect.XMost();
    3985           0 :       skipCycles = floor((iCoordLimit - dirtyRectIMost) / cycleLength);
    3986           0 :       if (skipCycles > 0) {
    3987           0 :         iCoordLimit -= skipCycles * cycleLength;
    3988             :       }
    3989             : 
    3990           0 :       RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
    3991           0 :       RefPtr<Path> path;
    3992             : 
    3993           0 :       ptICoord -= lineThickness;
    3994           0 :       builder->MoveTo(pt); // 1
    3995             : 
    3996           0 :       ptICoord = rectICoord;
    3997           0 :       builder->LineTo(pt); // 2
    3998             : 
    3999             :       // In vertical mode, to go "down" relative to the text we need to
    4000             :       // decrease the block coordinate, whereas in horizontal we increase
    4001             :       // it. So the sense of this flag is effectively inverted.
    4002           0 :       bool goDown = aParams.vertical ? false : true;
    4003           0 :       uint32_t iter = 0;
    4004           0 :       while (ptICoord < iCoordLimit) {
    4005           0 :         if (++iter > 1000) {
    4006             :           // stroke the current path and start again, to avoid pathological
    4007             :           // behavior in cairo with huge numbers of path segments
    4008           0 :           path = builder->Finish();
    4009           0 :           aDrawTarget.Stroke(path, color, strokeOptions, drawOptions);
    4010           0 :           builder = aDrawTarget.CreatePathBuilder();
    4011           0 :           builder->MoveTo(pt);
    4012           0 :           iter = 0;
    4013             :         }
    4014           0 :         ptICoord += adv;
    4015           0 :         ptBCoord += goDown ? adv : -adv;
    4016             : 
    4017           0 :         builder->LineTo(pt); // 3 and 5
    4018             : 
    4019           0 :         ptICoord += flatLengthAtVertex;
    4020           0 :         builder->LineTo(pt); // 4 and 6
    4021             : 
    4022           0 :         goDown = !goDown;
    4023             :       }
    4024           0 :       path = builder->Finish();
    4025           0 :       aDrawTarget.Stroke(path, color, strokeOptions, drawOptions);
    4026           0 :       return;
    4027             :     }
    4028             :     default:
    4029           0 :       NS_ERROR("Invalid style value!");
    4030             :   }
    4031             : }
    4032             : 
    4033             : Rect
    4034           0 : nsCSSRendering::DecorationLineToPath(const PaintDecorationLineParams& aParams)
    4035             : {
    4036           0 :   NS_ASSERTION(aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_NONE,
    4037             :                "aStyle is none");
    4038             : 
    4039           0 :   Rect path; // To benefit from RVO, we return this from all return points
    4040             : 
    4041           0 :   Rect rect = ToRect(GetTextDecorationRectInternal(aParams.pt, aParams));
    4042           0 :   if (rect.IsEmpty() || !rect.Intersects(aParams.dirtyRect)) {
    4043           0 :     return path;
    4044             :   }
    4045             : 
    4046           0 :   if (aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE &&
    4047           0 :       aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_OVERLINE &&
    4048           0 :       aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
    4049           0 :     NS_ERROR("Invalid decoration value!");
    4050           0 :     return path;
    4051             :   }
    4052             : 
    4053           0 :   if (aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
    4054             :     // For the moment, we support only solid text decorations.
    4055           0 :     return path;
    4056             :   }
    4057             : 
    4058           0 :   Float lineThickness = std::max(NS_round(aParams.lineSize.height), 1.0);
    4059             : 
    4060             :   // The block-direction position should be set to the middle of the line.
    4061           0 :   if (aParams.vertical) {
    4062           0 :     rect.x += lineThickness / 2;
    4063           0 :     path = Rect(rect.TopLeft() - Point(lineThickness / 2, 0.0),
    4064           0 :                 Size(lineThickness, rect.Height()));
    4065             :   } else {
    4066           0 :     rect.y += lineThickness / 2;
    4067           0 :     path = Rect(rect.TopLeft() - Point(0.0, lineThickness / 2),
    4068           0 :                 Size(rect.Width(), lineThickness));
    4069             :   }
    4070             : 
    4071           0 :   return path;
    4072             : }
    4073             : 
    4074             : nsRect
    4075           0 : nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext,
    4076             :                                       const DecorationRectParams& aParams)
    4077             : {
    4078           0 :   NS_ASSERTION(aPresContext, "aPresContext is null");
    4079           0 :   NS_ASSERTION(aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_NONE,
    4080             :                "aStyle is none");
    4081             : 
    4082           0 :   gfxRect rect = GetTextDecorationRectInternal(Point(0, 0), aParams);
    4083             :   // The rect values are already rounded to nearest device pixels.
    4084           0 :   nsRect r;
    4085           0 :   r.x = aPresContext->GfxUnitsToAppUnits(rect.X());
    4086           0 :   r.y = aPresContext->GfxUnitsToAppUnits(rect.Y());
    4087           0 :   r.width = aPresContext->GfxUnitsToAppUnits(rect.Width());
    4088           0 :   r.height = aPresContext->GfxUnitsToAppUnits(rect.Height());
    4089           0 :   return r;
    4090             : }
    4091             : 
    4092             : gfxRect
    4093           0 : nsCSSRendering::GetTextDecorationRectInternal(const Point& aPt,
    4094             :                                               const DecorationRectParams& aParams)
    4095             : {
    4096           0 :   NS_ASSERTION(aParams.style <= NS_STYLE_TEXT_DECORATION_STYLE_WAVY,
    4097             :                "Invalid aStyle value");
    4098             : 
    4099           0 :   if (aParams.style == NS_STYLE_TEXT_DECORATION_STYLE_NONE)
    4100           0 :     return gfxRect(0, 0, 0, 0);
    4101             : 
    4102           0 :   bool canLiftUnderline = aParams.descentLimit >= 0.0;
    4103             : 
    4104           0 :   gfxFloat iCoord = aParams.vertical ? aPt.y : aPt.x;
    4105           0 :   gfxFloat bCoord = aParams.vertical ? aPt.x : aPt.y;
    4106             : 
    4107             :   // 'left' and 'right' are relative to the line, so for vertical writing modes
    4108             :   // they will actually become top and bottom of the rendered line.
    4109             :   // Similarly, aLineSize.width and .height are actually length and thickness
    4110             :   // of the line, which runs horizontally or vertically according to aVertical.
    4111           0 :   const gfxFloat left  = floor(iCoord + 0.5),
    4112           0 :                  right = floor(iCoord + aParams.lineSize.width + 0.5);
    4113             : 
    4114             :   // We compute |r| as if for a horizontal text run, and then swap vertical
    4115             :   // and horizontal coordinates at the end if vertical was requested.
    4116           0 :   gfxRect r(left, 0, right - left, 0);
    4117             : 
    4118           0 :   gfxFloat lineThickness = NS_round(aParams.lineSize.height);
    4119           0 :   lineThickness = std::max(lineThickness, 1.0);
    4120             : 
    4121           0 :   gfxFloat ascent = NS_round(aParams.ascent);
    4122           0 :   gfxFloat descentLimit = floor(aParams.descentLimit);
    4123             : 
    4124           0 :   gfxFloat suggestedMaxRectHeight = std::max(std::min(ascent, descentLimit), 1.0);
    4125           0 :   r.height = lineThickness;
    4126           0 :   if (aParams.style == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE) {
    4127             :     /**
    4128             :      *  We will draw double line as:
    4129             :      *
    4130             :      * +-------------------------------------------+
    4131             :      * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
    4132             :      * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
    4133             :      * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
    4134             :      * |                                           | ^
    4135             :      * |                                           | | gap
    4136             :      * |                                           | v
    4137             :      * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
    4138             :      * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
    4139             :      * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
    4140             :      * +-------------------------------------------+
    4141             :      */
    4142           0 :     gfxFloat gap = NS_round(lineThickness / 2.0);
    4143           0 :     gap = std::max(gap, 1.0);
    4144           0 :     r.height = lineThickness * 2.0 + gap;
    4145           0 :     if (canLiftUnderline) {
    4146           0 :       if (r.Height() > suggestedMaxRectHeight) {
    4147             :         // Don't shrink the line height, because the thickness has some meaning.
    4148             :         // We can just shrink the gap at this time.
    4149           0 :         r.height = std::max(suggestedMaxRectHeight, lineThickness * 2.0 + 1.0);
    4150             :       }
    4151             :     }
    4152           0 :   } else if (aParams.style == NS_STYLE_TEXT_DECORATION_STYLE_WAVY) {
    4153             :     /**
    4154             :      *  We will draw wavy line as:
    4155             :      *
    4156             :      * +-------------------------------------------+
    4157             :      * |XXXXX            XXXXXX            XXXXXX  | ^
    4158             :      * |XXXXXX          XXXXXXXX          XXXXXXXX | | lineThickness
    4159             :      * |XXXXXXX        XXXXXXXXXX        XXXXXXXXXX| v
    4160             :      * |     XXX      XXX      XXX      XXX      XX|
    4161             :      * |      XXXXXXXXXX        XXXXXXXXXX        X|
    4162             :      * |       XXXXXXXX          XXXXXXXX          |
    4163             :      * |        XXXXXX            XXXXXX           |
    4164             :      * +-------------------------------------------+
    4165             :      */
    4166           0 :     r.height = lineThickness > 2.0 ? lineThickness * 4.0 : lineThickness * 3.0;
    4167           0 :     if (canLiftUnderline) {
    4168           0 :       if (r.Height() > suggestedMaxRectHeight) {
    4169             :         // Don't shrink the line height even if there is not enough space,
    4170             :         // because the thickness has some meaning.  E.g., the 1px wavy line and
    4171             :         // 2px wavy line can be used for different meaning in IME selections
    4172             :         // at same time.
    4173           0 :         r.height = std::max(suggestedMaxRectHeight, lineThickness * 2.0);
    4174             :       }
    4175             :     }
    4176             :   }
    4177             : 
    4178           0 :   gfxFloat baseline = floor(bCoord + aParams.ascent + 0.5);
    4179           0 :   gfxFloat offset = 0.0;
    4180           0 :   switch (aParams.decoration) {
    4181             :     case NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE:
    4182           0 :       offset = aParams.offset;
    4183           0 :       if (canLiftUnderline) {
    4184           0 :         if (descentLimit < -offset + r.Height()) {
    4185             :           // If we can ignore the offset and the decoration line is overflowing,
    4186             :           // we should align the bottom edge of the decoration line rect if it's
    4187             :           // possible.  Otherwise, we should lift up the top edge of the rect as
    4188             :           // far as possible.
    4189           0 :           gfxFloat offsetBottomAligned = -descentLimit + r.Height();
    4190           0 :           gfxFloat offsetTopAligned = 0.0;
    4191           0 :           offset = std::min(offsetBottomAligned, offsetTopAligned);
    4192             :         }
    4193             :       }
    4194           0 :       break;
    4195             :     case NS_STYLE_TEXT_DECORATION_LINE_OVERLINE:
    4196           0 :       offset = aParams.offset - lineThickness + r.Height();
    4197           0 :       break;
    4198             :     case NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH: {
    4199           0 :       gfxFloat extra = floor(r.Height() / 2.0 + 0.5);
    4200           0 :       extra = std::max(extra, lineThickness);
    4201           0 :       offset = aParams.offset - lineThickness + extra;
    4202           0 :       break;
    4203             :     }
    4204             :     default:
    4205           0 :       NS_ERROR("Invalid decoration value!");
    4206             :   }
    4207             : 
    4208           0 :   if (aParams.vertical) {
    4209           0 :     r.y = baseline + floor(offset + 0.5);
    4210           0 :     Swap(r.x, r.y);
    4211           0 :     Swap(r.width, r.height);
    4212             :   } else {
    4213           0 :     r.y = baseline - floor(offset + 0.5);
    4214             :   }
    4215             : 
    4216           0 :   return r;
    4217             : }
    4218             : 
    4219             : #define MAX_BLUR_RADIUS 300
    4220             : #define MAX_SPREAD_RADIUS 50
    4221             : 
    4222         102 : static inline gfxPoint ComputeBlurStdDev(nscoord aBlurRadius,
    4223             :                                          int32_t aAppUnitsPerDevPixel,
    4224             :                                          gfxFloat aScaleX,
    4225             :                                          gfxFloat aScaleY)
    4226             : {
    4227             :   // http://dev.w3.org/csswg/css3-background/#box-shadow says that the
    4228             :   // standard deviation of the blur should be half the given blur value.
    4229         102 :   gfxFloat blurStdDev = gfxFloat(aBlurRadius) / gfxFloat(aAppUnitsPerDevPixel);
    4230             : 
    4231         408 :   return gfxPoint(std::min((blurStdDev * aScaleX),
    4232         306 :                            gfxFloat(MAX_BLUR_RADIUS)) / 2.0,
    4233         306 :                   std::min((blurStdDev * aScaleY),
    4234         408 :                            gfxFloat(MAX_BLUR_RADIUS)) / 2.0);
    4235             : }
    4236             : 
    4237             : static inline IntSize
    4238          93 : ComputeBlurRadius(nscoord aBlurRadius,
    4239             :                   int32_t aAppUnitsPerDevPixel,
    4240             :                   gfxFloat aScaleX = 1.0,
    4241             :                   gfxFloat aScaleY = 1.0)
    4242             : {
    4243             :   gfxPoint scaledBlurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel,
    4244          93 :                                                 aScaleX, aScaleY);
    4245             :   return
    4246          93 :     gfxAlphaBoxBlur::CalculateBlurRadius(scaledBlurStdDev);
    4247             : }
    4248             : 
    4249             : // -----
    4250             : // nsContextBoxBlur
    4251             : // -----
    4252             : gfxContext*
    4253           0 : nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
    4254             :                        nscoord aBlurRadius,
    4255             :                        int32_t aAppUnitsPerDevPixel,
    4256             :                        gfxContext* aDestinationCtx,
    4257             :                        const nsRect& aDirtyRect,
    4258             :                        const gfxRect* aSkipRect,
    4259             :                        uint32_t aFlags)
    4260             : {
    4261           0 :   if (aRect.IsEmpty()) {
    4262           0 :     mContext = nullptr;
    4263           0 :     return nullptr;
    4264             :   }
    4265             : 
    4266           0 :   IntSize blurRadius;
    4267           0 :   IntSize spreadRadius;
    4268           0 :   GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(), aAppUnitsPerDevPixel,
    4269             :                          aBlurRadius, aSpreadRadius,
    4270           0 :                          blurRadius, spreadRadius);
    4271             : 
    4272           0 :   mDestinationCtx = aDestinationCtx;
    4273             : 
    4274             :   // If not blurring, draw directly onto the destination device
    4275           0 :   if (blurRadius.width <= 0 && blurRadius.height <= 0 &&
    4276           0 :       spreadRadius.width <= 0 && spreadRadius.height <= 0 &&
    4277           0 :       !(aFlags & FORCE_MASK)) {
    4278           0 :     mContext = aDestinationCtx;
    4279           0 :     return mContext;
    4280             :   }
    4281             : 
    4282             :   // Convert from app units to device pixels
    4283           0 :   gfxRect rect = nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
    4284             : 
    4285             :   gfxRect dirtyRect =
    4286           0 :     nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
    4287           0 :   dirtyRect.RoundOut();
    4288             : 
    4289           0 :   gfxMatrix transform = aDestinationCtx->CurrentMatrix();
    4290           0 :   rect = transform.TransformBounds(rect);
    4291             : 
    4292           0 :   mPreTransformed = !transform.IsIdentity();
    4293             : 
    4294             :   // Create the temporary surface for blurring
    4295           0 :   dirtyRect = transform.TransformBounds(dirtyRect);
    4296           0 :   if (aSkipRect) {
    4297           0 :     gfxRect skipRect = transform.TransformBounds(*aSkipRect);
    4298           0 :     mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
    4299           0 :                                   blurRadius, &dirtyRect, &skipRect);
    4300             :   } else {
    4301           0 :     mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
    4302           0 :                                   blurRadius, &dirtyRect, nullptr);
    4303             :   }
    4304             : 
    4305           0 :   if (mContext) {
    4306             :     // we don't need to blur if skipRect is equal to rect
    4307             :     // and mContext will be nullptr
    4308           0 :     mContext->Multiply(transform);
    4309             :   }
    4310           0 :   return mContext;
    4311             : }
    4312             : 
    4313             : void
    4314           0 : nsContextBoxBlur::DoPaint()
    4315             : {
    4316           0 :   if (mContext == mDestinationCtx) {
    4317           0 :     return;
    4318             :   }
    4319             : 
    4320           0 :   gfxContextMatrixAutoSaveRestore saveMatrix(mDestinationCtx);
    4321             : 
    4322           0 :   if (mPreTransformed) {
    4323           0 :     mDestinationCtx->SetMatrix(gfxMatrix());
    4324             :   }
    4325             : 
    4326           0 :   mAlphaBoxBlur.Paint(mDestinationCtx);
    4327             : }
    4328             : 
    4329             : gfxContext*
    4330           0 : nsContextBoxBlur::GetContext()
    4331             : {
    4332           0 :   return mContext;
    4333             : }
    4334             : 
    4335             : /* static */ nsMargin
    4336          83 : nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
    4337             :                                       int32_t aAppUnitsPerDevPixel)
    4338             : {
    4339          83 :   IntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel);
    4340             : 
    4341          83 :   nsMargin result;
    4342          83 :   result.top = result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
    4343          83 :   result.left = result.right = blurRadius.width  * aAppUnitsPerDevPixel;
    4344          83 :   return result;
    4345             : }
    4346             : 
    4347             : /* static */ void
    4348           9 : nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
    4349             :                                 const nsRect& aRect,
    4350             :                                 int32_t aAppUnitsPerDevPixel,
    4351             :                                 RectCornerRadii* aCornerRadii,
    4352             :                                 nscoord aBlurRadius,
    4353             :                                 const Color& aShadowColor,
    4354             :                                 const nsRect& aDirtyRect,
    4355             :                                 const gfxRect& aSkipRect)
    4356             : {
    4357           9 :   DrawTarget& aDestDrawTarget = *aDestinationCtx->GetDrawTarget();
    4358             : 
    4359           9 :   if (aRect.IsEmpty()) {
    4360           0 :     return;
    4361             :   }
    4362             : 
    4363           9 :   Rect shadowGfxRect = NSRectToRect(aRect, aAppUnitsPerDevPixel);
    4364             : 
    4365           9 :   if (aBlurRadius <= 0) {
    4366           0 :     ColorPattern color(ToDeviceColor(aShadowColor));
    4367           0 :     if (aCornerRadii) {
    4368           0 :       RefPtr<Path> roundedRect = MakePathForRoundedRect(aDestDrawTarget,
    4369             :                                                         shadowGfxRect,
    4370           0 :                                                         *aCornerRadii);
    4371           0 :       aDestDrawTarget.Fill(roundedRect, color);
    4372             :     } else {
    4373           0 :       aDestDrawTarget.FillRect(shadowGfxRect, color);
    4374             :     }
    4375           0 :     return;
    4376             :   }
    4377             : 
    4378           9 :   gfxFloat scaleX = 1;
    4379           9 :   gfxFloat scaleY = 1;
    4380             : 
    4381             :   // Do blurs in device space when possible.
    4382             :   // Chrome/Skia always does the blurs in device space
    4383             :   // and will sometimes get incorrect results (e.g. rotated blurs)
    4384           9 :   gfxMatrix transform = aDestinationCtx->CurrentMatrix();
    4385             :   // XXX: we could probably handle negative scales but for now it's easier just to fallback
    4386           9 :   if (!transform.HasNonAxisAlignedTransform() && transform._11 > 0.0 && transform._22 > 0.0) {
    4387           9 :     scaleX = transform._11;
    4388           9 :     scaleY = transform._22;
    4389           9 :     aDestinationCtx->SetMatrix(gfxMatrix());
    4390             :   } else {
    4391           0 :     transform = gfxMatrix();
    4392             :   }
    4393             : 
    4394           9 :   gfxPoint blurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
    4395             : 
    4396             :   gfxRect dirtyRect =
    4397           9 :     nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
    4398           9 :   dirtyRect.RoundOut();
    4399             : 
    4400           9 :   gfxRect shadowThebesRect = transform.TransformBounds(ThebesRect(shadowGfxRect));
    4401           9 :   dirtyRect = transform.TransformBounds(dirtyRect);
    4402           9 :   gfxRect skipRect = transform.TransformBounds(aSkipRect);
    4403             : 
    4404           9 :   if (aCornerRadii) {
    4405           9 :     aCornerRadii->Scale(scaleX, scaleY);
    4406             :   }
    4407             : 
    4408             :   gfxAlphaBoxBlur::BlurRectangle(aDestinationCtx,
    4409             :                                  shadowThebesRect,
    4410             :                                  aCornerRadii,
    4411             :                                  blurStdDev,
    4412             :                                  aShadowColor,
    4413             :                                  dirtyRect,
    4414           9 :                                  skipRect);
    4415             : }
    4416             : 
    4417             : /* static */ void
    4418          10 : nsContextBoxBlur::GetBlurAndSpreadRadius(DrawTarget* aDestDrawTarget,
    4419             :                                          int32_t aAppUnitsPerDevPixel,
    4420             :                                          nscoord aBlurRadius,
    4421             :                                          nscoord aSpreadRadius,
    4422             :                                          IntSize& aOutBlurRadius,
    4423             :                                          IntSize& aOutSpreadRadius,
    4424             :                                          bool aConstrainSpreadRadius)
    4425             : {
    4426             :   // Do blurs in device space when possible.
    4427             :   // Chrome/Skia always does the blurs in device space
    4428             :   // and will sometimes get incorrect results (e.g. rotated blurs)
    4429          10 :   Matrix transform = aDestDrawTarget->GetTransform();
    4430             :   // XXX: we could probably handle negative scales but for now it's easier just to fallback
    4431             :   gfxFloat scaleX, scaleY;
    4432          10 :   if (transform.HasNonAxisAlignedTransform() || transform._11 <= 0.0 || transform._22 <= 0.0) {
    4433           0 :     scaleX = 1;
    4434           0 :     scaleY = 1;
    4435             :   } else {
    4436          10 :     scaleX = transform._11;
    4437          10 :     scaleY = transform._22;
    4438             :   }
    4439             : 
    4440             :   // compute a large or smaller blur radius
    4441          10 :   aOutBlurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
    4442          10 :   aOutSpreadRadius =
    4443          20 :       IntSize(int32_t(aSpreadRadius * scaleX / aAppUnitsPerDevPixel),
    4444          10 :               int32_t(aSpreadRadius * scaleY / aAppUnitsPerDevPixel));
    4445             : 
    4446             : 
    4447          10 :   if (aConstrainSpreadRadius) {
    4448           0 :     aOutSpreadRadius.width = std::min(aOutSpreadRadius.width, int32_t(MAX_SPREAD_RADIUS));
    4449           0 :     aOutSpreadRadius.height = std::min(aOutSpreadRadius.height, int32_t(MAX_SPREAD_RADIUS));
    4450             :   }
    4451          10 : }
    4452             : 
    4453             : /* static */ bool
    4454          10 : nsContextBoxBlur::InsetBoxBlur(gfxContext* aDestinationCtx,
    4455             :                                Rect aDestinationRect,
    4456             :                                Rect aShadowClipRect,
    4457             :                                Color& aShadowColor,
    4458             :                                nscoord aBlurRadiusAppUnits,
    4459             :                                nscoord aSpreadDistanceAppUnits,
    4460             :                                int32_t aAppUnitsPerDevPixel,
    4461             :                                bool aHasBorderRadius,
    4462             :                                RectCornerRadii& aInnerClipRectRadii,
    4463             :                                Rect aSkipRect, Point aShadowOffset)
    4464             : {
    4465          10 :   if (aDestinationRect.IsEmpty()) {
    4466           0 :     mContext = nullptr;
    4467           0 :     return false;
    4468             :   }
    4469             : 
    4470          20 :   gfxContextAutoSaveRestore autoRestore(aDestinationCtx);
    4471             : 
    4472          10 :   IntSize blurRadius;
    4473          10 :   IntSize spreadRadius;
    4474             :   // Convert the blur and spread radius to device pixels
    4475          10 :   bool constrainSpreadRadius = false;
    4476          10 :   GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(), aAppUnitsPerDevPixel,
    4477             :                          aBlurRadiusAppUnits, aSpreadDistanceAppUnits,
    4478          10 :                          blurRadius, spreadRadius, constrainSpreadRadius);
    4479             : 
    4480             :   // The blur and spread radius are scaled already, so scale all
    4481             :   // input data to the blur. This way, we don't have to scale the min
    4482             :   // inset blur to the invert of the dest context, then rescale it back
    4483             :   // when we draw to the destination surface.
    4484          10 :   gfxSize scale = aDestinationCtx->CurrentMatrix().ScaleFactors(true);
    4485          10 :   Matrix transform = ToMatrix(aDestinationCtx->CurrentMatrix());
    4486             : 
    4487             :   // XXX: we could probably handle negative scales but for now it's easier just to fallback
    4488          10 :   if (!transform.HasNonAxisAlignedTransform() && transform._11 > 0.0 && transform._22 > 0.0) {
    4489             :     // If we don't have a rotation, we're pre-transforming all the rects.
    4490          10 :     aDestinationCtx->SetMatrix(gfxMatrix());
    4491             :   } else {
    4492             :     // Don't touch anything, we have a rotation.
    4493           0 :     transform = Matrix();
    4494             :   }
    4495             : 
    4496          10 :   Rect transformedDestRect = transform.TransformBounds(aDestinationRect);
    4497          10 :   Rect transformedShadowClipRect = transform.TransformBounds(aShadowClipRect);
    4498          10 :   Rect transformedSkipRect = transform.TransformBounds(aSkipRect);
    4499             : 
    4500          10 :   transformedDestRect.Round();
    4501          10 :   transformedShadowClipRect.Round();
    4502          10 :   transformedSkipRect.RoundIn();
    4503             : 
    4504          50 :   for (size_t i = 0; i < 4; i++) {
    4505          40 :     aInnerClipRectRadii[i].width = std::floor(scale.width * aInnerClipRectRadii[i].width);
    4506          40 :     aInnerClipRectRadii[i].height = std::floor(scale.height * aInnerClipRectRadii[i].height);
    4507             :   }
    4508             : 
    4509          10 :   mAlphaBoxBlur.BlurInsetBox(aDestinationCtx, transformedDestRect,
    4510             :                              transformedShadowClipRect,
    4511             :                              blurRadius, aShadowColor,
    4512             :                              aHasBorderRadius ? &aInnerClipRectRadii : nullptr,
    4513          10 :                              transformedSkipRect, aShadowOffset);
    4514          10 :   return true;
    4515             : }

Generated by: LCOV version 1.13