NS_IMETHODIMP
nsSimplePageSequenceFrame::PrePrintNextPage(nsITimerCallback* aCallback, bool* aDone)
{
  nsIFrame* currentPage = GetCurrentPageFrame();
  if (!currentPage) {
    *aDone = true;
    return NS_ERROR_FAILURE;
  }

  DetermineWhetherToPrintPage();
  // Nothing to do if the current page doesn't get printed OR rendering to
  // preview. For preview, the `CallPrintCallback` is called from within the
  // HTMLCanvasElement::HandlePrintCallback.
  if (!mPrintThisPage || !PresContext()->IsRootPaginatedDocument()) {
    *aDone = true;
    return NS_OK;
  }

  // If the canvasList is null, then generate it and start the render
  // process for all the canvas.
  if (!mCurrentCanvasListSetup) {
    mCurrentCanvasListSetup = true;
    GetPrintCanvasElementsInFrame(currentPage, &mCurrentCanvasList);

    if (mCurrentCanvasList.Length() != 0) {
      nsresult rv = NS_OK;

      // Begin printing of the document
      nsDeviceContext *dc = PresContext()->DeviceContext();
      PR_PL(("\n"));
      PR_PL(("***************** BeginPage *****************\n"));
      rv = dc->BeginPage();
      NS_ENSURE_SUCCESS(rv, rv);

      mCalledBeginPage = true;

      RefPtr<gfxContext> renderingContext = dc->CreateRenderingContext();
      NS_ENSURE_TRUE(renderingContext, NS_ERROR_OUT_OF_MEMORY);

      DrawTarget* drawTarget = renderingContext->GetDrawTarget();
      if (NS_WARN_IF(!drawTarget)) {
        return NS_ERROR_FAILURE;
      }

      for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
        HTMLCanvasElement* canvas = mCurrentCanvasList[i];
        nsIntSize size = canvas->GetSize();

        RefPtr<DrawTarget> canvasTarget =
          drawTarget->CreateSimilarDrawTarget(size, drawTarget->GetFormat());
        if (!canvasTarget) {
          continue;
        }

        nsICanvasRenderingContextInternal* ctx = canvas->GetContextAtIndex(0);
        if (!ctx) {
          continue;
        }

        // Initialize the context with the new DrawTarget.
        ctx->InitializeWithDrawTarget(nullptr, WrapNotNull(canvasTarget));

        // Start the rendering process.
        AutoWeakFrame weakFrame = this;
        canvas->DispatchPrintCallback(aCallback);
        NS_ENSURE_STATE(weakFrame.IsAlive());
      }
    }
  }
  uint32_t doneCounter = 0;
  for (int32_t i = mCurrentCanvasList.Length() - 1; i >= 0 ; i--) {
    HTMLCanvasElement* canvas = mCurrentCanvasList[i];

    if (canvas->IsPrintCallbackDone()) {
      doneCounter++;
    }
  }
  // If all canvas have finished rendering, return true, otherwise false.
  *aDone = doneCounter == mCurrentCanvasList.Length();

  return NS_OK;
}
Пример #2
0
DrawResult
nsSVGClipPathFrame::PaintClipMask(gfxContext& aMaskContext,
                                  nsIFrame* aClippedFrame,
                                  const gfxMatrix& aMatrix,
                                  Matrix* aMaskTransform,
                                  SourceSurface* aExtraMask,
                                  const Matrix& aExtraMasksTransform)
{
    // A clipPath can reference another clipPath.  We re-enter this method for
    // each clipPath in a reference chain, so here we limit chain length:
    static int16_t sRefChainLengthCounter = AutoReferenceLimiter::notReferencing;
    AutoReferenceLimiter
    refChainLengthLimiter(&sRefChainLengthCounter,
                          MAX_SVG_CLIP_PATH_REFERENCE_CHAIN_LENGTH);
    if (!refChainLengthLimiter.Reference()) {
        return DrawResult::SUCCESS; // Reference chain is too long!
    }

    // And to prevent reference loops we check that this clipPath only appears
    // once in the reference chain (if any) that we're currently processing:
    AutoReferenceLimiter refLoopDetector(&mReferencing, 1);
    if (!refLoopDetector.Reference()) {
        return DrawResult::SUCCESS; // Reference loop!
    }

    DrawResult result = DrawResult::SUCCESS;
    DrawTarget* maskDT = aMaskContext.GetDrawTarget();
    MOZ_ASSERT(maskDT->GetFormat() == SurfaceFormat::A8);

    // Paint this clipPath's contents into aMaskDT:
    // We need to set mMatrixForChildren here so that under the PaintSVG calls
    // on our children (below) our GetCanvasTM() method will return the correct
    // transform.
    mMatrixForChildren = GetClipPathTransform(aClippedFrame) * aMatrix;

    // Check if this clipPath is itself clipped by another clipPath:
    nsSVGClipPathFrame* clipPathThatClipsClipPath =
        nsSVGEffects::GetEffectProperties(this).GetClipPathFrame();
    nsSVGUtils::MaskUsage maskUsage;
    nsSVGUtils::DetermineMaskUsage(this, true, maskUsage);

    if (maskUsage.shouldApplyClipPath) {
        clipPathThatClipsClipPath->ApplyClipPath(aMaskContext, aClippedFrame,
                aMatrix);
    } else if (maskUsage.shouldGenerateClipMaskLayer) {
        Matrix maskTransform;
        RefPtr<SourceSurface> maskSurface;
        Tie(result, maskSurface) =
            clipPathThatClipsClipPath->GetClipMask(aMaskContext, aClippedFrame,
                    aMatrix, &maskTransform);
        aMaskContext.PushGroupForBlendBack(gfxContentType::ALPHA, 1.0,
                                           maskSurface, maskTransform);
        // The corresponding PopGroupAndBlend call below will mask the
        // blend using |maskSurface|.
    }

    // Paint our children into the mask:
    for (nsIFrame* kid = mFrames.FirstChild(); kid;
            kid = kid->GetNextSibling()) {
        result &= PaintFrameIntoMask(kid, aClippedFrame, aMaskContext, aMatrix);
    }

    if (maskUsage.shouldGenerateClipMaskLayer) {
        aMaskContext.PopGroupAndBlend();
    } else if (maskUsage.shouldApplyClipPath) {
        aMaskContext.PopClip();
    }

    // Moz2D transforms in the opposite direction to Thebes
    gfxMatrix maskTransfrom = aMaskContext.CurrentMatrix();
    maskTransfrom.Invert();

    if (aExtraMask) {
        ComposeExtraMask(maskDT, maskTransfrom, aExtraMask, aExtraMasksTransform);
    }

    *aMaskTransform = ToMatrix(maskTransfrom);
    return result;
}
Пример #3
0
/***
 * If we can, let's paint this ClientPaintedLayer's contents off the main thread.
 * The essential idea is that we ask the ContentClient for a DrawTarget and record
 * the moz2d commands. On the Paint Thread, we replay those commands to the
 * destination draw target. There are a couple of lifetime issues here though:
 *
 * 1) TextureClient owns the underlying buffer and DrawTarget. Because of this
 *    we have to keep the TextureClient and DrawTarget alive but trick the
 *    TextureClient into thinking it's already returned the DrawTarget
 *    since we iterate through different Rects to get DrawTargets*. If
 *    the TextureClient goes away, the DrawTarget and thus buffer can too.
 * 2) When ContentClient::EndPaint happens, it flushes the DrawTarget. We have
 *    to Reflush on the Paint Thread
 * 3) DrawTarget API is NOT thread safe. We get around this by recording
 *    on the main thread and painting on the paint thread. Logically,
 *    ClientLayerManager will force a flushed paint and block the main thread
 *    if we have another transaction. Thus we have a gap between when the main
 *    thread records, the paint thread paints, and we block the main thread
 *    from trying to paint again. The underlying API however is NOT thread safe.
 *  4) We have both "sync" and "async" OMTP. Sync OMTP means we paint on the main thread
 *     but block the main thread while the paint thread paints. Async OMTP doesn't block
 *     the main thread. Sync OMTP is only meant to be used as a debugging tool.
 */
