LCOV - code coverage report
Current view: top level - layout/painting - nsCSSRendering.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 162 1894 8.6 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13-14-ga5dd952