mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1453788 - Allow top level HTML windows to have persistent window state. r=smaug
Move tracking of persistent window state into nsXULWindow. Also, move special handling of the width/height of the window into nsXULWindow. MozReview-Commit-ID: LOmHGyYeNSU --HG-- extra : rebase_source : bcea16eb6209ff789948644a64968a7325cea4ef
This commit is contained in:
parent
65d34faa5e
commit
295e2f4aca
@ -1161,41 +1161,6 @@ XULDocument::Persist(const nsAString& aID,
|
||||
aRv = Persist(element, nameSpaceID, tag);
|
||||
}
|
||||
|
||||
enum class ConversionDirection {
|
||||
InnerToOuter,
|
||||
OuterToInner,
|
||||
};
|
||||
|
||||
static void
|
||||
ConvertWindowSize(nsIXULWindow* aWin,
|
||||
nsAtom* aAttr,
|
||||
ConversionDirection aDirection,
|
||||
nsAString& aInOutString)
|
||||
{
|
||||
MOZ_ASSERT(aWin);
|
||||
MOZ_ASSERT(aAttr == nsGkAtoms::width || aAttr == nsGkAtoms::height);
|
||||
|
||||
nsresult rv;
|
||||
int32_t size = aInOutString.ToInteger(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t sizeDiff = aAttr == nsGkAtoms::width
|
||||
? aWin->GetOuterToInnerWidthDifferenceInCSSPixels()
|
||||
: aWin->GetOuterToInnerHeightDifferenceInCSSPixels();
|
||||
|
||||
if (!sizeDiff) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t multiplier =
|
||||
aDirection == ConversionDirection::InnerToOuter ? 1 : - 1;
|
||||
|
||||
CopyASCIItoUTF16(nsPrintfCString("%d", size + multiplier * sizeDiff),
|
||||
aInOutString);
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULDocument::Persist(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute)
|
||||
@ -1236,16 +1201,9 @@ XULDocument::Persist(Element* aElement, int32_t aNameSpaceID,
|
||||
return mLocalStore->RemoveValue(uri, id, attrstr);
|
||||
}
|
||||
|
||||
// Make sure we store the <window> attributes as outer window size, see
|
||||
// bug 1444525 & co.
|
||||
if (aElement->IsXULElement(nsGkAtoms::window) &&
|
||||
(aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
|
||||
ConvertWindowSize(win,
|
||||
aAttribute,
|
||||
ConversionDirection::InnerToOuter,
|
||||
valuestr);
|
||||
}
|
||||
// Persisting attributes to windows is handled by nsXULWindow.
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mLocalStore->SetValue(uri, id, attrstr, valuestr);
|
||||
@ -1837,21 +1795,9 @@ XULDocument::ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert attributes from outer size to inner size for top-level
|
||||
// windows, see bug 1444525 & co.
|
||||
if (element->IsXULElement(nsGkAtoms::window) &&
|
||||
(attr == nsGkAtoms::width || attr == nsGkAtoms::height)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
|
||||
nsAutoString maybeConvertedValue = value;
|
||||
ConvertWindowSize(win,
|
||||
attr,
|
||||
ConversionDirection::OuterToInner,
|
||||
maybeConvertedValue);
|
||||
Unused <<
|
||||
element->SetAttr(kNameSpaceID_None, attr, maybeConvertedValue, true);
|
||||
|
||||
continue;
|
||||
}
|
||||
// Applying persistent attributes to windows is handled by nsXULWindow.
|
||||
if (element->IsXULElement(nsGkAtoms::window)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
|
||||
|
@ -1453,6 +1453,7 @@ GK_ATOM(xulcontentsgenerated, "xulcontentsgenerated")
|
||||
GK_ATOM(yes, "yes")
|
||||
GK_ATOM(z_index, "z-index")
|
||||
GK_ATOM(zeroDigit, "zero-digit")
|
||||
GK_ATOM(zlevel, "zlevel")
|
||||
|
||||
|
||||
GK_ATOM(percentage, "%")
|
||||
|
@ -92,6 +92,7 @@ nsXULWindow::nsXULWindow(uint32_t aChromeFlags)
|
||||
mContinueModalLoop(false),
|
||||
mDebuting(false),
|
||||
mChromeLoaded(false),
|
||||
mPersistentWindowStateLoaded(false),
|
||||
mSizingShellFromXUL(false),
|
||||
mShowAfterLoad(false),
|
||||
mIntrinsicallySized(false),
|
||||
@ -1123,6 +1124,7 @@ void nsXULWindow::OnChromeLoaded()
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mChromeLoaded = true;
|
||||
ApplyChromeFlags();
|
||||
LoadPersistentWindowState();
|
||||
SyncAttributesToWidget();
|
||||
SizeShell();
|
||||
|
||||
@ -1598,6 +1600,147 @@ void nsXULWindow::SyncAttributesToWidget()
|
||||
}
|
||||
}
|
||||
|
||||
enum class ConversionDirection {
|
||||
InnerToOuter,
|
||||
OuterToInner,
|
||||
};
|
||||
|
||||
static void
|
||||
ConvertWindowSize(nsIXULWindow* aWin,
|
||||
const nsAtom* aAttr,
|
||||
ConversionDirection aDirection,
|
||||
nsAString& aInOutString)
|
||||
{
|
||||
MOZ_ASSERT(aWin);
|
||||
MOZ_ASSERT(aAttr == nsGkAtoms::width || aAttr == nsGkAtoms::height);
|
||||
|
||||
nsresult rv;
|
||||
int32_t size = aInOutString.ToInteger(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t sizeDiff = aAttr == nsGkAtoms::width
|
||||
? aWin->GetOuterToInnerWidthDifferenceInCSSPixels()
|
||||
: aWin->GetOuterToInnerHeightDifferenceInCSSPixels();
|
||||
|
||||
if (!sizeDiff) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t multiplier =
|
||||
aDirection == ConversionDirection::InnerToOuter ? 1 : - 1;
|
||||
|
||||
CopyASCIItoUTF16(nsPrintfCString("%d", size + multiplier * sizeDiff),
|
||||
aInOutString);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULWindow::GetPersistentValue(const nsAtom* aAttr,
|
||||
nsAString& aValue)
|
||||
{
|
||||
nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
|
||||
if (!docShellElement) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoString windowElementId;
|
||||
docShellElement->GetId(windowElementId);
|
||||
// Elements must have an ID to be persisted.
|
||||
if (windowElementId.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> ownerDoc = docShellElement->OwnerDoc();
|
||||
nsIURI* docURI = ownerDoc->GetDocumentURI();
|
||||
if (!docURI) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = docURI->GetSpec(utf8uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
rv = mLocalStore->GetValue(uri,
|
||||
windowElementId,
|
||||
nsDependentAtomString(aAttr),
|
||||
aValue);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aAttr == nsGkAtoms::width || aAttr == nsGkAtoms::height) {
|
||||
// Convert attributes from outer size to inner size for top-level
|
||||
// windows, see bug 1444525 & co.
|
||||
ConvertWindowSize(this,
|
||||
aAttr,
|
||||
ConversionDirection::OuterToInner,
|
||||
aValue);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULWindow::SetPersistentValue(const nsAtom* aAttr,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
|
||||
if (!docShellElement) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoString windowElementId;
|
||||
docShellElement->GetId(windowElementId);
|
||||
// Match the behavior of XULDocument and only persist values if the element
|
||||
// has an ID.
|
||||
if (windowElementId.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> ownerDoc = docShellElement->OwnerDoc();
|
||||
nsIURI* docURI = ownerDoc->GetDocumentURI();
|
||||
if (!docURI) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = docURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
nsAutoString maybeConvertedValue(aValue);
|
||||
if (aAttr == nsGkAtoms::width || aAttr == nsGkAtoms::height) {
|
||||
// Make sure we store the <window> attributes as outer window size, see
|
||||
// bug 1444525 & co.
|
||||
ConvertWindowSize(this,
|
||||
aAttr,
|
||||
ConversionDirection::InnerToOuter,
|
||||
maybeConvertedValue);
|
||||
}
|
||||
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
return mLocalStore->SetValue(uri,
|
||||
windowElementId,
|
||||
nsDependentAtomString(aAttr),
|
||||
maybeConvertedValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
{
|
||||
// can happen when the persistence timer fires at an inopportune time
|
||||
@ -1639,17 +1782,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
}
|
||||
|
||||
nsAutoString sizeString;
|
||||
nsAutoString windowElementId;
|
||||
|
||||
// fetch docShellElement's ID and XUL owner document
|
||||
RefPtr<dom::XULDocument> ownerXULDoc =
|
||||
docShellElement->OwnerDoc()->IsXULDocument()
|
||||
? docShellElement->OwnerDoc()->AsXULDocument() : nullptr;
|
||||
if (docShellElement->IsXULElement()) {
|
||||
docShellElement->GetId(windowElementId);
|
||||
}
|
||||
|
||||
bool shouldPersist = !isFullscreen && ownerXULDoc;
|
||||
bool shouldPersist = !isFullscreen;
|
||||
ErrorResult rv;
|
||||
// (only for size elements which are persisted)
|
||||
if ((mPersistentAttributesDirty & PAD_POSITION) && gotRestoredBounds) {
|
||||
@ -1658,8 +1791,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
sizeString.AppendInt(NSToIntRound(rect.X() / posScale.scale));
|
||||
docShellElement->SetAttribute(SCREENX_ATTRIBUTE, sizeString, rv);
|
||||
if (shouldPersist) {
|
||||
IgnoredErrorResult err;
|
||||
ownerXULDoc->Persist(windowElementId, SCREENX_ATTRIBUTE, err);
|
||||
Unused << SetPersistentValue(nsGkAtoms::screenX, sizeString);
|
||||
}
|
||||
}
|
||||
if (persistString.Find("screenY") >= 0) {
|
||||
@ -1667,8 +1799,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
sizeString.AppendInt(NSToIntRound(rect.Y() / posScale.scale));
|
||||
docShellElement->SetAttribute(SCREENY_ATTRIBUTE, sizeString, rv);
|
||||
if (shouldPersist) {
|
||||
IgnoredErrorResult err;
|
||||
ownerXULDoc->Persist(windowElementId, SCREENY_ATTRIBUTE, err);
|
||||
Unused << SetPersistentValue(nsGkAtoms::screenY, sizeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1680,8 +1811,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
sizeString.AppendInt(NSToIntRound(innerRect.Width() / sizeScale.scale));
|
||||
docShellElement->SetAttribute(WIDTH_ATTRIBUTE, sizeString, rv);
|
||||
if (shouldPersist) {
|
||||
IgnoredErrorResult err;
|
||||
ownerXULDoc->Persist(windowElementId, WIDTH_ATTRIBUTE, err);
|
||||
Unused << SetPersistentValue(nsGkAtoms::width, sizeString);
|
||||
}
|
||||
}
|
||||
if (persistString.Find("height") >= 0) {
|
||||
@ -1689,8 +1819,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
sizeString.AppendInt(NSToIntRound(innerRect.Height() / sizeScale.scale));
|
||||
docShellElement->SetAttribute(HEIGHT_ATTRIBUTE, sizeString, rv);
|
||||
if (shouldPersist) {
|
||||
IgnoredErrorResult err;
|
||||
ownerXULDoc->Persist(windowElementId, HEIGHT_ATTRIBUTE, err);
|
||||
Unused << SetPersistentValue(nsGkAtoms::height, sizeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1707,8 +1836,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
sizeString.Assign(SIZEMODE_NORMAL);
|
||||
docShellElement->SetAttribute(MODE_ATTRIBUTE, sizeString, rv);
|
||||
if (shouldPersist && persistString.Find("sizemode") >= 0) {
|
||||
IgnoredErrorResult err;
|
||||
ownerXULDoc->Persist(windowElementId, MODE_ATTRIBUTE, err);
|
||||
Unused << SetPersistentValue(nsGkAtoms::sizemode, sizeString);
|
||||
}
|
||||
}
|
||||
if (persistString.Find("zlevel") >= 0) {
|
||||
@ -1720,8 +1848,7 @@ NS_IMETHODIMP nsXULWindow::SavePersistentAttributes()
|
||||
sizeString.AppendInt(zLevel);
|
||||
docShellElement->SetAttribute(ZLEVEL_ATTRIBUTE, sizeString, rv);
|
||||
if (shouldPersist) {
|
||||
IgnoredErrorResult err;
|
||||
ownerXULDoc->Persist(windowElementId, ZLEVEL_ATTRIBUTE, err);
|
||||
Unused << SetPersistentValue(nsGkAtoms::zlevel, sizeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2280,11 +2407,53 @@ NS_IMETHODIMP
|
||||
nsXULWindow::BeforeStartLayout()
|
||||
{
|
||||
ApplyChromeFlags();
|
||||
LoadPersistentWindowState();
|
||||
SyncAttributesToWidget();
|
||||
SizeShell();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsXULWindow::LoadPersistentWindowState()
|
||||
{
|
||||
// Only apply the persisted state once.
|
||||
if (mPersistentWindowStateLoaded) {
|
||||
return;
|
||||
}
|
||||
mPersistentWindowStateLoaded = true;
|
||||
|
||||
nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
|
||||
if (!docShellElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the window wants to persist anything.
|
||||
nsAutoString persist;
|
||||
docShellElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
|
||||
if (persist.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto loadValue = [&] (const nsAtom* aAttr) {
|
||||
nsDependentAtomString attrString(aAttr);
|
||||
if (persist.Find(attrString) >= 0) {
|
||||
nsAutoString value;
|
||||
nsresult rv = GetPersistentValue(aAttr, value);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to get persistent state.");
|
||||
if (NS_SUCCEEDED(rv) && !value.IsEmpty()) {
|
||||
IgnoredErrorResult err;
|
||||
docShellElement->SetAttribute(attrString, value, err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loadValue(nsGkAtoms::screenX);
|
||||
loadValue(nsGkAtoms::screenY);
|
||||
loadValue(nsGkAtoms::width);
|
||||
loadValue(nsGkAtoms::height);
|
||||
loadValue(nsGkAtoms::sizemode);
|
||||
}
|
||||
|
||||
void
|
||||
nsXULWindow::SizeShell()
|
||||
{
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsIWidgetListener.h"
|
||||
#include "nsITabParent.h"
|
||||
#include "nsIXULStore.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -41,6 +42,8 @@ class Element;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsAtom;
|
||||
|
||||
// nsXULWindow
|
||||
|
||||
#define NS_XULWINDOW_IMPL_CID \
|
||||
@ -142,6 +145,12 @@ protected:
|
||||
void PersistentAttributesDirty(uint32_t aDirtyFlags);
|
||||
nsresult GetTabCount(uint32_t* aResult);
|
||||
|
||||
void LoadPersistentWindowState();
|
||||
nsresult GetPersistentValue(const nsAtom* aAttr,
|
||||
nsAString& aValue);
|
||||
nsresult SetPersistentValue(const nsAtom* aAttr,
|
||||
const nsAString& aValue);
|
||||
|
||||
nsChromeTreeOwner* mChromeTreeOwner;
|
||||
nsContentTreeOwner* mContentTreeOwner;
|
||||
nsContentTreeOwner* mPrimaryContentTreeOwner;
|
||||
@ -157,6 +166,7 @@ protected:
|
||||
bool mContinueModalLoop;
|
||||
bool mDebuting; // being made visible right now
|
||||
bool mChromeLoaded; // True when chrome has loaded
|
||||
bool mPersistentWindowStateLoaded;
|
||||
bool mSizingShellFromXUL; // true when in SizeShell()
|
||||
bool mShowAfterLoad;
|
||||
bool mIntrinsicallySized;
|
||||
@ -186,6 +196,7 @@ private:
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult GetPrimaryTabParentSize(int32_t* aWidth, int32_t* aHeight);
|
||||
nsresult GetPrimaryContentShellSize(int32_t* aWidth, int32_t* aHeight);
|
||||
nsresult SetPrimaryTabParentSize(int32_t aWidth, int32_t aHeight);
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsXULWindow, NS_XULWINDOW_IMPL_CID)
|
||||
|
Loading…
Reference in New Issue
Block a user