1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AndroidCompositorWidget.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsWindow.h"
#include "SurfaceViewWrapperSupport.h"
namespace mozilla {
namespace widget {
AndroidCompositorWidget::AndroidCompositorWidget(
const AndroidCompositorWidgetInitData& aInitData,
const layers::CompositorOptions& aOptions)
: CompositorWidget(aOptions),
mWidgetId(aInitData.widgetId()),
mNativeWindow(nullptr),
mFormat(WINDOW_FORMAT_RGBA_8888),
mClientSize(aInitData.clientSize()) {}
AndroidCompositorWidget::~AndroidCompositorWidget() {
if (mNativeWindow) {
ANativeWindow_release(mNativeWindow);
}
}
already_AddRefed<gfx::DrawTarget>
AndroidCompositorWidget::StartRemoteDrawingInRegion(
const LayoutDeviceIntRegion& aInvalidRegion,
layers::BufferMode* aBufferMode) {
if (!mNativeWindow) {
EGLNativeWindowType window = GetEGLNativeWindow();
JNIEnv* const env = jni::GetEnvForThread();
mNativeWindow =
ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
if (mNativeWindow) {
mFormat = ANativeWindow_getFormat(mNativeWindow);
ANativeWindow_acquire(mNativeWindow);
} else {
return nullptr;
}
}
if (mFormat != WINDOW_FORMAT_RGBA_8888 &&
mFormat != WINDOW_FORMAT_RGBX_8888) {
gfxCriticalNoteOnce << "Non supported format: " << mFormat;
return nullptr;
}
// XXX Handle inOutDirtyBounds
if (ANativeWindow_lock(mNativeWindow, &mBuffer, nullptr) != 0) {
return nullptr;
}
const int bpp = 4;
gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
if (mFormat == WINDOW_FORMAT_RGBX_8888) {
format = gfx::SurfaceFormat::R8G8B8X8;
}
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(
gfx::BackendType::SKIA, static_cast<unsigned char*>(mBuffer.bits),
gfx::IntSize(mBuffer.width, mBuffer.height), mBuffer.stride * bpp, format,
true);
return dt.forget();
}
void AndroidCompositorWidget::EndRemoteDrawingInRegion(
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
ANativeWindow_unlockAndPost(mNativeWindow);
}
bool AndroidCompositorWidget::OnResumeComposition() {
OnCompositorSurfaceChanged();
if (!mSurface) {
gfxCriticalError() << "OnResumeComposition called with null Surface";
return false;
}
// If our Surface is in an abandoned state then we will never succesfully
// create an EGL Surface, and will eventually crash. Better to explicitly
// crash now.
if (SurfaceViewWrapperSupport::IsSurfaceAbandoned(mSurface)) {
MOZ_CRASH("Compositor resumed with abandoned Surface");
}
return true;
}
EGLNativeWindowType AndroidCompositorWidget::GetEGLNativeWindow() {
return (EGLNativeWindowType)mSurface.Get();
}
LayoutDeviceIntSize AndroidCompositorWidget::GetClientSize() {
return mClientSize;
}
void AndroidCompositorWidget::NotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) {
mClientSize =
LayoutDeviceIntSize(std::min(aClientSize.width, MOZ_WIDGET_MAX_SIZE),
std::min(aClientSize.height, MOZ_WIDGET_MAX_SIZE));
}
} // namespace widget
} // namespace mozilla
|