Source code

Revision control

Other Tools

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/. */
6
7
#include "XULPersist.h"
8
9
#ifdef MOZ_NEW_XULSTORE
10
# include "mozilla/XULStore.h"
11
#else
12
# include "nsIXULStore.h"
13
# include "nsIStringEnumerator.h"
14
#endif
15
#include "mozilla/BasePrincipal.h"
16
#include "nsIAppWindow.h"
17
18
namespace mozilla {
19
namespace dom {
20
21
static bool IsRootElement(Element* aElement) {
22
return aElement->OwnerDoc()->GetRootElement() == aElement;
23
}
24
25
static bool ShouldPersistAttribute(Element* aElement, nsAtom* aAttribute) {
26
if (IsRootElement(aElement)) {
27
// This is not an element of the top document, its owner is
28
// not an AppWindow. Persist it.
29
if (aElement->OwnerDoc()->GetInProcessParentDocument()) {
30
return true;
31
}
32
// The following attributes of xul:window should be handled in
33
// AppWindow::SavePersistentAttributes instead of here.
34
if (aAttribute == nsGkAtoms::screenX || aAttribute == nsGkAtoms::screenY ||
35
aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
36
aAttribute == nsGkAtoms::sizemode) {
37
return false;
38
}
39
}
40
return true;
41
}
42
43
NS_IMPL_ISUPPORTS(XULPersist, nsIDocumentObserver)
44
45
XULPersist::XULPersist(Document* aDocument)
46
: nsStubDocumentObserver(), mDocument(aDocument) {}
47
48
XULPersist::~XULPersist() {}
49
50
void XULPersist::Init() {
51
ApplyPersistentAttributes();
52
mDocument->AddObserver(this);
53
}
54
55
void XULPersist::DropDocumentReference() {
56
mDocument->RemoveObserver(this);
57
mDocument = nullptr;
58
}
59
60
void XULPersist::AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
61
nsAtom* aAttribute, int32_t aModType,
62
const nsAttrValue* aOldValue) {
63
NS_ASSERTION(aElement->OwnerDoc() == mDocument, "unexpected doc");
64
65
// See if there is anything we need to persist in the localstore.
66
//
67
// XXX Namespace handling broken :-(
68
nsAutoString persist;
69
// Persistence of attributes of xul:window is handled in AppWindow.
70
if (aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist) &&
71
ShouldPersistAttribute(aElement, aAttribute) && !persist.IsEmpty() &&
72
// XXXldb This should check that it's a token, not just a substring.
73
persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
74
// Might not need this, but be safe for now.
75
nsCOMPtr<nsIDocumentObserver> kungFuDeathGrip(this);
76
nsContentUtils::AddScriptRunner(
77
NewRunnableMethod<Element*, int32_t, nsAtom*>(
78
"dom::XULPersist::Persist", this, &XULPersist::Persist, aElement,
79
kNameSpaceID_None, aAttribute));
80
}
81
}
82
83
void XULPersist::Persist(Element* aElement, int32_t aNameSpaceID,
84
nsAtom* aAttribute) {
85
if (!mDocument) {
86
return;
87
}
88
// For non-chrome documents, persistance is simply broken
89
if (!mDocument->NodePrincipal()->IsSystemPrincipal()) {
90
return;
91
}
92
93
#ifndef MOZ_NEW_XULSTORE
94
if (!mLocalStore) {
95
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
96
if (NS_WARN_IF(!mLocalStore)) {
97
return;
98
}
99
}
100
#endif
101
102
nsAutoString id;
103
104
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
105
nsAtomString attrstr(aAttribute);
106
107
nsAutoString valuestr;
108
aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
109
110
nsAutoCString utf8uri;
111
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
112
if (NS_WARN_IF(NS_FAILED(rv))) {
113
return;
114
}
115
NS_ConvertUTF8toUTF16 uri(utf8uri);
116
117
bool hasAttr;
118
#ifdef MOZ_NEW_XULSTORE
119
rv = XULStore::HasValue(uri, id, attrstr, hasAttr);
120
#else
121
rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
122
#endif
123
124
if (NS_WARN_IF(NS_FAILED(rv))) {
125
return;
126
}
127
128
if (hasAttr && valuestr.IsEmpty()) {
129
#ifdef MOZ_NEW_XULSTORE
130
rv = XULStore::RemoveValue(uri, id, attrstr);
131
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "value removed");
132
#else
133
mLocalStore->RemoveValue(uri, id, attrstr);
134
#endif
135
return;
136
}
137
138
// Persisting attributes to top level windows is handled by AppWindow.
139
if (IsRootElement(aElement)) {
140
if (nsCOMPtr<nsIAppWindow> win =
141
mDocument->GetAppWindowIfToplevelChrome()) {
142
return;
143
}
144
}
145
146
#ifdef MOZ_NEW_XULSTORE
147
rv = XULStore::SetValue(uri, id, attrstr, valuestr);
148
#else
149
mLocalStore->SetValue(uri, id, attrstr, valuestr);
150
#endif
151
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "value set");
152
}
153
154
nsresult XULPersist::ApplyPersistentAttributes() {
155
if (!mDocument) {
156
return NS_ERROR_NOT_AVAILABLE;
157
}
158
// For non-chrome documents, persistance is simply broken
159
if (!mDocument->NodePrincipal()->IsSystemPrincipal()) {
160
return NS_ERROR_NOT_AVAILABLE;
161
}
162
163
// Add all of the 'persisted' attributes into the content
164
// model.
165
#ifndef MOZ_NEW_XULSTORE
166
if (!mLocalStore) {
167
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
168
if (NS_WARN_IF(!mLocalStore)) {
169
return NS_ERROR_NOT_INITIALIZED;
170
}
171
}
172
#endif
173
174
ApplyPersistentAttributesInternal();
175
176
return NS_OK;
177
}
178
179
nsresult XULPersist::ApplyPersistentAttributesInternal() {
180
nsCOMArray<Element> elements;
181
182
nsAutoCString utf8uri;
183
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
184
if (NS_WARN_IF(NS_FAILED(rv))) {
185
return rv;
186
}
187
NS_ConvertUTF8toUTF16 uri(utf8uri);
188
189
// Get a list of element IDs for which persisted values are available
190
#ifdef MOZ_NEW_XULSTORE
191
UniquePtr<XULStoreIterator> ids;
192
rv = XULStore::GetIDs(uri, ids);
193
#else
194
nsCOMPtr<nsIStringEnumerator> ids;
195
rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids));
196
#endif
197
if (NS_WARN_IF(NS_FAILED(rv))) {
198
return rv;
199
}
200
201
#ifdef MOZ_NEW_XULSTORE
202
while (ids->HasMore()) {
203
nsAutoString id;
204
rv = ids->GetNext(&id);
205
if (NS_WARN_IF(NS_FAILED(rv))) {
206
return rv;
207
}
208
#else
209
while (1) {
210
bool hasmore = false;
211
ids->HasMore(&hasmore);
212
if (!hasmore) {
213
break;
214
}
215
216
nsAutoString id;
217
ids->GetNext(id);
218
#endif
219
220
// We want to hold strong refs to the elements while applying
221
// persistent attributes, just in case.
222
const nsTArray<Element*>* allElements = mDocument->GetAllElementsForId(id);
223
if (!allElements) {
224
continue;
225
}
226
elements.Clear();
227
elements.SetCapacity(allElements->Length());
228
for (Element* element : *allElements) {
229
elements.AppendObject(element);
230
}
231
232
rv = ApplyPersistentAttributesToElements(id, elements);
233
if (NS_WARN_IF(NS_FAILED(rv))) {
234
return rv;
235
}
236
}
237
238
return NS_OK;
239
}
240
241
nsresult XULPersist::ApplyPersistentAttributesToElements(
242
const nsAString& aID, nsCOMArray<Element>& aElements) {
243
nsAutoCString utf8uri;
244
nsresult rv = mDocument->GetDocumentURI()->GetSpec(utf8uri);
245
if (NS_WARN_IF(NS_FAILED(rv))) {
246
return rv;
247
}
248
NS_ConvertUTF8toUTF16 uri(utf8uri);
249
250
// Get a list of attributes for which persisted values are available
251
#ifdef MOZ_NEW_XULSTORE
252
UniquePtr<XULStoreIterator> attrs;
253
rv = XULStore::GetAttrs(uri, aID, attrs);
254
#else
255
nsCOMPtr<nsIStringEnumerator> attrs;
256
rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs));
257
#endif
258
if (NS_WARN_IF(NS_FAILED(rv))) {
259
return rv;
260
}
261
262
#ifdef MOZ_NEW_XULSTORE
263
while (attrs->HasMore()) {
264
nsAutoString attrstr;
265
rv = attrs->GetNext(&attrstr);
266
if (NS_WARN_IF(NS_FAILED(rv))) {
267
return rv;
268
}
269
270
nsAutoString value;
271
rv = XULStore::GetValue(uri, aID, attrstr, value);
272
#else
273
while (1) {
274
bool hasmore = PR_FALSE;
275
attrs->HasMore(&hasmore);
276
if (!hasmore) {
277
break;
278
}
279
280
nsAutoString attrstr;
281
attrs->GetNext(attrstr);
282
283
nsAutoString value;
284
rv = mLocalStore->GetValue(uri, aID, attrstr, value);
285
#endif
286
if (NS_WARN_IF(NS_FAILED(rv))) {
287
return rv;
288
}
289
290
RefPtr<nsAtom> attr = NS_Atomize(attrstr);
291
if (NS_WARN_IF(!attr)) {
292
return NS_ERROR_OUT_OF_MEMORY;
293
}
294
295
uint32_t cnt = aElements.Length();
296
for (int32_t i = int32_t(cnt) - 1; i >= 0; --i) {
297
Element* element = aElements.SafeElementAt(i);
298
if (!element) {
299
continue;
300
}
301
302
// Applying persistent attributes to top level windows is handled
303
// by AppWindow.
304
if (IsRootElement(element)) {
305
if (nsCOMPtr<nsIAppWindow> win =
306
mDocument->GetAppWindowIfToplevelChrome()) {
307
continue;
308
}
309
}
310
311
Unused << element->SetAttr(kNameSpaceID_None, attr, value, true);
312
}
313
}
314
315
return NS_OK;
316
}
317
318
} // namespace dom
319
} // namespace mozilla