Example #1
0
VectorImage::Draw(gfxContext* aContext,
                  const nsIntSize& aSize,
                  const ImageRegion& aRegion,
                  uint32_t aWhichFrame,
                  SamplingFilter aSamplingFilter,
                  const Maybe<SVGImageContext>& aSVGContext,
                  uint32_t aFlags,
                  float aOpacity)
{
  if (aWhichFrame > FRAME_MAX_VALUE) {
    return DrawResult::BAD_ARGS;
  }

  if (!aContext) {
    return DrawResult::BAD_ARGS;
  }

  if (mError) {
    return DrawResult::BAD_IMAGE;
  }

  if (!mIsFullyLoaded) {
    return DrawResult::NOT_READY;
  }

  if (mAnimationConsumers == 0) {
    SendOnUnlockedDraw(aFlags);
  }

  MOZ_ASSERT(!(aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) ||
             (aSVGContext && aSVGContext->GetViewportSize()),
             "Viewport size is required when using "
             "FLAG_FORCE_PRESERVEASPECTRATIO_NONE");

  bool overridePAR = (aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext;

  bool haveContextPaint = aSVGContext && aSVGContext->GetContextPaint();
  bool blockContextPaint = false;
  if (haveContextPaint) {
    nsCOMPtr<nsIURI> imageURI = mURI->ToIURI();
    blockContextPaint = !SVGContextPaint::IsAllowedForImageFromURI(imageURI);
  }

  Maybe<SVGImageContext> newSVGContext;
  if (overridePAR || blockContextPaint) {
    // The key that we create for the image surface cache must match the way
    // that the image will be painted, so we need to initialize a new matching
    // SVGImageContext here in order to generate the correct key.

    newSVGContext = aSVGContext; // copy

    if (overridePAR) {
      // The SVGImageContext must take account of the preserveAspectRatio
      // overide:
      MOZ_ASSERT(!aSVGContext->GetPreserveAspectRatio(),
                 "FLAG_FORCE_PRESERVEASPECTRATIO_NONE is not expected if a "
                 "preserveAspectRatio override is supplied");
      Maybe<SVGPreserveAspectRatio> aspectRatio =
        Some(SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE,
                                    SVG_MEETORSLICE_UNKNOWN));
      newSVGContext->SetPreserveAspectRatio(aspectRatio);
    }

    if (blockContextPaint) {
      // The SVGImageContext must not include context paint if the image is
      // not allowed to use it:
      newSVGContext->ClearContextPaint();
    }
  }

  float animTime = (aWhichFrame == FRAME_FIRST)
                     ? 0.0f : mSVGDocumentWrapper->GetCurrentTime();

  SVGDrawingParameters params(aContext, aSize, aRegion, aSamplingFilter,
                              newSVGContext ? newSVGContext : aSVGContext,
                              animTime, aFlags, aOpacity);

  // If we have an prerasterized version of this image that matches the
  // drawing parameters, use that.
  RefPtr<gfxDrawable> svgDrawable = LookupCachedSurface(params);
  if (svgDrawable) {
    Show(svgDrawable, params);
    return DrawResult::SUCCESS;
  }

  // else, we need to paint the image:

  if (mIsDrawing) {
    NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
    return DrawResult::TEMPORARY_ERROR;
  }
  AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing);
  mIsDrawing = true;

  // Apply any 'preserveAspectRatio' override (if specified) to the root
  // element:
  AutoPreserveAspectRatioOverride autoPAR(newSVGContext ? newSVGContext : aSVGContext,
                                          mSVGDocumentWrapper->GetRootSVGElem());

  // Set the animation time:
  AutoSVGTimeSetRestore autoSVGTime(mSVGDocumentWrapper->GetRootSVGElem(),
                                    animTime);

  // Set context paint (if specified) on the document:
  Maybe<AutoSetRestoreSVGContextPaint> autoContextPaint;
  if (haveContextPaint && !blockContextPaint) {
    autoContextPaint.emplace(aSVGContext->GetContextPaint(),
                             mSVGDocumentWrapper->GetDocument());
  }

  // We didn't get a hit in the surface cache, so we'll need to rerasterize.
  CreateSurfaceAndShow(params, aContext->GetDrawTarget()->GetBackendType());
  return DrawResult::SUCCESS;
}