/* -*- Mode: c++; c-basic-offset: 2; tab-width: 4; indent-tabs-mode: nil; -*- * vim: set sw=2 ts=4 expandtab: * 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/. */
using mozilla::dom::ContentChild; using mozilla::dom::ContentParent; using mozilla::gfx::DataSourceSurface; using mozilla::gfx::IntSize; using mozilla::gfx::Matrix; using mozilla::gfx::SurfaceFormat; using mozilla::java::GeckoSession; using mozilla::java::sdk::IllegalStateException; using GeckoPrintException = GeckoSession::GeckoPrintException; static mozilla::LazyLogModule sGVSupportLog("GeckoViewSupport");
// All the toplevel windows that have been created; these are in // stacking order, so the window at gTopLevelWindows[0] is the topmost // one.
MOZ_RUNINIT static nsTArray<nsWindow*> gTopLevelWindows;
using WindowPtr = jni::NativeWeakPtr<GeckoViewSupport>;
/** * PanZoomController handles its native calls on the UI thread, so make * it separate from GeckoViewSupport.
*/ class NPZCSupport final
: public java::PanZoomController::NativeProvider::Natives<NPZCSupport> {
WindowPtr mWindow;
java::PanZoomController::NativeProvider::WeakRef mNPZC;
// Stores the returnResult of each pending motion event between // HandleMotionEvent and FinishHandlingMotionEvent.
std::queue<std::pair<uint64_t, java::GeckoResult::GlobalRef>>
mPendingMotionEventReturnResults;
// Only true if mAndroidVsync is non-null and the resampling pref is set. bool mTouchResamplingEnabled = false;
template <typename Lambda> class InputEvent final : public nsAppShell::Event {
java::PanZoomController::NativeProvider::GlobalRef mNPZC;
Lambda mLambda;
class MOZ_HEAP_CLASS Observer final : public AndroidVsync::Observer { public: static Observer* Create(jni::NativeWeakPtr<NPZCSupport>&& aNPZCSupport) { returnnew Observer(std::move(aNPZCSupport));
}
private: // Private constructor, part of a strategy to make sure // we're only able to create these on the heap. explicit Observer(jni::NativeWeakPtr<NPZCSupport>&& aNPZCSupport)
: mNPZCSupport(std::move(aNPZCSupport)) {}
void OnVsync(const TimeStamp& aTimeStamp) override { auto accessor = mNPZCSupport.Access();
using Base::AttachNative; using Base::DisposeNative;
void OnWeakNonIntrusiveDetach(already_AddRefed<Runnable> aDisposer) {
RefPtr<Runnable> disposer = aDisposer; // There are several considerations when shutting down NPZC. 1) The // Gecko thread may destroy NPZC at any time when nsWindow closes. 2) // There may be pending events on the Gecko thread when NPZC is // destroyed. 3) mWindow may not be available when the pending event // runs. 4) The UI thread may destroy NPZC at any time when GeckoView // is destroyed. 5) The UI thread may destroy NPZC at the same time as // Gecko thread trying to destroy NPZC. 6) There may be pending calls // on the UI thread when NPZC is destroyed. 7) mWindow may have been // cleared on the Gecko thread when the pending call happens on the UI // thread. // // 1) happens through OnWeakNonIntrusiveDetach, which first notifies the UI // thread through Destroy; Destroy then calls DisposeNative, which // finally disposes the native instance back on the Gecko thread. Using // Destroy to indirectly call DisposeNative here also solves 5), by // making everything go through the UI thread, avoiding contention. // // 2) and 3) are solved by clearing mWindow, which signals to the // pending event that we had shut down. In that case the event bails // and does not touch mWindow. // // 4) happens through DisposeNative directly. // // 6) is solved by keeping a destroyed flag in the Java NPZC instance, // and only make a pending call if the destroyed flag is not set. // // 7) is solved by taking a lock whenever mWindow is modified on the // Gecko thread or accessed on the UI thread. That way, we don't // release mWindow until the UI thread is done using it, thus avoiding // the race condition.
if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) { auto npzc = java::PanZoomController::NativeProvider::GlobalRef(mNPZC); if (!npzc) { return;
}
if (auto window = mWindow.Access()) {
nsWindow* gkWindow = window->GetNsWindow(); if (gkWindow) {
controller = gkWindow->mAPZC;
}
}
if (!controller) { return INPUT_RESULT_UNHANDLED;
}
ScreenPoint origin = ScreenPoint(aX, aY);
if (StaticPrefs::ui_scrolling_negate_wheel_scroll()) {
aHScroll = -aHScroll;
aVScroll = -aVScroll;
}
ScrollWheelInput input(
nsWindow::GetEventTimeStamp(aTime), nsWindow::GetModifiers(aMetaState),
ScrollWheelInput::SCROLLMODE_SMOOTH,
ScrollWheelInput::SCROLLDELTA_PIXEL, origin, aHScroll, aVScroll, false, // XXX Do we need to support auto-dir scrolling // for Android widgets with a wheel device? // Currently, I just leave it unimplemented. If // we need to implement it, what's the extra work // to do?
WheelDeltaAdjustmentStrategy::eNone);
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input); if (result.GetStatus() == nsEventStatus_eConsumeNoDefault) { return INPUT_RESULT_IGNORED;
}
private: static MouseInput::ButtonType GetButtonType(int button) {
MouseInput::ButtonType result = MouseInput::NONE;
switch (button) { case java::sdk::MotionEvent::BUTTON_PRIMARY:
result = MouseInput::PRIMARY_BUTTON; break; case java::sdk::MotionEvent::BUTTON_SECONDARY:
result = MouseInput::SECONDARY_BUTTON; break; case java::sdk::MotionEvent::BUTTON_TERTIARY:
result = MouseInput::MIDDLE_BUTTON; break; default: break;
}
return result;
}
static int16_t ConvertButtons(int buttons) {
int16_t result = 0;
if (buttons & java::sdk::MotionEvent::BUTTON_PRIMARY) {
result |= MouseButtonsFlag::ePrimaryFlag;
} if (buttons & java::sdk::MotionEvent::BUTTON_SECONDARY) {
result |= MouseButtonsFlag::eSecondaryFlag;
} if (buttons & java::sdk::MotionEvent::BUTTON_TERTIARY) {
result |= MouseButtonsFlag::eMiddleFlag;
} if (buttons & java::sdk::MotionEvent::BUTTON_BACK) {
result |= MouseButtonsFlag::e4thFlag;
} if (buttons & java::sdk::MotionEvent::BUTTON_FORWARD) {
result |= MouseButtonsFlag::e5thFlag;
}
return result;
}
static int32_t ConvertAPZHandledPlace(APZHandledPlace aHandledPlace) { switch (aHandledPlace) { case APZHandledPlace::Unhandled: return INPUT_RESULT_UNHANDLED; case APZHandledPlace::HandledByRoot: return INPUT_RESULT_HANDLED; case APZHandledPlace::HandledByContent: return INPUT_RESULT_HANDLED_CONTENT; case APZHandledPlace::Invalid:
MOZ_ASSERT_UNREACHABLE("The handled result should NOT be Invalid"); return INPUT_RESULT_UNHANDLED;
}
MOZ_ASSERT_UNREACHABLE("Unknown handled result"); return INPUT_RESULT_UNHANDLED;
}
static int32_t ConvertSideBits(SideBits aSideBits) {
int32_t ret = java::PanZoomController::SCROLLABLE_FLAG_NONE; if (aSideBits & SideBits::eTop) {
ret |= java::PanZoomController::SCROLLABLE_FLAG_TOP;
} if (aSideBits & SideBits::eRight) {
ret |= java::PanZoomController::SCROLLABLE_FLAG_RIGHT;
} if (aSideBits & SideBits::eBottom) {
ret |= java::PanZoomController::SCROLLABLE_FLAG_BOTTOM;
} if (aSideBits & SideBits::eLeft) {
ret |= java::PanZoomController::SCROLLABLE_FLAG_LEFT;
} return ret;
}
static int32_t ConvertScrollDirections(
layers::ScrollDirections aScrollDirections) {
int32_t ret = java::PanZoomController::OVERSCROLL_FLAG_NONE; if (aScrollDirections.contains(layers::HorizontalScrollDirection)) {
ret |= java::PanZoomController::OVERSCROLL_FLAG_HORIZONTAL;
} if (aScrollDirections.contains(layers::VerticalScrollDirection)) {
ret |= java::PanZoomController::OVERSCROLL_FLAG_VERTICAL;
} return ret;
}
// Actually we don't dispatch context menu event to APZ since we don't // handle it on APZ yet. If handling it, we need to consider how to // dispatch it on APZ thread. It may cause a race condition.
contextMenu.mType = MouseInput::MOUSE_CONTEXTMENU;
// Convert MotionEvent touch radius and orientation into the format required // by w3c touchevents. // toolMajor and toolMinor span a rectangle that's oriented as per // aOrientation, centered around the touch point. static std::pair<float, ScreenSize> ConvertOrientationAndRadius( float aOrientation, float aToolMajor, float aToolMinor) { float angle = aOrientation * 180.0f / M_PI; // w3c touchevents spec does not allow orientations == 90 // this shifts it to -90, which will be shifted to zero below if (angle >= 90.0) {
angle -= 180.0f;
}
// w3c touchevent radii are given with an orientation between 0 and // 90. The radii are found by removing the orientation and // measuring the x and y radii of the resulting ellipse. For // Android orientations >= 0 and < 90, use the y radius as the // major radius, and x as the minor radius. However, for an // orientation < 0, we have to shift the orientation by adding 90, // and reverse which radius is major and minor.
ScreenSize radius; if (angle < 0.0f) {
angle += 90.0f;
radius =
ScreenSize(int32_t(aToolMajor / 2.0f), int32_t(aToolMinor / 2.0f));
} else {
radius =
ScreenSize(int32_t(aToolMinor / 2.0f), int32_t(aToolMajor / 2.0f));
}
switch (eventData->Action()) { case java::sdk::MotionEvent::ACTION_DOWN: case java::sdk::MotionEvent::ACTION_POINTER_DOWN:
type = MultiTouchInput::MULTITOUCH_START; break; case java::sdk::MotionEvent::ACTION_MOVE:
type = MultiTouchInput::MULTITOUCH_MOVE; break; case java::sdk::MotionEvent::ACTION_UP: case java::sdk::MotionEvent::ACTION_POINTER_UP: // for pointer-up events we only want the data from // the one pointer that went up
type = MultiTouchInput::MULTITOUCH_END;
startIndex = eventData->ActionIndex();
endIndex = startIndex + 1; break; case java::sdk::MotionEvent::ACTION_OUTSIDE: case java::sdk::MotionEvent::ACTION_CANCEL:
type = MultiTouchInput::MULTITOUCH_CANCEL; break; default: if (returnResult) {
returnResult->Complete(
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
} return;
}
// Each of these is |pointerCount| values.
nsTArray<float> x(eventData->X()->GetElements());
nsTArray<float> y(eventData->Y()->GetElements());
nsTArray<float> orientation(eventData->Orientation()->GetElements());
nsTArray<float> pressure(eventData->Pressure()->GetElements());
nsTArray<float> toolMajor(eventData->ToolMajor()->GetElements());
nsTArray<float> toolMinor(eventData->ToolMinor()->GetElements());
for (size_t i = startIndex; i < endIndex; i++) { auto [orien, radius] = ConvertOrientationAndRadius(
orientation[i], toolMajor[i], toolMinor[i]);
ScreenIntPoint point(int32_t(floorf(x[i])), int32_t(floorf(y[i])));
SingleTouchData singleTouchData(pointerId[i], point, radius, orien,
pressure[i]);
for (size_t historyIndex = 0; historyIndex < historySize;
historyIndex++) {
size_t historicalI = historyIndex * pointerCount + i; auto [historicalAngle, historicalRadius] = ConvertOrientationAndRadius(
historicalOrientation[historicalI],
historicalToolMajor[historicalI], historicalToolMinor[historicalI]);
ScreenIntPoint historicalPoint(
int32_t(floorf(historicalX[historicalI])),
int32_t(floorf(historicalY[historicalI])));
singleTouchData.mHistoricalData.AppendElement(
SingleTouchData::HistoricalTouchData{
nsWindow::GetEventTimeStamp(historicalTime[historyIndex]),
historicalPoint,
{}, // mLocalScreenPoint will be computed later by APZ
historicalRadius,
historicalAngle,
historicalPressure[historicalI]});
}
input.mTouches.AppendElement(singleTouchData);
}
if (mAndroidVsync &&
eventData->Action() == java::sdk::MotionEvent::ACTION_DOWN) { // Query pref value at the beginning of a touch gesture so that we don't // leave events stuck in the resampler after a pref flip.
mTouchResamplingEnabled = StaticPrefs::android_touch_resampling_enabled();
}
if (!mTouchResamplingEnabled) {
FinishHandlingMotionEvent(std::move(input),
java::GeckoResult::LocalRef(returnResult)); return;
}
void ConsumeMotionEventsFromResampler() { auto outgoing = mTouchResampler.ConsumeOutgoingEvents(); while (!outgoing.empty()) { auto outgoingEvent = std::move(outgoing.front());
outgoing.pop();
java::GeckoResult::GlobalRef returnResult; if (outgoingEvent.mEventId) { // Look up the GeckoResult for this event. // The outgoing events from the resampler are in the same order as the // original events, and no event IDs are skipped.
MOZ_RELEASE_ASSERT(!mPendingMotionEventReturnResults.empty()); auto pair = mPendingMotionEventReturnResults.front();
mPendingMotionEventReturnResults.pop();
MOZ_RELEASE_ASSERT(pair.first == *outgoingEvent.mEventId);
returnResult = pair.second;
}
FinishHandlingMotionEvent(std::move(outgoingEvent.mEvent),
java::GeckoResult::LocalRef(returnResult));
}
}
/** * Compositor has some unique requirements for its native calls, so make it * separate from GeckoViewSupport.
*/ class LayerViewSupport final
: public GeckoSession::Compositor::Natives<LayerViewSupport> {
WindowPtr mWindow;
GeckoSession::Compositor::WeakRef mCompositor;
Atomic<bool, ReleaseAcquire> mCompositorPaused;
java::sdk::Surface::GlobalRef mSurface;
java::sdk::SurfaceControl::GlobalRef mSurfaceControl;
int32_t mX;
int32_t mY;
int32_t mWidth;
int32_t mHeight; // Used to communicate with the gecko compositor from the UI thread. // Set in NotifyCompositorCreated and cleared in // NotifyCompositorSessionLost.
RefPtr<UiCompositorControllerChild> mUiCompositorControllerChild; // Whether we have requested a new Surface from the GeckoSession. bool mRequestedNewSurface = false;
// In order to use Event::HasSameTypeAs in PostTo(), we cannot make // LayerViewEvent a template because each template instantiation is // a different type. So implement LayerViewEvent as a ProxyEvent. class LayerViewEvent final : public nsAppShell::ProxyEvent { using Event = nsAppShell::Event;
void PostTo(LinkedList<Event>& queue) override { // Give priority to compositor events, but keep in order with // existing compositor events.
nsAppShell::Event* event = queue.getFirst(); while (event && event->HasSameTypeAs(this)) {
event = event->getNext();
} if (event) {
event->setPrevious(this);
} else {
queue.insertBack(this);
}
}
};
uiThread->Dispatch(NS_NewRunnableFunction( "LayerViewSupport::OnWeakNonIntrusiveDetach",
[compositor, disposer = std::move(disposer),
results = &mCapturePixelsResults, window = mWindow]() mutable { if (auto accWindow = window.Access()) { while (!results->empty()) { auto aResult =
java::GeckoResult::LocalRef(results->front().mResult); if (aResult) {
aResult->CompleteExceptionally(
java::sdk::IllegalStateException::New( "The compositor has detached from the session")
.Cast<jni::Throwable>());
}
results->pop();
}
}
/// Called from the main thread whenever the compositor has been /// (re)initialized. void NotifyCompositorCreated(
RefPtr<UiCompositorControllerChild> aUiCompositorControllerChild) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
mUiCompositorControllerChild = aUiCompositorControllerChild;
if (mDefaultClearColor) {
mUiCompositorControllerChild->SetDefaultClearColor(*mDefaultClearColor);
}
if (!mCompositorPaused) { // If we are using SurfaceControl but mSurface is null, that means the // previous surface was destroyed along with the the previous // compositor, and we need to create a new one. if (mSurfaceControl && !mSurface) {
mSurface = java::SurfaceControlManager::GetInstance()->GetChildSurface(
mSurfaceControl, mWidth, mHeight);
}
if (auto window{mWindow.Access()}) {
nsWindow* gkWindow = window->GetNsWindow(); if (gkWindow) {
mUiCompositorControllerChild->OnCompositorSurfaceChanged(
gkWindow->mWidgetId, mSurface);
}
}
bool resumed = mUiCompositorControllerChild->ResumeAndResize(
mX, mY, mWidth, mHeight); if (!resumed) {
gfxCriticalNote
<< "Failed to resume compositor from NotifyCompositorCreated";
RequestNewSurface();
}
}
}
/// Called from the main thread whenever the compositor has been destroyed. void NotifyCompositorSessionLost() {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
mUiCompositorControllerChild = nullptr;
if (mSurfaceControl) { // If we are using SurfaceControl then we must set the Surface to null // here to ensure we create a new one when the new compositor is // created.
mSurface = nullptr;
}
if (auto window = mWindow.Access()) { while (!mCapturePixelsResults.empty()) { auto result =
java::GeckoResult::LocalRef(mCapturePixelsResults.front().mResult); if (result) {
result->CompleteExceptionally(
java::sdk::IllegalStateException::New( "Compositor session lost during screen pixels request")
.Cast<jni::Throwable>());
}
mCapturePixelsResults.pop();
}
}
}
auto locked(mWindow.Access()); if (!locked) { return; // Already shut down.
}
nsWindow* gkWindow = locked->GetNsWindow();
// We can have this situation if we get two GeckoViewSupport::Transfer() // called before the first AttachNPZC() gets here. Just detach the current // instance since that's what happens in GeckoViewSupport::Transfer() as // well.
gkWindow->mNPZCSupport.Detach();
// Set this true prior to attempting to pause the compositor, so that if // pausing fails the subsequent recovery knows to initialize the compositor // in a paused state.
mCompositorPaused = true;
if (mUiCompositorControllerChild) {
mUiCompositorControllerChild->Pause();
if (auto lock{mWindow.Access()}) { while (!mCapturePixelsResults.empty()) { auto result =
java::GeckoResult::LocalRef(mCapturePixelsResults.front().mResult); if (result) {
result->CompleteExceptionally(
java::sdk::IllegalStateException::New( "The compositor has detached from the session")
.Cast<jni::Throwable>());
}
mCapturePixelsResults.pop();
}
}
}
// Set this false prior to attempting to resume the compositor, so that if // resumption fails the subsequent recovery knows to initialize the // compositor in a resumed state.
mCompositorPaused = false;
if (mUiCompositorControllerChild) { bool resumed = mUiCompositorControllerChild->Resume(); if (!resumed) {
gfxCriticalNote
<< "Failed to resume compositor from SyncResumeCompositor";
RequestNewSurface();
}
}
}
// Set this false prior to attempting to resume the compositor, so that if // resumption fails the subsequent recovery knows to initialize the // compositor in a resumed state.
mCompositorPaused = false;
mX = aX;
mY = aY;
mWidth = aWidth;
mHeight = aHeight; if (StaticPrefs::widget_android_use_surfacecontrol_AtStartup()) {
mSurfaceControl =
java::sdk::SurfaceControl::GlobalRef::From(aSurfaceControl);
} if (mSurfaceControl) { // When using SurfaceControl, we create a child Surface to render in to // rather than rendering directly in to the Surface provided by the // application. This allows us to work around a bug on some versions of // Android when recovering from a GPU process crash.
mSurface = java::SurfaceControlManager::GetInstance()->GetChildSurface(
mSurfaceControl, mWidth, mHeight);
} else {
mSurface = java::sdk::Surface::GlobalRef::From(aSurface);
}
if (mUiCompositorControllerChild) { if (auto window = mWindow.Access()) {
nsWindow* gkWindow = window->GetNsWindow(); if (gkWindow) { // Send new Surface to GPU process, if one exists.
mUiCompositorControllerChild->OnCompositorSurfaceChanged(
gkWindow->mWidgetId, mSurface);
}
}
bool resumed = mUiCompositorControllerChild->ResumeAndResize(
aX, aY, aWidth, aHeight); if (!resumed) {
gfxCriticalNote
<< "Failed to resume compositor from SyncResumeResizeCompositor"; // Only request a new Surface if this SyncResumeAndResize call is not // response to a previous request, otherwise we will get stuck in an // infinite loop. if (!mRequestedNewSurface) {
RequestNewSurface();
} return;
}
}
mRequestedNewSurface = false;
class OnResumedEvent : public nsAppShell::Event {
GeckoSession::Compositor::GlobalRef mCompositor;
if (!lvsHolder) {
env->ExceptionClear(); return; // Already shut down.
}
auto lvs(lvsHolder->Access()); if (!lvs) {
env->ExceptionClear(); return; // Already shut down.
}
auto win = lvs->mWindow.Access(); if (!win) {
env->ExceptionClear(); return; // Already shut down.
}
// When we get here, the compositor has already been told to // resume. This means it's now safe for layer updates to occur. // Since we might have prevented one or more draw events from // occurring while the compositor was paused, we need to // schedule a draw event now. if (!lvs->mCompositorPaused) {
nsWindow* const gkWindow = win->GetNsWindow(); if (gkWindow) {
gkWindow->RedrawAll();
}
}
}
};
// Use priority queue for timing-sensitive event.
nsAppShell::PostEvent(
MakeUnique<LayerViewEvent>(MakeUnique<OnResumedEvent>(aObj)));
}
void RequestNewSurface() { if (constauto& compositor = GetJavaCompositor()) {
mRequestedNewSurface = true; if (mSurfaceControl) {
java::SurfaceControlManager::GetInstance()->RemoveSurface(
mSurfaceControl);
}
compositor->RequestNewSurface();
}
}
void RecvToolbarAnimatorMessage(int32_t aMessage) { auto compositor = GeckoSession::Compositor::LocalRef(mCompositor); if (compositor) {
compositor->RecvToolbarAnimatorMessage(aMessage);
}
}
if (size == 1) {
mUiCompositorControllerChild->RequestScreenPixels();
}
}
void RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize, bool aNeedsYFlip) {
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
CaptureRequest request;
java::GeckoResult::LocalRef result = nullptr;
java::sdk::Bitmap::LocalRef bitmap = nullptr; if (auto window = mWindow.Access()) { // The result might have been already rejected if the compositor was // detached from the session if (!mCapturePixelsResults.empty()) {
request = mCapturePixelsResults.front();
result = java::GeckoResult::LocalRef(request.mResult);
bitmap = java::sdk::Bitmap::LocalRef(request.mBitmap);
mCapturePixelsResults.pop();
}
}
if (result) { if (bitmap) {
RefPtr<DataSourceSurface> surf; if (aNeedsYFlip) {
surf = FlipScreenPixels(aMem, aSize, request.mSource,
request.mOutputSize);
} else {
surf = gfx::Factory::CreateWrappingDataSourceSurface(
aMem.get<uint8_t>(),
StrideForFormatAndWidth(SurfaceFormat::B8G8R8A8, aSize.width),
IntSize(aSize.width, aSize.height), SurfaceFormat::B8G8R8A8);
} if (surf) {
DataSourceSurface::ScopedMap smap(surf, DataSourceSurface::READ); auto pixels = mozilla::jni::ByteBuffer::New( reinterpret_cast<int8_t*>(smap.GetData()),
smap.GetStride() * request.mOutputSize.height);
bitmap->CopyPixelsFromBuffer(pixels);
result->Complete(bitmap);
} else {
result->CompleteExceptionally(
java::sdk::IllegalStateException::New( "Failed to create flipped snapshot surface (probably out " "of memory)")
.Cast<jni::Throwable>());
}
} else {
result->CompleteExceptionally(java::sdk::IllegalArgumentException::New( "No target bitmap argument provided")
.Cast<jni::Throwable>());
}
}
// Pixels have been copied, so Dealloc Shmem if (mUiCompositorControllerChild) {
mUiCompositorControllerChild->DeallocPixelBuffer(aMem);
if (auto window = mWindow.Access()) { if (!mCapturePixelsResults.empty()) {
mUiCompositorControllerChild->RequestScreenPixels();
}
}
}
}
// We'll need gfxPlatform to be initialized to create a compositor later. // Might as well do that now so that the GPU process launch can get a head // start.
gfxPlatform::GetPlatform();
// Prepare an nsIGeckoViewView to pass as argument to the window.
RefPtr<AndroidView> androidView = new AndroidView();
androidView->mEventDispatcher->Attach(
java::EventDispatcher::Ref::From(aDispatcher), nullptr);
androidView->mInitData = java::GeckoBundle::Ref::From(aInitData);
// Attach a new GeckoView support object to the new window.
GeckoSession::Window::LocalRef sessionWindow(aCls.Env(), aWindow); auto weakGeckoViewSupport =
jni::NativeWeakPtrHolder<GeckoViewSupport>::Attach(
sessionWindow, window, sessionWindow, pdomWindow);
if (window->mWidgetListener) {
nsCOMPtr<nsIAppWindow> appWindow(window->mWidgetListener->GetAppWindow()); if (appWindow) { // Our window is not intrinsically sized, so tell AppWindow to // not set a size for us.
appWindow->SetIntrinsicallySized(false);
}
}
}
void GeckoViewSupport::Close() { if (mWindow) { if (mWindow->mAndroidView) {
mWindow->mAndroidView->mEventDispatcher->Detach();
}
mWindow = nullptr;
}
auto compositor = GeckoSession::Compositor::LocalRef(
inst.Env(), GeckoSession::Compositor::Ref::From(aCompositor));
bool attachLvs;
{ // Scope for lvsAccess auto lvsAccess{mWindow->mLayerViewSupport.Access()}; // If we do not yet have mLayerViewSupport, or if the compositor has // changed, then we must attach a new one.
attachLvs = !lvsAccess || lvsAccess->GetJavaCompositor() != compositor;
}
if (attachLvs) {
mWindow->mLayerViewSupport =
jni::NativeWeakPtrHolder<LayerViewSupport>::Attach(
compositor, mWindow->mGeckoViewSupport, compositor);
if (RefPtr<UiCompositorControllerChild> uiCompositorController =
mWindow->GetUiCompositorControllerChild()) {
DispatchToUiThread( "LayerViewSupport::NotifyCompositorCreated",
[lvs = mWindow->mLayerViewSupport, uiCompositorController] { if (auto lvsAccess{lvs.Access()}) {
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.23Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.