bool
ClientPaintedLayer::PaintOffMainThread()
{
  mContentClient->BeginAsyncPaint();

  uint32_t flags = GetPaintFlags();

  PaintState state = mContentClient->BeginPaintBuffer(this, flags);
  if (!UpdatePaintRegion(state)) {
    return false;
  }

  bool didUpdate = false;
  RotatedContentBuffer::DrawIterator iter;

  // Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
  while (RefPtr<CapturedPaintState> captureState =
          mContentClient->BorrowDrawTargetForRecording(state, &iter))
  {
    DrawTarget* target = captureState->mTarget;
    if (!target || !target->IsValid()) {
      if (target) {
        mContentClient->ReturnDrawTargetToBuffer(target);
      }
      continue;
    }

    RefPtr<DrawTargetCapture> captureDT =
      Factory::CreateCaptureDrawTarget(target->GetBackendType(),
                                       target->GetSize(),
                                       target->GetFormat());

    captureDT->SetTransform(captureState->mTargetTransform);
    SetAntialiasingFlags(this, captureDT);

    RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
    MOZ_ASSERT(ctx); // already checked the target above

    ClientManager()->GetPaintedLayerCallback()(this,
                                              ctx,
                                              iter.mDrawRegion,
                                              iter.mDrawRegion,
                                              state.mClip,
                                              state.mRegionToInvalidate,
                                              ClientManager()->GetPaintedLayerCallbackData());

    ctx = nullptr;

    captureState->mCapture = captureDT.forget();
    PaintThread::Get()->PaintContents(captureState,
                                      RotatedContentBuffer::PrepareDrawTargetForPainting);

    mContentClient->ReturnDrawTargetToBuffer(target);

    didUpdate = true;
  }
  mContentClient->EndPaint(nullptr);

  if (didUpdate) {
    UpdateContentClient(state);
  }
  return true;
}