void Layer::ApplyPendingUpdatesForThisTransaction() { if (mPendingTransform && *mPendingTransform != mTransform) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this)); mTransform = *mPendingTransform; Mutated(); } mPendingTransform = nullptr; if (mPendingAnimations) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this)); mPendingAnimations->SwapElements(mAnimations); mPendingAnimations = nullptr; Mutated(); } }
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 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?"); } } }
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 Layer::SetAnimations(const AnimationArray& aAnimations) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) SetAnimations", this)); mAnimations = aAnimations; mAnimationData.Clear(); for (uint32_t i = 0; i < mAnimations.Length(); i++) { AnimData* data = mAnimationData.AppendElement(); InfallibleTArray<nsAutoPtr<css::ComputedTimingFunction> >& functions = data->mFunctions; const InfallibleTArray<AnimationSegment>& segments = mAnimations.ElementAt(i).segments(); for (uint32_t j = 0; j < segments.Length(); j++) { TimingFunction tf = segments.ElementAt(j).sampleFn(); css::ComputedTimingFunction* ctf = new css::ComputedTimingFunction(); switch (tf.type()) { case TimingFunction::TCubicBezierFunction: { CubicBezierFunction cbf = tf.get_CubicBezierFunction(); ctf->Init(nsTimingFunction(cbf.x1(), cbf.y1(), cbf.x2(), cbf.y2())); break; } default: { NS_ASSERTION(tf.type() == TimingFunction::TStepFunction, "Function must be bezier or step"); StepFunction sf = tf.get_StepFunction(); nsTimingFunction::Type type = sf.type() == 1 ? nsTimingFunction::StepStart : nsTimingFunction::StepEnd; ctf->Init(nsTimingFunction(type, sf.steps())); break; } } functions.AppendElement(ctf); } // Precompute the nsStyleAnimation::Values that we need if this is a transform // animation. InfallibleTArray<nsStyleAnimation::Value>& startValues = data->mStartValues; InfallibleTArray<nsStyleAnimation::Value>& endValues = data->mEndValues; for (uint32_t j = 0; j < mAnimations[i].segments().Length(); j++) { const AnimationSegment& segment = mAnimations[i].segments()[j]; nsStyleAnimation::Value* startValue = startValues.AppendElement(); nsStyleAnimation::Value* endValue = endValues.AppendElement(); if (segment.endState().type() == Animatable::TArrayOfTransformFunction) { const InfallibleTArray<TransformFunction>& startFunctions = segment.startState().get_ArrayOfTransformFunction(); startValue->SetTransformValue(CreateCSSValueList(startFunctions)); const InfallibleTArray<TransformFunction>& endFunctions = segment.endState().get_ArrayOfTransformFunction(); endValue->SetTransformValue(CreateCSSValueList(endFunctions)); } else { NS_ASSERTION(segment.endState().type() == Animatable::Tfloat, "Unknown Animatable type"); startValue->SetFloatValue(segment.startState().get_float()); endValue->SetFloatValue(segment.endState().get_float()); } } } Mutated(); }
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); } }