summaryrefslogtreecommitdiffstats
path: root/widget/android/AndroidCompositorWidget.cpp
blob: edbdad6bb6139ea5379ee0c09b65bc1b0637fabc (plain)
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