1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #include "BasicPaintedLayer.h"
8 #include <stdint.h>                // for uint32_t
9 #include "GeckoProfiler.h"         // for AUTO_PROFILER_LABEL
10 #include "ReadbackLayer.h"         // for ReadbackLayer, ReadbackSink
11 #include "ReadbackProcessor.h"     // for ReadbackProcessor::Update, etc
12 #include "RenderTrace.h"           // for RenderTraceInvalidateEnd, etc
13 #include "BasicLayersImpl.h"       // for AutoMaskData, etc
14 #include "gfxContext.h"            // for gfxContext, etc
15 #include "gfxRect.h"               // for gfxRect
16 #include "gfxUtils.h"              // for gfxUtils
17 #include "mozilla/gfx/2D.h"        // for DrawTarget
18 #include "mozilla/gfx/BaseRect.h"  // for BaseRect
19 #include "mozilla/gfx/Matrix.h"    // for Matrix
20 #include "mozilla/gfx/Rect.h"      // for Rect, IntRect
21 #include "mozilla/gfx/Types.h"     // for Float, etc
22 #include "mozilla/layers/LayersTypes.h"
23 #include "nsCOMPtr.h"         // for already_AddRefed
24 #include "nsISupportsImpl.h"  // for gfxContext::Release, etc
25 #include "nsPoint.h"          // for nsIntPoint
26 #include "nsRect.h"           // for mozilla::gfx::IntRect
27 #include "nsTArray.h"         // for nsTArray, nsTArray_Impl
28 #include "AutoMaskData.h"
29 #include "gfx2DGlue.h"
30 
31 namespace mozilla {
32 namespace layers {
33 
34 using namespace mozilla::gfx;
35 
IntersectWithClip(const nsIntRegion & aRegion,gfxContext * aContext)36 static nsIntRegion IntersectWithClip(const nsIntRegion& aRegion,
37                                      gfxContext* aContext) {
38   gfxRect clip = aContext->GetClipExtents();
39   nsIntRegion result;
40   result.And(aRegion, IntRect::RoundOut(clip.X(), clip.Y(), clip.Width(),
41                                         clip.Height()));
42   return result;
43 }
44 
PaintThebes(gfxContext * aContext,Layer * aMaskLayer,LayerManager::DrawPaintedLayerCallback aCallback,void * aCallbackData)45 void BasicPaintedLayer::PaintThebes(
46     gfxContext* aContext, Layer* aMaskLayer,
47     LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
48   AUTO_PROFILER_LABEL("BasicPaintedLayer::PaintThebes", GRAPHICS);
49 
50   NS_ASSERTION(BasicManager()->InDrawing(), "Can only draw in drawing phase");
51 
52   float opacity = GetEffectiveOpacity();
53   CompositionOp effectiveOperator = GetEffectiveOperator(this);
54 
55   if (!BasicManager()->IsRetained()) {
56     ClearValidRegion();
57     mContentClient->Clear();
58 
59     nsIntRegion toDraw =
60         IntersectWithClip(GetLocalVisibleRegion().ToUnknownRegion(), aContext);
61 
62     RenderTraceInvalidateStart(this, "FFFF00", toDraw.GetBounds());
63 
64     if (!toDraw.IsEmpty() && !IsHidden()) {
65       if (!aCallback) {
66         BasicManager()->SetTransactionIncomplete();
67         return;
68       }
69 
70       aContext->Save();
71 
72       bool needsGroup = opacity != 1.0 ||
73                         effectiveOperator != CompositionOp::OP_OVER ||
74                         aMaskLayer;
75       RefPtr<gfxContext> context = nullptr;
76       BasicLayerManager::PushedGroup group;
77       bool availableGroup = false;
78 
79       if (needsGroup) {
80         availableGroup =
81             BasicManager()->PushGroupForLayer(aContext, this, toDraw, group);
82         if (availableGroup) {
83           context = group.mGroupTarget;
84         }
85       } else {
86         context = aContext;
87       }
88       if (context) {
89         DrawTarget* target = context->GetDrawTarget();
90         bool oldAA = target->GetPermitSubpixelAA();
91         SetAntialiasingFlags(this, target);
92         aCallback(this, context, toDraw, toDraw, DrawRegionClip::NONE,
93                   nsIntRegion(), aCallbackData);
94         target->SetPermitSubpixelAA(oldAA);
95       }
96       if (needsGroup && availableGroup) {
97         BasicManager()->PopGroupForLayer(group);
98       }
99 
100       aContext->Restore();
101     }
102 
103     RenderTraceInvalidateEnd(this, "FFFF00");
104     return;
105   }
106 
107   if (BasicManager()->IsTransactionIncomplete()) return;
108 
109   gfxRect clipExtents;
110   clipExtents = aContext->GetClipExtents();
111 
112   // Pull out the mask surface and transform here, because the mask
113   // is internal to basic layers
114   AutoMoz2DMaskData mask;
115   SourceSurface* maskSurface = nullptr;
116   Matrix maskTransform;
117   if (GetMaskData(aMaskLayer, aContext->GetDeviceOffset(), &mask)) {
118     maskSurface = mask.GetSurface();
119     maskTransform = mask.GetTransform();
120   }
121 
122   if (!IsHidden() && !clipExtents.IsEmpty()) {
123     mContentClient->DrawTo(this, aContext->GetDrawTarget(), opacity,
124                            effectiveOperator, maskSurface, &maskTransform);
125   }
126 }
127 
Validate(LayerManager::DrawPaintedLayerCallback aCallback,void * aCallbackData,ReadbackProcessor * aReadback)128 void BasicPaintedLayer::Validate(
129     LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData,
130     ReadbackProcessor* aReadback) {
131   if (!mContentClient) {
132     // This client will have a null Forwarder, which means it will not have
133     // a ContentHost on the other side.
134     mContentClient = new ContentClientBasic(mBackend);
135   }
136 
137   if (!BasicManager()->IsRetained()) {
138     return;
139   }
140 
141   nsTArray<ReadbackProcessor::Update> readbackUpdates;
142   if (aReadback && UsedForReadback()) {
143     aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
144   }
145 
146   uint32_t flags = 0;
147 #ifndef MOZ_WIDGET_ANDROID
148   if (BasicManager()->CompositorMightResample()) {
149     flags |= ContentClient::PAINT_WILL_RESAMPLE;
150   }
151   if (!(flags & ContentClient::PAINT_WILL_RESAMPLE)) {
152     if (MayResample()) {
153       flags |= ContentClient::PAINT_WILL_RESAMPLE;
154     }
155   }
156 #endif
157   if (mDrawAtomically) {
158     flags |= ContentClient::PAINT_NO_ROTATION;
159   }
160   PaintState state = mContentClient->BeginPaint(this, flags);
161   SubtractFromValidRegion(state.mRegionToInvalidate);
162 
163   DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state);
164   if (target && target->IsValid()) {
165     // The area that became invalid and is visible needs to be repainted
166     // (this could be the whole visible area if our buffer switched
167     // from RGB to RGBA, because we might need to repaint with
168     // subpixel AA)
169     state.mRegionToInvalidate.And(state.mRegionToInvalidate,
170                                   GetLocalVisibleRegion().ToUnknownRegion());
171     SetAntialiasingFlags(this, target);
172 
173     RenderTraceInvalidateStart(this, "FFFF00", state.mRegionToDraw.GetBounds());
174 
175     RefPtr<gfxContext> ctx =
176         gfxContext::CreatePreservingTransformOrNull(target);
177     MOZ_ASSERT(ctx);  // already checked the target above
178 
179     PaintBuffer(ctx, state.mRegionToDraw, state.mRegionToDraw,
180                 state.mRegionToInvalidate, state.mClip, aCallback,
181                 aCallbackData);
182     MOZ_LAYERS_LOG_IF_SHADOWABLE(this,
183                                  ("Layer::Mutated(%p) PaintThebes", this));
184     Mutated();
185     ctx = nullptr;
186     mContentClient->ReturnDrawTarget(target);
187     target = nullptr;
188 
189     RenderTraceInvalidateEnd(this, "FFFF00");
190   } else {
191     if (target) {
192       mContentClient->ReturnDrawTarget(target);
193       target = nullptr;
194     }
195 
196     // It's possible that state.mRegionToInvalidate is nonempty here,
197     // if we are shrinking the valid region to nothing. So use mRegionToDraw
198     // instead.
199     NS_WARNING_ASSERTION(
200         state.mRegionToDraw.IsEmpty(),
201         "No context when we have something to draw, resource exhaustion?");
202   }
203 
204   for (uint32_t i = 0; i < readbackUpdates.Length(); ++i) {
205     ReadbackProcessor::Update& update = readbackUpdates[i];
206     nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset();
207     RefPtr<DrawTarget> dt = update.mLayer->GetSink()->BeginUpdate(
208         update.mUpdateRect + offset, update.mSequenceCounter);
209     if (dt) {
210       NS_ASSERTION(GetEffectiveOpacity() == 1.0,
211                    "Should only read back opaque layers");
212       NS_ASSERTION(!GetMaskLayer(),
213                    "Should only read back layers without masks");
214       dt->SetTransform(dt->GetTransform().PreTranslate(offset.x, offset.y));
215       mContentClient->DrawTo(this, dt, 1.0, CompositionOp::OP_OVER, nullptr,
216                              nullptr);
217       update.mLayer->GetSink()->EndUpdate(update.mUpdateRect + offset);
218     }
219   }
220 }
221 
CreatePaintedLayer()222 already_AddRefed<PaintedLayer> BasicLayerManager::CreatePaintedLayer() {
223   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
224 
225   BackendType backend = gfxPlatform::GetPlatform()->GetDefaultContentBackend();
226 
227   if (mDefaultTarget) {
228     backend = mDefaultTarget->GetDrawTarget()->GetBackendType();
229   } else if (mType == BLM_WIDGET) {
230     backend = gfxPlatform::GetPlatform()->GetContentBackendFor(
231         LayersBackend::LAYERS_BASIC);
232   }
233 
234   RefPtr<PaintedLayer> layer = new BasicPaintedLayer(this, backend);
235   return layer.forget();
236 }
237 
238 }  // namespace layers
239 }  // namespace mozilla
240