gecko-dev/widget/android/nsAppShell.h

274 строки
7.2 KiB
C
Исходник Обычный вид История

/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
2012-05-21 15:12:37 +04:00
/* 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/. */
#ifndef nsAppShell_h__
#define nsAppShell_h__
#include <time.h>
#include "mozilla/HangMonitor.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Monitor.h"
#include "mozilla/Move.h"
#include "mozilla/StaticPtr.h"
Bug 1343075 - Use GeckoEditableSupport from PuppetWidget; r=masayuki r=rbarker r=snorp r=esawin Bug 1343075 - 1a. Add TextEventDispatcherListener::GetIMEUpdatePreference; r=masayuki Add a GetIMEUpdatePreference method to TextEventDispatcherListener to optionally control which IME notifications are received by NotifyIME. This patch also makes nsBaseWidget forward its GetIMEUpdatePreference call to the widget's native TextEventDispatcherListener. Bug 1343075 - 1b. Implement GetIMEUpdatePreference for all TextEventDispatcherListener; r=masayuki This patch implements GetIMEUpdatePreference for all TextEventDispatcherListener implementations, by moving previous implementations of nsIWidget::GetIMEUpdatePreference. Bug 1343075 - 2. Allow setting a PuppetWidget's native TextEventDispatcherListener; r=masayuki In PuppetWidget, add getter and setter for the widget's native TextEventDispatcherListener. This allows overriding of PuppetWidget's default IME handling. For example, on Android, the PuppetWidget's native TextEventDispatcherListener will communicate directly with Java IME code in the main process. Bug 1343075 - 3. Add AIDL interface for main process; r=rbarker Add AIDL definition and implementation for an interface for the main process that child processes can access. Bug 1343075 - 4. Set Gecko thread JNIEnv for child process; r=snorp Add a JNIEnv* parameter to XRE_SetAndroidChildFds, which is used to set the Gecko thread JNIEnv for child processes. XRE_SetAndroidChildFds is the only Android-specific entry point for child processes, so I think it's the most logical place to initialize JNI. Bug 1343075 - 5. Support multiple remote GeckoEditableChild; r=esawin Support remote GeckoEditableChild instances that are created in the content processes and connect to the parent process GeckoEditableParent through binders. Support having multiple GeckoEditableChild instances in GeckoEditable by keeping track of which child is currently focused, and only allow calls to/from the focused child by using access tokens. Bug 1343075 - 6. Add method to get GeckoEditableParent instance; r=esawin Add IProcessManager.getEditableParent, which a content process can call to get the GeckoEditableParent instance that corresponds to a given content process tab, from the main process. Bug 1343075 - 7. Support GeckoEditableSupport in content processes; r=esawin Support creating and running GeckoEditableSupport attached to a PuppetWidget in content processes. Because we don't know PuppetWidget's lifetime as well as nsWindow's, when attached to PuppetWidget, we need to attach/detach our native object on focus/blur, respectively. Bug 1343075 - 8. Connect GeckoEditableSupport on PuppetWidget creation; r=esawin Listen to the "tab-child-created" notification and attach our content process GeckoEditableSupport to the new PuppetWidget. Bug 1343075 - 9. Update auto-generated bindings; r=me
2017-03-08 06:34:39 +03:00
#include "mozilla/TypeTraits.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/jni/Natives.h"
#include "nsBaseAppShell.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsInterfaceHashtable.h"
#include "nsIAndroidBridge.h"
namespace mozilla {
bool ProcessNextEvent();
void NotifyEvent();
}
class nsWindow;
class nsAppShell :
public nsBaseAppShell
{
public:
struct Event : mozilla::LinkedListElement<Event>
{
typedef mozilla::HangMonitor::ActivityType Type;
static uint64_t GetTime()
{
timespec time;
if (clock_gettime(CLOCK_MONOTONIC, &time)) {
return 0ull;
}
return uint64_t(time.tv_sec) * 1000000000ull + time.tv_nsec;
}
uint64_t mPostTime{ 0 };
bool HasSameTypeAs(const Event* other) const
{
// Compare vtable addresses to determine same type.
return *reinterpret_cast<const uintptr_t*>(this)
== *reinterpret_cast<const uintptr_t*>(other);
}
virtual ~Event() {}
virtual void Run() = 0;
virtual void PostTo(mozilla::LinkedList<Event>& queue)
{
queue.insertBack(this);
}
virtual Type ActivityType() const
{
return Type::kGeneralActivity;
}
};
template<typename T>
class LambdaEvent : public Event
{
protected:
T lambda;
public:
explicit LambdaEvent(T&& l) : lambda(mozilla::Move(l)) {}
void Run() override { return lambda(); }
};
class ProxyEvent : public Event
{
protected:
mozilla::UniquePtr<Event> baseEvent;
public:
explicit ProxyEvent(mozilla::UniquePtr<Event>&& event)
: baseEvent(mozilla::Move(event))
{}
void PostTo(mozilla::LinkedList<Event>& queue) override
{
baseEvent->PostTo(queue);
}
void Run() override
{
baseEvent->Run();
}
};
static nsAppShell* Get()
{
MOZ_ASSERT(NS_IsMainThread());
return sAppShell;
}
nsAppShell();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIOBSERVER
nsresult Init();
void NotifyNativeEvent();
bool ProcessNextNativeEvent(bool mayWait) override;
// Post a subclass of Event.
// e.g. PostEvent(mozilla::MakeUnique<MyEvent>());
template<typename T, typename D>
static void PostEvent(mozilla::UniquePtr<T, D>&& event)
{
mozilla::MutexAutoLock lock(*sAppShellLock);
if (!sAppShell) {
return;
}
sAppShell->mEventQueue.Post(mozilla::Move(event));
}
// Post a event that will call a lambda
// e.g. PostEvent([=] { /* do something */ });
template<typename T>
static void PostEvent(T&& lambda)
{
mozilla::MutexAutoLock lock(*sAppShellLock);
if (!sAppShell) {
return;
}
sAppShell->mEventQueue.Post(mozilla::MakeUnique<LambdaEvent<T>>(
mozilla::Move(lambda)));
}
// Post a event and wait for it to finish running on the Gecko thread.
static void SyncRunEvent(Event&& event,
mozilla::UniquePtr<Event>(*eventFactory)(
mozilla::UniquePtr<Event>&&) = nullptr);
Bug 1343075 - Use GeckoEditableSupport from PuppetWidget; r=masayuki r=rbarker r=snorp r=esawin Bug 1343075 - 1a. Add TextEventDispatcherListener::GetIMEUpdatePreference; r=masayuki Add a GetIMEUpdatePreference method to TextEventDispatcherListener to optionally control which IME notifications are received by NotifyIME. This patch also makes nsBaseWidget forward its GetIMEUpdatePreference call to the widget's native TextEventDispatcherListener. Bug 1343075 - 1b. Implement GetIMEUpdatePreference for all TextEventDispatcherListener; r=masayuki This patch implements GetIMEUpdatePreference for all TextEventDispatcherListener implementations, by moving previous implementations of nsIWidget::GetIMEUpdatePreference. Bug 1343075 - 2. Allow setting a PuppetWidget's native TextEventDispatcherListener; r=masayuki In PuppetWidget, add getter and setter for the widget's native TextEventDispatcherListener. This allows overriding of PuppetWidget's default IME handling. For example, on Android, the PuppetWidget's native TextEventDispatcherListener will communicate directly with Java IME code in the main process. Bug 1343075 - 3. Add AIDL interface for main process; r=rbarker Add AIDL definition and implementation for an interface for the main process that child processes can access. Bug 1343075 - 4. Set Gecko thread JNIEnv for child process; r=snorp Add a JNIEnv* parameter to XRE_SetAndroidChildFds, which is used to set the Gecko thread JNIEnv for child processes. XRE_SetAndroidChildFds is the only Android-specific entry point for child processes, so I think it's the most logical place to initialize JNI. Bug 1343075 - 5. Support multiple remote GeckoEditableChild; r=esawin Support remote GeckoEditableChild instances that are created in the content processes and connect to the parent process GeckoEditableParent through binders. Support having multiple GeckoEditableChild instances in GeckoEditable by keeping track of which child is currently focused, and only allow calls to/from the focused child by using access tokens. Bug 1343075 - 6. Add method to get GeckoEditableParent instance; r=esawin Add IProcessManager.getEditableParent, which a content process can call to get the GeckoEditableParent instance that corresponds to a given content process tab, from the main process. Bug 1343075 - 7. Support GeckoEditableSupport in content processes; r=esawin Support creating and running GeckoEditableSupport attached to a PuppetWidget in content processes. Because we don't know PuppetWidget's lifetime as well as nsWindow's, when attached to PuppetWidget, we need to attach/detach our native object on focus/blur, respectively. Bug 1343075 - 8. Connect GeckoEditableSupport on PuppetWidget creation; r=esawin Listen to the "tab-child-created" notification and attach our content process GeckoEditableSupport to the new PuppetWidget. Bug 1343075 - 9. Update auto-generated bindings; r=me
2017-03-08 06:34:39 +03:00
template<typename T> static
typename mozilla::EnableIf<!mozilla::IsBaseOf<Event, T>::value, void>::Type
SyncRunEvent(T&& lambda)
{
SyncRunEvent(LambdaEvent<T>(mozilla::Forward<T>(lambda)));
}
static already_AddRefed<nsIURI> ResolveURI(const nsCString& aUriStr);
void SetBrowserApp(nsIAndroidBrowserApp* aBrowserApp) {
mBrowserApp = aBrowserApp;
}
nsIAndroidBrowserApp* GetBrowserApp() {
return mBrowserApp;
}
protected:
static nsAppShell* sAppShell;
static mozilla::StaticAutoPtr<mozilla::Mutex> sAppShellLock;
static void RecordLatencies();
virtual ~nsAppShell();
nsresult AddObserver(const nsAString &aObserverKey, nsIObserver *aObserver);
class NativeCallbackEvent : public Event
{
// Capturing the nsAppShell instance is safe because if the app
// shell is detroyed, this lambda will not be called either.
nsAppShell* const appShell;
public:
explicit NativeCallbackEvent(nsAppShell* as) : appShell(as) {}
void Run() override { appShell->NativeEventCallback(); }
};
void ScheduleNativeEventCallback() override
{
mEventQueue.Post(mozilla::MakeUnique<NativeCallbackEvent>(this));
}
class Queue
{
private:
mozilla::Monitor mMonitor;
mozilla::LinkedList<Event> mQueue;
public:
enum {
LATENCY_UI,
LATENCY_OTHER,
LATENCY_COUNT
};
static uint32_t sLatencyCount[LATENCY_COUNT];
static uint64_t sLatencyTime[LATENCY_COUNT];
Queue() : mMonitor("nsAppShell.Queue")
{}
void Signal()
{
mozilla::MonitorAutoLock lock(mMonitor);
lock.NotifyAll();
}
void Post(mozilla::UniquePtr<Event>&& event)
{
MOZ_ASSERT(event && !event->isInList());
mozilla::MonitorAutoLock lock(mMonitor);
event->PostTo(mQueue);
if (event->isInList()) {
event->mPostTime = Event::GetTime();
// Ownership of event object transfers to the queue.
mozilla::Unused << event.release();
}
lock.NotifyAll();
}
mozilla::UniquePtr<Event> Pop(bool mayWait)
{
mozilla::MonitorAutoLock lock(mMonitor);
if (mayWait && mQueue.isEmpty()) {
#ifdef EARLY_BETA_OR_EARLIER
// Record latencies when we're about to be idle.
nsAppShell::RecordLatencies();
#endif
lock.Wait();
}
// Ownership of event object transfers to the return value.
mozilla::UniquePtr<Event> event(mQueue.popFirst());
if (!event || !event->mPostTime) {
return Move(event);
}
#ifdef EARLY_BETA_OR_EARLIER
const size_t latencyType = (event->ActivityType() ==
Event::Type::kUIActivity) ? LATENCY_UI : LATENCY_OTHER;
const uint64_t latency = Event::GetTime() - event->mPostTime;
sLatencyCount[latencyType]++;
sLatencyTime[latencyType] += latency;
#endif
return Move(event);
}
} mEventQueue;
mozilla::CondVar mSyncRunFinished;
bool mSyncRunQuit;
bool mAllowCoalescingTouches;
nsCOMPtr<nsIAndroidBrowserApp> mBrowserApp;
nsInterfaceHashtable<nsStringHashKey, nsIObserver> mObserversHash;
};
#endif // nsAppShell_h__