1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sw=2 et tw=78: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Johnny Stenback <jst@netscape.com>
25 : * L. David Baron <dbaron@dbaron.org>
26 : * Pierre Phaneuf <pp@ludusdesign.com>
27 : * Pete Collins <petejc@collab.net>
28 : * James Ross <silver@warwickcompsoc.co.uk>
29 : * Ryan Jones <sciguyryan@gmail.com>
30 : * Ms2ger <ms2ger@gmail.com>
31 : *
32 : * Alternatively, the contents of this file may be used under the terms of
33 : * either of the GNU General Public License Version 2 or later (the "GPL"),
34 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 : * in which case the provisions of the GPL or the LGPL are applicable instead
36 : * of those above. If you wish to allow use of your version of this file only
37 : * under the terms of either the GPL or the LGPL, and not to allow others to
38 : * use your version of this file under the terms of the MPL, indicate your
39 : * decision by deleting the provisions above and replace them with the notice
40 : * and other provisions required by the GPL or the LGPL. If you do not delete
41 : * the provisions above, a recipient may use your version of this file under
42 : * the terms of any one of the MPL, the GPL or the LGPL.
43 : *
44 : * ***** END LICENSE BLOCK ***** */
45 :
46 : /*
47 : * Base class for all our document implementations.
48 : */
49 :
50 : #include "mozilla/Util.h"
51 :
52 : #ifdef MOZ_LOGGING
53 : // so we can get logging even in release builds
54 : #define FORCE_PR_LOG 1
55 : #endif
56 : #include "prlog.h"
57 : #include "plstr.h"
58 : #include "prprf.h"
59 :
60 : #include "nsIInterfaceRequestor.h"
61 : #include "nsIInterfaceRequestorUtils.h"
62 : #include "nsDocument.h"
63 : #include "nsUnicharUtils.h"
64 : #include "nsIPrivateDOMEvent.h"
65 : #include "nsContentList.h"
66 : #include "nsIObserver.h"
67 : #include "nsIBaseWindow.h"
68 : #include "mozilla/css/Loader.h"
69 : #include "nsIDocShell.h"
70 : #include "nsIDocShellTreeItem.h"
71 : #include "nsIScriptRuntime.h"
72 : #include "nsCOMArray.h"
73 :
74 : #include "nsGUIEvent.h"
75 : #include "nsAsyncDOMEvent.h"
76 : #include "nsIDOMNodeFilter.h"
77 :
78 : #include "nsIDOMStyleSheet.h"
79 : #include "nsDOMAttribute.h"
80 : #include "nsIDOMDOMStringList.h"
81 : #include "nsIDOMDOMImplementation.h"
82 : #include "nsIDOMDocumentXBL.h"
83 : #include "mozilla/FunctionTimer.h"
84 : #include "nsGenericElement.h"
85 : #include "nsGenericHTMLElement.h"
86 : #include "nsIDOMCDATASection.h"
87 : #include "nsIDOMProcessingInstruction.h"
88 : #include "nsDOMString.h"
89 : #include "nsNodeUtils.h"
90 : #include "nsLayoutUtils.h" // for GetFrameForPoint
91 : #include "nsIFrame.h"
92 : #include "nsITabChild.h"
93 :
94 : #include "nsRange.h"
95 : #include "nsIDOMText.h"
96 : #include "nsIDOMComment.h"
97 : #include "nsDOMDocumentType.h"
98 : #include "nsNodeIterator.h"
99 : #include "nsTreeWalker.h"
100 :
101 : #include "nsIServiceManager.h"
102 :
103 : #include "nsContentCID.h"
104 : #include "nsDOMError.h"
105 : #include "nsIPresShell.h"
106 : #include "nsPresContext.h"
107 : #include "nsIJSON.h"
108 : #include "nsThreadUtils.h"
109 : #include "nsNodeInfoManager.h"
110 : #include "nsIXBLService.h"
111 : #include "nsIFileChannel.h"
112 : #include "nsIMultiPartChannel.h"
113 : #include "nsIRefreshURI.h"
114 : #include "nsIWebNavigation.h"
115 : #include "nsIScriptError.h"
116 :
117 : #include "nsNetUtil.h" // for NS_MakeAbsoluteURI
118 :
119 : #include "nsIScriptSecurityManager.h"
120 : #include "nsIPrincipal.h"
121 :
122 : #include "nsIDOMWindow.h"
123 : #include "nsPIDOMWindow.h"
124 : #include "nsIDOMElement.h"
125 : #include "nsFocusManager.h"
126 :
127 : // for radio group stuff
128 : #include "nsIDOMHTMLInputElement.h"
129 : #include "nsIRadioVisitor.h"
130 : #include "nsIFormControl.h"
131 :
132 : #include "nsXMLEventsManager.h"
133 :
134 : #include "nsBidiUtils.h"
135 :
136 : #include "nsIDOMUserDataHandler.h"
137 : #include "nsIDOMXPathEvaluator.h"
138 : #include "nsIXPathEvaluatorInternal.h"
139 : #include "nsIParserService.h"
140 : #include "nsContentCreatorFunctions.h"
141 :
142 : #include "nsIScriptContext.h"
143 : #include "nsBindingManager.h"
144 : #include "nsIDOMHTMLDocument.h"
145 : #include "nsIDOMHTMLFormElement.h"
146 : #include "nsIRequest.h"
147 : #include "nsILink.h"
148 : #include "nsBlobProtocolHandler.h"
149 :
150 : #include "nsCharsetAlias.h"
151 : #include "nsIParser.h"
152 : #include "nsIContentSink.h"
153 :
154 : #include "nsDateTimeFormatCID.h"
155 : #include "nsIDateTimeFormat.h"
156 : #include "nsEventDispatcher.h"
157 : #include "nsMutationEvent.h"
158 : #include "nsIDOMXPathEvaluator.h"
159 : #include "nsDOMCID.h"
160 :
161 : #include "jsapi.h"
162 : #include "nsIJSContextStack.h"
163 : #include "nsIXPConnect.h"
164 : #include "nsCycleCollector.h"
165 : #include "nsCCUncollectableMarker.h"
166 : #include "nsIContentPolicy.h"
167 : #include "nsContentPolicyUtils.h"
168 : #include "nsICategoryManager.h"
169 : #include "nsIDocumentLoaderFactory.h"
170 : #include "nsIContentViewer.h"
171 : #include "nsIXMLContentSink.h"
172 : #include "nsContentErrors.h"
173 : #include "nsIXULDocument.h"
174 : #include "nsIPrompt.h"
175 : #include "nsIPropertyBag2.h"
176 : #include "nsIDOMPageTransitionEvent.h"
177 : #include "nsFrameLoader.h"
178 : #include "nsEscape.h"
179 : #include "nsObjectLoadingContent.h"
180 : #ifdef MOZ_MEDIA
181 : #include "nsHTMLMediaElement.h"
182 : #endif // MOZ_MEDIA
183 :
184 : #include "mozAutoDocUpdate.h"
185 : #include "nsGlobalWindow.h"
186 : #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
187 : #include "nsDOMNavigationTiming.h"
188 : #include "nsEventStateManager.h"
189 :
190 : #include "nsSMILAnimationController.h"
191 : #include "imgIContainer.h"
192 : #include "nsSVGUtils.h"
193 :
194 : #include "nsRefreshDriver.h"
195 :
196 : // FOR CSP (autogenerated by xpidl)
197 : #include "nsIContentSecurityPolicy.h"
198 : #include "nsCSPService.h"
199 : #include "nsHTMLStyleSheet.h"
200 : #include "nsHTMLCSSStyleSheet.h"
201 :
202 : #include "mozilla/dom/Link.h"
203 : #include "nsIHTMLDocument.h"
204 : #include "nsXULAppAPI.h"
205 : #include "nsDOMTouchEvent.h"
206 :
207 : #include "mozilla/Preferences.h"
208 :
209 : #include "imgILoader.h"
210 : #include "nsWrapperCacheInlines.h"
211 :
212 : using namespace mozilla;
213 : using namespace mozilla::dom;
214 :
215 : typedef nsTArray<Link*> LinkArray;
216 :
217 : // Reference to the document which requested DOM full-screen mode.
218 1464 : nsWeakPtr nsDocument::sFullScreenDoc = nsnull;
219 :
220 : // Reference to the root document of the branch containing the document
221 : // which requested DOM full-screen mode.
222 1464 : nsWeakPtr nsDocument::sFullScreenRootDoc = nsnull;
223 :
224 : #ifdef PR_LOGGING
225 : static PRLogModuleInfo* gDocumentLeakPRLog;
226 : static PRLogModuleInfo* gCspPRLog;
227 : #endif
228 :
229 : #define NAME_NOT_VALID ((nsSimpleContentList*)1)
230 :
231 122 : nsIdentifierMapEntry::~nsIdentifierMapEntry()
232 : {
233 122 : }
234 :
235 : void
236 122 : nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
237 : {
238 122 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
239 : "mIdentifierMap mNameContentList");
240 122 : aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mNameContentList));
241 :
242 122 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, "mIdentifierMap mDocAllList");
243 122 : aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mDocAllList));
244 :
245 122 : if (mImageElement) {
246 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
247 : "mIdentifierMap mImageElement element");
248 0 : nsIContent* imageElement = mImageElement;
249 0 : aCallback->NoteXPCOMChild(imageElement);
250 : }
251 122 : }
252 :
253 : bool
254 122 : nsIdentifierMapEntry::IsEmpty()
255 : {
256 244 : return mIdContentList.Count() == 0 && !mNameContentList &&
257 244 : !mChangeCallbacks && !mImageElement;
258 : }
259 :
260 : Element*
261 78 : nsIdentifierMapEntry::GetIdElement()
262 : {
263 78 : return static_cast<Element*>(mIdContentList.SafeElementAt(0));
264 : }
265 :
266 : Element*
267 0 : nsIdentifierMapEntry::GetImageIdElement()
268 : {
269 0 : return mImageElement ? mImageElement.get() : GetIdElement();
270 : }
271 :
272 : void
273 0 : nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements)
274 : {
275 0 : for (PRInt32 i = 0; i < mIdContentList.Count(); ++i) {
276 0 : aElements->AppendObject(static_cast<Element*>(mIdContentList[i]));
277 : }
278 0 : }
279 :
280 : void
281 0 : nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
282 : void* aData, bool aForImage)
283 : {
284 0 : if (!mChangeCallbacks) {
285 0 : mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
286 0 : if (!mChangeCallbacks)
287 0 : return;
288 0 : mChangeCallbacks->Init();
289 : }
290 :
291 0 : ChangeCallback cc = { aCallback, aData, aForImage };
292 0 : mChangeCallbacks->PutEntry(cc);
293 : }
294 :
295 : void
296 0 : nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
297 : void* aData, bool aForImage)
298 : {
299 0 : if (!mChangeCallbacks)
300 0 : return;
301 0 : ChangeCallback cc = { aCallback, aData, aForImage };
302 0 : mChangeCallbacks->RemoveEntry(cc);
303 0 : if (mChangeCallbacks->Count() == 0) {
304 0 : mChangeCallbacks = nsnull;
305 : }
306 : }
307 :
308 : struct FireChangeArgs {
309 : Element* mFrom;
310 : Element* mTo;
311 : bool mImageOnly;
312 : bool mHaveImageOverride;
313 : };
314 :
315 : static PLDHashOperator
316 0 : FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry *aEntry, void *aArg)
317 : {
318 0 : FireChangeArgs* args = static_cast<FireChangeArgs*>(aArg);
319 : // Don't fire image changes for non-image observers, and don't fire element
320 : // changes for image observers when an image override is active.
321 0 : if (aEntry->mKey.mForImage ? (args->mHaveImageOverride && !args->mImageOnly) :
322 : args->mImageOnly)
323 0 : return PL_DHASH_NEXT;
324 0 : return aEntry->mKey.mCallback(args->mFrom, args->mTo, aEntry->mKey.mData)
325 0 : ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
326 : }
327 :
328 : void
329 244 : nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement,
330 : Element* aNewElement,
331 : bool aImageOnly)
332 : {
333 244 : if (!mChangeCallbacks)
334 244 : return;
335 :
336 0 : FireChangeArgs args = { aOldElement, aNewElement, aImageOnly, !!mImageElement };
337 0 : mChangeCallbacks->EnumerateEntries(FireChangeEnumerator, &args);
338 : }
339 :
340 : bool
341 122 : nsIdentifierMapEntry::AddIdElement(Element* aElement)
342 : {
343 122 : NS_PRECONDITION(aElement, "Must have element");
344 122 : NS_PRECONDITION(mIdContentList.IndexOf(nsnull) < 0,
345 : "Why is null in our list?");
346 :
347 : #ifdef DEBUG
348 : Element* currentElement =
349 122 : static_cast<Element*>(mIdContentList.SafeElementAt(0));
350 : #endif
351 :
352 : // Common case
353 122 : if (mIdContentList.Count() == 0) {
354 122 : if (!mIdContentList.AppendElement(aElement))
355 0 : return false;
356 122 : NS_ASSERTION(currentElement == nsnull, "How did that happen?");
357 122 : FireChangeCallbacks(nsnull, aElement);
358 122 : return true;
359 : }
360 :
361 : // We seem to have multiple content nodes for the same id, or XUL is messing
362 : // with us. Search for the right place to insert the content.
363 0 : PRInt32 start = 0;
364 0 : PRInt32 end = mIdContentList.Count();
365 0 : do {
366 0 : NS_ASSERTION(start < end, "Bogus start/end");
367 :
368 0 : PRInt32 cur = (start + end) / 2;
369 0 : NS_ASSERTION(cur >= start && cur < end, "What happened here?");
370 :
371 0 : Element* curElement = static_cast<Element*>(mIdContentList[cur]);
372 0 : if (curElement == aElement) {
373 : // Already in the list, so already in the right spot. Get out of here.
374 : // XXXbz this only happens because XUL does all sorts of random
375 : // UpdateIdTableEntry calls. Hate, hate, hate!
376 0 : return true;
377 : }
378 :
379 0 : if (nsContentUtils::PositionIsBefore(aElement, curElement)) {
380 0 : end = cur;
381 : } else {
382 0 : start = cur + 1;
383 : }
384 : } while (start != end);
385 :
386 0 : if (!mIdContentList.InsertElementAt(aElement, start))
387 0 : return false;
388 :
389 0 : if (start == 0) {
390 : Element* oldElement =
391 0 : static_cast<Element*>(mIdContentList.SafeElementAt(1));
392 0 : NS_ASSERTION(currentElement == oldElement, "How did that happen?");
393 0 : FireChangeCallbacks(oldElement, aElement);
394 : }
395 0 : return true;
396 : }
397 :
398 : void
399 122 : nsIdentifierMapEntry::RemoveIdElement(Element* aElement)
400 : {
401 122 : NS_PRECONDITION(aElement, "Missing element");
402 :
403 : // This should only be called while the document is in an update.
404 : // Assertions near the call to this method guarantee this.
405 :
406 : // This could fire in OOM situations
407 : // Only assert this in HTML documents for now as XUL does all sorts of weird
408 : // crap.
409 122 : NS_ASSERTION(!aElement->OwnerDoc()->IsHTML() ||
410 : mIdContentList.IndexOf(aElement) >= 0,
411 : "Removing id entry that doesn't exist");
412 :
413 : // XXXbz should this ever Compact() I guess when all the content is gone
414 : // we'll just get cleaned up in the natural order of things...
415 : Element* currentElement =
416 122 : static_cast<Element*>(mIdContentList.SafeElementAt(0));
417 122 : mIdContentList.RemoveElement(aElement);
418 122 : if (currentElement == aElement) {
419 : FireChangeCallbacks(currentElement,
420 122 : static_cast<Element*>(mIdContentList.SafeElementAt(0)));
421 : }
422 122 : }
423 :
424 : void
425 0 : nsIdentifierMapEntry::SetImageElement(Element* aElement)
426 : {
427 0 : Element* oldElement = GetImageIdElement();
428 0 : mImageElement = aElement;
429 0 : Element* newElement = GetImageIdElement();
430 0 : if (oldElement != newElement) {
431 0 : FireChangeCallbacks(oldElement, newElement, true);
432 : }
433 0 : }
434 :
435 : void
436 0 : nsIdentifierMapEntry::AddNameElement(nsIDocument* aDocument, Element* aElement)
437 : {
438 0 : if (!mNameContentList) {
439 0 : mNameContentList = new nsSimpleContentList(aDocument);
440 : }
441 :
442 0 : mNameContentList->AppendElement(aElement);
443 0 : }
444 :
445 : void
446 0 : nsIdentifierMapEntry::RemoveNameElement(Element* aElement)
447 : {
448 0 : if (mNameContentList) {
449 0 : mNameContentList->RemoveElement(aElement);
450 : }
451 0 : }
452 :
453 : // Helper structs for the content->subdoc map
454 :
455 : class SubDocMapEntry : public PLDHashEntryHdr
456 : {
457 : public:
458 : // Both of these are strong references
459 : Element *mKey; // must be first, to look like PLDHashEntryStub
460 : nsIDocument *mSubDocument;
461 : };
462 :
463 : struct FindContentData
464 : {
465 0 : FindContentData(nsIDocument *aSubDoc)
466 0 : : mSubDocument(aSubDoc), mResult(nsnull)
467 : {
468 0 : }
469 :
470 : nsISupports *mSubDocument;
471 : Element *mResult;
472 : };
473 :
474 :
475 : /**
476 : * A struct that holds all the information about a radio group.
477 : */
478 : struct nsRadioGroupStruct
479 0 : {
480 0 : nsRadioGroupStruct()
481 : : mRequiredRadioCount(0)
482 0 : , mGroupSuffersFromValueMissing(false)
483 0 : {}
484 :
485 : /**
486 : * A strong pointer to the currently selected radio button.
487 : */
488 : nsCOMPtr<nsIDOMHTMLInputElement> mSelectedRadioButton;
489 : nsCOMArray<nsIFormControl> mRadioButtons;
490 : PRUint32 mRequiredRadioCount;
491 : bool mGroupSuffersFromValueMissing;
492 : };
493 :
494 :
495 0 : nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
496 : {
497 0 : mLength = -1;
498 : // Not reference counted to avoid circular references.
499 : // The document will tell us when its going away.
500 0 : mDocument = aDocument;
501 0 : mDocument->AddObserver(this);
502 0 : }
503 :
504 0 : nsDOMStyleSheetList::~nsDOMStyleSheetList()
505 : {
506 0 : if (mDocument) {
507 0 : mDocument->RemoveObserver(this);
508 : }
509 0 : }
510 :
511 : DOMCI_DATA(StyleSheetList, nsDOMStyleSheetList)
512 :
513 : // XXX couldn't we use the GetIIDs method from CSSStyleSheetList here?
514 : // QueryInterface implementation for nsDOMStyleSheetList
515 0 : NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetList)
516 0 : NS_INTERFACE_TABLE3(nsDOMStyleSheetList,
517 : nsIDOMStyleSheetList,
518 : nsIDocumentObserver,
519 : nsIMutationObserver)
520 0 : NS_INTERFACE_TABLE_TO_MAP_SEGUE
521 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StyleSheetList)
522 0 : NS_INTERFACE_MAP_END
523 :
524 :
525 0 : NS_IMPL_ADDREF(nsDOMStyleSheetList)
526 0 : NS_IMPL_RELEASE(nsDOMStyleSheetList)
527 :
528 :
529 : NS_IMETHODIMP
530 0 : nsDOMStyleSheetList::GetLength(PRUint32* aLength)
531 : {
532 0 : if (mDocument) {
533 : // XXX Find the number and then cache it. We'll use the
534 : // observer notification to figure out if new ones have
535 : // been added or removed.
536 0 : if (-1 == mLength) {
537 0 : mLength = mDocument->GetNumberOfStyleSheets();
538 :
539 : #ifdef DEBUG
540 : PRInt32 i;
541 0 : for (i = 0; i < mLength; i++) {
542 0 : nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i);
543 0 : nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet));
544 0 : NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet");
545 : }
546 : #endif
547 : }
548 0 : *aLength = mLength;
549 : }
550 : else {
551 0 : *aLength = 0;
552 : }
553 :
554 0 : return NS_OK;
555 : }
556 :
557 : nsIStyleSheet*
558 0 : nsDOMStyleSheetList::GetItemAt(PRUint32 aIndex)
559 : {
560 0 : if (!mDocument || aIndex >= (PRUint32)mDocument->GetNumberOfStyleSheets()) {
561 0 : return nsnull;
562 : }
563 :
564 0 : nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(aIndex);
565 0 : NS_ASSERTION(sheet, "Must have a sheet");
566 :
567 0 : return sheet;
568 : }
569 :
570 : NS_IMETHODIMP
571 0 : nsDOMStyleSheetList::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn)
572 : {
573 0 : nsIStyleSheet *sheet = GetItemAt(aIndex);
574 0 : if (!sheet) {
575 0 : *aReturn = nsnull;
576 :
577 0 : return NS_OK;
578 : }
579 :
580 0 : return CallQueryInterface(sheet, aReturn);
581 : }
582 :
583 : void
584 0 : nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
585 : {
586 0 : mDocument = nsnull;
587 0 : }
588 :
589 : void
590 0 : nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument,
591 : nsIStyleSheet* aStyleSheet,
592 : bool aDocumentSheet)
593 : {
594 0 : if (aDocumentSheet && -1 != mLength) {
595 0 : nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
596 0 : if (domss) {
597 0 : mLength++;
598 : }
599 : }
600 0 : }
601 :
602 : void
603 0 : nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument,
604 : nsIStyleSheet* aStyleSheet,
605 : bool aDocumentSheet)
606 : {
607 0 : if (aDocumentSheet && -1 != mLength) {
608 0 : nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
609 0 : if (domss) {
610 0 : mLength--;
611 : }
612 : }
613 0 : }
614 :
615 : // nsOnloadBlocker implementation
616 9096 : NS_IMPL_ISUPPORTS1(nsOnloadBlocker, nsIRequest)
617 :
618 : NS_IMETHODIMP
619 0 : nsOnloadBlocker::GetName(nsACString &aResult)
620 : {
621 0 : aResult.AssignLiteral("about:document-onload-blocker");
622 0 : return NS_OK;
623 : }
624 :
625 : NS_IMETHODIMP
626 0 : nsOnloadBlocker::IsPending(bool *_retval)
627 : {
628 0 : *_retval = true;
629 0 : return NS_OK;
630 : }
631 :
632 : NS_IMETHODIMP
633 0 : nsOnloadBlocker::GetStatus(nsresult *status)
634 : {
635 0 : *status = NS_OK;
636 0 : return NS_OK;
637 : }
638 :
639 : NS_IMETHODIMP
640 0 : nsOnloadBlocker::Cancel(nsresult status)
641 : {
642 0 : return NS_OK;
643 : }
644 : NS_IMETHODIMP
645 0 : nsOnloadBlocker::Suspend(void)
646 : {
647 0 : return NS_OK;
648 : }
649 : NS_IMETHODIMP
650 0 : nsOnloadBlocker::Resume(void)
651 : {
652 0 : return NS_OK;
653 : }
654 :
655 : NS_IMETHODIMP
656 0 : nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup)
657 : {
658 0 : *aLoadGroup = nsnull;
659 0 : return NS_OK;
660 : }
661 :
662 : NS_IMETHODIMP
663 0 : nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup)
664 : {
665 0 : return NS_OK;
666 : }
667 :
668 : NS_IMETHODIMP
669 0 : nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags)
670 : {
671 0 : *aLoadFlags = nsIRequest::LOAD_NORMAL;
672 0 : return NS_OK;
673 : }
674 :
675 : NS_IMETHODIMP
676 0 : nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
677 : {
678 0 : return NS_OK;
679 : }
680 :
681 : // ==================================================================
682 :
683 1273 : nsExternalResourceMap::nsExternalResourceMap()
684 1273 : : mHaveShutDown(false)
685 : {
686 1273 : mMap.Init();
687 1273 : mPendingLoads.Init();
688 1273 : }
689 :
690 : nsIDocument*
691 0 : nsExternalResourceMap::RequestResource(nsIURI* aURI,
692 : nsINode* aRequestingNode,
693 : nsDocument* aDisplayDocument,
694 : ExternalResourceLoad** aPendingLoad)
695 : {
696 : // If we ever start allowing non-same-origin loads here, we might need to do
697 : // something interesting with aRequestingPrincipal even for the hashtable
698 : // gets.
699 0 : NS_PRECONDITION(aURI, "Must have a URI");
700 0 : NS_PRECONDITION(aRequestingNode, "Must have a node");
701 0 : *aPendingLoad = nsnull;
702 0 : if (mHaveShutDown) {
703 0 : return nsnull;
704 : }
705 :
706 : // First, make sure we strip the ref from aURI.
707 0 : nsCOMPtr<nsIURI> clone;
708 0 : nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(clone));
709 0 : if (NS_FAILED(rv) || !clone) {
710 0 : return nsnull;
711 : }
712 :
713 : ExternalResource* resource;
714 0 : mMap.Get(clone, &resource);
715 0 : if (resource) {
716 0 : return resource->mDocument;
717 : }
718 :
719 0 : nsRefPtr<PendingLoad> load;
720 0 : mPendingLoads.Get(clone, getter_AddRefs(load));
721 0 : if (load) {
722 0 : load.forget(aPendingLoad);
723 0 : return nsnull;
724 : }
725 :
726 0 : load = new PendingLoad(aDisplayDocument);
727 :
728 0 : if (!mPendingLoads.Put(clone, load)) {
729 0 : return nsnull;
730 : }
731 :
732 0 : if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) {
733 : // Make sure we don't thrash things by trying this load again, since
734 : // chances are it failed for good reasons (security check, etc).
735 0 : AddExternalResource(clone, nsnull, nsnull, aDisplayDocument);
736 : } else {
737 0 : load.forget(aPendingLoad);
738 : }
739 :
740 0 : return nsnull;
741 : }
742 :
743 : struct
744 : nsExternalResourceEnumArgs
745 : {
746 : nsIDocument::nsSubDocEnumFunc callback;
747 : void *data;
748 : };
749 :
750 : static PLDHashOperator
751 0 : ExternalResourceEnumerator(nsIURI* aKey,
752 : nsExternalResourceMap::ExternalResource* aData,
753 : void* aClosure)
754 : {
755 : nsExternalResourceEnumArgs* args =
756 0 : static_cast<nsExternalResourceEnumArgs*>(aClosure);
757 : bool next =
758 0 : aData->mDocument ? args->callback(aData->mDocument, args->data) : true;
759 0 : return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
760 : }
761 :
762 : void
763 0 : nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
764 : void* aData)
765 : {
766 0 : nsExternalResourceEnumArgs args = { aCallback, aData };
767 0 : mMap.EnumerateRead(ExternalResourceEnumerator, &args);
768 0 : }
769 :
770 : static PLDHashOperator
771 0 : ExternalResourceTraverser(nsIURI* aKey,
772 : nsExternalResourceMap::ExternalResource* aData,
773 : void* aClosure)
774 : {
775 : nsCycleCollectionTraversalCallback *cb =
776 0 : static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
777 :
778 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
779 : "mExternalResourceMap.mMap entry"
780 : "->mDocument");
781 0 : cb->NoteXPCOMChild(aData->mDocument);
782 :
783 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
784 : "mExternalResourceMap.mMap entry"
785 : "->mViewer");
786 0 : cb->NoteXPCOMChild(aData->mViewer);
787 :
788 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
789 : "mExternalResourceMap.mMap entry"
790 : "->mLoadGroup");
791 0 : cb->NoteXPCOMChild(aData->mLoadGroup);
792 :
793 0 : return PL_DHASH_NEXT;
794 : }
795 :
796 : void
797 1462 : nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
798 : {
799 : // mPendingLoads will get cleared out as the requests complete, so
800 : // no need to worry about those here.
801 1462 : mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
802 1462 : }
803 :
804 : static PLDHashOperator
805 0 : ExternalResourceHider(nsIURI* aKey,
806 : nsExternalResourceMap::ExternalResource* aData,
807 : void* aClosure)
808 : {
809 0 : if (aData->mViewer) {
810 0 : aData->mViewer->Hide();
811 : }
812 0 : return PL_DHASH_NEXT;
813 : }
814 :
815 : void
816 0 : nsExternalResourceMap::HideViewers()
817 : {
818 0 : mMap.EnumerateRead(ExternalResourceHider, nsnull);
819 0 : }
820 :
821 : static PLDHashOperator
822 0 : ExternalResourceShower(nsIURI* aKey,
823 : nsExternalResourceMap::ExternalResource* aData,
824 : void* aClosure)
825 : {
826 0 : if (aData->mViewer) {
827 0 : aData->mViewer->Show();
828 : }
829 0 : return PL_DHASH_NEXT;
830 : }
831 :
832 : void
833 0 : nsExternalResourceMap::ShowViewers()
834 : {
835 0 : mMap.EnumerateRead(ExternalResourceShower, nsnull);
836 0 : }
837 :
838 : void
839 0 : TransferZoomLevels(nsIDocument* aFromDoc,
840 : nsIDocument* aToDoc)
841 : {
842 0 : NS_ABORT_IF_FALSE(aFromDoc && aToDoc,
843 : "transferring zoom levels from/to null doc");
844 :
845 0 : nsIPresShell* fromShell = aFromDoc->GetShell();
846 0 : if (!fromShell)
847 0 : return;
848 :
849 0 : nsPresContext* fromCtxt = fromShell->GetPresContext();
850 0 : if (!fromCtxt)
851 0 : return;
852 :
853 0 : nsIPresShell* toShell = aToDoc->GetShell();
854 0 : if (!toShell)
855 0 : return;
856 :
857 0 : nsPresContext* toCtxt = toShell->GetPresContext();
858 0 : if (!toCtxt)
859 0 : return;
860 :
861 0 : toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
862 0 : toCtxt->SetMinFontSize(fromCtxt->MinFontSize(nsnull));
863 0 : toCtxt->SetTextZoom(fromCtxt->TextZoom());
864 : }
865 :
866 : void
867 0 : TransferShowingState(nsIDocument* aFromDoc, nsIDocument* aToDoc)
868 : {
869 0 : NS_ABORT_IF_FALSE(aFromDoc && aToDoc,
870 : "transferring showing state from/to null doc");
871 :
872 0 : if (aFromDoc->IsShowing()) {
873 0 : aToDoc->OnPageShow(true, nsnull);
874 : }
875 0 : }
876 :
877 : nsresult
878 0 : nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
879 : nsIContentViewer* aViewer,
880 : nsILoadGroup* aLoadGroup,
881 : nsIDocument* aDisplayDocument)
882 : {
883 0 : NS_PRECONDITION(aURI, "Unexpected call");
884 0 : NS_PRECONDITION((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
885 : "Must have both or neither");
886 :
887 0 : nsRefPtr<PendingLoad> load;
888 0 : mPendingLoads.Get(aURI, getter_AddRefs(load));
889 0 : mPendingLoads.Remove(aURI);
890 :
891 0 : nsresult rv = NS_OK;
892 :
893 0 : nsCOMPtr<nsIDocument> doc;
894 0 : if (aViewer) {
895 0 : doc = aViewer->GetDocument();
896 0 : NS_ASSERTION(doc, "Must have a document");
897 :
898 0 : nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(doc);
899 0 : if (xulDoc) {
900 : // We don't handle XUL stuff here yet.
901 0 : rv = NS_ERROR_NOT_AVAILABLE;
902 : } else {
903 0 : doc->SetDisplayDocument(aDisplayDocument);
904 :
905 : // Make sure that hiding our viewer will tear down its presentation.
906 0 : aViewer->SetSticky(false);
907 :
908 0 : rv = aViewer->Init(nsnull, nsIntRect(0, 0, 0, 0));
909 0 : if (NS_SUCCEEDED(rv)) {
910 0 : rv = aViewer->Open(nsnull, nsnull);
911 : }
912 : }
913 :
914 0 : if (NS_FAILED(rv)) {
915 0 : doc = nsnull;
916 0 : aViewer = nsnull;
917 0 : aLoadGroup = nsnull;
918 : }
919 : }
920 :
921 0 : ExternalResource* newResource = new ExternalResource();
922 0 : if (newResource && !mMap.Put(aURI, newResource)) {
923 0 : delete newResource;
924 0 : newResource = nsnull;
925 0 : if (NS_SUCCEEDED(rv)) {
926 0 : rv = NS_ERROR_OUT_OF_MEMORY;
927 : }
928 : }
929 :
930 0 : if (newResource) {
931 0 : newResource->mDocument = doc;
932 0 : newResource->mViewer = aViewer;
933 0 : newResource->mLoadGroup = aLoadGroup;
934 0 : if (doc) {
935 0 : TransferZoomLevels(aDisplayDocument, doc);
936 0 : TransferShowingState(aDisplayDocument, doc);
937 : }
938 : }
939 :
940 0 : const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers();
941 0 : for (PRUint32 i = 0; i < obs.Length(); ++i) {
942 0 : obs[i]->Observe(doc, "external-resource-document-created", nsnull);
943 : }
944 :
945 0 : return rv;
946 : }
947 :
948 0 : NS_IMPL_ISUPPORTS2(nsExternalResourceMap::PendingLoad,
949 : nsIStreamListener,
950 : nsIRequestObserver)
951 :
952 : NS_IMETHODIMP
953 0 : nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest *aRequest,
954 : nsISupports *aContext)
955 : {
956 0 : nsExternalResourceMap& map = mDisplayDocument->ExternalResourceMap();
957 0 : if (map.HaveShutDown()) {
958 0 : return NS_BINDING_ABORTED;
959 : }
960 :
961 0 : nsCOMPtr<nsIContentViewer> viewer;
962 0 : nsCOMPtr<nsILoadGroup> loadGroup;
963 0 : nsresult rv = SetupViewer(aRequest, getter_AddRefs(viewer),
964 0 : getter_AddRefs(loadGroup));
965 :
966 : // Make sure to do this no matter what
967 : nsresult rv2 = map.AddExternalResource(mURI, viewer, loadGroup,
968 0 : mDisplayDocument);
969 0 : if (NS_FAILED(rv)) {
970 0 : return rv;
971 : }
972 0 : if (NS_FAILED(rv2)) {
973 0 : mTargetListener = nsnull;
974 0 : return rv2;
975 : }
976 :
977 0 : return mTargetListener->OnStartRequest(aRequest, aContext);
978 : }
979 :
980 : nsresult
981 0 : nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest* aRequest,
982 : nsIContentViewer** aViewer,
983 : nsILoadGroup** aLoadGroup)
984 : {
985 0 : NS_PRECONDITION(!mTargetListener, "Unexpected call to OnStartRequest");
986 0 : *aViewer = nsnull;
987 0 : *aLoadGroup = nsnull;
988 :
989 0 : nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
990 0 : NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
991 :
992 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
993 0 : if (httpChannel) {
994 : bool requestSucceeded;
995 0 : if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
996 0 : !requestSucceeded) {
997 : // Bail out on this load, since it looks like we have an HTTP error page
998 0 : return NS_BINDING_ABORTED;
999 : }
1000 : }
1001 :
1002 0 : nsCAutoString type;
1003 0 : chan->GetContentType(type);
1004 :
1005 0 : nsCOMPtr<nsILoadGroup> loadGroup;
1006 0 : chan->GetLoadGroup(getter_AddRefs(loadGroup));
1007 :
1008 : // Give this document its own loadgroup
1009 : nsCOMPtr<nsILoadGroup> newLoadGroup =
1010 0 : do_CreateInstance(NS_LOADGROUP_CONTRACTID);
1011 0 : NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
1012 0 : newLoadGroup->SetLoadGroup(loadGroup);
1013 :
1014 0 : nsCOMPtr<nsIInterfaceRequestor> callbacks;
1015 0 : loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
1016 :
1017 : nsCOMPtr<nsIInterfaceRequestor> newCallbacks =
1018 0 : new LoadgroupCallbacks(callbacks);
1019 0 : newLoadGroup->SetNotificationCallbacks(newCallbacks);
1020 :
1021 : // This is some serious hackery cribbed from docshell
1022 : nsCOMPtr<nsICategoryManager> catMan =
1023 0 : do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
1024 0 : NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
1025 0 : nsXPIDLCString contractId;
1026 0 : nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", type.get(),
1027 0 : getter_Copies(contractId));
1028 0 : NS_ENSURE_SUCCESS(rv, rv);
1029 : nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
1030 0 : do_GetService(contractId);
1031 0 : NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
1032 :
1033 0 : nsCOMPtr<nsIContentViewer> viewer;
1034 0 : nsCOMPtr<nsIStreamListener> listener;
1035 0 : rv = docLoaderFactory->CreateInstance("external-resource", chan, newLoadGroup,
1036 : type.get(), nsnull, nsnull,
1037 0 : getter_AddRefs(listener),
1038 0 : getter_AddRefs(viewer));
1039 0 : NS_ENSURE_SUCCESS(rv, rv);
1040 0 : NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
1041 :
1042 0 : nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
1043 0 : if (!parser) {
1044 : /// We don't want to deal with the various fake documents yet
1045 0 : return NS_ERROR_NOT_IMPLEMENTED;
1046 : }
1047 :
1048 : // We can't handle HTML and other weird things here yet.
1049 0 : nsIContentSink* sink = parser->GetContentSink();
1050 0 : nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
1051 0 : if (!xmlSink) {
1052 0 : return NS_ERROR_NOT_IMPLEMENTED;
1053 : }
1054 :
1055 0 : listener.swap(mTargetListener);
1056 0 : viewer.forget(aViewer);
1057 0 : newLoadGroup.forget(aLoadGroup);
1058 0 : return NS_OK;
1059 : }
1060 :
1061 : NS_IMETHODIMP
1062 0 : nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
1063 : nsISupports* aContext,
1064 : nsIInputStream* aStream,
1065 : PRUint32 aOffset,
1066 : PRUint32 aCount)
1067 : {
1068 0 : NS_PRECONDITION(mTargetListener, "Shouldn't be getting called!");
1069 0 : if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
1070 0 : return NS_BINDING_ABORTED;
1071 : }
1072 0 : return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset,
1073 0 : aCount);
1074 : }
1075 :
1076 : NS_IMETHODIMP
1077 0 : nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest,
1078 : nsISupports* aContext,
1079 : nsresult aStatus)
1080 : {
1081 : // mTargetListener might be null if SetupViewer or AddExternalResource failed
1082 0 : if (mTargetListener) {
1083 0 : nsCOMPtr<nsIStreamListener> listener;
1084 0 : mTargetListener.swap(listener);
1085 0 : return listener->OnStopRequest(aRequest, aContext, aStatus);
1086 : }
1087 :
1088 0 : return NS_OK;
1089 : }
1090 :
1091 : nsresult
1092 0 : nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
1093 : nsINode* aRequestingNode)
1094 : {
1095 0 : NS_PRECONDITION(aURI, "Must have a URI");
1096 0 : NS_PRECONDITION(aRequestingNode, "Must have a node");
1097 :
1098 : // Time to start a load. First, the security checks.
1099 :
1100 0 : nsIPrincipal* requestingPrincipal = aRequestingNode->NodePrincipal();
1101 :
1102 0 : nsresult rv = nsContentUtils::GetSecurityManager()->
1103 : CheckLoadURIWithPrincipal(requestingPrincipal, aURI,
1104 0 : nsIScriptSecurityManager::STANDARD);
1105 0 : NS_ENSURE_SUCCESS(rv, rv);
1106 :
1107 : // Allow data URIs (let them skip the CheckMayLoad call), since we want
1108 : // to allow external resources from data URIs regardless of the difference
1109 : // in URI scheme.
1110 : bool doesInheritSecurityContext;
1111 : rv =
1112 : NS_URIChainHasFlags(aURI,
1113 : nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
1114 0 : &doesInheritSecurityContext);
1115 0 : if (NS_FAILED(rv) || !doesInheritSecurityContext) {
1116 0 : rv = requestingPrincipal->CheckMayLoad(aURI, true);
1117 0 : NS_ENSURE_SUCCESS(rv, rv);
1118 : }
1119 :
1120 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
1121 : rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
1122 : aURI,
1123 : requestingPrincipal,
1124 : aRequestingNode,
1125 0 : EmptyCString(), //mime guess
1126 : nsnull, //extra
1127 : &shouldLoad,
1128 : nsContentUtils::GetContentPolicy(),
1129 0 : nsContentUtils::GetSecurityManager());
1130 0 : if (NS_FAILED(rv)) return rv;
1131 0 : if (NS_CP_REJECTED(shouldLoad)) {
1132 : // Disallowed by content policy
1133 0 : return NS_ERROR_CONTENT_BLOCKED;
1134 : }
1135 :
1136 0 : nsIDocument* doc = aRequestingNode->OwnerDoc();
1137 :
1138 0 : nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
1139 0 : NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
1140 :
1141 0 : nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
1142 0 : nsCOMPtr<nsIChannel> channel;
1143 0 : rv = NS_NewChannel(getter_AddRefs(channel), aURI, nsnull, loadGroup, req);
1144 0 : NS_ENSURE_SUCCESS(rv, rv);
1145 :
1146 0 : mURI = aURI;
1147 :
1148 0 : return channel->AsyncOpen(this, nsnull);
1149 : }
1150 :
1151 0 : NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks,
1152 : nsIInterfaceRequestor)
1153 :
1154 : #define IMPL_SHIM(_i) \
1155 : NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
1156 :
1157 0 : IMPL_SHIM(nsILoadContext)
1158 0 : IMPL_SHIM(nsIProgressEventSink)
1159 0 : IMPL_SHIM(nsIChannelEventSink)
1160 0 : IMPL_SHIM(nsISecurityEventSink)
1161 0 : IMPL_SHIM(nsIApplicationCacheContainer)
1162 :
1163 : #undef IMPL_SHIM
1164 :
1165 : #define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
1166 :
1167 : #define TRY_SHIM(_i) \
1168 : PR_BEGIN_MACRO \
1169 : if (IID_IS(_i)) { \
1170 : nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \
1171 : if (!real) { \
1172 : return NS_NOINTERFACE; \
1173 : } \
1174 : nsCOMPtr<_i> shim = new _i##Shim(this, real); \
1175 : if (!shim) { \
1176 : return NS_ERROR_OUT_OF_MEMORY; \
1177 : } \
1178 : *aSink = shim.forget().get(); \
1179 : return NS_OK; \
1180 : } \
1181 : PR_END_MACRO
1182 :
1183 : NS_IMETHODIMP
1184 0 : nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID & aIID,
1185 : void **aSink)
1186 : {
1187 0 : if (mCallbacks &&
1188 0 : (IID_IS(nsIPrompt) || IID_IS(nsIAuthPrompt) || IID_IS(nsIAuthPrompt2) ||
1189 0 : IID_IS(nsITabChild))) {
1190 0 : return mCallbacks->GetInterface(aIID, aSink);
1191 : }
1192 :
1193 0 : *aSink = nsnull;
1194 :
1195 0 : TRY_SHIM(nsILoadContext);
1196 0 : TRY_SHIM(nsIProgressEventSink);
1197 0 : TRY_SHIM(nsIChannelEventSink);
1198 0 : TRY_SHIM(nsISecurityEventSink);
1199 0 : TRY_SHIM(nsIApplicationCacheContainer);
1200 :
1201 0 : return NS_NOINTERFACE;
1202 : }
1203 :
1204 : #undef TRY_SHIM
1205 : #undef IID_IS
1206 :
1207 0 : nsExternalResourceMap::ExternalResource::~ExternalResource()
1208 : {
1209 0 : if (mViewer) {
1210 0 : mViewer->Close(nsnull);
1211 0 : mViewer->Destroy();
1212 : }
1213 0 : }
1214 :
1215 : // ==================================================================
1216 : // =
1217 : // ==================================================================
1218 :
1219 : // If we ever have an nsIDocumentObserver notification for stylesheet title
1220 : // changes, we could make this inherit from nsDOMStringList instead of
1221 : // reimplementing nsIDOMDOMStringList.
1222 : class nsDOMStyleSheetSetList : public nsIDOMDOMStringList
1223 :
1224 : {
1225 : public:
1226 : NS_DECL_ISUPPORTS
1227 :
1228 : NS_DECL_NSIDOMDOMSTRINGLIST
1229 :
1230 : nsDOMStyleSheetSetList(nsIDocument* aDocument);
1231 :
1232 0 : void Disconnect()
1233 : {
1234 0 : mDocument = nsnull;
1235 0 : }
1236 :
1237 : protected:
1238 : // Rebuild our list of style sets
1239 : nsresult GetSets(nsTArray<nsString>& aStyleSets);
1240 :
1241 : nsIDocument* mDocument; // Our document; weak ref. It'll let us know if it
1242 : // dies.
1243 : };
1244 :
1245 0 : NS_IMPL_ADDREF(nsDOMStyleSheetSetList)
1246 0 : NS_IMPL_RELEASE(nsDOMStyleSheetSetList)
1247 0 : NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetSetList)
1248 : NS_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsDOMStyleSheetSetList)
1249 : NS_INTERFACE_TABLE_ENTRY(nsDOMStyleSheetSetList, nsIDOMDOMStringList)
1250 0 : NS_OFFSET_AND_INTERFACE_TABLE_END
1251 0 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1252 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMStringList)
1253 0 : NS_INTERFACE_MAP_END
1254 :
1255 0 : nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
1256 0 : : mDocument(aDocument)
1257 : {
1258 0 : NS_ASSERTION(mDocument, "Must have document!");
1259 0 : }
1260 :
1261 : NS_IMETHODIMP
1262 0 : nsDOMStyleSheetSetList::Item(PRUint32 aIndex, nsAString& aResult)
1263 : {
1264 0 : nsTArray<nsString> styleSets;
1265 0 : nsresult rv = GetSets(styleSets);
1266 0 : NS_ENSURE_SUCCESS(rv, rv);
1267 :
1268 0 : if (aIndex >= styleSets.Length()) {
1269 0 : SetDOMStringToNull(aResult);
1270 : } else {
1271 0 : aResult = styleSets[aIndex];
1272 : }
1273 :
1274 0 : return NS_OK;
1275 : }
1276 :
1277 : NS_IMETHODIMP
1278 0 : nsDOMStyleSheetSetList::GetLength(PRUint32 *aLength)
1279 : {
1280 0 : nsTArray<nsString> styleSets;
1281 0 : nsresult rv = GetSets(styleSets);
1282 0 : NS_ENSURE_SUCCESS(rv, rv);
1283 :
1284 0 : *aLength = styleSets.Length();
1285 :
1286 0 : return NS_OK;
1287 : }
1288 :
1289 : NS_IMETHODIMP
1290 0 : nsDOMStyleSheetSetList::Contains(const nsAString& aString, bool *aResult)
1291 : {
1292 0 : nsTArray<nsString> styleSets;
1293 0 : nsresult rv = GetSets(styleSets);
1294 0 : NS_ENSURE_SUCCESS(rv, rv);
1295 :
1296 0 : *aResult = styleSets.Contains(aString);
1297 :
1298 0 : return NS_OK;
1299 : }
1300 :
1301 : nsresult
1302 0 : nsDOMStyleSheetSetList::GetSets(nsTArray<nsString>& aStyleSets)
1303 : {
1304 0 : if (!mDocument) {
1305 0 : return NS_OK; // Spec says "no exceptions", and we have no style sets if we
1306 : // have no document, for sure
1307 : }
1308 :
1309 0 : PRInt32 count = mDocument->GetNumberOfStyleSheets();
1310 0 : nsAutoString title;
1311 0 : nsAutoString temp;
1312 0 : for (PRInt32 index = 0; index < count; index++) {
1313 0 : nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index);
1314 0 : NS_ASSERTION(sheet, "Null sheet in sheet list!");
1315 0 : sheet->GetTitle(title);
1316 0 : if (!title.IsEmpty() && !aStyleSets.Contains(title) &&
1317 0 : !aStyleSets.AppendElement(title)) {
1318 0 : return NS_ERROR_OUT_OF_MEMORY;
1319 : }
1320 : }
1321 :
1322 0 : return NS_OK;
1323 : }
1324 :
1325 : // ==================================================================
1326 : // =
1327 : // ==================================================================
1328 :
1329 : class nsDOMImplementation : public nsIDOMDOMImplementation
1330 : {
1331 : public:
1332 : nsDOMImplementation(nsIDocument* aOwner,
1333 : nsIScriptGlobalObject* aScriptObject,
1334 : nsIURI* aDocumentURI,
1335 : nsIURI* aBaseURI);
1336 : virtual ~nsDOMImplementation();
1337 :
1338 1 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1339 1496 : NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMImplementation)
1340 :
1341 : // nsIDOMDOMImplementation
1342 : NS_DECL_NSIDOMDOMIMPLEMENTATION
1343 :
1344 : protected:
1345 : nsCOMPtr<nsIDocument> mOwner;
1346 : nsWeakPtr mScriptObject;
1347 : nsCOMPtr<nsIURI> mDocumentURI;
1348 : nsCOMPtr<nsIURI> mBaseURI;
1349 : };
1350 :
1351 1 : nsDOMImplementation::nsDOMImplementation(nsIDocument* aOwner,
1352 : nsIScriptGlobalObject* aScriptObject,
1353 : nsIURI* aDocumentURI,
1354 : nsIURI* aBaseURI)
1355 : : mOwner(aOwner),
1356 1 : mScriptObject(do_GetWeakReference(aScriptObject)),
1357 : mDocumentURI(aDocumentURI),
1358 2 : mBaseURI(aBaseURI)
1359 : {
1360 1 : }
1361 :
1362 2 : nsDOMImplementation::~nsDOMImplementation()
1363 : {
1364 4 : }
1365 :
1366 : DOMCI_DATA(DOMImplementation, nsDOMImplementation)
1367 :
1368 : // QueryInterface implementation for nsDOMImplementation
1369 29 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMImplementation)
1370 15 : NS_INTERFACE_MAP_ENTRY(nsIDOMDOMImplementation)
1371 9 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDOMImplementation)
1372 7 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMImplementation)
1373 6 : NS_INTERFACE_MAP_END
1374 :
1375 1466 : NS_IMPL_CYCLE_COLLECTION_1(nsDOMImplementation, mOwner)
1376 :
1377 12 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMImplementation)
1378 12 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMImplementation)
1379 :
1380 :
1381 : NS_IMETHODIMP
1382 0 : nsDOMImplementation::HasFeature(const nsAString& aFeature,
1383 : const nsAString& aVersion,
1384 : bool* aReturn)
1385 : {
1386 : return nsGenericElement::InternalIsSupported(
1387 : static_cast<nsIDOMDOMImplementation*>(this),
1388 0 : aFeature, aVersion, aReturn);
1389 : }
1390 :
1391 : NS_IMETHODIMP
1392 1 : nsDOMImplementation::CreateDocumentType(const nsAString& aQualifiedName,
1393 : const nsAString& aPublicId,
1394 : const nsAString& aSystemId,
1395 : nsIDOMDocumentType** aReturn)
1396 : {
1397 1 : *aReturn = nsnull;
1398 1 : NS_ENSURE_STATE(mOwner);
1399 :
1400 1 : nsresult rv = nsContentUtils::CheckQName(aQualifiedName);
1401 1 : NS_ENSURE_SUCCESS(rv, rv);
1402 :
1403 2 : nsCOMPtr<nsIAtom> name = do_GetAtom(aQualifiedName);
1404 1 : NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
1405 :
1406 : // Indicate that there is no internal subset (not just an empty one)
1407 : return NS_NewDOMDocumentType(aReturn, mOwner->NodeInfoManager(),
1408 : name, aPublicId,
1409 1 : aSystemId, NullString());
1410 : }
1411 :
1412 : NS_IMETHODIMP
1413 1 : nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
1414 : const nsAString& aQualifiedName,
1415 : nsIDOMDocumentType* aDoctype,
1416 : nsIDOMDocument** aReturn)
1417 : {
1418 1 : *aReturn = nsnull;
1419 :
1420 : nsresult rv;
1421 1 : if (!aQualifiedName.IsEmpty()) {
1422 1 : nsIParserService *parserService = nsContentUtils::GetParserService();
1423 1 : NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
1424 :
1425 2 : const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
1426 : const PRUnichar *colon;
1427 1 : rv = parserService->CheckQName(qName, true, &colon);
1428 1 : NS_ENSURE_SUCCESS(rv, rv);
1429 :
1430 2 : if (colon &&
1431 0 : (DOMStringIsNull(aNamespaceURI) ||
1432 1 : (Substring(qName.get(), colon).EqualsLiteral("xml") &&
1433 0 : !aNamespaceURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace")))) {
1434 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
1435 : }
1436 : }
1437 0 : else if (DOMStringIsNull(aQualifiedName) &&
1438 0 : !DOMStringIsNull(aNamespaceURI)) {
1439 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
1440 : }
1441 :
1442 : nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
1443 2 : do_QueryReferent(mScriptObject);
1444 :
1445 1 : NS_ENSURE_STATE(!mScriptObject || scriptHandlingObject);
1446 :
1447 : return nsContentUtils::CreateDocument(aNamespaceURI, aQualifiedName, aDoctype,
1448 : mDocumentURI, mBaseURI,
1449 1 : mOwner->NodePrincipal(),
1450 : scriptHandlingObject,
1451 : DocumentFlavorLegacyGuess,
1452 2 : aReturn);
1453 : }
1454 :
1455 : NS_IMETHODIMP
1456 0 : nsDOMImplementation::CreateHTMLDocument(const nsAString& aTitle,
1457 : nsIDOMDocument** aReturn)
1458 : {
1459 0 : *aReturn = nsnull;
1460 0 : NS_ENSURE_STATE(mOwner);
1461 :
1462 0 : nsCOMPtr<nsIDOMDocumentType> doctype;
1463 : // Indicate that there is no internal subset (not just an empty one)
1464 0 : nsresult rv = NS_NewDOMDocumentType(getter_AddRefs(doctype),
1465 : mOwner->NodeInfoManager(),
1466 : nsGkAtoms::html, // aName
1467 0 : EmptyString(), // aPublicId
1468 0 : EmptyString(), // aSystemId
1469 0 : NullString()); // aInternalSubset
1470 0 : NS_ENSURE_SUCCESS(rv, rv);
1471 :
1472 :
1473 : nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
1474 0 : do_QueryReferent(mScriptObject);
1475 :
1476 0 : NS_ENSURE_STATE(!mScriptObject || scriptHandlingObject);
1477 :
1478 0 : nsCOMPtr<nsIDOMDocument> document;
1479 0 : rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(),
1480 : doctype, mDocumentURI, mBaseURI,
1481 0 : mOwner->NodePrincipal(),
1482 : scriptHandlingObject,
1483 : DocumentFlavorLegacyGuess,
1484 0 : getter_AddRefs(document));
1485 0 : NS_ENSURE_SUCCESS(rv, rv);
1486 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
1487 :
1488 0 : nsCOMPtr<nsIContent> root;
1489 0 : rv = doc->CreateElem(NS_LITERAL_STRING("html"), NULL, kNameSpaceID_XHTML,
1490 0 : getter_AddRefs(root));
1491 0 : NS_ENSURE_SUCCESS(rv, rv);
1492 0 : rv = doc->AppendChildTo(root, false);
1493 0 : NS_ENSURE_SUCCESS(rv, rv);
1494 :
1495 0 : nsCOMPtr<nsIContent> head;
1496 0 : rv = doc->CreateElem(NS_LITERAL_STRING("head"), NULL, kNameSpaceID_XHTML,
1497 0 : getter_AddRefs(head));
1498 0 : NS_ENSURE_SUCCESS(rv, rv);
1499 0 : rv = root->AppendChildTo(head, false);
1500 0 : NS_ENSURE_SUCCESS(rv, rv);
1501 :
1502 0 : nsCOMPtr<nsIContent> title;
1503 0 : rv = doc->CreateElem(NS_LITERAL_STRING("title"), NULL, kNameSpaceID_XHTML,
1504 0 : getter_AddRefs(title));
1505 0 : NS_ENSURE_SUCCESS(rv, rv);
1506 0 : rv = head->AppendChildTo(title, false);
1507 0 : NS_ENSURE_SUCCESS(rv, rv);
1508 :
1509 0 : nsCOMPtr<nsIContent> titleText;
1510 0 : rv = NS_NewTextNode(getter_AddRefs(titleText), doc->NodeInfoManager());
1511 0 : NS_ENSURE_SUCCESS(rv, rv);
1512 0 : rv = titleText->SetText(aTitle, false);
1513 0 : NS_ENSURE_SUCCESS(rv, rv);
1514 0 : rv = title->AppendChildTo(titleText, false);
1515 0 : NS_ENSURE_SUCCESS(rv, rv);
1516 :
1517 0 : nsCOMPtr<nsIContent> body;
1518 0 : rv = doc->CreateElem(NS_LITERAL_STRING("body"), NULL, kNameSpaceID_XHTML,
1519 0 : getter_AddRefs(body));
1520 0 : NS_ENSURE_SUCCESS(rv, rv);
1521 0 : rv = root->AppendChildTo(body, false);
1522 0 : NS_ENSURE_SUCCESS(rv, rv);
1523 :
1524 0 : document.forget(aReturn);
1525 :
1526 0 : return NS_OK;
1527 : }
1528 :
1529 : // ==================================================================
1530 : // =
1531 : // ==================================================================
1532 :
1533 : // NOTE! nsDocument::operator new() zeroes out all members, so don't
1534 : // bother initializing members to 0.
1535 :
1536 1273 : nsDocument::nsDocument(const char* aContentType)
1537 : : nsIDocument()
1538 : , mAnimatingImages(true)
1539 1273 : , mVisibilityState(eHidden)
1540 : {
1541 1273 : SetContentTypeInternal(nsDependentCString(aContentType));
1542 :
1543 : #ifdef PR_LOGGING
1544 1273 : if (!gDocumentLeakPRLog)
1545 249 : gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
1546 :
1547 1273 : if (gDocumentLeakPRLog)
1548 1273 : PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
1549 : ("DOCUMENT %p created", this));
1550 :
1551 1273 : if (!gCspPRLog)
1552 249 : gCspPRLog = PR_NewLogModule("CSP");
1553 : #endif
1554 :
1555 : // Start out mLastStyleSheetSet as null, per spec
1556 1273 : SetDOMStringToNull(mLastStyleSheetSet);
1557 :
1558 1273 : mLinksToUpdate.Init();
1559 1273 : }
1560 :
1561 : static PLDHashOperator
1562 0 : ClearAllBoxObjects(const void* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
1563 : {
1564 0 : if (aBoxObject) {
1565 0 : aBoxObject->Clear();
1566 : }
1567 0 : return PL_DHASH_NEXT;
1568 : }
1569 :
1570 2542 : nsDocument::~nsDocument()
1571 : {
1572 : #ifdef PR_LOGGING
1573 1271 : if (gDocumentLeakPRLog)
1574 1271 : PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
1575 : ("DOCUMENT %p destroyed", this));
1576 : #endif
1577 :
1578 : #ifdef DEBUG
1579 1271 : nsCycleCollector_DEBUG_wasFreed(static_cast<nsIDocument*>(this));
1580 : #endif
1581 :
1582 1271 : NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document");
1583 :
1584 1271 : mInDestructor = true;
1585 1271 : mInUnlinkOrDeletion = true;
1586 :
1587 : // Clear mObservers to keep it in sync with the mutationobserver list
1588 1271 : mObservers.Clear();
1589 :
1590 1271 : if (mStyleSheetSetList) {
1591 0 : mStyleSheetSetList->Disconnect();
1592 : }
1593 :
1594 1271 : if (mAnimationController) {
1595 0 : mAnimationController->Disconnect();
1596 : }
1597 :
1598 1271 : mParentDocument = nsnull;
1599 :
1600 : // Kill the subdocument map, doing this will release its strong
1601 : // references, if any.
1602 1271 : if (mSubDocuments) {
1603 0 : PL_DHashTableDestroy(mSubDocuments);
1604 :
1605 0 : mSubDocuments = nsnull;
1606 : }
1607 :
1608 : // Destroy link map now so we don't waste time removing
1609 : // links one by one
1610 1271 : DestroyElementMaps();
1611 :
1612 2542 : nsAutoScriptBlocker scriptBlocker;
1613 :
1614 : PRInt32 indx; // must be signed
1615 1271 : PRUint32 count = mChildren.ChildCount();
1616 1271 : for (indx = PRInt32(count) - 1; indx >= 0; --indx) {
1617 0 : mChildren.ChildAt(indx)->UnbindFromTree();
1618 0 : mChildren.RemoveChildAt(indx);
1619 : }
1620 1271 : mFirstChild = nsnull;
1621 1271 : mCachedRootElement = nsnull;
1622 :
1623 : // Let the stylesheets know we're going away
1624 1271 : indx = mStyleSheets.Count();
1625 2542 : while (--indx >= 0) {
1626 0 : mStyleSheets[indx]->SetOwningDocument(nsnull);
1627 : }
1628 1271 : indx = mCatalogSheets.Count();
1629 2542 : while (--indx >= 0) {
1630 0 : mCatalogSheets[indx]->SetOwningDocument(nsnull);
1631 : }
1632 1271 : if (mAttrStyleSheet)
1633 469 : mAttrStyleSheet->SetOwningDocument(nsnull);
1634 1271 : if (mStyleAttrStyleSheet)
1635 469 : mStyleAttrStyleSheet->SetOwningDocument(nsnull);
1636 :
1637 1271 : if (mListenerManager) {
1638 0 : mListenerManager->Disconnect();
1639 0 : UnsetFlags(NODE_HAS_LISTENERMANAGER);
1640 : }
1641 :
1642 1271 : if (mScriptLoader) {
1643 1271 : mScriptLoader->DropDocumentReference();
1644 : }
1645 :
1646 1271 : if (mCSSLoader) {
1647 : // Could be null here if Init() failed
1648 1271 : mCSSLoader->DropDocumentReference();
1649 1271 : NS_RELEASE(mCSSLoader);
1650 : }
1651 :
1652 : // XXX Ideally we'd do this cleanup in the nsIDocument destructor.
1653 1271 : if (mNodeInfoManager) {
1654 1271 : mNodeInfoManager->DropDocumentReference();
1655 : }
1656 :
1657 1271 : if (mAttrStyleSheet) {
1658 469 : mAttrStyleSheet->SetOwningDocument(nsnull);
1659 : }
1660 :
1661 1271 : if (mStyleAttrStyleSheet) {
1662 469 : mStyleAttrStyleSheet->SetOwningDocument(nsnull);
1663 : }
1664 :
1665 1271 : delete mHeaderData;
1666 :
1667 1271 : if (mBoxObjectTable) {
1668 0 : mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
1669 0 : delete mBoxObjectTable;
1670 : }
1671 :
1672 1271 : mPendingTitleChangeEvent.Revoke();
1673 :
1674 1271 : for (PRUint32 i = 0; i < mFileDataUris.Length(); ++i) {
1675 0 : nsBlobProtocolHandler::RemoveFileDataEntry(mFileDataUris[i]);
1676 : }
1677 :
1678 : // We don't want to leave residual locks on images. Make sure we're in an
1679 : // unlocked state, and then clear the table.
1680 1271 : SetImageLockingState(false);
1681 1271 : mImageTracker.Clear();
1682 1271 : }
1683 :
1684 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
1685 :
1686 154563 : NS_INTERFACE_TABLE_HEAD(nsDocument)
1687 154563 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1688 : NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsDocument)
1689 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
1690 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentXBL)
1691 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal)
1692 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMEventTarget)
1693 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
1694 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
1695 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
1696 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
1697 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch)
1698 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver)
1699 : NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers)
1700 137424 : NS_OFFSET_AND_INTERFACE_TABLE_END
1701 137424 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
1702 116746 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
1703 13842 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
1704 : new nsNode3Tearoff(this))
1705 13842 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNodeSelector,
1706 : new nsNodeSelectorTearoff(this))
1707 27642 : if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
1708 13800 : aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
1709 42 : if (!mXPathEvaluatorTearoff) {
1710 : nsresult rv;
1711 : mXPathEvaluatorTearoff =
1712 : do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID,
1713 2 : static_cast<nsIDocument *>(this), &rv);
1714 2 : NS_ENSURE_SUCCESS(rv, rv);
1715 : }
1716 :
1717 42 : return mXPathEvaluatorTearoff->QueryInterface(aIID, aInstancePtr);
1718 : }
1719 : else
1720 13800 : NS_INTERFACE_MAP_END
1721 :
1722 :
1723 169709 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
1724 169705 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsDocument,
1725 : nsNodeUtils::LastRelease(this))
1726 :
1727 2237 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
1728 2237 : return nsGenericElement::CanSkip(tmp, aRemovingAllowed);
1729 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1730 :
1731 1287 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument)
1732 1287 : return nsGenericElement::CanSkipInCC(tmp);
1733 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1734 :
1735 1317 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument)
1736 1317 : return nsGenericElement::CanSkipThis(tmp);
1737 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1738 :
1739 : static PLDHashOperator
1740 0 : SubDocTraverser(PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number,
1741 : void *arg)
1742 : {
1743 0 : SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
1744 : nsCycleCollectionTraversalCallback *cb =
1745 0 : static_cast<nsCycleCollectionTraversalCallback*>(arg);
1746 :
1747 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mSubDocuments entry->mKey");
1748 0 : cb->NoteXPCOMChild(entry->mKey);
1749 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mSubDocuments entry->mSubDocument");
1750 0 : cb->NoteXPCOMChild(entry->mSubDocument);
1751 :
1752 0 : return PL_DHASH_NEXT;
1753 : }
1754 :
1755 : static PLDHashOperator
1756 0 : RadioGroupsTraverser(const nsAString& aKey, nsRadioGroupStruct* aData,
1757 : void* aClosure)
1758 : {
1759 : nsCycleCollectionTraversalCallback *cb =
1760 0 : static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
1761 :
1762 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
1763 : "mRadioGroups entry->mSelectedRadioButton");
1764 0 : cb->NoteXPCOMChild(aData->mSelectedRadioButton);
1765 :
1766 0 : PRUint32 i, count = aData->mRadioButtons.Count();
1767 0 : for (i = 0; i < count; ++i) {
1768 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
1769 : "mRadioGroups entry->mRadioButtons[i]");
1770 0 : cb->NoteXPCOMChild(aData->mRadioButtons[i]);
1771 : }
1772 :
1773 0 : return PL_DHASH_NEXT;
1774 : }
1775 :
1776 : static PLDHashOperator
1777 0 : BoxObjectTraverser(const void* key, nsPIBoxObject* boxObject, void* userArg)
1778 : {
1779 : nsCycleCollectionTraversalCallback *cb =
1780 0 : static_cast<nsCycleCollectionTraversalCallback*>(userArg);
1781 :
1782 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mBoxObjectTable entry");
1783 0 : cb->NoteXPCOMChild(boxObject);
1784 :
1785 0 : return PL_DHASH_NEXT;
1786 : }
1787 :
1788 : static PLDHashOperator
1789 122 : IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg)
1790 : {
1791 : nsCycleCollectionTraversalCallback *cb =
1792 122 : static_cast<nsCycleCollectionTraversalCallback*>(aArg);
1793 122 : aEntry->Traverse(cb);
1794 122 : return PL_DHASH_NEXT;
1795 : }
1796 :
1797 : static const char* kNSURIs[] = {
1798 : "([none])",
1799 : "(xmlns)",
1800 : "(xml)",
1801 : "(xhtml)",
1802 : "(XLink)",
1803 : "(XSLT)",
1804 : "(XBL)",
1805 : "(MathML)",
1806 : "(RDF)",
1807 : "(XUL)"
1808 : };
1809 :
1810 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
1811 1462 : if (NS_UNLIKELY(cb.WantDebugInfo())) {
1812 : char name[512];
1813 0 : nsCAutoString loadedAsData;
1814 0 : if (tmp->IsLoadedAsData()) {
1815 0 : loadedAsData.AssignLiteral("data");
1816 : } else {
1817 0 : loadedAsData.AssignLiteral("normal");
1818 : }
1819 0 : PRUint32 nsid = tmp->GetDefaultNamespaceID();
1820 0 : nsCAutoString uri;
1821 0 : if (tmp->mDocumentURI)
1822 0 : tmp->mDocumentURI->GetSpec(uri);
1823 0 : if (nsid < ArrayLength(kNSURIs)) {
1824 : PR_snprintf(name, sizeof(name), "nsDocument %s %s %s",
1825 0 : loadedAsData.get(), kNSURIs[nsid], uri.get());
1826 : }
1827 : else {
1828 : PR_snprintf(name, sizeof(name), "nsDocument %s %s",
1829 0 : loadedAsData.get(), uri.get());
1830 : }
1831 0 : cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsDocument), name);
1832 : }
1833 : else {
1834 1462 : NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get())
1835 : }
1836 :
1837 : // Always need to traverse script objects, so do that before we check
1838 : // if we're uncollectable.
1839 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1840 :
1841 1462 : if (!nsINode::Traverse(tmp, cb)) {
1842 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
1843 : }
1844 :
1845 1462 : tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb);
1846 :
1847 1462 : tmp->mExternalResourceMap.Traverse(&cb);
1848 :
1849 : // Traverse the mChildren nsAttrAndChildArray.
1850 3037 : for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()); indx > 0; --indx) {
1851 1575 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
1852 1575 : cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
1853 : }
1854 :
1855 : // Traverse all nsIDocument pointer members.
1856 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo)
1857 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDisplayDocument)
1858 :
1859 : // Traverse all nsDocument nsCOMPtrs.
1860 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
1861 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptGlobalObject)
1862 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mListenerManager,
1863 : nsEventListenerManager)
1864 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMStyleSheets)
1865 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
1866 :
1867 1462 : tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb);
1868 :
1869 : // The boxobject for an element will only exist as long as it's in the
1870 : // document, so we'll traverse the table here instead of from the element.
1871 1462 : if (tmp->mBoxObjectTable) {
1872 0 : tmp->mBoxObjectTable->EnumerateRead(BoxObjectTraverser, &cb);
1873 : }
1874 :
1875 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
1876 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mStyleAttrStyleSheet, nsIStyleSheet)
1877 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXPathEvaluatorTearoff)
1878 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLayoutHistoryState)
1879 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnloadBlocker)
1880 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBaseNodeWithHref)
1881 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMImplementation)
1882 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mImageMaps,
1883 : nsIDOMNodeList)
1884 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalDocument)
1885 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedEncoder)
1886 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStateObjectCached)
1887 :
1888 : // Traverse all our nsCOMArrays.
1889 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets)
1890 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets)
1891 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPreloadingImages)
1892 :
1893 1462 : for (PRUint32 i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
1894 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
1895 0 : cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i]);
1896 : }
1897 :
1898 : // Traverse animation components
1899 1462 : if (tmp->mAnimationController) {
1900 0 : tmp->mAnimationController->Traverse(&cb);
1901 : }
1902 :
1903 1462 : if (tmp->mSubDocuments && tmp->mSubDocuments->ops) {
1904 0 : PL_DHashTableEnumerate(tmp->mSubDocuments, SubDocTraverser, &cb);
1905 : }
1906 1462 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1907 :
1908 :
1909 1462 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
1910 1462 : nsINode::Trace(tmp, aCallback, aClosure);
1911 1462 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
1912 :
1913 :
1914 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
1915 1271 : tmp->mInUnlinkOrDeletion = true;
1916 :
1917 : // Clear out our external resources
1918 1271 : tmp->mExternalResourceMap.Shutdown();
1919 :
1920 2542 : nsAutoScriptBlocker scriptBlocker;
1921 :
1922 1271 : nsINode::Unlink(tmp);
1923 :
1924 : // Unlink the mChildren nsAttrAndChildArray.
1925 2644 : for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()) - 1;
1926 : indx >= 0; --indx) {
1927 1373 : tmp->mChildren.ChildAt(indx)->UnbindFromTree();
1928 1373 : tmp->mChildren.RemoveChildAt(indx);
1929 : }
1930 1271 : tmp->mFirstChild = nsnull;
1931 :
1932 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXPathEvaluatorTearoff)
1933 1271 : tmp->mCachedRootElement = nsnull; // Avoid a dangling pointer
1934 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
1935 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBaseNodeWithHref)
1936 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDOMImplementation)
1937 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageMaps)
1938 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalDocument)
1939 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedEncoder)
1940 :
1941 1271 : tmp->mParentDocument = nsnull;
1942 :
1943 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPreloadingImages)
1944 :
1945 :
1946 1271 : if (tmp->mBoxObjectTable) {
1947 0 : tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
1948 0 : delete tmp->mBoxObjectTable;
1949 0 : tmp->mBoxObjectTable = nsnull;
1950 : }
1951 :
1952 1271 : if (tmp->mListenerManager) {
1953 0 : tmp->mListenerManager->Disconnect();
1954 0 : tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
1955 0 : tmp->mListenerManager = nsnull;
1956 : }
1957 :
1958 1271 : if (tmp->mSubDocuments) {
1959 0 : PL_DHashTableDestroy(tmp->mSubDocuments);
1960 0 : tmp->mSubDocuments = nsnull;
1961 : }
1962 :
1963 1271 : tmp->mFrameRequestCallbacks.Clear();
1964 :
1965 1271 : tmp->mRadioGroups.Clear();
1966 :
1967 : // nsDocument has a pretty complex destructor, so we're going to
1968 : // assume that *most* cycles you actually want to break somewhere
1969 : // else, and not unlink an awful lot here.
1970 :
1971 1271 : tmp->mIdentifierMap.Clear();
1972 :
1973 1271 : if (tmp->mAnimationController) {
1974 0 : tmp->mAnimationController->Unlink();
1975 : }
1976 :
1977 1271 : tmp->mPendingTitleChangeEvent.Revoke();
1978 :
1979 1271 : tmp->mInUnlinkOrDeletion = false;
1980 1271 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1981 :
1982 :
1983 : nsresult
1984 1273 : nsDocument::Init()
1985 : {
1986 1273 : if (mCSSLoader || mNodeInfoManager || mScriptLoader) {
1987 0 : return NS_ERROR_ALREADY_INITIALIZED;
1988 : }
1989 :
1990 1273 : mIdentifierMap.Init();
1991 1273 : (void)mStyledLinks.Init();
1992 1273 : mRadioGroups.Init();
1993 :
1994 : // Force initialization.
1995 1273 : nsINode::nsSlots* slots = GetSlots();
1996 1273 : NS_ENSURE_TRUE(slots,NS_ERROR_OUT_OF_MEMORY);
1997 :
1998 : // Prepend self as mutation-observer whether we need it or not (some
1999 : // subclasses currently do, other don't). This is because the code in
2000 : // nsNodeUtils always notifies the first observer first, expecting the
2001 : // first observer to be the document.
2002 1273 : NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)),
2003 : NS_ERROR_OUT_OF_MEMORY);
2004 :
2005 :
2006 1273 : mOnloadBlocker = new nsOnloadBlocker();
2007 1273 : NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
2008 :
2009 1273 : mCSSLoader = new mozilla::css::Loader(this);
2010 1273 : NS_ENSURE_TRUE(mCSSLoader, NS_ERROR_OUT_OF_MEMORY);
2011 1273 : NS_ADDREF(mCSSLoader);
2012 : // Assume we're not quirky, until we know otherwise
2013 1273 : mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
2014 :
2015 1273 : mNodeInfoManager = new nsNodeInfoManager();
2016 1273 : NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
2017 :
2018 1273 : nsresult rv = mNodeInfoManager->Init(this);
2019 1273 : NS_ENSURE_SUCCESS(rv, rv);
2020 :
2021 : // mNodeInfo keeps NodeInfoManager alive!
2022 1273 : mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
2023 1273 : NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
2024 1273 : NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_NODE,
2025 : "Bad NodeType in aNodeInfo");
2026 :
2027 1273 : NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
2028 :
2029 1273 : mScriptLoader = new nsScriptLoader(this);
2030 1273 : NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY);
2031 :
2032 1273 : if (!mImageTracker.Init()) {
2033 0 : return NS_ERROR_OUT_OF_MEMORY;
2034 : }
2035 :
2036 1273 : return NS_OK;
2037 : }
2038 :
2039 : void
2040 1271 : nsIDocument::DeleteAllProperties()
2041 : {
2042 2550 : for (PRUint32 i = 0; i < GetPropertyTableCount(); ++i) {
2043 1279 : PropertyTable(i)->DeleteAllProperties();
2044 : }
2045 1271 : }
2046 :
2047 : void
2048 0 : nsIDocument::DeleteAllPropertiesFor(nsINode* aNode)
2049 : {
2050 0 : for (PRUint32 i = 0; i < GetPropertyTableCount(); ++i) {
2051 0 : PropertyTable(i)->DeleteAllPropertiesFor(aNode);
2052 : }
2053 0 : }
2054 :
2055 : nsPropertyTable*
2056 270 : nsIDocument::GetExtraPropertyTable(PRUint16 aCategory)
2057 : {
2058 270 : NS_ASSERTION(aCategory > 0, "Category 0 should have already been handled");
2059 548 : while (aCategory >= mExtraPropertyTables.Length() + 1) {
2060 8 : mExtraPropertyTables.AppendElement(new nsPropertyTable());
2061 : }
2062 270 : return mExtraPropertyTables[aCategory - 1];
2063 : }
2064 :
2065 : void
2066 0 : nsDocument::AddXMLEventsContent(nsIContent *aXMLEventsElement)
2067 : {
2068 0 : if (!mXMLEventsManager) {
2069 0 : mXMLEventsManager = new nsXMLEventsManager();
2070 0 : AddObserver(mXMLEventsManager);
2071 : }
2072 0 : mXMLEventsManager->AddXMLEventsContent(aXMLEventsElement);
2073 0 : }
2074 :
2075 : void
2076 469 : nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
2077 : {
2078 938 : nsCOMPtr<nsIURI> uri;
2079 938 : nsCOMPtr<nsIPrincipal> principal;
2080 469 : if (aChannel) {
2081 : // Note: this code is duplicated in nsXULDocument::StartDocumentLoad and
2082 : // nsScriptSecurityManager::GetChannelPrincipal.
2083 : // Note: this should match nsDocShell::OnLoadingSite
2084 469 : NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
2085 :
2086 : nsIScriptSecurityManager *securityManager =
2087 469 : nsContentUtils::GetSecurityManager();
2088 469 : if (securityManager) {
2089 : securityManager->GetChannelPrincipal(aChannel,
2090 469 : getter_AddRefs(principal));
2091 : }
2092 : }
2093 :
2094 469 : ResetToURI(uri, aLoadGroup, principal);
2095 :
2096 938 : nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
2097 469 : if (bag) {
2098 938 : nsCOMPtr<nsIURI> baseURI;
2099 938 : bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
2100 938 : NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
2101 469 : if (baseURI) {
2102 0 : mDocumentBaseURI = baseURI;
2103 : }
2104 : }
2105 :
2106 469 : mChannel = aChannel;
2107 469 : }
2108 :
2109 : void
2110 469 : nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
2111 : nsIPrincipal* aPrincipal)
2112 : {
2113 469 : NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
2114 :
2115 : #ifdef PR_LOGGING
2116 469 : if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
2117 0 : nsCAutoString spec;
2118 0 : aURI->GetSpec(spec);
2119 0 : PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
2120 : }
2121 : #endif
2122 :
2123 469 : mSecurityInfo = nsnull;
2124 :
2125 469 : mDocumentLoadGroup = nsnull;
2126 :
2127 : // Delete references to sub-documents and kill the subdocument map,
2128 : // if any. It holds strong references
2129 469 : if (mSubDocuments) {
2130 0 : PL_DHashTableDestroy(mSubDocuments);
2131 :
2132 0 : mSubDocuments = nsnull;
2133 : }
2134 :
2135 : // Destroy link map now so we don't waste time removing
2136 : // links one by one
2137 469 : DestroyElementMaps();
2138 :
2139 469 : bool oldVal = mInUnlinkOrDeletion;
2140 469 : mInUnlinkOrDeletion = true;
2141 469 : PRUint32 count = mChildren.ChildCount();
2142 : { // Scope for update
2143 938 : MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, true);
2144 469 : for (PRInt32 i = PRInt32(count) - 1; i >= 0; i--) {
2145 0 : nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
2146 :
2147 0 : nsIContent* previousSibling = content->GetPreviousSibling();
2148 :
2149 0 : if (nsINode::GetFirstChild() == content) {
2150 0 : mFirstChild = content->GetNextSibling();
2151 : }
2152 0 : mChildren.RemoveChildAt(i);
2153 0 : nsNodeUtils::ContentRemoved(this, content, i, previousSibling);
2154 0 : content->UnbindFromTree();
2155 : }
2156 : }
2157 469 : mInUnlinkOrDeletion = oldVal;
2158 469 : mCachedRootElement = nsnull;
2159 :
2160 : // Reset our stylesheets
2161 469 : ResetStylesheetsToURI(aURI);
2162 :
2163 : // Release the listener manager
2164 469 : if (mListenerManager) {
2165 0 : mListenerManager->Disconnect();
2166 0 : mListenerManager = nsnull;
2167 : }
2168 :
2169 : // Release the stylesheets list.
2170 469 : mDOMStyleSheets = nsnull;
2171 :
2172 : // Release our principal after tearing down the document, rather than before.
2173 : // This ensures that, during teardown, the document and the dying window (which
2174 : // already nulled out its document pointer and cached the principal) have
2175 : // matching principals.
2176 469 : SetPrincipal(nsnull);
2177 :
2178 : // Clear the original URI so SetDocumentURI sets it.
2179 469 : mOriginalURI = nsnull;
2180 :
2181 469 : SetDocumentURI(aURI);
2182 : // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
2183 : // mDocumentURI.
2184 469 : mDocumentBaseURI = nsnull;
2185 :
2186 469 : if (aLoadGroup) {
2187 0 : mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
2188 : // there was an assertion here that aLoadGroup was not null. This
2189 : // is no longer valid: nsDocShell::SetDocument does not create a
2190 : // load group, and it works just fine
2191 :
2192 : // XXXbz what does "just fine" mean exactly? And given that there
2193 : // is no nsDocShell::SetDocument, what is this talking about?
2194 : }
2195 :
2196 469 : mLastModified.Truncate();
2197 : // XXXbz I guess we're assuming that the caller will either pass in
2198 : // a channel with a useful type or call SetContentType?
2199 469 : SetContentTypeInternal(EmptyCString());
2200 469 : mContentLanguage.Truncate();
2201 469 : mBaseTarget.Truncate();
2202 469 : mReferrer.Truncate();
2203 :
2204 469 : mXMLDeclarationBits = 0;
2205 :
2206 : // Now get our new principal
2207 469 : if (aPrincipal) {
2208 469 : SetPrincipal(aPrincipal);
2209 : } else {
2210 : nsIScriptSecurityManager *securityManager =
2211 0 : nsContentUtils::GetSecurityManager();
2212 0 : if (securityManager) {
2213 0 : nsCOMPtr<nsIPrincipal> principal;
2214 : nsresult rv =
2215 : securityManager->GetCodebasePrincipal(mDocumentURI,
2216 0 : getter_AddRefs(principal));
2217 0 : if (NS_SUCCEEDED(rv)) {
2218 0 : SetPrincipal(principal);
2219 : }
2220 : }
2221 : }
2222 469 : }
2223 :
2224 : nsresult
2225 469 : nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
2226 : {
2227 469 : NS_PRECONDITION(aURI, "Null URI passed to ResetStylesheetsToURI");
2228 :
2229 938 : mozAutoDocUpdate upd(this, UPDATE_STYLE, true);
2230 :
2231 : // The stylesheets should forget us
2232 469 : PRInt32 indx = mStyleSheets.Count();
2233 938 : while (--indx >= 0) {
2234 0 : nsIStyleSheet* sheet = mStyleSheets[indx];
2235 0 : sheet->SetOwningDocument(nsnull);
2236 :
2237 0 : if (sheet->IsApplicable()) {
2238 0 : RemoveStyleSheetFromStyleSets(sheet);
2239 : }
2240 :
2241 : // XXX Tell observers?
2242 : }
2243 :
2244 469 : indx = mCatalogSheets.Count();
2245 938 : while (--indx >= 0) {
2246 0 : nsIStyleSheet* sheet = mCatalogSheets[indx];
2247 0 : sheet->SetOwningDocument(nsnull);
2248 :
2249 0 : if (sheet->IsApplicable()) {
2250 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
2251 0 : if (shell) {
2252 0 : shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet);
2253 : }
2254 : }
2255 :
2256 : // XXX Tell observers?
2257 : }
2258 :
2259 :
2260 : // Release all the sheets
2261 469 : mStyleSheets.Clear();
2262 : // NOTE: We don't release the catalog sheets. It doesn't really matter
2263 : // now, but it could in the future -- in which case not releasing them
2264 : // is probably the right thing to do.
2265 :
2266 : // Now reset our inline style and attribute sheets.
2267 469 : nsresult rv = NS_OK;
2268 469 : if (mAttrStyleSheet) {
2269 : // Remove this sheet from all style sets
2270 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
2271 0 : if (shell) {
2272 : shell->StyleSet()->RemoveStyleSheet(nsStyleSet::ePresHintSheet,
2273 0 : mAttrStyleSheet);
2274 : }
2275 0 : mAttrStyleSheet->Reset(aURI);
2276 : } else {
2277 469 : rv = NS_NewHTMLStyleSheet(getter_AddRefs(mAttrStyleSheet), aURI, this);
2278 469 : NS_ENSURE_SUCCESS(rv, rv);
2279 : }
2280 :
2281 : // Don't use AddStyleSheet, since it'll put the sheet into style
2282 : // sets in the document level, which is not desirable here.
2283 469 : mAttrStyleSheet->SetOwningDocument(this);
2284 :
2285 469 : if (mStyleAttrStyleSheet) {
2286 : // Remove this sheet from all style sets
2287 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
2288 0 : if (shell) {
2289 : shell->StyleSet()->
2290 0 : RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet);
2291 : }
2292 0 : mStyleAttrStyleSheet->Reset(aURI);
2293 : } else {
2294 469 : mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet();
2295 469 : NS_ENSURE_TRUE(mStyleAttrStyleSheet, NS_ERROR_OUT_OF_MEMORY);
2296 469 : rv = mStyleAttrStyleSheet->Init(aURI, this);
2297 469 : NS_ENSURE_SUCCESS(rv, rv);
2298 : }
2299 :
2300 : // The loop over style sets below will handle putting this sheet
2301 : // into style sets as needed.
2302 469 : mStyleAttrStyleSheet->SetOwningDocument(this);
2303 :
2304 : // Now set up our style sets
2305 938 : nsCOMPtr<nsIPresShell> shell = GetShell();
2306 469 : if (shell) {
2307 0 : FillStyleSet(shell->StyleSet());
2308 : }
2309 :
2310 469 : return rv;
2311 : }
2312 :
2313 : void
2314 0 : nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
2315 : {
2316 0 : NS_PRECONDITION(aStyleSet, "Must have a style set");
2317 0 : NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0,
2318 : "Style set already has a preshint sheet?");
2319 0 : NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0,
2320 : "Style set already has document sheets?");
2321 0 : NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eStyleAttrSheet) == 0,
2322 : "Style set already has style attr sheets?");
2323 0 : NS_PRECONDITION(mStyleAttrStyleSheet, "No style attr stylesheet?");
2324 0 : NS_PRECONDITION(mAttrStyleSheet, "No attr stylesheet?");
2325 :
2326 0 : aStyleSet->AppendStyleSheet(nsStyleSet::ePresHintSheet, mAttrStyleSheet);
2327 :
2328 : aStyleSet->AppendStyleSheet(nsStyleSet::eStyleAttrSheet,
2329 0 : mStyleAttrStyleSheet);
2330 :
2331 : PRInt32 i;
2332 0 : for (i = mStyleSheets.Count() - 1; i >= 0; --i) {
2333 0 : nsIStyleSheet* sheet = mStyleSheets[i];
2334 0 : if (sheet->IsApplicable()) {
2335 0 : aStyleSet->AddDocStyleSheet(sheet, this);
2336 : }
2337 : }
2338 :
2339 0 : for (i = mCatalogSheets.Count() - 1; i >= 0; --i) {
2340 0 : nsIStyleSheet* sheet = mCatalogSheets[i];
2341 0 : if (sheet->IsApplicable()) {
2342 0 : aStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
2343 : }
2344 : }
2345 0 : }
2346 :
2347 : nsresult
2348 1038 : nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
2349 : nsILoadGroup* aLoadGroup,
2350 : nsISupports* aContainer,
2351 : nsIStreamListener **aDocListener,
2352 : bool aReset, nsIContentSink* aSink)
2353 : {
2354 : #ifdef PR_LOGGING
2355 1038 : if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
2356 0 : nsCOMPtr<nsIURI> uri;
2357 0 : aChannel->GetURI(getter_AddRefs(uri));
2358 0 : nsCAutoString spec;
2359 0 : if (uri)
2360 0 : uri->GetSpec(spec);
2361 0 : PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec.get());
2362 : }
2363 : #endif
2364 :
2365 1038 : SetReadyStateInternal(READYSTATE_LOADING);
2366 :
2367 1038 : if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
2368 1038 : mLoadedAsData = true;
2369 : // We need to disable script & style loading in this case.
2370 : // We leave them disabled even in EndLoad(), and let anyone
2371 : // who puts the document on display to worry about enabling.
2372 :
2373 : // Do not load/process scripts when loading as data
2374 1038 : ScriptLoader()->SetEnabled(false);
2375 :
2376 : // styles
2377 1038 : CSSLoader()->SetEnabled(false); // Do not load/process styles when loading as data
2378 0 : } else if (nsCRT::strcmp("external-resource", aCommand) == 0) {
2379 : // Allow CSS, but not scripts
2380 0 : ScriptLoader()->SetEnabled(false);
2381 : }
2382 :
2383 1038 : mMayStartLayout = false;
2384 :
2385 1038 : mHaveInputEncoding = true;
2386 :
2387 1038 : if (aReset) {
2388 469 : Reset(aChannel, aLoadGroup);
2389 : }
2390 :
2391 2076 : nsCAutoString contentType;
2392 1038 : if (NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
2393 : // XXX this is only necessary for viewsource:
2394 1038 : nsACString::const_iterator start, end, semicolon;
2395 1038 : contentType.BeginReading(start);
2396 1038 : contentType.EndReading(end);
2397 1038 : semicolon = start;
2398 1038 : FindCharInReadable(';', semicolon, end);
2399 1038 : SetContentTypeInternal(Substring(start, semicolon));
2400 : }
2401 :
2402 1038 : RetrieveRelevantHeaders(aChannel);
2403 :
2404 1038 : mChannel = aChannel;
2405 :
2406 1038 : nsresult rv = InitCSP();
2407 1038 : NS_ENSURE_SUCCESS(rv, rv);
2408 :
2409 1038 : return NS_OK;
2410 : }
2411 :
2412 : nsresult
2413 1038 : nsDocument::InitCSP()
2414 : {
2415 1038 : if (CSPService::sCSPEnabled) {
2416 2076 : nsAutoString cspHeaderValue;
2417 2076 : nsAutoString cspROHeaderValue;
2418 :
2419 1038 : this->GetHeaderData(nsGkAtoms::headerCSP, cspHeaderValue);
2420 1038 : this->GetHeaderData(nsGkAtoms::headerCSPReportOnly, cspROHeaderValue);
2421 :
2422 1038 : bool system = false;
2423 1038 : nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
2424 :
2425 1038 : if (NS_SUCCEEDED(ssm->IsSystemPrincipal(NodePrincipal(), &system)) && system) {
2426 : // only makes sense to register new CSP if this document is not priviliged
2427 70 : return NS_OK;
2428 : }
2429 :
2430 968 : if (cspHeaderValue.IsEmpty() && cspROHeaderValue.IsEmpty()) {
2431 : // no CSP header present, stop processing
2432 968 : return NS_OK;
2433 : }
2434 :
2435 : #ifdef PR_LOGGING
2436 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP header specified for document %p", this));
2437 : #endif
2438 :
2439 : nsresult rv;
2440 0 : nsCOMPtr<nsIContentSecurityPolicy> mCSP;
2441 0 : mCSP = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
2442 :
2443 0 : if (NS_FAILED(rv)) {
2444 : #ifdef PR_LOGGING
2445 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %x", rv));
2446 : #endif
2447 0 : return rv;
2448 : }
2449 :
2450 : // Store the request context for violation reports
2451 0 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
2452 0 : mCSP->ScanRequestData(httpChannel);
2453 :
2454 : // Start parsing the policy
2455 0 : nsCOMPtr<nsIURI> chanURI;
2456 0 : mChannel->GetURI(getter_AddRefs(chanURI));
2457 :
2458 : #ifdef PR_LOGGING
2459 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP Loaded"));
2460 : #endif
2461 :
2462 : // ReportOnly mode is enabled *only* if there are no regular-strength CSP
2463 : // headers present. If there are, then we ignore the ReportOnly mode and
2464 : // toss a warning into the error console, proceeding with enforcing the
2465 : // regular-strength CSP.
2466 0 : if (cspHeaderValue.IsEmpty()) {
2467 0 : mCSP->SetReportOnlyMode(true);
2468 :
2469 : // Need to tokenize the header value since multiple headers could be
2470 : // concatenated into one comma-separated list of policies.
2471 : // See RFC2616 section 4.2 (last paragraph)
2472 0 : nsCharSeparatedTokenizer tokenizer(cspROHeaderValue, ',');
2473 0 : while (tokenizer.hasMoreTokens()) {
2474 0 : const nsSubstring& policy = tokenizer.nextToken();
2475 0 : mCSP->RefinePolicy(policy, chanURI);
2476 : #ifdef PR_LOGGING
2477 : {
2478 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG,
2479 : ("CSP (report only) refined with policy: \"%s\"",
2480 : NS_ConvertUTF16toUTF8(policy).get()));
2481 : }
2482 : #endif
2483 : }
2484 : } else {
2485 : //XXX(sstamm): maybe we should post a warning when both read only and regular
2486 : // CSP headers are present.
2487 :
2488 : // Need to tokenize the header value since multiple headers could be
2489 : // concatenated into one comma-separated list of policies.
2490 : // See RFC2616 section 4.2 (last paragraph)
2491 0 : nsCharSeparatedTokenizer tokenizer(cspHeaderValue, ',');
2492 0 : while (tokenizer.hasMoreTokens()) {
2493 0 : const nsSubstring& policy = tokenizer.nextToken();
2494 0 : mCSP->RefinePolicy(policy, chanURI);
2495 : #ifdef PR_LOGGING
2496 : {
2497 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG,
2498 : ("CSP refined with policy: \"%s\"",
2499 : NS_ConvertUTF16toUTF8(policy).get()));
2500 : }
2501 : #endif
2502 : }
2503 : }
2504 :
2505 : // Check for frame-ancestor violation
2506 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
2507 0 : if (docShell) {
2508 0 : bool safeAncestry = false;
2509 :
2510 : // PermitsAncestry sends violation reports when necessary
2511 0 : rv = mCSP->PermitsAncestry(docShell, &safeAncestry);
2512 0 : NS_ENSURE_SUCCESS(rv, rv);
2513 :
2514 0 : if (!safeAncestry) {
2515 : #ifdef PR_LOGGING
2516 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG,
2517 : ("CSP doesn't like frame's ancestry, not loading."));
2518 : #endif
2519 : // stop! ERROR page!
2520 0 : mChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
2521 : }
2522 : }
2523 :
2524 : //Copy into principal
2525 0 : nsIPrincipal* principal = GetPrincipal();
2526 :
2527 0 : if (principal) {
2528 0 : principal->SetCsp(mCSP);
2529 : #ifdef PR_LOGGING
2530 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG,
2531 : ("Inserted CSP into principal %p", principal));
2532 : }
2533 : else {
2534 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG,
2535 : ("Couldn't copy CSP into absent principal %p", principal));
2536 : #endif
2537 : }
2538 : }
2539 : #ifdef PR_LOGGING
2540 : else { //CSP was not enabled!
2541 0 : PR_LOG(gCspPRLog, PR_LOG_DEBUG,
2542 : ("CSP is disabled, skipping CSP init for document %p", this));
2543 : }
2544 : #endif
2545 0 : return NS_OK;
2546 : }
2547 :
2548 : void
2549 0 : nsDocument::StopDocumentLoad()
2550 : {
2551 0 : if (mParser) {
2552 0 : mParserAborted = true;
2553 0 : mParser->Terminate();
2554 : }
2555 0 : }
2556 :
2557 : void
2558 1742 : nsDocument::SetDocumentURI(nsIURI* aURI)
2559 : {
2560 3484 : nsCOMPtr<nsIURI> oldBase = GetDocBaseURI();
2561 1742 : mDocumentURI = NS_TryToMakeImmutable(aURI);
2562 1742 : nsIURI* newBase = GetDocBaseURI();
2563 :
2564 1742 : bool equalBases = false;
2565 1742 : if (oldBase && newBase) {
2566 0 : oldBase->Equals(newBase, &equalBases);
2567 : }
2568 : else {
2569 1742 : equalBases = !oldBase && !newBase;
2570 : }
2571 :
2572 : // If this is the first time we're setting the document's URI, set the
2573 : // document's original URI.
2574 1742 : if (!mOriginalURI)
2575 1742 : mOriginalURI = mDocumentURI;
2576 :
2577 : // If changing the document's URI changed the base URI of the document, we
2578 : // need to refresh the hrefs of all the links on the page.
2579 1742 : if (!equalBases) {
2580 1273 : RefreshLinkHrefs();
2581 : }
2582 1742 : }
2583 :
2584 : NS_IMETHODIMP
2585 0 : nsDocument::GetLastModified(nsAString& aLastModified)
2586 : {
2587 0 : if (!mLastModified.IsEmpty()) {
2588 0 : aLastModified.Assign(mLastModified);
2589 : } else {
2590 : // If we for whatever reason failed to find the last modified time
2591 : // (or even the current time), fall back to what NS4.x returned.
2592 0 : aLastModified.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00"));
2593 : }
2594 :
2595 0 : return NS_OK;
2596 : }
2597 :
2598 : void
2599 0 : nsDocument::AddToNameTable(Element *aElement, nsIAtom* aName)
2600 : {
2601 : nsIdentifierMapEntry *entry =
2602 0 : mIdentifierMap.PutEntry(nsDependentAtomString(aName));
2603 :
2604 : // Null for out-of-memory
2605 0 : if (entry) {
2606 0 : entry->AddNameElement(this, aElement);
2607 : }
2608 0 : }
2609 :
2610 : void
2611 0 : nsDocument::RemoveFromNameTable(Element *aElement, nsIAtom* aName)
2612 : {
2613 : // Speed up document teardown
2614 0 : if (mIdentifierMap.Count() == 0)
2615 0 : return;
2616 :
2617 : nsIdentifierMapEntry *entry =
2618 0 : mIdentifierMap.GetEntry(nsDependentAtomString(aName));
2619 0 : if (!entry) // Could be false if the element was anonymous, hence never added
2620 0 : return;
2621 :
2622 0 : entry->RemoveNameElement(aElement);
2623 : }
2624 :
2625 : void
2626 122 : nsDocument::AddToIdTable(Element *aElement, nsIAtom* aId)
2627 : {
2628 : nsIdentifierMapEntry *entry =
2629 122 : mIdentifierMap.PutEntry(nsDependentAtomString(aId));
2630 :
2631 122 : if (entry) { /* True except on OOM */
2632 122 : entry->AddIdElement(aElement);
2633 : }
2634 122 : }
2635 :
2636 : void
2637 122 : nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
2638 : {
2639 122 : NS_ASSERTION(aId, "huhwhatnow?");
2640 :
2641 : // Speed up document teardown
2642 122 : if (mIdentifierMap.Count() == 0) {
2643 0 : return;
2644 : }
2645 :
2646 : nsIdentifierMapEntry *entry =
2647 122 : mIdentifierMap.GetEntry(nsDependentAtomString(aId));
2648 122 : if (!entry) // Can be null for XML elements with changing ids.
2649 0 : return;
2650 :
2651 122 : entry->RemoveIdElement(aElement);
2652 122 : if (entry->IsEmpty()) {
2653 122 : mIdentifierMap.RawRemoveEntry(entry);
2654 : }
2655 : }
2656 :
2657 : nsIPrincipal*
2658 0 : nsDocument::GetPrincipal()
2659 : {
2660 0 : return NodePrincipal();
2661 : }
2662 :
2663 : extern bool sDisablePrefetchHTTPSPref;
2664 :
2665 : void
2666 3249 : nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
2667 : {
2668 3249 : if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
2669 3544 : nsCOMPtr<nsIURI> uri;
2670 1772 : aNewPrincipal->GetURI(getter_AddRefs(uri));
2671 : bool isHTTPS;
2672 1772 : if (!uri || NS_FAILED(uri->SchemeIs("https", &isHTTPS)) ||
2673 : isHTTPS) {
2674 539 : mAllowDNSPrefetch = false;
2675 : }
2676 : }
2677 3249 : mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
2678 3249 : }
2679 :
2680 : NS_IMETHODIMP
2681 0 : nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
2682 : {
2683 0 : NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
2684 :
2685 0 : return NS_OK;
2686 : }
2687 :
2688 : NS_IMETHODIMP
2689 0 : nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache)
2690 : {
2691 0 : mApplicationCache = aApplicationCache;
2692 :
2693 0 : return NS_OK;
2694 : }
2695 :
2696 : NS_IMETHODIMP
2697 0 : nsDocument::GetContentType(nsAString& aContentType)
2698 : {
2699 0 : CopyUTF8toUTF16(GetContentTypeInternal(), aContentType);
2700 :
2701 0 : return NS_OK;
2702 : }
2703 :
2704 : void
2705 0 : nsDocument::SetContentType(const nsAString& aContentType)
2706 : {
2707 0 : NS_ASSERTION(GetContentTypeInternal().IsEmpty() ||
2708 : GetContentTypeInternal().Equals(NS_ConvertUTF16toUTF8(aContentType)),
2709 : "Do you really want to change the content-type?");
2710 :
2711 0 : SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
2712 0 : }
2713 :
2714 : /* Return true if the document is in the focused top-level window, and is an
2715 : * ancestor of the focused DOMWindow. */
2716 : NS_IMETHODIMP
2717 0 : nsDocument::HasFocus(bool* aResult)
2718 : {
2719 0 : *aResult = false;
2720 :
2721 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
2722 0 : if (!fm)
2723 0 : return NS_ERROR_NOT_AVAILABLE;
2724 :
2725 : // Is there a focused DOMWindow?
2726 0 : nsCOMPtr<nsIDOMWindow> focusedWindow;
2727 0 : fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
2728 0 : if (!focusedWindow)
2729 0 : return NS_OK;
2730 :
2731 : // Are we an ancestor of the focused DOMWindow?
2732 0 : nsCOMPtr<nsIDOMDocument> domDocument;
2733 0 : focusedWindow->GetDocument(getter_AddRefs(domDocument));
2734 0 : nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
2735 :
2736 0 : for (nsIDocument* currentDoc = document; currentDoc;
2737 : currentDoc = currentDoc->GetParentDocument()) {
2738 0 : if (currentDoc == this) {
2739 : // Yes, we are an ancestor
2740 0 : *aResult = true;
2741 0 : return NS_OK;
2742 : }
2743 : }
2744 :
2745 0 : return NS_OK;
2746 : }
2747 :
2748 : NS_IMETHODIMP
2749 0 : nsDocument::GetReferrer(nsAString& aReferrer)
2750 : {
2751 0 : CopyUTF8toUTF16(mReferrer, aReferrer);
2752 0 : return NS_OK;
2753 : }
2754 :
2755 : NS_IMETHODIMP
2756 0 : nsDocument::GetActiveElement(nsIDOMElement **aElement)
2757 : {
2758 0 : *aElement = nsnull;
2759 :
2760 : // Get the focused element.
2761 0 : nsCOMPtr<nsPIDOMWindow> window = GetWindow();
2762 0 : if (window) {
2763 0 : nsCOMPtr<nsPIDOMWindow> focusedWindow;
2764 : nsIContent* focusedContent =
2765 : nsFocusManager::GetFocusedDescendant(window, false,
2766 0 : getter_AddRefs(focusedWindow));
2767 : // be safe and make sure the element is from this document
2768 0 : if (focusedContent && focusedContent->OwnerDoc() == this) {
2769 0 : CallQueryInterface(focusedContent, aElement);
2770 0 : return NS_OK;
2771 : }
2772 : }
2773 :
2774 : // No focused element anywhere in this document. Try to get the BODY.
2775 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryObject(this);
2776 0 : if (htmlDoc) {
2777 0 : nsCOMPtr<nsIDOMHTMLElement> bodyElement;
2778 0 : htmlDoc->GetBody(getter_AddRefs(bodyElement));
2779 0 : if (bodyElement) {
2780 0 : *aElement = bodyElement;
2781 0 : NS_ADDREF(*aElement);
2782 : }
2783 : // Because of IE compatibility, return null when html document doesn't have
2784 : // a body.
2785 0 : return NS_OK;
2786 : }
2787 :
2788 : // If we couldn't get a BODY, return the root element.
2789 0 : return GetDocumentElement(aElement);
2790 : }
2791 :
2792 : NS_IMETHODIMP
2793 0 : nsDocument::GetCurrentScript(nsIDOMElement **aElement)
2794 : {
2795 0 : nsIScriptElement* script = mScriptLoader->GetCurrentScript();
2796 0 : if (script) {
2797 0 : return CallQueryInterface(script, aElement);
2798 : }
2799 :
2800 0 : *aElement = nsnull;
2801 :
2802 0 : return NS_OK;
2803 : }
2804 :
2805 : NS_IMETHODIMP
2806 0 : nsDocument::ElementFromPoint(float aX, float aY, nsIDOMElement** aReturn)
2807 : {
2808 0 : return ElementFromPointHelper(aX, aY, false, true, aReturn);
2809 : }
2810 :
2811 : nsresult
2812 0 : nsDocument::ElementFromPointHelper(float aX, float aY,
2813 : bool aIgnoreRootScrollFrame,
2814 : bool aFlushLayout,
2815 : nsIDOMElement** aReturn)
2816 : {
2817 0 : NS_ENSURE_ARG_POINTER(aReturn);
2818 0 : *aReturn = nsnull;
2819 : // As per the the spec, we return null if either coord is negative
2820 0 : if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0))
2821 0 : return NS_OK;
2822 :
2823 0 : nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
2824 0 : nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
2825 0 : nsPoint pt(x, y);
2826 :
2827 : // Make sure the layout information we get is up-to-date, and
2828 : // ensure we get a root frame (for everything but XUL)
2829 0 : if (aFlushLayout)
2830 0 : FlushPendingNotifications(Flush_Layout);
2831 :
2832 0 : nsIPresShell *ps = GetShell();
2833 0 : NS_ENSURE_STATE(ps);
2834 0 : nsIFrame *rootFrame = ps->GetRootFrame();
2835 :
2836 : // XUL docs, unlike HTML, have no frame tree until everything's done loading
2837 0 : if (!rootFrame)
2838 0 : return NS_OK; // return null to premature XUL callers as a reminder to wait
2839 :
2840 : nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, true,
2841 0 : aIgnoreRootScrollFrame);
2842 0 : if (!ptFrame)
2843 0 : return NS_OK;
2844 :
2845 0 : nsIContent* ptContent = ptFrame->GetContent();
2846 0 : NS_ENSURE_STATE(ptContent);
2847 :
2848 : // If the content is in a subdocument, try to get the element from |this| doc
2849 0 : nsIDocument *currentDoc = ptContent->GetCurrentDoc();
2850 0 : if (currentDoc && (currentDoc != this)) {
2851 0 : *aReturn = CheckAncestryAndGetFrame(currentDoc).get();
2852 0 : return NS_OK;
2853 : }
2854 :
2855 : // If we have an anonymous element (such as an internal div from a textbox),
2856 : // or a node that isn't an element (such as a text frame node),
2857 : // replace it with the first non-anonymous parent node of type element.
2858 0 : while (ptContent &&
2859 0 : (!ptContent->IsElement() ||
2860 0 : ptContent->IsInAnonymousSubtree())) {
2861 : // XXXldb: Faster to jump to GetBindingParent if non-null?
2862 0 : ptContent = ptContent->GetParent();
2863 : }
2864 :
2865 0 : if (ptContent)
2866 0 : CallQueryInterface(ptContent, aReturn);
2867 0 : return NS_OK;
2868 : }
2869 :
2870 : nsresult
2871 0 : nsDocument::NodesFromRectHelper(float aX, float aY,
2872 : float aTopSize, float aRightSize,
2873 : float aBottomSize, float aLeftSize,
2874 : bool aIgnoreRootScrollFrame,
2875 : bool aFlushLayout,
2876 : nsIDOMNodeList** aReturn)
2877 : {
2878 0 : NS_ENSURE_ARG_POINTER(aReturn);
2879 :
2880 0 : nsSimpleContentList* elements = new nsSimpleContentList(this);
2881 0 : NS_ADDREF(elements);
2882 0 : *aReturn = elements;
2883 :
2884 : // Following the same behavior of elementFromPoint,
2885 : // we don't return anything if either coord is negative
2886 0 : if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0))
2887 0 : return NS_OK;
2888 :
2889 0 : nscoord x = nsPresContext::CSSPixelsToAppUnits(aX - aLeftSize);
2890 0 : nscoord y = nsPresContext::CSSPixelsToAppUnits(aY - aTopSize);
2891 0 : nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
2892 0 : nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
2893 :
2894 0 : nsRect rect(x, y, w, h);
2895 :
2896 : // Make sure the layout information we get is up-to-date, and
2897 : // ensure we get a root frame (for everything but XUL)
2898 0 : if (aFlushLayout) {
2899 0 : FlushPendingNotifications(Flush_Layout);
2900 : }
2901 :
2902 0 : nsIPresShell *ps = GetShell();
2903 0 : NS_ENSURE_STATE(ps);
2904 0 : nsIFrame *rootFrame = ps->GetRootFrame();
2905 :
2906 : // XUL docs, unlike HTML, have no frame tree until everything's done loading
2907 0 : if (!rootFrame)
2908 0 : return NS_OK; // return nothing to premature XUL callers as a reminder to wait
2909 :
2910 0 : nsAutoTArray<nsIFrame*,8> outFrames;
2911 : nsLayoutUtils::GetFramesForArea(rootFrame, rect, outFrames,
2912 0 : true, aIgnoreRootScrollFrame);
2913 :
2914 0 : PRInt32 length = outFrames.Length();
2915 0 : if (!length)
2916 0 : return NS_OK;
2917 :
2918 : // Used to filter out repeated elements in sequence.
2919 0 : nsIContent* lastAdded = nsnull;
2920 :
2921 0 : for (PRInt32 i = 0; i < length; i++) {
2922 :
2923 0 : nsIContent* ptContent = outFrames.ElementAt(i)->GetContent();
2924 0 : NS_ENSURE_STATE(ptContent);
2925 :
2926 : // If the content is in a subdocument, try to get the element from |this| doc
2927 0 : nsIDocument *currentDoc = ptContent->GetCurrentDoc();
2928 0 : if (currentDoc && (currentDoc != this)) {
2929 : // XXX felipe: I can't get this type right without the intermediate vars
2930 0 : nsCOMPtr<nsIDOMElement> x = CheckAncestryAndGetFrame(currentDoc);
2931 0 : nsCOMPtr<nsIContent> elementDoc = do_QueryInterface(x);
2932 0 : if (elementDoc != lastAdded) {
2933 0 : elements->AppendElement(elementDoc);
2934 0 : lastAdded = elementDoc;
2935 : }
2936 0 : continue;
2937 : }
2938 :
2939 : // If we have an anonymous element (such as an internal div from a textbox),
2940 : // or a node that isn't an element or a text node,
2941 : // replace it with the first non-anonymous parent node.
2942 0 : while (ptContent &&
2943 0 : (!(ptContent->IsElement() ||
2944 0 : ptContent->IsNodeOfType(nsINode::eTEXT)) ||
2945 0 : ptContent->IsInAnonymousSubtree())) {
2946 : // XXXldb: Faster to jump to GetBindingParent if non-null?
2947 0 : ptContent = ptContent->GetParent();
2948 : }
2949 :
2950 0 : if (ptContent && ptContent != lastAdded) {
2951 0 : elements->AppendElement(ptContent);
2952 0 : lastAdded = ptContent;
2953 : }
2954 : }
2955 0 : return NS_OK;
2956 : }
2957 :
2958 : NS_IMETHODIMP
2959 0 : nsDocument::GetElementsByClassName(const nsAString& aClasses,
2960 : nsIDOMNodeList** aReturn)
2961 : {
2962 0 : return nsContentUtils::GetElementsByClassName(this, aClasses, aReturn);
2963 : }
2964 :
2965 : NS_IMETHODIMP
2966 0 : nsDocument::ReleaseCapture()
2967 : {
2968 : // only release the capture if the caller can access it. This prevents a
2969 : // page from stopping a scrollbar grab for example.
2970 0 : nsCOMPtr<nsIDOMNode> node = do_QueryInterface(nsIPresShell::GetCapturingContent());
2971 0 : if (node && nsContentUtils::CanCallerAccess(node)) {
2972 0 : nsIPresShell::SetCapturingContent(nsnull, 0);
2973 : }
2974 0 : return NS_OK;
2975 : }
2976 :
2977 : nsresult
2978 1842 : nsDocument::SetBaseURI(nsIURI* aURI)
2979 : {
2980 1842 : if (!aURI && !mDocumentBaseURI) {
2981 1607 : return NS_OK;
2982 : }
2983 :
2984 : // Don't do anything if the URI wasn't actually changed.
2985 235 : if (aURI && mDocumentBaseURI) {
2986 0 : bool equalBases = false;
2987 0 : mDocumentBaseURI->Equals(aURI, &equalBases);
2988 0 : if (equalBases) {
2989 0 : return NS_OK;
2990 : }
2991 : }
2992 :
2993 235 : if (aURI) {
2994 235 : mDocumentBaseURI = NS_TryToMakeImmutable(aURI);
2995 : } else {
2996 0 : mDocumentBaseURI = nsnull;
2997 : }
2998 235 : RefreshLinkHrefs();
2999 :
3000 235 : return NS_OK;
3001 : }
3002 :
3003 : void
3004 0 : nsDocument::GetBaseTarget(nsAString &aBaseTarget)
3005 : {
3006 0 : aBaseTarget = mBaseTarget;
3007 0 : }
3008 :
3009 : void
3010 2684 : nsDocument::SetDocumentCharacterSet(const nsACString& aCharSetID)
3011 : {
3012 2684 : if (!mCharacterSet.Equals(aCharSetID)) {
3013 1273 : mCharacterSet = aCharSetID;
3014 :
3015 : #ifdef DEBUG
3016 2546 : nsCAutoString canonicalName;
3017 1273 : nsCharsetAlias::GetPreferred(aCharSetID, canonicalName);
3018 1273 : NS_ASSERTION(canonicalName.Equals(aCharSetID),
3019 : "charset name must be canonical");
3020 : #endif
3021 :
3022 1273 : PRInt32 n = mCharSetObservers.Length();
3023 :
3024 1273 : for (PRInt32 i = 0; i < n; i++) {
3025 0 : nsIObserver* observer = mCharSetObservers.ElementAt(i);
3026 :
3027 : observer->Observe(static_cast<nsIDocument *>(this), "charset",
3028 0 : NS_ConvertASCIItoUTF16(aCharSetID).get());
3029 : }
3030 : }
3031 2684 : }
3032 :
3033 : nsresult
3034 0 : nsDocument::AddCharSetObserver(nsIObserver* aObserver)
3035 : {
3036 0 : NS_ENSURE_ARG_POINTER(aObserver);
3037 :
3038 0 : NS_ENSURE_TRUE(mCharSetObservers.AppendElement(aObserver), NS_ERROR_FAILURE);
3039 :
3040 0 : return NS_OK;
3041 : }
3042 :
3043 : void
3044 0 : nsDocument::RemoveCharSetObserver(nsIObserver* aObserver)
3045 : {
3046 0 : mCharSetObservers.RemoveElement(aObserver);
3047 0 : }
3048 :
3049 : void
3050 3349 : nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const
3051 : {
3052 3349 : aData.Truncate();
3053 3349 : const nsDocHeaderData* data = mHeaderData;
3054 6706 : while (data) {
3055 8 : if (data->mField == aHeaderField) {
3056 0 : aData = data->mData;
3057 :
3058 0 : break;
3059 : }
3060 8 : data = data->mNext;
3061 : }
3062 3349 : }
3063 :
3064 : void
3065 4 : nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
3066 : {
3067 4 : if (!aHeaderField) {
3068 0 : NS_ERROR("null headerField");
3069 0 : return;
3070 : }
3071 :
3072 4 : if (!mHeaderData) {
3073 4 : if (!aData.IsEmpty()) { // don't bother storing empty string
3074 4 : mHeaderData = new nsDocHeaderData(aHeaderField, aData);
3075 : }
3076 : }
3077 : else {
3078 0 : nsDocHeaderData* data = mHeaderData;
3079 0 : nsDocHeaderData** lastPtr = &mHeaderData;
3080 0 : bool found = false;
3081 0 : do { // look for existing and replace
3082 0 : if (data->mField == aHeaderField) {
3083 0 : if (!aData.IsEmpty()) {
3084 0 : data->mData.Assign(aData);
3085 : }
3086 : else { // don't store empty string
3087 0 : *lastPtr = data->mNext;
3088 0 : data->mNext = nsnull;
3089 0 : delete data;
3090 : }
3091 0 : found = true;
3092 :
3093 0 : break;
3094 : }
3095 0 : lastPtr = &(data->mNext);
3096 0 : data = *lastPtr;
3097 : } while (data);
3098 :
3099 0 : if (!aData.IsEmpty() && !found) {
3100 : // didn't find, append
3101 0 : *lastPtr = new nsDocHeaderData(aHeaderField, aData);
3102 : }
3103 : }
3104 :
3105 4 : if (aHeaderField == nsGkAtoms::headerContentLanguage) {
3106 0 : CopyUTF16toUTF8(aData, mContentLanguage);
3107 : }
3108 :
3109 : // Set the default script-type on the root element.
3110 4 : if (aHeaderField == nsGkAtoms::headerContentScriptType) {
3111 0 : Element *root = GetRootElement();
3112 0 : if (root) {
3113 : // Get the script-type ID for this value.
3114 : nsresult rv;
3115 0 : nsCOMPtr<nsIScriptRuntime> runtime;
3116 0 : rv = NS_GetScriptRuntime(aData, getter_AddRefs(runtime));
3117 0 : if (NS_FAILED(rv) || runtime == nsnull) {
3118 0 : NS_WARNING("The script-type is unknown");
3119 : } else {
3120 0 : root->SetScriptTypeID(runtime->GetScriptTypeID());
3121 : }
3122 : }
3123 : }
3124 :
3125 4 : if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
3126 : // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
3127 : // spec.
3128 0 : if (DOMStringIsNull(mLastStyleSheetSet)) {
3129 : // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
3130 : // per spec. The idea here is that we're changing our preferred set and
3131 : // that shouldn't change the value of lastStyleSheetSet. Also, we're
3132 : // using the Internal version so we can update the CSSLoader and not have
3133 : // to worry about null strings.
3134 0 : EnableStyleSheetsForSetInternal(aData, true);
3135 : }
3136 : }
3137 :
3138 4 : if (aHeaderField == nsGkAtoms::refresh) {
3139 : // We get into this code before we have a script global yet, so get to
3140 : // our container via mDocumentContainer.
3141 0 : nsCOMPtr<nsIRefreshURI> refresher = do_QueryReferent(mDocumentContainer);
3142 0 : if (refresher) {
3143 : // Note: using mDocumentURI instead of mBaseURI here, for consistency
3144 : // (used to just use the current URI of our webnavigation, but that
3145 : // should really be the same thing). Note that this code can run
3146 : // before the current URI of the webnavigation has been updated, so we
3147 : // can't assert equality here.
3148 0 : refresher->SetupRefreshURIFromHeader(mDocumentURI,
3149 0 : NS_ConvertUTF16toUTF8(aData));
3150 : }
3151 : }
3152 :
3153 4 : if (aHeaderField == nsGkAtoms::headerDNSPrefetchControl &&
3154 : mAllowDNSPrefetch) {
3155 : // Chromium treats any value other than 'on' (case insensitive) as 'off'.
3156 0 : mAllowDNSPrefetch = aData.IsEmpty() || aData.LowerCaseEqualsLiteral("on");
3157 : }
3158 : }
3159 :
3160 : bool
3161 1038 : nsDocument::TryChannelCharset(nsIChannel *aChannel,
3162 : PRInt32& aCharsetSource,
3163 : nsACString& aCharset)
3164 : {
3165 1038 : if(kCharsetFromChannel <= aCharsetSource) {
3166 0 : return true;
3167 : }
3168 :
3169 1038 : if (aChannel) {
3170 2076 : nsCAutoString charsetVal;
3171 1038 : nsresult rv = aChannel->GetContentCharset(charsetVal);
3172 1038 : if (NS_SUCCEEDED(rv)) {
3173 2076 : nsCAutoString preferred;
3174 1038 : rv = nsCharsetAlias::GetPreferred(charsetVal, preferred);
3175 1038 : if(NS_SUCCEEDED(rv)) {
3176 560 : aCharset = preferred;
3177 560 : aCharsetSource = kCharsetFromChannel;
3178 560 : return true;
3179 : }
3180 : }
3181 : }
3182 478 : return false;
3183 : }
3184 :
3185 : nsresult
3186 0 : nsDocument::CreateShell(nsPresContext* aContext, nsIViewManager* aViewManager,
3187 : nsStyleSet* aStyleSet,
3188 : nsIPresShell** aInstancePtrResult)
3189 : {
3190 : // Don't add anything here. Add it to |doCreateShell| instead.
3191 : // This exists so that subclasses can pass other values for the 4th
3192 : // parameter some of the time.
3193 : return doCreateShell(aContext, aViewManager, aStyleSet,
3194 0 : eCompatibility_FullStandards, aInstancePtrResult);
3195 : }
3196 :
3197 : nsresult
3198 0 : nsDocument::doCreateShell(nsPresContext* aContext,
3199 : nsIViewManager* aViewManager, nsStyleSet* aStyleSet,
3200 : nsCompatibility aCompatMode,
3201 : nsIPresShell** aInstancePtrResult)
3202 : {
3203 0 : *aInstancePtrResult = nsnull;
3204 :
3205 0 : NS_ASSERTION(!mPresShell, "We have a presshell already!");
3206 :
3207 0 : NS_ENSURE_FALSE(GetBFCacheEntry(), NS_ERROR_FAILURE);
3208 :
3209 0 : FillStyleSet(aStyleSet);
3210 :
3211 0 : nsCOMPtr<nsIPresShell> shell;
3212 0 : nsresult rv = NS_NewPresShell(getter_AddRefs(shell));
3213 0 : if (NS_FAILED(rv)) {
3214 0 : return rv;
3215 : }
3216 :
3217 0 : rv = shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode);
3218 0 : NS_ENSURE_SUCCESS(rv, rv);
3219 :
3220 : // Note: we don't hold a ref to the shell (it holds a ref to us)
3221 0 : mPresShell = shell;
3222 :
3223 0 : mExternalResourceMap.ShowViewers();
3224 :
3225 0 : MaybeRescheduleAnimationFrameNotifications();
3226 :
3227 0 : shell.swap(*aInstancePtrResult);
3228 :
3229 0 : return NS_OK;
3230 : }
3231 :
3232 : void
3233 0 : nsDocument::MaybeRescheduleAnimationFrameNotifications()
3234 : {
3235 0 : if (!mPresShell || !IsEventHandlingEnabled()) {
3236 : // bail out for now, until one of those conditions changes
3237 0 : return;
3238 : }
3239 :
3240 0 : nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver();
3241 0 : if (!mFrameRequestCallbacks.IsEmpty()) {
3242 0 : rd->ScheduleFrameRequestCallbacks(this);
3243 : }
3244 : }
3245 :
3246 : void
3247 0 : nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
3248 : {
3249 0 : aCallbacks.AppendElements(mFrameRequestCallbacks);
3250 0 : mFrameRequestCallbacks.Clear();
3251 0 : }
3252 :
3253 0 : PLDHashOperator RequestDiscardEnumerator(imgIRequest* aKey,
3254 : PRUint32 aData,
3255 : void* userArg)
3256 : {
3257 0 : aKey->RequestDiscard();
3258 0 : return PL_DHASH_NEXT;
3259 : }
3260 :
3261 : void
3262 0 : nsDocument::DeleteShell()
3263 : {
3264 0 : mExternalResourceMap.HideViewers();
3265 0 : if (IsEventHandlingEnabled()) {
3266 0 : RevokeAnimationFrameNotifications();
3267 : }
3268 :
3269 : // When our shell goes away, request that all our images be immediately
3270 : // discarded, so we don't carry around decoded image data for a document we
3271 : // no longer intend to paint.
3272 0 : mImageTracker.EnumerateRead(RequestDiscardEnumerator, nsnull);
3273 :
3274 0 : mPresShell = nsnull;
3275 0 : }
3276 :
3277 : void
3278 0 : nsDocument::RevokeAnimationFrameNotifications()
3279 : {
3280 0 : if (!mFrameRequestCallbacks.IsEmpty()) {
3281 : mPresShell->GetPresContext()->RefreshDriver()->
3282 0 : RevokeFrameRequestCallbacks(this);
3283 : }
3284 0 : }
3285 :
3286 : static void
3287 0 : SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
3288 : {
3289 0 : SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
3290 :
3291 0 : NS_RELEASE(e->mKey);
3292 0 : if (e->mSubDocument) {
3293 0 : e->mSubDocument->SetParentDocument(nsnull);
3294 0 : NS_RELEASE(e->mSubDocument);
3295 : }
3296 0 : }
3297 :
3298 : static bool
3299 0 : SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key)
3300 : {
3301 : SubDocMapEntry *e =
3302 : const_cast<SubDocMapEntry *>
3303 0 : (static_cast<const SubDocMapEntry *>(entry));
3304 :
3305 0 : e->mKey = const_cast<Element*>(static_cast<const Element*>(key));
3306 0 : NS_ADDREF(e->mKey);
3307 :
3308 0 : e->mSubDocument = nsnull;
3309 0 : return true;
3310 : }
3311 :
3312 : nsresult
3313 0 : nsDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc)
3314 : {
3315 0 : NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED);
3316 :
3317 0 : if (!aSubDoc) {
3318 : // aSubDoc is nsnull, remove the mapping
3319 :
3320 0 : if (mSubDocuments) {
3321 : SubDocMapEntry *entry =
3322 : static_cast<SubDocMapEntry*>
3323 : (PL_DHashTableOperate(mSubDocuments, aElement,
3324 0 : PL_DHASH_LOOKUP));
3325 :
3326 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3327 0 : PL_DHashTableRawRemove(mSubDocuments, entry);
3328 : }
3329 : }
3330 : } else {
3331 0 : if (!mSubDocuments) {
3332 : // Create a new hashtable
3333 :
3334 : static PLDHashTableOps hash_table_ops =
3335 : {
3336 : PL_DHashAllocTable,
3337 : PL_DHashFreeTable,
3338 : PL_DHashVoidPtrKeyStub,
3339 : PL_DHashMatchEntryStub,
3340 : PL_DHashMoveEntryStub,
3341 : SubDocClearEntry,
3342 : PL_DHashFinalizeStub,
3343 : SubDocInitEntry
3344 : };
3345 :
3346 : mSubDocuments = PL_NewDHashTable(&hash_table_ops, nsnull,
3347 0 : sizeof(SubDocMapEntry), 16);
3348 0 : if (!mSubDocuments) {
3349 0 : return NS_ERROR_OUT_OF_MEMORY;
3350 : }
3351 : }
3352 :
3353 : // Add a mapping to the hash table
3354 : SubDocMapEntry *entry =
3355 : static_cast<SubDocMapEntry*>
3356 : (PL_DHashTableOperate(mSubDocuments, aElement,
3357 0 : PL_DHASH_ADD));
3358 :
3359 0 : if (!entry) {
3360 0 : return NS_ERROR_OUT_OF_MEMORY;
3361 : }
3362 :
3363 0 : if (entry->mSubDocument) {
3364 0 : entry->mSubDocument->SetParentDocument(nsnull);
3365 :
3366 : // Release the old sub document
3367 0 : NS_RELEASE(entry->mSubDocument);
3368 : }
3369 :
3370 0 : entry->mSubDocument = aSubDoc;
3371 0 : NS_ADDREF(entry->mSubDocument);
3372 :
3373 0 : aSubDoc->SetParentDocument(this);
3374 : }
3375 :
3376 0 : return NS_OK;
3377 : }
3378 :
3379 : nsIDocument*
3380 0 : nsDocument::GetSubDocumentFor(nsIContent *aContent) const
3381 : {
3382 0 : if (mSubDocuments && aContent->IsElement()) {
3383 : SubDocMapEntry *entry =
3384 : static_cast<SubDocMapEntry*>
3385 0 : (PL_DHashTableOperate(mSubDocuments, aContent->AsElement(),
3386 0 : PL_DHASH_LOOKUP));
3387 :
3388 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
3389 0 : return entry->mSubDocument;
3390 : }
3391 : }
3392 :
3393 0 : return nsnull;
3394 : }
3395 :
3396 : static PLDHashOperator
3397 0 : FindContentEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
3398 : PRUint32 number, void *arg)
3399 : {
3400 0 : SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
3401 0 : FindContentData *data = static_cast<FindContentData*>(arg);
3402 :
3403 0 : if (entry->mSubDocument == data->mSubDocument) {
3404 0 : data->mResult = entry->mKey;
3405 :
3406 0 : return PL_DHASH_STOP;
3407 : }
3408 :
3409 0 : return PL_DHASH_NEXT;
3410 : }
3411 :
3412 : Element*
3413 0 : nsDocument::FindContentForSubDocument(nsIDocument *aDocument) const
3414 : {
3415 0 : NS_ENSURE_TRUE(aDocument, nsnull);
3416 :
3417 0 : if (!mSubDocuments) {
3418 0 : return nsnull;
3419 : }
3420 :
3421 0 : FindContentData data(aDocument);
3422 0 : PL_DHashTableEnumerate(mSubDocuments, FindContentEnumerator, &data);
3423 :
3424 0 : return data.mResult;
3425 : }
3426 :
3427 : bool
3428 12632 : nsDocument::IsNodeOfType(PRUint32 aFlags) const
3429 : {
3430 12632 : return !(aFlags & ~eDOCUMENT);
3431 : }
3432 :
3433 : PRUint16
3434 0 : nsDocument::NodeType()
3435 : {
3436 0 : return (PRUint16)nsIDOMNode::DOCUMENT_NODE;
3437 : }
3438 :
3439 : void
3440 0 : nsDocument::NodeName(nsAString& aNodeName)
3441 : {
3442 0 : aNodeName.AssignLiteral("#document");
3443 0 : }
3444 :
3445 : Element*
3446 5482 : nsIDocument::GetRootElement() const
3447 : {
3448 3160 : return (mCachedRootElement && mCachedRootElement->GetNodeParent() == this) ?
3449 8642 : mCachedRootElement : GetRootElementInternal();
3450 : }
3451 :
3452 : Element*
3453 2322 : nsDocument::GetRootElementInternal() const
3454 : {
3455 : // Loop backwards because any non-elements, such as doctypes and PIs
3456 : // are likely to appear before the root element.
3457 : PRUint32 i;
3458 2424 : for (i = mChildren.ChildCount(); i > 0; --i) {
3459 1140 : nsIContent* child = mChildren.ChildAt(i - 1);
3460 1140 : if (child->IsElement()) {
3461 1038 : const_cast<nsDocument*>(this)->mCachedRootElement = child->AsElement();
3462 1038 : return child->AsElement();
3463 : }
3464 : }
3465 :
3466 1284 : const_cast<nsDocument*>(this)->mCachedRootElement = nsnull;
3467 1284 : return nsnull;
3468 : }
3469 :
3470 : nsIContent *
3471 56 : nsDocument::GetChildAt(PRUint32 aIndex) const
3472 : {
3473 56 : return mChildren.GetSafeChildAt(aIndex);
3474 : }
3475 :
3476 : PRInt32
3477 21 : nsDocument::IndexOf(nsINode* aPossibleChild) const
3478 : {
3479 21 : return mChildren.IndexOfChild(aPossibleChild);
3480 : }
3481 :
3482 : PRUint32
3483 1754 : nsDocument::GetChildCount() const
3484 : {
3485 1754 : return mChildren.ChildCount();
3486 : }
3487 :
3488 : nsIContent * const *
3489 72 : nsDocument::GetChildArray(PRUint32* aChildCount) const
3490 : {
3491 72 : return mChildren.GetChildArray(aChildCount);
3492 : }
3493 :
3494 :
3495 : nsresult
3496 1385 : nsDocument::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
3497 : bool aNotify)
3498 : {
3499 1385 : if (aKid->IsElement() && GetRootElement()) {
3500 0 : NS_ERROR("Inserting element child when we already have one");
3501 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
3502 : }
3503 :
3504 1385 : return doInsertChildAt(aKid, aIndex, aNotify, mChildren);
3505 : }
3506 :
3507 : nsresult
3508 0 : nsDocument::AppendChildTo(nsIContent* aKid, bool aNotify)
3509 : {
3510 : // Make sure to _not_ call the subclass InsertChildAt here. If
3511 : // subclasses wanted to hook into this stuff, they would have
3512 : // overridden AppendChildTo.
3513 : // XXXbz maybe this should just be a non-virtual method on nsINode?
3514 : // Feels that way to me...
3515 0 : return nsDocument::InsertChildAt(aKid, GetChildCount(), aNotify);
3516 : }
3517 :
3518 : nsresult
3519 10 : nsDocument::RemoveChildAt(PRUint32 aIndex, bool aNotify)
3520 : {
3521 20 : nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex);
3522 10 : if (!oldKid) {
3523 0 : return NS_OK;
3524 : }
3525 :
3526 10 : if (oldKid->IsElement()) {
3527 : // Destroy the link map up front before we mess with the child list.
3528 10 : DestroyElementMaps();
3529 : }
3530 :
3531 : nsresult rv =
3532 10 : doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
3533 10 : mCachedRootElement = nsnull;
3534 10 : return rv;
3535 : }
3536 :
3537 : PRInt32
3538 0 : nsDocument::GetNumberOfStyleSheets() const
3539 : {
3540 0 : return mStyleSheets.Count();
3541 : }
3542 :
3543 : nsIStyleSheet*
3544 0 : nsDocument::GetStyleSheetAt(PRInt32 aIndex) const
3545 : {
3546 0 : NS_ENSURE_TRUE(0 <= aIndex && aIndex < mStyleSheets.Count(), nsnull);
3547 0 : return mStyleSheets[aIndex];
3548 : }
3549 :
3550 : PRInt32
3551 0 : nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const
3552 : {
3553 0 : return mStyleSheets.IndexOf(aSheet);
3554 : }
3555 :
3556 : void
3557 0 : nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet)
3558 : {
3559 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
3560 0 : if (shell) {
3561 0 : shell->StyleSet()->AddDocStyleSheet(aSheet, this);
3562 : }
3563 0 : }
3564 :
3565 : void
3566 0 : nsDocument::AddStyleSheet(nsIStyleSheet* aSheet)
3567 : {
3568 0 : NS_PRECONDITION(aSheet, "null arg");
3569 0 : mStyleSheets.AppendObject(aSheet);
3570 0 : aSheet->SetOwningDocument(this);
3571 :
3572 0 : if (aSheet->IsApplicable()) {
3573 0 : AddStyleSheetToStyleSets(aSheet);
3574 : }
3575 :
3576 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, true));
3577 0 : }
3578 :
3579 : void
3580 0 : nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet)
3581 : {
3582 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
3583 0 : if (shell) {
3584 0 : shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet);
3585 : }
3586 0 : }
3587 :
3588 : void
3589 0 : nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
3590 : {
3591 0 : NS_PRECONDITION(aSheet, "null arg");
3592 0 : nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
3593 :
3594 0 : if (!mStyleSheets.RemoveObject(aSheet)) {
3595 0 : NS_NOTREACHED("stylesheet not found");
3596 : return;
3597 : }
3598 :
3599 0 : if (!mIsGoingAway) {
3600 0 : if (aSheet->IsApplicable()) {
3601 0 : RemoveStyleSheetFromStyleSets(aSheet);
3602 : }
3603 :
3604 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (this, aSheet, true));
3605 : }
3606 :
3607 0 : aSheet->SetOwningDocument(nsnull);
3608 : }
3609 :
3610 : void
3611 0 : nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
3612 : nsCOMArray<nsIStyleSheet>& aNewSheets)
3613 : {
3614 0 : BeginUpdate(UPDATE_STYLE);
3615 :
3616 : // XXX Need to set the sheet on the ownernode, if any
3617 0 : NS_PRECONDITION(aOldSheets.Count() == aNewSheets.Count(),
3618 : "The lists must be the same length!");
3619 0 : PRInt32 count = aOldSheets.Count();
3620 :
3621 0 : nsCOMPtr<nsIStyleSheet> oldSheet;
3622 : PRInt32 i;
3623 0 : for (i = 0; i < count; ++i) {
3624 0 : oldSheet = aOldSheets[i];
3625 :
3626 : // First remove the old sheet.
3627 0 : NS_ASSERTION(oldSheet, "None of the old sheets should be null");
3628 0 : PRInt32 oldIndex = mStyleSheets.IndexOf(oldSheet);
3629 0 : RemoveStyleSheet(oldSheet); // This does the right notifications
3630 :
3631 : // Now put the new one in its place. If it's null, just ignore it.
3632 0 : nsIStyleSheet* newSheet = aNewSheets[i];
3633 0 : if (newSheet) {
3634 0 : mStyleSheets.InsertObjectAt(newSheet, oldIndex);
3635 0 : newSheet->SetOwningDocument(this);
3636 0 : if (newSheet->IsApplicable()) {
3637 0 : AddStyleSheetToStyleSets(newSheet);
3638 : }
3639 :
3640 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, newSheet, true));
3641 : }
3642 : }
3643 :
3644 0 : EndUpdate(UPDATE_STYLE);
3645 0 : }
3646 :
3647 : void
3648 0 : nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex)
3649 : {
3650 0 : NS_PRECONDITION(aSheet, "null ptr");
3651 0 : mStyleSheets.InsertObjectAt(aSheet, aIndex);
3652 :
3653 0 : aSheet->SetOwningDocument(this);
3654 :
3655 0 : if (aSheet->IsApplicable()) {
3656 0 : AddStyleSheetToStyleSets(aSheet);
3657 : }
3658 :
3659 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, true));
3660 0 : }
3661 :
3662 :
3663 : void
3664 0 : nsDocument::SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
3665 : bool aApplicable)
3666 : {
3667 0 : NS_PRECONDITION(aSheet, "null arg");
3668 :
3669 : // If we're actually in the document style sheet list
3670 0 : if (-1 != mStyleSheets.IndexOf(aSheet)) {
3671 0 : if (aApplicable) {
3672 0 : AddStyleSheetToStyleSets(aSheet);
3673 : } else {
3674 0 : RemoveStyleSheetFromStyleSets(aSheet);
3675 : }
3676 : }
3677 :
3678 : // We have to always notify, since this will be called for sheets
3679 : // that are children of sheets in our style set, as well as some
3680 : // sheets for nsHTMLEditor.
3681 :
3682 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged,
3683 : (this, aSheet, aApplicable));
3684 0 : }
3685 :
3686 : // These three functions are a lot like the implementation of the
3687 : // corresponding API for regular stylesheets.
3688 :
3689 : PRInt32
3690 0 : nsDocument::GetNumberOfCatalogStyleSheets() const
3691 : {
3692 0 : return mCatalogSheets.Count();
3693 : }
3694 :
3695 : nsIStyleSheet*
3696 0 : nsDocument::GetCatalogStyleSheetAt(PRInt32 aIndex) const
3697 : {
3698 0 : NS_ENSURE_TRUE(0 <= aIndex && aIndex < mCatalogSheets.Count(), nsnull);
3699 0 : return mCatalogSheets[aIndex];
3700 : }
3701 :
3702 : void
3703 0 : nsDocument::AddCatalogStyleSheet(nsIStyleSheet* aSheet)
3704 : {
3705 0 : mCatalogSheets.AppendObject(aSheet);
3706 0 : aSheet->SetOwningDocument(this);
3707 :
3708 0 : if (aSheet->IsApplicable()) {
3709 : // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
3710 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
3711 0 : if (shell) {
3712 0 : shell->StyleSet()->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
3713 : }
3714 : }
3715 :
3716 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, false));
3717 0 : }
3718 :
3719 : void
3720 0 : nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI)
3721 : {
3722 0 : mozilla::css::Loader* cssLoader = CSSLoader();
3723 0 : if (cssLoader->GetEnabled()) {
3724 0 : PRInt32 sheetCount = GetNumberOfCatalogStyleSheets();
3725 0 : for (PRInt32 i = 0; i < sheetCount; i++) {
3726 0 : nsIStyleSheet* sheet = GetCatalogStyleSheetAt(i);
3727 0 : NS_ASSERTION(sheet, "unexpected null stylesheet in the document");
3728 0 : if (sheet) {
3729 0 : nsCAutoString uriStr;
3730 0 : sheet->GetSheetURI()->GetSpec(uriStr);
3731 0 : if (uriStr.Equals(aStyleSheetURI))
3732 : return;
3733 : }
3734 : }
3735 :
3736 0 : nsCOMPtr<nsIURI> uri;
3737 0 : NS_NewURI(getter_AddRefs(uri), aStyleSheetURI);
3738 0 : if (uri) {
3739 0 : nsRefPtr<nsCSSStyleSheet> sheet;
3740 0 : cssLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet));
3741 0 : if (sheet) {
3742 0 : BeginUpdate(UPDATE_STYLE);
3743 0 : AddCatalogStyleSheet(sheet);
3744 0 : EndUpdate(UPDATE_STYLE);
3745 : }
3746 : }
3747 : }
3748 : }
3749 :
3750 : nsIScriptGlobalObject*
3751 8450 : nsDocument::GetScriptGlobalObject() const
3752 : {
3753 : // If we're going away, we've already released the reference to our
3754 : // ScriptGlobalObject. We can, however, try to obtain it for the
3755 : // caller through our docshell.
3756 :
3757 : // We actually need to start returning the docshell's script global
3758 : // object as soon as nsDocumentViewer::Close has called
3759 : // RemovedFromDocShell on us.
3760 8450 : if (mRemovedFromDocShell) {
3761 : nsCOMPtr<nsIInterfaceRequestor> requestor =
3762 0 : do_QueryReferent(mDocumentContainer);
3763 0 : if (requestor) {
3764 0 : nsCOMPtr<nsIScriptGlobalObject> globalObject = do_GetInterface(requestor);
3765 0 : return globalObject;
3766 : }
3767 : }
3768 :
3769 8450 : return mScriptGlobalObject;
3770 : }
3771 :
3772 : nsIScriptGlobalObject*
3773 1924 : nsDocument::GetScopeObject()
3774 : {
3775 3848 : nsCOMPtr<nsIScriptGlobalObject> scope(do_QueryReferent(mScopeObject));
3776 1924 : return scope;
3777 : }
3778 :
3779 : static void
3780 0 : NotifyActivityChanged(nsIContent *aContent, void *aUnused)
3781 : {
3782 : #ifdef MOZ_MEDIA
3783 0 : nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
3784 0 : if (domMediaElem) {
3785 0 : nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
3786 0 : mediaElem->NotifyOwnerDocumentActivityChanged();
3787 : }
3788 : #endif
3789 0 : nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aContent));
3790 0 : if (objectLoadingContent) {
3791 0 : nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
3792 0 : olc->NotifyOwnerDocumentActivityChanged();
3793 : }
3794 0 : }
3795 :
3796 : void
3797 0 : nsIDocument::SetContainer(nsISupports* aContainer)
3798 : {
3799 0 : mDocumentContainer = do_GetWeakReference(aContainer);
3800 0 : EnumerateFreezableElements(NotifyActivityChanged, nsnull);
3801 0 : }
3802 :
3803 : void
3804 0 : nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
3805 : {
3806 : #ifdef DEBUG
3807 : {
3808 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobalObject));
3809 :
3810 0 : NS_ASSERTION(!win || win->IsInnerWindow(),
3811 : "Script global object must be an inner window!");
3812 : }
3813 : #endif
3814 0 : NS_ABORT_IF_FALSE(aScriptGlobalObject || !mAnimationController ||
3815 : mAnimationController->IsPausedByType(
3816 : nsSMILTimeContainer::PAUSE_PAGEHIDE |
3817 : nsSMILTimeContainer::PAUSE_BEGIN),
3818 : "Clearing window pointer while animations are unpaused");
3819 :
3820 0 : if (mScriptGlobalObject && !aScriptGlobalObject) {
3821 : // We're detaching from the window. We need to grab a pointer to
3822 : // our layout history state now.
3823 0 : mLayoutHistoryState = GetLayoutHistoryState();
3824 :
3825 0 : if (mPresShell && !EventHandlingSuppressed()) {
3826 0 : RevokeAnimationFrameNotifications();
3827 : }
3828 :
3829 : // Also make sure to remove our onload blocker now if we haven't done it yet
3830 0 : if (mOnloadBlockCount != 0) {
3831 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
3832 0 : if (loadGroup) {
3833 0 : loadGroup->RemoveRequest(mOnloadBlocker, nsnull, NS_OK);
3834 : }
3835 : }
3836 : }
3837 :
3838 0 : mScriptGlobalObject = aScriptGlobalObject;
3839 :
3840 0 : if (aScriptGlobalObject) {
3841 0 : mScriptObject = nsnull;
3842 0 : mHasHadScriptHandlingObject = true;
3843 : // Go back to using the docshell for the layout history state
3844 0 : mLayoutHistoryState = nsnull;
3845 0 : mScopeObject = do_GetWeakReference(aScriptGlobalObject);
3846 :
3847 : #ifdef DEBUG
3848 0 : if (!mWillReparent) {
3849 : // We really shouldn't have a wrapper here but if we do we need to make sure
3850 : // it has the correct parent.
3851 0 : JSObject *obj = GetWrapperPreserveColor();
3852 0 : if (obj) {
3853 0 : JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject();
3854 0 : nsIScriptContext *scx = aScriptGlobalObject->GetContext();
3855 0 : JSContext *cx = scx ? scx->GetNativeContext() : nsnull;
3856 0 : if (!cx) {
3857 0 : nsContentUtils::ThreadJSContextStack()->Peek(&cx);
3858 0 : if (!cx) {
3859 0 : nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
3860 0 : NS_ASSERTION(cx, "Uhoh, no context, this is bad!");
3861 : }
3862 : }
3863 0 : if (cx) {
3864 0 : NS_ASSERTION(JS_GetGlobalForObject(cx, obj) == newScope,
3865 : "Wrong scope, this is really bad!");
3866 : }
3867 : }
3868 : }
3869 : #endif
3870 :
3871 0 : if (mAllowDNSPrefetch) {
3872 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
3873 0 : if (docShell) {
3874 : #ifdef DEBUG
3875 : nsCOMPtr<nsIWebNavigation> webNav =
3876 0 : do_GetInterface(aScriptGlobalObject);
3877 0 : NS_ASSERTION(SameCOMIdentity(webNav, docShell),
3878 : "Unexpected container or script global?");
3879 : #endif
3880 : bool allowDNSPrefetch;
3881 0 : docShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
3882 0 : mAllowDNSPrefetch = allowDNSPrefetch;
3883 : }
3884 : }
3885 :
3886 0 : MaybeRescheduleAnimationFrameNotifications();
3887 : }
3888 :
3889 : // Remember the pointer to our window (or lack there of), to avoid
3890 : // having to QI every time it's asked for.
3891 0 : nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
3892 0 : mWindow = window;
3893 :
3894 : // Set our visibility state, but do not fire the event. This is correct
3895 : // because either we're coming out of bfcache (in which case IsVisible() will
3896 : // still test false at this point and no state change will happen) or we're
3897 : // doing the initial document load and don't want to fire the event for this
3898 : // change.
3899 0 : mVisibilityState = GetVisibilityState();
3900 0 : }
3901 :
3902 : nsIScriptGlobalObject*
3903 18124 : nsDocument::GetScriptHandlingObjectInternal() const
3904 : {
3905 18124 : NS_ASSERTION(!mScriptGlobalObject,
3906 : "Do not call this when mScriptGlobalObject is set!");
3907 :
3908 : nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
3909 36248 : do_QueryReferent(mScriptObject);
3910 36248 : nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptHandlingObject);
3911 18124 : if (win) {
3912 0 : NS_ASSERTION(win->IsInnerWindow(), "Should have inner window here!");
3913 0 : nsPIDOMWindow* outer = win->GetOuterWindow();
3914 0 : if (!outer || outer->GetCurrentInnerWindow() != win) {
3915 0 : NS_WARNING("Wrong inner/outer window combination!");
3916 0 : return nsnull;
3917 : }
3918 : }
3919 18124 : return scriptHandlingObject;
3920 : }
3921 : void
3922 1273 : nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
3923 : {
3924 1273 : NS_ASSERTION(!mScriptGlobalObject ||
3925 : mScriptGlobalObject == aScriptObject,
3926 : "Wrong script object!");
3927 2546 : nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aScriptObject);
3928 1273 : NS_ASSERTION(!win || win->IsInnerWindow(), "Should have inner window here!");
3929 1273 : mScopeObject = mScriptObject = do_GetWeakReference(aScriptObject);
3930 1273 : if (aScriptObject) {
3931 0 : mHasHadScriptHandlingObject = true;
3932 : }
3933 1273 : }
3934 :
3935 : nsPIDOMWindow *
3936 7456 : nsDocument::GetWindowInternal() const
3937 : {
3938 7456 : NS_ASSERTION(!mWindow, "This should not be called when mWindow is not null!");
3939 :
3940 14912 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(GetScriptGlobalObject()));
3941 :
3942 7456 : if (!win) {
3943 7456 : return nsnull;
3944 : }
3945 :
3946 0 : return win->GetOuterWindow();
3947 : }
3948 :
3949 : nsPIDOMWindow *
3950 0 : nsDocument::GetInnerWindowInternal()
3951 : {
3952 0 : NS_ASSERTION(mRemovedFromDocShell,
3953 : "This document should have been removed from docshell!");
3954 :
3955 0 : nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(GetScriptGlobalObject()));
3956 :
3957 0 : return win;
3958 : }
3959 :
3960 : nsScriptLoader*
3961 2311 : nsDocument::ScriptLoader()
3962 : {
3963 2311 : return mScriptLoader;
3964 : }
3965 :
3966 : bool
3967 0 : nsDocument::InternalAllowXULXBL()
3968 : {
3969 0 : if (nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal())) {
3970 0 : mAllowXULXBL = eTriTrue;
3971 0 : return true;
3972 : }
3973 :
3974 0 : mAllowXULXBL = eTriFalse;
3975 0 : return false;
3976 : }
3977 :
3978 : // Note: We don't hold a reference to the document observer; we assume
3979 : // that it has a live reference to the document.
3980 : void
3981 1038 : nsDocument::AddObserver(nsIDocumentObserver* aObserver)
3982 : {
3983 1038 : NS_ASSERTION(mObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex,
3984 : "Observer already in the list");
3985 1038 : mObservers.AppendElement(aObserver);
3986 1038 : AddMutationObserver(aObserver);
3987 1038 : }
3988 :
3989 : bool
3990 2138 : nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
3991 : {
3992 : // If we're in the process of destroying the document (and we're
3993 : // informing the observers of the destruction), don't remove the
3994 : // observers from the list. This is not a big deal, since we
3995 : // don't hold a live reference to the observers.
3996 2138 : if (!mInDestructor) {
3997 2138 : RemoveMutationObserver(aObserver);
3998 2138 : return mObservers.RemoveElement(aObserver);
3999 : }
4000 :
4001 0 : return mObservers.Contains(aObserver);
4002 : }
4003 :
4004 : void
4005 6283 : nsDocument::MaybeEndOutermostXBLUpdate()
4006 : {
4007 : // Only call BindingManager()->EndOutermostUpdate() when
4008 : // we're not in an update and it is safe to run scripts.
4009 6283 : if (mUpdateNestLevel == 0 && mInXBLUpdate) {
4010 4958 : if (nsContentUtils::IsSafeToRunScript()) {
4011 4890 : mInXBLUpdate = false;
4012 4890 : BindingManager()->EndOutermostUpdate();
4013 68 : } else if (!mInDestructor) {
4014 : nsContentUtils::AddScriptRunner(
4015 68 : NS_NewRunnableMethod(this, &nsDocument::MaybeEndOutermostXBLUpdate));
4016 : }
4017 : }
4018 6283 : }
4019 :
4020 : void
4021 6215 : nsDocument::BeginUpdate(nsUpdateType aUpdateType)
4022 : {
4023 6215 : if (mUpdateNestLevel == 0 && !mInXBLUpdate) {
4024 4890 : mInXBLUpdate = true;
4025 4890 : BindingManager()->BeginOutermostUpdate();
4026 : }
4027 :
4028 6215 : ++mUpdateNestLevel;
4029 6215 : nsContentUtils::AddScriptBlocker();
4030 6215 : NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, aUpdateType));
4031 6215 : }
4032 :
4033 : void
4034 6215 : nsDocument::EndUpdate(nsUpdateType aUpdateType)
4035 : {
4036 6215 : NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, aUpdateType));
4037 :
4038 6215 : nsContentUtils::RemoveScriptBlocker();
4039 :
4040 6215 : --mUpdateNestLevel;
4041 :
4042 : // This set of updates may have created XBL bindings. Let the
4043 : // binding manager know we're done.
4044 6215 : MaybeEndOutermostXBLUpdate();
4045 :
4046 6215 : MaybeInitializeFinalizeFrameLoaders();
4047 6215 : }
4048 :
4049 : void
4050 1038 : nsDocument::BeginLoad()
4051 : {
4052 : // Block onload here to prevent having to deal with blocking and
4053 : // unblocking it while we know the document is loading.
4054 1038 : BlockOnload();
4055 :
4056 1038 : if (mScriptLoader) {
4057 1038 : mScriptLoader->BeginDeferringScripts();
4058 : }
4059 :
4060 1038 : NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
4061 1038 : }
4062 :
4063 : void
4064 0 : nsDocument::ReportEmptyGetElementByIdArg()
4065 : {
4066 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
4067 : "DOM", this,
4068 : nsContentUtils::eDOM_PROPERTIES,
4069 0 : "EmptyGetElementByIdParam");
4070 0 : }
4071 :
4072 : Element*
4073 78 : nsDocument::GetElementById(const nsAString& aElementId)
4074 : {
4075 78 : if (!CheckGetElementByIdArg(aElementId)) {
4076 0 : return nsnull;
4077 : }
4078 :
4079 78 : nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
4080 78 : return entry ? entry->GetIdElement() : nsnull;
4081 : }
4082 :
4083 : const nsSmallVoidArray*
4084 0 : nsDocument::GetAllElementsForId(const nsAString& aElementId) const
4085 : {
4086 0 : if (aElementId.IsEmpty()) {
4087 0 : return nsnull;
4088 : }
4089 :
4090 0 : nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
4091 0 : return entry ? entry->GetIdElements() : nsnull;
4092 : }
4093 :
4094 : NS_IMETHODIMP
4095 0 : nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
4096 : {
4097 0 : Element *content = GetElementById(aId);
4098 0 : if (content) {
4099 0 : return CallQueryInterface(content, aReturn);
4100 : }
4101 :
4102 0 : *aReturn = nsnull;
4103 :
4104 0 : return NS_OK;
4105 : }
4106 :
4107 : Element*
4108 0 : nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
4109 : void* aData, bool aForImage)
4110 : {
4111 0 : nsDependentAtomString id(aID);
4112 :
4113 0 : if (!CheckGetElementByIdArg(id))
4114 0 : return nsnull;
4115 :
4116 0 : nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(id);
4117 0 : NS_ENSURE_TRUE(entry, nsnull);
4118 :
4119 0 : entry->AddContentChangeCallback(aObserver, aData, aForImage);
4120 0 : return aForImage ? entry->GetImageIdElement() : entry->GetIdElement();
4121 : }
4122 :
4123 : void
4124 0 : nsDocument::RemoveIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
4125 : void* aData, bool aForImage)
4126 : {
4127 0 : nsDependentAtomString id(aID);
4128 :
4129 0 : if (!CheckGetElementByIdArg(id))
4130 : return;
4131 :
4132 0 : nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(id);
4133 0 : if (!entry) {
4134 : return;
4135 : }
4136 :
4137 0 : entry->RemoveContentChangeCallback(aObserver, aData, aForImage);
4138 : }
4139 :
4140 : NS_IMETHODIMP
4141 0 : nsDocument::MozSetImageElement(const nsAString& aImageElementId,
4142 : nsIDOMElement* aImageElement)
4143 : {
4144 0 : if (aImageElementId.IsEmpty())
4145 0 : return NS_OK;
4146 :
4147 : // Hold a script blocker while calling SetImageElement since that can call
4148 : // out to id-observers
4149 0 : nsAutoScriptBlocker scriptBlocker;
4150 :
4151 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(aImageElement);
4152 0 : nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aImageElementId);
4153 0 : if (entry) {
4154 0 : entry->SetImageElement(content ? content->AsElement() : nsnull);
4155 0 : if (entry->IsEmpty()) {
4156 0 : mIdentifierMap.RemoveEntry(aImageElementId);
4157 : }
4158 : }
4159 0 : return NS_OK;
4160 : }
4161 :
4162 : Element*
4163 0 : nsDocument::LookupImageElement(const nsAString& aId)
4164 : {
4165 0 : if (aId.IsEmpty())
4166 0 : return nsnull;
4167 :
4168 0 : nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
4169 0 : return entry ? entry->GetImageIdElement() : nsnull;
4170 : }
4171 :
4172 : void
4173 1038 : nsDocument::DispatchContentLoadedEvents()
4174 : {
4175 : NS_TIME_FUNCTION;
4176 : // If you add early returns from this method, make sure you're
4177 : // calling UnblockOnload properly.
4178 :
4179 : // Unpin references to preloaded images
4180 1038 : mPreloadingImages.Clear();
4181 :
4182 1038 : if (mTiming) {
4183 0 : mTiming->NotifyDOMContentLoadedStart(nsIDocument::GetDocumentURI());
4184 : }
4185 :
4186 : // Fire a DOM event notifying listeners that this document has been
4187 : // loaded (excluding images and other loads initiated by this
4188 : // document).
4189 : nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
4190 1038 : NS_LITERAL_STRING("DOMContentLoaded"),
4191 1038 : true, true);
4192 :
4193 1038 : if (mTiming) {
4194 0 : mTiming->NotifyDOMContentLoadedEnd(nsIDocument::GetDocumentURI());
4195 : }
4196 :
4197 : // If this document is a [i]frame, fire a DOMFrameContentLoaded
4198 : // event on all parent documents notifying that the HTML (excluding
4199 : // other external files such as images and stylesheets) in a frame
4200 : // has finished loading.
4201 :
4202 : // target_frame is the [i]frame element that will be used as the
4203 : // target for the event. It's the [i]frame whose content is done
4204 : // loading.
4205 2076 : nsCOMPtr<nsIDOMEventTarget> target_frame;
4206 :
4207 1038 : if (mParentDocument) {
4208 : target_frame =
4209 0 : do_QueryInterface(mParentDocument->FindContentForSubDocument(this));
4210 : }
4211 :
4212 1038 : if (target_frame) {
4213 0 : nsCOMPtr<nsIDocument> parent = mParentDocument;
4214 0 : do {
4215 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(parent);
4216 :
4217 0 : nsCOMPtr<nsIDOMEvent> event;
4218 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent;
4219 0 : if (domDoc) {
4220 0 : domDoc->CreateEvent(NS_LITERAL_STRING("Events"),
4221 0 : getter_AddRefs(event));
4222 :
4223 0 : privateEvent = do_QueryInterface(event);
4224 : }
4225 :
4226 0 : if (event && privateEvent) {
4227 0 : event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), true,
4228 0 : true);
4229 :
4230 0 : privateEvent->SetTarget(target_frame);
4231 0 : privateEvent->SetTrusted(true);
4232 :
4233 : // To dispatch this event we must manually call
4234 : // nsEventDispatcher::Dispatch() on the ancestor document since the
4235 : // target is not in the same document, so the event would never reach
4236 : // the ancestor document if we used the normal event
4237 : // dispatching code.
4238 :
4239 0 : nsEvent* innerEvent = privateEvent->GetInternalNSEvent();
4240 0 : if (innerEvent) {
4241 0 : nsEventStatus status = nsEventStatus_eIgnore;
4242 :
4243 0 : nsIPresShell *shell = parent->GetShell();
4244 0 : if (shell) {
4245 0 : nsRefPtr<nsPresContext> context = shell->GetPresContext();
4246 :
4247 0 : if (context) {
4248 : nsEventDispatcher::Dispatch(parent, context, innerEvent, event,
4249 0 : &status);
4250 : }
4251 : }
4252 : }
4253 : }
4254 :
4255 0 : parent = parent->GetParentDocument();
4256 0 : } while (parent);
4257 : }
4258 :
4259 : // If the document has a manifest attribute, fire a MozApplicationManifest
4260 : // event.
4261 1038 : Element* root = GetRootElement();
4262 1038 : if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
4263 : nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
4264 0 : NS_LITERAL_STRING("MozApplicationManifest"),
4265 0 : true, true);
4266 : }
4267 :
4268 1038 : UnblockOnload(true);
4269 1038 : }
4270 :
4271 : void
4272 1038 : nsDocument::EndLoad()
4273 : {
4274 : // Drop the ref to our parser, if any, but keep hold of the sink so that we
4275 : // can flush it from FlushPendingNotifications as needed. We might have to
4276 : // do that to get a StartLayout() to happen.
4277 1038 : if (mParser) {
4278 1038 : mWeakSink = do_GetWeakReference(mParser->GetContentSink());
4279 1038 : mParser = nsnull;
4280 : }
4281 :
4282 1038 : NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
4283 :
4284 1038 : if (!mSynchronousDOMContentLoaded) {
4285 : nsRefPtr<nsIRunnable> ev =
4286 0 : NS_NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents);
4287 0 : NS_DispatchToCurrentThread(ev);
4288 : } else {
4289 1038 : DispatchContentLoadedEvents();
4290 : }
4291 1038 : }
4292 :
4293 : void
4294 0 : nsDocument::ContentStateChanged(nsIContent* aContent, nsEventStates aStateMask)
4295 : {
4296 0 : NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
4297 : "Someone forgot a scriptblocker");
4298 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged,
4299 : (this, aContent, aStateMask));
4300 0 : }
4301 :
4302 : void
4303 0 : nsDocument::DocumentStatesChanged(nsEventStates aStateMask)
4304 : {
4305 : // Invalidate our cached state.
4306 0 : mGotDocumentState &= ~aStateMask;
4307 0 : mDocumentState &= ~aStateMask;
4308 :
4309 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged, (this, aStateMask));
4310 0 : }
4311 :
4312 : void
4313 0 : nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet,
4314 : nsIStyleRule* aOldStyleRule,
4315 : nsIStyleRule* aNewStyleRule)
4316 : {
4317 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged,
4318 : (this, aStyleSheet,
4319 : aOldStyleRule, aNewStyleRule));
4320 0 : }
4321 :
4322 : void
4323 0 : nsDocument::StyleRuleAdded(nsIStyleSheet* aStyleSheet,
4324 : nsIStyleRule* aStyleRule)
4325 : {
4326 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded,
4327 : (this, aStyleSheet, aStyleRule));
4328 0 : }
4329 :
4330 : void
4331 0 : nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet,
4332 : nsIStyleRule* aStyleRule)
4333 : {
4334 0 : NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved,
4335 : (this, aStyleSheet, aStyleRule));
4336 0 : }
4337 :
4338 :
4339 : //
4340 : // nsIDOMDocument interface
4341 : //
4342 : NS_IMETHODIMP
4343 0 : nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype)
4344 : {
4345 0 : NS_ENSURE_ARG_POINTER(aDoctype);
4346 :
4347 0 : *aDoctype = nsnull;
4348 : PRInt32 i, count;
4349 0 : count = mChildren.ChildCount();
4350 0 : for (i = 0; i < count; i++) {
4351 0 : CallQueryInterface(mChildren.ChildAt(i), aDoctype);
4352 :
4353 0 : if (*aDoctype) {
4354 0 : return NS_OK;
4355 : }
4356 : }
4357 :
4358 0 : return NS_OK;
4359 : }
4360 :
4361 : NS_IMETHODIMP
4362 2 : nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation)
4363 : {
4364 2 : if (!mDOMImplementation) {
4365 2 : nsCOMPtr<nsIURI> uri;
4366 1 : NS_NewURI(getter_AddRefs(uri), "about:blank");
4367 1 : NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
4368 1 : bool hasHadScriptObject = true;
4369 : nsIScriptGlobalObject* scriptObject =
4370 1 : GetScriptHandlingObject(hasHadScriptObject);
4371 1 : NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
4372 2 : mDOMImplementation = new nsDOMImplementation(this, scriptObject, uri, uri);
4373 1 : if (!mDOMImplementation) {
4374 0 : return NS_ERROR_OUT_OF_MEMORY;
4375 : }
4376 : }
4377 :
4378 2 : NS_ADDREF(*aImplementation = mDOMImplementation);
4379 :
4380 2 : return NS_OK;
4381 : }
4382 :
4383 : NS_IMETHODIMP
4384 2121 : nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement)
4385 : {
4386 2121 : NS_ENSURE_ARG_POINTER(aDocumentElement);
4387 :
4388 2121 : Element* root = GetRootElement();
4389 2121 : if (root) {
4390 2121 : return CallQueryInterface(root, aDocumentElement);
4391 : }
4392 :
4393 0 : *aDocumentElement = nsnull;
4394 :
4395 0 : return NS_OK;
4396 : }
4397 :
4398 : NS_IMETHODIMP
4399 0 : nsDocument::CreateElement(const nsAString& aTagName,
4400 : nsIDOMElement** aReturn)
4401 : {
4402 0 : *aReturn = nsnull;
4403 0 : nsCOMPtr<nsIContent> content;
4404 0 : nsresult rv = CreateElement(aTagName, getter_AddRefs(content));
4405 0 : NS_ENSURE_SUCCESS(rv, rv);
4406 0 : return CallQueryInterface(content, aReturn);
4407 : }
4408 :
4409 0 : bool IsLowercaseASCII(const nsAString& aValue)
4410 : {
4411 0 : PRInt32 len = aValue.Length();
4412 0 : for (PRInt32 i = 0; i < len; ++i) {
4413 0 : PRUnichar c = aValue[i];
4414 0 : if (!(0x0061 <= (c) && ((c) <= 0x007a))) {
4415 0 : return false;
4416 : }
4417 : }
4418 0 : return true;
4419 : }
4420 :
4421 : nsresult
4422 8 : nsDocument::CreateElement(const nsAString& aTagName,
4423 : nsIContent** aReturn)
4424 : {
4425 8 : *aReturn = nsnull;
4426 :
4427 8 : nsresult rv = nsContentUtils::CheckQName(aTagName, false);
4428 8 : NS_ENSURE_SUCCESS(rv, rv);
4429 :
4430 8 : bool needsLowercase = IsHTML() && !IsLowercaseASCII(aTagName);
4431 16 : nsAutoString lcTagName;
4432 8 : if (needsLowercase) {
4433 0 : nsContentUtils::ASCIIToLower(aTagName, lcTagName);
4434 : }
4435 :
4436 : rv = CreateElem(needsLowercase ? lcTagName : aTagName,
4437 8 : nsnull, mDefaultElementType, aReturn);
4438 8 : return rv;
4439 : }
4440 :
4441 : NS_IMETHODIMP
4442 1 : nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
4443 : const nsAString& aQualifiedName,
4444 : nsIDOMElement** aReturn)
4445 : {
4446 1 : *aReturn = nsnull;
4447 2 : nsCOMPtr<nsIContent> content;
4448 : nsresult rv = CreateElementNS(aNamespaceURI, aQualifiedName,
4449 1 : getter_AddRefs(content));
4450 1 : NS_ENSURE_SUCCESS(rv, rv);
4451 1 : return CallQueryInterface(content, aReturn);
4452 : }
4453 :
4454 : nsresult
4455 166 : nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
4456 : const nsAString& aQualifiedName,
4457 : nsIContent** aReturn)
4458 : {
4459 332 : nsCOMPtr<nsINodeInfo> nodeInfo;
4460 : nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
4461 : aQualifiedName,
4462 : mNodeInfoManager,
4463 : nsIDOMNode::ELEMENT_NODE,
4464 166 : getter_AddRefs(nodeInfo));
4465 166 : NS_ENSURE_SUCCESS(rv, rv);
4466 :
4467 166 : return NS_NewElement(aReturn, nodeInfo.forget(), NOT_FROM_PARSER);
4468 : }
4469 :
4470 : NS_IMETHODIMP
4471 0 : nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
4472 : {
4473 0 : *aReturn = nsnull;
4474 0 : nsCOMPtr<nsIContent> content;
4475 0 : nsresult rv = CreateTextNode(aData, getter_AddRefs(content));
4476 0 : NS_ENSURE_SUCCESS(rv, rv);
4477 0 : return CallQueryInterface(content, aReturn);
4478 : }
4479 :
4480 : nsresult
4481 34 : nsDocument::CreateTextNode(const nsAString& aData, nsIContent** aReturn)
4482 : {
4483 34 : nsresult rv = NS_NewTextNode(aReturn, mNodeInfoManager);
4484 34 : if (NS_SUCCEEDED(rv)) {
4485 : // Don't notify; this node is still being created.
4486 34 : (*aReturn)->SetText(aData, false);
4487 : }
4488 34 : return rv;
4489 : }
4490 :
4491 : NS_IMETHODIMP
4492 57 : nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn)
4493 : {
4494 57 : return NS_NewDocumentFragment(aReturn, mNodeInfoManager);
4495 : }
4496 :
4497 : NS_IMETHODIMP
4498 1 : nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn)
4499 : {
4500 1 : *aReturn = nsnull;
4501 :
4502 : // Make sure the substring "--" is not present in aData. Otherwise
4503 : // we'll create a document that can't be serialized.
4504 1 : if (FindInReadable(NS_LITERAL_STRING("--"), aData)) {
4505 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
4506 : }
4507 :
4508 2 : nsCOMPtr<nsIContent> comment;
4509 1 : nsresult rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager);
4510 :
4511 1 : if (NS_SUCCEEDED(rv)) {
4512 : // Don't notify; this node is still being created.
4513 1 : comment->SetText(aData, false);
4514 :
4515 1 : rv = CallQueryInterface(comment, aReturn);
4516 : }
4517 :
4518 1 : return rv;
4519 : }
4520 :
4521 : NS_IMETHODIMP
4522 0 : nsDocument::CreateCDATASection(const nsAString& aData,
4523 : nsIDOMCDATASection** aReturn)
4524 : {
4525 0 : NS_ENSURE_ARG_POINTER(aReturn);
4526 0 : *aReturn = nsnull;
4527 :
4528 0 : if (IsHTML()) {
4529 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
4530 : }
4531 :
4532 0 : if (FindInReadable(NS_LITERAL_STRING("]]>"), aData)) {
4533 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
4534 : }
4535 :
4536 0 : nsCOMPtr<nsIContent> content;
4537 0 : nsresult rv = NS_NewXMLCDATASection(getter_AddRefs(content),
4538 0 : mNodeInfoManager);
4539 :
4540 0 : if (NS_SUCCEEDED(rv)) {
4541 : // Don't notify; this node is still being created.
4542 0 : content->SetText(aData, false);
4543 :
4544 0 : rv = CallQueryInterface(content, aReturn);
4545 : }
4546 :
4547 0 : return rv;
4548 : }
4549 :
4550 : NS_IMETHODIMP
4551 1 : nsDocument::CreateProcessingInstruction(const nsAString& aTarget,
4552 : const nsAString& aData,
4553 : nsIDOMProcessingInstruction** aReturn)
4554 : {
4555 1 : *aReturn = nsnull;
4556 :
4557 1 : nsresult rv = nsContentUtils::CheckQName(aTarget, false);
4558 1 : NS_ENSURE_SUCCESS(rv, rv);
4559 :
4560 1 : if (FindInReadable(NS_LITERAL_STRING("?>"), aData)) {
4561 0 : return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
4562 : }
4563 :
4564 2 : nsCOMPtr<nsIContent> content;
4565 1 : rv = NS_NewXMLProcessingInstruction(getter_AddRefs(content),
4566 1 : mNodeInfoManager, aTarget, aData);
4567 1 : if (NS_FAILED(rv)) {
4568 0 : return rv;
4569 : }
4570 :
4571 1 : return CallQueryInterface(content, aReturn);
4572 : }
4573 :
4574 : NS_IMETHODIMP
4575 4 : nsDocument::CreateAttribute(const nsAString& aName,
4576 : nsIDOMAttr** aReturn)
4577 : {
4578 4 : *aReturn = nsnull;
4579 :
4580 4 : WarnOnceAbout(eCreateAttribute);
4581 :
4582 4 : NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED);
4583 :
4584 4 : nsresult rv = nsContentUtils::CheckQName(aName, false);
4585 4 : NS_ENSURE_SUCCESS(rv, rv);
4586 :
4587 8 : nsCOMPtr<nsINodeInfo> nodeInfo;
4588 : rv = mNodeInfoManager->GetNodeInfo(aName, nsnull, kNameSpaceID_None,
4589 : nsIDOMNode::ATTRIBUTE_NODE,
4590 4 : getter_AddRefs(nodeInfo));
4591 4 : NS_ENSURE_SUCCESS(rv, rv);
4592 :
4593 8 : nsAutoString value;
4594 : nsCOMPtr<nsIDOMAttr> attribute =
4595 12 : new nsDOMAttribute(nsnull, nodeInfo.forget(), value, false);
4596 4 : attribute.forget(aReturn);
4597 4 : return NS_OK;
4598 : }
4599 :
4600 : NS_IMETHODIMP
4601 1 : nsDocument::CreateAttributeNS(const nsAString & aNamespaceURI,
4602 : const nsAString & aQualifiedName,
4603 : nsIDOMAttr **aResult)
4604 : {
4605 1 : NS_ENSURE_ARG_POINTER(aResult);
4606 1 : *aResult = nsnull;
4607 :
4608 1 : WarnOnceAbout(eCreateAttributeNS);
4609 :
4610 2 : nsCOMPtr<nsINodeInfo> nodeInfo;
4611 : nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
4612 : aQualifiedName,
4613 : mNodeInfoManager,
4614 : nsIDOMNode::ATTRIBUTE_NODE,
4615 1 : getter_AddRefs(nodeInfo));
4616 1 : NS_ENSURE_SUCCESS(rv, rv);
4617 :
4618 2 : nsAutoString value;
4619 : nsCOMPtr<nsIDOMAttr> attribute =
4620 3 : new nsDOMAttribute(nsnull, nodeInfo.forget(), value, true);
4621 1 : attribute.forget(aResult);
4622 1 : return NS_OK;
4623 : }
4624 :
4625 : NS_IMETHODIMP
4626 0 : nsDocument::GetElementsByTagName(const nsAString& aTagname,
4627 : nsIDOMNodeList** aReturn)
4628 : {
4629 0 : nsRefPtr<nsContentList> list = GetElementsByTagName(aTagname);
4630 0 : NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
4631 :
4632 : // transfer ref to aReturn
4633 0 : *aReturn = list.forget().get();
4634 0 : return NS_OK;
4635 : }
4636 :
4637 : already_AddRefed<nsContentList>
4638 40 : nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
4639 : const nsAString& aLocalName)
4640 : {
4641 40 : PRInt32 nameSpaceId = kNameSpaceID_Wildcard;
4642 :
4643 40 : if (!aNamespaceURI.EqualsLiteral("*")) {
4644 : nsresult rv =
4645 19 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
4646 19 : nameSpaceId);
4647 19 : NS_ENSURE_SUCCESS(rv, nsnull);
4648 : }
4649 :
4650 40 : NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
4651 :
4652 40 : return NS_GetContentList(this, nameSpaceId, aLocalName);
4653 : }
4654 :
4655 : NS_IMETHODIMP
4656 0 : nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
4657 : const nsAString& aLocalName,
4658 : nsIDOMNodeList** aReturn)
4659 : {
4660 : nsRefPtr<nsContentList> list = GetElementsByTagNameNS(aNamespaceURI,
4661 0 : aLocalName);
4662 0 : NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
4663 :
4664 : // transfer ref to aReturn
4665 0 : *aReturn = list.forget().get();
4666 0 : return NS_OK;
4667 : }
4668 :
4669 : NS_IMETHODIMP
4670 0 : nsDocument::GetAsync(bool *aAsync)
4671 : {
4672 0 : NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
4673 :
4674 0 : return NS_ERROR_NOT_IMPLEMENTED;
4675 : }
4676 :
4677 : NS_IMETHODIMP
4678 0 : nsDocument::SetAsync(bool aAsync)
4679 : {
4680 0 : NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!");
4681 :
4682 0 : return NS_ERROR_NOT_IMPLEMENTED;
4683 : }
4684 :
4685 : NS_IMETHODIMP
4686 0 : nsDocument::Load(const nsAString& aUrl, bool *aReturn)
4687 : {
4688 0 : NS_ERROR("nsDocument::Load() should be overriden by subclass!");
4689 :
4690 0 : return NS_ERROR_NOT_IMPLEMENTED;
4691 : }
4692 :
4693 : NS_IMETHODIMP
4694 0 : nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
4695 : {
4696 0 : if (!mDOMStyleSheets) {
4697 0 : mDOMStyleSheets = new nsDOMStyleSheetList(this);
4698 0 : if (!mDOMStyleSheets) {
4699 0 : return NS_ERROR_OUT_OF_MEMORY;
4700 : }
4701 : }
4702 :
4703 0 : *aStyleSheets = mDOMStyleSheets;
4704 0 : NS_ADDREF(*aStyleSheets);
4705 :
4706 0 : return NS_OK;
4707 : }
4708 :
4709 : NS_IMETHODIMP
4710 0 : nsDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
4711 : {
4712 0 : aSheetSet.Truncate();
4713 :
4714 : // Look through our sheets, find the selected set title
4715 0 : PRInt32 count = GetNumberOfStyleSheets();
4716 0 : nsAutoString title;
4717 0 : for (PRInt32 index = 0; index < count; index++) {
4718 0 : nsIStyleSheet* sheet = GetStyleSheetAt(index);
4719 0 : NS_ASSERTION(sheet, "Null sheet in sheet list!");
4720 :
4721 0 : nsCOMPtr<nsIDOMStyleSheet> domSheet = do_QueryInterface(sheet);
4722 0 : NS_ASSERTION(domSheet, "Sheet must QI to nsIDOMStyleSheet");
4723 : bool disabled;
4724 0 : domSheet->GetDisabled(&disabled);
4725 0 : if (disabled) {
4726 : // Disabled sheets don't affect the currently selected set
4727 0 : continue;
4728 : }
4729 :
4730 0 : sheet->GetTitle(title);
4731 :
4732 0 : if (aSheetSet.IsEmpty()) {
4733 0 : aSheetSet = title;
4734 0 : } else if (!title.IsEmpty() && !aSheetSet.Equals(title)) {
4735 : // Sheets from multiple sets enabled; return null string, per spec.
4736 0 : SetDOMStringToNull(aSheetSet);
4737 : break;
4738 : }
4739 : }
4740 :
4741 0 : return NS_OK;
4742 : }
4743 :
4744 : NS_IMETHODIMP
4745 0 : nsDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet)
4746 : {
4747 0 : if (DOMStringIsNull(aSheetSet)) {
4748 0 : return NS_OK;
4749 : }
4750 :
4751 : // Must update mLastStyleSheetSet before doing anything else with stylesheets
4752 : // or CSSLoaders.
4753 0 : mLastStyleSheetSet = aSheetSet;
4754 0 : EnableStyleSheetsForSetInternal(aSheetSet, true);
4755 0 : return NS_OK;
4756 : }
4757 :
4758 : NS_IMETHODIMP
4759 0 : nsDocument::GetLastStyleSheetSet(nsAString& aSheetSet)
4760 : {
4761 0 : aSheetSet = mLastStyleSheetSet;
4762 0 : return NS_OK;
4763 : }
4764 :
4765 : NS_IMETHODIMP
4766 1273 : nsDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet)
4767 : {
4768 1273 : GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet);
4769 1273 : return NS_OK;
4770 : }
4771 :
4772 : NS_IMETHODIMP
4773 0 : nsDocument::GetStyleSheetSets(nsIDOMDOMStringList** aList)
4774 : {
4775 0 : if (!mStyleSheetSetList) {
4776 0 : mStyleSheetSetList = new nsDOMStyleSheetSetList(this);
4777 0 : if (!mStyleSheetSetList) {
4778 0 : return NS_ERROR_OUT_OF_MEMORY;
4779 : }
4780 : }
4781 :
4782 0 : NS_ADDREF(*aList = mStyleSheetSetList);
4783 0 : return NS_OK;
4784 : }
4785 :
4786 : NS_IMETHODIMP
4787 0 : nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet)
4788 : {
4789 : // Per spec, passing in null is a no-op.
4790 0 : if (!DOMStringIsNull(aSheetSet)) {
4791 : // Note: must make sure to not change the CSSLoader's preferred sheet --
4792 : // that value should be equal to either our lastStyleSheetSet (if that's
4793 : // non-null) or to our preferredStyleSheetSet. And this method doesn't
4794 : // change either of those.
4795 0 : EnableStyleSheetsForSetInternal(aSheetSet, false);
4796 : }
4797 :
4798 0 : return NS_OK;
4799 : }
4800 :
4801 : void
4802 0 : nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
4803 : bool aUpdateCSSLoader)
4804 : {
4805 0 : BeginUpdate(UPDATE_STYLE);
4806 0 : PRInt32 count = GetNumberOfStyleSheets();
4807 0 : nsAutoString title;
4808 0 : for (PRInt32 index = 0; index < count; index++) {
4809 0 : nsIStyleSheet* sheet = GetStyleSheetAt(index);
4810 0 : NS_ASSERTION(sheet, "Null sheet in sheet list!");
4811 0 : sheet->GetTitle(title);
4812 0 : if (!title.IsEmpty()) {
4813 0 : sheet->SetEnabled(title.Equals(aSheetSet));
4814 : }
4815 : }
4816 0 : if (aUpdateCSSLoader) {
4817 0 : CSSLoader()->SetPreferredSheet(aSheetSet);
4818 : }
4819 0 : EndUpdate(UPDATE_STYLE);
4820 0 : }
4821 :
4822 : NS_IMETHODIMP
4823 28 : nsDocument::GetCharacterSet(nsAString& aCharacterSet)
4824 : {
4825 28 : CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet);
4826 28 : return NS_OK;
4827 : }
4828 :
4829 : NS_IMETHODIMP
4830 0 : nsDocument::ImportNode(nsIDOMNode* aImportedNode,
4831 : bool aDeep,
4832 : PRUint8 aArgc,
4833 : nsIDOMNode** aResult)
4834 : {
4835 0 : NS_ENSURE_ARG(aImportedNode);
4836 0 : if (aArgc == 0) {
4837 0 : aDeep = true;
4838 : }
4839 :
4840 0 : *aResult = nsnull;
4841 :
4842 0 : nsresult rv = nsContentUtils::CheckSameOrigin(this, aImportedNode);
4843 0 : if (NS_FAILED(rv)) {
4844 0 : return rv;
4845 : }
4846 :
4847 : PRUint16 nodeType;
4848 0 : aImportedNode->GetNodeType(&nodeType);
4849 0 : switch (nodeType) {
4850 : case nsIDOMNode::ATTRIBUTE_NODE:
4851 : case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
4852 : case nsIDOMNode::ELEMENT_NODE:
4853 : case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
4854 : case nsIDOMNode::TEXT_NODE:
4855 : case nsIDOMNode::CDATA_SECTION_NODE:
4856 : case nsIDOMNode::COMMENT_NODE:
4857 : case nsIDOMNode::DOCUMENT_TYPE_NODE:
4858 : {
4859 0 : nsCOMPtr<nsINode> imported = do_QueryInterface(aImportedNode);
4860 0 : NS_ENSURE_TRUE(imported, NS_ERROR_FAILURE);
4861 :
4862 0 : nsCOMPtr<nsIDOMNode> newNode;
4863 0 : nsCOMArray<nsINode> nodesWithProperties;
4864 : rv = nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager,
4865 0 : nodesWithProperties, getter_AddRefs(newNode));
4866 0 : NS_ENSURE_SUCCESS(rv, rv);
4867 :
4868 0 : nsIDocument *ownerDoc = imported->OwnerDoc();
4869 : rv = nsNodeUtils::CallUserDataHandlers(nodesWithProperties, ownerDoc,
4870 : nsIDOMUserDataHandler::NODE_IMPORTED,
4871 0 : true);
4872 0 : NS_ENSURE_SUCCESS(rv, rv);
4873 :
4874 0 : newNode.swap(*aResult);
4875 :
4876 0 : return NS_OK;
4877 : }
4878 : case nsIDOMNode::ENTITY_NODE:
4879 : case nsIDOMNode::ENTITY_REFERENCE_NODE:
4880 : case nsIDOMNode::NOTATION_NODE:
4881 : {
4882 0 : return NS_ERROR_NOT_IMPLEMENTED;
4883 : }
4884 : default:
4885 : {
4886 0 : NS_WARNING("Don't know how to clone this nodetype for importNode.");
4887 :
4888 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
4889 : }
4890 : }
4891 : }
4892 :
4893 : NS_IMETHODIMP
4894 0 : nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURI)
4895 : {
4896 0 : NS_ENSURE_ARG(aContent);
4897 :
4898 0 : nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent);
4899 0 : if (NS_FAILED(rv)) {
4900 0 : return rv;
4901 : }
4902 :
4903 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aContent));
4904 :
4905 0 : nsCOMPtr<nsIURI> uri;
4906 0 : rv = NS_NewURI(getter_AddRefs(uri), aURI);
4907 0 : if (NS_FAILED(rv)) {
4908 0 : return rv;
4909 : }
4910 :
4911 : // Figure out the right principal to use
4912 0 : nsCOMPtr<nsIPrincipal> subject;
4913 0 : nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
4914 0 : if (secMan) {
4915 0 : rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
4916 0 : NS_ENSURE_SUCCESS(rv, rv);
4917 : }
4918 :
4919 0 : if (!subject) {
4920 : // Fall back to our principal. Or should we fall back to the null
4921 : // principal? The latter would just mean no binding loads....
4922 0 : subject = NodePrincipal();
4923 : }
4924 :
4925 0 : return BindingManager()->AddLayeredBinding(content, uri, subject);
4926 : }
4927 :
4928 : NS_IMETHODIMP
4929 0 : nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsAString& aURI)
4930 : {
4931 0 : NS_ENSURE_ARG(aContent);
4932 :
4933 0 : nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent);
4934 0 : if (NS_FAILED(rv)) {
4935 0 : return rv;
4936 : }
4937 :
4938 0 : nsCOMPtr<nsIURI> uri;
4939 0 : rv = NS_NewURI(getter_AddRefs(uri), aURI);
4940 0 : if (NS_FAILED(rv)) {
4941 0 : return rv;
4942 : }
4943 :
4944 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aContent));
4945 0 : return BindingManager()->RemoveLayeredBinding(content, uri);
4946 : }
4947 :
4948 : NS_IMETHODIMP
4949 0 : nsDocument::LoadBindingDocument(const nsAString& aURI)
4950 : {
4951 0 : nsCOMPtr<nsIURI> uri;
4952 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
4953 : mCharacterSet.get(),
4954 0 : GetDocBaseURI());
4955 0 : NS_ENSURE_SUCCESS(rv, rv);
4956 :
4957 : // Figure out the right principal to use
4958 0 : nsCOMPtr<nsIPrincipal> subject;
4959 0 : nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
4960 0 : if (secMan) {
4961 0 : rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
4962 0 : NS_ENSURE_SUCCESS(rv, rv);
4963 : }
4964 :
4965 0 : if (!subject) {
4966 : // Fall back to our principal. Or should we fall back to the null
4967 : // principal? The latter would just mean no binding loads....
4968 0 : subject = NodePrincipal();
4969 : }
4970 :
4971 0 : BindingManager()->LoadBindingDocument(this, uri, subject);
4972 :
4973 0 : return NS_OK;
4974 : }
4975 :
4976 : NS_IMETHODIMP
4977 0 : nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult)
4978 : {
4979 0 : *aResult = nsnull;
4980 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
4981 0 : if (!content)
4982 0 : return NS_ERROR_FAILURE;
4983 :
4984 0 : nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(content->GetBindingParent()));
4985 0 : NS_IF_ADDREF(*aResult = elt);
4986 0 : return NS_OK;
4987 : }
4988 :
4989 : static nsresult
4990 0 : GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName,
4991 : const nsAString& aAttrValue, bool aUniversalMatch,
4992 : nsIDOMElement** aResult)
4993 : {
4994 0 : if (aUniversalMatch ? aContent->HasAttr(kNameSpaceID_None, aAttrName) :
4995 : aContent->AttrValueIs(kNameSpaceID_None, aAttrName,
4996 0 : aAttrValue, eCaseMatters)) {
4997 0 : return CallQueryInterface(aContent, aResult);
4998 : }
4999 :
5000 0 : for (nsIContent* child = aContent->GetFirstChild();
5001 : child;
5002 0 : child = child->GetNextSibling()) {
5003 :
5004 : GetElementByAttribute(child, aAttrName, aAttrValue, aUniversalMatch,
5005 0 : aResult);
5006 :
5007 0 : if (*aResult)
5008 0 : return NS_OK;
5009 : }
5010 :
5011 0 : return NS_OK;
5012 : }
5013 :
5014 : NS_IMETHODIMP
5015 0 : nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement,
5016 : const nsAString& aAttrName,
5017 : const nsAString& aAttrValue,
5018 : nsIDOMElement** aResult)
5019 : {
5020 0 : *aResult = nsnull;
5021 :
5022 0 : nsCOMPtr<nsIDOMNodeList> nodeList;
5023 0 : GetAnonymousNodes(aElement, getter_AddRefs(nodeList));
5024 :
5025 0 : if (!nodeList)
5026 0 : return NS_OK;
5027 :
5028 0 : nsCOMPtr<nsIAtom> attribute = do_GetAtom(aAttrName);
5029 :
5030 : PRUint32 length;
5031 0 : nodeList->GetLength(&length);
5032 :
5033 0 : bool universalMatch = aAttrValue.EqualsLiteral("*");
5034 :
5035 0 : for (PRUint32 i = 0; i < length; ++i) {
5036 0 : nsCOMPtr<nsIDOMNode> current;
5037 0 : nodeList->Item(i, getter_AddRefs(current));
5038 :
5039 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(current));
5040 :
5041 : GetElementByAttribute(content, attribute, aAttrValue, universalMatch,
5042 0 : aResult);
5043 0 : if (*aResult)
5044 0 : return NS_OK;
5045 : }
5046 :
5047 0 : return NS_OK;
5048 : }
5049 :
5050 :
5051 : NS_IMETHODIMP
5052 0 : nsDocument::GetAnonymousNodes(nsIDOMElement* aElement,
5053 : nsIDOMNodeList** aResult)
5054 : {
5055 0 : *aResult = nsnull;
5056 :
5057 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
5058 0 : return BindingManager()->GetAnonymousNodesFor(content, aResult);
5059 : }
5060 :
5061 : NS_IMETHODIMP
5062 31 : nsDocument::CreateRange(nsIDOMRange** aReturn)
5063 : {
5064 62 : nsRefPtr<nsRange> range = new nsRange();
5065 31 : nsresult rv = range->Set(this, 0, this, 0);
5066 31 : NS_ENSURE_SUCCESS(rv, rv);
5067 :
5068 31 : range.forget(aReturn);
5069 31 : return NS_OK;
5070 : }
5071 :
5072 : NS_IMETHODIMP
5073 0 : nsDocument::CreateNodeIterator(nsIDOMNode *aRoot,
5074 : PRUint32 aWhatToShow,
5075 : nsIDOMNodeFilter *aFilter,
5076 : PRUint8 aOptionalArgc,
5077 : nsIDOMNodeIterator **_retval)
5078 : {
5079 0 : *_retval = nsnull;
5080 :
5081 0 : if (!aOptionalArgc) {
5082 0 : aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
5083 : }
5084 :
5085 0 : if (!aRoot)
5086 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
5087 :
5088 0 : nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
5089 0 : NS_ENSURE_SUCCESS(rv, rv);
5090 :
5091 0 : NS_ENSURE_ARG_POINTER(_retval);
5092 :
5093 0 : nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
5094 0 : NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
5095 :
5096 : nsNodeIterator *iterator = new nsNodeIterator(root,
5097 : aWhatToShow,
5098 0 : aFilter);
5099 0 : NS_ENSURE_TRUE(iterator, NS_ERROR_OUT_OF_MEMORY);
5100 :
5101 0 : NS_ADDREF(*_retval = iterator);
5102 :
5103 0 : return NS_OK;
5104 : }
5105 :
5106 : NS_IMETHODIMP
5107 65 : nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
5108 : PRUint32 aWhatToShow,
5109 : nsIDOMNodeFilter *aFilter,
5110 : PRUint8 aOptionalArgc,
5111 : nsIDOMTreeWalker **_retval)
5112 : {
5113 65 : *_retval = nsnull;
5114 :
5115 65 : if (!aOptionalArgc) {
5116 0 : aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
5117 : }
5118 :
5119 65 : if (!aRoot)
5120 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
5121 :
5122 65 : nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
5123 65 : NS_ENSURE_SUCCESS(rv, rv);
5124 :
5125 65 : NS_ENSURE_ARG_POINTER(_retval);
5126 :
5127 130 : nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
5128 65 : NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
5129 :
5130 : nsTreeWalker* walker = new nsTreeWalker(root,
5131 : aWhatToShow,
5132 130 : aFilter);
5133 65 : NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY);
5134 :
5135 65 : NS_ADDREF(*_retval = walker);
5136 :
5137 65 : return NS_OK;
5138 : }
5139 :
5140 :
5141 : NS_IMETHODIMP
5142 0 : nsDocument::GetDefaultView(nsIDOMWindow** aDefaultView)
5143 : {
5144 0 : *aDefaultView = nsnull;
5145 0 : nsCOMPtr<nsPIDOMWindow> win = GetWindow();
5146 0 : win.forget(aDefaultView);
5147 0 : return NS_OK;
5148 : }
5149 :
5150 : NS_IMETHODIMP
5151 0 : nsDocument::GetLocation(nsIDOMLocation **_retval)
5152 : {
5153 0 : NS_ENSURE_ARG_POINTER(_retval);
5154 0 : *_retval = nsnull;
5155 :
5156 0 : nsCOMPtr<nsIDOMWindow> w = do_QueryInterface(mScriptGlobalObject);
5157 :
5158 0 : if (!w) {
5159 0 : return NS_OK;
5160 : }
5161 :
5162 0 : return w->GetLocation(_retval);
5163 : }
5164 :
5165 : Element*
5166 0 : nsIDocument::GetHtmlElement()
5167 : {
5168 0 : Element* rootElement = GetRootElement();
5169 0 : if (rootElement && rootElement->IsHTML(nsGkAtoms::html))
5170 0 : return rootElement;
5171 0 : return nsnull;
5172 : }
5173 :
5174 : Element*
5175 0 : nsIDocument::GetHtmlChildElement(nsIAtom* aTag)
5176 : {
5177 0 : Element* html = GetHtmlElement();
5178 0 : if (!html)
5179 0 : return nsnull;
5180 :
5181 : // Look for the element with aTag inside html. This needs to run
5182 : // forwards to find the first such element.
5183 0 : for (nsIContent* child = html->GetFirstChild();
5184 : child;
5185 0 : child = child->GetNextSibling()) {
5186 0 : if (child->IsHTML(aTag))
5187 0 : return child->AsElement();
5188 : }
5189 0 : return nsnull;
5190 : }
5191 :
5192 : nsIContent*
5193 1036 : nsDocument::GetTitleContent(PRUint32 aNamespace)
5194 : {
5195 : // mMayHaveTitleElement will have been set to true if any HTML or SVG
5196 : // <title> element has been bound to this document. So if it's false,
5197 : // we know there is nothing to do here. This avoids us having to search
5198 : // the whole DOM if someone calls document.title on a large document
5199 : // without a title.
5200 1036 : if (!mMayHaveTitleElement)
5201 1036 : return nsnull;
5202 :
5203 : nsRefPtr<nsContentList> list =
5204 0 : NS_GetContentList(this, aNamespace, NS_LITERAL_STRING("title"));
5205 :
5206 0 : return list->Item(0, false);
5207 : }
5208 :
5209 : void
5210 1036 : nsDocument::GetTitleFromElement(PRUint32 aNamespace, nsAString& aTitle)
5211 : {
5212 1036 : nsIContent* title = GetTitleContent(aNamespace);
5213 1036 : if (!title)
5214 1036 : return;
5215 0 : nsContentUtils::GetNodeTextContent(title, false, aTitle);
5216 : }
5217 :
5218 : NS_IMETHODIMP
5219 1038 : nsDocument::GetTitle(nsAString& aTitle)
5220 : {
5221 1038 : aTitle.Truncate();
5222 :
5223 1038 : nsIContent *rootElement = GetRootElement();
5224 1038 : if (!rootElement)
5225 0 : return NS_OK;
5226 :
5227 2076 : nsAutoString tmp;
5228 :
5229 1038 : switch (rootElement->GetNameSpaceID()) {
5230 : #ifdef MOZ_XUL
5231 : case kNameSpaceID_XUL:
5232 2 : rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp);
5233 2 : break;
5234 : #endif
5235 : case kNameSpaceID_SVG:
5236 0 : if (rootElement->Tag() == nsGkAtoms::svg) {
5237 0 : GetTitleFromElement(kNameSpaceID_SVG, tmp);
5238 0 : break;
5239 : } // else fall through
5240 : default:
5241 1036 : GetTitleFromElement(kNameSpaceID_XHTML, tmp);
5242 1036 : break;
5243 : }
5244 :
5245 1038 : tmp.CompressWhitespace();
5246 1038 : aTitle = tmp;
5247 1038 : return NS_OK;
5248 : }
5249 :
5250 : NS_IMETHODIMP
5251 0 : nsDocument::SetTitle(const nsAString& aTitle)
5252 : {
5253 0 : Element *rootElement = GetRootElement();
5254 0 : if (!rootElement)
5255 0 : return NS_OK;
5256 :
5257 0 : switch (rootElement->GetNameSpaceID()) {
5258 : case kNameSpaceID_SVG:
5259 0 : return NS_OK; // SVG doesn't support setting a title
5260 : #ifdef MOZ_XUL
5261 : case kNameSpaceID_XUL:
5262 : return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title,
5263 0 : aTitle, true);
5264 : #endif
5265 : }
5266 :
5267 : // Batch updates so that mutation events don't change "the title
5268 : // element" under us
5269 0 : mozAutoDocUpdate updateBatch(this, UPDATE_CONTENT_MODEL, true);
5270 :
5271 0 : nsIContent* title = GetTitleContent(kNameSpaceID_XHTML);
5272 0 : if (!title) {
5273 0 : Element *head = GetHeadElement();
5274 0 : if (!head)
5275 0 : return NS_OK;
5276 :
5277 : {
5278 0 : nsCOMPtr<nsINodeInfo> titleInfo;
5279 : titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nsnull,
5280 : kNameSpaceID_XHTML,
5281 0 : nsIDOMNode::ELEMENT_NODE);
5282 0 : if (!titleInfo)
5283 0 : return NS_OK;
5284 0 : title = NS_NewHTMLTitleElement(titleInfo.forget());
5285 0 : if (!title)
5286 0 : return NS_OK;
5287 : }
5288 :
5289 0 : head->AppendChildTo(title, true);
5290 : }
5291 :
5292 0 : return nsContentUtils::SetNodeTextContent(title, aTitle, false);
5293 : }
5294 :
5295 : void
5296 1038 : nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement)
5297 : {
5298 1038 : NS_ASSERTION(!mInUnlinkOrDeletion || !aBoundTitleElement,
5299 : "Setting a title while unlinking or destroying the element?");
5300 1038 : if (mInUnlinkOrDeletion) {
5301 0 : return;
5302 : }
5303 :
5304 1038 : if (aBoundTitleElement) {
5305 0 : mMayHaveTitleElement = true;
5306 : }
5307 1038 : if (mPendingTitleChangeEvent.IsPending())
5308 0 : return;
5309 :
5310 : nsRefPtr<nsRunnableMethod<nsDocument, void, false> > event =
5311 : NS_NewNonOwningRunnableMethod(this,
5312 2076 : &nsDocument::DoNotifyPossibleTitleChange);
5313 1038 : nsresult rv = NS_DispatchToCurrentThread(event);
5314 1038 : if (NS_SUCCEEDED(rv)) {
5315 1038 : mPendingTitleChangeEvent = event;
5316 : }
5317 : }
5318 :
5319 : void
5320 1038 : nsDocument::DoNotifyPossibleTitleChange()
5321 : {
5322 1038 : mPendingTitleChangeEvent.Forget();
5323 1038 : mHaveFiredTitleChange = true;
5324 :
5325 2076 : nsAutoString title;
5326 1038 : GetTitle(title);
5327 :
5328 2076 : nsCOMPtr<nsIPresShell> shell = GetShell();
5329 1038 : if (shell) {
5330 0 : nsCOMPtr<nsISupports> container = shell->GetPresContext()->GetContainer();
5331 0 : if (container) {
5332 0 : nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container);
5333 0 : if (docShellWin) {
5334 0 : docShellWin->SetTitle(title.get());
5335 : }
5336 : }
5337 : }
5338 :
5339 : // Fire a DOM event for the title change.
5340 : nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
5341 1038 : NS_LITERAL_STRING("DOMTitleChanged"),
5342 1038 : true, true);
5343 1038 : }
5344 :
5345 : NS_IMETHODIMP
5346 0 : nsDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult)
5347 : {
5348 0 : nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
5349 0 : NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
5350 :
5351 0 : nsIDocument* doc = content->OwnerDoc();
5352 0 : NS_ENSURE_TRUE(doc == this, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
5353 :
5354 0 : if (!mHasWarnedAboutBoxObjects && !content->IsXUL()) {
5355 0 : mHasWarnedAboutBoxObjects = true;
5356 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
5357 : "BoxObjects", this,
5358 : nsContentUtils::eDOM_PROPERTIES,
5359 0 : "UseOfGetBoxObjectForWarning");
5360 : }
5361 :
5362 0 : *aResult = nsnull;
5363 :
5364 0 : if (!mBoxObjectTable) {
5365 0 : mBoxObjectTable = new nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject>;
5366 0 : if (mBoxObjectTable && !mBoxObjectTable->Init(12)) {
5367 0 : mBoxObjectTable = nsnull;
5368 : }
5369 : } else {
5370 : // Want to use Get(content, aResult); but it's the wrong type
5371 0 : *aResult = mBoxObjectTable->GetWeak(content);
5372 0 : if (*aResult) {
5373 0 : NS_ADDREF(*aResult);
5374 0 : return NS_OK;
5375 : }
5376 : }
5377 :
5378 : PRInt32 namespaceID;
5379 0 : nsCOMPtr<nsIAtom> tag = BindingManager()->ResolveTag(content, &namespaceID);
5380 :
5381 0 : nsCAutoString contractID("@mozilla.org/layout/xul-boxobject");
5382 0 : if (namespaceID == kNameSpaceID_XUL) {
5383 0 : if (tag == nsGkAtoms::browser ||
5384 0 : tag == nsGkAtoms::editor ||
5385 0 : tag == nsGkAtoms::iframe)
5386 0 : contractID += "-container";
5387 0 : else if (tag == nsGkAtoms::menu)
5388 0 : contractID += "-menu";
5389 0 : else if (tag == nsGkAtoms::popup ||
5390 0 : tag == nsGkAtoms::menupopup ||
5391 0 : tag == nsGkAtoms::panel ||
5392 0 : tag == nsGkAtoms::tooltip)
5393 0 : contractID += "-popup";
5394 0 : else if (tag == nsGkAtoms::tree)
5395 0 : contractID += "-tree";
5396 0 : else if (tag == nsGkAtoms::listbox)
5397 0 : contractID += "-listbox";
5398 0 : else if (tag == nsGkAtoms::scrollbox)
5399 0 : contractID += "-scrollbox";
5400 : }
5401 0 : contractID += ";1";
5402 :
5403 0 : nsCOMPtr<nsPIBoxObject> boxObject(do_CreateInstance(contractID.get()));
5404 0 : if (!boxObject)
5405 0 : return NS_ERROR_FAILURE;
5406 :
5407 0 : boxObject->Init(content);
5408 :
5409 0 : if (mBoxObjectTable) {
5410 0 : mBoxObjectTable->Put(content, boxObject.get());
5411 : }
5412 :
5413 0 : *aResult = boxObject;
5414 0 : NS_ADDREF(*aResult);
5415 :
5416 0 : return NS_OK;
5417 : }
5418 :
5419 : void
5420 75809 : nsDocument::ClearBoxObjectFor(nsIContent* aContent)
5421 : {
5422 75809 : if (mBoxObjectTable) {
5423 0 : nsPIBoxObject *boxObject = mBoxObjectTable->GetWeak(aContent);
5424 0 : if (boxObject) {
5425 0 : boxObject->Clear();
5426 0 : mBoxObjectTable->Remove(aContent);
5427 : }
5428 : }
5429 75809 : }
5430 :
5431 : nsresult
5432 0 : nsDocument::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
5433 : {
5434 0 : return BindingManager()->GetXBLChildNodesFor(aContent, aResult);
5435 : }
5436 :
5437 : nsresult
5438 0 : nsDocument::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
5439 : {
5440 0 : return BindingManager()->GetContentListFor(aContent, aResult);
5441 : }
5442 :
5443 : void
5444 0 : nsDocument::FlushSkinBindings()
5445 : {
5446 0 : BindingManager()->FlushSkinBindings();
5447 0 : }
5448 :
5449 : nsresult
5450 0 : nsDocument::InitializeFrameLoader(nsFrameLoader* aLoader)
5451 : {
5452 0 : mInitializableFrameLoaders.RemoveElement(aLoader);
5453 : // Don't even try to initialize.
5454 0 : if (mInDestructor) {
5455 : NS_WARNING("Trying to initialize a frame loader while"
5456 0 : "document is being deleted");
5457 0 : return NS_ERROR_FAILURE;
5458 : }
5459 :
5460 0 : mInitializableFrameLoaders.AppendElement(aLoader);
5461 0 : if (!mFrameLoaderRunner) {
5462 : mFrameLoaderRunner =
5463 0 : NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders);
5464 0 : NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
5465 0 : nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
5466 : }
5467 0 : return NS_OK;
5468 : }
5469 :
5470 : nsresult
5471 0 : nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader)
5472 : {
5473 0 : mInitializableFrameLoaders.RemoveElement(aLoader);
5474 0 : if (mInDestructor) {
5475 0 : return NS_ERROR_FAILURE;
5476 : }
5477 :
5478 0 : mFinalizableFrameLoaders.AppendElement(aLoader);
5479 0 : if (!mFrameLoaderRunner) {
5480 : mFrameLoaderRunner =
5481 0 : NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders);
5482 0 : NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
5483 0 : nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
5484 : }
5485 0 : return NS_OK;
5486 : }
5487 :
5488 : void
5489 6215 : nsDocument::MaybeInitializeFinalizeFrameLoaders()
5490 : {
5491 6215 : if (mDelayFrameLoaderInitialization || mUpdateNestLevel != 0) {
5492 : // This method will be recalled when mUpdateNestLevel drops to 0,
5493 : // or when !mDelayFrameLoaderInitialization.
5494 1325 : mFrameLoaderRunner = nsnull;
5495 1325 : return;
5496 : }
5497 :
5498 : // We're not in an update, but it is not safe to run scripts, so
5499 : // postpone frameloader initialization and finalization.
5500 4890 : if (!nsContentUtils::IsSafeToRunScript()) {
5501 204 : if (!mInDestructor && !mFrameLoaderRunner &&
5502 68 : (mInitializableFrameLoaders.Length() ||
5503 68 : mFinalizableFrameLoaders.Length())) {
5504 : mFrameLoaderRunner =
5505 0 : NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders);
5506 0 : nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
5507 : }
5508 68 : return;
5509 : }
5510 4822 : mFrameLoaderRunner = nsnull;
5511 :
5512 : // Don't use a temporary array for mInitializableFrameLoaders, because
5513 : // loading a frame may cause some other frameloader to be removed from the
5514 : // array. But be careful to keep the loader alive when starting the load!
5515 9644 : while (mInitializableFrameLoaders.Length()) {
5516 0 : nsRefPtr<nsFrameLoader> loader = mInitializableFrameLoaders[0];
5517 0 : mInitializableFrameLoaders.RemoveElementAt(0);
5518 0 : NS_ASSERTION(loader, "null frameloader in the array?");
5519 0 : loader->ReallyStartLoading();
5520 : }
5521 :
5522 4822 : PRUint32 length = mFinalizableFrameLoaders.Length();
5523 4822 : if (length > 0) {
5524 0 : nsTArray<nsRefPtr<nsFrameLoader> > loaders;
5525 0 : mFinalizableFrameLoaders.SwapElements(loaders);
5526 0 : for (PRUint32 i = 0; i < length; ++i) {
5527 0 : loaders[i]->Finalize();
5528 : }
5529 : }
5530 : }
5531 :
5532 : void
5533 0 : nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell* aShell)
5534 : {
5535 0 : PRUint32 length = mInitializableFrameLoaders.Length();
5536 0 : for (PRUint32 i = 0; i < length; ++i) {
5537 0 : if (mInitializableFrameLoaders[i]->GetExistingDocShell() == aShell) {
5538 0 : mInitializableFrameLoaders.RemoveElementAt(i);
5539 0 : return;
5540 : }
5541 : }
5542 : }
5543 :
5544 : bool
5545 0 : nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell)
5546 : {
5547 0 : if (aShell) {
5548 0 : PRUint32 length = mFinalizableFrameLoaders.Length();
5549 0 : for (PRUint32 i = 0; i < length; ++i) {
5550 0 : if (mFinalizableFrameLoaders[i]->GetExistingDocShell() == aShell) {
5551 0 : return true;
5552 : }
5553 : }
5554 : }
5555 0 : return false;
5556 : }
5557 :
5558 : nsIDocument*
5559 0 : nsDocument::RequestExternalResource(nsIURI* aURI,
5560 : nsINode* aRequestingNode,
5561 : ExternalResourceLoad** aPendingLoad)
5562 : {
5563 0 : NS_PRECONDITION(aURI, "Must have a URI");
5564 0 : NS_PRECONDITION(aRequestingNode, "Must have a node");
5565 0 : if (mDisplayDocument) {
5566 0 : return mDisplayDocument->RequestExternalResource(aURI,
5567 : aRequestingNode,
5568 0 : aPendingLoad);
5569 : }
5570 :
5571 : return mExternalResourceMap.RequestResource(aURI, aRequestingNode,
5572 0 : this, aPendingLoad);
5573 : }
5574 :
5575 : void
5576 0 : nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
5577 : {
5578 0 : mExternalResourceMap.EnumerateResources(aCallback, aData);
5579 0 : }
5580 :
5581 : nsSMILAnimationController*
5582 0 : nsDocument::GetAnimationController()
5583 : {
5584 : // We create the animation controller lazily because most documents won't want
5585 : // one and only SVG documents and the like will call this
5586 0 : if (mAnimationController)
5587 0 : return mAnimationController;
5588 : // Refuse to create an Animation Controller if SMIL is disabled, and also
5589 : // for data documents.
5590 0 : if (!NS_SMILEnabled() || mLoadedAsData || mLoadedAsInteractiveData)
5591 0 : return nsnull;
5592 :
5593 0 : mAnimationController = new nsSMILAnimationController(this);
5594 :
5595 : // If there's a presContext then check the animation mode and pause if
5596 : // necessary.
5597 0 : nsIPresShell *shell = GetShell();
5598 0 : if (mAnimationController && shell) {
5599 0 : nsPresContext *context = shell->GetPresContext();
5600 0 : if (context &&
5601 0 : context->ImageAnimationMode() == imgIContainer::kDontAnimMode) {
5602 0 : mAnimationController->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
5603 : }
5604 : }
5605 :
5606 : // If we're hidden (or being hidden), notify the newly-created animation
5607 : // controller. (Skip this check for SVG-as-an-image documents, though,
5608 : // because they don't get OnPageShow / OnPageHide calls).
5609 0 : if (!mIsShowing && !mIsBeingUsedAsImage) {
5610 0 : mAnimationController->OnPageHide();
5611 : }
5612 :
5613 0 : return mAnimationController;
5614 : }
5615 :
5616 : struct DirTable {
5617 : const char* mName;
5618 : PRUint8 mValue;
5619 : };
5620 :
5621 : static const DirTable dirAttributes[] = {
5622 : {"ltr", IBMBIDI_TEXTDIRECTION_LTR},
5623 : {"rtl", IBMBIDI_TEXTDIRECTION_RTL},
5624 : {0}
5625 : };
5626 :
5627 : /**
5628 : * Retrieve the "direction" property of the document.
5629 : *
5630 : * @lina 01/09/2001
5631 : */
5632 : NS_IMETHODIMP
5633 0 : nsDocument::GetDir(nsAString& aDirection)
5634 : {
5635 0 : PRUint32 options = GetBidiOptions();
5636 0 : for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
5637 0 : if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) {
5638 0 : CopyASCIItoUTF16(elt->mName, aDirection);
5639 0 : break;
5640 : }
5641 : }
5642 :
5643 0 : return NS_OK;
5644 : }
5645 :
5646 : /**
5647 : * Set the "direction" property of the document.
5648 : *
5649 : * @lina 01/09/2001
5650 : */
5651 : NS_IMETHODIMP
5652 0 : nsDocument::SetDir(const nsAString& aDirection)
5653 : {
5654 0 : PRUint32 options = GetBidiOptions();
5655 :
5656 0 : for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
5657 0 : if (aDirection == NS_ConvertASCIItoUTF16(elt->mName)) {
5658 0 : if (GET_BIDI_OPTION_DIRECTION(options) != elt->mValue) {
5659 0 : SET_BIDI_OPTION_DIRECTION(options, elt->mValue);
5660 0 : nsIPresShell *shell = GetShell();
5661 0 : if (shell) {
5662 0 : nsPresContext *context = shell->GetPresContext();
5663 0 : NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
5664 0 : context->SetBidi(options, true);
5665 : } else {
5666 : // No presentation; just set it on ourselves
5667 0 : SetBidiOptions(options);
5668 : }
5669 : }
5670 :
5671 0 : break;
5672 : }
5673 : }
5674 :
5675 0 : return NS_OK;
5676 : }
5677 :
5678 :
5679 : //
5680 : // nsIDOMNode methods
5681 : //
5682 : NS_IMETHODIMP
5683 0 : nsDocument::GetNodeName(nsAString& aNodeName)
5684 : {
5685 0 : aNodeName.AssignLiteral("#document");
5686 :
5687 0 : return NS_OK;
5688 : }
5689 :
5690 : NS_IMETHODIMP
5691 0 : nsDocument::GetNodeValue(nsAString& aNodeValue)
5692 : {
5693 0 : SetDOMStringToNull(aNodeValue);
5694 :
5695 0 : return NS_OK;
5696 : }
5697 :
5698 : NS_IMETHODIMP
5699 0 : nsDocument::SetNodeValue(const nsAString& aNodeValue)
5700 : {
5701 : // The DOM spec says that when nodeValue is defined to be null "setting it
5702 : // has no effect", so we don't throw an exception.
5703 0 : return NS_OK;
5704 : }
5705 :
5706 : NS_IMETHODIMP
5707 54 : nsDocument::GetNodeType(PRUint16* aNodeType)
5708 : {
5709 54 : *aNodeType = nsIDOMNode::DOCUMENT_NODE;
5710 :
5711 54 : return NS_OK;
5712 : }
5713 :
5714 : NS_IMETHODIMP
5715 0 : nsDocument::GetParentNode(nsIDOMNode** aParentNode)
5716 : {
5717 0 : *aParentNode = nsnull;
5718 :
5719 0 : return NS_OK;
5720 : }
5721 :
5722 : NS_IMETHODIMP
5723 0 : nsDocument::GetParentElement(nsIDOMElement** aParentElement)
5724 : {
5725 0 : *aParentElement = nsnull;
5726 0 : return NS_OK;
5727 : }
5728 :
5729 : NS_IMETHODIMP
5730 109 : nsDocument::GetChildNodes(nsIDOMNodeList** aChildNodes)
5731 : {
5732 109 : return nsINode::GetChildNodes(aChildNodes);
5733 : }
5734 :
5735 : NS_IMETHODIMP
5736 0 : nsDocument::HasChildNodes(bool* aHasChildNodes)
5737 : {
5738 0 : NS_ENSURE_ARG(aHasChildNodes);
5739 :
5740 0 : *aHasChildNodes = (mChildren.ChildCount() != 0);
5741 :
5742 0 : return NS_OK;
5743 : }
5744 :
5745 : NS_IMETHODIMP
5746 0 : nsDocument::HasAttributes(bool* aHasAttributes)
5747 : {
5748 0 : NS_ENSURE_ARG(aHasAttributes);
5749 :
5750 0 : *aHasAttributes = false;
5751 :
5752 0 : return NS_OK;
5753 : }
5754 :
5755 : NS_IMETHODIMP
5756 2 : nsDocument::GetFirstChild(nsIDOMNode** aFirstChild)
5757 : {
5758 2 : return nsINode::GetFirstChild(aFirstChild);
5759 : }
5760 :
5761 : NS_IMETHODIMP
5762 72 : nsDocument::GetLastChild(nsIDOMNode** aLastChild)
5763 : {
5764 72 : return nsINode::GetLastChild(aLastChild);
5765 : }
5766 :
5767 : NS_IMETHODIMP
5768 0 : nsDocument::GetPreviousSibling(nsIDOMNode** aPreviousSibling)
5769 : {
5770 0 : *aPreviousSibling = nsnull;
5771 :
5772 0 : return NS_OK;
5773 : }
5774 :
5775 : NS_IMETHODIMP
5776 0 : nsDocument::GetNextSibling(nsIDOMNode** aNextSibling)
5777 : {
5778 0 : *aNextSibling = nsnull;
5779 :
5780 0 : return NS_OK;
5781 : }
5782 :
5783 : NS_IMETHODIMP
5784 0 : nsDocument::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
5785 : {
5786 0 : *aAttributes = nsnull;
5787 :
5788 0 : return NS_OK;
5789 : }
5790 :
5791 : NS_IMETHODIMP
5792 0 : nsDocument::GetNamespaceURI(nsAString& aNamespaceURI)
5793 : {
5794 0 : SetDOMStringToNull(aNamespaceURI);
5795 :
5796 0 : return NS_OK;
5797 : }
5798 :
5799 : NS_IMETHODIMP
5800 0 : nsDocument::GetPrefix(nsAString& aPrefix)
5801 : {
5802 0 : SetDOMStringToNull(aPrefix);
5803 :
5804 0 : return NS_OK;
5805 : }
5806 :
5807 : NS_IMETHODIMP
5808 0 : nsDocument::GetLocalName(nsAString& aLocalName)
5809 : {
5810 0 : SetDOMStringToNull(aLocalName);
5811 :
5812 0 : return NS_OK;
5813 : }
5814 :
5815 : NS_IMETHODIMP
5816 1 : nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
5817 : nsIDOMNode** aReturn)
5818 : {
5819 1 : return ReplaceOrInsertBefore(false, aNewChild, aRefChild, aReturn);
5820 : }
5821 :
5822 : NS_IMETHODIMP
5823 0 : nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
5824 : nsIDOMNode** aReturn)
5825 : {
5826 0 : return ReplaceOrInsertBefore(true, aNewChild, aOldChild, aReturn);
5827 : }
5828 :
5829 : NS_IMETHODIMP
5830 10 : nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
5831 : {
5832 10 : return nsINode::RemoveChild(aOldChild, aReturn);
5833 : }
5834 :
5835 : NS_IMETHODIMP
5836 1 : nsDocument::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
5837 : {
5838 1 : return nsDocument::InsertBefore(aNewChild, nsnull, aReturn);
5839 : }
5840 :
5841 : NS_IMETHODIMP
5842 0 : nsDocument::CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode** aReturn)
5843 : {
5844 0 : if (!aOptionalArgc) {
5845 0 : aDeep = true;
5846 : }
5847 :
5848 0 : return nsNodeUtils::CloneNodeImpl(this, aDeep, !mCreatingStaticClone, aReturn);
5849 : }
5850 :
5851 : NS_IMETHODIMP
5852 0 : nsDocument::Normalize()
5853 : {
5854 0 : return nsIDocument::Normalize();
5855 : }
5856 :
5857 : NS_IMETHODIMP
5858 0 : nsDocument::IsSupported(const nsAString& aFeature, const nsAString& aVersion,
5859 : bool* aReturn)
5860 : {
5861 : return nsGenericElement::InternalIsSupported(static_cast<nsIDOMDocument*>(this),
5862 0 : aFeature, aVersion, aReturn);
5863 : }
5864 :
5865 : NS_IMETHODIMP
5866 0 : nsDocument::GetDOMBaseURI(nsAString &aURI)
5867 : {
5868 0 : return nsIDocument::GetDOMBaseURI(aURI);
5869 : }
5870 :
5871 : NS_IMETHODIMP
5872 0 : nsDocument::GetTextContent(nsAString &aTextContent)
5873 : {
5874 0 : SetDOMStringToNull(aTextContent);
5875 0 : return NS_OK;
5876 : }
5877 :
5878 : NS_IMETHODIMP
5879 0 : nsDocument::IsEqualNode(nsIDOMNode* aOther, bool* aResult)
5880 : {
5881 0 : return nsINode::IsEqualNode(aOther, aResult);
5882 : }
5883 :
5884 : NS_IMETHODIMP
5885 0 : nsDocument::CompareDocumentPosition(nsIDOMNode *other,
5886 : PRUint16 *aResult)
5887 : {
5888 0 : return nsINode::CompareDocumentPosition(other, aResult);
5889 : }
5890 :
5891 : NS_IMETHODIMP
5892 0 : nsDocument::SetTextContent(const nsAString & aTextContent)
5893 : {
5894 0 : return nsINode::SetTextContent(aTextContent);
5895 : }
5896 :
5897 : NS_IMETHODIMP
5898 0 : nsDocument::LookupPrefix(const nsAString & namespaceURI, nsAString & aResult)
5899 : {
5900 0 : return nsINode::LookupPrefix(namespaceURI, aResult);
5901 : }
5902 :
5903 : NS_IMETHODIMP
5904 0 : nsDocument::IsDefaultNamespace(const nsAString & namespaceURI,
5905 : bool *aResult)
5906 : {
5907 0 : return nsINode::IsDefaultNamespace(namespaceURI, aResult);
5908 : }
5909 :
5910 : NS_IMETHODIMP
5911 0 : nsDocument::LookupNamespaceURI(const nsAString & prefix,
5912 : nsAString & aResult)
5913 : {
5914 0 : return nsINode::LookupNamespaceURI(prefix, aResult);
5915 : }
5916 :
5917 : NS_IMETHODIMP
5918 0 : nsDocument::SetUserData(const nsAString & key,
5919 : nsIVariant *data, nsIDOMUserDataHandler *handler,
5920 : nsIVariant **aResult)
5921 : {
5922 0 : return nsINode::SetUserData(key, data, handler, aResult);
5923 : }
5924 :
5925 : NS_IMETHODIMP
5926 0 : nsDocument::GetUserData(const nsAString & key,
5927 : nsIVariant **aResult)
5928 : {
5929 0 : return nsINode::GetUserData(key, aResult);
5930 : }
5931 :
5932 : NS_IMETHODIMP
5933 0 : nsDocument::Contains(nsIDOMNode* aOther, bool* aReturn)
5934 : {
5935 0 : return nsINode::Contains(aOther, aReturn);
5936 : }
5937 :
5938 : NS_IMETHODIMP
5939 0 : nsDocument::GetInputEncoding(nsAString& aInputEncoding)
5940 : {
5941 0 : WarnOnceAbout(eInputEncoding);
5942 0 : if (mHaveInputEncoding) {
5943 0 : return GetCharacterSet(aInputEncoding);
5944 : }
5945 :
5946 0 : SetDOMStringToNull(aInputEncoding);
5947 0 : return NS_OK;
5948 : }
5949 :
5950 : NS_IMETHODIMP
5951 0 : nsDocument::GetMozSyntheticDocument(bool *aSyntheticDocument)
5952 : {
5953 0 : *aSyntheticDocument = mIsSyntheticDocument;
5954 0 : return NS_OK;
5955 : }
5956 :
5957 : NS_IMETHODIMP
5958 0 : nsDocument::GetDocumentURI(nsAString& aDocumentURI)
5959 : {
5960 0 : if (mDocumentURI) {
5961 0 : nsCAutoString uri;
5962 0 : mDocumentURI->GetSpec(uri);
5963 0 : CopyUTF8toUTF16(uri, aDocumentURI);
5964 : } else {
5965 0 : SetDOMStringToNull(aDocumentURI);
5966 : }
5967 :
5968 0 : return NS_OK;
5969 : }
5970 :
5971 : static void BlastSubtreeToPieces(nsINode *aNode);
5972 :
5973 : PLDHashOperator
5974 0 : BlastFunc(nsAttrHashKey::KeyType aKey, nsDOMAttribute *aData, void* aUserArg)
5975 : {
5976 : nsCOMPtr<nsIAttribute> *attr =
5977 0 : static_cast<nsCOMPtr<nsIAttribute>*>(aUserArg);
5978 :
5979 0 : *attr = aData;
5980 :
5981 0 : NS_ASSERTION(attr->get(),
5982 : "non-nsIAttribute somehow made it into the hashmap?!");
5983 :
5984 0 : return PL_DHASH_STOP;
5985 : }
5986 :
5987 : static void
5988 0 : BlastSubtreeToPieces(nsINode *aNode)
5989 : {
5990 : PRUint32 i, count;
5991 0 : if (aNode->IsElement()) {
5992 0 : nsGenericElement *element = static_cast<nsGenericElement*>(aNode);
5993 0 : const nsDOMAttributeMap *map = element->GetAttributeMap();
5994 0 : if (map) {
5995 0 : nsCOMPtr<nsIAttribute> attr;
5996 0 : while (map->Enumerate(BlastFunc, &attr) > 0) {
5997 0 : BlastSubtreeToPieces(attr);
5998 :
5999 : #ifdef DEBUG
6000 : nsresult rv =
6001 : #endif
6002 : element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
6003 : attr->NodeInfo()->NameAtom(),
6004 0 : false);
6005 :
6006 : // XXX Should we abort here?
6007 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, UnsetAttr shouldn't fail!");
6008 : }
6009 : }
6010 : }
6011 :
6012 0 : count = aNode->GetChildCount();
6013 0 : for (i = 0; i < count; ++i) {
6014 0 : BlastSubtreeToPieces(aNode->GetFirstChild());
6015 : #ifdef DEBUG
6016 : nsresult rv =
6017 : #endif
6018 0 : aNode->RemoveChildAt(0, false);
6019 :
6020 : // XXX Should we abort here?
6021 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, RemoveChildAt shouldn't fail!");
6022 : }
6023 0 : }
6024 :
6025 :
6026 : class nsUserDataCaller : public nsRunnable
6027 0 : {
6028 : public:
6029 0 : nsUserDataCaller(nsCOMArray<nsINode>& aNodesWithProperties,
6030 : nsIDocument* aOwnerDoc)
6031 : : mNodesWithProperties(aNodesWithProperties),
6032 0 : mOwnerDoc(aOwnerDoc)
6033 : {
6034 0 : }
6035 :
6036 0 : NS_IMETHOD Run()
6037 : {
6038 : nsNodeUtils::CallUserDataHandlers(mNodesWithProperties, mOwnerDoc,
6039 : nsIDOMUserDataHandler::NODE_ADOPTED,
6040 0 : false);
6041 0 : return NS_OK;
6042 : }
6043 :
6044 : private:
6045 : nsCOMArray<nsINode> mNodesWithProperties;
6046 : nsCOMPtr<nsIDocument> mOwnerDoc;
6047 : };
6048 :
6049 : NS_IMETHODIMP
6050 0 : nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
6051 : {
6052 0 : NS_ENSURE_ARG(aAdoptedNode);
6053 :
6054 0 : *aResult = nsnull;
6055 :
6056 0 : nsresult rv = nsContentUtils::CheckSameOrigin(this, aAdoptedNode);
6057 0 : NS_ENSURE_SUCCESS(rv, rv);
6058 :
6059 0 : nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
6060 :
6061 : // Scope firing mutation events so that we don't carry any state that
6062 : // might be stale
6063 : {
6064 0 : nsINode* parent = adoptedNode->GetNodeParent();
6065 0 : if (parent) {
6066 : nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent,
6067 0 : adoptedNode->OwnerDoc());
6068 : }
6069 : }
6070 :
6071 0 : nsAutoScriptBlocker scriptBlocker;
6072 :
6073 : PRUint16 nodeType;
6074 0 : aAdoptedNode->GetNodeType(&nodeType);
6075 0 : switch (nodeType) {
6076 : case nsIDOMNode::ATTRIBUTE_NODE:
6077 : {
6078 : // Remove from ownerElement.
6079 0 : nsCOMPtr<nsIDOMAttr> adoptedAttr = do_QueryInterface(aAdoptedNode);
6080 0 : NS_ASSERTION(adoptedAttr, "Attribute not implementing nsIDOMAttr");
6081 :
6082 0 : nsCOMPtr<nsIDOMElement> ownerElement;
6083 0 : rv = adoptedAttr->GetOwnerElement(getter_AddRefs(ownerElement));
6084 0 : NS_ENSURE_SUCCESS(rv, rv);
6085 :
6086 0 : if (ownerElement) {
6087 0 : nsCOMPtr<nsIDOMAttr> newAttr;
6088 0 : rv = ownerElement->RemoveAttributeNode(adoptedAttr,
6089 0 : getter_AddRefs(newAttr));
6090 0 : NS_ENSURE_SUCCESS(rv, rv);
6091 :
6092 0 : newAttr.swap(adoptedAttr);
6093 : }
6094 :
6095 0 : break;
6096 : }
6097 : case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
6098 : case nsIDOMNode::ELEMENT_NODE:
6099 : case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
6100 : case nsIDOMNode::TEXT_NODE:
6101 : case nsIDOMNode::CDATA_SECTION_NODE:
6102 : case nsIDOMNode::COMMENT_NODE:
6103 : case nsIDOMNode::DOCUMENT_TYPE_NODE:
6104 : {
6105 : // We don't want to adopt an element into its own contentDocument or into
6106 : // a descendant contentDocument, so we check if the frameElement of this
6107 : // document or any of its parents is the adopted node or one of its
6108 : // descendants.
6109 0 : nsIDocument *doc = this;
6110 0 : do {
6111 0 : nsPIDOMWindow *win = doc->GetWindow();
6112 0 : if (win) {
6113 : nsCOMPtr<nsINode> node =
6114 0 : do_QueryInterface(win->GetFrameElementInternal());
6115 0 : if (node &&
6116 0 : nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
6117 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
6118 : }
6119 : }
6120 : } while ((doc = doc->GetParentDocument()));
6121 :
6122 : // Remove from parent.
6123 0 : nsCOMPtr<nsINode> parent = adoptedNode->GetNodeParent();
6124 0 : if (parent) {
6125 0 : rv = parent->RemoveChildAt(parent->IndexOf(adoptedNode), true);
6126 0 : NS_ENSURE_SUCCESS(rv, rv);
6127 : }
6128 :
6129 0 : break;
6130 : }
6131 : case nsIDOMNode::ENTITY_REFERENCE_NODE:
6132 : {
6133 0 : return NS_ERROR_NOT_IMPLEMENTED;
6134 : }
6135 : case nsIDOMNode::DOCUMENT_NODE:
6136 : case nsIDOMNode::ENTITY_NODE:
6137 : case nsIDOMNode::NOTATION_NODE:
6138 : {
6139 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
6140 : }
6141 : default:
6142 : {
6143 0 : NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
6144 :
6145 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
6146 : }
6147 : }
6148 :
6149 0 : nsIDocument *oldDocument = adoptedNode->OwnerDoc();
6150 0 : bool sameDocument = oldDocument == this;
6151 :
6152 0 : JSContext *cx = nsnull;
6153 0 : JSObject *newScope = nsnull;
6154 0 : if (!sameDocument) {
6155 0 : rv = nsContentUtils::GetContextAndScope(oldDocument, this, &cx, &newScope);
6156 0 : NS_ENSURE_SUCCESS(rv, rv);
6157 : }
6158 :
6159 0 : nsCOMArray<nsINode> nodesWithProperties;
6160 : rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nsnull : mNodeInfoManager,
6161 0 : cx, newScope, nodesWithProperties);
6162 0 : if (NS_FAILED(rv)) {
6163 : // Disconnect all nodes from their parents, since some have the old document
6164 : // as their ownerDocument and some have this as their ownerDocument.
6165 0 : BlastSubtreeToPieces(adoptedNode);
6166 :
6167 0 : if (!sameDocument && oldDocument) {
6168 0 : PRUint32 count = nodesWithProperties.Count();
6169 0 : for (PRUint32 j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
6170 0 : for (PRUint32 i = 0; i < count; ++i) {
6171 : // Remove all properties.
6172 : oldDocument->PropertyTable(j)->
6173 0 : DeleteAllPropertiesFor(nodesWithProperties[i]);
6174 : }
6175 : }
6176 : }
6177 :
6178 0 : return rv;
6179 : }
6180 :
6181 0 : PRUint32 count = nodesWithProperties.Count();
6182 0 : if (!sameDocument && oldDocument) {
6183 0 : for (PRUint32 j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
6184 0 : nsPropertyTable *oldTable = oldDocument->PropertyTable(j);
6185 0 : nsPropertyTable *newTable = PropertyTable(j);
6186 0 : for (PRUint32 i = 0; i < count; ++i) {
6187 0 : if (NS_SUCCEEDED(rv)) {
6188 0 : rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i],
6189 0 : newTable);
6190 : } else {
6191 0 : oldTable->DeleteAllPropertiesFor(nodesWithProperties[i]);
6192 : }
6193 : }
6194 : }
6195 :
6196 0 : if (NS_FAILED(rv)) {
6197 : // Disconnect all nodes from their parents.
6198 0 : BlastSubtreeToPieces(adoptedNode);
6199 :
6200 0 : return rv;
6201 : }
6202 : }
6203 :
6204 0 : if (nodesWithProperties.Count()) {
6205 : nsContentUtils::AddScriptRunner(new nsUserDataCaller(nodesWithProperties,
6206 0 : this));
6207 : }
6208 :
6209 0 : NS_ASSERTION(adoptedNode->OwnerDoc() == this,
6210 : "Should still be in the document we just got adopted into");
6211 :
6212 0 : return CallQueryInterface(adoptedNode, aResult);
6213 : }
6214 :
6215 : NS_IMETHODIMP
6216 0 : nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
6217 : {
6218 0 : return nsINode::GetOwnerDocument(aOwnerDocument);
6219 : }
6220 :
6221 : nsEventListenerManager*
6222 14600 : nsDocument::GetListenerManager(bool aCreateIfNotFound)
6223 : {
6224 14600 : if (!mListenerManager && aCreateIfNotFound) {
6225 : mListenerManager =
6226 0 : new nsEventListenerManager(static_cast<nsIDOMEventTarget*>(this));
6227 0 : SetFlags(NODE_HAS_LISTENERMANAGER);
6228 : }
6229 :
6230 14600 : return mListenerManager;
6231 : }
6232 :
6233 : nsresult
6234 6409 : nsDocument::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
6235 : {
6236 6409 : aVisitor.mCanHandle = true;
6237 : // FIXME! This is a hack to make middle mouse paste working also in Editor.
6238 : // Bug 329119
6239 6409 : aVisitor.mForceContentDispatch = true;
6240 :
6241 : // Load events must not propagate to |window| object, see bug 335251.
6242 6409 : if (aVisitor.mEvent->message != NS_LOAD) {
6243 5371 : nsGlobalWindow* window = static_cast<nsGlobalWindow*>(GetWindow());
6244 5371 : aVisitor.mParentTarget = static_cast<nsIDOMEventTarget*>(window);
6245 : }
6246 6409 : return NS_OK;
6247 : }
6248 :
6249 : NS_IMETHODIMP
6250 6403 : nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
6251 : {
6252 6403 : NS_ENSURE_ARG_POINTER(aReturn);
6253 6403 : *aReturn = nsnull;
6254 :
6255 : // Obtain a presentation shell
6256 :
6257 6403 : nsIPresShell *shell = GetShell();
6258 :
6259 6403 : nsPresContext *presContext = nsnull;
6260 :
6261 6403 : if (shell) {
6262 : // Retrieve the context
6263 0 : presContext = shell->GetPresContext();
6264 : }
6265 :
6266 : // Create event even without presContext.
6267 : return nsEventDispatcher::CreateEvent(presContext, nsnull,
6268 6403 : aEventType, aReturn);
6269 : }
6270 :
6271 : void
6272 7331 : nsDocument::FlushPendingNotifications(mozFlushType aType)
6273 : {
6274 : // We need to flush the sink for non-HTML documents (because the XML
6275 : // parser still does insertion with deferred notifications). We
6276 : // also need to flush the sink if this is a layout-related flush, to
6277 : // make sure that layout is started as needed. But we can skip that
6278 : // part if we have no presshell or if it's already done an initial
6279 : // reflow.
6280 21993 : if ((!IsHTML() ||
6281 : (aType > Flush_ContentAndNotify && mPresShell &&
6282 0 : !mPresShell->DidInitialReflow())) &&
6283 14662 : (mParser || mWeakSink)) {
6284 160 : nsCOMPtr<nsIContentSink> sink;
6285 80 : if (mParser) {
6286 0 : sink = mParser->GetContentSink();
6287 : } else {
6288 80 : sink = do_QueryReferent(mWeakSink);
6289 80 : if (!sink) {
6290 80 : mWeakSink = nsnull;
6291 : }
6292 : }
6293 : // Determine if it is safe to flush the sink notifications
6294 : // by determining if it safe to flush all the presshells.
6295 80 : if (sink && (aType == Flush_Content || IsSafeToFlush())) {
6296 0 : sink->FlushPendingNotifications(aType);
6297 : }
6298 : }
6299 :
6300 : // Should we be flushing pending binding constructors in here?
6301 :
6302 7331 : if (aType <= Flush_ContentAndNotify) {
6303 : // Nothing to do here
6304 7331 : return;
6305 : }
6306 :
6307 : // If we have a parent we must flush the parent too to ensure that our
6308 : // container is reflowed if its size was changed. But if it's not safe to
6309 : // flush ourselves, then don't flush the parent, since that can cause things
6310 : // like resizes of our frame's widget, which we can't handle while flushing
6311 : // is unsafe.
6312 : // Since media queries mean that a size change of our container can
6313 : // affect style, we need to promote a style flush on ourself to a
6314 : // layout flush on our parent, since we need our container to be the
6315 : // correct size to determine the correct style.
6316 0 : if (mParentDocument && IsSafeToFlush()) {
6317 0 : mozFlushType parentType = aType;
6318 0 : if (aType >= Flush_Style)
6319 0 : parentType = NS_MAX(Flush_Layout, aType);
6320 0 : mParentDocument->FlushPendingNotifications(parentType);
6321 : }
6322 :
6323 : // We can optimize away getting our presshell and calling
6324 : // FlushPendingNotifications on it if we don't need a flush of the sort we're
6325 : // looking at. The one exception is if mInFlush is true, because in that
6326 : // case we might have set mNeedStyleFlush and mNeedLayoutFlush to false
6327 : // already but the presshell hasn't actually done the corresponding work yet.
6328 : // So if mInFlush and reentering this code, we need to flush the presshell.
6329 0 : if (mNeedStyleFlush ||
6330 : (mNeedLayoutFlush && aType >= Flush_InterruptibleLayout) ||
6331 : aType >= Flush_Display ||
6332 : mInFlush) {
6333 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
6334 0 : if (shell) {
6335 0 : mNeedStyleFlush = false;
6336 0 : mNeedLayoutFlush = mNeedLayoutFlush && (aType < Flush_InterruptibleLayout);
6337 : // mInFlush is a bitfield, so can't us AutoRestore here. But we
6338 : // need to keep track of multi-level reentry correctly, so need
6339 : // to restore the old mInFlush value.
6340 0 : bool oldInFlush = mInFlush;
6341 0 : mInFlush = true;
6342 0 : shell->FlushPendingNotifications(aType);
6343 0 : mInFlush = oldInFlush;
6344 : }
6345 : }
6346 : }
6347 :
6348 : static bool
6349 0 : Flush(nsIDocument* aDocument, void* aData)
6350 : {
6351 0 : const mozFlushType* type = static_cast<const mozFlushType*>(aData);
6352 0 : aDocument->FlushPendingNotifications(*type);
6353 0 : return true;
6354 : }
6355 :
6356 : void
6357 0 : nsDocument::FlushExternalResources(mozFlushType aType)
6358 : {
6359 0 : NS_ASSERTION(aType >= Flush_Style,
6360 : "should only need to flush for style or higher in external resources");
6361 :
6362 0 : if (GetDisplayDocument()) {
6363 0 : return;
6364 : }
6365 0 : EnumerateExternalResources(Flush, &aType);
6366 : }
6367 :
6368 : void
6369 825 : nsDocument::SetXMLDeclaration(const PRUnichar *aVersion,
6370 : const PRUnichar *aEncoding,
6371 : const PRInt32 aStandalone)
6372 : {
6373 825 : if (!aVersion || *aVersion == '\0') {
6374 0 : mXMLDeclarationBits = 0;
6375 0 : return;
6376 : }
6377 :
6378 825 : mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS;
6379 :
6380 825 : if (aEncoding && *aEncoding != '\0') {
6381 630 : mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS;
6382 : }
6383 :
6384 825 : if (aStandalone == 1) {
6385 : mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS |
6386 0 : XML_DECLARATION_BITS_STANDALONE_YES;
6387 : }
6388 825 : else if (aStandalone == 0) {
6389 0 : mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS;
6390 : }
6391 : }
6392 :
6393 : void
6394 75 : nsDocument::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding,
6395 : nsAString& aStandalone)
6396 : {
6397 75 : aVersion.Truncate();
6398 75 : aEncoding.Truncate();
6399 75 : aStandalone.Truncate();
6400 :
6401 75 : if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) {
6402 46 : return;
6403 : }
6404 :
6405 : // always until we start supporting 1.1 etc.
6406 29 : aVersion.AssignLiteral("1.0");
6407 :
6408 29 : if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
6409 : // This is what we have stored, not necessarily what was written
6410 : // in the original
6411 28 : GetCharacterSet(aEncoding);
6412 : }
6413 :
6414 29 : if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) {
6415 0 : if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) {
6416 0 : aStandalone.AssignLiteral("yes");
6417 : } else {
6418 0 : aStandalone.AssignLiteral("no");
6419 : }
6420 : }
6421 : }
6422 :
6423 : bool
6424 0 : nsDocument::IsScriptEnabled()
6425 : {
6426 0 : nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
6427 0 : NS_ENSURE_TRUE(sm, false);
6428 :
6429 0 : nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
6430 0 : NS_ENSURE_TRUE(globalObject, false);
6431 :
6432 0 : nsIScriptContext *scriptContext = globalObject->GetContext();
6433 0 : NS_ENSURE_TRUE(scriptContext, false);
6434 :
6435 0 : JSContext* cx = scriptContext->GetNativeContext();
6436 0 : NS_ENSURE_TRUE(cx, false);
6437 :
6438 : bool enabled;
6439 0 : nsresult rv = sm->CanExecuteScripts(cx, NodePrincipal(), &enabled);
6440 0 : NS_ENSURE_SUCCESS(rv, false);
6441 0 : return enabled;
6442 : }
6443 :
6444 : nsresult
6445 0 : nsDocument::GetRadioGroup(const nsAString& aName,
6446 : nsRadioGroupStruct **aRadioGroup)
6447 : {
6448 0 : nsAutoString tmKey(aName);
6449 0 : if(IsHTML())
6450 0 : ToLowerCase(tmKey); //should case-insensitive.
6451 0 : if (mRadioGroups.Get(tmKey, aRadioGroup))
6452 0 : return NS_OK;
6453 :
6454 0 : nsAutoPtr<nsRadioGroupStruct> radioGroup(new nsRadioGroupStruct());
6455 0 : NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY);
6456 0 : NS_ENSURE_TRUE(mRadioGroups.Put(tmKey, radioGroup), NS_ERROR_OUT_OF_MEMORY);
6457 :
6458 0 : *aRadioGroup = radioGroup;
6459 0 : radioGroup.forget();
6460 :
6461 0 : return NS_OK;
6462 : }
6463 :
6464 : NS_IMETHODIMP
6465 0 : nsDocument::SetCurrentRadioButton(const nsAString& aName,
6466 : nsIDOMHTMLInputElement* aRadio)
6467 : {
6468 0 : nsRadioGroupStruct* radioGroup = nsnull;
6469 0 : GetRadioGroup(aName, &radioGroup);
6470 0 : if (radioGroup) {
6471 0 : radioGroup->mSelectedRadioButton = aRadio;
6472 : }
6473 :
6474 0 : return NS_OK;
6475 : }
6476 :
6477 : NS_IMETHODIMP
6478 0 : nsDocument::GetCurrentRadioButton(const nsAString& aName,
6479 : nsIDOMHTMLInputElement** aRadio)
6480 : {
6481 0 : nsRadioGroupStruct* radioGroup = nsnull;
6482 0 : GetRadioGroup(aName, &radioGroup);
6483 0 : if (radioGroup) {
6484 0 : *aRadio = radioGroup->mSelectedRadioButton;
6485 0 : NS_IF_ADDREF(*aRadio);
6486 : }
6487 :
6488 0 : return NS_OK;
6489 : }
6490 :
6491 : NS_IMETHODIMP
6492 0 : nsDocument::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
6493 : PRInt32 *aPositionIndex,
6494 : PRInt32 *aItemsInGroup)
6495 : {
6496 0 : *aPositionIndex = 0;
6497 0 : *aItemsInGroup = 1;
6498 0 : nsAutoString name;
6499 0 : aRadio->GetName(name);
6500 0 : if (name.IsEmpty()) {
6501 0 : return NS_OK;
6502 : }
6503 :
6504 0 : nsRadioGroupStruct* radioGroup = nsnull;
6505 0 : nsresult rv = GetRadioGroup(name, &radioGroup);
6506 0 : NS_ENSURE_SUCCESS(rv, rv);
6507 :
6508 0 : nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(aRadio));
6509 0 : NS_ASSERTION(radioControl, "Radio button should implement nsIFormControl");
6510 0 : *aPositionIndex = radioGroup->mRadioButtons.IndexOf(radioControl);
6511 0 : NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
6512 0 : *aItemsInGroup = radioGroup->mRadioButtons.Count();
6513 :
6514 0 : return NS_OK;
6515 : }
6516 :
6517 : NS_IMETHODIMP
6518 0 : nsDocument::GetNextRadioButton(const nsAString& aName,
6519 : const bool aPrevious,
6520 : nsIDOMHTMLInputElement* aFocusedRadio,
6521 : nsIDOMHTMLInputElement** aRadioOut)
6522 : {
6523 : // XXX Can we combine the HTML radio button method impls of
6524 : // nsDocument and nsHTMLFormControl?
6525 : // XXX Why is HTML radio button stuff in nsDocument, as
6526 : // opposed to nsHTMLDocument?
6527 0 : *aRadioOut = nsnull;
6528 :
6529 0 : nsRadioGroupStruct* radioGroup = nsnull;
6530 0 : GetRadioGroup(aName, &radioGroup);
6531 0 : if (!radioGroup) {
6532 0 : return NS_ERROR_FAILURE;
6533 : }
6534 :
6535 : // Return the radio button relative to the focused radio button.
6536 : // If no radio is focused, get the radio relative to the selected one.
6537 0 : nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
6538 0 : if (aFocusedRadio) {
6539 0 : currentRadio = aFocusedRadio;
6540 : }
6541 : else {
6542 0 : currentRadio = radioGroup->mSelectedRadioButton;
6543 0 : if (!currentRadio) {
6544 0 : return NS_ERROR_FAILURE;
6545 : }
6546 : }
6547 0 : nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(currentRadio));
6548 0 : PRInt32 index = radioGroup->mRadioButtons.IndexOf(radioControl);
6549 0 : if (index < 0) {
6550 0 : return NS_ERROR_FAILURE;
6551 : }
6552 :
6553 0 : PRInt32 numRadios = radioGroup->mRadioButtons.Count();
6554 : bool disabled;
6555 0 : nsCOMPtr<nsIDOMHTMLInputElement> radio;
6556 0 : do {
6557 0 : if (aPrevious) {
6558 0 : if (--index < 0) {
6559 0 : index = numRadios -1;
6560 : }
6561 : }
6562 0 : else if (++index >= numRadios) {
6563 0 : index = 0;
6564 : }
6565 0 : radio = do_QueryInterface(radioGroup->mRadioButtons[index]);
6566 0 : NS_ASSERTION(radio, "mRadioButtons holding a non-radio button");
6567 0 : radio->GetDisabled(&disabled);
6568 0 : } while (disabled && radio != currentRadio);
6569 :
6570 0 : NS_IF_ADDREF(*aRadioOut = radio);
6571 0 : return NS_OK;
6572 : }
6573 :
6574 : NS_IMETHODIMP
6575 0 : nsDocument::AddToRadioGroup(const nsAString& aName,
6576 : nsIFormControl* aRadio)
6577 : {
6578 0 : nsRadioGroupStruct* radioGroup = nsnull;
6579 0 : GetRadioGroup(aName, &radioGroup);
6580 0 : if (radioGroup) {
6581 0 : radioGroup->mRadioButtons.AppendObject(aRadio);
6582 :
6583 0 : nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
6584 0 : NS_ASSERTION(element, "radio controls have to be content elements");
6585 0 : if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
6586 0 : radioGroup->mRequiredRadioCount++;
6587 : }
6588 : }
6589 :
6590 0 : return NS_OK;
6591 : }
6592 :
6593 : NS_IMETHODIMP
6594 0 : nsDocument::RemoveFromRadioGroup(const nsAString& aName,
6595 : nsIFormControl* aRadio)
6596 : {
6597 0 : nsRadioGroupStruct* radioGroup = nsnull;
6598 0 : GetRadioGroup(aName, &radioGroup);
6599 0 : if (radioGroup) {
6600 0 : radioGroup->mRadioButtons.RemoveObject(aRadio);
6601 :
6602 0 : nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
6603 0 : NS_ASSERTION(element, "radio controls have to be content elements");
6604 0 : if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
6605 0 : radioGroup->mRequiredRadioCount--;
6606 : NS_ASSERTION(radioGroup->mRequiredRadioCount >= 0,
6607 : "mRequiredRadioCount shouldn't be negative!");
6608 : }
6609 : }
6610 :
6611 0 : return NS_OK;
6612 : }
6613 :
6614 : NS_IMETHODIMP
6615 0 : nsDocument::WalkRadioGroup(const nsAString& aName,
6616 : nsIRadioVisitor* aVisitor,
6617 : bool aFlushContent)
6618 : {
6619 0 : nsRadioGroupStruct* radioGroup = nsnull;
6620 0 : GetRadioGroup(aName, &radioGroup);
6621 0 : if (!radioGroup) {
6622 0 : return NS_OK;
6623 : }
6624 :
6625 0 : for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
6626 0 : if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
6627 0 : return NS_OK;
6628 : }
6629 : }
6630 :
6631 0 : return NS_OK;
6632 : }
6633 :
6634 : PRUint32
6635 0 : nsDocument::GetRequiredRadioCount(const nsAString& aName) const
6636 : {
6637 0 : nsRadioGroupStruct* radioGroup = nsnull;
6638 : // TODO: we should call GetRadioGroup here (and make it const) but for that
6639 : // we would need to have an explicit CreateRadioGroup() instead of create
6640 : // one when GetRadioGroup is called. See bug 636123.
6641 0 : nsAutoString tmKey(aName);
6642 0 : if (IsHTML())
6643 0 : ToLowerCase(tmKey); //should case-insensitive.
6644 0 : mRadioGroups.Get(tmKey, &radioGroup);
6645 :
6646 0 : return radioGroup ? radioGroup->mRequiredRadioCount : 0;
6647 : }
6648 :
6649 : void
6650 0 : nsDocument::RadioRequiredChanged(const nsAString& aName, nsIFormControl* aRadio)
6651 : {
6652 0 : nsRadioGroupStruct* radioGroup = nsnull;
6653 0 : GetRadioGroup(aName, &radioGroup);
6654 :
6655 0 : if (!radioGroup) {
6656 0 : return;
6657 : }
6658 :
6659 0 : nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
6660 0 : NS_ASSERTION(element, "radio controls have to be content elements");
6661 0 : if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
6662 0 : radioGroup->mRequiredRadioCount++;
6663 : } else {
6664 0 : radioGroup->mRequiredRadioCount--;
6665 : NS_ASSERTION(radioGroup->mRequiredRadioCount >= 0,
6666 : "mRequiredRadioCount shouldn't be negative!");
6667 : }
6668 : }
6669 :
6670 : bool
6671 0 : nsDocument::GetValueMissingState(const nsAString& aName) const
6672 : {
6673 0 : nsRadioGroupStruct* radioGroup = nsnull;
6674 : // TODO: we should call GetRadioGroup here (and make it const) but for that
6675 : // we would need to have an explicit CreateRadioGroup() instead of create
6676 : // one when GetRadioGroup is called. See bug 636123.
6677 0 : nsAutoString tmKey(aName);
6678 0 : if (IsHTML())
6679 0 : ToLowerCase(tmKey); //should case-insensitive.
6680 0 : mRadioGroups.Get(tmKey, &radioGroup);
6681 :
6682 0 : return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
6683 : }
6684 :
6685 : void
6686 0 : nsDocument::SetValueMissingState(const nsAString& aName, bool aValue)
6687 : {
6688 0 : nsRadioGroupStruct* radioGroup = nsnull;
6689 0 : GetRadioGroup(aName, &radioGroup);
6690 :
6691 0 : if (!radioGroup) {
6692 0 : return;
6693 : }
6694 :
6695 0 : radioGroup->mGroupSuffersFromValueMissing = aValue;
6696 : }
6697 :
6698 : void
6699 1038 : nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
6700 : {
6701 2076 : nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
6702 1038 : PRTime modDate = LL_ZERO;
6703 : nsresult rv;
6704 :
6705 1038 : if (httpChannel) {
6706 934 : nsCAutoString tmp;
6707 934 : rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
6708 467 : tmp);
6709 :
6710 467 : if (NS_SUCCEEDED(rv)) {
6711 : PRTime time;
6712 361 : PRStatus st = PR_ParseTimeString(tmp.get(), true, &time);
6713 361 : if (st == PR_SUCCESS) {
6714 361 : modDate = time;
6715 : }
6716 : }
6717 :
6718 : // The misspelled key 'referer' is as per the HTTP spec
6719 934 : rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
6720 467 : mReferrer);
6721 467 : if (NS_FAILED(rv)) {
6722 467 : mReferrer.Truncate();
6723 : }
6724 :
6725 : static const char *const headers[] = {
6726 : "default-style",
6727 : "content-style-type",
6728 : "content-language",
6729 : "content-disposition",
6730 : "refresh",
6731 : "x-dns-prefetch-control",
6732 : "x-content-security-policy",
6733 : "x-content-security-policy-report-only",
6734 : "x-frame-options",
6735 : // add more http headers if you need
6736 : // XXXbz don't add content-location support without reading bug
6737 : // 238654 and its dependencies/dups first.
6738 : 0
6739 : };
6740 :
6741 934 : nsCAutoString headerVal;
6742 467 : const char *const *name = headers;
6743 5137 : while (*name) {
6744 : rv =
6745 4203 : httpChannel->GetResponseHeader(nsDependentCString(*name), headerVal);
6746 4203 : if (NS_SUCCEEDED(rv) && !headerVal.IsEmpty()) {
6747 8 : nsCOMPtr<nsIAtom> key = do_GetAtom(*name);
6748 4 : SetHeaderData(key, NS_ConvertASCIItoUTF16(headerVal));
6749 : }
6750 4203 : ++name;
6751 : }
6752 : } else {
6753 1142 : nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(aChannel);
6754 571 : if (fileChannel) {
6755 0 : nsCOMPtr<nsIFile> file;
6756 0 : fileChannel->GetFile(getter_AddRefs(file));
6757 0 : if (file) {
6758 : PRTime msecs;
6759 0 : rv = file->GetLastModifiedTime(&msecs);
6760 :
6761 0 : if (NS_SUCCEEDED(rv)) {
6762 : PRInt64 intermediateValue;
6763 0 : LL_I2L(intermediateValue, PR_USEC_PER_MSEC);
6764 0 : LL_MUL(modDate, msecs, intermediateValue);
6765 : }
6766 : }
6767 : } else {
6768 1142 : nsCAutoString contentDisp;
6769 571 : rv = aChannel->GetContentDispositionHeader(contentDisp);
6770 571 : if (NS_SUCCEEDED(rv)) {
6771 : SetHeaderData(nsGkAtoms::headerContentDisposition,
6772 0 : NS_ConvertASCIItoUTF16(contentDisp));
6773 : }
6774 : }
6775 : }
6776 :
6777 1038 : if (LL_IS_ZERO(modDate)) {
6778 : // We got nothing from our attempt to ask nsIFileChannel and
6779 : // nsIHttpChannel for the last modified time. Return the current
6780 : // time.
6781 677 : modDate = PR_Now();
6782 : }
6783 :
6784 1038 : mLastModified.Truncate();
6785 1038 : if (LL_NE(modDate, LL_ZERO)) {
6786 : PRExplodedTime prtime;
6787 1038 : PR_ExplodeTime(modDate, PR_LocalTimeParameters, &prtime);
6788 : // "MM/DD/YYYY hh:mm:ss"
6789 : char formatedTime[24];
6790 1038 : if (PR_snprintf(formatedTime, sizeof(formatedTime),
6791 : "%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
6792 : prtime.tm_month + 1, prtime.tm_mday, prtime.tm_year,
6793 1038 : prtime.tm_hour , prtime.tm_min, prtime.tm_sec)) {
6794 1038 : CopyASCIItoUTF16(nsDependentCString(formatedTime), mLastModified);
6795 : }
6796 : }
6797 1038 : }
6798 :
6799 : nsresult
6800 8 : nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix, PRInt32 aNamespaceID,
6801 : nsIContent **aResult)
6802 : {
6803 : #ifdef DEBUG
6804 16 : nsAutoString qName;
6805 8 : if (aPrefix) {
6806 0 : aPrefix->ToString(qName);
6807 0 : qName.Append(':');
6808 : }
6809 8 : qName.Append(aName);
6810 :
6811 : // Note: "a:b:c" is a valid name in non-namespaces XML, and
6812 : // nsDocument::CreateElement can call us with such a name and no prefix,
6813 : // which would cause an error if we just used true here.
6814 8 : bool nsAware = aPrefix != nsnull || aNamespaceID != GetDefaultNamespaceID();
6815 8 : NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName, nsAware)),
6816 : "Don't pass invalid prefixes to nsDocument::CreateElem, "
6817 : "check caller.");
6818 : #endif
6819 :
6820 8 : *aResult = nsnull;
6821 :
6822 16 : nsCOMPtr<nsINodeInfo> nodeInfo;
6823 : mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID,
6824 : nsIDOMNode::ELEMENT_NODE,
6825 8 : getter_AddRefs(nodeInfo));
6826 8 : NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
6827 :
6828 8 : return NS_NewElement(aResult, nodeInfo.forget(), NOT_FROM_PARSER);
6829 : }
6830 :
6831 : bool
6832 0 : nsDocument::IsSafeToFlush() const
6833 : {
6834 0 : nsIPresShell* shell = GetShell();
6835 0 : if (!shell)
6836 0 : return true;
6837 :
6838 0 : return shell->IsSafeToFlush();
6839 : }
6840 :
6841 : nsresult
6842 0 : nsDocument::Sanitize()
6843 : {
6844 : // Sanitize the document by resetting all password fields and any form
6845 : // fields with autocomplete=off to their default values. We do this now,
6846 : // instead of when the presentation is restored, to offer some protection
6847 : // in case there is ever an exploit that allows a cached document to be
6848 : // accessed from a different document.
6849 :
6850 : // First locate all input elements, regardless of whether they are
6851 : // in a form, and reset the password and autocomplete=off elements.
6852 :
6853 0 : nsCOMPtr<nsIDOMNodeList> nodes;
6854 0 : nsresult rv = GetElementsByTagName(NS_LITERAL_STRING("input"),
6855 0 : getter_AddRefs(nodes));
6856 0 : NS_ENSURE_SUCCESS(rv, rv);
6857 :
6858 0 : PRUint32 length = 0;
6859 0 : if (nodes)
6860 0 : nodes->GetLength(&length);
6861 :
6862 0 : nsCOMPtr<nsIDOMNode> item;
6863 0 : nsAutoString value;
6864 : PRUint32 i;
6865 :
6866 0 : for (i = 0; i < length; ++i) {
6867 0 : nodes->Item(i, getter_AddRefs(item));
6868 0 : NS_ASSERTION(item, "null item in node list!");
6869 :
6870 0 : nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(item);
6871 0 : if (!input)
6872 0 : continue;
6873 :
6874 0 : bool resetValue = false;
6875 :
6876 0 : input->GetAttribute(NS_LITERAL_STRING("autocomplete"), value);
6877 0 : if (value.LowerCaseEqualsLiteral("off")) {
6878 0 : resetValue = true;
6879 : } else {
6880 0 : input->GetType(value);
6881 0 : if (value.LowerCaseEqualsLiteral("password"))
6882 0 : resetValue = true;
6883 : }
6884 :
6885 0 : if (resetValue) {
6886 0 : nsCOMPtr<nsIFormControl> fc = do_QueryInterface(input);
6887 0 : fc->Reset();
6888 : }
6889 : }
6890 :
6891 : // Now locate all _form_ elements that have autocomplete=off and reset them
6892 0 : rv = GetElementsByTagName(NS_LITERAL_STRING("form"), getter_AddRefs(nodes));
6893 0 : NS_ENSURE_SUCCESS(rv, rv);
6894 :
6895 0 : length = 0;
6896 0 : if (nodes)
6897 0 : nodes->GetLength(&length);
6898 :
6899 0 : for (i = 0; i < length; ++i) {
6900 0 : nodes->Item(i, getter_AddRefs(item));
6901 0 : NS_ASSERTION(item, "null item in nodelist");
6902 :
6903 0 : nsCOMPtr<nsIDOMHTMLFormElement> form = do_QueryInterface(item);
6904 0 : if (!form)
6905 0 : continue;
6906 :
6907 0 : form->GetAttribute(NS_LITERAL_STRING("autocomplete"), value);
6908 0 : if (value.LowerCaseEqualsLiteral("off"))
6909 0 : form->Reset();
6910 : }
6911 :
6912 0 : return NS_OK;
6913 : }
6914 :
6915 : struct SubDocEnumArgs
6916 : {
6917 : nsIDocument::nsSubDocEnumFunc callback;
6918 : void *data;
6919 : };
6920 :
6921 : static PLDHashOperator
6922 0 : SubDocHashEnum(PLDHashTable *table, PLDHashEntryHdr *hdr,
6923 : PRUint32 number, void *arg)
6924 : {
6925 0 : SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
6926 0 : SubDocEnumArgs *args = static_cast<SubDocEnumArgs*>(arg);
6927 :
6928 0 : nsIDocument *subdoc = entry->mSubDocument;
6929 0 : bool next = subdoc ? args->callback(subdoc, args->data) : true;
6930 :
6931 0 : return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
6932 : }
6933 :
6934 : void
6935 0 : nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback, void *aData)
6936 : {
6937 0 : if (mSubDocuments) {
6938 0 : SubDocEnumArgs args = { aCallback, aData };
6939 0 : PL_DHashTableEnumerate(mSubDocuments, SubDocHashEnum, &args);
6940 : }
6941 0 : }
6942 :
6943 : static PLDHashOperator
6944 0 : CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr,
6945 : PRUint32 number, void *arg)
6946 : {
6947 0 : SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
6948 0 : bool *canCacheArg = static_cast<bool*>(arg);
6949 :
6950 0 : nsIDocument *subdoc = entry->mSubDocument;
6951 :
6952 : // The aIgnoreRequest we were passed is only for us, so don't pass it on.
6953 0 : bool canCache = subdoc ? subdoc->CanSavePresentation(nsnull) : false;
6954 0 : if (!canCache) {
6955 0 : *canCacheArg = false;
6956 0 : return PL_DHASH_STOP;
6957 : }
6958 :
6959 0 : return PL_DHASH_NEXT;
6960 : }
6961 :
6962 : #ifdef DEBUG_bryner
6963 : #define DEBUG_PAGE_CACHE
6964 : #endif
6965 :
6966 : bool
6967 0 : nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
6968 : {
6969 0 : if (EventHandlingSuppressed()) {
6970 0 : return false;
6971 : }
6972 :
6973 0 : nsPIDOMWindow* win = GetInnerWindow();
6974 0 : if (win && win->TimeoutSuspendCount()) {
6975 0 : return false;
6976 : }
6977 :
6978 : // Check our event listener manager for unload/beforeunload listeners.
6979 0 : nsCOMPtr<nsIDOMEventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
6980 0 : if (piTarget) {
6981 : nsEventListenerManager* manager =
6982 0 : piTarget->GetListenerManager(false);
6983 0 : if (manager && manager->HasUnloadListeners()) {
6984 0 : return false;
6985 : }
6986 : }
6987 :
6988 : // Check if we have pending network requests
6989 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
6990 0 : if (loadGroup) {
6991 0 : nsCOMPtr<nsISimpleEnumerator> requests;
6992 0 : loadGroup->GetRequests(getter_AddRefs(requests));
6993 :
6994 0 : bool hasMore = false;
6995 :
6996 : // We want to bail out if we have any requests other than aNewRequest (or
6997 : // in the case when aNewRequest is a part of a multipart response the base
6998 : // channel the multipart response is coming in on).
6999 0 : nsCOMPtr<nsIChannel> baseChannel;
7000 0 : nsCOMPtr<nsIMultiPartChannel> part(do_QueryInterface(aNewRequest));
7001 0 : if (part) {
7002 0 : part->GetBaseChannel(getter_AddRefs(baseChannel));
7003 : }
7004 :
7005 0 : while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
7006 0 : nsCOMPtr<nsISupports> elem;
7007 0 : requests->GetNext(getter_AddRefs(elem));
7008 :
7009 0 : nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
7010 0 : if (request && request != aNewRequest && request != baseChannel) {
7011 : #ifdef DEBUG_PAGE_CACHE
7012 : nsCAutoString requestName, docSpec;
7013 : request->GetName(requestName);
7014 : if (mDocumentURI)
7015 : mDocumentURI->GetSpec(docSpec);
7016 :
7017 : printf("document %s has request %s\n",
7018 : docSpec.get(), requestName.get());
7019 : #endif
7020 0 : return false;
7021 : }
7022 : }
7023 : }
7024 :
7025 : // Check if we have running IndexedDB transactions
7026 : indexedDB::IndexedDatabaseManager* idbManager =
7027 0 : indexedDB::IndexedDatabaseManager::Get();
7028 0 : if (idbManager && idbManager->HasOpenTransactions(win)) {
7029 0 : return false;
7030 : }
7031 :
7032 0 : bool canCache = true;
7033 0 : if (mSubDocuments)
7034 0 : PL_DHashTableEnumerate(mSubDocuments, CanCacheSubDocument, &canCache);
7035 :
7036 0 : return canCache;
7037 : }
7038 :
7039 : void
7040 0 : nsDocument::Destroy()
7041 : {
7042 : // The ContentViewer wants to release the document now. So, tell our content
7043 : // to drop any references to the document so that it can be destroyed.
7044 0 : if (mIsGoingAway)
7045 0 : return;
7046 :
7047 0 : mIsGoingAway = true;
7048 :
7049 0 : RemovedFromDocShell();
7050 :
7051 0 : bool oldVal = mInUnlinkOrDeletion;
7052 0 : mInUnlinkOrDeletion = true;
7053 0 : PRUint32 i, count = mChildren.ChildCount();
7054 0 : for (i = 0; i < count; ++i) {
7055 0 : mChildren.ChildAt(i)->DestroyContent();
7056 : }
7057 0 : mInUnlinkOrDeletion = oldVal;
7058 :
7059 0 : mLayoutHistoryState = nsnull;
7060 :
7061 : // Shut down our external resource map. We might not need this for
7062 : // leak-fixing if we fix DocumentViewerImpl to do cycle-collection, but
7063 : // tearing down all those frame trees right now is the right thing to do.
7064 0 : mExternalResourceMap.Shutdown();
7065 :
7066 : // XXX We really should let cycle collection do this, but that currently still
7067 : // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
7068 0 : nsContentUtils::ReleaseWrapper(static_cast<nsINode*>(this), this);
7069 : }
7070 :
7071 : void
7072 0 : nsDocument::RemovedFromDocShell()
7073 : {
7074 0 : if (mRemovedFromDocShell)
7075 0 : return;
7076 :
7077 0 : mRemovedFromDocShell = true;
7078 0 : EnumerateFreezableElements(NotifyActivityChanged, nsnull);
7079 :
7080 0 : PRUint32 i, count = mChildren.ChildCount();
7081 0 : for (i = 0; i < count; ++i) {
7082 0 : mChildren.ChildAt(i)->SaveSubtreeState();
7083 : }
7084 : }
7085 :
7086 : already_AddRefed<nsILayoutHistoryState>
7087 1 : nsDocument::GetLayoutHistoryState() const
7088 : {
7089 1 : nsILayoutHistoryState* state = nsnull;
7090 1 : if (!mScriptGlobalObject) {
7091 1 : NS_IF_ADDREF(state = mLayoutHistoryState);
7092 : } else {
7093 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocumentContainer));
7094 0 : if (docShell) {
7095 0 : docShell->GetLayoutHistoryState(&state);
7096 : }
7097 : }
7098 :
7099 1 : return state;
7100 : }
7101 :
7102 : void
7103 0 : nsDocument::EnsureOnloadBlocker()
7104 : {
7105 : // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
7106 : // -- it's not ours.
7107 0 : if (mOnloadBlockCount != 0 && mScriptGlobalObject) {
7108 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
7109 0 : if (loadGroup) {
7110 : // Check first to see if mOnloadBlocker is in the loadgroup.
7111 0 : nsCOMPtr<nsISimpleEnumerator> requests;
7112 0 : loadGroup->GetRequests(getter_AddRefs(requests));
7113 :
7114 0 : bool hasMore = false;
7115 0 : while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
7116 0 : nsCOMPtr<nsISupports> elem;
7117 0 : requests->GetNext(getter_AddRefs(elem));
7118 0 : nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
7119 0 : if (request && request == mOnloadBlocker) {
7120 : return;
7121 : }
7122 : }
7123 :
7124 : // Not in the loadgroup, so add it.
7125 0 : loadGroup->AddRequest(mOnloadBlocker, nsnull);
7126 : }
7127 : }
7128 : }
7129 :
7130 : void
7131 0 : nsDocument::AsyncBlockOnload()
7132 : {
7133 0 : while (mAsyncOnloadBlockCount) {
7134 0 : --mAsyncOnloadBlockCount;
7135 0 : BlockOnload();
7136 : }
7137 0 : }
7138 :
7139 : void
7140 3114 : nsDocument::BlockOnload()
7141 : {
7142 3114 : if (mDisplayDocument) {
7143 0 : mDisplayDocument->BlockOnload();
7144 0 : return;
7145 : }
7146 :
7147 : // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
7148 : // -- it's not ours.
7149 3114 : if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
7150 0 : if (!nsContentUtils::IsSafeToRunScript()) {
7151 : // Because AddRequest may lead to OnStateChange calls in chrome,
7152 : // block onload only when there are no script blockers.
7153 0 : ++mAsyncOnloadBlockCount;
7154 0 : if (mAsyncOnloadBlockCount == 1) {
7155 : bool success = nsContentUtils::AddScriptRunner(
7156 0 : NS_NewRunnableMethod(this, &nsDocument::AsyncBlockOnload));
7157 :
7158 : // The script runner shouldn't fail to add. But if somebody broke
7159 : // something and it does, we'll thrash at 100% cpu forever. The best
7160 : // response is just to ignore the onload blocking request. See bug 579535.
7161 0 : if (!success) {
7162 0 : NS_WARNING("Disaster! Onload blocking script runner failed to add - expect bad things!");
7163 0 : mAsyncOnloadBlockCount = 0;
7164 : }
7165 : }
7166 0 : return;
7167 : }
7168 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
7169 0 : if (loadGroup) {
7170 0 : loadGroup->AddRequest(mOnloadBlocker, nsnull);
7171 : }
7172 : }
7173 3114 : ++mOnloadBlockCount;
7174 : }
7175 :
7176 : void
7177 3114 : nsDocument::UnblockOnload(bool aFireSync)
7178 : {
7179 3114 : if (mDisplayDocument) {
7180 0 : mDisplayDocument->UnblockOnload(aFireSync);
7181 0 : return;
7182 : }
7183 :
7184 3114 : if (mOnloadBlockCount == 0 && mAsyncOnloadBlockCount == 0) {
7185 0 : NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
7186 0 : return;
7187 : }
7188 :
7189 3114 : --mOnloadBlockCount;
7190 :
7191 : // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
7192 : // -- it's not ours.
7193 3114 : if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
7194 0 : if (aFireSync && mAsyncOnloadBlockCount == 0) {
7195 : // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
7196 0 : ++mOnloadBlockCount;
7197 0 : DoUnblockOnload();
7198 : } else {
7199 0 : PostUnblockOnloadEvent();
7200 : }
7201 : }
7202 : }
7203 :
7204 0 : class nsUnblockOnloadEvent : public nsRunnable {
7205 : public:
7206 0 : nsUnblockOnloadEvent(nsDocument *doc) : mDoc(doc) {}
7207 0 : NS_IMETHOD Run() {
7208 0 : mDoc->DoUnblockOnload();
7209 0 : return NS_OK;
7210 : }
7211 : private:
7212 : nsRefPtr<nsDocument> mDoc;
7213 : };
7214 :
7215 : void
7216 0 : nsDocument::PostUnblockOnloadEvent()
7217 : {
7218 0 : nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this);
7219 0 : nsresult rv = NS_DispatchToCurrentThread(evt);
7220 0 : if (NS_SUCCEEDED(rv)) {
7221 : // Stabilize block count so we don't post more events while this one is up
7222 0 : ++mOnloadBlockCount;
7223 : } else {
7224 0 : NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
7225 : }
7226 0 : }
7227 :
7228 : void
7229 0 : nsDocument::DoUnblockOnload()
7230 : {
7231 0 : NS_PRECONDITION(!mDisplayDocument,
7232 : "Shouldn't get here for resource document");
7233 0 : NS_PRECONDITION(mOnloadBlockCount != 0,
7234 : "Shouldn't have a count of zero here, since we stabilized in "
7235 : "PostUnblockOnloadEvent");
7236 :
7237 0 : --mOnloadBlockCount;
7238 :
7239 0 : if (mOnloadBlockCount != 0) {
7240 : // We blocked again after the last unblock. Nothing to do here. We'll
7241 : // post a new event when we unblock again.
7242 0 : return;
7243 : }
7244 :
7245 0 : if (mAsyncOnloadBlockCount != 0) {
7246 : // We need to wait until the async onload block has been handled.
7247 0 : PostUnblockOnloadEvent();
7248 : }
7249 :
7250 : // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
7251 : // -- it's not ours.
7252 0 : if (mScriptGlobalObject) {
7253 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
7254 0 : if (loadGroup) {
7255 0 : loadGroup->RemoveRequest(mOnloadBlocker, nsnull, NS_OK);
7256 : }
7257 : }
7258 : }
7259 :
7260 : /* See if document is a child of this. If so, return the frame element in this
7261 : * document that holds currentDoc (or an ancestor). */
7262 : already_AddRefed<nsIDOMElement>
7263 0 : nsDocument::CheckAncestryAndGetFrame(nsIDocument* aDocument) const
7264 : {
7265 : nsIDocument* parentDoc;
7266 0 : for (parentDoc = aDocument->GetParentDocument();
7267 : parentDoc != static_cast<const nsIDocument* const>(this);
7268 : parentDoc = parentDoc->GetParentDocument()) {
7269 0 : if (!parentDoc) {
7270 0 : return nsnull;
7271 : }
7272 :
7273 0 : aDocument = parentDoc;
7274 : }
7275 :
7276 : // In a child document. Get the appropriate frame.
7277 0 : nsPIDOMWindow* currentWindow = aDocument->GetWindow();
7278 0 : if (!currentWindow) {
7279 0 : return nsnull;
7280 : }
7281 0 : nsIDOMElement* frameElement = currentWindow->GetFrameElementInternal();
7282 0 : if (!frameElement) {
7283 0 : return nsnull;
7284 : }
7285 :
7286 : // Sanity check result
7287 0 : nsCOMPtr<nsIDOMDocument> domDocument;
7288 0 : frameElement->GetOwnerDocument(getter_AddRefs(domDocument));
7289 0 : if (domDocument != this) {
7290 0 : NS_ERROR("Child documents should live in windows the parent owns");
7291 0 : return nsnull;
7292 : }
7293 :
7294 0 : NS_ADDREF(frameElement);
7295 0 : return frameElement;
7296 : }
7297 :
7298 : void
7299 0 : nsDocument::DispatchPageTransition(nsIDOMEventTarget* aDispatchTarget,
7300 : const nsAString& aType,
7301 : bool aPersisted)
7302 : {
7303 0 : if (aDispatchTarget) {
7304 0 : nsCOMPtr<nsIDOMEvent> event;
7305 0 : CreateEvent(NS_LITERAL_STRING("pagetransition"), getter_AddRefs(event));
7306 0 : nsCOMPtr<nsIDOMPageTransitionEvent> ptEvent = do_QueryInterface(event);
7307 0 : nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(ptEvent);
7308 0 : if (pEvent && NS_SUCCEEDED(ptEvent->InitPageTransitionEvent(aType, true,
7309 : true,
7310 : aPersisted))) {
7311 0 : pEvent->SetTrusted(true);
7312 0 : pEvent->SetTarget(this);
7313 : nsEventDispatcher::DispatchDOMEvent(aDispatchTarget, nsnull, event,
7314 0 : nsnull, nsnull);
7315 : }
7316 : }
7317 0 : }
7318 :
7319 : static bool
7320 0 : NotifyPageShow(nsIDocument* aDocument, void* aData)
7321 : {
7322 0 : const bool* aPersistedPtr = static_cast<const bool*>(aData);
7323 0 : aDocument->OnPageShow(*aPersistedPtr, nsnull);
7324 0 : return true;
7325 : }
7326 :
7327 : void
7328 0 : nsDocument::OnPageShow(bool aPersisted,
7329 : nsIDOMEventTarget* aDispatchStartTarget)
7330 : {
7331 0 : mVisible = true;
7332 :
7333 0 : EnumerateFreezableElements(NotifyActivityChanged, nsnull);
7334 0 : EnumerateExternalResources(NotifyPageShow, &aPersisted);
7335 :
7336 0 : Element* root = GetRootElement();
7337 0 : if (aPersisted && root) {
7338 : // Send out notifications that our <link> elements are attached.
7339 : nsRefPtr<nsContentList> links = NS_GetContentList(root,
7340 : kNameSpaceID_Unknown,
7341 0 : NS_LITERAL_STRING("link"));
7342 :
7343 0 : PRUint32 linkCount = links->Length(true);
7344 0 : for (PRUint32 i = 0; i < linkCount; ++i) {
7345 0 : nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, false));
7346 0 : if (link) {
7347 0 : link->LinkAdded();
7348 : }
7349 : }
7350 : }
7351 :
7352 : // See nsIDocument
7353 0 : if (!aDispatchStartTarget) {
7354 : // Set mIsShowing before firing events, in case those event handlers
7355 : // move us around.
7356 0 : mIsShowing = true;
7357 : }
7358 :
7359 0 : if (mAnimationController) {
7360 0 : mAnimationController->OnPageShow();
7361 : }
7362 :
7363 0 : if (aPersisted) {
7364 0 : SetImagesNeedAnimating(true);
7365 : }
7366 :
7367 0 : UpdateVisibilityState();
7368 :
7369 0 : nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
7370 0 : if (!target) {
7371 0 : target = do_QueryInterface(GetWindow());
7372 : }
7373 0 : DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted);
7374 0 : }
7375 :
7376 : static bool
7377 0 : NotifyPageHide(nsIDocument* aDocument, void* aData)
7378 : {
7379 0 : const bool* aPersistedPtr = static_cast<const bool*>(aData);
7380 0 : aDocument->OnPageHide(*aPersistedPtr, nsnull);
7381 0 : return true;
7382 : }
7383 :
7384 : void
7385 0 : nsDocument::OnPageHide(bool aPersisted,
7386 : nsIDOMEventTarget* aDispatchStartTarget)
7387 : {
7388 : // Send out notifications that our <link> elements are detached,
7389 : // but only if this is not a full unload.
7390 0 : Element* root = GetRootElement();
7391 0 : if (aPersisted && root) {
7392 : nsRefPtr<nsContentList> links = NS_GetContentList(root,
7393 : kNameSpaceID_Unknown,
7394 0 : NS_LITERAL_STRING("link"));
7395 :
7396 0 : PRUint32 linkCount = links->Length(true);
7397 0 : for (PRUint32 i = 0; i < linkCount; ++i) {
7398 0 : nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, false));
7399 0 : if (link) {
7400 0 : link->LinkRemoved();
7401 : }
7402 : }
7403 : }
7404 :
7405 : // See nsIDocument
7406 0 : if (!aDispatchStartTarget) {
7407 : // Set mIsShowing before firing events, in case those event handlers
7408 : // move us around.
7409 0 : mIsShowing = false;
7410 : }
7411 :
7412 0 : if (mAnimationController) {
7413 0 : mAnimationController->OnPageHide();
7414 : }
7415 :
7416 0 : if (aPersisted) {
7417 0 : SetImagesNeedAnimating(false);
7418 : }
7419 :
7420 : // Now send out a PageHide event.
7421 0 : nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
7422 0 : if (!target) {
7423 0 : target = do_QueryInterface(GetWindow());
7424 : }
7425 0 : DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
7426 :
7427 0 : mVisible = false;
7428 :
7429 0 : UpdateVisibilityState();
7430 :
7431 0 : EnumerateExternalResources(NotifyPageHide, &aPersisted);
7432 0 : EnumerateFreezableElements(NotifyActivityChanged, nsnull);
7433 :
7434 0 : if (IsFullScreenDoc()) {
7435 : // A full-screen doc has been hidden. We need to ensure we exit
7436 : // full-screen, i.e. remove full-screen state from all full-screen
7437 : // documents, and exit the top-level window from full-screen mode.
7438 : // By the time a doc is hidden, it has been removed from the doc tree,
7439 : // so nsIDocument::ExitFullScreen() won't be able to traverse to this
7440 : // document to reset its state, so reset full-screen state in *this*
7441 : // document. OnPageHide() is called in every hidden document, so doing
7442 : // this ensures all hidden documents have their full-screen state reset.
7443 0 : ClearFullScreenStack();
7444 :
7445 : // Next reset full-screen state in all visible documents in the doctree.
7446 0 : nsIDocument::ExitFullScreen(false);
7447 : }
7448 0 : }
7449 :
7450 : void
7451 36 : nsDocument::WillDispatchMutationEvent(nsINode* aTarget)
7452 : {
7453 36 : NS_ASSERTION(mSubtreeModifiedDepth != 0 ||
7454 : mSubtreeModifiedTargets.Count() == 0,
7455 : "mSubtreeModifiedTargets not cleared after dispatching?");
7456 36 : ++mSubtreeModifiedDepth;
7457 36 : if (aTarget) {
7458 : // MayDispatchMutationEvent is often called just before this method,
7459 : // so it has already appended the node to mSubtreeModifiedTargets.
7460 2 : PRInt32 count = mSubtreeModifiedTargets.Count();
7461 2 : if (!count || mSubtreeModifiedTargets[count - 1] != aTarget) {
7462 2 : mSubtreeModifiedTargets.AppendObject(aTarget);
7463 : }
7464 : }
7465 36 : }
7466 :
7467 : void
7468 36 : nsDocument::MutationEventDispatched(nsINode* aTarget)
7469 : {
7470 36 : --mSubtreeModifiedDepth;
7471 36 : if (mSubtreeModifiedDepth == 0) {
7472 36 : PRInt32 count = mSubtreeModifiedTargets.Count();
7473 36 : if (!count) {
7474 4 : return;
7475 : }
7476 :
7477 64 : nsCOMPtr<nsPIDOMWindow> window;
7478 32 : window = do_QueryInterface(GetScriptGlobalObject());
7479 32 : if (window &&
7480 32 : !window->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) {
7481 0 : mSubtreeModifiedTargets.Clear();
7482 : return;
7483 : }
7484 :
7485 64 : nsCOMArray<nsINode> realTargets;
7486 123 : for (PRInt32 i = 0; i < count; ++i) {
7487 91 : nsINode* possibleTarget = mSubtreeModifiedTargets[i];
7488 182 : nsCOMPtr<nsIContent> content = do_QueryInterface(possibleTarget);
7489 91 : if (content && content->IsInNativeAnonymousSubtree()) {
7490 0 : continue;
7491 : }
7492 :
7493 91 : nsINode* commonAncestor = nsnull;
7494 91 : PRInt32 realTargetCount = realTargets.Count();
7495 116 : for (PRInt32 j = 0; j < realTargetCount; ++j) {
7496 : commonAncestor =
7497 74 : nsContentUtils::GetCommonAncestor(possibleTarget, realTargets[j]);
7498 74 : if (commonAncestor) {
7499 49 : realTargets.ReplaceObjectAt(commonAncestor, j);
7500 49 : break;
7501 : }
7502 : }
7503 91 : if (!commonAncestor) {
7504 42 : realTargets.AppendObject(possibleTarget);
7505 : }
7506 : }
7507 :
7508 32 : mSubtreeModifiedTargets.Clear();
7509 :
7510 32 : PRInt32 realTargetCount = realTargets.Count();
7511 74 : for (PRInt32 k = 0; k < realTargetCount; ++k) {
7512 84 : nsMutationEvent mutation(true, NS_MUTATION_SUBTREEMODIFIED);
7513 84 : (new nsAsyncDOMEvent(realTargets[k], mutation))->RunDOMEventWhenSafe();
7514 : }
7515 : }
7516 : }
7517 :
7518 : void
7519 0 : nsDocument::AddStyleRelevantLink(Link* aLink)
7520 : {
7521 0 : NS_ASSERTION(aLink, "Passing in a null link. Expect crashes RSN!");
7522 : #ifdef DEBUG
7523 0 : nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
7524 0 : NS_ASSERTION(!entry, "Document already knows about this Link!");
7525 0 : mStyledLinksCleared = false;
7526 : #endif
7527 0 : (void)mStyledLinks.PutEntry(aLink);
7528 0 : }
7529 :
7530 : void
7531 0 : nsDocument::ForgetLink(Link* aLink)
7532 : {
7533 0 : NS_ASSERTION(aLink, "Passing in a null link. Expect crashes RSN!");
7534 : #ifdef DEBUG
7535 0 : nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
7536 0 : NS_ASSERTION(entry || mStyledLinksCleared,
7537 : "Document knows nothing about this Link!");
7538 : #endif
7539 0 : (void)mStyledLinks.RemoveEntry(aLink);
7540 0 : }
7541 :
7542 : void
7543 1750 : nsDocument::DestroyElementMaps()
7544 : {
7545 : #ifdef DEBUG
7546 1750 : mStyledLinksCleared = true;
7547 : #endif
7548 1750 : mStyledLinks.Clear();
7549 1750 : mIdentifierMap.Clear();
7550 1750 : }
7551 :
7552 : static
7553 : PLDHashOperator
7554 0 : EnumerateStyledLinks(nsPtrHashKey<Link>* aEntry, void* aArray)
7555 : {
7556 0 : LinkArray* array = static_cast<LinkArray*>(aArray);
7557 0 : (void)array->AppendElement(aEntry->GetKey());
7558 0 : return PL_DHASH_NEXT;
7559 : }
7560 :
7561 : void
7562 1508 : nsDocument::RefreshLinkHrefs()
7563 : {
7564 : // Get a list of all links we know about. We will reset them, which will
7565 : // remove them from the document, so we need a copy of what is in the
7566 : // hashtable.
7567 3016 : LinkArray linksToNotify(mStyledLinks.Count());
7568 1508 : (void)mStyledLinks.EnumerateEntries(EnumerateStyledLinks, &linksToNotify);
7569 :
7570 : // Reset all of our styled links.
7571 3016 : nsAutoScriptBlocker scriptBlocker;
7572 1508 : for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) {
7573 0 : linksToNotify[i]->ResetLinkState(true);
7574 : }
7575 1508 : }
7576 :
7577 : nsresult
7578 0 : nsDocument::CloneDocHelper(nsDocument* clone) const
7579 : {
7580 0 : clone->mIsStaticDocument = mCreatingStaticClone;
7581 :
7582 : // Init document
7583 0 : nsresult rv = clone->Init();
7584 0 : NS_ENSURE_SUCCESS(rv, rv);
7585 :
7586 : // Set URI/principal
7587 0 : clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
7588 : // Must set the principal first, since SetBaseURI checks it.
7589 0 : clone->SetPrincipal(NodePrincipal());
7590 0 : clone->mDocumentBaseURI = mDocumentBaseURI;
7591 :
7592 0 : if (mCreatingStaticClone) {
7593 0 : nsCOMPtr<nsIChannel> channel = GetChannel();
7594 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
7595 0 : if (channel && loadGroup) {
7596 0 : clone->Reset(channel, loadGroup);
7597 : } else {
7598 0 : nsIURI* uri = static_cast<const nsIDocument*>(this)->GetDocumentURI();
7599 0 : if (uri) {
7600 0 : clone->ResetToURI(uri, loadGroup, NodePrincipal());
7601 : }
7602 : }
7603 0 : nsCOMPtr<nsISupports> container = GetContainer();
7604 0 : clone->SetContainer(container);
7605 : }
7606 :
7607 : // Set scripting object
7608 0 : bool hasHadScriptObject = true;
7609 : nsIScriptGlobalObject* scriptObject =
7610 0 : GetScriptHandlingObject(hasHadScriptObject);
7611 0 : NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
7612 0 : clone->SetScriptHandlingObject(scriptObject);
7613 :
7614 : // Make the clone a data document
7615 0 : clone->SetLoadedAsData(true);
7616 :
7617 : // Misc state
7618 :
7619 : // State from nsIDocument
7620 0 : clone->mCharacterSet = mCharacterSet;
7621 0 : clone->mCharacterSetSource = mCharacterSetSource;
7622 0 : clone->mCompatMode = mCompatMode;
7623 0 : clone->mBidiOptions = mBidiOptions;
7624 0 : clone->mContentLanguage = mContentLanguage;
7625 0 : clone->SetContentTypeInternal(GetContentTypeInternal());
7626 0 : clone->mSecurityInfo = mSecurityInfo;
7627 :
7628 : // State from nsDocument
7629 0 : clone->mIsRegularHTML = mIsRegularHTML;
7630 0 : clone->mXMLDeclarationBits = mXMLDeclarationBits;
7631 0 : clone->mBaseTarget = mBaseTarget;
7632 0 : return NS_OK;
7633 : }
7634 :
7635 : void
7636 4325 : nsDocument::SetReadyStateInternal(ReadyState rs)
7637 : {
7638 4325 : mReadyState = rs;
7639 4325 : if (mTiming) {
7640 0 : switch (rs) {
7641 : case READYSTATE_LOADING:
7642 0 : mTiming->NotifyDOMLoading(nsIDocument::GetDocumentURI());
7643 0 : break;
7644 : case READYSTATE_INTERACTIVE:
7645 0 : mTiming->NotifyDOMInteractive(nsIDocument::GetDocumentURI());
7646 0 : break;
7647 : case READYSTATE_COMPLETE:
7648 0 : mTiming->NotifyDOMComplete(nsIDocument::GetDocumentURI());
7649 0 : break;
7650 : default:
7651 0 : NS_WARNING("Unexpected ReadyState value");
7652 0 : break;
7653 : }
7654 : }
7655 : // At the time of loading start, we don't have timing object, record time.
7656 4325 : if (READYSTATE_LOADING == rs) {
7657 1038 : mLoadingTimeStamp = mozilla::TimeStamp::Now();
7658 : }
7659 :
7660 : nsRefPtr<nsAsyncDOMEvent> plevent =
7661 12975 : new nsAsyncDOMEvent(this, NS_LITERAL_STRING("readystatechange"), false, false);
7662 4325 : if (plevent) {
7663 4325 : plevent->RunDOMEventWhenSafe();
7664 : }
7665 4325 : }
7666 :
7667 : nsIDocument::ReadyState
7668 0 : nsDocument::GetReadyStateEnum()
7669 : {
7670 0 : return mReadyState;
7671 : }
7672 :
7673 : NS_IMETHODIMP
7674 0 : nsDocument::GetReadyState(nsAString& aReadyState)
7675 : {
7676 0 : switch(mReadyState) {
7677 : case READYSTATE_LOADING :
7678 0 : aReadyState.Assign(NS_LITERAL_STRING("loading"));
7679 0 : break;
7680 : case READYSTATE_INTERACTIVE :
7681 0 : aReadyState.Assign(NS_LITERAL_STRING("interactive"));
7682 0 : break;
7683 : case READYSTATE_COMPLETE :
7684 0 : aReadyState.Assign(NS_LITERAL_STRING("complete"));
7685 0 : break;
7686 : default:
7687 0 : aReadyState.Assign(NS_LITERAL_STRING("uninitialized"));
7688 : }
7689 0 : return NS_OK;
7690 : }
7691 :
7692 : static bool
7693 0 : SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
7694 : {
7695 0 : aDocument->SuppressEventHandling(*static_cast<PRUint32*>(aData));
7696 0 : return true;
7697 : }
7698 :
7699 : void
7700 0 : nsDocument::SuppressEventHandling(PRUint32 aIncrease)
7701 : {
7702 0 : if (mEventsSuppressed == 0 && aIncrease != 0 && mPresShell &&
7703 0 : mScriptGlobalObject) {
7704 0 : RevokeAnimationFrameNotifications();
7705 : }
7706 0 : mEventsSuppressed += aIncrease;
7707 0 : EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
7708 0 : }
7709 :
7710 : static void
7711 0 : FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
7712 : bool aFireEvents)
7713 : {
7714 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
7715 0 : if (!fm)
7716 0 : return;
7717 :
7718 0 : for (PRUint32 i = 0; i < aDocuments.Length(); ++i) {
7719 0 : if (!aDocuments[i]->EventHandlingSuppressed()) {
7720 0 : fm->FireDelayedEvents(aDocuments[i]);
7721 0 : nsCOMPtr<nsIPresShell> shell = aDocuments[i]->GetShell();
7722 0 : if (shell) {
7723 0 : shell->FireOrClearDelayedEvents(aFireEvents);
7724 : }
7725 : }
7726 : }
7727 : }
7728 :
7729 : void
7730 0 : nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr)
7731 : {
7732 : // Early exit if the img is already present in the img-cache
7733 : // which indicates that the "real" load has already started and
7734 : // that we shouldn't preload it.
7735 : PRInt16 blockingStatus;
7736 0 : if (nsContentUtils::IsImageInCache(uri) ||
7737 : !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
7738 0 : this, NodePrincipal(), &blockingStatus)) {
7739 0 : return;
7740 : }
7741 :
7742 0 : nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
7743 0 : switch (nsGenericElement::StringToCORSMode(aCrossOriginAttr)) {
7744 : case CORS_NONE:
7745 : // Nothing to do
7746 0 : break;
7747 : case CORS_ANONYMOUS:
7748 0 : loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
7749 0 : break;
7750 : case CORS_USE_CREDENTIALS:
7751 0 : loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
7752 0 : break;
7753 : default:
7754 : /* should never happen */
7755 0 : MOZ_NOT_REACHED("Unknown CORS mode!");
7756 : }
7757 :
7758 : // Image not in cache - trigger preload
7759 0 : nsCOMPtr<imgIRequest> request;
7760 : nsresult rv =
7761 : nsContentUtils::LoadImage(uri,
7762 : this,
7763 : NodePrincipal(),
7764 : mDocumentURI, // uri of document used as referrer
7765 : nsnull, // no observer
7766 : loadFlags,
7767 0 : getter_AddRefs(request));
7768 :
7769 : // Pin image-reference to avoid evicting it from the img-cache before
7770 : // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
7771 : // unlink
7772 0 : if (NS_SUCCEEDED(rv)) {
7773 0 : mPreloadingImages.AppendObject(request);
7774 : }
7775 : }
7776 :
7777 : nsEventStates
7778 0 : nsDocument::GetDocumentState()
7779 : {
7780 0 : if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_RTL_LOCALE)) {
7781 0 : if (IsDocumentRightToLeft()) {
7782 0 : mDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
7783 : }
7784 0 : mGotDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
7785 : }
7786 0 : if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
7787 0 : nsIPresShell* shell = GetShell();
7788 0 : if (shell && shell->GetPresContext() &&
7789 0 : shell->GetPresContext()->IsTopLevelWindowInactive()) {
7790 0 : mDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
7791 : }
7792 0 : mGotDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
7793 : }
7794 0 : return mDocumentState;
7795 : }
7796 :
7797 : namespace {
7798 :
7799 : /**
7800 : * Stub for LoadSheet(), since all we want is to get the sheet into
7801 : * the CSSLoader's style cache
7802 : */
7803 0 : class StubCSSLoaderObserver : public nsICSSLoaderObserver {
7804 : public:
7805 : NS_IMETHOD
7806 0 : StyleSheetLoaded(nsCSSStyleSheet*, bool, nsresult)
7807 : {
7808 0 : return NS_OK;
7809 : }
7810 : NS_DECL_ISUPPORTS
7811 : };
7812 0 : NS_IMPL_ISUPPORTS1(StubCSSLoaderObserver, nsICSSLoaderObserver)
7813 :
7814 : }
7815 :
7816 : void
7817 0 : nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset)
7818 : {
7819 : // The CSSLoader will retain this object after we return.
7820 0 : nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
7821 :
7822 : // Charset names are always ASCII.
7823 : CSSLoader()->LoadSheet(uri, NodePrincipal(),
7824 0 : NS_LossyConvertUTF16toASCII(charset),
7825 0 : obs);
7826 0 : }
7827 :
7828 : nsresult
7829 0 : nsDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
7830 : nsCSSStyleSheet** sheet)
7831 : {
7832 0 : return CSSLoader()->LoadSheetSync(uri, isAgentSheet, isAgentSheet, sheet);
7833 : }
7834 :
7835 : class nsDelayedEventDispatcher : public nsRunnable
7836 : {
7837 : public:
7838 0 : nsDelayedEventDispatcher(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments)
7839 0 : {
7840 0 : mDocuments.SwapElements(aDocuments);
7841 0 : }
7842 0 : virtual ~nsDelayedEventDispatcher() {}
7843 :
7844 0 : NS_IMETHOD Run()
7845 : {
7846 0 : FireOrClearDelayedEvents(mDocuments, true);
7847 0 : return NS_OK;
7848 : }
7849 :
7850 : private:
7851 : nsTArray<nsCOMPtr<nsIDocument> > mDocuments;
7852 : };
7853 :
7854 : static bool
7855 0 : GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
7856 : {
7857 0 : PRUint32 suppression = aDocument->EventHandlingSuppressed();
7858 0 : if (suppression > 0) {
7859 0 : static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
7860 : }
7861 : nsTArray<nsCOMPtr<nsIDocument> >* docs =
7862 0 : static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
7863 0 : docs->AppendElement(aDocument);
7864 0 : aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, docs);
7865 0 : return true;
7866 : }
7867 :
7868 : void
7869 0 : nsDocument::UnsuppressEventHandlingAndFireEvents(bool aFireEvents)
7870 : {
7871 0 : nsTArray<nsCOMPtr<nsIDocument> > documents;
7872 0 : GetAndUnsuppressSubDocuments(this, &documents);
7873 :
7874 0 : if (aFireEvents) {
7875 0 : NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(documents));
7876 : } else {
7877 0 : FireOrClearDelayedEvents(documents, false);
7878 : }
7879 0 : }
7880 :
7881 : nsISupports*
7882 0 : nsDocument::GetCurrentContentSink()
7883 : {
7884 0 : return mParser ? mParser->GetContentSink() : nsnull;
7885 : }
7886 :
7887 : void
7888 0 : nsDocument::RegisterFileDataUri(const nsACString& aUri)
7889 : {
7890 0 : mFileDataUris.AppendElement(aUri);
7891 0 : }
7892 :
7893 : void
7894 0 : nsDocument::UnregisterFileDataUri(const nsACString& aUri)
7895 : {
7896 0 : mFileDataUris.RemoveElement(aUri);
7897 0 : }
7898 :
7899 : void
7900 1050 : nsDocument::SetScrollToRef(nsIURI *aDocumentURI)
7901 : {
7902 1050 : if (!aDocumentURI) {
7903 0 : return;
7904 : }
7905 :
7906 2100 : nsCAutoString ref;
7907 :
7908 : // Since all URI's that pass through here aren't URL's we can't
7909 : // rely on the nsIURI implementation for providing a way for
7910 : // finding the 'ref' part of the URI, we'll haveto revert to
7911 : // string routines for finding the data past '#'
7912 :
7913 1050 : aDocumentURI->GetSpec(ref);
7914 :
7915 1050 : nsReadingIterator<char> start, end;
7916 :
7917 1050 : ref.BeginReading(start);
7918 1050 : ref.EndReading(end);
7919 :
7920 1050 : if (FindCharInReadable('#', start, end)) {
7921 0 : ++start; // Skip over the '#'
7922 :
7923 0 : mScrollToRef = Substring(start, end);
7924 : }
7925 : }
7926 :
7927 : void
7928 1038 : nsDocument::ScrollToRef()
7929 : {
7930 1038 : if (mScrolledToRefAlready) {
7931 0 : return;
7932 : }
7933 :
7934 1038 : if (mScrollToRef.IsEmpty()) {
7935 1038 : return;
7936 : }
7937 :
7938 0 : char* tmpstr = ToNewCString(mScrollToRef);
7939 0 : if (!tmpstr) {
7940 0 : return;
7941 : }
7942 :
7943 0 : nsUnescape(tmpstr);
7944 0 : nsCAutoString unescapedRef;
7945 0 : unescapedRef.Assign(tmpstr);
7946 0 : nsMemory::Free(tmpstr);
7947 :
7948 0 : nsresult rv = NS_ERROR_FAILURE;
7949 : // We assume that the bytes are in UTF-8, as it says in the spec:
7950 : // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
7951 0 : NS_ConvertUTF8toUTF16 ref(unescapedRef);
7952 :
7953 0 : nsCOMPtr<nsIPresShell> shell = GetShell();
7954 0 : if (shell) {
7955 : // Check an empty string which might be caused by the UTF-8 conversion
7956 0 : if (!ref.IsEmpty()) {
7957 : // Note that GoToAnchor will handle flushing layout as needed.
7958 0 : rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
7959 : } else {
7960 0 : rv = NS_ERROR_FAILURE;
7961 : }
7962 :
7963 : // If UTF-8 URI failed then try to assume the string as a
7964 : // document's charset.
7965 :
7966 0 : if (NS_FAILED(rv)) {
7967 0 : const nsACString &docCharset = GetDocumentCharacterSet();
7968 :
7969 0 : rv = nsContentUtils::ConvertStringFromCharset(docCharset, unescapedRef, ref);
7970 :
7971 0 : if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
7972 0 : rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
7973 : }
7974 : }
7975 0 : if (NS_SUCCEEDED(rv)) {
7976 0 : mScrolledToRefAlready = true;
7977 : }
7978 : }
7979 : }
7980 :
7981 : void
7982 1038 : nsDocument::ResetScrolledToRefAlready()
7983 : {
7984 1038 : mScrolledToRefAlready = false;
7985 1038 : }
7986 :
7987 : void
7988 0 : nsDocument::SetChangeScrollPosWhenScrollingToRef(bool aValue)
7989 : {
7990 0 : mChangeScrollPosWhenScrollingToRef = aValue;
7991 0 : }
7992 :
7993 : void
7994 0 : nsIDocument::RegisterFreezableElement(nsIContent* aContent)
7995 : {
7996 0 : if (!mFreezableElements) {
7997 0 : mFreezableElements = new nsTHashtable<nsPtrHashKey<nsIContent> >();
7998 0 : if (!mFreezableElements)
7999 0 : return;
8000 0 : mFreezableElements->Init();
8001 : }
8002 0 : mFreezableElements->PutEntry(aContent);
8003 : }
8004 :
8005 : bool
8006 0 : nsIDocument::UnregisterFreezableElement(nsIContent* aContent)
8007 : {
8008 0 : if (!mFreezableElements)
8009 0 : return false;
8010 0 : if (!mFreezableElements->GetEntry(aContent))
8011 0 : return false;
8012 0 : mFreezableElements->RemoveEntry(aContent);
8013 0 : return true;
8014 : }
8015 :
8016 : struct EnumerateFreezablesData {
8017 : nsIDocument::FreezableElementEnumerator mEnumerator;
8018 : void* mData;
8019 : };
8020 :
8021 : static PLDHashOperator
8022 0 : EnumerateFreezables(nsPtrHashKey<nsIContent>* aEntry, void* aData)
8023 : {
8024 0 : EnumerateFreezablesData* data = static_cast<EnumerateFreezablesData*>(aData);
8025 0 : data->mEnumerator(aEntry->GetKey(), data->mData);
8026 0 : return PL_DHASH_NEXT;
8027 : }
8028 :
8029 : void
8030 0 : nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
8031 : void* aData)
8032 : {
8033 0 : if (!mFreezableElements)
8034 0 : return;
8035 0 : EnumerateFreezablesData data = { aEnumerator, aData };
8036 0 : mFreezableElements->EnumerateEntries(EnumerateFreezables, &data);
8037 : }
8038 :
8039 : void
8040 0 : nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
8041 : {
8042 0 : mLinksToUpdate.PutEntry(aLink);
8043 0 : mHasLinksToUpdate = true;
8044 0 : }
8045 :
8046 : void
8047 0 : nsIDocument::UnregisterPendingLinkUpdate(Link* aLink)
8048 : {
8049 0 : if (!mHasLinksToUpdate)
8050 0 : return;
8051 :
8052 0 : mLinksToUpdate.RemoveEntry(aLink);
8053 : }
8054 :
8055 : static PLDHashOperator
8056 0 : EnumeratePendingLinkUpdates(nsPtrHashKey<Link>* aEntry, void* aData)
8057 : {
8058 0 : aEntry->GetKey()->GetElement()->UpdateLinkState(aEntry->GetKey()->LinkState());
8059 0 : return PL_DHASH_NEXT;
8060 : }
8061 :
8062 : void
8063 110 : nsIDocument::FlushPendingLinkUpdates()
8064 : {
8065 110 : if (!mHasLinksToUpdate)
8066 110 : return;
8067 :
8068 0 : nsAutoScriptBlocker scriptBlocker;
8069 0 : mLinksToUpdate.EnumerateEntries(EnumeratePendingLinkUpdates, nsnull);
8070 0 : mLinksToUpdate.Clear();
8071 0 : mHasLinksToUpdate = false;
8072 : }
8073 :
8074 : already_AddRefed<nsIDocument>
8075 0 : nsIDocument::CreateStaticClone(nsISupports* aCloneContainer)
8076 : {
8077 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(this);
8078 0 : NS_ENSURE_TRUE(domDoc, nsnull);
8079 0 : mCreatingStaticClone = true;
8080 :
8081 : // Make document use different container during cloning.
8082 0 : nsCOMPtr<nsISupports> originalContainer = GetContainer();
8083 0 : SetContainer(aCloneContainer);
8084 0 : nsCOMPtr<nsIDOMNode> clonedNode;
8085 0 : nsresult rv = domDoc->CloneNode(true, 1, getter_AddRefs(clonedNode));
8086 0 : SetContainer(originalContainer);
8087 :
8088 0 : nsCOMPtr<nsIDocument> clonedDoc;
8089 0 : if (NS_SUCCEEDED(rv)) {
8090 0 : clonedDoc = do_QueryInterface(clonedNode);
8091 0 : if (clonedDoc) {
8092 0 : if (IsStaticDocument()) {
8093 0 : clonedDoc->mOriginalDocument = mOriginalDocument;
8094 : } else {
8095 0 : clonedDoc->mOriginalDocument = this;
8096 : }
8097 0 : PRInt32 sheetsCount = GetNumberOfStyleSheets();
8098 0 : for (PRInt32 i = 0; i < sheetsCount; ++i) {
8099 0 : nsRefPtr<nsCSSStyleSheet> sheet = do_QueryObject(GetStyleSheetAt(i));
8100 0 : if (sheet) {
8101 0 : if (sheet->IsApplicable()) {
8102 : nsRefPtr<nsCSSStyleSheet> clonedSheet =
8103 0 : sheet->Clone(nsnull, nsnull, clonedDoc, nsnull);
8104 0 : NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!");
8105 0 : if (clonedSheet) {
8106 0 : clonedDoc->AddStyleSheet(clonedSheet);
8107 : }
8108 : }
8109 : }
8110 : }
8111 :
8112 0 : sheetsCount = GetNumberOfCatalogStyleSheets();
8113 0 : for (PRInt32 i = 0; i < sheetsCount; ++i) {
8114 : nsRefPtr<nsCSSStyleSheet> sheet =
8115 0 : do_QueryObject(GetCatalogStyleSheetAt(i));
8116 0 : if (sheet) {
8117 0 : if (sheet->IsApplicable()) {
8118 : nsRefPtr<nsCSSStyleSheet> clonedSheet =
8119 0 : sheet->Clone(nsnull, nsnull, clonedDoc, nsnull);
8120 0 : NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!");
8121 0 : if (clonedSheet) {
8122 0 : clonedDoc->AddCatalogStyleSheet(clonedSheet);
8123 : }
8124 : }
8125 : }
8126 : }
8127 : }
8128 : }
8129 0 : mCreatingStaticClone = false;
8130 0 : return clonedDoc.forget();
8131 : }
8132 :
8133 : nsresult
8134 0 : nsIDocument::ScheduleFrameRequestCallback(nsIFrameRequestCallback* aCallback,
8135 : PRInt32 *aHandle)
8136 : {
8137 0 : if (mFrameRequestCallbackCounter == PR_INT32_MAX) {
8138 : // Can't increment without overflowing; bail out
8139 0 : return NS_ERROR_NOT_AVAILABLE;
8140 : }
8141 0 : PRInt32 newHandle = ++mFrameRequestCallbackCounter;
8142 :
8143 0 : bool alreadyRegistered = !mFrameRequestCallbacks.IsEmpty();
8144 : DebugOnly<FrameRequest*> request =
8145 0 : mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
8146 0 : NS_ASSERTION(request, "This is supposed to be infallible!");
8147 0 : if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled()) {
8148 : mPresShell->GetPresContext()->RefreshDriver()->
8149 0 : ScheduleFrameRequestCallbacks(this);
8150 : }
8151 :
8152 0 : *aHandle = newHandle;
8153 0 : return NS_OK;
8154 : }
8155 :
8156 : void
8157 0 : nsIDocument::CancelFrameRequestCallback(PRInt32 aHandle)
8158 : {
8159 : // mFrameRequestCallbacks is stored sorted by handle
8160 0 : if (mFrameRequestCallbacks.RemoveElementSorted(aHandle) &&
8161 0 : mFrameRequestCallbacks.IsEmpty() &&
8162 0 : mPresShell && IsEventHandlingEnabled()) {
8163 : mPresShell->GetPresContext()->RefreshDriver()->
8164 0 : RevokeFrameRequestCallbacks(this);
8165 : }
8166 0 : }
8167 :
8168 : nsresult
8169 0 : nsDocument::GetStateObject(nsIVariant** aState)
8170 : {
8171 : // Get the document's current state object. This is the object backing both
8172 : // history.state and popStateEvent.state.
8173 : //
8174 : // mStateObjectContainer may be null; this just means that there's no
8175 : // current state object.
8176 :
8177 0 : nsCOMPtr<nsIVariant> stateObj;
8178 0 : if (!mStateObjectCached && mStateObjectContainer) {
8179 0 : JSContext *cx = nsContentUtils::GetContextFromDocument(this);
8180 0 : mStateObjectContainer->
8181 0 : DeserializeToVariant(cx, getter_AddRefs(mStateObjectCached));
8182 : }
8183 :
8184 0 : NS_IF_ADDREF(*aState = mStateObjectCached);
8185 :
8186 0 : return NS_OK;
8187 : }
8188 :
8189 : nsDOMNavigationTiming*
8190 0 : nsDocument::GetNavigationTiming() const
8191 : {
8192 0 : return mTiming;
8193 : }
8194 :
8195 : nsresult
8196 0 : nsDocument::SetNavigationTiming(nsDOMNavigationTiming* aTiming)
8197 : {
8198 0 : mTiming = aTiming;
8199 0 : if (!mLoadingTimeStamp.IsNull() && mTiming) {
8200 0 : mTiming->SetDOMLoadingTimeStamp(nsIDocument::GetDocumentURI(), mLoadingTimeStamp);
8201 : }
8202 0 : return NS_OK;
8203 : }
8204 :
8205 : Element*
8206 0 : nsDocument::FindImageMap(const nsAString& aUseMapValue)
8207 : {
8208 0 : if (aUseMapValue.IsEmpty()) {
8209 0 : return nsnull;
8210 : }
8211 :
8212 0 : nsAString::const_iterator start, end;
8213 0 : aUseMapValue.BeginReading(start);
8214 0 : aUseMapValue.EndReading(end);
8215 :
8216 0 : PRInt32 hash = aUseMapValue.FindChar('#');
8217 0 : if (hash < 0) {
8218 0 : return nsnull;
8219 : }
8220 : // aUsemap contains a '#', set start to point right after the '#'
8221 0 : start.advance(hash + 1);
8222 :
8223 0 : if (start == end) {
8224 0 : return nsnull; // aUsemap == "#"
8225 : }
8226 :
8227 0 : const nsAString& mapName = Substring(start, end);
8228 :
8229 0 : if (!mImageMaps) {
8230 0 : mImageMaps = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::map, nsGkAtoms::map);
8231 : }
8232 :
8233 0 : PRUint32 i, n = mImageMaps->Length(true);
8234 0 : for (i = 0; i < n; ++i) {
8235 0 : nsIContent* map = mImageMaps->GetNodeAt(i);
8236 0 : if (map->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, mapName,
8237 0 : eCaseMatters) ||
8238 : map->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, mapName,
8239 0 : eIgnoreCase)) {
8240 0 : return map->AsElement();
8241 : }
8242 : }
8243 :
8244 0 : return nsnull;
8245 : }
8246 :
8247 : #define DEPRECATED_OPERATION(_op) #_op "Warning",
8248 : static const char* kWarnings[] = {
8249 : #include "nsDeprecatedOperationList.h"
8250 : nsnull
8251 : };
8252 : #undef DEPRECATED_OPERATION
8253 :
8254 : void
8255 259 : nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation)
8256 : {
8257 : PR_STATIC_ASSERT(eDeprecatedOperationCount <= 64);
8258 259 : if (mWarnedAbout & (1 << aOperation)) {
8259 254 : return;
8260 : }
8261 5 : mWarnedAbout |= (1 << aOperation);
8262 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
8263 : "DOM Core", this,
8264 : nsContentUtils::eDOM_PROPERTIES,
8265 5 : kWarnings[aOperation]);
8266 : }
8267 :
8268 : nsresult
8269 0 : nsDocument::AddImage(imgIRequest* aImage)
8270 : {
8271 0 : NS_ENSURE_ARG_POINTER(aImage);
8272 :
8273 : // See if the image is already in the hashtable. If it is, get the old count.
8274 0 : PRUint32 oldCount = 0;
8275 0 : mImageTracker.Get(aImage, &oldCount);
8276 :
8277 : // Put the image in the hashtable, with the proper count.
8278 0 : bool success = mImageTracker.Put(aImage, oldCount + 1);
8279 0 : if (!success)
8280 0 : return NS_ERROR_OUT_OF_MEMORY;
8281 :
8282 0 : nsresult rv = NS_OK;
8283 :
8284 : // If this is the first insertion and we're locking images, lock this image
8285 : // too.
8286 0 : if (oldCount == 0 && mLockingImages) {
8287 0 : rv = aImage->LockImage();
8288 0 : if (NS_SUCCEEDED(rv))
8289 0 : rv = aImage->RequestDecode();
8290 : }
8291 :
8292 : // If this is the first insertion and we're animating images, request
8293 : // that this image be animated too.
8294 0 : if (oldCount == 0 && mAnimatingImages) {
8295 0 : nsresult rv2 = aImage->IncrementAnimationConsumers();
8296 0 : rv = NS_SUCCEEDED(rv) ? rv2 : rv;
8297 : }
8298 :
8299 0 : return rv;
8300 : }
8301 :
8302 : static void
8303 0 : NotifyAudioAvailableListener(nsIContent *aContent, void *aUnused)
8304 : {
8305 : #ifdef MOZ_MEDIA
8306 0 : nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
8307 0 : if (domMediaElem) {
8308 0 : nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
8309 0 : mediaElem->NotifyAudioAvailableListener();
8310 : }
8311 : #endif
8312 0 : }
8313 :
8314 : void
8315 0 : nsDocument::NotifyAudioAvailableListener()
8316 : {
8317 0 : mHasAudioAvailableListener = true;
8318 0 : EnumerateFreezableElements(::NotifyAudioAvailableListener, nsnull);
8319 0 : }
8320 :
8321 : nsresult
8322 0 : nsDocument::RemoveImage(imgIRequest* aImage)
8323 : {
8324 0 : NS_ENSURE_ARG_POINTER(aImage);
8325 :
8326 : // Get the old count. It should exist and be > 0.
8327 0 : PRUint32 count = 0;
8328 0 : DebugOnly<bool> found = mImageTracker.Get(aImage, &count);
8329 0 : NS_ABORT_IF_FALSE(found, "Removing image that wasn't in the tracker!");
8330 0 : NS_ABORT_IF_FALSE(count > 0, "Entry in the cache tracker with count 0!");
8331 :
8332 : // We're removing, so decrement the count.
8333 0 : count--;
8334 :
8335 : // If the count is now zero, remove from the tracker.
8336 : // Otherwise, set the new value.
8337 0 : if (count != 0) {
8338 0 : mImageTracker.Put(aImage, count);
8339 0 : return NS_OK;
8340 : }
8341 :
8342 0 : mImageTracker.Remove(aImage);
8343 :
8344 0 : nsresult rv = NS_OK;
8345 :
8346 : // Now that we're no longer tracking this image, unlock it if we'd
8347 : // previously locked it.
8348 0 : if (mLockingImages) {
8349 0 : rv = aImage->UnlockImage();
8350 : }
8351 :
8352 : // If we're animating images, remove our request to animate this one.
8353 0 : if (mAnimatingImages) {
8354 0 : nsresult rv2 = aImage->DecrementAnimationConsumers();
8355 0 : rv = NS_SUCCEEDED(rv) ? rv2 : rv;
8356 : }
8357 :
8358 : // Request that the image be discarded if nobody else holds a lock on it.
8359 : // Do this even if !mLockingImages, because even if we didn't just unlock
8360 : // this image, it might still be a candidate for discarding.
8361 0 : aImage->RequestDiscard();
8362 :
8363 0 : return rv;
8364 : }
8365 :
8366 0 : PLDHashOperator LockEnumerator(imgIRequest* aKey,
8367 : PRUint32 aData,
8368 : void* userArg)
8369 : {
8370 0 : aKey->LockImage();
8371 0 : aKey->RequestDecode();
8372 0 : return PL_DHASH_NEXT;
8373 : }
8374 :
8375 0 : PLDHashOperator UnlockEnumerator(imgIRequest* aKey,
8376 : PRUint32 aData,
8377 : void* userArg)
8378 : {
8379 0 : aKey->UnlockImage();
8380 0 : return PL_DHASH_NEXT;
8381 : }
8382 :
8383 :
8384 : nsresult
8385 1271 : nsDocument::SetImageLockingState(bool aLocked)
8386 : {
8387 1271 : if (XRE_GetProcessType() == GeckoProcessType_Content &&
8388 0 : !Preferences::GetBool("content.image.allow_locking", true)) {
8389 0 : return NS_OK;
8390 : }
8391 :
8392 : // If there's no change, there's nothing to do.
8393 1271 : if (mLockingImages == aLocked)
8394 1271 : return NS_OK;
8395 :
8396 : // Otherwise, iterate over our images and perform the appropriate action.
8397 : mImageTracker.EnumerateRead(aLocked ? LockEnumerator
8398 : : UnlockEnumerator,
8399 0 : nsnull);
8400 :
8401 : // Update state.
8402 0 : mLockingImages = aLocked;
8403 :
8404 0 : return NS_OK;
8405 : }
8406 :
8407 0 : PLDHashOperator IncrementAnimationEnumerator(imgIRequest* aKey,
8408 : PRUint32 aData,
8409 : void* userArg)
8410 : {
8411 0 : aKey->IncrementAnimationConsumers();
8412 0 : return PL_DHASH_NEXT;
8413 : }
8414 :
8415 0 : PLDHashOperator DecrementAnimationEnumerator(imgIRequest* aKey,
8416 : PRUint32 aData,
8417 : void* userArg)
8418 : {
8419 0 : aKey->DecrementAnimationConsumers();
8420 0 : return PL_DHASH_NEXT;
8421 : }
8422 :
8423 : void
8424 0 : nsDocument::SetImagesNeedAnimating(bool aAnimating)
8425 : {
8426 : // If there's no change, there's nothing to do.
8427 0 : if (mAnimatingImages == aAnimating)
8428 0 : return;
8429 :
8430 : // Otherwise, iterate over our images and perform the appropriate action.
8431 : mImageTracker.EnumerateRead(aAnimating ? IncrementAnimationEnumerator
8432 : : DecrementAnimationEnumerator,
8433 0 : nsnull);
8434 :
8435 : // Update state.
8436 0 : mAnimatingImages = aAnimating;
8437 : }
8438 :
8439 : NS_IMETHODIMP
8440 0 : nsDocument::CreateTouch(nsIDOMWindow* aView,
8441 : nsIDOMEventTarget* aTarget,
8442 : PRInt32 aIdentifier,
8443 : PRInt32 aPageX,
8444 : PRInt32 aPageY,
8445 : PRInt32 aScreenX,
8446 : PRInt32 aScreenY,
8447 : PRInt32 aClientX,
8448 : PRInt32 aClientY,
8449 : PRInt32 aRadiusX,
8450 : PRInt32 aRadiusY,
8451 : float aRotationAngle,
8452 : float aForce,
8453 : nsIDOMTouch** aRetVal)
8454 : {
8455 0 : NS_ADDREF(*aRetVal = new nsDOMTouch(aTarget,
8456 : aIdentifier,
8457 : aPageX,
8458 : aPageY,
8459 : aScreenX,
8460 : aScreenY,
8461 : aClientX,
8462 : aClientY,
8463 : aRadiusX,
8464 : aRadiusY,
8465 : aRotationAngle,
8466 0 : aForce));
8467 0 : return NS_OK;
8468 : }
8469 :
8470 : NS_IMETHODIMP
8471 0 : nsDocument::CreateTouchList(nsIVariant* aPoints,
8472 : nsIDOMTouchList** aRetVal)
8473 : {
8474 0 : nsRefPtr<nsDOMTouchList> retval = new nsDOMTouchList();
8475 0 : if (aPoints) {
8476 : PRUint16 type;
8477 0 : aPoints->GetDataType(&type);
8478 0 : if (type == nsIDataType::VTYPE_INTERFACE ||
8479 : type == nsIDataType::VTYPE_INTERFACE_IS) {
8480 0 : nsCOMPtr<nsISupports> data;
8481 0 : aPoints->GetAsISupports(getter_AddRefs(data));
8482 0 : nsCOMPtr<nsIDOMTouch> point = do_QueryInterface(data);
8483 0 : if (point) {
8484 0 : retval->Append(point);
8485 0 : }
8486 0 : } else if (type == nsIDataType::VTYPE_ARRAY) {
8487 : PRUint16 valueType;
8488 : nsIID iid;
8489 : PRUint32 valueCount;
8490 : void* rawArray;
8491 0 : aPoints->GetAsArray(&valueType, &iid, &valueCount, &rawArray);
8492 0 : if (valueType == nsIDataType::VTYPE_INTERFACE ||
8493 : valueType == nsIDataType::VTYPE_INTERFACE_IS) {
8494 0 : nsISupports** values = static_cast<nsISupports**>(rawArray);
8495 0 : for (PRUint32 i = 0; i < valueCount; ++i) {
8496 0 : nsCOMPtr<nsISupports> supports = dont_AddRef(values[i]);
8497 0 : nsCOMPtr<nsIDOMTouch> point = do_QueryInterface(supports);
8498 0 : if (point) {
8499 0 : retval->Append(point);
8500 : }
8501 : }
8502 : }
8503 0 : nsMemory::Free(rawArray);
8504 : }
8505 : }
8506 :
8507 0 : *aRetVal = retval.forget().get();
8508 0 : return NS_OK;
8509 : }
8510 :
8511 : static void
8512 0 : DispatchFullScreenChange(nsIDocument* aTarget)
8513 : {
8514 : nsRefPtr<nsAsyncDOMEvent> e =
8515 : new nsAsyncDOMEvent(aTarget,
8516 0 : NS_LITERAL_STRING("mozfullscreenchange"),
8517 : true,
8518 0 : false);
8519 0 : e->PostDOMEvent();
8520 0 : }
8521 :
8522 : NS_IMETHODIMP
8523 0 : nsDocument::MozCancelFullScreen()
8524 : {
8525 0 : if (!nsContentUtils::IsRequestFullScreenAllowed()) {
8526 0 : return NS_OK;
8527 : }
8528 0 : RestorePreviousFullScreenState();
8529 0 : return NS_OK;
8530 : }
8531 :
8532 : // Runnable to set window full-screen mode. Used as a script runner
8533 : // to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to
8534 : // run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event
8535 : // (handled in chome code) which is unsafe to run if this is called in
8536 : // nsGenericElement::UnbindFromTree().
8537 0 : class nsSetWindowFullScreen : public nsRunnable {
8538 : public:
8539 0 : nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue)
8540 0 : : mDoc(aDoc), mValue(aValue) {}
8541 :
8542 0 : NS_IMETHOD Run()
8543 : {
8544 0 : if (mDoc->GetWindow()) {
8545 0 : mDoc->GetWindow()->SetFullScreenInternal(mValue, false);
8546 : }
8547 0 : return NS_OK;
8548 : }
8549 :
8550 : private:
8551 : nsCOMPtr<nsIDocument> mDoc;
8552 : bool mValue;
8553 : };
8554 :
8555 : static void
8556 0 : SetWindowFullScreen(nsIDocument* aDoc, bool aValue)
8557 : {
8558 0 : nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue));
8559 0 : }
8560 :
8561 0 : class nsCallExitFullScreen : public nsRunnable {
8562 : public:
8563 0 : NS_IMETHOD Run()
8564 : {
8565 0 : nsDocument::ExitFullScreen();
8566 0 : return NS_OK;
8567 : }
8568 : };
8569 :
8570 : /* static */
8571 : void
8572 0 : nsIDocument::ExitFullScreen(bool aRunAsync)
8573 : {
8574 0 : if (aRunAsync) {
8575 0 : NS_DispatchToCurrentThread(new nsCallExitFullScreen());
8576 0 : return;
8577 : }
8578 0 : nsDocument::ExitFullScreen();
8579 : }
8580 :
8581 : static bool
8582 0 : ResetFullScreen(nsIDocument* aDocument, void* aData) {
8583 0 : if (aDocument->IsFullScreenDoc()) {
8584 0 : static_cast<nsDocument*>(aDocument)->ClearFullScreenStack();
8585 0 : NS_ASSERTION(!aDocument->IsFullScreenDoc(), "Should reset full-screen");
8586 0 : nsTArray<nsIDocument*>* changed = reinterpret_cast<nsTArray<nsIDocument*>*>(aData);
8587 0 : changed->AppendElement(aDocument);
8588 0 : aDocument->EnumerateSubDocuments(ResetFullScreen, aData);
8589 : }
8590 0 : return true;
8591 : }
8592 :
8593 : /* static */
8594 : void
8595 0 : nsDocument::ExitFullScreen()
8596 : {
8597 : // Clear full-screen stacks in all descendant documents.
8598 0 : nsCOMPtr<nsIDocument> root(do_QueryReferent(sFullScreenRootDoc));
8599 0 : if (!root) {
8600 : // Not in full-screen mode.
8601 : return;
8602 : }
8603 0 : NS_ASSERTION(root->IsFullScreenDoc(),
8604 : "Full-screen root should be a full-screen doc...");
8605 :
8606 : // Stores a list of documents to which we must dispatch "mozfullscreenchange".
8607 : // We're required by the spec to dispatch the events in leaf-to-root
8608 : // order when exiting full-screen, but we traverse the doctree in a
8609 : // root-to-leaf order, so we save references to the documents we must
8610 : // dispatch to so that we dispatch in the specified order.
8611 0 : nsAutoTArray<nsIDocument*, 8> changed;
8612 :
8613 : // Walk the tree of full-screen documents, and reset their full-screen state.
8614 0 : ResetFullScreen(root, static_cast<void*>(&changed));
8615 :
8616 : // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
8617 : // order so that the events for the leaf document arrives before the root
8618 : // document, as required by the spec.
8619 0 : for (PRUint32 i = 0; i < changed.Length(); ++i) {
8620 0 : DispatchFullScreenChange(changed[changed.Length() - i - 1]);
8621 : }
8622 :
8623 : // Reset global state. Do this before we move the window out of full-screen
8624 : // mode, as that calls nsGlobalWindow::SetFullScreen() which calls back into
8625 : // nsIDocument::ExitFullScreen().
8626 0 : sFullScreenRootDoc = nsnull;
8627 0 : sFullScreenDoc = nsnull;
8628 :
8629 : // Move the top-level window out of full-screen mode.
8630 0 : SetWindowFullScreen(root, false);
8631 : }
8632 :
8633 : void
8634 0 : nsDocument::RestorePreviousFullScreenState()
8635 : {
8636 0 : NS_ASSERTION(!IsFullScreenDoc() || sFullScreenDoc != nsnull,
8637 : "Should have a full-screen doc when full-screen!");
8638 :
8639 0 : if (!IsFullScreenDoc() || !GetWindow() || !sFullScreenDoc) {
8640 0 : return;
8641 : }
8642 :
8643 : // Clear full-screen stacks in all descendant documents, bottom up.
8644 0 : nsCOMPtr<nsIDocument> fullScreenDoc(do_QueryReferent(sFullScreenDoc));
8645 0 : nsIDocument* doc = fullScreenDoc;
8646 0 : while (doc != this) {
8647 0 : NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc");
8648 0 : static_cast<nsDocument*>(doc)->ClearFullScreenStack();
8649 0 : DispatchFullScreenChange(doc);
8650 0 : doc = doc->GetParentDocument();
8651 : }
8652 :
8653 : // Roll-back full-screen state to previous full-screen element.
8654 0 : NS_ASSERTION(doc == this, "Must have reached this doc.");
8655 0 : while (doc != nsnull) {
8656 0 : static_cast<nsDocument*>(doc)->FullScreenStackPop();
8657 0 : DispatchFullScreenChange(doc);
8658 0 : if (static_cast<nsDocument*>(doc)->mFullScreenStack.IsEmpty()) {
8659 : // Full-screen stack in document is empty. Go back up to the parent
8660 : // document. We'll pop the containing element off its stack, and use
8661 : // its next full-screen element as the full-screen element.
8662 0 : doc = doc->GetParentDocument();
8663 : } else {
8664 : // Else we popped the top of the stack, and there's still another
8665 : // element in there, so that will become the full-screen element.
8666 0 : sFullScreenDoc = do_GetWeakReference(doc);
8667 0 : break;
8668 : }
8669 : }
8670 :
8671 0 : if (doc == nsnull) {
8672 : // We moved all documents out of full-screen mode, reset global full-screen
8673 : // state and move the top-level window out of full-screen mode.
8674 0 : DebugOnly< nsCOMPtr<nsIDocument> > root(do_QueryReferent(sFullScreenRootDoc));
8675 0 : NS_ASSERTION(!root->IsFullScreenDoc(), "Should have cleared all docs' stacks");
8676 0 : sFullScreenDoc = nsnull;
8677 0 : sFullScreenRootDoc = nsnull;
8678 0 : SetWindowFullScreen(this, false);
8679 : }
8680 : }
8681 :
8682 : bool
8683 0 : nsDocument::IsFullScreenDoc()
8684 : {
8685 0 : return GetFullScreenElement() != nsnull;
8686 : }
8687 :
8688 : class nsCallRequestFullScreen : public nsRunnable
8689 0 : {
8690 : public:
8691 0 : nsCallRequestFullScreen(Element* aElement)
8692 : : mElement(aElement),
8693 : mDoc(aElement->OwnerDoc()),
8694 0 : mWasCallerChrome(nsContentUtils::IsCallerChrome())
8695 : {
8696 0 : }
8697 :
8698 0 : NS_IMETHOD Run()
8699 : {
8700 0 : nsDocument* doc = static_cast<nsDocument*>(mDoc.get());
8701 0 : doc->RequestFullScreen(mElement, mWasCallerChrome);
8702 0 : return NS_OK;
8703 : }
8704 :
8705 : nsRefPtr<Element> mElement;
8706 : nsCOMPtr<nsIDocument> mDoc;
8707 : bool mWasCallerChrome;
8708 : };
8709 :
8710 : void
8711 0 : nsDocument::AsyncRequestFullScreen(Element* aElement)
8712 : {
8713 0 : NS_ASSERTION(aElement,
8714 : "Must pass non-null element to nsDocument::AsyncRequestFullScreen");
8715 0 : if (!aElement) {
8716 0 : return;
8717 : }
8718 : // Request full-screen asynchronously.
8719 0 : nsCOMPtr<nsIRunnable> event(new nsCallRequestFullScreen(aElement));
8720 0 : NS_DispatchToCurrentThread(event);
8721 : }
8722 :
8723 : static void
8724 0 : LogFullScreenDenied(bool aLogFailure, const char* aMessage, nsIDocument* aDoc)
8725 : {
8726 0 : if (!aLogFailure) {
8727 0 : return;
8728 : }
8729 : nsRefPtr<nsAsyncDOMEvent> e =
8730 : new nsAsyncDOMEvent(aDoc,
8731 0 : NS_LITERAL_STRING("mozfullscreenerror"),
8732 : true,
8733 0 : false);
8734 0 : e->PostDOMEvent();
8735 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
8736 : "DOM", aDoc,
8737 : nsContentUtils::eDOM_PROPERTIES,
8738 0 : aMessage);
8739 : }
8740 :
8741 : void
8742 0 : nsDocument::ClearFullScreenStack()
8743 : {
8744 0 : if (mFullScreenStack.IsEmpty()) {
8745 0 : return;
8746 : }
8747 : // The top element in the full-screen stack will have full-screen
8748 : // style bits set on it and its ancestors. Remove the style bits.
8749 : // Note the non-top elements won't have the style bits set.
8750 0 : Element* top = FullScreenStackTop();
8751 0 : NS_ASSERTION(top, "Should have a top when full-screen stack isn't empty");
8752 0 : if (top) {
8753 0 : nsEventStateManager::SetFullScreenState(top, false);
8754 : }
8755 0 : mFullScreenStack.Clear();
8756 : }
8757 :
8758 : bool
8759 0 : nsDocument::FullScreenStackPush(Element* aElement)
8760 : {
8761 0 : NS_ASSERTION(aElement, "Must pass non-null to FullScreenStackPush()");
8762 0 : Element* top = FullScreenStackTop();
8763 0 : if (top == aElement || !aElement) {
8764 0 : return false;
8765 : }
8766 0 : if (top) {
8767 : // We're pushing a new element onto the full-screen stack, so we must
8768 : // remove the ancestor and full-screen styles from the former top of the
8769 : // stack.
8770 0 : nsEventStateManager::SetFullScreenState(top, false);
8771 : }
8772 0 : nsEventStateManager::SetFullScreenState(aElement, true);
8773 0 : mFullScreenStack.AppendElement(do_GetWeakReference(aElement));
8774 0 : NS_ASSERTION(GetFullScreenElement() == aElement, "Should match");
8775 0 : return true;
8776 : }
8777 :
8778 : void
8779 0 : nsDocument::FullScreenStackPop()
8780 : {
8781 0 : if (mFullScreenStack.IsEmpty()) {
8782 0 : return;
8783 : }
8784 :
8785 : // Remove styles from existing top element.
8786 0 : Element* top = FullScreenStackTop();
8787 0 : nsEventStateManager::SetFullScreenState(top, false);
8788 :
8789 : // Remove top element. Note the remaining top element in the stack
8790 : // will not have full-screen style bits set, so we will need to restore
8791 : // them on the new top element before returning.
8792 0 : PRUint32 last = mFullScreenStack.Length() - 1;
8793 0 : mFullScreenStack.RemoveElementAt(last);
8794 :
8795 : // Pop from the stack null elements (references to elements which have
8796 : // been GC'd since they were added to the stack) and elements which are
8797 : // no longer in this document.
8798 0 : while (!mFullScreenStack.IsEmpty()) {
8799 0 : Element* element = FullScreenStackTop();
8800 0 : if (!element || !element->IsInDoc() || element->OwnerDoc() != this) {
8801 0 : NS_ASSERTION(!element->IsFullScreenAncestor(),
8802 : "Should have already removed full-screen styles");
8803 0 : PRUint32 last = mFullScreenStack.Length() - 1;
8804 0 : mFullScreenStack.RemoveElementAt(last);
8805 : } else {
8806 : // The top element of the stack is now an in-doc element. Apply the
8807 : // full-screen styles and return.
8808 0 : nsEventStateManager::SetFullScreenState(element, true);
8809 0 : break;
8810 : }
8811 : }
8812 : }
8813 :
8814 : Element*
8815 0 : nsDocument::FullScreenStackTop()
8816 : {
8817 0 : if (mFullScreenStack.IsEmpty()) {
8818 0 : return nsnull;
8819 : }
8820 0 : PRUint32 last = mFullScreenStack.Length() - 1;
8821 0 : nsCOMPtr<Element> element(do_QueryReferent(mFullScreenStack[last]));
8822 0 : NS_ASSERTION(element, "Should have full-screen element!");
8823 0 : NS_ASSERTION(element->IsInDoc(), "Full-screen element should be in doc");
8824 0 : NS_ASSERTION(element->OwnerDoc() == this, "Full-screen element should be in this doc");
8825 0 : return element;
8826 : }
8827 :
8828 : // Returns true if aDoc is in the focused tab in the active window.
8829 : static bool
8830 0 : IsInActiveTab(nsIDocument* aDoc)
8831 : {
8832 0 : nsCOMPtr<nsISupports> container = aDoc->GetContainer();
8833 0 : nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(container);
8834 0 : if (!docshell) {
8835 0 : return false;
8836 : }
8837 :
8838 0 : bool isActive = false;
8839 0 : docshell->GetIsActive(&isActive);
8840 0 : if (!isActive) {
8841 0 : return false;
8842 : }
8843 :
8844 0 : nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(container);
8845 0 : if (!dsti) {
8846 0 : return false;
8847 : }
8848 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
8849 0 : dsti->GetRootTreeItem(getter_AddRefs(rootItem));
8850 0 : if (!rootItem) {
8851 0 : return false;
8852 : }
8853 0 : nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
8854 0 : if (!rootWin) {
8855 0 : return false;
8856 : }
8857 :
8858 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
8859 0 : if (!fm) {
8860 0 : return false;
8861 : }
8862 :
8863 0 : nsCOMPtr<nsIDOMWindow> activeWindow;
8864 0 : fm->GetActiveWindow(getter_AddRefs(activeWindow));
8865 0 : if (!activeWindow) {
8866 0 : return false;
8867 : }
8868 :
8869 0 : return activeWindow == rootWin;
8870 : }
8871 :
8872 : void
8873 0 : nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
8874 : {
8875 0 : NS_ASSERTION(aElement,
8876 : "Must pass non-null element to nsDocument::RequestFullScreen");
8877 0 : if (!aElement || aElement == GetFullScreenElement()) {
8878 0 : return;
8879 : }
8880 0 : if (!aElement->IsInDoc()) {
8881 0 : LogFullScreenDenied(true, "FullScreenDeniedNotInDocument", this);
8882 0 : return;
8883 : }
8884 0 : if (aElement->OwnerDoc() != this) {
8885 0 : LogFullScreenDenied(true, "FullScreenDeniedMovedDocument", this);
8886 0 : return;
8887 : }
8888 0 : if (!GetWindow()) {
8889 0 : LogFullScreenDenied(true, "FullScreenDeniedLostWindow", this);
8890 0 : return;
8891 : }
8892 0 : if (!IsFullScreenEnabled(aWasCallerChrome, true)) {
8893 : // IsFullScreenEnabled calls LogFullScreenDenied, no need to log.
8894 0 : return;
8895 : }
8896 0 : if (GetFullScreenElement() &&
8897 0 : !nsContentUtils::ContentIsDescendantOf(aElement, GetFullScreenElement())) {
8898 : // If this document is full-screen, only grant full-screen requests from
8899 : // a descendent of the current full-screen element.
8900 0 : LogFullScreenDenied(true, "FullScreenDeniedNotDescendant", this);
8901 0 : return;
8902 : }
8903 0 : if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
8904 0 : LogFullScreenDenied(true, "FullScreenDeniedNotFocusedTab", this);
8905 0 : return;
8906 : }
8907 : // Deny requests when a windowed plugin is focused.
8908 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
8909 0 : if (!fm) {
8910 0 : NS_WARNING("Failed to retrieve focus manager in full-screen request.");
8911 0 : return;
8912 : }
8913 0 : nsCOMPtr<nsIDOMElement> focusedElement;
8914 0 : fm->GetFocusedElement(getter_AddRefs(focusedElement));
8915 0 : if (focusedElement) {
8916 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(focusedElement);
8917 0 : if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(content)) {
8918 0 : LogFullScreenDenied(true, "FullScreenDeniedFocusedPlugin", this);
8919 : return;
8920 : }
8921 : }
8922 :
8923 : // Stores a list of documents which we must dispatch "mozfullscreenchange"
8924 : // too. We're required by the spec to dispatch the events in root-to-leaf
8925 : // order, but we traverse the doctree in a leaf-to-root order, so we save
8926 : // references to the documents we must dispatch to so that we get the order
8927 : // as specified.
8928 0 : nsAutoTArray<nsIDocument*, 8> changed;
8929 :
8930 : // Remember the root document, so that if a full-screen document is hidden
8931 : // we can reset full-screen state in the remaining visible full-screen documents.
8932 0 : sFullScreenRootDoc = do_GetWeakReference(nsContentUtils::GetRootDocument(this));
8933 :
8934 : // Set the full-screen element. This sets the full-screen style on the
8935 : // element, and the full-screen-ancestor styles on ancestors of the element
8936 : // in this document.
8937 0 : DebugOnly<bool> x = FullScreenStackPush(aElement);
8938 0 : NS_ASSERTION(x, "Full-screen state of requesting doc should always change!");
8939 0 : changed.AppendElement(this);
8940 :
8941 : // Propagate up the document hierarchy, setting the full-screen element as
8942 : // the element's container in ancestor documents. This also sets the
8943 : // appropriate css styles as well. Note we don't propagate down the
8944 : // document hierarchy, the full-screen element (or its container) is not
8945 : // visible there.
8946 0 : nsIDocument* child = this;
8947 : nsIDocument* parent;
8948 0 : while ((parent = child->GetParentDocument())) {
8949 0 : Element* element = parent->FindContentForSubDocument(child)->AsElement();
8950 0 : if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
8951 0 : changed.AppendElement(parent);
8952 0 : child = parent;
8953 : } else {
8954 : // We've reached either the root, or a point in the doctree where the
8955 : // new full-screen element container is the same as the previous
8956 : // full-screen element's container. No more changes need to be made
8957 : // to the full-screen stacks of documents further up the tree.
8958 0 : break;
8959 : }
8960 : }
8961 :
8962 : // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
8963 : // order so that the events for the root document arrives before the leaf
8964 : // document, as required by the spec.
8965 0 : for (PRUint32 i = 0; i < changed.Length(); ++i) {
8966 0 : DispatchFullScreenChange(changed[changed.Length() - i - 1]);
8967 : }
8968 :
8969 : // Remember this is the requesting full-screen document.
8970 0 : sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
8971 :
8972 : #ifdef DEBUG
8973 : // Note assertions must run before SetWindowFullScreen() as that does
8974 : // synchronous event dispatch which can run script which exits full-screen!
8975 0 : NS_ASSERTION(GetFullScreenElement() == aElement,
8976 : "Full-screen element should be the requested element!");
8977 0 : NS_ASSERTION(IsFullScreenDoc(), "Should be full-screen doc");
8978 0 : nsCOMPtr<nsIDOMHTMLElement> fse;
8979 0 : GetMozFullScreenElement(getter_AddRefs(fse));
8980 0 : nsCOMPtr<nsIContent> c(do_QueryInterface(fse));
8981 0 : NS_ASSERTION(c->AsElement() == aElement,
8982 : "GetMozFullScreenElement should match GetFullScreenElement()");
8983 : #endif
8984 :
8985 : // Make the window full-screen. Note we must make the state changes above
8986 : // before making the window full-screen, as then the document reports as
8987 : // being in full-screen mode when the chrome "fullscreen" event fires,
8988 : // enabling chrome to distinguish between browser and dom full-screen
8989 : // modes. Also note that nsGlobalWindow::SetFullScreen() (which
8990 : // SetWindowFullScreen() calls) proxies to the root window in its hierarchy,
8991 : // and does not operate on the a per-nsIDOMWindow basis.
8992 0 : SetWindowFullScreen(this, true);
8993 : }
8994 :
8995 : NS_IMETHODIMP
8996 0 : nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement)
8997 : {
8998 0 : NS_ENSURE_ARG_POINTER(aFullScreenElement);
8999 0 : *aFullScreenElement = nsnull;
9000 0 : if (IsFullScreenDoc()) {
9001 : // Must have a full-screen element while in full-screen mode.
9002 0 : NS_ENSURE_STATE(GetFullScreenElement());
9003 0 : CallQueryInterface(GetFullScreenElement(), aFullScreenElement);
9004 : }
9005 0 : return NS_OK;
9006 : }
9007 :
9008 : Element*
9009 0 : nsDocument::GetFullScreenElement()
9010 : {
9011 0 : Element* element = FullScreenStackTop();
9012 0 : NS_ASSERTION(!element || element->IsFullScreenAncestor(),
9013 : "Should have full-screen styles applied!");
9014 0 : return element;
9015 : }
9016 :
9017 : NS_IMETHODIMP
9018 0 : nsDocument::GetMozFullScreen(bool *aFullScreen)
9019 : {
9020 0 : NS_ENSURE_ARG_POINTER(aFullScreen);
9021 0 : *aFullScreen = IsFullScreenDoc();
9022 0 : return NS_OK;
9023 : }
9024 :
9025 : NS_IMETHODIMP
9026 0 : nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
9027 : {
9028 0 : NS_ENSURE_ARG_POINTER(aFullScreen);
9029 0 : *aFullScreen = IsFullScreenEnabled(nsContentUtils::IsCallerChrome(), false);
9030 0 : return NS_OK;
9031 : }
9032 :
9033 : static bool
9034 0 : HasFullScreenSubDocument(nsIDocument* aDoc, void* aData)
9035 : {
9036 0 : if (aDoc->IsFullScreenDoc()) {
9037 : // This subdocument is full-screen. Set result and return false to
9038 : // stop iteration.
9039 0 : *static_cast<bool*>(aData) = true;
9040 0 : return false;
9041 : }
9042 0 : return true;
9043 : }
9044 :
9045 : static bool
9046 0 : HasFullScreenSubDocument(nsIDocument* aDoc)
9047 : {
9048 0 : bool result = false;
9049 0 : aDoc->EnumerateSubDocuments(&HasFullScreenSubDocument, static_cast<void*>(&result));
9050 0 : return result;
9051 : }
9052 :
9053 : bool
9054 0 : nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure)
9055 : {
9056 0 : if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome) {
9057 : // Chrome code can always use the full-screen API, provided it's not
9058 : // explicitly disabled. Note IsCallerChrome() returns true when running
9059 : // in an nsRunnable, so don't use GetMozFullScreenEnabled() from an
9060 : // nsRunnable!
9061 0 : return true;
9062 : }
9063 :
9064 0 : if (!nsContentUtils::IsFullScreenApiEnabled()) {
9065 0 : LogFullScreenDenied(aLogFailure, "FullScreenDeniedDisabled", this);
9066 0 : return false;
9067 : }
9068 0 : if (!IsVisible()) {
9069 0 : LogFullScreenDenied(aLogFailure, "FullScreenDeniedHidden", this);
9070 0 : return false;
9071 : }
9072 0 : if (HasFullScreenSubDocument(this)) {
9073 0 : LogFullScreenDenied(aLogFailure, "FullScreenDeniedSubDocFullScreen", this);
9074 0 : return false;
9075 : }
9076 :
9077 : // Ensure that all ancestor <iframe> elements have the mozallowfullscreen
9078 : // boolean attribute set.
9079 0 : nsINode* node = static_cast<nsINode*>(this);
9080 0 : do {
9081 0 : nsIContent* content = static_cast<nsIContent*>(node);
9082 0 : if (content->IsHTML(nsGkAtoms::iframe) &&
9083 0 : !content->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)) {
9084 : // The node requesting fullscreen, or one of its crossdoc ancestors,
9085 : // is an iframe which doesn't have the "mozalllowfullscreen" attribute.
9086 : // This request is not authorized by the parent document.
9087 0 : LogFullScreenDenied(aLogFailure, "FullScreenDeniedIframeDisallowed", this);
9088 0 : return false;
9089 : }
9090 0 : node = nsContentUtils::GetCrossDocParentNode(node);
9091 : } while (node);
9092 :
9093 0 : return true;
9094 : }
9095 :
9096 : #define EVENT(name_, id_, type_, struct_) \
9097 : NS_IMETHODIMP nsDocument::GetOn##name_(JSContext *cx, jsval *vp) { \
9098 : return nsINode::GetOn##name_(cx, vp); \
9099 : } \
9100 : NS_IMETHODIMP nsDocument::SetOn##name_(JSContext *cx, const jsval &v) { \
9101 : return nsINode::SetOn##name_(cx, v); \
9102 : }
9103 : #define TOUCH_EVENT EVENT
9104 : #define DOCUMENT_ONLY_EVENT EVENT
9105 : #include "nsEventNameList.h"
9106 : #undef DOCUMENT_ONLY_EVENT
9107 : #undef TOUCH_EVENT
9108 : #undef EVENT
9109 :
9110 : void
9111 0 : nsDocument::UpdateVisibilityState()
9112 : {
9113 0 : VisibilityState oldState = mVisibilityState;
9114 0 : mVisibilityState = GetVisibilityState();
9115 0 : if (oldState != mVisibilityState) {
9116 : nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
9117 0 : NS_LITERAL_STRING("mozvisibilitychange"),
9118 0 : false, false);
9119 : }
9120 0 : }
9121 :
9122 : nsDocument::VisibilityState
9123 0 : nsDocument::GetVisibilityState() const
9124 : {
9125 : // We have to check a few pieces of information here:
9126 : // 1) Are we in bfcache (!IsVisible())? If so, nothing else matters.
9127 : // 2) Do we have an outer window? If not, we're hidden. Note that we don't
9128 : // want to use GetWindow here because it does weird groveling for windows
9129 : // in some cases.
9130 : // 3) Is our outer window background? If so, we're hidden.
9131 : // Otherwise, we're visible.
9132 0 : if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
9133 0 : mWindow->GetOuterWindow()->IsBackground()) {
9134 0 : return eHidden;
9135 : }
9136 :
9137 0 : return eVisible;
9138 : }
9139 :
9140 : /* virtual */ void
9141 0 : nsDocument::PostVisibilityUpdateEvent()
9142 : {
9143 : nsCOMPtr<nsIRunnable> event =
9144 0 : NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
9145 0 : NS_DispatchToMainThread(event);
9146 0 : }
9147 :
9148 : NS_IMETHODIMP
9149 0 : nsDocument::GetMozHidden(bool* aHidden)
9150 : {
9151 0 : *aHidden = mVisibilityState != eVisible;
9152 0 : return NS_OK;
9153 : }
9154 :
9155 : NS_IMETHODIMP
9156 0 : nsDocument::GetMozVisibilityState(nsAString& aState)
9157 : {
9158 : // This needs to stay in sync with the VisibilityState enum.
9159 : static const char states[][8] = {
9160 : "hidden",
9161 : "visible"
9162 : };
9163 : PR_STATIC_ASSERT(NS_ARRAY_LENGTH(states) == eVisibilityStateCount);
9164 0 : aState.AssignASCII(states[mVisibilityState]);
9165 0 : return NS_OK;
9166 : }
9167 :
9168 : /* virtual */ void
9169 0 : nsIDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
9170 : {
9171 : aWindowSizes->mDOM +=
9172 0 : nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
9173 :
9174 0 : if (mPresShell) {
9175 : mPresShell->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
9176 : &aWindowSizes->mLayoutArenas,
9177 : &aWindowSizes->mLayoutStyleSets,
9178 0 : &aWindowSizes->mLayoutTextRuns);
9179 : }
9180 :
9181 : // Measurement of the following members may be added later if DMD finds it
9182 : // is worthwhile:
9183 : // - many!
9184 0 : }
9185 :
9186 : void
9187 0 : nsIDocument::DocSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
9188 : {
9189 0 : aWindowSizes->mDOM += aWindowSizes->mMallocSizeOf(this);
9190 0 : DocSizeOfExcludingThis(aWindowSizes);
9191 0 : }
9192 :
9193 : static size_t
9194 0 : SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet* aStyleSheet,
9195 : nsMallocSizeOfFun aMallocSizeOf,
9196 : void* aData)
9197 : {
9198 0 : return aStyleSheet->SizeOfIncludingThis(aMallocSizeOf);
9199 : }
9200 :
9201 : size_t
9202 0 : nsDocument::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
9203 : {
9204 : // This SizeOfExcludingThis() overrides the one from nsINode. But
9205 : // nsDocuments can only appear at the top of the DOM tree, and we use the
9206 : // specialized DocSizeOfExcludingThis() in that case. So this should never
9207 : // be called.
9208 0 : MOZ_NOT_REACHED("nsDocument::SizeOfExcludingThis");
9209 : return 0;
9210 : }
9211 :
9212 : void
9213 0 : nsDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
9214 : {
9215 0 : nsIDocument::DocSizeOfExcludingThis(aWindowSizes);
9216 :
9217 0 : for (nsIContent* node = nsINode::GetFirstChild();
9218 : node;
9219 0 : node = node->GetNextNode(this))
9220 : {
9221 : aWindowSizes->mDOM +=
9222 0 : node->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
9223 : }
9224 :
9225 : aWindowSizes->mStyleSheets +=
9226 : mStyleSheets.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
9227 0 : aWindowSizes->mMallocSizeOf);
9228 : aWindowSizes->mDOM +=
9229 : mAttrStyleSheet ?
9230 0 : mAttrStyleSheet->DOMSizeOfIncludingThis(aWindowSizes->mMallocSizeOf) :
9231 0 : 0;
9232 :
9233 : // Measurement of the following members may be added later if DMD finds it
9234 : // is worthwhile:
9235 : // - many!
9236 4392 : }
|