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 "ClientPaintedLayer.h"
8 #include "ClientTiledPaintedLayer.h"    // for ClientTiledPaintedLayer
9 #include <stdint.h>                     // for uint32_t
10 #include "client/ClientLayerManager.h"  // for ClientLayerManager, etc
11 #include "gfxContext.h"                 // for gfxContext
12 #include "gfx2DGlue.h"
13 #include "gfxEnv.h"   // for gfxEnv
14 #include "gfxRect.h"  // for gfxRect
15 
16 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
17 #include "mozilla/gfx/2D.h"      // for DrawTarget
18 #include "mozilla/gfx/DrawEventRecorder.h"
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 "mozilla/Preferences.h"
24 #include "mozilla/ProfilerLabels.h"
25 #include "nsCOMPtr.h"         // for already_AddRefed
26 #include "nsISupportsImpl.h"  // for Layer::AddRef, etc
27 #include "nsRect.h"           // for mozilla::gfx::IntRect
28 #include "PaintThread.h"
29 #include "ReadbackProcessor.h"
30 #include "RotatedBuffer.h"
31 
32 namespace mozilla {
33 namespace layers {
34 
35 using namespace mozilla::gfx;
36 
EnsureContentClient()37 bool ClientPaintedLayer::EnsureContentClient() {
38   if (!mContentClient) {
39     mContentClient = ContentClient::CreateContentClient(
40         ClientManager()->AsShadowForwarder());
41 
42     if (!mContentClient) {
43       return false;
44     }
45 
46     mContentClient->Connect();
47     ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
48     MOZ_ASSERT(mContentClient->GetForwarder());
49   }
50 
51   return true;
52 }
53 
UpdateContentClient(PaintState & aState)54 void ClientPaintedLayer::UpdateContentClient(PaintState& aState) {
55   Mutated();
56 
57   AddToValidRegion(aState.mRegionToDraw);
58 
59   ContentClientRemoteBuffer* contentClientRemote =
60       static_cast<ContentClientRemoteBuffer*>(mContentClient.get());
61   MOZ_ASSERT(contentClientRemote->GetIPCHandle());
62 
63   // Hold(this) ensures this layer is kept alive through the current transaction
64   // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
65   // so deleting this Hold for whatever reason will break things.
66   ClientManager()->Hold(this);
67   contentClientRemote->Updated(aState.mRegionToDraw,
68                                mVisibleRegion.ToUnknownRegion());
69 }
70 
UpdatePaintRegion(PaintState & aState)71 bool ClientPaintedLayer::UpdatePaintRegion(PaintState& aState) {
72   SubtractFromValidRegion(aState.mRegionToInvalidate);
73 
74   if (!aState.mRegionToDraw.IsEmpty() &&
75       !ClientManager()->GetPaintedLayerCallback()) {
76     ClientManager()->SetTransactionIncomplete();
77     return false;
78   }
79 
80   // The area that became invalid and is visible needs to be repainted
81   // (this could be the whole visible area if our buffer switched
82   // from RGB to RGBA, because we might need to repaint with
83   // subpixel AA)
84   aState.mRegionToInvalidate.And(aState.mRegionToInvalidate,
85                                  GetLocalVisibleRegion().ToUnknownRegion());
86   return true;
87 }
88 
FinishPaintState(PaintState & aState)89 void ClientPaintedLayer::FinishPaintState(PaintState& aState) {
90   if (aState.mAsyncTask && !aState.mAsyncTask->mCapture->IsEmpty()) {
91     ClientManager()->SetQueuedAsyncPaints();
92     PaintThread::Get()->QueuePaintTask(std::move(aState.mAsyncTask));
93   }
94 }
95 
GetPaintFlags(ReadbackProcessor * aReadback)96 uint32_t ClientPaintedLayer::GetPaintFlags(ReadbackProcessor* aReadback) {
97   uint32_t flags = ContentClient::PAINT_CAN_DRAW_ROTATED;
98 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
99   if (ClientManager()->CompositorMightResample()) {
100     flags |= ContentClient::PAINT_WILL_RESAMPLE;
101   }
102   if (!(flags & ContentClient::PAINT_WILL_RESAMPLE)) {
103     if (MayResample()) {
104       flags |= ContentClient::PAINT_WILL_RESAMPLE;
105     }
106   }
107 #endif
108   if ((!aReadback || !UsedForReadback()) && PaintThread::Get()) {
109     flags |= ContentClient::PAINT_ASYNC;
110   }
111   return flags;
112 }
113 
RenderLayerWithReadback(ReadbackProcessor * aReadback)114 void ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor* aReadback) {
115   AUTO_PROFILER_LABEL("ClientPaintedLayer::RenderLayerWithReadback", GRAPHICS);
116   NS_ASSERTION(ClientManager()->InDrawing(), "Can only draw in drawing phase");
117 
118   RenderMaskLayers(this);
119 
120   if (!EnsureContentClient()) {
121     return;
122   }
123 
124   nsTArray<ReadbackProcessor::Update> readbackUpdates;
125   nsIntRegion readbackRegion;
126   if (aReadback && UsedForReadback()) {
127     aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
128   }
129 
130   uint32_t flags = GetPaintFlags(aReadback);
131 
132   PaintState state = mContentClient->BeginPaint(this, flags);
133   if (!UpdatePaintRegion(state)) {
134     mContentClient->EndPaint(state, nullptr);
135     FinishPaintState(state);
136     return;
137   }
138 
139   bool didUpdate = false;
140   RotatedBuffer::DrawIterator iter;
141   while (DrawTarget* target =
142              mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
143     SetAntialiasingFlags(this, target);
144 
145     RefPtr<gfxContext> ctx =
146         gfxContext::CreatePreservingTransformOrNull(target);
147     MOZ_ASSERT(ctx);  // already checked the target above
148 
149     if (!gfxEnv::SkipRasterization()) {
150       if (!target->IsCaptureDT()) {
151         target->ClearRect(Rect());
152         if (target->IsValid()) {
153           ClientManager()->GetPaintedLayerCallback()(
154               this, ctx, iter.mDrawRegion, iter.mDrawRegion, state.mClip,
155               state.mRegionToInvalidate,
156               ClientManager()->GetPaintedLayerCallbackData());
157         }
158       } else {
159         ClientManager()->GetPaintedLayerCallback()(
160             this, ctx, iter.mDrawRegion, iter.mDrawRegion, state.mClip,
161             state.mRegionToInvalidate,
162             ClientManager()->GetPaintedLayerCallbackData());
163       }
164     }
165 
166     ctx = nullptr;
167     mContentClient->ReturnDrawTarget(target);
168     didUpdate = true;
169   }
170 
171   mContentClient->EndPaint(state, &readbackUpdates);
172   FinishPaintState(state);
173 
174   if (didUpdate) {
175     UpdateContentClient(state);
176   }
177 }
178 
CreatePaintedLayer()179 already_AddRefed<PaintedLayer> ClientLayerManager::CreatePaintedLayer() {
180   return CreatePaintedLayerWithHint(NONE);
181 }
182 
CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)183 already_AddRefed<PaintedLayer> ClientLayerManager::CreatePaintedLayerWithHint(
184     PaintedLayerCreationHint aHint) {
185   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
186   if (gfxPlatform::GetPlatform()->UsesTiling()) {
187     RefPtr<ClientTiledPaintedLayer> layer =
188         new ClientTiledPaintedLayer(this, aHint);
189     CREATE_SHADOW(Painted);
190     return layer.forget();
191   } else {
192     RefPtr<ClientPaintedLayer> layer = new ClientPaintedLayer(this, aHint);
193     CREATE_SHADOW(Painted);
194     return layer.forget();
195   }
196 }
197 
PrintInfo(std::stringstream & aStream,const char * aPrefix)198 void ClientPaintedLayer::PrintInfo(std::stringstream& aStream,
199                                    const char* aPrefix) {
200   PaintedLayer::PrintInfo(aStream, aPrefix);
201   if (mContentClient) {
202     aStream << "\n";
203     nsAutoCString pfx(aPrefix);
204     pfx += "  ";
205     mContentClient->PrintInfo(aStream, pfx.get());
206   }
207 }
208 
209 }  // namespace layers
210 }  // namespace mozilla
211