mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1490464 - Fix XUL attribute persistence for browser.xhtml. r=smaug
Move XUL persistence handling into it's own class and make it a separate nsIDocumentObserver so it can also be used in non-XUL documents. To avoid adding persistence to all non-XUL documents, a document must add the "mozpersist" attribute to the root element if it wants enable the feature. Differential Revision: https://phabricator.services.mozilla.com/D6802 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
1f08e736e4
commit
9058324771
@ -73,6 +73,7 @@
|
||||
persist="screenX screenY width height sizemode"
|
||||
#ifdef BROWSER_XHTML
|
||||
hidden="true"
|
||||
mozpersist=""
|
||||
#endif
|
||||
>
|
||||
|
||||
|
@ -259,6 +259,7 @@
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "mozilla/dom/XULBroadcastManager.h"
|
||||
#include "mozilla/dom/XULPersist.h"
|
||||
#include "mozilla/dom/TreeBoxObject.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXULCommandDispatcher.h"
|
||||
@ -1737,6 +1738,10 @@ nsDocument::~nsDocument()
|
||||
mXULBroadcastManager->DropDocumentReference();
|
||||
}
|
||||
|
||||
if (mXULPersist) {
|
||||
mXULPersist->DropDocumentReference();
|
||||
}
|
||||
|
||||
delete mHeaderData;
|
||||
|
||||
ClearAllBoxObjects();
|
||||
@ -8972,6 +8977,13 @@ nsIDocument::SetReadyStateInternal(ReadyState rs)
|
||||
}
|
||||
|
||||
if (READYSTATE_INTERACTIVE == rs) {
|
||||
if (nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
|
||||
Element* root = GetRootElement();
|
||||
if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozpersist)) {
|
||||
mXULPersist = new XULPersist(this);
|
||||
mXULPersist->Init();
|
||||
}
|
||||
}
|
||||
TriggerInitialDocumentTranslation();
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,7 @@ class AnonymousContent;
|
||||
class Attr;
|
||||
class BoxObject;
|
||||
class XULBroadcastManager;
|
||||
class XULPersist;
|
||||
class ClientInfo;
|
||||
class ClientState;
|
||||
class CDATASection;
|
||||
@ -4756,6 +4757,7 @@ protected:
|
||||
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
|
||||
|
||||
RefPtr<mozilla::dom::XULBroadcastManager> mXULBroadcastManager;
|
||||
RefPtr<mozilla::dom::XULPersist> mXULPersist;
|
||||
|
||||
// At the moment, trackers might be blocked by Tracking Protection or FastBlock.
|
||||
// In order to know the numbers of trackers detected and blocked, we add
|
||||
|
@ -82,6 +82,7 @@
|
||||
#include "mozilla/dom/ProcessingInstruction.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/XULDocumentBinding.h"
|
||||
#include "mozilla/dom/XULPersist.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -127,7 +128,6 @@ namespace dom {
|
||||
XULDocument::XULDocument(void)
|
||||
: XMLDocument("application/vnd.mozilla.xul+xml"),
|
||||
mNextSrcLoadWaiter(nullptr),
|
||||
mApplyingPersistedAttrs(false),
|
||||
mIsWritingFastLoad(false),
|
||||
mDocumentLoaded(false),
|
||||
mStillWalking(false),
|
||||
@ -201,12 +201,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULDocument, XMLDocument)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPrototype)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypes)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStore)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULDocument, XMLDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStore)
|
||||
//XXX We should probably unlink all the objects we traverse.
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -423,58 +421,6 @@ XULDocument::OnPrototypeLoadDone(bool aResumeWalk)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldPersistAttribute(Element* aElement, nsAtom* aAttribute)
|
||||
{
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
// This is not an element of the top document, its owner is
|
||||
// not an nsXULWindow. Persist it.
|
||||
if (aElement->OwnerDoc()->GetParentDocument()) {
|
||||
return true;
|
||||
}
|
||||
// The following attributes of xul:window should be handled in
|
||||
// nsXULWindow::SavePersistentAttributes instead of here.
|
||||
if (aAttribute == nsGkAtoms::screenX ||
|
||||
aAttribute == nsGkAtoms::screenY ||
|
||||
aAttribute == nsGkAtoms::width ||
|
||||
aAttribute == nsGkAtoms::height ||
|
||||
aAttribute == nsGkAtoms::sizemode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ASSERTION(aElement->OwnerDoc() == this, "unexpected doc");
|
||||
|
||||
// Might not need this, but be safe for now.
|
||||
nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
|
||||
|
||||
// See if there is anything we need to persist in the localstore.
|
||||
//
|
||||
// XXX Namespace handling broken :-(
|
||||
nsAutoString persist;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
|
||||
// Persistence of attributes of xul:window is handled in nsXULWindow.
|
||||
if (ShouldPersistAttribute(aElement, aAttribute) && !persist.IsEmpty() &&
|
||||
// XXXldb This should check that it's a token, not just a substring.
|
||||
persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod<Element*, int32_t, nsAtom*>(
|
||||
"dom::XULDocument::Persist",
|
||||
this,
|
||||
&XULDocument::Persist,
|
||||
aElement,
|
||||
kNameSpaceID_None,
|
||||
aAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::ContentAppended(nsIContent* aFirstNewContent)
|
||||
{
|
||||
@ -513,58 +459,6 @@ XULDocument::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling)
|
||||
// nsIDocument interface
|
||||
//
|
||||
|
||||
|
||||
void
|
||||
XULDocument::Persist(Element* aElement, int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute)
|
||||
{
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()))
|
||||
return;
|
||||
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
|
||||
nsAtomString attrstr(aAttribute);
|
||||
|
||||
nsAutoString valuestr;
|
||||
aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocumentURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
bool hasAttr;
|
||||
rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAttr && valuestr.IsEmpty()) {
|
||||
mLocalStore->RemoveValue(uri, id, attrstr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Persisting attributes to top level windows is handled by nsXULWindow.
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mLocalStore->SetValue(uri, id, attrstr, valuestr);
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::AddElementToDocumentPost(Element* aElement)
|
||||
{
|
||||
@ -721,145 +615,6 @@ XULDocument::PrepareToLoadPrototype(nsIURI* aURI, const char* aCommand,
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
XULDocument::ApplyPersistentAttributes()
|
||||
{
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(NodePrincipal()))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// Add all of the 'persisted' attributes into the content
|
||||
// model.
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
mApplyingPersistedAttrs = true;
|
||||
ApplyPersistentAttributesInternal();
|
||||
mApplyingPersistedAttrs = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
XULDocument::ApplyPersistentAttributesInternal()
|
||||
{
|
||||
nsCOMArray<Element> elements;
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocumentURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of element IDs for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> ids;
|
||||
rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = false;
|
||||
ids->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
ids->GetNext(id);
|
||||
|
||||
nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(id);
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We want to hold strong refs to the elements while applying
|
||||
// persistent attributes, just in case.
|
||||
elements.Clear();
|
||||
elements.SetCapacity(entry->GetIdElements().Length());
|
||||
for (Element* element : entry->GetIdElements()) {
|
||||
elements.AppendObject(element);
|
||||
}
|
||||
if (elements.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = ApplyPersistentAttributesToElements(id, elements);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULDocument::ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements)
|
||||
{
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocumentURI->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of attributes for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> attrs;
|
||||
rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = PR_FALSE;
|
||||
attrs->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrstr;
|
||||
attrs->GetNext(attrstr);
|
||||
|
||||
nsAutoString value;
|
||||
rv = mLocalStore->GetValue(uri, aID, attrstr, value);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<nsAtom> attr = NS_Atomize(attrstr);
|
||||
if (NS_WARN_IF(!attr)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t cnt = aElements.Count();
|
||||
for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
|
||||
RefPtr<Element> element = aElements.SafeObjectAt(i);
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Applying persistent attributes to top level windows is handled
|
||||
// by nsXULWindow.
|
||||
if (element->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
XULDocument::TraceProtos(JSTracer* aTrc)
|
||||
{
|
||||
@ -1282,7 +1037,8 @@ XULDocument::ResumeWalk()
|
||||
// If we get here, there is nothing left for us to walk. The content
|
||||
// model is built and ready for layout.
|
||||
|
||||
ApplyPersistentAttributes();
|
||||
mXULPersist = new XULPersist(this);
|
||||
mXULPersist->Init();
|
||||
|
||||
mStillWalking = false;
|
||||
if (mPendingSheets == 0) {
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
#include "nsIXULStore.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/ScriptLoader.h"
|
||||
@ -83,7 +82,6 @@ public:
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
|
||||
/**
|
||||
* Notify the XUL document that a subtree has been added
|
||||
@ -146,11 +144,6 @@ protected:
|
||||
nsIPrincipal* aDocumentPrincipal,
|
||||
nsIParser** aResult);
|
||||
|
||||
nsresult ApplyPersistentAttributes();
|
||||
nsresult ApplyPersistentAttributesInternal();
|
||||
nsresult ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements);
|
||||
|
||||
void AddElementToDocumentPost(Element* aElement);
|
||||
|
||||
static void DirectionChanged(const char* aPrefName, XULDocument* aData);
|
||||
@ -160,11 +153,6 @@ protected:
|
||||
|
||||
static LazyLogModule gXULLog;
|
||||
|
||||
void
|
||||
Persist(mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
|
||||
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// IMPORTANT: The ownership implicit in the following member
|
||||
@ -177,8 +165,6 @@ protected:
|
||||
|
||||
XULDocument* mNextSrcLoadWaiter; // [OWNER] but not COMPtr
|
||||
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
bool mApplyingPersistedAttrs;
|
||||
bool mIsWritingFastLoad;
|
||||
bool mDocumentLoaded;
|
||||
/**
|
||||
|
285
dom/xul/XULPersist.cpp
Normal file
285
dom/xul/XULPersist.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
/* -*- 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 https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "XULPersist.h"
|
||||
|
||||
#include "nsIXULStore.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static bool
|
||||
ShouldPersistAttribute(Element* aElement, nsAtom* aAttribute)
|
||||
{
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
// This is not an element of the top document, its owner is
|
||||
// not an nsXULWindow. Persist it.
|
||||
if (aElement->OwnerDoc()->GetParentDocument()) {
|
||||
return true;
|
||||
}
|
||||
// The following attributes of xul:window should be handled in
|
||||
// nsXULWindow::SavePersistentAttributes instead of here.
|
||||
if (aAttribute == nsGkAtoms::screenX ||
|
||||
aAttribute == nsGkAtoms::screenY ||
|
||||
aAttribute == nsGkAtoms::width ||
|
||||
aAttribute == nsGkAtoms::height ||
|
||||
aAttribute == nsGkAtoms::sizemode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(XULPersist, nsIDocumentObserver)
|
||||
|
||||
XULPersist::XULPersist(nsIDocument* aDocument)
|
||||
: nsStubDocumentObserver(),
|
||||
mDocument(aDocument)
|
||||
{
|
||||
}
|
||||
|
||||
XULPersist::~XULPersist()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::Init()
|
||||
{
|
||||
ApplyPersistentAttributes();
|
||||
mDocument->AddObserver(this);
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::DropDocumentReference()
|
||||
{
|
||||
mDocument->RemoveObserver(this);
|
||||
mDocument = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::AttributeChanged(dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ASSERTION(aElement->OwnerDoc() == mDocument, "unexpected doc");
|
||||
|
||||
// Might not need this, but be safe for now.
|
||||
nsCOMPtr<nsIDocumentObserver> kungFuDeathGrip(this);
|
||||
|
||||
// See if there is anything we need to persist in the localstore.
|
||||
//
|
||||
// XXX Namespace handling broken :-(
|
||||
nsAutoString persist;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
|
||||
// Persistence of attributes of xul:window is handled in nsXULWindow.
|
||||
if (ShouldPersistAttribute(aElement, aAttribute) && !persist.IsEmpty() &&
|
||||
// XXXldb This should check that it's a token, not just a substring.
|
||||
persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
|
||||
nsContentUtils::AddScriptRunner(
|
||||
NewRunnableMethod<Element*, int32_t, nsAtom*>(
|
||||
"dom::XULPersist::Persist",
|
||||
this,
|
||||
&XULPersist::Persist,
|
||||
aElement,
|
||||
kNameSpaceID_None,
|
||||
aAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
XULPersist::Persist(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return;
|
||||
}
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
|
||||
nsAtomString attrstr(aAttribute);
|
||||
|
||||
nsAutoString valuestr;
|
||||
aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
bool hasAttr;
|
||||
rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAttr && valuestr.IsEmpty()) {
|
||||
mLocalStore->RemoveValue(uri, id, attrstr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Persisting attributes to top level windows is handled by nsXULWindow.
|
||||
if (aElement->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = mDocument->GetXULWindowIfToplevelChrome()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mLocalStore->SetValue(uri, id, attrstr, valuestr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULPersist::ApplyPersistentAttributes()
|
||||
{
|
||||
if (!mDocument) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
// For non-chrome documents, persistance is simply broken
|
||||
if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Add all of the 'persisted' attributes into the content
|
||||
// model.
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyPersistentAttributesInternal();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULPersist::ApplyPersistentAttributesInternal()
|
||||
{
|
||||
nsCOMArray<Element> elements;
|
||||
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of element IDs for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> ids;
|
||||
rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = false;
|
||||
ids->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
ids->GetNext(id);
|
||||
|
||||
// We want to hold strong refs to the elements while applying
|
||||
// persistent attributes, just in case.
|
||||
const nsTArray<Element*>* allElements = mDocument->GetAllElementsForId(id);
|
||||
if (!allElements) {
|
||||
continue;
|
||||
}
|
||||
elements.Clear();
|
||||
elements.SetCapacity(allElements->Length());
|
||||
for (Element* element : *allElements) {
|
||||
elements.AppendObject(element);
|
||||
}
|
||||
|
||||
rv = ApplyPersistentAttributesToElements(id, elements);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XULPersist::ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements)
|
||||
{
|
||||
nsAutoCString utf8uri;
|
||||
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of attributes for which persisted values are available
|
||||
nsCOMPtr<nsIStringEnumerator> attrs;
|
||||
rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
bool hasmore = PR_FALSE;
|
||||
attrs->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrstr;
|
||||
attrs->GetNext(attrstr);
|
||||
|
||||
nsAutoString value;
|
||||
rv = mLocalStore->GetValue(uri, aID, attrstr, value);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<nsAtom> attr = NS_Atomize(attrstr);
|
||||
if (NS_WARN_IF(!attr)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t cnt = aElements.Length();
|
||||
for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
|
||||
Element* element = aElements.SafeElementAt(i);
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Applying persistent attributes to top level windows is handled
|
||||
// by nsXULWindow.
|
||||
if (element->IsXULElement(nsGkAtoms::window)) {
|
||||
if (nsCOMPtr<nsIXULWindow> win = mDocument->GetXULWindowIfToplevelChrome()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
49
dom/xul/XULPersist.h
Normal file
49
dom/xul/XULPersist.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_XULPersist_h
|
||||
#define mozilla_dom_XULPersist_h
|
||||
|
||||
class nsIXULStore;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class XULPersist final : public nsStubDocumentObserver
|
||||
{
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit XULPersist(nsIDocument* aDocument);
|
||||
void Init();
|
||||
void DropDocumentReference();
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
|
||||
protected:
|
||||
|
||||
void Persist(mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute);
|
||||
|
||||
private:
|
||||
~XULPersist();
|
||||
nsresult ApplyPersistentAttributes();
|
||||
nsresult ApplyPersistentAttributesInternal();
|
||||
nsresult ApplyPersistentAttributesToElements(const nsAString &aID,
|
||||
nsCOMArray<Element>& aElements);
|
||||
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
nsIDocument* MOZ_NON_OWNING_REF mDocument;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // mozilla_dom_XULPersist_h
|
@ -25,6 +25,7 @@ if CONFIG['MOZ_XUL']:
|
||||
'XULBroadcastManager.h',
|
||||
'XULFrameElement.h',
|
||||
'XULMenuElement.h',
|
||||
'XULPersist.h',
|
||||
'XULPopupElement.h',
|
||||
'XULScrollElement.h',
|
||||
'XULTextElement.h',
|
||||
@ -44,6 +45,7 @@ if CONFIG['MOZ_XUL']:
|
||||
'XULDocument.cpp',
|
||||
'XULFrameElement.cpp',
|
||||
'XULMenuElement.cpp',
|
||||
'XULPersist.cpp',
|
||||
'XULPopupElement.cpp',
|
||||
'XULScrollElement.cpp',
|
||||
'XULTextElement.cpp',
|
||||
|
@ -39,6 +39,7 @@ STATIC_ATOMS = [
|
||||
Atom("moztype", "_moz-type"),
|
||||
Atom("mozdirty", "_moz_dirty"),
|
||||
Atom("mozdisallowselectionprint", "mozdisallowselectionprint"),
|
||||
Atom("mozpersist", "mozpersist"),
|
||||
Atom("mozdonotsend", "moz-do-not-send"),
|
||||
Atom("mozeditorbogusnode", "_moz_editor_bogus_node"),
|
||||
Atom("mozgeneratedcontentbefore", "_moz_generated_content_before"),
|
||||
|
Loading…
Reference in New Issue
Block a user