Bug 1632310 [wpt PR 23186] - Add test for computed versus resolved style., a=testonly
[gecko.git] / gfx / layers / AsyncCanvasRenderer.cpp
blob6666012adb54d45677163f584568576c841665e5
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/. */
7 #include "AsyncCanvasRenderer.h"
9 #include "gfxUtils.h"
10 #include "GLContext.h"
11 #include "GLReadTexImageHelper.h"
12 #include "GLScreenBuffer.h"
13 #include "Layers.h"
14 #include "mozilla/dom/HTMLCanvasElement.h"
15 #include "nsICanvasRenderingContextInternal.h"
16 #include "mozilla/layers/BufferTexture.h"
17 #include "mozilla/layers/CanvasClient.h"
18 #include "mozilla/layers/CompositableForwarder.h"
19 #include "mozilla/layers/TextureClient.h"
20 #include "mozilla/layers/TextureClientSharedSurface.h"
21 #include "mozilla/layers/ShadowLayers.h"
22 #include "mozilla/ReentrantMonitor.h"
23 #include "nsIRunnable.h"
24 #include "nsThreadUtils.h"
26 namespace mozilla {
27 namespace layers {
29 AsyncCanvasRenderer::AsyncCanvasRenderer()
30 : mHTMLCanvasElement(nullptr),
31 mContext(nullptr),
32 mGLContext(nullptr),
33 mIsAlphaPremultiplied(true),
34 mWidth(0),
35 mHeight(0),
36 mCanvasClient(nullptr),
37 mMutex("AsyncCanvasRenderer::mMutex"),
38 mContextType(dom::CanvasContextType::NoContext) {
39 MOZ_COUNT_CTOR(AsyncCanvasRenderer);
42 AsyncCanvasRenderer::~AsyncCanvasRenderer() {
43 MOZ_COUNT_DTOR(AsyncCanvasRenderer);
46 void AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() {
47 class Runnable final : public mozilla::Runnable {
48 public:
49 explicit Runnable(AsyncCanvasRenderer* aRenderer)
50 : mozilla::Runnable("Runnable"), mRenderer(aRenderer) {}
52 NS_IMETHOD Run() override {
53 if (mRenderer) {
54 dom::HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(mRenderer);
57 return NS_OK;
60 private:
61 RefPtr<AsyncCanvasRenderer> mRenderer;
64 nsCOMPtr<nsIRunnable> runnable = new Runnable(this);
65 nsresult rv = NS_DispatchToMainThread(runnable);
66 if (NS_FAILED(rv)) {
67 NS_WARNING("Failed to dispatch a runnable to the main-thread.");
71 void AsyncCanvasRenderer::NotifyElementAboutInvalidation() {
72 class Runnable final : public mozilla::Runnable {
73 public:
74 explicit Runnable(AsyncCanvasRenderer* aRenderer)
75 : mozilla::Runnable("Runnable"), mRenderer(aRenderer) {}
77 NS_IMETHOD Run() override {
78 if (mRenderer) {
79 dom::HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(mRenderer);
82 return NS_OK;
85 private:
86 RefPtr<AsyncCanvasRenderer> mRenderer;
89 nsCOMPtr<nsIRunnable> runnable = new Runnable(this);
90 nsresult rv = NS_DispatchToMainThread(runnable);
91 if (NS_FAILED(rv)) {
92 NS_WARNING("Failed to dispatch a runnable to the main-thread.");
96 void AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) {
97 mCanvasClient = aClient;
98 if (aClient) {
99 mCanvasClientAsyncHandle = aClient->GetAsyncHandle();
100 if (mContext) {
101 MOZ_ASSERT(mCanvasClient->GetForwarder() &&
102 mCanvasClient->GetForwarder()->AsLayerForwarder() &&
103 mCanvasClient->GetForwarder()
104 ->AsLayerForwarder()
105 ->GetShadowManager());
106 LayerTransactionChild* ltc =
107 mCanvasClient->GetForwarder()->AsLayerForwarder()->GetShadowManager();
108 DebugOnly<bool> success =
109 mContext->UpdateCompositableHandle(ltc, mCanvasClientAsyncHandle);
110 MOZ_ASSERT(success);
112 } else {
113 mCanvasClientAsyncHandle = CompositableHandle();
117 void AsyncCanvasRenderer::SetActiveEventTarget() {
118 MutexAutoLock lock(mMutex);
119 mActiveEventTarget = GetCurrentThreadSerialEventTarget();
122 void AsyncCanvasRenderer::ResetActiveEventTarget() {
123 MutexAutoLock lock(mMutex);
124 mActiveEventTarget = nullptr;
127 already_AddRefed<nsISerialEventTarget>
128 AsyncCanvasRenderer::GetActiveEventTarget() {
129 MutexAutoLock lock(mMutex);
130 nsCOMPtr<nsISerialEventTarget> result = mActiveEventTarget;
131 return result.forget();
134 ImageContainer* AsyncCanvasRenderer::GetImageContainer() {
135 MOZ_ASSERT(mContextType == dom::CanvasContextType::ImageBitmap);
136 MutexAutoLock lock(mMutex);
137 if (!mImageContainer) {
138 mImageContainer =
139 LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
141 return mImageContainer;
144 dom::CanvasContextType AsyncCanvasRenderer::GetContextType() {
145 MutexAutoLock lock(mMutex);
146 return mContextType;
149 void AsyncCanvasRenderer::SetContextType(dom::CanvasContextType aContextType) {
150 MutexAutoLock lock(mMutex);
151 mContextType = aContextType;
154 void AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient) {
155 MutexAutoLock lock(mMutex);
157 if (!aTextureClient) {
158 mSurfaceForBasic = nullptr;
159 return;
162 TextureClientAutoLock texLock(aTextureClient, layers::OpenMode::OPEN_READ);
163 if (!texLock.Succeeded()) {
164 return;
167 const gfx::IntSize& size = aTextureClient->GetSize();
168 // This buffer would be used later for content rendering. So we choose
169 // B8G8R8A8 format here.
170 const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
171 // Avoid to create buffer every time.
172 if (!mSurfaceForBasic || size != mSurfaceForBasic->GetSize() ||
173 format != mSurfaceForBasic->GetFormat()) {
174 uint32_t stride =
175 gfx::GetAlignedStride<8>(size.width, BytesPerPixel(format));
176 mSurfaceForBasic =
177 gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
178 if (!mSurfaceForBasic) {
179 return;
183 MappedTextureData mapped;
184 if (!aTextureClient->BorrowMappedData(mapped)) {
185 return;
188 const uint8_t* lockedBytes = mapped.data;
189 gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic,
190 gfx::DataSourceSurface::MapType::WRITE);
191 if (!map.IsMapped()) {
192 return;
195 MOZ_ASSERT(map.GetStride() == mapped.stride);
196 memcpy(map.GetData(), lockedBytes,
197 map.GetStride() * mSurfaceForBasic->GetSize().height);
199 if (mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
200 mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8X8) {
201 gl::SwapRAndBComponents(mSurfaceForBasic);
205 already_AddRefed<gfx::DataSourceSurface> AsyncCanvasRenderer::UpdateTarget() {
206 if (!mGLContext) {
207 return nullptr;
210 gl::SharedSurface* frontbuffer = nullptr;
211 gl::GLScreenBuffer* screen = mGLContext->Screen();
212 const auto& front = screen->Front();
213 if (front) {
214 frontbuffer = front->Surf();
217 if (!frontbuffer) {
218 return nullptr;
221 if (frontbuffer->mType == gl::SharedSurfaceType::Basic) {
222 return nullptr;
225 const gfx::IntSize& size = frontbuffer->mSize;
226 // This buffer would be used later for content rendering. So we choose
227 // B8G8R8A8 format here.
228 const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
229 uint32_t stride = gfx::GetAlignedStride<8>(size.width, BytesPerPixel(format));
230 RefPtr<gfx::DataSourceSurface> surface =
231 gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
233 if (NS_WARN_IF(!surface)) {
234 return nullptr;
237 if (!frontbuffer->ReadbackBySharedHandle(surface)) {
238 return nullptr;
241 bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
242 if (needsPremult) {
243 gfxUtils::PremultiplyDataSurface(surface, surface);
246 return surface.forget();
249 already_AddRefed<gfx::DataSourceSurface> AsyncCanvasRenderer::GetSurface() {
250 MOZ_ASSERT(NS_IsMainThread());
251 MutexAutoLock lock(mMutex);
252 if (mSurfaceForBasic) {
253 // Since SourceSurface isn't thread-safe, we need copy to a new
254 // SourceSurface.
255 gfx::DataSourceSurface::ScopedMap srcMap(mSurfaceForBasic,
256 gfx::DataSourceSurface::READ);
258 RefPtr<gfx::DataSourceSurface> result =
259 gfx::Factory::CreateDataSourceSurfaceWithStride(
260 mSurfaceForBasic->GetSize(), mSurfaceForBasic->GetFormat(),
261 srcMap.GetStride());
262 if (NS_WARN_IF(!result)) {
263 return nullptr;
266 gfx::DataSourceSurface::ScopedMap dstMap(result,
267 gfx::DataSourceSurface::WRITE);
269 if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) {
270 return nullptr;
273 memcpy(dstMap.GetData(), srcMap.GetData(),
274 srcMap.GetStride() * mSurfaceForBasic->GetSize().height);
275 return result.forget();
276 } else {
277 return UpdateTarget();
281 nsresult AsyncCanvasRenderer::GetInputStream(const char* aMimeType,
282 const nsAString& aEncoderOptions,
283 nsIInputStream** aStream) {
284 MOZ_ASSERT(NS_IsMainThread());
285 RefPtr<gfx::DataSourceSurface> surface = GetSurface();
286 if (!surface) {
287 return NS_ERROR_FAILURE;
290 gfx::DataSourceSurface::ScopedMap map(surface, gfx::DataSourceSurface::READ);
292 // Handle y flip.
293 RefPtr<gfx::DataSourceSurface> dataSurf =
294 gl::YInvertImageSurface(surface, map.GetStride());
296 return gfxUtils::GetInputStream(dataSurf, false, aMimeType, aEncoderOptions,
297 aStream);
300 } // namespace layers
301 } // namespace mozilla