LCOV - code coverage report
Current view: top level - layout/painting - nsImageRenderer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 142 460 30.9 %
Date: 2017-07-14 16:53:18 Functions: 18 27 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : // vim:cindent:ts=2:et:sw=2:
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* utility functions for drawing borders and backgrounds */
       8             : 
       9             : #include "nsImageRenderer.h"
      10             : 
      11             : #include "mozilla/webrender/WebRenderAPI.h"
      12             : 
      13             : #include "gfxContext.h"
      14             : #include "gfxDrawable.h"
      15             : #include "ImageOps.h"
      16             : #include "mozilla/layers/StackingContextHelper.h"
      17             : #include "nsContentUtils.h"
      18             : #include "nsCSSRendering.h"
      19             : #include "nsCSSRenderingGradients.h"
      20             : #include "nsIFrame.h"
      21             : #include "nsStyleStructInlines.h"
      22             : #include "nsSVGDisplayableFrame.h"
      23             : #include "nsSVGEffects.h"
      24             : #include "nsSVGIntegrationUtils.h"
      25             : 
      26             : using namespace mozilla;
      27             : using namespace mozilla::gfx;
      28             : using namespace mozilla::image;
      29             : using namespace mozilla::layers;
      30             : 
      31             : nsSize
      32         268 : CSSSizeOrRatio::ComputeConcreteSize() const
      33             : {
      34         268 :   NS_ASSERTION(CanComputeConcreteSize(), "Cannot compute");
      35         268 :   if (mHasWidth && mHasHeight) {
      36         268 :     return nsSize(mWidth, mHeight);
      37             :   }
      38           0 :   if (mHasWidth) {
      39           0 :     nscoord height = NSCoordSaturatingNonnegativeMultiply(
      40           0 :       mWidth,
      41           0 :       double(mRatio.height) / mRatio.width);
      42           0 :     return nsSize(mWidth, height);
      43             :   }
      44             : 
      45           0 :   MOZ_ASSERT(mHasHeight);
      46           0 :   nscoord width = NSCoordSaturatingNonnegativeMultiply(
      47           0 :     mHeight,
      48           0 :     double(mRatio.width) / mRatio.height);
      49           0 :   return nsSize(width, mHeight);
      50             : }
      51             : 
      52         457 : nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame,
      53             :                                  const nsStyleImage* aImage,
      54         457 :                                  uint32_t aFlags)
      55             :   : mForFrame(aForFrame)
      56             :   , mImage(aImage)
      57         457 :   , mType(aImage->GetType())
      58             :   , mImageContainer(nullptr)
      59             :   , mGradientData(nullptr)
      60             :   , mPaintServerFrame(nullptr)
      61             :   , mPrepareResult(DrawResult::NOT_READY)
      62             :   , mSize(0, 0)
      63             :   , mFlags(aFlags)
      64             :   , mExtendMode(ExtendMode::CLAMP)
      65         914 :   , mMaskOp(NS_STYLE_MASK_MODE_MATCH_SOURCE)
      66             : {
      67         457 : }
      68             : 
      69         463 : nsImageRenderer::~nsImageRenderer()
      70             : {
      71         463 : }
      72             : 
      73             : static bool
      74           0 : ShouldTreatAsCompleteDueToSyncDecode(const nsStyleImage* aImage,
      75             :                                      uint32_t aFlags)
      76             : {
      77           0 :   if (!(aFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES)) {
      78           0 :     return false;
      79             :   }
      80             : 
      81           0 :   if (aImage->GetType() != eStyleImageType_Image) {
      82           0 :     return false;
      83             :   }
      84             : 
      85           0 :   imgRequestProxy* req = aImage->GetImageData();
      86           0 :   if (!req) {
      87           0 :     return false;
      88             :   }
      89             : 
      90           0 :   uint32_t status = 0;
      91           0 :   if (NS_FAILED(req->GetImageStatus(&status))) {
      92           0 :     return false;
      93             :   }
      94             : 
      95           0 :   if (status & imgIRequest::STATUS_ERROR) {
      96             :     // The image is "complete" since it's a corrupt image. If we created an
      97             :     // imgIContainer at all, return true.
      98           0 :     nsCOMPtr<imgIContainer> image;
      99           0 :     req->GetImage(getter_AddRefs(image));
     100           0 :     return bool(image);
     101             :   }
     102             : 
     103           0 :   if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
     104             :     // We must have loaded all of the image's data and the size must be
     105             :     // available, or else sync decoding won't be able to decode the image.
     106           0 :     return false;
     107             :   }
     108             : 
     109           0 :   return true;
     110             : }
     111             : 
     112             : bool
     113         457 : nsImageRenderer::PrepareImage()
     114             : {
     115         457 :   if (mImage->IsEmpty()) {
     116           2 :     mPrepareResult = DrawResult::BAD_IMAGE;
     117           2 :     return false;
     118             :   }
     119             : 
     120         455 :   if (!mImage->IsComplete()) {
     121             :     // Make sure the image is actually decoding.
     122           9 :     bool frameComplete = mImage->StartDecoding();
     123             : 
     124             :     // Check again to see if we finished.
     125             :     // We cannot prepare the image for rendering if it is not fully loaded.
     126             :     // Special case: If we requested a sync decode and the image has loaded, push
     127             :     // on through because the Draw() will do a sync decode then.
     128           9 :     if (!(frameComplete || mImage->IsComplete()) &&
     129           0 :         !ShouldTreatAsCompleteDueToSyncDecode(mImage, mFlags)) {
     130           0 :       mPrepareResult = DrawResult::NOT_READY;
     131           0 :       return false;
     132             :     }
     133             :   }
     134             : 
     135         455 :   switch (mType) {
     136             :     case eStyleImageType_Image: {
     137         324 :       MOZ_ASSERT(mImage->GetImageData(),
     138             :                  "must have image data, since we checked IsEmpty above");
     139         324 :       nsCOMPtr<imgIContainer> srcImage;
     140             :       DebugOnly<nsresult> rv =
     141         324 :         mImage->GetImageData()->GetImage(getter_AddRefs(srcImage));
     142         324 :       MOZ_ASSERT(NS_SUCCEEDED(rv) && srcImage,
     143             :                  "If GetImage() is failing, mImage->IsComplete() "
     144             :                  "should have returned false");
     145             : 
     146         324 :       if (!mImage->GetCropRect()) {
     147         272 :         mImageContainer.swap(srcImage);
     148             :       } else {
     149          52 :         nsIntRect actualCropRect;
     150             :         bool isEntireImage;
     151             :         bool success =
     152          52 :           mImage->ComputeActualCropRect(actualCropRect, &isEntireImage);
     153          52 :         if (!success || actualCropRect.IsEmpty()) {
     154             :           // The cropped image has zero size
     155           0 :           mPrepareResult = DrawResult::BAD_IMAGE;
     156           0 :           return false;
     157             :         }
     158          52 :         if (isEntireImage) {
     159             :           // The cropped image is identical to the source image
     160           0 :           mImageContainer.swap(srcImage);
     161             :         } else {
     162         104 :           nsCOMPtr<imgIContainer> subImage = ImageOps::Clip(srcImage,
     163             :                                                             actualCropRect,
     164         156 :                                                             Nothing());
     165          52 :           mImageContainer.swap(subImage);
     166             :         }
     167             :       }
     168         324 :       mPrepareResult = DrawResult::SUCCESS;
     169         324 :       break;
     170             :     }
     171             :     case eStyleImageType_Gradient:
     172         131 :       mGradientData = mImage->GetGradientData();
     173         131 :       mPrepareResult = DrawResult::SUCCESS;
     174         131 :       break;
     175             :     case eStyleImageType_Element:
     176             :     {
     177             :       nsAutoString elementId =
     178           0 :         NS_LITERAL_STRING("#") + nsDependentAtomString(mImage->GetElementId());
     179           0 :       nsCOMPtr<nsIURI> targetURI;
     180           0 :       nsCOMPtr<nsIURI> base = mForFrame->GetContent()->GetBaseURI();
     181           0 :       nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), elementId,
     182           0 :                                                 mForFrame->GetContent()->GetUncomposedDoc(), base);
     183           0 :       nsSVGPaintingProperty* property = nsSVGEffects::GetPaintingPropertyForURI(
     184           0 :           targetURI, mForFrame->FirstContinuation(),
     185           0 :           nsSVGEffects::BackgroundImageProperty());
     186           0 :       if (!property) {
     187           0 :         mPrepareResult = DrawResult::BAD_IMAGE;
     188           0 :         return false;
     189             :       }
     190             : 
     191             :       // If the referenced element is an <img>, <canvas>, or <video> element,
     192             :       // prefer SurfaceFromElement as it's more reliable.
     193             :       mImageElementSurface =
     194           0 :         nsLayoutUtils::SurfaceFromElement(property->GetReferencedElement());
     195           0 :       if (!mImageElementSurface.GetSourceSurface()) {
     196           0 :         nsIFrame* paintServerFrame = property->GetReferencedFrame();
     197             :         // If there's no referenced frame, or the referenced frame is
     198             :         // non-displayable SVG, then we have nothing valid to paint.
     199           0 :         if (!paintServerFrame ||
     200           0 :             (paintServerFrame->IsFrameOfType(nsIFrame::eSVG) &&
     201           0 :              !paintServerFrame->IsFrameOfType(nsIFrame::eSVGPaintServer) &&
     202           0 :              !static_cast<nsSVGDisplayableFrame*>(do_QueryFrame(paintServerFrame)))) {
     203           0 :           mPrepareResult = DrawResult::BAD_IMAGE;
     204           0 :           return false;
     205             :         }
     206           0 :         mPaintServerFrame = paintServerFrame;
     207             :       }
     208             : 
     209           0 :       mPrepareResult = DrawResult::SUCCESS;
     210           0 :       break;
     211             :     }
     212             :     case eStyleImageType_Null:
     213             :     default:
     214           0 :       break;
     215             :   }
     216             : 
     217         455 :   return IsReady();
     218             : }
     219             : 
     220             : CSSSizeOrRatio
     221         458 : nsImageRenderer::ComputeIntrinsicSize()
     222             : {
     223         458 :   NS_ASSERTION(IsReady(), "Ensure PrepareImage() has returned true "
     224             :                           "before calling me");
     225             : 
     226         458 :   CSSSizeOrRatio result;
     227         458 :   switch (mType) {
     228             :     case eStyleImageType_Image:
     229             :     {
     230             :       bool haveWidth, haveHeight;
     231         324 :       CSSIntSize imageIntSize;
     232         324 :       nsLayoutUtils::ComputeSizeForDrawing(mImageContainer, imageIntSize,
     233         324 :                                            result.mRatio, haveWidth, haveHeight);
     234         324 :       if (haveWidth) {
     235         324 :         result.SetWidth(nsPresContext::CSSPixelsToAppUnits(imageIntSize.width));
     236             :       }
     237         324 :       if (haveHeight) {
     238         324 :         result.SetHeight(nsPresContext::CSSPixelsToAppUnits(imageIntSize.height));
     239             :       }
     240             : 
     241             :       // If we know the aspect ratio and one of the dimensions,
     242             :       // we can compute the other missing width or height.
     243         324 :       if (!haveHeight && haveWidth && result.mRatio.width != 0) {
     244             :         nscoord intrinsicHeight =
     245           0 :           NSCoordSaturatingNonnegativeMultiply(imageIntSize.width,
     246           0 :                                                float(result.mRatio.height) /
     247           0 :                                                float(result.mRatio.width));
     248           0 :         result.SetHeight(nsPresContext::CSSPixelsToAppUnits(intrinsicHeight));
     249         324 :       } else if (haveHeight && !haveWidth && result.mRatio.height != 0) {
     250             :         nscoord intrinsicWidth =
     251           0 :           NSCoordSaturatingNonnegativeMultiply(imageIntSize.height,
     252           0 :                                                float(result.mRatio.width) /
     253           0 :                                                float(result.mRatio.height));
     254           0 :         result.SetWidth(nsPresContext::CSSPixelsToAppUnits(intrinsicWidth));
     255             :       }
     256             : 
     257         324 :       break;
     258             :     }
     259             :     case eStyleImageType_Element:
     260             :     {
     261             :       // XXX element() should have the width/height of the referenced element,
     262             :       //     and that element's ratio, if it matches.  If it doesn't match, it
     263             :       //     should have no width/height or ratio.  See element() in CSS images:
     264             :       //     <http://dev.w3.org/csswg/css-images-4/#element-notation>.
     265             :       //     Make sure to change nsStyleImageLayers::Size::DependsOnFrameSize
     266             :       //     when fixing this!
     267           0 :       if (mPaintServerFrame) {
     268             :         // SVG images have no intrinsic size
     269           0 :         if (!mPaintServerFrame->IsFrameOfType(nsIFrame::eSVG)) {
     270             :           // The intrinsic image size for a generic nsIFrame paint server is
     271             :           // the union of the border-box rects of all of its continuations,
     272             :           // rounded to device pixels.
     273             :           int32_t appUnitsPerDevPixel =
     274           0 :             mForFrame->PresContext()->AppUnitsPerDevPixel();
     275             :           result.SetSize(
     276           0 :             IntSizeToAppUnits(
     277           0 :               nsSVGIntegrationUtils::GetContinuationUnionSize(mPaintServerFrame).
     278             :                 ToNearestPixels(appUnitsPerDevPixel),
     279           0 :               appUnitsPerDevPixel));
     280             :         }
     281             :       } else {
     282           0 :         NS_ASSERTION(mImageElementSurface.GetSourceSurface(),
     283             :                      "Surface should be ready.");
     284           0 :         IntSize surfaceSize = mImageElementSurface.mSize;
     285             :         result.SetSize(
     286           0 :           nsSize(nsPresContext::CSSPixelsToAppUnits(surfaceSize.width),
     287           0 :                  nsPresContext::CSSPixelsToAppUnits(surfaceSize.height)));
     288             :       }
     289           0 :       break;
     290             :     }
     291             :     case eStyleImageType_Gradient:
     292             :       // Per <http://dev.w3.org/csswg/css3-images/#gradients>, gradients have no
     293             :       // intrinsic dimensions.
     294             :     case eStyleImageType_Null:
     295             :     default:
     296         134 :       break;
     297             :   }
     298             : 
     299         458 :   return result;
     300             : }
     301             : 
     302             : /* static */ nsSize
     303         455 : nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize,
     304             :                                      const CSSSizeOrRatio& aIntrinsicSize,
     305             :                                      const nsSize& aDefaultSize)
     306             : {
     307             :   // The specified size is fully specified, just use that
     308         455 :   if (aSpecifiedSize.IsConcrete()) {
     309         216 :     return aSpecifiedSize.ComputeConcreteSize();
     310             :   }
     311             : 
     312         239 :   MOZ_ASSERT(!aSpecifiedSize.mHasWidth || !aSpecifiedSize.mHasHeight);
     313             : 
     314         239 :   if (!aSpecifiedSize.mHasWidth && !aSpecifiedSize.mHasHeight) {
     315             :     // no specified size, try using the intrinsic size
     316         127 :     if (aIntrinsicSize.CanComputeConcreteSize()) {
     317          52 :       return aIntrinsicSize.ComputeConcreteSize();
     318             :     }
     319             : 
     320          75 :     if (aIntrinsicSize.mHasWidth) {
     321           0 :       return nsSize(aIntrinsicSize.mWidth, aDefaultSize.height);
     322             :     }
     323          75 :     if (aIntrinsicSize.mHasHeight) {
     324           0 :       return nsSize(aDefaultSize.width, aIntrinsicSize.mHeight);
     325             :     }
     326             : 
     327             :     // couldn't use the intrinsic size either, revert to using the default size
     328             :     return ComputeConstrainedSize(aDefaultSize,
     329             :                                   aIntrinsicSize.mRatio,
     330          75 :                                   CONTAIN);
     331             :   }
     332             : 
     333         112 :   MOZ_ASSERT(aSpecifiedSize.mHasWidth || aSpecifiedSize.mHasHeight);
     334             : 
     335             :   // The specified height is partial, try to compute the missing part.
     336         112 :   if (aSpecifiedSize.mHasWidth) {
     337             :     nscoord height;
     338           0 :     if (aIntrinsicSize.HasRatio()) {
     339           0 :       height = NSCoordSaturatingNonnegativeMultiply(
     340           0 :         aSpecifiedSize.mWidth,
     341           0 :         double(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width);
     342           0 :     } else if (aIntrinsicSize.mHasHeight) {
     343           0 :       height = aIntrinsicSize.mHeight;
     344             :     } else {
     345           0 :       height = aDefaultSize.height;
     346             :     }
     347           0 :     return nsSize(aSpecifiedSize.mWidth, height);
     348             :   }
     349             : 
     350         112 :   MOZ_ASSERT(aSpecifiedSize.mHasHeight);
     351             :   nscoord width;
     352         112 :   if (aIntrinsicSize.HasRatio()) {
     353          56 :     width = NSCoordSaturatingNonnegativeMultiply(
     354          56 :       aSpecifiedSize.mHeight,
     355         112 :       double(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height);
     356          56 :   } else if (aIntrinsicSize.mHasWidth) {
     357           0 :     width = aIntrinsicSize.mWidth;
     358             :   } else {
     359          56 :     width = aDefaultSize.width;
     360             :   }
     361         112 :   return nsSize(width, aSpecifiedSize.mHeight);
     362             : }
     363             : 
     364             : /* static */ nsSize
     365          75 : nsImageRenderer::ComputeConstrainedSize(const nsSize& aConstrainingSize,
     366             :                                         const nsSize& aIntrinsicRatio,
     367             :                                         FitType aFitType)
     368             : {
     369          75 :   if (aIntrinsicRatio.width <= 0 && aIntrinsicRatio.height <= 0) {
     370          75 :     return aConstrainingSize;
     371             :   }
     372             : 
     373           0 :   float scaleX = double(aConstrainingSize.width) / aIntrinsicRatio.width;
     374           0 :   float scaleY = double(aConstrainingSize.height) / aIntrinsicRatio.height;
     375           0 :   nsSize size;
     376           0 :   if ((aFitType == CONTAIN) == (scaleX < scaleY)) {
     377           0 :     size.width = aConstrainingSize.width;
     378           0 :     size.height = NSCoordSaturatingNonnegativeMultiply(
     379           0 :                     aIntrinsicRatio.height, scaleX);
     380             :     // If we're reducing the size by less than one css pixel, then just use the
     381             :     // constraining size.
     382           0 :     if (aFitType == CONTAIN && aConstrainingSize.height - size.height < nsPresContext::AppUnitsPerCSSPixel()) {
     383           0 :       size.height = aConstrainingSize.height;
     384             :     }
     385             :   } else {
     386           0 :     size.width = NSCoordSaturatingNonnegativeMultiply(
     387           0 :                    aIntrinsicRatio.width, scaleY);
     388           0 :     if (aFitType == CONTAIN && aConstrainingSize.width - size.width < nsPresContext::AppUnitsPerCSSPixel()) {
     389           0 :       size.width = aConstrainingSize.width;
     390             :     }
     391           0 :     size.height = aConstrainingSize.height;
     392             :   }
     393           0 :   return size;
     394             : }
     395             : 
     396             : /**
     397             :  * mSize is the image's "preferred" size for this particular rendering, while
     398             :  * the drawn (aka concrete) size is the actual rendered size after accounting
     399             :  * for background-size etc..  The preferred size is most often the image's
     400             :  * intrinsic dimensions.  But for images with incomplete intrinsic dimensions,
     401             :  * the preferred size varies, depending on the specified and default sizes, see
     402             :  * nsImageRenderer::Compute*Size.
     403             :  *
     404             :  * This distinction is necessary because the components of a vector image are
     405             :  * specified with respect to its preferred size for a rendering situation, not
     406             :  * to its actual rendered size.  For example, consider a 4px wide background
     407             :  * vector image with no height which contains a left-aligned
     408             :  * 2px wide black rectangle with height 100%.  If the background-size width is
     409             :  * auto (or 4px), the vector image will render 4px wide, and the black rectangle
     410             :  * will be 2px wide.  If the background-size width is 8px, the vector image will
     411             :  * render 8px wide, and the black rectangle will be 4px wide -- *not* 2px wide.
     412             :  * In both cases mSize.width will be 4px; but in the first case the returned
     413             :  * width will be 4px, while in the second case the returned width will be 8px.
     414             :  */
     415             : void
     416         455 : nsImageRenderer::SetPreferredSize(const CSSSizeOrRatio& aIntrinsicSize,
     417             :                                   const nsSize& aDefaultSize)
     418             : {
     419         910 :   mSize.width = aIntrinsicSize.mHasWidth
     420         455 :                   ? aIntrinsicSize.mWidth
     421             :                   : aDefaultSize.width;
     422         910 :   mSize.height = aIntrinsicSize.mHasHeight
     423         455 :                   ? aIntrinsicSize.mHeight
     424             :                   : aDefaultSize.height;
     425         455 : }
     426             : 
     427             : // Convert from nsImageRenderer flags to the flags we want to use for drawing in
     428             : // the imgIContainer namespace.
     429             : static uint32_t
     430          36 : ConvertImageRendererToDrawFlags(uint32_t aImageRendererFlags)
     431             : {
     432          36 :   uint32_t drawFlags = imgIContainer::FLAG_NONE;
     433          36 :   if (aImageRendererFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) {
     434           0 :     drawFlags |= imgIContainer::FLAG_SYNC_DECODE;
     435             :   }
     436          36 :   if (aImageRendererFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) {
     437          36 :     drawFlags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
     438             :   }
     439          36 :   return drawFlags;
     440             : }
     441             : 
     442             : /*
     443             :  *  SVG11: A luminanceToAlpha operation is equivalent to the following matrix operation:                                                   |
     444             :  *  | R' |     |      0        0        0  0  0 |   | R |
     445             :  *  | G' |     |      0        0        0  0  0 |   | G |
     446             :  *  | B' |  =  |      0        0        0  0  0 | * | B |
     447             :  *  | A' |     | 0.2125   0.7154   0.0721  0  0 |   | A |
     448             :  *  | 1  |     |      0        0        0  0  1 |   | 1 |
     449             :  */
     450             : static void
     451           0 : RGBALuminanceOperation(uint8_t *aData,
     452             :                        int32_t aStride,
     453             :                        const IntSize &aSize)
     454             : {
     455           0 :   int32_t redFactor = 55;    // 256 * 0.2125
     456           0 :   int32_t greenFactor = 183; // 256 * 0.7154
     457           0 :   int32_t blueFactor = 18;   // 256 * 0.0721
     458             : 
     459           0 :   for (int32_t y = 0; y < aSize.height; y++) {
     460           0 :     uint32_t *pixel = (uint32_t*)(aData + aStride * y);
     461           0 :     for (int32_t x = 0; x < aSize.width; x++) {
     462           0 :       *pixel = (((((*pixel & 0x00FF0000) >> 16) * redFactor) +
     463           0 :                  (((*pixel & 0x0000FF00) >>  8) * greenFactor) +
     464           0 :                   ((*pixel & 0x000000FF)        * blueFactor)) >> 8) << 24;
     465           0 :       pixel++;
     466             :     }
     467             :   }
     468           0 : }
     469             : 
     470             : DrawResult
     471          62 : nsImageRenderer::Draw(nsPresContext*       aPresContext,
     472             :                       gfxContext&          aRenderingContext,
     473             :                       const nsRect&        aDirtyRect,
     474             :                       const nsRect&        aDest,
     475             :                       const nsRect&        aFill,
     476             :                       const nsPoint&       aAnchor,
     477             :                       const nsSize&        aRepeatSize,
     478             :                       const CSSIntRect&    aSrc,
     479             :                       float                aOpacity)
     480             : {
     481          62 :   if (!IsReady()) {
     482           0 :     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     483           0 :     return DrawResult::TEMPORARY_ERROR;
     484             :   }
     485         248 :   if (aDest.IsEmpty() || aFill.IsEmpty() ||
     486         186 :       mSize.width <= 0 || mSize.height <= 0) {
     487           0 :     return DrawResult::SUCCESS;
     488             :   }
     489             : 
     490          62 :   SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(mForFrame);
     491          62 :   DrawResult result = DrawResult::SUCCESS;
     492         124 :   RefPtr<gfxContext> ctx = &aRenderingContext;
     493          62 :   IntRect tmpDTRect;
     494             : 
     495          62 :   if (ctx->CurrentOp() != CompositionOp::OP_OVER || mMaskOp == NS_STYLE_MASK_MODE_LUMINANCE) {
     496           0 :     gfxRect clipRect = ctx->GetClipExtents();
     497           0 :     tmpDTRect = RoundedOut(ToRect(clipRect));
     498           0 :     if (tmpDTRect.IsEmpty()) {
     499           0 :       return DrawResult::SUCCESS;
     500             :     }
     501             :     RefPtr<DrawTarget> tempDT =
     502           0 :       gfxPlatform::GetPlatform()->CreateSimilarSoftwareDrawTarget(ctx->GetDrawTarget(),
     503           0 :                                                                   tmpDTRect.Size(),
     504           0 :                                                                   SurfaceFormat::B8G8R8A8);
     505           0 :     if (!tempDT || !tempDT->IsValid()) {
     506           0 :       gfxDevCrash(LogReason::InvalidContext) << "ImageRenderer::Draw problem " << gfx::hexa(tempDT);
     507           0 :       return DrawResult::TEMPORARY_ERROR;
     508             :     }
     509           0 :     tempDT->SetTransform(Matrix::Translation(-tmpDTRect.TopLeft()));
     510           0 :     ctx = gfxContext::CreatePreservingTransformOrNull(tempDT);
     511           0 :     if (!ctx) {
     512           0 :       gfxDevCrash(LogReason::InvalidContext) << "ImageRenderer::Draw problem " << gfx::hexa(tempDT);
     513           0 :       return DrawResult::TEMPORARY_ERROR;
     514             :     }
     515             :   }
     516             : 
     517          62 :   switch (mType) {
     518             :     case eStyleImageType_Image:
     519             :     {
     520             :       CSSIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
     521          36 :                            nsPresContext::AppUnitsToIntCSSPixels(mSize.height));
     522             :       result =
     523          36 :         nsLayoutUtils::DrawBackgroundImage(*ctx, mForFrame,
     524             :                                            aPresContext,
     525             :                                            mImageContainer, imageSize,
     526             :                                            samplingFilter,
     527             :                                            aDest, aFill, aRepeatSize,
     528             :                                            aAnchor, aDirtyRect,
     529             :                                            ConvertImageRendererToDrawFlags(mFlags),
     530          36 :                                            mExtendMode, aOpacity);
     531          36 :       break;
     532             :     }
     533             :     case eStyleImageType_Gradient:
     534             :     {
     535             :       nsCSSGradientRenderer renderer =
     536          52 :         nsCSSGradientRenderer::Create(aPresContext, mGradientData, mSize);
     537             : 
     538          26 :       renderer.Paint(*ctx, aDest, aFill, aRepeatSize, aSrc, aDirtyRect, aOpacity);
     539          26 :       break;
     540             :     }
     541             :     case eStyleImageType_Element:
     542             :     {
     543           0 :       RefPtr<gfxDrawable> drawable = DrawableForElement(aDest, *ctx);
     544           0 :       if (!drawable) {
     545           0 :         NS_WARNING("Could not create drawable for element");
     546           0 :         return DrawResult::TEMPORARY_ERROR;
     547             :       }
     548             : 
     549           0 :       nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
     550             :       result =
     551           0 :         nsLayoutUtils::DrawImage(*ctx, mForFrame->StyleContext(),
     552             :                                  aPresContext, image,
     553             :                                  samplingFilter, aDest, aFill, aAnchor, aDirtyRect,
     554             :                                  ConvertImageRendererToDrawFlags(mFlags),
     555           0 :                                  aOpacity);
     556           0 :       break;
     557             :     }
     558             :     case eStyleImageType_Null:
     559             :     default:
     560           0 :       break;
     561             :   }
     562             : 
     563          62 :   if (!tmpDTRect.IsEmpty()) {
     564           0 :     RefPtr<SourceSurface> surf = ctx->GetDrawTarget()->Snapshot();
     565           0 :     if (mMaskOp == NS_STYLE_MASK_MODE_LUMINANCE) {
     566           0 :       RefPtr<DataSourceSurface> maskData = surf->GetDataSurface();
     567             :       DataSourceSurface::MappedSurface map;
     568           0 :       if (!maskData->Map(DataSourceSurface::MapType::WRITE, &map)) {
     569           0 :         return result;
     570             :       }
     571             : 
     572           0 :       RGBALuminanceOperation(map.mData, map.mStride, maskData->GetSize());
     573           0 :       maskData->Unmap();
     574           0 :       surf = maskData;
     575             :     }
     576             : 
     577           0 :     DrawTarget* dt = aRenderingContext.GetDrawTarget();
     578           0 :     dt->DrawSurface(surf, Rect(tmpDTRect.x, tmpDTRect.y, tmpDTRect.width, tmpDTRect.height),
     579           0 :                     Rect(0, 0, tmpDTRect.width, tmpDTRect.height),
     580           0 :                     DrawSurfaceOptions(SamplingFilter::POINT),
     581           0 :                     DrawOptions(1.0f, aRenderingContext.CurrentOp()));
     582             :   }
     583             : 
     584          62 :   return result;
     585             : }
     586             : 
     587             : DrawResult
     588           0 : nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
     589             :                                             mozilla::wr::DisplayListBuilder&            aBuilder,
     590             :                                             const mozilla::layers::StackingContextHelper& aSc,
     591             :                                             nsTArray<WebRenderParentCommand>&           aParentCommands,
     592             :                                             mozilla::layers::WebRenderDisplayItemLayer* aLayer,
     593             :                                             mozilla::layers::WebRenderLayerManager* aManager,
     594             :                                             nsDisplayItem*       aItem,
     595             :                                             const nsRect&        aDirtyRect,
     596             :                                             const nsRect&        aDest,
     597             :                                             const nsRect&        aFill,
     598             :                                             const nsPoint&       aAnchor,
     599             :                                             const nsSize&        aRepeatSize,
     600             :                                             const CSSIntRect&    aSrc,
     601             :                                             float                aOpacity)
     602             : {
     603           0 :   if (!IsReady()) {
     604           0 :     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     605           0 :     return DrawResult::NOT_READY;
     606             :   }
     607           0 :   if (aDest.IsEmpty() || aFill.IsEmpty() ||
     608           0 :       mSize.width <= 0 || mSize.height <= 0) {
     609           0 :     return DrawResult::SUCCESS;
     610             :   }
     611             : 
     612           0 :   switch (mType) {
     613             :     case eStyleImageType_Gradient:
     614             :     {
     615             :       nsCSSGradientRenderer renderer =
     616           0 :         nsCSSGradientRenderer::Create(aPresContext, mGradientData, mSize);
     617             : 
     618           0 :       renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aLayer, aDest, aFill, aRepeatSize, aSrc, aOpacity);
     619           0 :       break;
     620             :     }
     621             :     case eStyleImageType_Image:
     622             :     {
     623             :       // XXX(aosmond): We will support downscale-on-decode in bug 1368776. Until
     624             :       // then, don't pass FLAG_HIGH_QUALITY_SCALING.
     625           0 :       uint32_t containerFlags = imgIContainer::FLAG_NONE;
     626           0 :       if (mFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) {
     627           0 :         containerFlags |= imgIContainer::FLAG_SYNC_DECODE;
     628             :       }
     629             :       RefPtr<layers::ImageContainer> container =
     630           0 :         mImageContainer->GetImageContainer(aManager, containerFlags);
     631           0 :       if (!container) {
     632           0 :         NS_WARNING("Failed to get image container");
     633           0 :         return DrawResult::NOT_READY;
     634             :       }
     635             : 
     636           0 :       gfx::IntSize size;
     637           0 :       Maybe<wr::ImageKey> key = aManager->CreateImageKey(aItem, container, aBuilder, aSc, size);
     638             : 
     639           0 :       if (key.isNothing()) {
     640           0 :         return DrawResult::BAD_IMAGE;
     641             :       }
     642             : 
     643           0 :       const int32_t appUnitsPerDevPixel = mForFrame->PresContext()->AppUnitsPerDevPixel();
     644             :       LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(
     645           0 :           aDest, appUnitsPerDevPixel);
     646             : 
     647           0 :       nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos(aDest.TopLeft(),
     648           0 :                                                                       aFill.TopLeft(),
     649           0 :                                                                       aRepeatSize);
     650             :       LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(
     651           0 :           nsRect(firstTilePos.x, firstTilePos.y,
     652           0 :                  aFill.XMost() - firstTilePos.x, aFill.YMost() - firstTilePos.y),
     653           0 :           appUnitsPerDevPixel);
     654           0 :       WrRect fill = aSc.ToRelativeWrRect(fillRect);
     655             :       WrRect clip = aSc.ToRelativeWrRect(
     656           0 :           LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
     657             : 
     658             :       LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits(
     659           0 :           aRepeatSize - aDest.Size(), appUnitsPerDevPixel);
     660           0 :       aBuilder.PushImage(fill, clip,
     661           0 :                          wr::ToWrSize(destRect.Size()), wr::ToWrSize(gapSize),
     662           0 :                          wr::ImageRendering::Auto, key.value());
     663           0 :       break;
     664             :     }
     665             :     default:
     666           0 :       break;
     667             :   }
     668             : 
     669           0 :   return DrawResult::SUCCESS;
     670             : }
     671             : 
     672             : already_AddRefed<gfxDrawable>
     673           0 : nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
     674             :                                     gfxContext&  aContext)
     675             : {
     676           0 :   NS_ASSERTION(mType == eStyleImageType_Element,
     677             :                "DrawableForElement only makes sense if backed by an element");
     678           0 :   if (mPaintServerFrame) {
     679             :     // XXX(seth): In order to not pass FLAG_SYNC_DECODE_IMAGES here,
     680             :     // DrawableFromPaintServer would have to return a DrawResult indicating
     681             :     // whether any images could not be painted because they weren't fully
     682             :     // decoded. Even always passing FLAG_SYNC_DECODE_IMAGES won't eliminate all
     683             :     // problems, as it won't help if there are image which haven't finished
     684             :     // loading, but it's better than nothing.
     685           0 :     int32_t appUnitsPerDevPixel = mForFrame->PresContext()->AppUnitsPerDevPixel();
     686           0 :     nsRect destRect = aImageRect - aImageRect.TopLeft();
     687           0 :     nsIntSize roundedOut = destRect.ToOutsidePixels(appUnitsPerDevPixel).Size();
     688           0 :     IntSize imageSize(roundedOut.width, roundedOut.height);
     689             :     RefPtr<gfxDrawable> drawable =
     690           0 :       nsSVGIntegrationUtils::DrawableFromPaintServer(
     691             :         mPaintServerFrame, mForFrame, mSize, imageSize,
     692           0 :         aContext.GetDrawTarget(),
     693           0 :         aContext.CurrentMatrix(),
     694           0 :         nsSVGIntegrationUtils::FLAG_SYNC_DECODE_IMAGES);
     695             : 
     696           0 :     return drawable.forget();
     697             :   }
     698           0 :   NS_ASSERTION(mImageElementSurface.GetSourceSurface(), "Surface should be ready.");
     699             :   RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(
     700           0 :                                 mImageElementSurface.GetSourceSurface().get(),
     701           0 :                                 mImageElementSurface.mSize);
     702           0 :   return drawable.forget();
     703             : }
     704             : 
     705             : DrawResult
     706          59 : nsImageRenderer::DrawLayer(nsPresContext*       aPresContext,
     707             :                            gfxContext&          aRenderingContext,
     708             :                            const nsRect&        aDest,
     709             :                            const nsRect&        aFill,
     710             :                            const nsPoint&       aAnchor,
     711             :                            const nsRect&        aDirty,
     712             :                            const nsSize&        aRepeatSize,
     713             :                            float                aOpacity)
     714             : {
     715          59 :   if (!IsReady()) {
     716           0 :     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     717           0 :     return DrawResult::TEMPORARY_ERROR;
     718             :   }
     719         236 :   if (aDest.IsEmpty() || aFill.IsEmpty() ||
     720         177 :       mSize.width <= 0 || mSize.height <= 0) {
     721           0 :     return DrawResult::SUCCESS;
     722             :   }
     723             : 
     724             :   return Draw(aPresContext, aRenderingContext,
     725             :               aDirty, aDest, aFill, aAnchor, aRepeatSize,
     726         177 :               CSSIntRect(0, 0,
     727             :                          nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
     728          59 :                          nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
     729          59 :               aOpacity);
     730             : }
     731             : 
     732             : DrawResult
     733           0 : nsImageRenderer::BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
     734             :                                                     mozilla::wr::DisplayListBuilder& aBuilder,
     735             :                                                     const mozilla::layers::StackingContextHelper& aSc,
     736             :                                                     nsTArray<WebRenderParentCommand>& aParentCommands,
     737             :                                                     WebRenderDisplayItemLayer*       aLayer,
     738             :                                                     mozilla::layers::WebRenderLayerManager* aManager,
     739             :                                                     nsDisplayItem*       aItem,
     740             :                                                     const nsRect&        aDest,
     741             :                                                     const nsRect&        aFill,
     742             :                                                     const nsPoint&       aAnchor,
     743             :                                                     const nsRect&        aDirty,
     744             :                                                     const nsSize&        aRepeatSize,
     745             :                                                     float                aOpacity)
     746             : {
     747           0 :   if (!IsReady()) {
     748           0 :     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     749           0 :     return mPrepareResult;
     750             :   }
     751           0 :   if (aDest.IsEmpty() || aFill.IsEmpty() ||
     752           0 :       mSize.width <= 0 || mSize.height <= 0) {
     753           0 :     return DrawResult::SUCCESS;
     754             :   }
     755             :   return BuildWebRenderDisplayItems(aPresContext, aBuilder, aSc, aParentCommands,
     756             :                                     aLayer, aManager, aItem,
     757             :                                     aDirty, aDest, aFill, aAnchor, aRepeatSize,
     758           0 :                                     CSSIntRect(0, 0,
     759             :                                                nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
     760           0 :                                                nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
     761           0 :                                     aOpacity);
     762             : }
     763             : 
     764             : /**
     765             :  * Compute the size and position of the master copy of the image. I.e., a single
     766             :  * tile used to fill the dest rect.
     767             :  * aFill The destination rect to be filled
     768             :  * aHFill and aVFill are the repeat patterns for the component -
     769             :  * NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
     770             :  * aUnitSize The size of the source rect in dest coords.
     771             :  */
     772             : static nsRect
     773           0 : ComputeTile(nsRect&              aFill,
     774             :             uint8_t              aHFill,
     775             :             uint8_t              aVFill,
     776             :             const nsSize&        aUnitSize,
     777             :             nsSize&              aRepeatSize)
     778             : {
     779           0 :   nsRect tile;
     780           0 :   switch (aHFill) {
     781             :   case NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH:
     782           0 :     tile.x = aFill.x;
     783           0 :     tile.width = aFill.width;
     784           0 :     aRepeatSize.width = tile.width;
     785           0 :     break;
     786             :   case NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT:
     787           0 :     tile.x = aFill.x + aFill.width/2 - aUnitSize.width/2;
     788           0 :     tile.width = aUnitSize.width;
     789           0 :     aRepeatSize.width = tile.width;
     790           0 :     break;
     791             :   case NS_STYLE_BORDER_IMAGE_REPEAT_ROUND:
     792           0 :     tile.x = aFill.x;
     793           0 :     tile.width = nsCSSRendering::ComputeRoundedSize(aUnitSize.width,
     794             :                                                     aFill.width);
     795           0 :     aRepeatSize.width = tile.width;
     796           0 :     break;
     797             :   case NS_STYLE_BORDER_IMAGE_REPEAT_SPACE:
     798             :     {
     799             :       nscoord space;
     800           0 :       aRepeatSize.width =
     801           0 :         nsCSSRendering::ComputeBorderSpacedRepeatSize(aUnitSize.width,
     802             :                                                       aFill.width, space);
     803           0 :       tile.x = aFill.x + space;
     804           0 :       tile.width = aUnitSize.width;
     805           0 :       aFill.x = tile.x;
     806           0 :       aFill.width = aFill.width - space * 2;
     807             :     }
     808           0 :     break;
     809             :   default:
     810           0 :     NS_NOTREACHED("unrecognized border-image fill style");
     811             :   }
     812             : 
     813           0 :   switch (aVFill) {
     814             :   case NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH:
     815           0 :     tile.y = aFill.y;
     816           0 :     tile.height = aFill.height;
     817           0 :     aRepeatSize.height = tile.height;
     818           0 :     break;
     819             :   case NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT:
     820           0 :     tile.y = aFill.y + aFill.height/2 - aUnitSize.height/2;
     821           0 :     tile.height = aUnitSize.height;
     822           0 :     aRepeatSize.height = tile.height;
     823           0 :     break;
     824             :   case NS_STYLE_BORDER_IMAGE_REPEAT_ROUND:
     825           0 :     tile.y = aFill.y;
     826           0 :     tile.height = nsCSSRendering::ComputeRoundedSize(aUnitSize.height,
     827             :                                                      aFill.height);
     828           0 :     aRepeatSize.height = tile.height;
     829           0 :     break;
     830             :   case NS_STYLE_BORDER_IMAGE_REPEAT_SPACE:
     831             :     {
     832             :       nscoord space;
     833           0 :       aRepeatSize.height =
     834           0 :         nsCSSRendering::ComputeBorderSpacedRepeatSize(aUnitSize.height,
     835             :                                                       aFill.height, space);
     836           0 :       tile.y = aFill.y + space;
     837           0 :       tile.height = aUnitSize.height;
     838           0 :       aFill.y = tile.y;
     839           0 :       aFill.height = aFill.height - space * 2;
     840             :     }
     841           0 :     break;
     842             :   default:
     843           0 :     NS_NOTREACHED("unrecognized border-image fill style");
     844             :   }
     845             : 
     846           0 :   return tile;
     847             : }
     848             : 
     849             : /**
     850             :  * Returns true if the given set of arguments will require the tiles which fill
     851             :  * the dest rect to be scaled from the source tile. See comment on ComputeTile
     852             :  * for argument descriptions.
     853             :  */
     854             : static bool
     855           3 : RequiresScaling(const nsRect&        aFill,
     856             :                 uint8_t              aHFill,
     857             :                 uint8_t              aVFill,
     858             :                 const nsSize&        aUnitSize)
     859             : {
     860             :   // If we have no tiling in either direction, we can skip the intermediate
     861             :   // scaling step.
     862           3 :   return (aHFill != NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH ||
     863           3 :           aVFill != NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH) &&
     864           0 :          (aUnitSize.width != aFill.width ||
     865           3 :           aUnitSize.height != aFill.height);
     866             : }
     867             : 
     868             : DrawResult
     869          24 : nsImageRenderer::DrawBorderImageComponent(nsPresContext*       aPresContext,
     870             :                                           gfxContext&          aRenderingContext,
     871             :                                           const nsRect&        aDirtyRect,
     872             :                                           const nsRect&        aFill,
     873             :                                           const CSSIntRect&    aSrc,
     874             :                                           uint8_t              aHFill,
     875             :                                           uint8_t              aVFill,
     876             :                                           const nsSize&        aUnitSize,
     877             :                                           uint8_t              aIndex,
     878             :                                           const Maybe<nsSize>& aSVGViewportSize,
     879             :                                           const bool           aHasIntrinsicRatio)
     880             : {
     881          24 :   if (!IsReady()) {
     882           0 :     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
     883           0 :     return DrawResult::BAD_ARGS;
     884             :   }
     885          24 :   if (aFill.IsEmpty() || aSrc.IsEmpty()) {
     886          21 :     return DrawResult::SUCCESS;
     887             :   }
     888             : 
     889           3 :   if (mType == eStyleImageType_Image || mType == eStyleImageType_Element) {
     890           0 :     nsCOMPtr<imgIContainer> subImage;
     891             : 
     892             :     // To draw one portion of an image into a border component, we stretch that
     893             :     // portion to match the size of that border component and then draw onto.
     894             :     // However, preserveAspectRatio attribute of a SVG image may break this rule.
     895             :     // To get correct rendering result, we add
     896             :     // FLAG_FORCE_PRESERVEASPECTRATIO_NONE flag here, to tell mImage to ignore
     897             :     // preserveAspectRatio attribute, and always do non-uniform stretch.
     898           0 :     uint32_t drawFlags = ConvertImageRendererToDrawFlags(mFlags) |
     899           0 :                            imgIContainer::FLAG_FORCE_PRESERVEASPECTRATIO_NONE;
     900             :     // For those SVG image sources which don't have fixed aspect ratio (i.e.
     901             :     // without viewport size and viewBox), we should scale the source uniformly
     902             :     // after the viewport size is decided by "Default Sizing Algorithm".
     903           0 :     if (!aHasIntrinsicRatio) {
     904           0 :       drawFlags = drawFlags | imgIContainer::FLAG_FORCE_UNIFORM_SCALING;
     905             :     }
     906             :     // Retrieve or create the subimage we'll draw.
     907           0 :     nsIntRect srcRect(aSrc.x, aSrc.y, aSrc.width, aSrc.height);
     908           0 :     if (mType == eStyleImageType_Image) {
     909           0 :       if ((subImage = mImage->GetSubImage(aIndex)) == nullptr) {
     910           0 :         subImage = ImageOps::Clip(mImageContainer, srcRect, aSVGViewportSize);
     911           0 :         mImage->SetSubImage(aIndex, subImage);
     912             :       }
     913             :     } else {
     914             :       // This path, for eStyleImageType_Element, is currently slower than it
     915             :       // needs to be because we don't cache anything. (In particular, if we have
     916             :       // to draw to a temporary surface inside ClippedImage, we don't cache that
     917             :       // temporary surface since we immediately throw the ClippedImage we create
     918             :       // here away.) However, if we did cache, we'd need to know when to
     919             :       // invalidate that cache, and it's not clear that it's worth the trouble
     920             :       // since using border-image with -moz-element is rare.
     921             : 
     922             :       RefPtr<gfxDrawable> drawable =
     923           0 :         DrawableForElement(nsRect(nsPoint(), mSize),
     924           0 :                            aRenderingContext);
     925           0 :       if (!drawable) {
     926           0 :         NS_WARNING("Could not create drawable for element");
     927           0 :         return DrawResult::TEMPORARY_ERROR;
     928             :       }
     929             : 
     930           0 :       nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
     931           0 :       subImage = ImageOps::Clip(image, srcRect, aSVGViewportSize);
     932             :     }
     933             : 
     934           0 :     MOZ_ASSERT(!aSVGViewportSize ||
     935             :                subImage->GetType() == imgIContainer::TYPE_VECTOR);
     936             : 
     937           0 :     SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(mForFrame);
     938             : 
     939           0 :     if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
     940           0 :       return nsLayoutUtils::DrawSingleImage(aRenderingContext,
     941             :                                             aPresContext,
     942             :                                             subImage,
     943             :                                             samplingFilter,
     944             :                                             aFill, aDirtyRect,
     945           0 :                                             /* no SVGImageContext */ Nothing(),
     946           0 :                                             drawFlags);
     947             :     }
     948             : 
     949           0 :     nsSize repeatSize;
     950           0 :     nsRect fillRect(aFill);
     951           0 :     nsRect tile = ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize);
     952           0 :     CSSIntSize imageSize(srcRect.width, srcRect.height);
     953           0 :     return nsLayoutUtils::DrawBackgroundImage(aRenderingContext,
     954             :                                               mForFrame, aPresContext,
     955             :                                               subImage, imageSize, samplingFilter,
     956             :                                               tile, fillRect, repeatSize,
     957           0 :                                               tile.TopLeft(), aDirtyRect,
     958             :                                               drawFlags,
     959           0 :                                               ExtendMode::CLAMP, 1.0);
     960             :   }
     961             : 
     962           3 :   nsSize repeatSize(aFill.Size());
     963           6 :   nsRect fillRect(aFill);
     964           3 :   nsRect destTile = RequiresScaling(fillRect, aHFill, aVFill, aUnitSize)
     965             :                   ? ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize)
     966           6 :                   : fillRect;
     967             :   return Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
     968           3 :               fillRect, destTile.TopLeft(), repeatSize, aSrc);
     969             : }
     970             : 
     971             : bool
     972         194 : nsImageRenderer::IsRasterImage()
     973             : {
     974         194 :   if (mType != eStyleImageType_Image || !mImageContainer)
     975          50 :     return false;
     976         144 :   return mImageContainer->GetType() == imgIContainer::TYPE_RASTER;
     977             : }
     978             : 
     979             : bool
     980           0 : nsImageRenderer::IsAnimatedImage()
     981             : {
     982           0 :   if (mType != eStyleImageType_Image || !mImageContainer)
     983           0 :     return false;
     984           0 :   bool animated = false;
     985           0 :   if (NS_SUCCEEDED(mImageContainer->GetAnimated(&animated)) && animated)
     986           0 :     return true;
     987             : 
     988           0 :   return false;
     989             : }
     990             : 
     991             : already_AddRefed<imgIContainer>
     992          72 : nsImageRenderer::GetImage()
     993             : {
     994          72 :   if (mType != eStyleImageType_Image || !mImageContainer) {
     995           0 :     return nullptr;
     996             :   }
     997             : 
     998         144 :   nsCOMPtr<imgIContainer> image = mImageContainer;
     999          72 :   return image.forget();
    1000             : }
    1001             : 
    1002             : bool
    1003           0 : nsImageRenderer::IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags)
    1004             : {
    1005           0 :   if (!mImageContainer) {
    1006           0 :     return false;
    1007             :   }
    1008           0 :   return mImageContainer->IsImageContainerAvailable(aManager, aFlags);
    1009             : }
    1010             : 
    1011             : void
    1012           3 : nsImageRenderer::PurgeCacheForViewportChange(
    1013             :   const Maybe<nsSize>& aSVGViewportSize, const bool aHasIntrinsicRatio)
    1014             : {
    1015             :   // Check if we should flush the cached data - only vector images need to do
    1016             :   // the check since they might not have fixed ratio.
    1017           3 :   if (mImageContainer &&
    1018           3 :       mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
    1019           0 :     mImage->PurgeCacheForViewportChange(aSVGViewportSize, aHasIntrinsicRatio);
    1020             :   }
    1021           3 : }
    1022             : 
    1023             : already_AddRefed<nsStyleGradient>
    1024           0 : nsImageRenderer::GetGradientData()
    1025             : {
    1026           0 :   RefPtr<nsStyleGradient> res = mGradientData;
    1027           0 :   return res.forget();
    1028           9 : }
    1029             : 

Generated by: LCOV version 1.13