Bug 1734394 - Make Geckoview use the session store collector r=geckoview-reviewers,agi,farre,peterv

When the session storage prefs are enabled, GeckoSession updateSessionState will provide the bundle of information, including zoom, scroll, and form data, to the delegate. Currently works for Fission and on Fenix.

Differential Revision: https://phabricator.services.mozilla.com/D148215
This commit is contained in:
Cathy Lu 2022-07-15 20:44:55 +00:00
Родитель 5601c9d71d
Коммит df9bafbf73
26 изменённых файлов: 594 добавлений и 299 удалений

Просмотреть файл

@ -1109,6 +1109,10 @@ pref("browser.sessionstore.upgradeBackup.maxUpgradeBackups", 3);
pref("browser.sessionstore.debug", false);
// Forget closed windows/tabs after two weeks
pref("browser.sessionstore.cleanup.forget_closed_after", 1209600000);
// Platform collects data for session store
pref("browser.sessionstore.platform_collection", true);
// Platform collects session storage data for session store
pref("browser.sessionstore.collect_session_storage", true);
// Don't quit the browser when Ctrl + Q is pressed.
pref("browser.quitShortcut.disabled", false);

Просмотреть файл

@ -2445,7 +2445,7 @@ nsresult CanonicalBrowsingContext::WriteSessionStorageToSessionStore(
void CanonicalBrowsingContext::UpdateSessionStoreSessionStorage(
const std::function<void()>& aDone) {
if constexpr (!SessionStoreUtils::NATIVE_LISTENER) {
if (!StaticPrefs::browser_sessionstore_collect_session_storage_AtStartup()) {
aDone();
return;
}
@ -2478,7 +2478,7 @@ void CanonicalBrowsingContext::UpdateSessionStoreForStorage(
}
void CanonicalBrowsingContext::MaybeScheduleSessionStoreUpdate() {
if constexpr (!SessionStoreUtils::NATIVE_LISTENER) {
if (!StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
return;
}

Просмотреть файл

@ -5781,7 +5781,7 @@ nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
}
}
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
if (StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
if (IsForceReloadType(mLoadType)) {
if (WindowContext* windowContext =
mBrowsingContext->GetCurrentWindowContext()) {
@ -6525,7 +6525,7 @@ nsresult nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
// incorrectly overrides session store data from the following load.
return NS_OK;
}
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
if (StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
if (WindowContext* windowContext =
mBrowsingContext->GetCurrentWindowContext()) {
using Change = SessionStoreChangeListener::Change;

Просмотреть файл

@ -3089,7 +3089,7 @@ nsresult nsFrameLoader::EnsureMessageManager() {
NS_ENSURE_TRUE(mChildMessageManager, NS_ERROR_UNEXPECTED);
// Set up session store
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
if (StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
if (XRE_IsParentProcess() && mIsTopLevelContent) {
mSessionStoreChild = SessionStoreChild::GetOrCreate(
GetExtantBrowsingContext(), mOwnerContent);

Просмотреть файл

@ -26,6 +26,18 @@ interface SessionStoreFormData {
object toJSON();
};
[GenerateConversionToJS]
dictionary SessionStoreDisplaySize {
unsigned long width;
unsigned long height;
};
[GenerateConversionToJS]
dictionary SessionStoreZoomData {
double resolution;
SessionStoreDisplaySize displaySize;
};
[ChromeOnly, Exposed=Window]
interface SessionStoreScrollData {
[Cached, Pure]

Просмотреть файл

@ -519,7 +519,7 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
mIPCOpen = true;
if constexpr (SessionStoreUtils::NATIVE_LISTENER) {
if (StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
mSessionStoreChild = SessionStoreChild::GetOrCreate(mBrowsingContext);
}

Просмотреть файл

@ -918,7 +918,7 @@ void BackgroundSessionStorageManager::SetCurrentBrowsingContextId(
}
void BackgroundSessionStorageManager::MaybeScheduleSessionStoreUpdate() {
if constexpr (!SessionStoreUtils::NATIVE_LISTENER) {
if (!StaticPrefs::browser_sessionstore_platform_collection_AtStartup()) {
return;
}

Просмотреть файл

@ -27,6 +27,7 @@ const DEFAULT_INTERVAL_MS = 1500;
const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
const PREF_INTERVAL = "browser.sessionstore.interval";
const PREF_SESSION_COLLECTION = "browser.sessionstore.platform_collection";
class Handler {
constructor(store) {
@ -598,13 +599,18 @@ class SessionStateAggregator extends GeckoViewChildModule {
this.stateChangeNotifier = new StateChangeNotifier(this);
this.handlers = [
new FormDataListener(this),
new SessionHistoryListener(this),
new ScrollPositionListener(this),
this.stateChangeNotifier,
this.messageQueue,
];
if (!Services.prefs.getBoolPref(PREF_SESSION_COLLECTION, false)) {
this.handlers.push(
new FormDataListener(this),
new ScrollPositionListener(this)
);
}
this.messageManager.addMessageListener("GeckoView:FlushSessionState", this);
}

Просмотреть файл

@ -1311,6 +1311,36 @@ public class GeckoSession {
}
});
}
@WrapForJNI(calledFrom = "gecko")
private void onUpdateSessionStore(final GeckoBundle aBundle) {
ThreadUtils.runOnUiThread(
() -> {
final GeckoSession session = mOwner.get();
if (session == null) {
return;
}
GeckoBundle scroll = aBundle.getBundle("scroll");
if (scroll == null) {
scroll = new GeckoBundle();
aBundle.putBundle("scroll", scroll);
}
// Here we unfortunately need to do some re-mapping since `zoom` is passed in a separate
// bunds and we wish to keep the bundle format.
scroll.putBundle("zoom", aBundle.getBundle("zoom"));
final SessionState stateCache = session.mStateCache;
stateCache.updateSessionState(aBundle);
final SessionState state = new SessionState(stateCache);
if (!state.isEmpty()) {
final ProgressDelegate progressDelegate = session.getProgressDelegate();
if (progressDelegate != null) {
progressDelegate.onSessionStateChange(session, state);
} else {
}
}
});
}
}
private class Listener implements BundleEventListener {

Просмотреть файл

@ -1455,6 +1455,24 @@
value: 15000
mirror: always
# Platform collection of data for session store
- name: browser.sessionstore.platform_collection
type: bool
value: @IS_NOT_ANDROID@
mirror: once
# Platform collection of session storage data for session store
- name: browser.sessionstore.collect_session_storage
type: bool
value: @IS_NOT_ANDROID@
mirror: once
# Platform collection of zoom data for session store
- name: browser.sessionstore.collect_zoom
type: bool
value: @IS_NOT_ANDROID@
mirror: once
# Causes SessionStore to ignore non-final update messages from
# browser tabs that were not caused by a flush from the parent.
# This is a testing flag and should not be used by end-users.

Просмотреть файл

@ -9,6 +9,7 @@ include protocol PInProcess;
include SessionStoreTypes;
using mozilla::dom::MaybeDiscardedBrowsingContext from "mozilla/dom/BrowsingContext.h";
using mozilla::dom::MaybeSessionStoreZoom from "mozilla/dom/SessionStoreScrollData.h";
namespace mozilla {
namespace dom {
@ -31,8 +32,8 @@ parent:
* collected incrementally.
*/
async SessionStoreUpdate(
nsCString? aDocShellCaps, bool? aPrivateMode, bool aNeedCollectSHistory,
uint32_t aEpoch);
nsCString? aDocShellCaps, bool? aPrivateMode, MaybeSessionStoreZoom aZoom,
bool aNeedCollectSHistory, uint32_t aEpoch);
/**
* Sends data to be stored to the session store. The collected data

Просмотреть файл

@ -24,6 +24,7 @@
#include "nsPIDOMWindow.h"
#include "nsTHashMap.h"
#include "nsTHashtable.h"
#include "nsLayoutUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -31,6 +32,7 @@ using namespace mozilla::dom;
namespace {
constexpr auto kInput = u"input"_ns;
constexpr auto kScroll = u"mozvisualscroll"_ns;
constexpr auto kResize = u"mozvisualresize"_ns;
static constexpr char kNoAutoUpdates[] =
"browser.sessionstore.debug.no_auto_updates";
@ -120,14 +122,16 @@ SessionStoreChangeListener::HandleEvent(dom::Event* aEvent) {
RecordChange(windowContext, Change::Input);
} else if (eventType == kScroll) {
RecordChange(windowContext, Change::Scroll);
} else if (eventType == kResize && browsingContext->IsTop()) {
RecordChange(windowContext, Change::Resize);
}
return NS_OK;
}
/* static */ already_AddRefed<SessionStoreChangeListener>
SessionStoreChangeListener::Create(BrowsingContext* aBrowsingContext) {
MOZ_RELEASE_ASSERT(SessionStoreUtils::NATIVE_LISTENER);
MOZ_RELEASE_ASSERT(
StaticPrefs::browser_sessionstore_platform_collection_AtStartup());
if (!aBrowsingContext) {
return nullptr;
}
@ -181,6 +185,29 @@ static void CollectFormData(Document* aDocument,
}
}
static void GetZoom(BrowsingContext* aBrowsingContext,
Maybe<SessionStoreZoom>& aZoom) {
nsIDocShell* docShell = aBrowsingContext->GetDocShell();
if (!docShell) {
return;
}
PresShell* presShell = docShell->GetPresShell();
if (!presShell) {
return;
}
LayoutDeviceIntSize displaySize;
if (!nsLayoutUtils::GetContentViewerSize(presShell->GetPresContext(),
displaySize)) {
return;
}
aZoom.emplace(presShell->GetResolution(), displaySize.width,
displaySize.height);
}
void SessionStoreChangeListener::FlushSessionStore() {
if (mTimer) {
mTimer->Cancel();
@ -189,6 +216,7 @@ void SessionStoreChangeListener::FlushSessionStore() {
bool collectSessionHistory = false;
bool collectWireFrame = false;
bool didResize = false;
for (auto& iter : mSessionStoreChanges) {
WindowContext* windowContext = iter.GetKey();
@ -230,6 +258,10 @@ void SessionStoreChangeListener::FlushSessionStore() {
collectSessionHistory =
collectSessionHistory || changes.contains(Change::SessionHistory);
if (presShell && changes.contains(Change::Resize)) {
didResize = true;
}
mSessionStoreChild->IncrementalSessionStoreUpdate(
browsingContext, maybeFormData, maybeScroll, mEpoch);
}
@ -239,7 +271,13 @@ void SessionStoreChangeListener::FlushSessionStore() {
}
mSessionStoreChanges.Clear();
mSessionStoreChild->UpdateSessionStore(collectSessionHistory);
Maybe<SessionStoreZoom> zoom;
if (didResize) {
GetZoom(mBrowsingContext->Top(), zoom);
}
mSessionStoreChild->UpdateSessionStore(collectSessionHistory, zoom);
}
/* static */
@ -314,6 +352,9 @@ void SessionStoreChangeListener::AddEventListeners() {
if (EventTarget* target = GetEventTarget()) {
target->AddSystemEventListener(kInput, this, false);
target->AddSystemEventListener(kScroll, this, false);
if (StaticPrefs::browser_sessionstore_collect_zoom_AtStartup()) {
target->AddSystemEventListener(kResize, this, false);
}
mCurrentEventTarget = target;
}
}
@ -322,6 +363,9 @@ void SessionStoreChangeListener::RemoveEventListeners() {
if (mCurrentEventTarget) {
mCurrentEventTarget->RemoveSystemEventListener(kInput, this, false);
mCurrentEventTarget->RemoveSystemEventListener(kScroll, this, false);
if (StaticPrefs::browser_sessionstore_collect_zoom_AtStartup()) {
mCurrentEventTarget->RemoveSystemEventListener(kResize, this, false);
}
}
mCurrentEventTarget = nullptr;

Просмотреть файл

@ -56,7 +56,7 @@ class SessionStoreChangeListener final : public nsINamed,
void FlushSessionStore();
enum class Change { Input, Scroll, SessionHistory, WireFrame };
enum class Change { Input, Scroll, SessionHistory, WireFrame, Resize };
static SessionStoreChangeListener* CollectSessionStoreData(
WindowContext* aWindowContext, const EnumSet<Change>& aChanges);

Просмотреть файл

@ -167,10 +167,12 @@ void SessionStoreChild::UpdateEventTargets() {
}
}
void SessionStoreChild::UpdateSessionStore(bool aSessionHistoryUpdate) {
void SessionStoreChild::UpdateSessionStore(bool aSessionHistoryUpdate,
const MaybeSessionStoreZoom& aZoom) {
if (!mSessionStoreListener) {
// This is the case when we're shutting down, and expect a final update.
SessionStoreUpdate(Nothing(), Nothing(), aSessionHistoryUpdate, 0);
SessionStoreUpdate(Nothing(), Nothing(), Nothing(), aSessionHistoryUpdate,
0);
return;
}
@ -187,7 +189,7 @@ void SessionStoreChild::UpdateSessionStore(bool aSessionHistoryUpdate) {
}
SessionStoreUpdate(
docShellCaps, privatedMode,
docShellCaps, privatedMode, aZoom,
store->GetAndClearSHistoryChanged() || aSessionHistoryUpdate,
mSessionStoreListener->GetEpoch());
}
@ -216,14 +218,15 @@ mozilla::ipc::IPCResult SessionStoreChild::RecvFlushTabState(
void SessionStoreChild::SessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
const bool aNeedCollectSHistory, const uint32_t& aEpoch) {
const MaybeSessionStoreZoom& aZoom, const bool aNeedCollectSHistory,
const uint32_t& aEpoch) {
if (XRE_IsContentProcess()) {
Unused << SendSessionStoreUpdate(aDocShellCaps, aPrivatedMode,
Unused << SendSessionStoreUpdate(aDocShellCaps, aPrivatedMode, aZoom,
aNeedCollectSHistory, aEpoch);
} else if (SessionStoreParent* sessionStoreParent =
static_cast<SessionStoreParent*>(
InProcessChild::ParentActorFor(this))) {
sessionStoreParent->SessionStoreUpdate(aDocShellCaps, aPrivatedMode,
sessionStoreParent->SessionStoreUpdate(aDocShellCaps, aPrivatedMode, aZoom,
aNeedCollectSHistory, aEpoch);
}
}

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/dom/PSessionStoreChild.h"
#include "mozilla/dom/SessionStoreScrollData.h"
#include "mozilla/dom/SessionStoreChangeListener.h"
#include "mozilla/dom/SessionStoreListener.h"
#include "mozilla/RefPtr.h"
@ -31,12 +32,14 @@ class SessionStoreChild final : public PSessionStoreChild {
void SetOwnerContent(Element* aElement);
void Stop();
void UpdateEventTargets();
void UpdateSessionStore(bool aSessionHistoryUpdate = false);
void UpdateSessionStore(bool aSessionHistoryUpdate = false,
const MaybeSessionStoreZoom& aZoom = Nothing());
void FlushSessionStore();
void UpdateSHistoryChanges();
void SessionStoreUpdate(const Maybe<nsCString>& aDocShellCaps,
const Maybe<bool>& aPrivatedMode,
const MaybeSessionStoreZoom& aZoom,
const bool aNeedCollectSHistory,
const uint32_t& aEpoch);

Просмотреть файл

@ -25,6 +25,12 @@
#include "nsImportModule.h"
#include "nsIXPConnect.h"
#ifdef ANDROID
# include "mozilla/widget/nsWindow.h"
# include "mozilla/jni/GeckoBundleUtils.h"
# include "JavaBuiltins.h"
#endif /* ANDROID */
using namespace mozilla;
using namespace mozilla::dom;
@ -33,9 +39,81 @@ SessionStoreParent::SessionStoreParent(
BrowserSessionStore* aSessionStore)
: mBrowsingContext(aBrowsingContext), mSessionStore(aSessionStore) {}
#ifdef ANDROID
static void DoSessionStoreUpdate(CanonicalBrowsingContext* aBrowsingContext,
const Maybe<nsCString>& aDocShellCaps,
const Maybe<bool>& aPrivatedMode,
SessionStoreFormData* aFormData,
SessionStoreScrollData* aScroll,
const MaybeSessionStoreZoom& aZoom,
bool aNeedCollectSHistory, uint32_t aEpoch) {
RefPtr<BrowserSessionStore> sessionStore =
BrowserSessionStore::GetOrCreate(aBrowsingContext->Top());
nsCOMPtr<nsIWidget> widget =
aBrowsingContext->GetParentProcessWidgetContaining();
if (RefPtr<nsWindow> window = nsWindow::From(widget)) {
AutoJSAPI jsapi;
if (!jsapi.Init(xpc::PrivilegedJunkScope())) {
return;
}
jni::Object::LocalRef formDataBundle(jni::GetGeckoThreadEnv());
jni::Object::LocalRef scrollBundle(jni::GetGeckoThreadEnv());
if (aFormData) {
JS::RootedObject object(jsapi.cx());
ErrorResult rv;
aFormData->ToJSON(jsapi.cx(), &object);
JS::RootedValue value(jsapi.cx(), JS::ObjectValue(*object));
if (NS_FAILED(jni::BoxData(jsapi.cx(), value, formDataBundle, true))) {
JS_ClearPendingException(jsapi.cx());
return;
}
}
if (aScroll) {
JS::RootedObject object(jsapi.cx());
ErrorResult rv;
aScroll->ToJSON(jsapi.cx(), &object);
JS::RootedValue value(jsapi.cx(), JS::ObjectValue(*object));
if (NS_FAILED(jni::BoxData(jsapi.cx(), value, scrollBundle, true))) {
JS_ClearPendingException(jsapi.cx());
return;
}
}
GECKOBUNDLE_START(update);
GECKOBUNDLE_PUT(update, "formdata", formDataBundle);
GECKOBUNDLE_PUT(update, "scroll", scrollBundle);
if (aZoom) {
GECKOBUNDLE_START(zoomBundle);
GECKOBUNDLE_PUT(zoomBundle, "resolution",
java::sdk::Double::New(Get<0>(*aZoom)));
GECKOBUNDLE_START(displaySizeBundle);
GECKOBUNDLE_PUT(displaySizeBundle, "width",
java::sdk::Integer::ValueOf(Get<1>(*aZoom)));
GECKOBUNDLE_PUT(displaySizeBundle, "height",
java::sdk::Integer::ValueOf(Get<2>(*aZoom)));
GECKOBUNDLE_FINISH(displaySizeBundle);
GECKOBUNDLE_PUT(zoomBundle, "displaySize", displaySizeBundle);
GECKOBUNDLE_FINISH(zoomBundle);
GECKOBUNDLE_PUT(update, "zoom", zoomBundle);
}
GECKOBUNDLE_FINISH(update);
window->OnUpdateSessionStore(update);
}
}
#else
static void DoSessionStoreUpdate(CanonicalBrowsingContext* aBrowsingContext,
const Maybe<nsCString>& aDocShellCaps,
const Maybe<bool>& aPrivatedMode,
SessionStoreFormData* aFormData,
SessionStoreScrollData* aScroll,
const MaybeSessionStoreZoom& aZoom,
bool aNeedCollectSHistory, uint32_t aEpoch) {
UpdateSessionStoreData data;
if (aDocShellCaps.isSome()) {
@ -54,11 +132,19 @@ static void DoSessionStoreUpdate(CanonicalBrowsingContext* aBrowsingContext,
RefPtr<BrowserSessionStore> sessionStore =
BrowserSessionStore::GetOrCreate(aBrowsingContext->Top());
SessionStoreFormData* formData = sessionStore->GetFormdata();
data.mFormdata.Construct(formData);
if (!aFormData) {
SessionStoreFormData* formData = sessionStore->GetFormdata();
data.mFormdata.Construct(formData);
} else {
data.mFormdata.Construct(aFormData);
}
SessionStoreScrollData* scroll = sessionStore->GetScroll();
data.mScroll.Construct(scroll);
if (!aScroll) {
SessionStoreScrollData* scroll = sessionStore->GetScroll();
data.mScroll.Construct(scroll);
} else {
data.mScroll.Construct(aScroll);
}
nsCOMPtr<nsISessionStoreFunctions> funcs = do_ImportModule(
"resource://gre/modules/SessionStoreFunctions.jsm", fallible);
@ -83,6 +169,7 @@ static void DoSessionStoreUpdate(CanonicalBrowsingContext* aBrowsingContext,
Unused << funcs->UpdateSessionStore(nullptr, aBrowsingContext, key, aEpoch,
aNeedCollectSHistory, update);
}
#endif
void SessionStoreParent::FlushAllSessionStoreChildren(
const std::function<void()>& aDone) {
@ -158,13 +245,23 @@ void SessionStoreParent::FinalFlushAllSessionStoreChildren(
mozilla::ipc::IPCResult SessionStoreParent::RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
const bool aNeedCollectSHistory, const uint32_t& aEpoch) {
const MaybeSessionStoreZoom& aZoom, const bool aNeedCollectSHistory,
const uint32_t& aEpoch) {
if (!mBrowsingContext) {
return IPC_OK();
}
DoSessionStoreUpdate(mBrowsingContext, aDocShellCaps, aPrivatedMode,
aNeedCollectSHistory, aEpoch);
RefPtr<SessionStoreFormData> formData =
mHasNewFormData ? mSessionStore->GetFormdata() : nullptr;
RefPtr<SessionStoreScrollData> scroll =
mHasNewScrollPosition ? mSessionStore->GetScroll() : nullptr;
DoSessionStoreUpdate(mBrowsingContext, aDocShellCaps, aPrivatedMode, formData,
scroll, aZoom, aNeedCollectSHistory, aEpoch);
mHasNewFormData = false;
mHasNewScrollPosition = false;
return IPC_OK();
}
@ -173,6 +270,13 @@ mozilla::ipc::IPCResult SessionStoreParent::RecvIncrementalSessionStoreUpdate(
const Maybe<FormData>& aFormData, const Maybe<nsPoint>& aScrollPosition,
uint32_t aEpoch) {
if (!aBrowsingContext.IsNull()) {
if (aFormData.isSome()) {
mHasNewFormData = true;
}
if (aScrollPosition.isSome()) {
mHasNewScrollPosition = true;
}
mSessionStore->UpdateSessionStore(
aBrowsingContext.GetMaybeDiscarded()->Canonical(), aFormData,
aScrollPosition, aEpoch);
@ -192,8 +296,9 @@ mozilla::ipc::IPCResult SessionStoreParent::RecvResetSessionStore(
void SessionStoreParent::SessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
const bool aNeedCollectSHistory, const uint32_t& aEpoch) {
Unused << RecvSessionStoreUpdate(aDocShellCaps, aPrivatedMode,
const MaybeSessionStoreZoom& aZoom, const bool aNeedCollectSHistory,
const uint32_t& aEpoch) {
Unused << RecvSessionStoreUpdate(aDocShellCaps, aPrivatedMode, aZoom,
aNeedCollectSHistory, aEpoch);
}

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PSessionStoreParent.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/SessionStoreScrollData.h"
namespace mozilla::dom {
class BrowserParent;
@ -31,7 +32,8 @@ class SessionStoreParent final : public PSessionStoreParent {
*/
mozilla::ipc::IPCResult RecvSessionStoreUpdate(
const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
const bool aNeedCollectSHistory, const uint32_t& aEpoch);
const MaybeSessionStoreZoom& aZoom, const bool aNeedCollectSHistory,
const uint32_t& aEpoch);
mozilla::ipc::IPCResult RecvIncrementalSessionStoreUpdate(
const MaybeDiscarded<BrowsingContext>& aBrowsingContext,
@ -48,6 +50,7 @@ class SessionStoreParent final : public PSessionStoreParent {
friend class SessionStoreChild;
void SessionStoreUpdate(const Maybe<nsCString>& aDocShellCaps,
const Maybe<bool>& aPrivatedMode,
const MaybeSessionStoreZoom& aZoom,
const bool aNeedCollectSHistory,
const uint32_t& aEpoch);
@ -65,6 +68,9 @@ class SessionStoreParent final : public PSessionStoreParent {
already_AddRefed<SessionStoreParent::FlushTabStatePromise>
FlushSessionStore();
bool mHasNewFormData = false;
bool mHasNewScrollPosition = false;
RefPtr<CanonicalBrowsingContext> mBrowsingContext;
RefPtr<BrowserSessionStore> mSessionStore;
};

Просмотреть файл

@ -7,17 +7,24 @@
#ifndef mozilla_dom_SessionStoreScrollData_h
#define mozilla_dom_SessionStoreScrollData_h
#include "js/TypeDecls.h"
#include "mozilla/WeakPtr.h"
#include "nsPoint.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/SessionStoreChangeListener.h"
namespace mozilla::dom {
class BrowsingContext;
class WindowGlobalParent;
class OwningByteStringOrObjectOrNull;
struct SessionStoreZoomData;
using SessionStoreZoom = mozilla::Tuple<float, uint32_t, uint32_t>;
using MaybeSessionStoreZoom =
mozilla::Maybe<mozilla::Tuple<float, uint32_t, uint32_t>>;
class SessionStoreScrollData final : public nsISupports,
public nsWrapperCache,
@ -53,6 +60,7 @@ class SessionStoreScrollData final : public nsISupports,
~SessionStoreScrollData() = default;
nsPoint mScroll;
MaybeSessionStoreZoom mZoom;
nsTArray<RefPtr<SessionStoreScrollData>> mChildren;
};

Просмотреть файл

@ -139,15 +139,8 @@ class SessionStoreUtils {
const nsTArray<SSCacheCopy>& aValues,
Record<nsCString, Record<nsString, nsString>>& aStorage);
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_THUNDERBIRD) || \
defined(MOZ_SUITE)
static constexpr bool NATIVE_LISTENER = false;
#else
static constexpr bool NATIVE_LISTENER = true;
#endif
static bool CopyProperty(JSContext* aCx, JS::Handle<JSObject*> aDst,
JS::Handle<JSObject*> aSrc, const nsAString& aName);
static bool CopyProperty(JSContext* aCx, JS::HandleObject aDst,
JS::HandleObject aSrc, const nsAString& aName);
template <typename T>
static bool CopyChildren(JSContext* aCx, JS::Handle<JSObject*> aDst,

Просмотреть файл

@ -19,6 +19,7 @@
#include "mozilla/ScopeExit.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/java/EventCallbackWrappers.h"
#include "mozilla/jni/GeckoBundleUtils.h"
// Disable the C++ 2a warning. See bug #1509926
#if defined(__clang__)
@ -38,266 +39,9 @@ bool CheckJS(JSContext* aCx, bool aResult) {
return aResult;
}
nsresult BoxString(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut) {
if (aData.isNullOrUndefined()) {
aOut = nullptr;
return NS_OK;
}
MOZ_ASSERT(aData.isString());
JS::RootedString str(aCx, aData.toString());
if (JS::StringHasLatin1Chars(str)) {
nsAutoJSString autoStr;
NS_ENSURE_TRUE(CheckJS(aCx, autoStr.init(aCx, str)), NS_ERROR_FAILURE);
// StringParam can automatically convert a nsString to jstring.
aOut = jni::StringParam(autoStr, aOut.Env(), fallible);
if (!aOut) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// Two-byte string
JNIEnv* const env = aOut.Env();
const char16_t* chars;
{
JS::AutoCheckCannotGC nogc;
size_t len = 0;
chars = JS_GetTwoByteStringCharsAndLength(aCx, nogc, str, &len);
if (chars) {
aOut = jni::String::LocalRef::Adopt(
env, env->NewString(reinterpret_cast<const jchar*>(chars), len));
}
}
if (NS_WARN_IF(!CheckJS(aCx, !!chars) || !aOut)) {
env->ExceptionClear();
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult BoxObject(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut);
template <typename Type, bool (JS::Value::*IsType)() const,
Type (JS::Value::*ToType)() const, class ArrayType,
typename ArrayType::LocalRef (*NewArray)(const Type*, size_t)>
nsresult BoxArrayPrimitive(JSContext* aCx, JS::HandleObject aData,
jni::Object::LocalRef& aOut, size_t aLength,
JS::HandleValue aElement) {
JS::RootedValue element(aCx);
auto data = MakeUnique<Type[]>(aLength);
data[0] = (aElement.get().*ToType)();
for (size_t i = 1; i < aLength; i++) {
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetElement(aCx, aData, i, &element)),
NS_ERROR_FAILURE);
NS_ENSURE_TRUE((element.get().*IsType)(), NS_ERROR_INVALID_ARG);
data[i] = (element.get().*ToType)();
}
aOut = (*NewArray)(data.get(), aLength);
return NS_OK;
}
template <class Type,
nsresult (*Box)(JSContext*, JS::HandleValue, jni::Object::LocalRef&),
typename IsType>
nsresult BoxArrayObject(JSContext* aCx, JS::HandleObject aData,
jni::Object::LocalRef& aOut, size_t aLength,
JS::HandleValue aElement, IsType&& aIsType) {
auto out = jni::ObjectArray::New<Type>(aLength);
JS::RootedValue element(aCx);
jni::Object::LocalRef jniElement(aOut.Env());
nsresult rv = (*Box)(aCx, aElement, jniElement);
NS_ENSURE_SUCCESS(rv, rv);
out->SetElement(0, jniElement);
for (size_t i = 1; i < aLength; i++) {
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetElement(aCx, aData, i, &element)),
NS_ERROR_FAILURE);
NS_ENSURE_TRUE(element.isNullOrUndefined() || aIsType(element),
NS_ERROR_INVALID_ARG);
rv = (*Box)(aCx, element, jniElement);
NS_ENSURE_SUCCESS(rv, rv);
out->SetElement(i, jniElement);
}
aOut = out;
return NS_OK;
}
nsresult BoxArray(JSContext* aCx, JS::HandleObject aData,
jni::Object::LocalRef& aOut) {
uint32_t length = 0;
NS_ENSURE_TRUE(CheckJS(aCx, JS::GetArrayLength(aCx, aData, &length)),
NS_ERROR_FAILURE);
if (!length) {
// Always represent empty arrays as an empty boolean array.
aOut = java::GeckoBundle::EMPTY_BOOLEAN_ARRAY();
return NS_OK;
}
// We only check the first element's type. If the array has mixed types,
// we'll throw an error during actual conversion.
JS::RootedValue element(aCx);
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetElement(aCx, aData, 0, &element)),
NS_ERROR_FAILURE);
if (element.isBoolean()) {
return BoxArrayPrimitive<bool, &JS::Value::isBoolean, &JS::Value::toBoolean,
jni::BooleanArray, &jni::BooleanArray::New>(
aCx, aData, aOut, length, element);
}
if (element.isInt32()) {
nsresult rv =
BoxArrayPrimitive<int32_t, &JS::Value::isInt32, &JS::Value::toInt32,
jni::IntArray, &jni::IntArray::New>(aCx, aData, aOut,
length, element);
if (rv != NS_ERROR_INVALID_ARG) {
return rv;
}
// Not int32, but we can still try a double array.
}
if (element.isNumber()) {
return BoxArrayPrimitive<double, &JS::Value::isNumber, &JS::Value::toNumber,
jni::DoubleArray, &jni::DoubleArray::New>(
aCx, aData, aOut, length, element);
}
if (element.isNullOrUndefined() || element.isString()) {
const auto isString = [](JS::HandleValue val) -> bool {
return val.isString();
};
nsresult rv = BoxArrayObject<jni::String, &BoxString>(
aCx, aData, aOut, length, element, isString);
if (element.isString() || rv != NS_ERROR_INVALID_ARG) {
return rv;
}
// First element was null/undefined, so it may still be an object array.
}
const auto isObject = [aCx](JS::HandleValue val) -> bool {
if (!val.isObject()) {
return false;
}
bool array = false;
JS::RootedObject obj(aCx, &val.toObject());
// We don't support array of arrays.
return CheckJS(aCx, JS::IsArrayObject(aCx, obj, &array)) && !array;
};
if (element.isNullOrUndefined() || isObject(element)) {
return BoxArrayObject<java::GeckoBundle, &BoxObject>(
aCx, aData, aOut, length, element, isObject);
}
NS_WARNING("Unknown type");
return NS_ERROR_INVALID_ARG;
}
nsresult BoxValue(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut);
nsresult BoxObject(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut) {
if (aData.isNullOrUndefined()) {
aOut = nullptr;
return NS_OK;
}
MOZ_ASSERT(aData.isObject());
JS::Rooted<JS::IdVector> ids(aCx, JS::IdVector(aCx));
JS::RootedObject obj(aCx, &aData.toObject());
bool isArray = false;
if (CheckJS(aCx, JS::IsArrayObject(aCx, obj, &isArray)) && isArray) {
return BoxArray(aCx, obj, aOut);
}
NS_ENSURE_TRUE(CheckJS(aCx, JS_Enumerate(aCx, obj, &ids)), NS_ERROR_FAILURE);
const size_t length = ids.length();
auto keys = jni::ObjectArray::New<jni::String>(length);
auto values = jni::ObjectArray::New<jni::Object>(length);
// Iterate through each property of the JS object.
for (size_t i = 0; i < ids.length(); i++) {
const JS::RootedId id(aCx, ids[i]);
JS::RootedValue idVal(aCx);
JS::RootedValue val(aCx);
jni::Object::LocalRef key(aOut.Env());
jni::Object::LocalRef value(aOut.Env());
NS_ENSURE_TRUE(CheckJS(aCx, JS_IdToValue(aCx, id, &idVal)),
NS_ERROR_FAILURE);
JS::RootedString idStr(aCx, JS::ToString(aCx, idVal));
NS_ENSURE_TRUE(CheckJS(aCx, !!idStr), NS_ERROR_FAILURE);
idVal.setString(idStr);
NS_ENSURE_SUCCESS(BoxString(aCx, idVal, key), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetPropertyById(aCx, obj, id, &val)),
NS_ERROR_FAILURE);
nsresult rv = BoxValue(aCx, val, value);
if (rv == NS_ERROR_INVALID_ARG && !JS_IsExceptionPending(aCx)) {
nsAutoJSString autoStr;
if (CheckJS(aCx, autoStr.init(aCx, idVal.toString()))) {
JS_ReportErrorUTF8(aCx, u8"Invalid event data property %s",
NS_ConvertUTF16toUTF8(autoStr).get());
}
}
NS_ENSURE_SUCCESS(rv, rv);
keys->SetElement(i, key);
values->SetElement(i, value);
}
aOut = java::GeckoBundle::New(keys, values);
return NS_OK;
}
nsresult BoxValue(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut) {
if (aData.isNullOrUndefined()) {
aOut = nullptr;
} else if (aData.isBoolean()) {
aOut = aData.toBoolean() ? java::sdk::Boolean::TRUE()
: java::sdk::Boolean::FALSE();
} else if (aData.isInt32()) {
aOut = java::sdk::Integer::ValueOf(aData.toInt32());
} else if (aData.isNumber()) {
aOut = java::sdk::Double::New(aData.toNumber());
} else if (aData.isString()) {
return BoxString(aCx, aData, aOut);
} else if (aData.isObject()) {
return BoxObject(aCx, aData, aOut);
} else {
NS_WARNING("Unknown type");
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
nsresult BoxData(const nsAString& aEvent, JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut, bool aObjectOnly) {
nsresult rv = NS_ERROR_INVALID_ARG;
if (!aObjectOnly) {
rv = BoxValue(aCx, aData, aOut);
} else if (aData.isObject() || aData.isNullOrUndefined()) {
rv = BoxObject(aCx, aData, aOut);
}
nsresult rv = jni::BoxData(aCx, aData, aOut, aObjectOnly);
if (rv != NS_ERROR_INVALID_ARG) {
return rv;
}

Просмотреть файл

@ -91,6 +91,8 @@ class GeckoViewSupport final
void OnShowDynamicToolbar() const;
void OnUpdateSessionStore(mozilla::jni::Object::Param aBundle);
void PassExternalResponse(java::WebResponse::Param aResponse);
void AttachMediaSessionController(

Просмотреть файл

@ -0,0 +1,289 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 "mozilla/jni/GeckoBundleUtils.h"
#include "JavaBuiltins.h"
#include "js/Warnings.h"
#include "nsJSUtils.h"
#include "js/Array.h"
namespace mozilla::jni {
namespace detail {
bool CheckJS(JSContext* aCx, bool aResult) {
if (!aResult) {
JS_ClearPendingException(aCx);
}
return aResult;
}
nsresult BoxString(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut) {
if (aData.isNullOrUndefined()) {
aOut = nullptr;
return NS_OK;
}
MOZ_ASSERT(aData.isString());
JS::RootedString str(aCx, aData.toString());
if (JS::StringHasLatin1Chars(str)) {
nsAutoJSString autoStr;
NS_ENSURE_TRUE(CheckJS(aCx, autoStr.init(aCx, str)), NS_ERROR_FAILURE);
// StringParam can automatically convert a nsString to jstring.
aOut = jni::StringParam(autoStr, aOut.Env(), fallible);
if (!aOut) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// Two-byte string
JNIEnv* const env = aOut.Env();
const char16_t* chars;
{
JS::AutoCheckCannotGC nogc;
size_t len = 0;
chars = JS_GetTwoByteStringCharsAndLength(aCx, nogc, str, &len);
if (chars) {
aOut = jni::String::LocalRef::Adopt(
env, env->NewString(reinterpret_cast<const jchar*>(chars), len));
}
}
if (NS_WARN_IF(!CheckJS(aCx, !!chars) || !aOut)) {
env->ExceptionClear();
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult BoxObject(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut);
template <typename Type, bool (JS::Value::*IsType)() const,
Type (JS::Value::*ToType)() const, class ArrayType,
typename ArrayType::LocalRef (*NewArray)(const Type*, size_t)>
nsresult BoxArrayPrimitive(JSContext* aCx, JS::HandleObject aData,
jni::Object::LocalRef& aOut, size_t aLength,
JS::HandleValue aElement) {
JS::RootedValue element(aCx);
auto data = MakeUnique<Type[]>(aLength);
data[0] = (aElement.get().*ToType)();
for (size_t i = 1; i < aLength; i++) {
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetElement(aCx, aData, i, &element)),
NS_ERROR_FAILURE);
NS_ENSURE_TRUE((element.get().*IsType)(), NS_ERROR_INVALID_ARG);
data[i] = (element.get().*ToType)();
}
aOut = (*NewArray)(data.get(), aLength);
return NS_OK;
}
template <class Type,
nsresult (*Box)(JSContext*, JS::HandleValue, jni::Object::LocalRef&),
typename IsType>
nsresult BoxArrayObject(JSContext* aCx, JS::HandleObject aData,
jni::Object::LocalRef& aOut, size_t aLength,
JS::HandleValue aElement, IsType&& aIsType) {
auto out = jni::ObjectArray::New<Type>(aLength);
JS::RootedValue element(aCx);
jni::Object::LocalRef jniElement(aOut.Env());
nsresult rv = (*Box)(aCx, aElement, jniElement);
NS_ENSURE_SUCCESS(rv, rv);
out->SetElement(0, jniElement);
for (size_t i = 1; i < aLength; i++) {
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetElement(aCx, aData, i, &element)),
NS_ERROR_FAILURE);
NS_ENSURE_TRUE(element.isNullOrUndefined() || aIsType(element),
NS_ERROR_INVALID_ARG);
rv = (*Box)(aCx, element, jniElement);
NS_ENSURE_SUCCESS(rv, rv);
out->SetElement(i, jniElement);
}
aOut = out;
return NS_OK;
}
nsresult BoxArray(JSContext* aCx, JS::HandleObject aData,
jni::Object::LocalRef& aOut) {
uint32_t length = 0;
NS_ENSURE_TRUE(CheckJS(aCx, JS::GetArrayLength(aCx, aData, &length)),
NS_ERROR_FAILURE);
if (!length) {
// Always represent empty arrays as an empty boolean array.
aOut = java::GeckoBundle::EMPTY_BOOLEAN_ARRAY();
return NS_OK;
}
// We only check the first element's type. If the array has mixed types,
// we'll throw an error during actual conversion.
JS::RootedValue element(aCx);
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetElement(aCx, aData, 0, &element)),
NS_ERROR_FAILURE);
if (element.isBoolean()) {
return BoxArrayPrimitive<bool, &JS::Value::isBoolean, &JS::Value::toBoolean,
jni::BooleanArray, &jni::BooleanArray::New>(
aCx, aData, aOut, length, element);
}
if (element.isInt32()) {
nsresult rv =
BoxArrayPrimitive<int32_t, &JS::Value::isInt32, &JS::Value::toInt32,
jni::IntArray, &jni::IntArray::New>(aCx, aData, aOut,
length, element);
if (rv != NS_ERROR_INVALID_ARG) {
return rv;
}
// Not int32, but we can still try a double array.
}
if (element.isNumber()) {
return BoxArrayPrimitive<double, &JS::Value::isNumber, &JS::Value::toNumber,
jni::DoubleArray, &jni::DoubleArray::New>(
aCx, aData, aOut, length, element);
}
if (element.isNullOrUndefined() || element.isString()) {
const auto isString = [](JS::HandleValue val) -> bool {
return val.isString();
};
nsresult rv = BoxArrayObject<jni::String, &BoxString>(
aCx, aData, aOut, length, element, isString);
if (element.isString() || rv != NS_ERROR_INVALID_ARG) {
return rv;
}
// First element was null/undefined, so it may still be an object array.
}
const auto isObject = [aCx](JS::HandleValue val) -> bool {
if (!val.isObject()) {
return false;
}
bool array = false;
JS::RootedObject obj(aCx, &val.toObject());
// We don't support array of arrays.
return CheckJS(aCx, JS::IsArrayObject(aCx, obj, &array)) && !array;
};
if (element.isNullOrUndefined() || isObject(element)) {
return BoxArrayObject<java::GeckoBundle, &BoxObject>(
aCx, aData, aOut, length, element, isObject);
}
NS_WARNING("Unknown type");
return NS_ERROR_INVALID_ARG;
}
nsresult BoxValue(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut);
nsresult BoxObject(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut) {
if (aData.isNullOrUndefined()) {
aOut = nullptr;
return NS_OK;
}
MOZ_ASSERT(aData.isObject());
JS::Rooted<JS::IdVector> ids(aCx, JS::IdVector(aCx));
JS::RootedObject obj(aCx, &aData.toObject());
bool isArray = false;
if (CheckJS(aCx, JS::IsArrayObject(aCx, obj, &isArray)) && isArray) {
return BoxArray(aCx, obj, aOut);
}
NS_ENSURE_TRUE(CheckJS(aCx, JS_Enumerate(aCx, obj, &ids)), NS_ERROR_FAILURE);
const size_t length = ids.length();
auto keys = jni::ObjectArray::New<jni::String>(length);
auto values = jni::ObjectArray::New<jni::Object>(length);
// Iterate through each property of the JS object.
for (size_t i = 0; i < ids.length(); i++) {
const JS::RootedId id(aCx, ids[i]);
JS::RootedValue idVal(aCx);
JS::RootedValue val(aCx);
jni::Object::LocalRef key(aOut.Env());
jni::Object::LocalRef value(aOut.Env());
NS_ENSURE_TRUE(CheckJS(aCx, JS_IdToValue(aCx, id, &idVal)),
NS_ERROR_FAILURE);
JS::RootedString idStr(aCx, JS::ToString(aCx, idVal));
NS_ENSURE_TRUE(CheckJS(aCx, !!idStr), NS_ERROR_FAILURE);
idVal.setString(idStr);
NS_ENSURE_SUCCESS(BoxString(aCx, idVal, key), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(CheckJS(aCx, JS_GetPropertyById(aCx, obj, id, &val)),
NS_ERROR_FAILURE);
nsresult rv = BoxValue(aCx, val, value);
if (rv == NS_ERROR_INVALID_ARG && !JS_IsExceptionPending(aCx)) {
nsAutoJSString autoStr;
if (CheckJS(aCx, autoStr.init(aCx, idVal.toString()))) {
JS_ReportErrorUTF8(aCx, "Invalid event data property %s",
NS_ConvertUTF16toUTF8(autoStr).get());
}
}
NS_ENSURE_SUCCESS(rv, rv);
keys->SetElement(i, key);
values->SetElement(i, value);
}
aOut = java::GeckoBundle::New(keys, values);
return NS_OK;
}
nsresult BoxValue(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut) {
if (aData.isNullOrUndefined()) {
aOut = nullptr;
} else if (aData.isBoolean()) {
aOut = aData.toBoolean() ? java::sdk::Boolean::TRUE()
: java::sdk::Boolean::FALSE();
} else if (aData.isInt32()) {
aOut = java::sdk::Integer::ValueOf(aData.toInt32());
} else if (aData.isNumber()) {
aOut = java::sdk::Double::New(aData.toNumber());
} else if (aData.isString()) {
return BoxString(aCx, aData, aOut);
} else if (aData.isObject()) {
return BoxObject(aCx, aData, aOut);
} else {
NS_WARNING("Unknown type");
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
} // namespace detail
nsresult BoxData(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut, bool aObjectOnly) {
nsresult rv = NS_ERROR_INVALID_ARG;
if (!aObjectOnly) {
rv = detail::BoxValue(aCx, aData, aOut);
} else if (aData.isObject() || aData.isNullOrUndefined()) {
rv = detail::BoxObject(aCx, aData, aOut);
}
return rv;
}
} // namespace mozilla::jni

Просмотреть файл

@ -9,6 +9,8 @@
#include "mozilla/java/GeckoBundleWrappers.h"
#include "jsapi.h"
namespace mozilla {
namespace jni {
@ -35,6 +37,9 @@ namespace jni {
auto name = \
mozilla::java::GeckoBundle::New(_##name##_jkeys, _##name##_jvalues);
nsresult BoxData(JSContext* aCx, JS::HandleValue aData,
jni::Object::LocalRef& aOut, bool aObjectOnly);
} // namespace jni
} // namespace mozilla

Просмотреть файл

@ -21,6 +21,7 @@ EXPORTS.mozilla.jni += [
UNIFIED_SOURCES += [
"Conversions.cpp",
"GeckoBundleUtils.cpp",
"Utils.cpp",
]

Просмотреть файл

@ -2093,6 +2093,15 @@ RefPtr<MozPromise<bool, bool, false>> nsWindow::OnLoadRequest(
: nullptr;
}
void nsWindow::OnUpdateSessionStore(mozilla::jni::Object::Param aBundle) {
auto geckoViewSupport(mGeckoViewSupport.Access());
if (!geckoViewSupport) {
return;
}
geckoViewSupport->OnUpdateSessionStore(aBundle);
}
float nsWindow::GetDPI() {
float dpi = 160.0f;
@ -2430,6 +2439,16 @@ void nsWindow::ShowDynamicToolbar() {
acc->OnShowDynamicToolbar();
}
void GeckoViewSupport::OnUpdateSessionStore(
mozilla::jni::Object::Param aBundle) {
GeckoSession::Window::LocalRef window(mGeckoViewWindow);
if (!window) {
return;
}
window->OnUpdateSessionStore(aBundle);
}
void nsWindow::OnSizeChanged(const gfx::IntSize& aSize) {
ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, aSize.width,
aSize.height);

Просмотреть файл

@ -69,6 +69,8 @@ class nsWindow final : public nsBaseWidget {
nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture,
bool aIsTopLevel);
void OnUpdateSessionStore(mozilla::jni::Object::Param aBundle);
private:
// Unique ID given to each widget, used to map Surfaces to widgets
// in the CompositorSurfaceManager.