1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "XULPersist.h"
9 #ifdef MOZ_NEW_XULSTORE
10 # include "mozilla/XULStore.h"
12 # include "nsIXULStore.h"
13 # include "nsIStringEnumerator.h"
15 #include "mozilla/BasePrincipal.h"
16 #include "mozilla/dom/Document.h"
17 #include "mozilla/dom/Element.h"
18 #include "nsContentUtils.h"
19 #include "nsIAppWindow.h"
21 namespace mozilla::dom
{
23 static bool IsRootElement(Element
* aElement
) {
24 return aElement
->OwnerDoc()->GetRootElement() == aElement
;
27 static bool ShouldPersistAttribute(Element
* aElement
, nsAtom
* aAttribute
) {
28 if (IsRootElement(aElement
)) {
29 // This is not an element of the top document, its owner is
30 // not an AppWindow. Persist it.
31 if (aElement
->OwnerDoc()->GetInProcessParentDocument()) {
34 // The following attributes of xul:window should be handled in
35 // AppWindow::SavePersistentAttributes instead of here.
36 if (aAttribute
== nsGkAtoms::screenX
|| aAttribute
== nsGkAtoms::screenY
||
37 aAttribute
== nsGkAtoms::width
|| aAttribute
== nsGkAtoms::height
||
38 aAttribute
== nsGkAtoms::sizemode
) {
45 NS_IMPL_ISUPPORTS(XULPersist
, nsIDocumentObserver
)
47 XULPersist::XULPersist(Document
* aDocument
)
48 : nsStubDocumentObserver(), mDocument(aDocument
) {}
50 XULPersist::~XULPersist() = default;
52 void XULPersist::Init() {
53 ApplyPersistentAttributes();
54 mDocument
->AddObserver(this);
57 void XULPersist::DropDocumentReference() {
58 mDocument
->RemoveObserver(this);
62 void XULPersist::AttributeChanged(dom::Element
* aElement
, int32_t aNameSpaceID
,
63 nsAtom
* aAttribute
, int32_t aModType
,
64 const nsAttrValue
* aOldValue
) {
65 NS_ASSERTION(aElement
->OwnerDoc() == mDocument
, "unexpected doc");
67 // See if there is anything we need to persist in the localstore.
69 // XXX Namespace handling broken :-(
71 // Persistence of attributes of xul:window is handled in AppWindow.
72 if (aElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::persist
, persist
) &&
73 ShouldPersistAttribute(aElement
, aAttribute
) && !persist
.IsEmpty() &&
74 // XXXldb This should check that it's a token, not just a substring.
75 persist
.Find(nsDependentAtomString(aAttribute
)) >= 0) {
76 // Might not need this, but be safe for now.
77 nsCOMPtr
<nsIDocumentObserver
> kungFuDeathGrip(this);
78 nsContentUtils::AddScriptRunner(
79 NewRunnableMethod
<Element
*, int32_t, nsAtom
*>(
80 "dom::XULPersist::Persist", this, &XULPersist::Persist
, aElement
,
81 kNameSpaceID_None
, aAttribute
));
85 void XULPersist::Persist(Element
* aElement
, int32_t aNameSpaceID
,
90 // For non-chrome documents, persistance is simply broken
91 if (!mDocument
->NodePrincipal()->IsSystemPrincipal()) {
95 #ifndef MOZ_NEW_XULSTORE
97 mLocalStore
= do_GetService("@mozilla.org/xul/xulstore;1");
98 if (NS_WARN_IF(!mLocalStore
)) {
106 aElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::id
, id
);
107 nsAtomString
attrstr(aAttribute
);
109 nsAutoString valuestr
;
110 aElement
->GetAttr(kNameSpaceID_None
, aAttribute
, valuestr
);
112 nsAutoCString utf8uri
;
113 nsresult rv
= mDocument
->GetDocumentURI()->GetSpec(utf8uri
);
114 if (NS_WARN_IF(NS_FAILED(rv
))) {
117 NS_ConvertUTF8toUTF16
uri(utf8uri
);
120 #ifdef MOZ_NEW_XULSTORE
121 rv
= XULStore::HasValue(uri
, id
, attrstr
, hasAttr
);
123 rv
= mLocalStore
->HasValue(uri
, id
, attrstr
, &hasAttr
);
126 if (NS_WARN_IF(NS_FAILED(rv
))) {
130 if (hasAttr
&& valuestr
.IsEmpty()) {
131 #ifdef MOZ_NEW_XULSTORE
132 rv
= XULStore::RemoveValue(uri
, id
, attrstr
);
133 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
), "value removed");
135 mLocalStore
->RemoveValue(uri
, id
, attrstr
);
140 // Persisting attributes to top level windows is handled by AppWindow.
141 if (IsRootElement(aElement
)) {
142 if (nsCOMPtr
<nsIAppWindow
> win
=
143 mDocument
->GetAppWindowIfToplevelChrome()) {
148 #ifdef MOZ_NEW_XULSTORE
149 rv
= XULStore::SetValue(uri
, id
, attrstr
, valuestr
);
151 mLocalStore
->SetValue(uri
, id
, attrstr
, valuestr
);
153 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
), "value set");
156 nsresult
XULPersist::ApplyPersistentAttributes() {
158 return NS_ERROR_NOT_AVAILABLE
;
160 // For non-chrome documents, persistance is simply broken
161 if (!mDocument
->NodePrincipal()->IsSystemPrincipal()) {
162 return NS_ERROR_NOT_AVAILABLE
;
165 // Add all of the 'persisted' attributes into the content
167 #ifndef MOZ_NEW_XULSTORE
169 mLocalStore
= do_GetService("@mozilla.org/xul/xulstore;1");
170 if (NS_WARN_IF(!mLocalStore
)) {
171 return NS_ERROR_NOT_INITIALIZED
;
176 ApplyPersistentAttributesInternal();
181 nsresult
XULPersist::ApplyPersistentAttributesInternal() {
182 nsCOMArray
<Element
> elements
;
184 nsAutoCString utf8uri
;
185 nsresult rv
= mDocument
->GetDocumentURI()->GetSpec(utf8uri
);
186 if (NS_WARN_IF(NS_FAILED(rv
))) {
189 NS_ConvertUTF8toUTF16
uri(utf8uri
);
191 // Get a list of element IDs for which persisted values are available
192 #ifdef MOZ_NEW_XULSTORE
193 UniquePtr
<XULStoreIterator
> ids
;
194 rv
= XULStore::GetIDs(uri
, ids
);
196 nsCOMPtr
<nsIStringEnumerator
> ids
;
197 rv
= mLocalStore
->GetIDsEnumerator(uri
, getter_AddRefs(ids
));
199 if (NS_WARN_IF(NS_FAILED(rv
))) {
203 #ifdef MOZ_NEW_XULSTORE
204 while (ids
->HasMore()) {
206 rv
= ids
->GetNext(&id
);
207 if (NS_WARN_IF(NS_FAILED(rv
))) {
212 bool hasmore
= false;
213 ids
->HasMore(&hasmore
);
222 // We want to hold strong refs to the elements while applying
223 // persistent attributes, just in case.
224 const nsTArray
<Element
*>* allElements
= mDocument
->GetAllElementsForId(id
);
229 elements
.SetCapacity(allElements
->Length());
230 for (Element
* element
: *allElements
) {
231 elements
.AppendObject(element
);
234 rv
= ApplyPersistentAttributesToElements(id
, elements
);
235 if (NS_WARN_IF(NS_FAILED(rv
))) {
243 nsresult
XULPersist::ApplyPersistentAttributesToElements(
244 const nsAString
& aID
, nsCOMArray
<Element
>& aElements
) {
245 nsAutoCString utf8uri
;
246 nsresult rv
= mDocument
->GetDocumentURI()->GetSpec(utf8uri
);
247 if (NS_WARN_IF(NS_FAILED(rv
))) {
250 NS_ConvertUTF8toUTF16
uri(utf8uri
);
252 // Get a list of attributes for which persisted values are available
253 #ifdef MOZ_NEW_XULSTORE
254 UniquePtr
<XULStoreIterator
> attrs
;
255 rv
= XULStore::GetAttrs(uri
, aID
, attrs
);
257 nsCOMPtr
<nsIStringEnumerator
> attrs
;
258 rv
= mLocalStore
->GetAttributeEnumerator(uri
, aID
, getter_AddRefs(attrs
));
260 if (NS_WARN_IF(NS_FAILED(rv
))) {
264 #ifdef MOZ_NEW_XULSTORE
265 while (attrs
->HasMore()) {
266 nsAutoString attrstr
;
267 rv
= attrs
->GetNext(&attrstr
);
268 if (NS_WARN_IF(NS_FAILED(rv
))) {
273 rv
= XULStore::GetValue(uri
, aID
, attrstr
, value
);
276 bool hasmore
= PR_FALSE
;
277 attrs
->HasMore(&hasmore
);
282 nsAutoString attrstr
;
283 attrs
->GetNext(attrstr
);
286 rv
= mLocalStore
->GetValue(uri
, aID
, attrstr
, value
);
288 if (NS_WARN_IF(NS_FAILED(rv
))) {
292 RefPtr
<nsAtom
> attr
= NS_Atomize(attrstr
);
293 if (NS_WARN_IF(!attr
)) {
294 return NS_ERROR_OUT_OF_MEMORY
;
297 uint32_t cnt
= aElements
.Length();
298 for (int32_t i
= int32_t(cnt
) - 1; i
>= 0; --i
) {
299 Element
* element
= aElements
.SafeElementAt(i
);
304 // Applying persistent attributes to top level windows is handled
306 if (IsRootElement(element
)) {
307 if (nsCOMPtr
<nsIAppWindow
> win
=
308 mDocument
->GetAppWindowIfToplevelChrome()) {
313 Unused
<< element
->SetAttr(kNameSpaceID_None
, attr
, value
, true);
320 } // namespace mozilla::dom