void ThebesLayerComposite::RenderLayer(const nsIntPoint& aOffset, const nsIntRect& aClipRect) { if (!mBuffer || !mBuffer->IsAttached()) { return; } MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() && mBuffer->GetLayer() == this, "buffer is corrupted"); gfx::Matrix4x4 transform; ToMatrix4x4(GetEffectiveTransform(), transform); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsRefPtr<gfxImageSurface> surf = mBuffer->GetAsSurface(); WriteSnapshotToDumpFile(this, surf); } #endif EffectChain effectChain; LayerManagerComposite::AddMaskEffect(mMaskLayer, effectChain); nsIntRegion visibleRegion = GetEffectiveVisibleRegion(); TiledLayerProperties tiledLayerProps; if (mRequiresTiledProperties) { // calculating these things can be a little expensive, so don't // do them if we don't have to tiledLayerProps.mVisibleRegion = visibleRegion; tiledLayerProps.mDisplayPort = GetDisplayPort(); tiledLayerProps.mEffectiveResolution = GetEffectiveResolution(); tiledLayerProps.mCompositionBounds = GetCompositionBounds(); tiledLayerProps.mRetainTiles = !mIsFixedPosition; tiledLayerProps.mValidRegion = mValidRegion; } mBuffer->SetPaintWillResample(MayResample()); mBuffer->Composite(effectChain, GetEffectiveOpacity(), transform, gfx::Point(aOffset.x, aOffset.y), gfx::FILTER_LINEAR, clipRect, &visibleRegion, mRequiresTiledProperties ? &tiledLayerProps : nullptr); if (mRequiresTiledProperties) { mValidRegion = tiledLayerProps.mValidRegion; } LayerManagerComposite::RemoveMaskEffect(mMaskLayer); mCompositeManager->GetCompositor()->MakeCurrent(); }
void ClientThebesLayer::PaintThebes() { PROFILER_LABEL("ClientThebesLayer", "PaintThebes"); NS_ASSERTION(ClientManager()->InDrawing(), "Can only draw in drawing phase"); //TODO: This is going to copy back pixels that we might end up // drawing over anyway. It would be nice if we could avoid // this duplication. mContentClient->SyncFrontBufferToBackBuffer(); bool canUseOpaqueSurface = CanUseOpaqueSurface(); ContentType contentType = canUseOpaqueSurface ? GFX_CONTENT_COLOR : GFX_CONTENT_COLOR_ALPHA; { uint32_t flags = 0; #ifndef MOZ_WIDGET_ANDROID if (ClientManager()->CompositorMightResample()) { flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; } } #endif PaintState state = mContentClient->BeginPaintBuffer(this, contentType, flags); mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); if (state.mContext) { // The area that became invalid and is visible needs to be repainted // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, GetEffectiveVisibleRegion()); nsIntRegion extendedDrawRegion = state.mRegionToDraw; SetAntialiasingFlags(this, state.mContext); PaintBuffer(state.mContext, state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, state.mDidSelfCopy, state.mClip); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); } else { // It's possible that state.mRegionToInvalidate is nonempty here, // if we are shrinking the valid region to nothing. So use mRegionToDraw // instead. NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), "No context when we have something to draw, resource exhaustion?"); } } }
void ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect) { if (!mBuffer || !mBuffer->IsAttached()) { return; } PROFILER_LABEL("ThebesLayerComposite", "RenderLayer", js::ProfileEntry::Category::GRAPHICS); MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() && mBuffer->GetLayer() == this, "buffer is corrupted"); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface(); if (surf) { WriteSnapshotToDumpFile(this, surf); } } #endif EffectChain effectChain(this); LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain); AddBlendModeEffect(effectChain); const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion(); TiledLayerProperties tiledLayerProps; if (mRequiresTiledProperties) { tiledLayerProps.mVisibleRegion = visibleRegion; tiledLayerProps.mEffectiveResolution = GetEffectiveResolution(); tiledLayerProps.mValidRegion = mValidRegion; } mBuffer->SetPaintWillResample(MayResample()); mBuffer->Composite(effectChain, GetEffectiveOpacity(), GetEffectiveTransform(), gfx::Filter::LINEAR, clipRect, &visibleRegion, mRequiresTiledProperties ? &tiledLayerProps : nullptr); mBuffer->BumpFlashCounter(); if (mRequiresTiledProperties) { mValidRegion = tiledLayerProps.mValidRegion; } mCompositeManager->GetCompositor()->MakeCurrent(); }
void ClientThebesLayer::PaintThebes() { PROFILER_LABEL("ClientThebesLayer", "PaintThebes"); NS_ASSERTION(ClientManager()->InDrawing(), "Can only draw in drawing phase"); { mContentClient->PrepareFrame(); uint32_t flags = 0; #ifndef MOZ_WIDGET_ANDROID if (ClientManager()->CompositorMightResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } } #endif PaintState state = mContentClient->BeginPaintBuffer(this, flags); mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); if (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(this, state)) { // The area that became invalid and is visible needs to be repainted // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, GetEffectiveVisibleRegion()); SetAntialiasingFlags(this, target); nsRefPtr<gfxContext> ctx = gfxContext::ContextForDrawTarget(target); PaintBuffer(ctx, state.mRegionToDraw, state.mRegionToDraw, state.mRegionToInvalidate, state.mDidSelfCopy, state.mClip); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); ctx = nullptr; mContentClient->ReturnDrawTargetToBuffer(target); } else { // It's possible that state.mRegionToInvalidate is nonempty here, // if we are shrinking the valid region to nothing. So use mRegionToDraw // instead. NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), "No context when we have something to draw, resource exhaustion?"); } } }
uint32_t ClientPaintedLayer::GetPaintFlags() { uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED; #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE if (ClientManager()->CompositorMightResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } } #endif return flags; }
void PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect) { if (!mBuffer || !mBuffer->IsAttached()) { return; } PROFILER_LABEL("PaintedLayerComposite", "RenderLayer", js::ProfileEntry::Category::GRAPHICS); Compositor* compositor = mCompositeManager->GetCompositor(); MOZ_ASSERT(mBuffer->GetCompositor() == compositor && mBuffer->GetLayer() == this, "buffer is corrupted"); const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion(); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface(); if (surf) { WriteSnapshotToDumpFile(this, surf); } } #endif RenderWithAllMasks(this, compositor, aClipRect, [&](EffectChain& effectChain, const Rect& clipRect) { mBuffer->SetPaintWillResample(MayResample()); mBuffer->Composite(this, effectChain, GetEffectiveOpacity(), GetEffectiveTransform(), GetEffectFilter(), clipRect, &visibleRegion); }); mBuffer->BumpFlashCounter(); compositor->MakeCurrent(); }
void ClientTiledPaintedLayer::RenderLayer() { LayerManager::DrawPaintedLayerCallback callback = ClientManager()->GetPaintedLayerCallback(); void *data = ClientManager()->GetPaintedLayerCallbackData(); if (!callback) { ClientManager()->SetTransactionIncomplete(); return; } if (!mContentClient) { mContentClient = new TiledContentClient(this, ClientManager()); mContentClient->Connect(); ClientManager()->AsShadowForwarder()->Attach(mContentClient, this); MOZ_ASSERT(mContentClient->GetForwarder()); } if (mContentClient->mTiledBuffer.HasFormatChanged()) { mValidRegion = nsIntRegion(); mContentClient->mTiledBuffer.ResetPaintedAndValidState(); } TILING_LOG("TILING %p: Initial visible region %s\n", this, Stringify(mVisibleRegion).c_str()); TILING_LOG("TILING %p: Initial valid region %s\n", this, Stringify(mValidRegion).c_str()); TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str()); nsIntRegion neededRegion = mVisibleRegion; #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE // This is handled by PadDrawTargetOutFromRegion in TiledContentClient for mobile if (MayResample()) { // If we're resampling then bilinear filtering can read up to 1 pixel // outside of our texture coords. Make the visible region a single rect, // and pad it out by 1 pixel (restricted to tile boundaries) so that // we always have valid content or transparent pixels to sample from. nsIntRect bounds = neededRegion.GetBounds(); nsIntRect wholeTiles = bounds; wholeTiles.Inflate(nsIntSize( gfxPlatform::GetPlatform()->GetTileWidth(), gfxPlatform::GetPlatform()->GetTileHeight())); nsIntRect padded = bounds; padded.Inflate(1); padded.IntersectRect(padded, wholeTiles); neededRegion = padded; } #endif nsIntRegion invalidRegion; invalidRegion.Sub(neededRegion, mValidRegion); if (invalidRegion.IsEmpty()) { EndPaint(); return; } if (!ClientManager()->IsRepeatTransaction()) { // Only paint the mask layer on the first transaction. if (GetMaskLayer()) { ToClientLayer(GetMaskLayer())->RenderLayer(); } // In some cases we can take a fast path and just be done with it. if (UseFastPath()) { TILING_LOG("TILING %p: Taking fast-path\n", this); mValidRegion = neededRegion; mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data); ClientManager()->Hold(this); mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER); return; } // For more complex cases we need to calculate a bunch of metrics before we // can do the paint. BeginPaint(); if (mPaintData.mPaintFinished) { return; } // Make sure that tiles that fall outside of the visible region or outside of the // critical displayport are discarded on the first update. Also make sure that we // only draw stuff inside the critical displayport on the first update. mValidRegion.And(mValidRegion, neededRegion); if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); } TILING_LOG("TILING %p: First-transaction valid region %s\n", this, Stringify(mValidRegion).c_str()); TILING_LOG("TILING %p: First-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str()); } else { if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); } TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str()); } nsIntRegion lowPrecisionInvalidRegion; if (gfxPrefs::UseLowPrecisionBuffer()) { // Calculate the invalid region for the low precision buffer. Make sure // to remove the valid high-precision area so we don't double-paint it. lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion); lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion); } TILING_LOG("TILING %p: Low-precision invalid region %s\n", this, Stringify(lowPrecisionInvalidRegion).c_str()); bool updatedHighPrecision = RenderHighPrecision(invalidRegion, neededRegion, callback, data); if (updatedHighPrecision) { ClientManager()->Hold(this); mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER); if (!mPaintData.mPaintFinished) { // There is still more high-res stuff to paint, so we're not // done yet. A subsequent transaction will take care of this. ClientManager()->SetRepeatTransaction(); return; } } // If there is nothing to draw in low-precision, then we're done. if (lowPrecisionInvalidRegion.IsEmpty()) { EndPaint(); return; } if (updatedHighPrecision) { // If there are low precision updates, but we just did some high-precision // updates, then mark the paint as unfinished and request a repeat transaction. // This is so that we don't perform low-precision updates in the same transaction // as high-precision updates. TILING_LOG("TILING %p: Scheduling repeat transaction for low-precision painting\n", this); ClientManager()->SetRepeatTransaction(); mPaintData.mLowPrecisionPaintCount = 1; mPaintData.mPaintFinished = false; return; } bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion, neededRegion, callback, data); if (updatedLowPrecision) { ClientManager()->Hold(this); mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER); if (!mPaintData.mPaintFinished) { // There is still more low-res stuff to paint, so we're not // done yet. A subsequent transaction will take care of this. ClientManager()->SetRepeatTransaction(); return; } } // If we get here, we've done all the high- and low-precision // paints we wanted to do, so we can finish the paint and chill. EndPaint(); }
void BasicThebesLayer::PaintThebes(gfxContext* aContext, Layer* aMaskLayer, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData, ReadbackProcessor* aReadback) { PROFILER_LABEL("BasicThebesLayer", "PaintThebes"); NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase"); nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface(); if (!mContentClient) { // we pass a null pointer for the Forwarder argument, which means // this will not have a ContentHost on the other side. mContentClient = new ContentClientBasic(nullptr, BasicManager()); } nsTArray<ReadbackProcessor::Update> readbackUpdates; if (aReadback && UsedForReadback()) { aReadback->GetThebesLayerUpdates(this, &readbackUpdates); } //TODO: This is going to copy back pixels that we might end up // drawing over anyway. It would be nice if we could avoid // this duplication. mContentClient->SyncFrontBufferToBackBuffer(); bool canUseOpaqueSurface = CanUseOpaqueSurface(); ContentType contentType = canUseOpaqueSurface ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA; float opacity = GetEffectiveOpacity(); if (!BasicManager()->IsRetained()) { NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer"); mValidRegion.SetEmpty(); mContentClient->Clear(); nsIntRegion toDraw = IntersectWithClip(GetEffectiveVisibleRegion(), aContext); RenderTraceInvalidateStart(this, "FFFF00", toDraw.GetBounds()); if (!toDraw.IsEmpty() && !IsHidden()) { if (!aCallback) { BasicManager()->SetTransactionIncomplete(); return; } aContext->Save(); bool needsClipToVisibleRegion = GetClipToVisibleRegion(); bool needsGroup = opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER || aMaskLayer; nsRefPtr<gfxContext> groupContext; if (needsGroup) { groupContext = BasicManager()->PushGroupForLayer(aContext, this, toDraw, &needsClipToVisibleRegion); if (GetOperator() != gfxContext::OPERATOR_OVER) { needsClipToVisibleRegion = true; } } else { groupContext = aContext; } SetAntialiasingFlags(this, groupContext); aCallback(this, groupContext, toDraw, CLIP_NONE, nsIntRegion(), aCallbackData); if (needsGroup) { BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext); if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } AutoSetOperator setOperator(aContext, GetOperator()); PaintWithMask(aContext, opacity, aMaskLayer); } aContext->Restore(); } RenderTraceInvalidateEnd(this, "FFFF00"); return; } { uint32_t flags = 0; #ifndef MOZ_WIDGET_ANDROID if (BasicManager()->CompositorMightResample()) { flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & ThebesLayerBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE; } } #endif if (mDrawAtomically) { flags |= ThebesLayerBuffer::PAINT_NO_ROTATION; } PaintState state = mContentClient->BeginPaintBuffer(this, contentType, flags); mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); if (state.mContext) { // The area that became invalid and is visible needs to be repainted // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, GetEffectiveVisibleRegion()); nsIntRegion extendedDrawRegion = state.mRegionToDraw; SetAntialiasingFlags(this, state.mContext); RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds()); PaintBuffer(state.mContext, state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, state.mDidSelfCopy, state.mClip, aCallback, aCallbackData); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); RenderTraceInvalidateEnd(this, "FFFF00"); } else { // It's possible that state.mRegionToInvalidate is nonempty here, // if we are shrinking the valid region to nothing. So use mRegionToDraw // instead. NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), "No context when we have something to draw, resource exhaustion?"); } } if (BasicManager()->IsTransactionIncomplete()) return; gfxRect clipExtents; clipExtents = aContext->GetClipExtents(); // Pull out the mask surface and transform here, because the mask // is internal to basic layers AutoMaskData mask; gfxASurface* maskSurface = nullptr; const gfxMatrix* maskTransform = nullptr; if (GetMaskData(aMaskLayer, &mask)) { maskSurface = mask.GetSurface(); maskTransform = &mask.GetTransform(); } if (!IsHidden() && !clipExtents.IsEmpty()) { AutoSetOperator setOperator(aContext, GetOperator()); mContentClient->DrawTo(this, aContext, opacity, maskSurface, maskTransform); } for (uint32_t i = 0; i < readbackUpdates.Length(); ++i) { ReadbackProcessor::Update& update = readbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); nsRefPtr<gfxContext> ctx = update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (ctx) { NS_ASSERTION(opacity == 1.0, "Should only read back opaque layers"); ctx->Translate(gfxPoint(offset.x, offset.y)); mContentClient->DrawTo(this, ctx, 1.0, maskSurface, maskTransform); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } } }
void BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData) { if (!mContentClient) { // This client will have a null Forwarder, which means it will not have // a ContentHost on the other side. mContentClient = new ContentClientBasic(); } if (!BasicManager()->IsRetained()) { return; } uint32_t flags = 0; #ifndef MOZ_WIDGET_ANDROID if (BasicManager()->CompositorMightResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } } #endif if (mDrawAtomically) { flags |= RotatedContentBuffer::PAINT_NO_ROTATION; } PaintState state = mContentClient->BeginPaintBuffer(this, flags); mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); if (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state)) { // The area that became invalid and is visible needs to be repainted // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, GetEffectiveVisibleRegion()); SetAntialiasingFlags(this, target); RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds()); nsRefPtr<gfxContext> ctx = gfxContext::ContextForDrawTarget(target); PaintBuffer(ctx, state.mRegionToDraw, state.mRegionToDraw, state.mRegionToInvalidate, state.mDidSelfCopy, state.mClip, aCallback, aCallbackData); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); ctx = nullptr; mContentClient->ReturnDrawTargetToBuffer(target); RenderTraceInvalidateEnd(this, "FFFF00"); } else { // It's possible that state.mRegionToInvalidate is nonempty here, // if we are shrinking the valid region to nothing. So use mRegionToDraw // instead. NS_WARN_IF_FALSE(state.mRegionToDraw.IsEmpty(), "No context when we have something to draw, resource exhaustion?"); } }
void ClientThebesLayer::PaintThebes() { PROFILER_LABEL("ClientThebesLayer", "PaintThebes"); NS_ASSERTION(ClientManager()->InDrawing(), "Can only draw in drawing phase"); uint32_t flags = RotatedContentBuffer::PAINT_CAN_DRAW_ROTATED; #ifndef MOZ_WIDGET_ANDROID if (ClientManager()->CompositorMightResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } if (!(flags & RotatedContentBuffer::PAINT_WILL_RESAMPLE)) { if (MayResample()) { flags |= RotatedContentBuffer::PAINT_WILL_RESAMPLE; } } #endif PaintState state = mContentClient->BeginPaintBuffer(this, flags); mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate); if (!state.mRegionToDraw.IsEmpty() && !ClientManager()->GetThebesLayerCallback()) { ClientManager()->SetTransactionIncomplete(); return; } // The area that became invalid and is visible needs to be repainted // (this could be the whole visible area if our buffer switched // from RGB to RGBA, because we might need to repaint with // subpixel AA) state.mRegionToInvalidate.And(state.mRegionToInvalidate, GetEffectiveVisibleRegion()); bool didUpdate = false; RotatedContentBuffer::DrawIterator iter; while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) { SetAntialiasingFlags(this, target); nsRefPtr<gfxContext> ctx = gfxContext::ContextForDrawTarget(target); ClientManager()->GetThebesLayerCallback()(this, ctx, iter.mDrawRegion, state.mClip, state.mRegionToInvalidate, ClientManager()->GetThebesLayerCallbackData()); ctx = nullptr; mContentClient->ReturnDrawTargetToBuffer(target); didUpdate = true; } if (didUpdate) { Mutated(); mValidRegion.Or(mValidRegion, state.mRegionToDraw); ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get()); MOZ_ASSERT(contentClientRemote->GetIPDLActor()); // Hold(this) ensures this layer is kept alive through the current transaction // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer), // so deleting this Hold for whatever reason will break things. ClientManager()->Hold(this); contentClientRemote->Updated(state.mRegionToDraw, mVisibleRegion, state.mDidSelfCopy); } }