1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsDocument.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,12287 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Base class for all our document implementations. 1.12 + */ 1.13 + 1.14 +#include "nsDocument.h" 1.15 + 1.16 +#include "mozilla/ArrayUtils.h" 1.17 +#include "mozilla/AutoRestore.h" 1.18 +#include "mozilla/DebugOnly.h" 1.19 +#include "mozilla/MemoryReporting.h" 1.20 +#include "mozilla/Likely.h" 1.21 +#include <algorithm> 1.22 + 1.23 +#ifdef MOZ_LOGGING 1.24 +// so we can get logging even in release builds 1.25 +#define FORCE_PR_LOG 1 1.26 +#endif 1.27 +#include "prlog.h" 1.28 +#include "plstr.h" 1.29 +#include "prprf.h" 1.30 + 1.31 +#include "mozilla/Telemetry.h" 1.32 +#include "nsIInterfaceRequestor.h" 1.33 +#include "nsIInterfaceRequestorUtils.h" 1.34 +#include "nsUnicharUtils.h" 1.35 +#include "nsContentList.h" 1.36 +#include "nsIObserver.h" 1.37 +#include "nsIBaseWindow.h" 1.38 +#include "mozilla/css/Loader.h" 1.39 +#include "mozilla/css/ImageLoader.h" 1.40 +#include "nsDocShell.h" 1.41 +#include "nsIDocShellTreeItem.h" 1.42 +#include "nsCOMArray.h" 1.43 +#include "nsDOMClassInfo.h" 1.44 +#include "nsCxPusher.h" 1.45 + 1.46 +#include "mozilla/AsyncEventDispatcher.h" 1.47 +#include "mozilla/BasicEvents.h" 1.48 +#include "mozilla/EventListenerManager.h" 1.49 +#include "mozilla/EventStateManager.h" 1.50 +#include "nsIDOMNodeFilter.h" 1.51 + 1.52 +#include "nsIDOMStyleSheet.h" 1.53 +#include "mozilla/dom/Attr.h" 1.54 +#include "nsIDOMDOMImplementation.h" 1.55 +#include "nsIDOMDocumentXBL.h" 1.56 +#include "mozilla/dom/Element.h" 1.57 +#include "nsGenericHTMLElement.h" 1.58 +#include "mozilla/dom/CDATASection.h" 1.59 +#include "mozilla/dom/ProcessingInstruction.h" 1.60 +#include "nsDOMString.h" 1.61 +#include "nsNodeUtils.h" 1.62 +#include "nsLayoutUtils.h" // for GetFrameForPoint 1.63 +#include "nsIFrame.h" 1.64 +#include "nsITabChild.h" 1.65 + 1.66 +#include "nsRange.h" 1.67 +#include "nsIDOMText.h" 1.68 +#include "nsIDOMComment.h" 1.69 +#include "mozilla/dom/DocumentType.h" 1.70 +#include "mozilla/dom/NodeIterator.h" 1.71 +#include "mozilla/dom/TreeWalker.h" 1.72 + 1.73 +#include "nsIServiceManager.h" 1.74 + 1.75 +#include "nsContentCID.h" 1.76 +#include "nsError.h" 1.77 +#include "nsPresShell.h" 1.78 +#include "nsPresContext.h" 1.79 +#include "nsIJSON.h" 1.80 +#include "nsThreadUtils.h" 1.81 +#include "nsNodeInfoManager.h" 1.82 +#include "nsIFileChannel.h" 1.83 +#include "nsIMultiPartChannel.h" 1.84 +#include "nsIRefreshURI.h" 1.85 +#include "nsIWebNavigation.h" 1.86 +#include "nsIScriptError.h" 1.87 +#include "nsStyleSheetService.h" 1.88 + 1.89 +#include "nsNetUtil.h" // for NS_MakeAbsoluteURI 1.90 + 1.91 +#include "nsIScriptSecurityManager.h" 1.92 +#include "nsIPrincipal.h" 1.93 + 1.94 +#include "nsIDOMWindow.h" 1.95 +#include "nsPIDOMWindow.h" 1.96 +#include "nsIDOMElement.h" 1.97 +#include "nsFocusManager.h" 1.98 + 1.99 +// for radio group stuff 1.100 +#include "nsIDOMHTMLInputElement.h" 1.101 +#include "nsIRadioVisitor.h" 1.102 +#include "nsIFormControl.h" 1.103 + 1.104 +#include "nsBidiUtils.h" 1.105 + 1.106 +#include "nsIDOMUserDataHandler.h" 1.107 +#include "nsIDOMXPathExpression.h" 1.108 +#include "nsIDOMXPathNSResolver.h" 1.109 +#include "nsIParserService.h" 1.110 +#include "nsContentCreatorFunctions.h" 1.111 + 1.112 +#include "nsIScriptContext.h" 1.113 +#include "nsBindingManager.h" 1.114 +#include "nsIDOMHTMLDocument.h" 1.115 +#include "nsHTMLDocument.h" 1.116 +#include "nsIDOMHTMLFormElement.h" 1.117 +#include "nsIRequest.h" 1.118 +#include "nsHostObjectProtocolHandler.h" 1.119 + 1.120 +#include "nsCharsetAlias.h" 1.121 +#include "nsCharsetSource.h" 1.122 +#include "nsIParser.h" 1.123 +#include "nsIContentSink.h" 1.124 + 1.125 +#include "nsDateTimeFormatCID.h" 1.126 +#include "nsIDateTimeFormat.h" 1.127 +#include "mozilla/EventDispatcher.h" 1.128 +#include "mozilla/EventStates.h" 1.129 +#include "mozilla/InternalMutationEvent.h" 1.130 +#include "nsDOMCID.h" 1.131 + 1.132 +#include "jsapi.h" 1.133 +#include "nsIXPConnect.h" 1.134 +#include "nsCCUncollectableMarker.h" 1.135 +#include "nsIContentPolicy.h" 1.136 +#include "nsContentPolicyUtils.h" 1.137 +#include "nsICategoryManager.h" 1.138 +#include "nsIDocumentLoaderFactory.h" 1.139 +#include "nsIDocumentLoader.h" 1.140 +#include "nsIContentViewer.h" 1.141 +#include "nsIXMLContentSink.h" 1.142 +#include "nsIXULDocument.h" 1.143 +#include "nsIPrompt.h" 1.144 +#include "nsIPropertyBag2.h" 1.145 +#include "nsIDOMPageTransitionEvent.h" 1.146 +#include "nsIDOMStyleRuleChangeEvent.h" 1.147 +#include "nsIDOMStyleSheetChangeEvent.h" 1.148 +#include "nsIDOMStyleSheetApplicableStateChangeEvent.h" 1.149 +#include "nsJSUtils.h" 1.150 +#include "nsFrameLoader.h" 1.151 +#include "nsEscape.h" 1.152 +#include "nsObjectLoadingContent.h" 1.153 +#include "nsHtml5TreeOpExecutor.h" 1.154 +#include "nsIDOMElementReplaceEvent.h" 1.155 +#include "mozilla/dom/HTMLLinkElement.h" 1.156 +#include "mozilla/dom/HTMLMediaElement.h" 1.157 +#ifdef MOZ_MEDIA_NAVIGATOR 1.158 +#include "mozilla/MediaManager.h" 1.159 +#endif // MOZ_MEDIA_NAVIGATOR 1.160 +#ifdef MOZ_WEBRTC 1.161 +#include "IPeerConnection.h" 1.162 +#endif // MOZ_WEBRTC 1.163 + 1.164 +#include "mozAutoDocUpdate.h" 1.165 +#include "nsGlobalWindow.h" 1.166 +#include "mozilla/dom/EncodingUtils.h" 1.167 +#include "mozilla/dom/quota/QuotaManager.h" 1.168 +#include "nsDOMNavigationTiming.h" 1.169 + 1.170 +#include "nsSMILAnimationController.h" 1.171 +#include "imgIContainer.h" 1.172 +#include "nsSVGUtils.h" 1.173 +#include "SVGElementFactory.h" 1.174 + 1.175 +#include "nsRefreshDriver.h" 1.176 + 1.177 +// FOR CSP (autogenerated by xpidl) 1.178 +#include "nsIContentSecurityPolicy.h" 1.179 +#include "nsCSPService.h" 1.180 +#include "nsHTMLStyleSheet.h" 1.181 +#include "nsHTMLCSSStyleSheet.h" 1.182 +#include "mozilla/dom/DOMImplementation.h" 1.183 +#include "mozilla/dom/ShadowRoot.h" 1.184 +#include "mozilla/dom/Comment.h" 1.185 +#include "nsTextNode.h" 1.186 +#include "mozilla/dom/Link.h" 1.187 +#include "mozilla/dom/HTMLElementBinding.h" 1.188 +#include "mozilla/dom/SVGElementBinding.h" 1.189 +#include "nsXULAppAPI.h" 1.190 +#include "mozilla/dom/Touch.h" 1.191 +#include "mozilla/dom/TouchEvent.h" 1.192 +#include "GeneratedEvents.h" 1.193 + 1.194 +#include "mozilla/Preferences.h" 1.195 + 1.196 +#include "imgILoader.h" 1.197 +#include "imgRequestProxy.h" 1.198 +#include "nsWrapperCacheInlines.h" 1.199 +#include "nsSandboxFlags.h" 1.200 +#include "nsIAppsService.h" 1.201 +#include "mozilla/dom/BindingUtils.h" 1.202 +#include "mozilla/dom/DocumentFragment.h" 1.203 +#include "mozilla/dom/Event.h" 1.204 +#include "mozilla/dom/HTMLBodyElement.h" 1.205 +#include "mozilla/dom/HTMLInputElement.h" 1.206 +#include "mozilla/dom/NodeFilterBinding.h" 1.207 +#include "mozilla/dom/OwningNonNull.h" 1.208 +#include "mozilla/dom/UndoManager.h" 1.209 +#include "mozilla/dom/WebComponentsBinding.h" 1.210 +#include "nsFrame.h" 1.211 +#include "nsDOMCaretPosition.h" 1.212 +#include "nsIDOMHTMLTextAreaElement.h" 1.213 +#include "nsViewportInfo.h" 1.214 +#include "nsIContentPermissionPrompt.h" 1.215 +#include "mozilla/StaticPtr.h" 1.216 +#include "nsITextControlElement.h" 1.217 +#include "nsIDOMNSEditableElement.h" 1.218 +#include "nsIEditor.h" 1.219 +#include "nsIDOMCSSStyleRule.h" 1.220 +#include "mozilla/css/Rule.h" 1.221 +#include "nsIDOMLocation.h" 1.222 +#include "nsIHttpChannelInternal.h" 1.223 +#include "nsISecurityConsoleMessage.h" 1.224 +#include "nsCharSeparatedTokenizer.h" 1.225 +#include "mozilla/dom/XPathEvaluator.h" 1.226 +#include "nsIDocumentEncoder.h" 1.227 +#include "nsIStructuredCloneContainer.h" 1.228 +#include "nsIMutableArray.h" 1.229 +#include "nsContentPermissionHelper.h" 1.230 +#include "mozilla/dom/DOMStringList.h" 1.231 +#include "nsWindowMemoryReporter.h" 1.232 + 1.233 +using namespace mozilla; 1.234 +using namespace mozilla::dom; 1.235 + 1.236 +typedef nsTArray<Link*> LinkArray; 1.237 + 1.238 +#ifdef PR_LOGGING 1.239 +static PRLogModuleInfo* gDocumentLeakPRLog; 1.240 +static PRLogModuleInfo* gCspPRLog; 1.241 +#endif 1.242 + 1.243 +#define NAME_NOT_VALID ((nsSimpleContentList*)1) 1.244 + 1.245 +nsIdentifierMapEntry::~nsIdentifierMapEntry() 1.246 +{ 1.247 +} 1.248 + 1.249 +void 1.250 +nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback) 1.251 +{ 1.252 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, 1.253 + "mIdentifierMap mNameContentList"); 1.254 + aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mNameContentList)); 1.255 + 1.256 + if (mImageElement) { 1.257 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, 1.258 + "mIdentifierMap mImageElement element"); 1.259 + nsIContent* imageElement = mImageElement; 1.260 + aCallback->NoteXPCOMChild(imageElement); 1.261 + } 1.262 +} 1.263 + 1.264 +bool 1.265 +nsIdentifierMapEntry::IsEmpty() 1.266 +{ 1.267 + return mIdContentList.Count() == 0 && !mNameContentList && 1.268 + !mChangeCallbacks && !mImageElement; 1.269 +} 1.270 + 1.271 +Element* 1.272 +nsIdentifierMapEntry::GetIdElement() 1.273 +{ 1.274 + return static_cast<Element*>(mIdContentList.SafeElementAt(0)); 1.275 +} 1.276 + 1.277 +Element* 1.278 +nsIdentifierMapEntry::GetImageIdElement() 1.279 +{ 1.280 + return mImageElement ? mImageElement.get() : GetIdElement(); 1.281 +} 1.282 + 1.283 +void 1.284 +nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements) 1.285 +{ 1.286 + for (int32_t i = 0; i < mIdContentList.Count(); ++i) { 1.287 + aElements->AppendObject(static_cast<Element*>(mIdContentList[i])); 1.288 + } 1.289 +} 1.290 + 1.291 +void 1.292 +nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback, 1.293 + void* aData, bool aForImage) 1.294 +{ 1.295 + if (!mChangeCallbacks) { 1.296 + mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>; 1.297 + if (!mChangeCallbacks) 1.298 + return; 1.299 + } 1.300 + 1.301 + ChangeCallback cc = { aCallback, aData, aForImage }; 1.302 + mChangeCallbacks->PutEntry(cc); 1.303 +} 1.304 + 1.305 +void 1.306 +nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback, 1.307 + void* aData, bool aForImage) 1.308 +{ 1.309 + if (!mChangeCallbacks) 1.310 + return; 1.311 + ChangeCallback cc = { aCallback, aData, aForImage }; 1.312 + mChangeCallbacks->RemoveEntry(cc); 1.313 + if (mChangeCallbacks->Count() == 0) { 1.314 + mChangeCallbacks = nullptr; 1.315 + } 1.316 +} 1.317 + 1.318 +struct FireChangeArgs { 1.319 + Element* mFrom; 1.320 + Element* mTo; 1.321 + bool mImageOnly; 1.322 + bool mHaveImageOverride; 1.323 +}; 1.324 + 1.325 +namespace mozilla { 1.326 +namespace dom { 1.327 + 1.328 +static PLDHashOperator 1.329 +CustomDefinitionsTraverse(CustomElementHashKey* aKey, 1.330 + CustomElementDefinition* aDefinition, 1.331 + void* aArg) 1.332 +{ 1.333 + nsCycleCollectionTraversalCallback* cb = 1.334 + static_cast<nsCycleCollectionTraversalCallback*>(aArg); 1.335 + 1.336 + nsAutoPtr<LifecycleCallbacks>& callbacks = aDefinition->mCallbacks; 1.337 + 1.338 + if (callbacks->mAttributeChangedCallback.WasPassed()) { 1.339 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.340 + "mCustomDefinitions->mCallbacks->mAttributeChangedCallback"); 1.341 + cb->NoteXPCOMChild(aDefinition->mCallbacks->mAttributeChangedCallback.Value()); 1.342 + } 1.343 + 1.344 + if (callbacks->mCreatedCallback.WasPassed()) { 1.345 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.346 + "mCustomDefinitions->mCallbacks->mCreatedCallback"); 1.347 + cb->NoteXPCOMChild(aDefinition->mCallbacks->mCreatedCallback.Value()); 1.348 + } 1.349 + 1.350 + if (callbacks->mAttachedCallback.WasPassed()) { 1.351 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.352 + "mCustomDefinitions->mCallbacks->mAttachedCallback"); 1.353 + cb->NoteXPCOMChild(aDefinition->mCallbacks->mAttachedCallback.Value()); 1.354 + } 1.355 + 1.356 + if (callbacks->mDetachedCallback.WasPassed()) { 1.357 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.358 + "mCustomDefinitions->mCallbacks->mDetachedCallback"); 1.359 + cb->NoteXPCOMChild(aDefinition->mCallbacks->mDetachedCallback.Value()); 1.360 + } 1.361 + 1.362 + return PL_DHASH_NEXT; 1.363 +} 1.364 + 1.365 +static PLDHashOperator 1.366 +CandidatesTraverse(CustomElementHashKey* aKey, 1.367 + nsTArray<nsRefPtr<Element>>* aData, 1.368 + void* aArg) 1.369 +{ 1.370 + nsCycleCollectionTraversalCallback *cb = 1.371 + static_cast<nsCycleCollectionTraversalCallback*>(aArg); 1.372 + for (size_t i = 0; i < aData->Length(); ++i) { 1.373 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mCandidatesMap->Element"); 1.374 + cb->NoteXPCOMChild(aData->ElementAt(i)); 1.375 + } 1.376 + return PL_DHASH_NEXT; 1.377 +} 1.378 + 1.379 +struct CustomDefinitionTraceArgs 1.380 +{ 1.381 + const TraceCallbacks& callbacks; 1.382 + void* closure; 1.383 +}; 1.384 + 1.385 +static PLDHashOperator 1.386 +CustomDefinitionTrace(CustomElementHashKey *aKey, 1.387 + CustomElementDefinition *aData, 1.388 + void *aArg) 1.389 +{ 1.390 + CustomDefinitionTraceArgs* traceArgs = static_cast<CustomDefinitionTraceArgs*>(aArg); 1.391 + MOZ_ASSERT(aData, "Definition must not be null"); 1.392 + traceArgs->callbacks.Trace(&aData->mPrototype, "mCustomDefinitions prototype", 1.393 + traceArgs->closure); 1.394 + return PL_DHASH_NEXT; 1.395 +} 1.396 + 1.397 +NS_IMPL_CYCLE_COLLECTION_CLASS(Registry) 1.398 + 1.399 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry) 1.400 + CustomDefinitionTraceArgs customDefinitionArgs = { aCallbacks, aClosure }; 1.401 + tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionTrace, 1.402 + &customDefinitionArgs); 1.403 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.404 + 1.405 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry) 1.406 + tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionsTraverse, &cb); 1.407 + tmp->mCandidatesMap.EnumerateRead(CandidatesTraverse, &cb); 1.408 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.409 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.410 + 1.411 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Registry) 1.412 + tmp->mCustomDefinitions.Clear(); 1.413 + tmp->mCandidatesMap.Clear(); 1.414 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.415 + 1.416 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Registry) 1.417 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.418 +NS_INTERFACE_MAP_END 1.419 + 1.420 +NS_IMPL_CYCLE_COLLECTING_ADDREF(Registry) 1.421 +NS_IMPL_CYCLE_COLLECTING_RELEASE(Registry) 1.422 + 1.423 +Registry::Registry() 1.424 +{ 1.425 + mozilla::HoldJSObjects(this); 1.426 +} 1.427 + 1.428 +Registry::~Registry() 1.429 +{ 1.430 + mozilla::DropJSObjects(this); 1.431 +} 1.432 + 1.433 +void 1.434 +CustomElementCallback::Call() 1.435 +{ 1.436 + ErrorResult rv; 1.437 + switch (mType) { 1.438 + case nsIDocument::eCreated: 1.439 + // For the duration of this callback invocation, the element is being created 1.440 + // flag must be set to true. 1.441 + mOwnerData->mElementIsBeingCreated = true; 1.442 + mOwnerData->mCreatedCallbackInvoked = true; 1.443 + static_cast<LifecycleCreatedCallback *>(mCallback.get())->Call(mThisObject, rv); 1.444 + mOwnerData->mElementIsBeingCreated = false; 1.445 + break; 1.446 + case nsIDocument::eAttached: 1.447 + static_cast<LifecycleAttachedCallback *>(mCallback.get())->Call(mThisObject, rv); 1.448 + break; 1.449 + case nsIDocument::eDetached: 1.450 + static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv); 1.451 + break; 1.452 + case nsIDocument::eAttributeChanged: 1.453 + static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject, 1.454 + mArgs.name, mArgs.oldValue, mArgs.newValue, rv); 1.455 + break; 1.456 + } 1.457 +} 1.458 + 1.459 +void 1.460 +CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const 1.461 +{ 1.462 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject"); 1.463 + aCb.NoteXPCOMChild(mThisObject); 1.464 + 1.465 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mCallback"); 1.466 + aCb.NoteXPCOMChild(mCallback); 1.467 +} 1.468 + 1.469 +CustomElementCallback::CustomElementCallback(Element* aThisObject, 1.470 + nsIDocument::ElementCallbackType aCallbackType, 1.471 + mozilla::dom::CallbackFunction* aCallback, 1.472 + CustomElementData* aOwnerData) 1.473 + : mThisObject(aThisObject), 1.474 + mCallback(aCallback), 1.475 + mType(aCallbackType), 1.476 + mOwnerData(aOwnerData) 1.477 +{ 1.478 +} 1.479 + 1.480 +CustomElementDefinition::CustomElementDefinition(JSObject* aPrototype, 1.481 + nsIAtom* aType, 1.482 + nsIAtom* aLocalName, 1.483 + LifecycleCallbacks* aCallbacks, 1.484 + uint32_t aNamespaceID, 1.485 + uint32_t aDocOrder) 1.486 + : mPrototype(aPrototype), 1.487 + mType(aType), 1.488 + mLocalName(aLocalName), 1.489 + mCallbacks(aCallbacks), 1.490 + mNamespaceID(aNamespaceID), 1.491 + mDocOrder(aDocOrder) 1.492 +{ 1.493 +} 1.494 + 1.495 +CustomElementData::CustomElementData(nsIAtom* aType) 1.496 + : mType(aType), 1.497 + mCurrentCallback(-1), 1.498 + mElementIsBeingCreated(false), 1.499 + mCreatedCallbackInvoked(true), 1.500 + mAssociatedMicroTask(-1) 1.501 +{ 1.502 +} 1.503 + 1.504 +void 1.505 +CustomElementData::RunCallbackQueue() 1.506 +{ 1.507 + // Note: It's possible to re-enter this method. 1.508 + while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) { 1.509 + mCallbackQueue[mCurrentCallback]->Call(); 1.510 + } 1.511 + 1.512 + mCallbackQueue.Clear(); 1.513 + mCurrentCallback = -1; 1.514 +} 1.515 + 1.516 +} // namespace dom 1.517 +} // namespace mozilla 1.518 + 1.519 +static PLDHashOperator 1.520 +FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry *aEntry, void *aArg) 1.521 +{ 1.522 + FireChangeArgs* args = static_cast<FireChangeArgs*>(aArg); 1.523 + // Don't fire image changes for non-image observers, and don't fire element 1.524 + // changes for image observers when an image override is active. 1.525 + if (aEntry->mKey.mForImage ? (args->mHaveImageOverride && !args->mImageOnly) : 1.526 + args->mImageOnly) 1.527 + return PL_DHASH_NEXT; 1.528 + return aEntry->mKey.mCallback(args->mFrom, args->mTo, aEntry->mKey.mData) 1.529 + ? PL_DHASH_NEXT : PL_DHASH_REMOVE; 1.530 +} 1.531 + 1.532 +void 1.533 +nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement, 1.534 + Element* aNewElement, 1.535 + bool aImageOnly) 1.536 +{ 1.537 + if (!mChangeCallbacks) 1.538 + return; 1.539 + 1.540 + FireChangeArgs args = { aOldElement, aNewElement, aImageOnly, !!mImageElement }; 1.541 + mChangeCallbacks->EnumerateEntries(FireChangeEnumerator, &args); 1.542 +} 1.543 + 1.544 +bool 1.545 +nsIdentifierMapEntry::AddIdElement(Element* aElement) 1.546 +{ 1.547 + NS_PRECONDITION(aElement, "Must have element"); 1.548 + NS_PRECONDITION(mIdContentList.IndexOf(nullptr) < 0, 1.549 + "Why is null in our list?"); 1.550 + 1.551 +#ifdef DEBUG 1.552 + Element* currentElement = 1.553 + static_cast<Element*>(mIdContentList.SafeElementAt(0)); 1.554 +#endif 1.555 + 1.556 + // Common case 1.557 + if (mIdContentList.Count() == 0) { 1.558 + if (!mIdContentList.AppendElement(aElement)) 1.559 + return false; 1.560 + NS_ASSERTION(currentElement == nullptr, "How did that happen?"); 1.561 + FireChangeCallbacks(nullptr, aElement); 1.562 + return true; 1.563 + } 1.564 + 1.565 + // We seem to have multiple content nodes for the same id, or XUL is messing 1.566 + // with us. Search for the right place to insert the content. 1.567 + int32_t start = 0; 1.568 + int32_t end = mIdContentList.Count(); 1.569 + do { 1.570 + NS_ASSERTION(start < end, "Bogus start/end"); 1.571 + 1.572 + int32_t cur = (start + end) / 2; 1.573 + NS_ASSERTION(cur >= start && cur < end, "What happened here?"); 1.574 + 1.575 + Element* curElement = static_cast<Element*>(mIdContentList[cur]); 1.576 + if (curElement == aElement) { 1.577 + // Already in the list, so already in the right spot. Get out of here. 1.578 + // XXXbz this only happens because XUL does all sorts of random 1.579 + // UpdateIdTableEntry calls. Hate, hate, hate! 1.580 + return true; 1.581 + } 1.582 + 1.583 + if (nsContentUtils::PositionIsBefore(aElement, curElement)) { 1.584 + end = cur; 1.585 + } else { 1.586 + start = cur + 1; 1.587 + } 1.588 + } while (start != end); 1.589 + 1.590 + if (!mIdContentList.InsertElementAt(aElement, start)) 1.591 + return false; 1.592 + 1.593 + if (start == 0) { 1.594 + Element* oldElement = 1.595 + static_cast<Element*>(mIdContentList.SafeElementAt(1)); 1.596 + NS_ASSERTION(currentElement == oldElement, "How did that happen?"); 1.597 + FireChangeCallbacks(oldElement, aElement); 1.598 + } 1.599 + return true; 1.600 +} 1.601 + 1.602 +void 1.603 +nsIdentifierMapEntry::RemoveIdElement(Element* aElement) 1.604 +{ 1.605 + NS_PRECONDITION(aElement, "Missing element"); 1.606 + 1.607 + // This should only be called while the document is in an update. 1.608 + // Assertions near the call to this method guarantee this. 1.609 + 1.610 + // This could fire in OOM situations 1.611 + // Only assert this in HTML documents for now as XUL does all sorts of weird 1.612 + // crap. 1.613 + NS_ASSERTION(!aElement->OwnerDoc()->IsHTML() || 1.614 + mIdContentList.IndexOf(aElement) >= 0, 1.615 + "Removing id entry that doesn't exist"); 1.616 + 1.617 + // XXXbz should this ever Compact() I guess when all the content is gone 1.618 + // we'll just get cleaned up in the natural order of things... 1.619 + Element* currentElement = 1.620 + static_cast<Element*>(mIdContentList.SafeElementAt(0)); 1.621 + mIdContentList.RemoveElement(aElement); 1.622 + if (currentElement == aElement) { 1.623 + FireChangeCallbacks(currentElement, 1.624 + static_cast<Element*>(mIdContentList.SafeElementAt(0))); 1.625 + } 1.626 +} 1.627 + 1.628 +void 1.629 +nsIdentifierMapEntry::SetImageElement(Element* aElement) 1.630 +{ 1.631 + Element* oldElement = GetImageIdElement(); 1.632 + mImageElement = aElement; 1.633 + Element* newElement = GetImageIdElement(); 1.634 + if (oldElement != newElement) { 1.635 + FireChangeCallbacks(oldElement, newElement, true); 1.636 + } 1.637 +} 1.638 + 1.639 +void 1.640 +nsIdentifierMapEntry::AddNameElement(nsINode* aNode, Element* aElement) 1.641 +{ 1.642 + if (!mNameContentList) { 1.643 + mNameContentList = new nsSimpleContentList(aNode); 1.644 + } 1.645 + 1.646 + mNameContentList->AppendElement(aElement); 1.647 +} 1.648 + 1.649 +void 1.650 +nsIdentifierMapEntry::RemoveNameElement(Element* aElement) 1.651 +{ 1.652 + if (mNameContentList) { 1.653 + mNameContentList->RemoveElement(aElement); 1.654 + } 1.655 +} 1.656 + 1.657 +bool 1.658 +nsIdentifierMapEntry::HasIdElementExposedAsHTMLDocumentProperty() 1.659 +{ 1.660 + Element* idElement = GetIdElement(); 1.661 + return idElement && 1.662 + nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(idElement); 1.663 +} 1.664 + 1.665 +// static 1.666 +size_t 1.667 +nsIdentifierMapEntry::SizeOfExcludingThis(nsIdentifierMapEntry* aEntry, 1.668 + MallocSizeOf aMallocSizeOf, 1.669 + void*) 1.670 +{ 1.671 + return aEntry->GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf); 1.672 +} 1.673 + 1.674 +// Helper structs for the content->subdoc map 1.675 + 1.676 +class SubDocMapEntry : public PLDHashEntryHdr 1.677 +{ 1.678 +public: 1.679 + // Both of these are strong references 1.680 + Element *mKey; // must be first, to look like PLDHashEntryStub 1.681 + nsIDocument *mSubDocument; 1.682 +}; 1.683 + 1.684 +struct FindContentData 1.685 +{ 1.686 + FindContentData(nsIDocument *aSubDoc) 1.687 + : mSubDocument(aSubDoc), mResult(nullptr) 1.688 + { 1.689 + } 1.690 + 1.691 + nsISupports *mSubDocument; 1.692 + Element *mResult; 1.693 +}; 1.694 + 1.695 + 1.696 +/** 1.697 + * A struct that holds all the information about a radio group. 1.698 + */ 1.699 +struct nsRadioGroupStruct 1.700 +{ 1.701 + nsRadioGroupStruct() 1.702 + : mRequiredRadioCount(0) 1.703 + , mGroupSuffersFromValueMissing(false) 1.704 + {} 1.705 + 1.706 + /** 1.707 + * A strong pointer to the currently selected radio button. 1.708 + */ 1.709 + nsRefPtr<HTMLInputElement> mSelectedRadioButton; 1.710 + nsCOMArray<nsIFormControl> mRadioButtons; 1.711 + uint32_t mRequiredRadioCount; 1.712 + bool mGroupSuffersFromValueMissing; 1.713 +}; 1.714 + 1.715 + 1.716 +nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument) 1.717 +{ 1.718 + mLength = -1; 1.719 + // Not reference counted to avoid circular references. 1.720 + // The document will tell us when its going away. 1.721 + mDocument = aDocument; 1.722 + mDocument->AddObserver(this); 1.723 +} 1.724 + 1.725 +nsDOMStyleSheetList::~nsDOMStyleSheetList() 1.726 +{ 1.727 + if (mDocument) { 1.728 + mDocument->RemoveObserver(this); 1.729 + } 1.730 +} 1.731 + 1.732 +NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList, StyleSheetList, 1.733 + nsIDocumentObserver, 1.734 + nsIMutationObserver) 1.735 + 1.736 +uint32_t 1.737 +nsDOMStyleSheetList::Length() 1.738 +{ 1.739 + if (!mDocument) { 1.740 + return 0; 1.741 + } 1.742 + 1.743 + // XXX Find the number and then cache it. We'll use the 1.744 + // observer notification to figure out if new ones have 1.745 + // been added or removed. 1.746 + if (-1 == mLength) { 1.747 + mLength = mDocument->GetNumberOfStyleSheets(); 1.748 + 1.749 +#ifdef DEBUG 1.750 + int32_t i; 1.751 + for (i = 0; i < mLength; i++) { 1.752 + nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i); 1.753 + nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet)); 1.754 + NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet"); 1.755 + } 1.756 +#endif 1.757 + } 1.758 + return mLength; 1.759 +} 1.760 + 1.761 +nsCSSStyleSheet* 1.762 +nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound) 1.763 +{ 1.764 + if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) { 1.765 + aFound = false; 1.766 + return nullptr; 1.767 + } 1.768 + 1.769 + aFound = true; 1.770 + nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(aIndex); 1.771 + NS_ASSERTION(sheet, "Must have a sheet"); 1.772 + 1.773 + return static_cast<nsCSSStyleSheet*>(sheet); 1.774 +} 1.775 + 1.776 +void 1.777 +nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode) 1.778 +{ 1.779 + mDocument = nullptr; 1.780 +} 1.781 + 1.782 +void 1.783 +nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument, 1.784 + nsIStyleSheet* aStyleSheet, 1.785 + bool aDocumentSheet) 1.786 +{ 1.787 + if (aDocumentSheet && -1 != mLength) { 1.788 + nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet)); 1.789 + if (domss) { 1.790 + mLength++; 1.791 + } 1.792 + } 1.793 +} 1.794 + 1.795 +void 1.796 +nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument, 1.797 + nsIStyleSheet* aStyleSheet, 1.798 + bool aDocumentSheet) 1.799 +{ 1.800 + if (aDocumentSheet && -1 != mLength) { 1.801 + nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet)); 1.802 + if (domss) { 1.803 + mLength--; 1.804 + } 1.805 + } 1.806 +} 1.807 + 1.808 +// nsOnloadBlocker implementation 1.809 +NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest) 1.810 + 1.811 +NS_IMETHODIMP 1.812 +nsOnloadBlocker::GetName(nsACString &aResult) 1.813 +{ 1.814 + aResult.AssignLiteral("about:document-onload-blocker"); 1.815 + return NS_OK; 1.816 +} 1.817 + 1.818 +NS_IMETHODIMP 1.819 +nsOnloadBlocker::IsPending(bool *_retval) 1.820 +{ 1.821 + *_retval = true; 1.822 + return NS_OK; 1.823 +} 1.824 + 1.825 +NS_IMETHODIMP 1.826 +nsOnloadBlocker::GetStatus(nsresult *status) 1.827 +{ 1.828 + *status = NS_OK; 1.829 + return NS_OK; 1.830 +} 1.831 + 1.832 +NS_IMETHODIMP 1.833 +nsOnloadBlocker::Cancel(nsresult status) 1.834 +{ 1.835 + return NS_OK; 1.836 +} 1.837 +NS_IMETHODIMP 1.838 +nsOnloadBlocker::Suspend(void) 1.839 +{ 1.840 + return NS_OK; 1.841 +} 1.842 +NS_IMETHODIMP 1.843 +nsOnloadBlocker::Resume(void) 1.844 +{ 1.845 + return NS_OK; 1.846 +} 1.847 + 1.848 +NS_IMETHODIMP 1.849 +nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup) 1.850 +{ 1.851 + *aLoadGroup = nullptr; 1.852 + return NS_OK; 1.853 +} 1.854 + 1.855 +NS_IMETHODIMP 1.856 +nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup) 1.857 +{ 1.858 + return NS_OK; 1.859 +} 1.860 + 1.861 +NS_IMETHODIMP 1.862 +nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags) 1.863 +{ 1.864 + *aLoadFlags = nsIRequest::LOAD_NORMAL; 1.865 + return NS_OK; 1.866 +} 1.867 + 1.868 +NS_IMETHODIMP 1.869 +nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags) 1.870 +{ 1.871 + return NS_OK; 1.872 +} 1.873 + 1.874 +// ================================================================== 1.875 + 1.876 +nsExternalResourceMap::nsExternalResourceMap() 1.877 + : mHaveShutDown(false) 1.878 +{ 1.879 +} 1.880 + 1.881 +nsIDocument* 1.882 +nsExternalResourceMap::RequestResource(nsIURI* aURI, 1.883 + nsINode* aRequestingNode, 1.884 + nsDocument* aDisplayDocument, 1.885 + ExternalResourceLoad** aPendingLoad) 1.886 +{ 1.887 + // If we ever start allowing non-same-origin loads here, we might need to do 1.888 + // something interesting with aRequestingPrincipal even for the hashtable 1.889 + // gets. 1.890 + NS_PRECONDITION(aURI, "Must have a URI"); 1.891 + NS_PRECONDITION(aRequestingNode, "Must have a node"); 1.892 + *aPendingLoad = nullptr; 1.893 + if (mHaveShutDown) { 1.894 + return nullptr; 1.895 + } 1.896 + 1.897 + // First, make sure we strip the ref from aURI. 1.898 + nsCOMPtr<nsIURI> clone; 1.899 + nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(clone)); 1.900 + if (NS_FAILED(rv) || !clone) { 1.901 + return nullptr; 1.902 + } 1.903 + 1.904 + ExternalResource* resource; 1.905 + mMap.Get(clone, &resource); 1.906 + if (resource) { 1.907 + return resource->mDocument; 1.908 + } 1.909 + 1.910 + nsRefPtr<PendingLoad> load; 1.911 + mPendingLoads.Get(clone, getter_AddRefs(load)); 1.912 + if (load) { 1.913 + load.forget(aPendingLoad); 1.914 + return nullptr; 1.915 + } 1.916 + 1.917 + load = new PendingLoad(aDisplayDocument); 1.918 + 1.919 + mPendingLoads.Put(clone, load); 1.920 + 1.921 + if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) { 1.922 + // Make sure we don't thrash things by trying this load again, since 1.923 + // chances are it failed for good reasons (security check, etc). 1.924 + AddExternalResource(clone, nullptr, nullptr, aDisplayDocument); 1.925 + } else { 1.926 + load.forget(aPendingLoad); 1.927 + } 1.928 + 1.929 + return nullptr; 1.930 +} 1.931 + 1.932 +struct 1.933 +nsExternalResourceEnumArgs 1.934 +{ 1.935 + nsIDocument::nsSubDocEnumFunc callback; 1.936 + void *data; 1.937 +}; 1.938 + 1.939 +static PLDHashOperator 1.940 +ExternalResourceEnumerator(nsIURI* aKey, 1.941 + nsExternalResourceMap::ExternalResource* aData, 1.942 + void* aClosure) 1.943 +{ 1.944 + nsExternalResourceEnumArgs* args = 1.945 + static_cast<nsExternalResourceEnumArgs*>(aClosure); 1.946 + bool next = 1.947 + aData->mDocument ? args->callback(aData->mDocument, args->data) : true; 1.948 + return next ? PL_DHASH_NEXT : PL_DHASH_STOP; 1.949 +} 1.950 + 1.951 +void 1.952 +nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback, 1.953 + void* aData) 1.954 +{ 1.955 + nsExternalResourceEnumArgs args = { aCallback, aData }; 1.956 + mMap.EnumerateRead(ExternalResourceEnumerator, &args); 1.957 +} 1.958 + 1.959 +static PLDHashOperator 1.960 +ExternalResourceTraverser(nsIURI* aKey, 1.961 + nsExternalResourceMap::ExternalResource* aData, 1.962 + void* aClosure) 1.963 +{ 1.964 + nsCycleCollectionTraversalCallback *cb = 1.965 + static_cast<nsCycleCollectionTraversalCallback*>(aClosure); 1.966 + 1.967 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.968 + "mExternalResourceMap.mMap entry" 1.969 + "->mDocument"); 1.970 + cb->NoteXPCOMChild(aData->mDocument); 1.971 + 1.972 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.973 + "mExternalResourceMap.mMap entry" 1.974 + "->mViewer"); 1.975 + cb->NoteXPCOMChild(aData->mViewer); 1.976 + 1.977 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.978 + "mExternalResourceMap.mMap entry" 1.979 + "->mLoadGroup"); 1.980 + cb->NoteXPCOMChild(aData->mLoadGroup); 1.981 + 1.982 + return PL_DHASH_NEXT; 1.983 +} 1.984 + 1.985 +void 1.986 +nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const 1.987 +{ 1.988 + // mPendingLoads will get cleared out as the requests complete, so 1.989 + // no need to worry about those here. 1.990 + mMap.EnumerateRead(ExternalResourceTraverser, aCallback); 1.991 +} 1.992 + 1.993 +static PLDHashOperator 1.994 +ExternalResourceHider(nsIURI* aKey, 1.995 + nsExternalResourceMap::ExternalResource* aData, 1.996 + void* aClosure) 1.997 +{ 1.998 + if (aData->mViewer) { 1.999 + aData->mViewer->Hide(); 1.1000 + } 1.1001 + return PL_DHASH_NEXT; 1.1002 +} 1.1003 + 1.1004 +void 1.1005 +nsExternalResourceMap::HideViewers() 1.1006 +{ 1.1007 + mMap.EnumerateRead(ExternalResourceHider, nullptr); 1.1008 +} 1.1009 + 1.1010 +static PLDHashOperator 1.1011 +ExternalResourceShower(nsIURI* aKey, 1.1012 + nsExternalResourceMap::ExternalResource* aData, 1.1013 + void* aClosure) 1.1014 +{ 1.1015 + if (aData->mViewer) { 1.1016 + aData->mViewer->Show(); 1.1017 + } 1.1018 + return PL_DHASH_NEXT; 1.1019 +} 1.1020 + 1.1021 +void 1.1022 +nsExternalResourceMap::ShowViewers() 1.1023 +{ 1.1024 + mMap.EnumerateRead(ExternalResourceShower, nullptr); 1.1025 +} 1.1026 + 1.1027 +void 1.1028 +TransferZoomLevels(nsIDocument* aFromDoc, 1.1029 + nsIDocument* aToDoc) 1.1030 +{ 1.1031 + NS_ABORT_IF_FALSE(aFromDoc && aToDoc, 1.1032 + "transferring zoom levels from/to null doc"); 1.1033 + 1.1034 + nsIPresShell* fromShell = aFromDoc->GetShell(); 1.1035 + if (!fromShell) 1.1036 + return; 1.1037 + 1.1038 + nsPresContext* fromCtxt = fromShell->GetPresContext(); 1.1039 + if (!fromCtxt) 1.1040 + return; 1.1041 + 1.1042 + nsIPresShell* toShell = aToDoc->GetShell(); 1.1043 + if (!toShell) 1.1044 + return; 1.1045 + 1.1046 + nsPresContext* toCtxt = toShell->GetPresContext(); 1.1047 + if (!toCtxt) 1.1048 + return; 1.1049 + 1.1050 + toCtxt->SetFullZoom(fromCtxt->GetFullZoom()); 1.1051 + toCtxt->SetBaseMinFontSize(fromCtxt->BaseMinFontSize()); 1.1052 + toCtxt->SetTextZoom(fromCtxt->TextZoom()); 1.1053 +} 1.1054 + 1.1055 +void 1.1056 +TransferShowingState(nsIDocument* aFromDoc, nsIDocument* aToDoc) 1.1057 +{ 1.1058 + NS_ABORT_IF_FALSE(aFromDoc && aToDoc, 1.1059 + "transferring showing state from/to null doc"); 1.1060 + 1.1061 + if (aFromDoc->IsShowing()) { 1.1062 + aToDoc->OnPageShow(true, nullptr); 1.1063 + } 1.1064 +} 1.1065 + 1.1066 +nsresult 1.1067 +nsExternalResourceMap::AddExternalResource(nsIURI* aURI, 1.1068 + nsIContentViewer* aViewer, 1.1069 + nsILoadGroup* aLoadGroup, 1.1070 + nsIDocument* aDisplayDocument) 1.1071 +{ 1.1072 + NS_PRECONDITION(aURI, "Unexpected call"); 1.1073 + NS_PRECONDITION((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup), 1.1074 + "Must have both or neither"); 1.1075 + 1.1076 + nsRefPtr<PendingLoad> load; 1.1077 + mPendingLoads.Get(aURI, getter_AddRefs(load)); 1.1078 + mPendingLoads.Remove(aURI); 1.1079 + 1.1080 + nsresult rv = NS_OK; 1.1081 + 1.1082 + nsCOMPtr<nsIDocument> doc; 1.1083 + if (aViewer) { 1.1084 + doc = aViewer->GetDocument(); 1.1085 + NS_ASSERTION(doc, "Must have a document"); 1.1086 + 1.1087 + nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(doc); 1.1088 + if (xulDoc) { 1.1089 + // We don't handle XUL stuff here yet. 1.1090 + rv = NS_ERROR_NOT_AVAILABLE; 1.1091 + } else { 1.1092 + doc->SetDisplayDocument(aDisplayDocument); 1.1093 + 1.1094 + // Make sure that hiding our viewer will tear down its presentation. 1.1095 + aViewer->SetSticky(false); 1.1096 + 1.1097 + rv = aViewer->Init(nullptr, nsIntRect(0, 0, 0, 0)); 1.1098 + if (NS_SUCCEEDED(rv)) { 1.1099 + rv = aViewer->Open(nullptr, nullptr); 1.1100 + } 1.1101 + } 1.1102 + 1.1103 + if (NS_FAILED(rv)) { 1.1104 + doc = nullptr; 1.1105 + aViewer = nullptr; 1.1106 + aLoadGroup = nullptr; 1.1107 + } 1.1108 + } 1.1109 + 1.1110 + ExternalResource* newResource = new ExternalResource(); 1.1111 + mMap.Put(aURI, newResource); 1.1112 + 1.1113 + newResource->mDocument = doc; 1.1114 + newResource->mViewer = aViewer; 1.1115 + newResource->mLoadGroup = aLoadGroup; 1.1116 + if (doc) { 1.1117 + TransferZoomLevels(aDisplayDocument, doc); 1.1118 + TransferShowingState(aDisplayDocument, doc); 1.1119 + } 1.1120 + 1.1121 + const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers(); 1.1122 + for (uint32_t i = 0; i < obs.Length(); ++i) { 1.1123 + obs[i]->Observe(doc, "external-resource-document-created", nullptr); 1.1124 + } 1.1125 + 1.1126 + return rv; 1.1127 +} 1.1128 + 1.1129 +NS_IMPL_ISUPPORTS(nsExternalResourceMap::PendingLoad, 1.1130 + nsIStreamListener, 1.1131 + nsIRequestObserver) 1.1132 + 1.1133 +NS_IMETHODIMP 1.1134 +nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest *aRequest, 1.1135 + nsISupports *aContext) 1.1136 +{ 1.1137 + nsExternalResourceMap& map = mDisplayDocument->ExternalResourceMap(); 1.1138 + if (map.HaveShutDown()) { 1.1139 + return NS_BINDING_ABORTED; 1.1140 + } 1.1141 + 1.1142 + nsCOMPtr<nsIContentViewer> viewer; 1.1143 + nsCOMPtr<nsILoadGroup> loadGroup; 1.1144 + nsresult rv = SetupViewer(aRequest, getter_AddRefs(viewer), 1.1145 + getter_AddRefs(loadGroup)); 1.1146 + 1.1147 + // Make sure to do this no matter what 1.1148 + nsresult rv2 = map.AddExternalResource(mURI, viewer, loadGroup, 1.1149 + mDisplayDocument); 1.1150 + if (NS_FAILED(rv)) { 1.1151 + return rv; 1.1152 + } 1.1153 + if (NS_FAILED(rv2)) { 1.1154 + mTargetListener = nullptr; 1.1155 + return rv2; 1.1156 + } 1.1157 + 1.1158 + return mTargetListener->OnStartRequest(aRequest, aContext); 1.1159 +} 1.1160 + 1.1161 +nsresult 1.1162 +nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest* aRequest, 1.1163 + nsIContentViewer** aViewer, 1.1164 + nsILoadGroup** aLoadGroup) 1.1165 +{ 1.1166 + NS_PRECONDITION(!mTargetListener, "Unexpected call to OnStartRequest"); 1.1167 + *aViewer = nullptr; 1.1168 + *aLoadGroup = nullptr; 1.1169 + 1.1170 + nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest)); 1.1171 + NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED); 1.1172 + 1.1173 + nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest)); 1.1174 + if (httpChannel) { 1.1175 + bool requestSucceeded; 1.1176 + if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) || 1.1177 + !requestSucceeded) { 1.1178 + // Bail out on this load, since it looks like we have an HTTP error page 1.1179 + return NS_BINDING_ABORTED; 1.1180 + } 1.1181 + } 1.1182 + 1.1183 + nsAutoCString type; 1.1184 + chan->GetContentType(type); 1.1185 + 1.1186 + nsCOMPtr<nsILoadGroup> loadGroup; 1.1187 + chan->GetLoadGroup(getter_AddRefs(loadGroup)); 1.1188 + 1.1189 + // Give this document its own loadgroup 1.1190 + nsCOMPtr<nsILoadGroup> newLoadGroup = 1.1191 + do_CreateInstance(NS_LOADGROUP_CONTRACTID); 1.1192 + NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY); 1.1193 + newLoadGroup->SetLoadGroup(loadGroup); 1.1194 + 1.1195 + nsCOMPtr<nsIInterfaceRequestor> callbacks; 1.1196 + loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks)); 1.1197 + 1.1198 + nsCOMPtr<nsIInterfaceRequestor> newCallbacks = 1.1199 + new LoadgroupCallbacks(callbacks); 1.1200 + newLoadGroup->SetNotificationCallbacks(newCallbacks); 1.1201 + 1.1202 + // This is some serious hackery cribbed from docshell 1.1203 + nsCOMPtr<nsICategoryManager> catMan = 1.1204 + do_GetService(NS_CATEGORYMANAGER_CONTRACTID); 1.1205 + NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE); 1.1206 + nsXPIDLCString contractId; 1.1207 + nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", type.get(), 1.1208 + getter_Copies(contractId)); 1.1209 + NS_ENSURE_SUCCESS(rv, rv); 1.1210 + nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory = 1.1211 + do_GetService(contractId); 1.1212 + NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE); 1.1213 + 1.1214 + nsCOMPtr<nsIContentViewer> viewer; 1.1215 + nsCOMPtr<nsIStreamListener> listener; 1.1216 + rv = docLoaderFactory->CreateInstance("external-resource", chan, newLoadGroup, 1.1217 + type.get(), nullptr, nullptr, 1.1218 + getter_AddRefs(listener), 1.1219 + getter_AddRefs(viewer)); 1.1220 + NS_ENSURE_SUCCESS(rv, rv); 1.1221 + NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED); 1.1222 + 1.1223 + nsCOMPtr<nsIParser> parser = do_QueryInterface(listener); 1.1224 + if (!parser) { 1.1225 + /// We don't want to deal with the various fake documents yet 1.1226 + return NS_ERROR_NOT_IMPLEMENTED; 1.1227 + } 1.1228 + 1.1229 + // We can't handle HTML and other weird things here yet. 1.1230 + nsIContentSink* sink = parser->GetContentSink(); 1.1231 + nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink); 1.1232 + if (!xmlSink) { 1.1233 + return NS_ERROR_NOT_IMPLEMENTED; 1.1234 + } 1.1235 + 1.1236 + listener.swap(mTargetListener); 1.1237 + viewer.forget(aViewer); 1.1238 + newLoadGroup.forget(aLoadGroup); 1.1239 + return NS_OK; 1.1240 +} 1.1241 + 1.1242 +NS_IMETHODIMP 1.1243 +nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest, 1.1244 + nsISupports* aContext, 1.1245 + nsIInputStream* aStream, 1.1246 + uint64_t aOffset, 1.1247 + uint32_t aCount) 1.1248 +{ 1.1249 + NS_PRECONDITION(mTargetListener, "Shouldn't be getting called!"); 1.1250 + if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) { 1.1251 + return NS_BINDING_ABORTED; 1.1252 + } 1.1253 + return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset, 1.1254 + aCount); 1.1255 +} 1.1256 + 1.1257 +NS_IMETHODIMP 1.1258 +nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest, 1.1259 + nsISupports* aContext, 1.1260 + nsresult aStatus) 1.1261 +{ 1.1262 + // mTargetListener might be null if SetupViewer or AddExternalResource failed 1.1263 + if (mTargetListener) { 1.1264 + nsCOMPtr<nsIStreamListener> listener; 1.1265 + mTargetListener.swap(listener); 1.1266 + return listener->OnStopRequest(aRequest, aContext, aStatus); 1.1267 + } 1.1268 + 1.1269 + return NS_OK; 1.1270 +} 1.1271 + 1.1272 +nsresult 1.1273 +nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI, 1.1274 + nsINode* aRequestingNode) 1.1275 +{ 1.1276 + NS_PRECONDITION(aURI, "Must have a URI"); 1.1277 + NS_PRECONDITION(aRequestingNode, "Must have a node"); 1.1278 + 1.1279 + // Time to start a load. First, the security checks. 1.1280 + 1.1281 + nsIPrincipal* requestingPrincipal = aRequestingNode->NodePrincipal(); 1.1282 + 1.1283 + nsresult rv = nsContentUtils::GetSecurityManager()-> 1.1284 + CheckLoadURIWithPrincipal(requestingPrincipal, aURI, 1.1285 + nsIScriptSecurityManager::STANDARD); 1.1286 + NS_ENSURE_SUCCESS(rv, rv); 1.1287 + 1.1288 + // Allow data URIs and other URI's that inherit their principal by passing 1.1289 + // true as the 3rd argument of CheckMayLoad, since we want 1.1290 + // to allow external resources from data URIs regardless of the difference 1.1291 + // in URI scheme. 1.1292 + rv = requestingPrincipal->CheckMayLoad(aURI, true, true); 1.1293 + NS_ENSURE_SUCCESS(rv, rv); 1.1294 + 1.1295 + int16_t shouldLoad = nsIContentPolicy::ACCEPT; 1.1296 + rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER, 1.1297 + aURI, 1.1298 + requestingPrincipal, 1.1299 + aRequestingNode, 1.1300 + EmptyCString(), //mime guess 1.1301 + nullptr, //extra 1.1302 + &shouldLoad, 1.1303 + nsContentUtils::GetContentPolicy(), 1.1304 + nsContentUtils::GetSecurityManager()); 1.1305 + if (NS_FAILED(rv)) return rv; 1.1306 + if (NS_CP_REJECTED(shouldLoad)) { 1.1307 + // Disallowed by content policy 1.1308 + return NS_ERROR_CONTENT_BLOCKED; 1.1309 + } 1.1310 + 1.1311 + nsIDocument* doc = aRequestingNode->OwnerDoc(); 1.1312 + 1.1313 + nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker(); 1.1314 + NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY); 1.1315 + 1.1316 + nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup(); 1.1317 + nsCOMPtr<nsIChannel> channel; 1.1318 + rv = NS_NewChannel(getter_AddRefs(channel), aURI, nullptr, loadGroup, req); 1.1319 + NS_ENSURE_SUCCESS(rv, rv); 1.1320 + 1.1321 + mURI = aURI; 1.1322 + 1.1323 + return channel->AsyncOpen(this, nullptr); 1.1324 +} 1.1325 + 1.1326 +NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks, 1.1327 + nsIInterfaceRequestor) 1.1328 + 1.1329 +#define IMPL_SHIM(_i) \ 1.1330 + NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i) 1.1331 + 1.1332 +IMPL_SHIM(nsILoadContext) 1.1333 +IMPL_SHIM(nsIProgressEventSink) 1.1334 +IMPL_SHIM(nsIChannelEventSink) 1.1335 +IMPL_SHIM(nsISecurityEventSink) 1.1336 +IMPL_SHIM(nsIApplicationCacheContainer) 1.1337 + 1.1338 +#undef IMPL_SHIM 1.1339 + 1.1340 +#define IID_IS(_i) aIID.Equals(NS_GET_IID(_i)) 1.1341 + 1.1342 +#define TRY_SHIM(_i) \ 1.1343 + PR_BEGIN_MACRO \ 1.1344 + if (IID_IS(_i)) { \ 1.1345 + nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \ 1.1346 + if (!real) { \ 1.1347 + return NS_NOINTERFACE; \ 1.1348 + } \ 1.1349 + nsCOMPtr<_i> shim = new _i##Shim(this, real); \ 1.1350 + if (!shim) { \ 1.1351 + return NS_ERROR_OUT_OF_MEMORY; \ 1.1352 + } \ 1.1353 + shim.forget(aSink); \ 1.1354 + return NS_OK; \ 1.1355 + } \ 1.1356 + PR_END_MACRO 1.1357 + 1.1358 +NS_IMETHODIMP 1.1359 +nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID & aIID, 1.1360 + void **aSink) 1.1361 +{ 1.1362 + if (mCallbacks && 1.1363 + (IID_IS(nsIPrompt) || IID_IS(nsIAuthPrompt) || IID_IS(nsIAuthPrompt2) || 1.1364 + IID_IS(nsITabChild))) { 1.1365 + return mCallbacks->GetInterface(aIID, aSink); 1.1366 + } 1.1367 + 1.1368 + *aSink = nullptr; 1.1369 + 1.1370 + TRY_SHIM(nsILoadContext); 1.1371 + TRY_SHIM(nsIProgressEventSink); 1.1372 + TRY_SHIM(nsIChannelEventSink); 1.1373 + TRY_SHIM(nsISecurityEventSink); 1.1374 + TRY_SHIM(nsIApplicationCacheContainer); 1.1375 + 1.1376 + return NS_NOINTERFACE; 1.1377 +} 1.1378 + 1.1379 +#undef TRY_SHIM 1.1380 +#undef IID_IS 1.1381 + 1.1382 +nsExternalResourceMap::ExternalResource::~ExternalResource() 1.1383 +{ 1.1384 + if (mViewer) { 1.1385 + mViewer->Close(nullptr); 1.1386 + mViewer->Destroy(); 1.1387 + } 1.1388 +} 1.1389 + 1.1390 +// ================================================================== 1.1391 +// = 1.1392 +// ================================================================== 1.1393 + 1.1394 +// If we ever have an nsIDocumentObserver notification for stylesheet title 1.1395 +// changes we should update the list from that instead of overriding 1.1396 +// EnsureFresh. 1.1397 +class nsDOMStyleSheetSetList MOZ_FINAL : public DOMStringList 1.1398 +{ 1.1399 +public: 1.1400 + nsDOMStyleSheetSetList(nsIDocument* aDocument); 1.1401 + 1.1402 + void Disconnect() 1.1403 + { 1.1404 + mDocument = nullptr; 1.1405 + } 1.1406 + 1.1407 + virtual void EnsureFresh() MOZ_OVERRIDE; 1.1408 + 1.1409 +protected: 1.1410 + nsIDocument* mDocument; // Our document; weak ref. It'll let us know if it 1.1411 + // dies. 1.1412 +}; 1.1413 + 1.1414 +nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument) 1.1415 + : mDocument(aDocument) 1.1416 +{ 1.1417 + NS_ASSERTION(mDocument, "Must have document!"); 1.1418 +} 1.1419 + 1.1420 +void 1.1421 +nsDOMStyleSheetSetList::EnsureFresh() 1.1422 +{ 1.1423 + mNames.Clear(); 1.1424 + 1.1425 + if (!mDocument) { 1.1426 + return; // Spec says "no exceptions", and we have no style sets if we have 1.1427 + // no document, for sure 1.1428 + } 1.1429 + 1.1430 + int32_t count = mDocument->GetNumberOfStyleSheets(); 1.1431 + nsAutoString title; 1.1432 + for (int32_t index = 0; index < count; index++) { 1.1433 + nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index); 1.1434 + NS_ASSERTION(sheet, "Null sheet in sheet list!"); 1.1435 + sheet->GetTitle(title); 1.1436 + if (!title.IsEmpty() && !mNames.Contains(title) && !Add(title)) { 1.1437 + return; 1.1438 + } 1.1439 + } 1.1440 +} 1.1441 + 1.1442 +// ================================================================== 1.1443 +nsIDocument::SelectorCache::SelectorCache() 1.1444 + : nsExpirationTracker<SelectorCacheKey, 4>(1000) { } 1.1445 + 1.1446 +// CacheList takes ownership of aSelectorList. 1.1447 +void nsIDocument::SelectorCache::CacheList(const nsAString& aSelector, 1.1448 + nsCSSSelectorList* aSelectorList) 1.1449 +{ 1.1450 + SelectorCacheKey* key = new SelectorCacheKey(aSelector); 1.1451 + mTable.Put(key->mKey, aSelectorList); 1.1452 + AddObject(key); 1.1453 +} 1.1454 + 1.1455 +class nsIDocument::SelectorCacheKeyDeleter MOZ_FINAL : public nsRunnable 1.1456 +{ 1.1457 +public: 1.1458 + explicit SelectorCacheKeyDeleter(SelectorCacheKey* aToDelete) 1.1459 + : mSelector(aToDelete) 1.1460 + { 1.1461 + MOZ_COUNT_CTOR(SelectorCacheKeyDeleter); 1.1462 + } 1.1463 + 1.1464 + ~SelectorCacheKeyDeleter() 1.1465 + { 1.1466 + MOZ_COUNT_DTOR(SelectorCacheKeyDeleter); 1.1467 + } 1.1468 + 1.1469 + NS_IMETHOD Run() 1.1470 + { 1.1471 + return NS_OK; 1.1472 + } 1.1473 + 1.1474 +private: 1.1475 + nsAutoPtr<SelectorCacheKey> mSelector; 1.1476 +}; 1.1477 + 1.1478 +void nsIDocument::SelectorCache::NotifyExpired(SelectorCacheKey* aSelector) 1.1479 +{ 1.1480 + RemoveObject(aSelector); 1.1481 + mTable.Remove(aSelector->mKey); 1.1482 + nsCOMPtr<nsIRunnable> runnable = new SelectorCacheKeyDeleter(aSelector); 1.1483 + NS_DispatchToCurrentThread(runnable); 1.1484 +} 1.1485 + 1.1486 + 1.1487 +struct nsIDocument::FrameRequest 1.1488 +{ 1.1489 + FrameRequest(const FrameRequestCallbackHolder& aCallback, 1.1490 + int32_t aHandle) : 1.1491 + mCallback(aCallback), 1.1492 + mHandle(aHandle) 1.1493 + {} 1.1494 + 1.1495 + // Conversion operator so that we can append these to a 1.1496 + // FrameRequestCallbackList 1.1497 + operator const FrameRequestCallbackHolder& () const { 1.1498 + return mCallback; 1.1499 + } 1.1500 + 1.1501 + // Comparator operators to allow RemoveElementSorted with an 1.1502 + // integer argument on arrays of FrameRequest 1.1503 + bool operator==(int32_t aHandle) const { 1.1504 + return mHandle == aHandle; 1.1505 + } 1.1506 + bool operator<(int32_t aHandle) const { 1.1507 + return mHandle < aHandle; 1.1508 + } 1.1509 + 1.1510 + FrameRequestCallbackHolder mCallback; 1.1511 + int32_t mHandle; 1.1512 +}; 1.1513 + 1.1514 +static already_AddRefed<nsINodeInfo> nullNodeInfo(nullptr); 1.1515 + 1.1516 +// ================================================================== 1.1517 +// = 1.1518 +// ================================================================== 1.1519 +nsIDocument::nsIDocument() 1.1520 + : nsINode(nullNodeInfo), 1.1521 + mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")), 1.1522 + mNodeInfoManager(nullptr), 1.1523 + mCompatMode(eCompatibility_FullStandards), 1.1524 + mVisibilityState(dom::VisibilityState::Hidden), 1.1525 + mIsInitialDocumentInWindow(false), 1.1526 + mMayStartLayout(true), 1.1527 + mVisible(true), 1.1528 + mRemovedFromDocShell(false), 1.1529 + // mAllowDNSPrefetch starts true, so that we can always reliably && it 1.1530 + // with various values that might disable it. Since we never prefetch 1.1531 + // unless we get a window, and in that case the docshell value will get 1.1532 + // &&-ed in, this is safe. 1.1533 + mAllowDNSPrefetch(true), 1.1534 + mIsBeingUsedAsImage(false), 1.1535 + mHasLinksToUpdate(false), 1.1536 + mPartID(0), 1.1537 + mDidFireDOMContentLoaded(true) 1.1538 +{ 1.1539 + SetInDocument(); 1.1540 +} 1.1541 + 1.1542 +// NOTE! nsDocument::operator new() zeroes out all members, so don't 1.1543 +// bother initializing members to 0. 1.1544 + 1.1545 +nsDocument::nsDocument(const char* aContentType) 1.1546 + : nsIDocument() 1.1547 + , mAnimatingImages(true) 1.1548 + , mViewportType(Unknown) 1.1549 +{ 1.1550 + SetContentTypeInternal(nsDependentCString(aContentType)); 1.1551 + 1.1552 +#ifdef PR_LOGGING 1.1553 + if (!gDocumentLeakPRLog) 1.1554 + gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak"); 1.1555 + 1.1556 + if (gDocumentLeakPRLog) 1.1557 + PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG, 1.1558 + ("DOCUMENT %p created", this)); 1.1559 + 1.1560 + if (!gCspPRLog) 1.1561 + gCspPRLog = PR_NewLogModule("CSP"); 1.1562 +#endif 1.1563 + 1.1564 + // Start out mLastStyleSheetSet as null, per spec 1.1565 + SetDOMStringToNull(mLastStyleSheetSet); 1.1566 + 1.1567 + if (sProcessingStack.empty()) { 1.1568 + sProcessingStack.construct(); 1.1569 + // Add the base queue sentinel to the processing stack. 1.1570 + sProcessingStack.ref().AppendElement((CustomElementData*) nullptr); 1.1571 + } 1.1572 +} 1.1573 + 1.1574 +static PLDHashOperator 1.1575 +ClearAllBoxObjects(nsIContent* aKey, nsPIBoxObject* aBoxObject, void* aUserArg) 1.1576 +{ 1.1577 + if (aBoxObject) { 1.1578 + aBoxObject->Clear(); 1.1579 + } 1.1580 + return PL_DHASH_NEXT; 1.1581 +} 1.1582 + 1.1583 +nsIDocument::~nsIDocument() 1.1584 +{ 1.1585 + if (mNodeInfoManager) { 1.1586 + mNodeInfoManager->DropDocumentReference(); 1.1587 + } 1.1588 +} 1.1589 + 1.1590 + 1.1591 +nsDocument::~nsDocument() 1.1592 +{ 1.1593 +#ifdef PR_LOGGING 1.1594 + if (gDocumentLeakPRLog) 1.1595 + PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG, 1.1596 + ("DOCUMENT %p destroyed", this)); 1.1597 +#endif 1.1598 + 1.1599 + NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document"); 1.1600 + 1.1601 + if (IsTopLevelContentDocument()) { 1.1602 + //don't report for about: pages 1.1603 + nsCOMPtr<nsIPrincipal> principal = GetPrincipal(); 1.1604 + nsCOMPtr<nsIURI> uri; 1.1605 + principal->GetURI(getter_AddRefs(uri)); 1.1606 + bool isAboutScheme = true; 1.1607 + if (uri) { 1.1608 + uri->SchemeIs("about", &isAboutScheme); 1.1609 + } 1.1610 + 1.1611 + if (!isAboutScheme) { 1.1612 + // Record the page load 1.1613 + uint32_t pageLoaded = 1; 1.1614 + Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER, pageLoaded); 1.1615 + // Record the mixed content status of the docshell in Telemetry 1.1616 + enum { 1.1617 + NO_MIXED_CONTENT = 0, // There is no Mixed Content on the page 1.1618 + MIXED_DISPLAY_CONTENT = 1, // The page attempted to load Mixed Display Content 1.1619 + MIXED_ACTIVE_CONTENT = 2, // The page attempted to load Mixed Active Content 1.1620 + MIXED_DISPLAY_AND_ACTIVE_CONTENT = 3 // The page attempted to load Mixed Display & Mixed Active Content 1.1621 + }; 1.1622 + 1.1623 + bool mixedActiveLoaded = GetHasMixedActiveContentLoaded(); 1.1624 + bool mixedActiveBlocked = GetHasMixedActiveContentBlocked(); 1.1625 + 1.1626 + bool mixedDisplayLoaded = GetHasMixedDisplayContentLoaded(); 1.1627 + bool mixedDisplayBlocked = GetHasMixedDisplayContentBlocked(); 1.1628 + 1.1629 + bool hasMixedDisplay = (mixedDisplayBlocked || mixedDisplayLoaded); 1.1630 + bool hasMixedActive = (mixedActiveBlocked || mixedActiveLoaded); 1.1631 + 1.1632 + uint32_t mixedContentLevel = NO_MIXED_CONTENT; 1.1633 + if (hasMixedDisplay && hasMixedActive) { 1.1634 + mixedContentLevel = MIXED_DISPLAY_AND_ACTIVE_CONTENT; 1.1635 + } else if (hasMixedActive){ 1.1636 + mixedContentLevel = MIXED_ACTIVE_CONTENT; 1.1637 + } else if (hasMixedDisplay) { 1.1638 + mixedContentLevel = MIXED_DISPLAY_CONTENT; 1.1639 + } 1.1640 + Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel); 1.1641 + } 1.1642 + } 1.1643 + 1.1644 + mInDestructor = true; 1.1645 + mInUnlinkOrDeletion = true; 1.1646 + 1.1647 + mRegistry = nullptr; 1.1648 + 1.1649 + mozilla::DropJSObjects(this); 1.1650 + 1.1651 + // Clear mObservers to keep it in sync with the mutationobserver list 1.1652 + mObservers.Clear(); 1.1653 + 1.1654 + if (mStyleSheetSetList) { 1.1655 + mStyleSheetSetList->Disconnect(); 1.1656 + } 1.1657 + 1.1658 + if (mAnimationController) { 1.1659 + mAnimationController->Disconnect(); 1.1660 + } 1.1661 + 1.1662 + mParentDocument = nullptr; 1.1663 + 1.1664 + // Kill the subdocument map, doing this will release its strong 1.1665 + // references, if any. 1.1666 + if (mSubDocuments) { 1.1667 + PL_DHashTableDestroy(mSubDocuments); 1.1668 + 1.1669 + mSubDocuments = nullptr; 1.1670 + } 1.1671 + 1.1672 + // Destroy link map now so we don't waste time removing 1.1673 + // links one by one 1.1674 + DestroyElementMaps(); 1.1675 + 1.1676 + nsAutoScriptBlocker scriptBlocker; 1.1677 + 1.1678 + int32_t indx; // must be signed 1.1679 + uint32_t count = mChildren.ChildCount(); 1.1680 + for (indx = int32_t(count) - 1; indx >= 0; --indx) { 1.1681 + mChildren.ChildAt(indx)->UnbindFromTree(); 1.1682 + mChildren.RemoveChildAt(indx); 1.1683 + } 1.1684 + mFirstChild = nullptr; 1.1685 + mCachedRootElement = nullptr; 1.1686 + 1.1687 + // Let the stylesheets know we're going away 1.1688 + indx = mStyleSheets.Count(); 1.1689 + while (--indx >= 0) { 1.1690 + mStyleSheets[indx]->SetOwningDocument(nullptr); 1.1691 + } 1.1692 + indx = mCatalogSheets.Count(); 1.1693 + while (--indx >= 0) { 1.1694 + static_cast<nsCSSStyleSheet*>(mCatalogSheets[indx])->SetOwningNode(nullptr); 1.1695 + mCatalogSheets[indx]->SetOwningDocument(nullptr); 1.1696 + } 1.1697 + if (mAttrStyleSheet) { 1.1698 + mAttrStyleSheet->SetOwningDocument(nullptr); 1.1699 + } 1.1700 + 1.1701 + if (mListenerManager) { 1.1702 + mListenerManager->Disconnect(); 1.1703 + UnsetFlags(NODE_HAS_LISTENERMANAGER); 1.1704 + } 1.1705 + 1.1706 + if (mScriptLoader) { 1.1707 + mScriptLoader->DropDocumentReference(); 1.1708 + } 1.1709 + 1.1710 + if (mCSSLoader) { 1.1711 + // Could be null here if Init() failed 1.1712 + mCSSLoader->DropDocumentReference(); 1.1713 + } 1.1714 + 1.1715 + if (mStyleImageLoader) { 1.1716 + mStyleImageLoader->DropDocumentReference(); 1.1717 + } 1.1718 + 1.1719 + delete mHeaderData; 1.1720 + 1.1721 + if (mBoxObjectTable) { 1.1722 + mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr); 1.1723 + delete mBoxObjectTable; 1.1724 + } 1.1725 + 1.1726 + mPendingTitleChangeEvent.Revoke(); 1.1727 + 1.1728 + for (uint32_t i = 0; i < mHostObjectURIs.Length(); ++i) { 1.1729 + nsHostObjectProtocolHandler::RemoveDataEntry(mHostObjectURIs[i]); 1.1730 + } 1.1731 + 1.1732 + // We don't want to leave residual locks on images. Make sure we're in an 1.1733 + // unlocked state, and then clear the table. 1.1734 + SetImageLockingState(false); 1.1735 + mImageTracker.Clear(); 1.1736 + 1.1737 + mPlugins.Clear(); 1.1738 +} 1.1739 + 1.1740 +NS_INTERFACE_TABLE_HEAD(nsDocument) 1.1741 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.1742 + NS_INTERFACE_TABLE_BEGIN 1.1743 + NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode) 1.1744 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode) 1.1745 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument) 1.1746 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocument) 1.1747 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNode) 1.1748 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentXBL) 1.1749 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal) 1.1750 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMEventTarget) 1.1751 + NS_INTERFACE_TABLE_ENTRY(nsDocument, mozilla::dom::EventTarget) 1.1752 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference) 1.1753 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer) 1.1754 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver) 1.1755 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer) 1.1756 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver) 1.1757 + NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathEvaluator) 1.1758 + NS_INTERFACE_TABLE_END 1.1759 + NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument) 1.1760 + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver, 1.1761 + new nsNode3Tearoff(this)) 1.1762 +NS_INTERFACE_MAP_END 1.1763 + 1.1764 + 1.1765 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument) 1.1766 +NS_IMETHODIMP_(MozExternalRefCountType) 1.1767 +nsDocument::Release() 1.1768 +{ 1.1769 + NS_PRECONDITION(0 != mRefCnt, "dup release"); 1.1770 + NS_ASSERT_OWNINGTHREAD(nsDocument); 1.1771 + nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(nsDocument)::Upcast(this); 1.1772 + bool shouldDelete = false; 1.1773 + nsrefcnt count = mRefCnt.decr(base, &shouldDelete); 1.1774 + NS_LOG_RELEASE(this, count, "nsDocument"); 1.1775 + if (count == 0) { 1.1776 + if (mStackRefCnt && !mNeedsReleaseAfterStackRefCntRelease) { 1.1777 + mNeedsReleaseAfterStackRefCntRelease = true; 1.1778 + NS_ADDREF_THIS(); 1.1779 + return mRefCnt.get(); 1.1780 + } 1.1781 + mRefCnt.incr(base); 1.1782 + nsNodeUtils::LastRelease(this); 1.1783 + mRefCnt.decr(base); 1.1784 + if (shouldDelete) { 1.1785 + mRefCnt.stabilizeForDeletion(); 1.1786 + DeleteCycleCollectable(); 1.1787 + } 1.1788 + } 1.1789 + return count; 1.1790 +} 1.1791 + 1.1792 +NS_IMETHODIMP_(void) 1.1793 +nsDocument::DeleteCycleCollectable() 1.1794 +{ 1.1795 + delete this; 1.1796 +} 1.1797 + 1.1798 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument) 1.1799 + if (Element::CanSkip(tmp, aRemovingAllowed)) { 1.1800 + EventListenerManager* elm = tmp->GetExistingListenerManager(); 1.1801 + if (elm) { 1.1802 + elm->MarkForCC(); 1.1803 + } 1.1804 + return true; 1.1805 + } 1.1806 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 1.1807 + 1.1808 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument) 1.1809 + return Element::CanSkipInCC(tmp); 1.1810 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 1.1811 + 1.1812 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument) 1.1813 + return Element::CanSkipThis(tmp); 1.1814 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 1.1815 + 1.1816 +static PLDHashOperator 1.1817 +SubDocTraverser(PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, 1.1818 + void *arg) 1.1819 +{ 1.1820 + SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr); 1.1821 + nsCycleCollectionTraversalCallback *cb = 1.1822 + static_cast<nsCycleCollectionTraversalCallback*>(arg); 1.1823 + 1.1824 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mSubDocuments entry->mKey"); 1.1825 + cb->NoteXPCOMChild(entry->mKey); 1.1826 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mSubDocuments entry->mSubDocument"); 1.1827 + cb->NoteXPCOMChild(entry->mSubDocument); 1.1828 + 1.1829 + return PL_DHASH_NEXT; 1.1830 +} 1.1831 + 1.1832 +static PLDHashOperator 1.1833 +RadioGroupsTraverser(const nsAString& aKey, nsRadioGroupStruct* aData, 1.1834 + void* aClosure) 1.1835 +{ 1.1836 + nsCycleCollectionTraversalCallback *cb = 1.1837 + static_cast<nsCycleCollectionTraversalCallback*>(aClosure); 1.1838 + 1.1839 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.1840 + "mRadioGroups entry->mSelectedRadioButton"); 1.1841 + cb->NoteXPCOMChild(ToSupports(aData->mSelectedRadioButton)); 1.1842 + 1.1843 + uint32_t i, count = aData->mRadioButtons.Count(); 1.1844 + for (i = 0; i < count; ++i) { 1.1845 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, 1.1846 + "mRadioGroups entry->mRadioButtons[i]"); 1.1847 + cb->NoteXPCOMChild(aData->mRadioButtons[i]); 1.1848 + } 1.1849 + 1.1850 + return PL_DHASH_NEXT; 1.1851 +} 1.1852 + 1.1853 +static PLDHashOperator 1.1854 +BoxObjectTraverser(nsIContent* key, nsPIBoxObject* boxObject, void* userArg) 1.1855 +{ 1.1856 + nsCycleCollectionTraversalCallback *cb = 1.1857 + static_cast<nsCycleCollectionTraversalCallback*>(userArg); 1.1858 + 1.1859 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mBoxObjectTable entry"); 1.1860 + cb->NoteXPCOMChild(boxObject); 1.1861 + 1.1862 + return PL_DHASH_NEXT; 1.1863 +} 1.1864 + 1.1865 +static PLDHashOperator 1.1866 +IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg) 1.1867 +{ 1.1868 + nsCycleCollectionTraversalCallback *cb = 1.1869 + static_cast<nsCycleCollectionTraversalCallback*>(aArg); 1.1870 + aEntry->Traverse(cb); 1.1871 + return PL_DHASH_NEXT; 1.1872 +} 1.1873 + 1.1874 +static const char* kNSURIs[] = { 1.1875 + "([none])", 1.1876 + "(xmlns)", 1.1877 + "(xml)", 1.1878 + "(xhtml)", 1.1879 + "(XLink)", 1.1880 + "(XSLT)", 1.1881 + "(XBL)", 1.1882 + "(MathML)", 1.1883 + "(RDF)", 1.1884 + "(XUL)" 1.1885 +}; 1.1886 + 1.1887 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) 1.1888 + if (MOZ_UNLIKELY(cb.WantDebugInfo())) { 1.1889 + char name[512]; 1.1890 + nsAutoCString loadedAsData; 1.1891 + if (tmp->IsLoadedAsData()) { 1.1892 + loadedAsData.AssignLiteral("data"); 1.1893 + } else { 1.1894 + loadedAsData.AssignLiteral("normal"); 1.1895 + } 1.1896 + uint32_t nsid = tmp->GetDefaultNamespaceID(); 1.1897 + nsAutoCString uri; 1.1898 + if (tmp->mDocumentURI) 1.1899 + tmp->mDocumentURI->GetSpec(uri); 1.1900 + if (nsid < ArrayLength(kNSURIs)) { 1.1901 + PR_snprintf(name, sizeof(name), "nsDocument %s %s %s", 1.1902 + loadedAsData.get(), kNSURIs[nsid], uri.get()); 1.1903 + } 1.1904 + else { 1.1905 + PR_snprintf(name, sizeof(name), "nsDocument %s %s", 1.1906 + loadedAsData.get(), uri.get()); 1.1907 + } 1.1908 + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name); 1.1909 + } 1.1910 + else { 1.1911 + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get()) 1.1912 + } 1.1913 + 1.1914 + // Always need to traverse script objects, so do that before we check 1.1915 + // if we're uncollectable. 1.1916 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.1917 + 1.1918 + if (!nsINode::Traverse(tmp, cb)) { 1.1919 + return NS_SUCCESS_INTERRUPTED_TRAVERSE; 1.1920 + } 1.1921 + 1.1922 + tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb); 1.1923 + 1.1924 + tmp->mExternalResourceMap.Traverse(&cb); 1.1925 + 1.1926 + // Traverse the mChildren nsAttrAndChildArray. 1.1927 + for (int32_t indx = int32_t(tmp->mChildren.ChildCount()); indx > 0; --indx) { 1.1928 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]"); 1.1929 + cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1)); 1.1930 + } 1.1931 + 1.1932 + // Traverse all nsIDocument pointer members. 1.1933 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo) 1.1934 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument) 1.1935 + 1.1936 + // Traverse all nsDocument nsCOMPtrs. 1.1937 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser) 1.1938 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject) 1.1939 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager) 1.1940 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets) 1.1941 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList) 1.1942 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader) 1.1943 + 1.1944 + tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb); 1.1945 + 1.1946 + // The boxobject for an element will only exist as long as it's in the 1.1947 + // document, so we'll traverse the table here instead of from the element. 1.1948 + if (tmp->mBoxObjectTable) { 1.1949 + tmp->mBoxObjectTable->EnumerateRead(BoxObjectTraverser, &cb); 1.1950 + } 1.1951 + 1.1952 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel) 1.1953 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet) 1.1954 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluator) 1.1955 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState) 1.1956 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker) 1.1957 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref) 1.1958 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation) 1.1959 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps) 1.1960 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument) 1.1961 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder) 1.1962 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached) 1.1963 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager) 1.1964 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner) 1.1965 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection) 1.1966 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry) 1.1967 + 1.1968 + // Traverse all our nsCOMArrays. 1.1969 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets) 1.1970 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCatalogSheets) 1.1971 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages) 1.1972 + 1.1973 + for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) { 1.1974 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]"); 1.1975 + cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback.GetISupports()); 1.1976 + } 1.1977 + 1.1978 + // Traverse animation components 1.1979 + if (tmp->mAnimationController) { 1.1980 + tmp->mAnimationController->Traverse(&cb); 1.1981 + } 1.1982 + 1.1983 + if (tmp->mSubDocuments && tmp->mSubDocuments->ops) { 1.1984 + PL_DHashTableEnumerate(tmp->mSubDocuments, SubDocTraverser, &cb); 1.1985 + } 1.1986 + 1.1987 + if (tmp->mCSSLoader) { 1.1988 + tmp->mCSSLoader->TraverseCachedSheets(cb); 1.1989 + } 1.1990 + 1.1991 + for (uint32_t i = 0; i < tmp->mHostObjectURIs.Length(); ++i) { 1.1992 + nsHostObjectProtocolHandler::Traverse(tmp->mHostObjectURIs[i], cb); 1.1993 + } 1.1994 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.1995 + 1.1996 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument) 1.1997 + 1.1998 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument) 1.1999 + if (tmp->PreservingWrapper()) { 1.2000 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); 1.2001 + } 1.2002 + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 1.2003 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.2004 + 1.2005 + 1.2006 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) 1.2007 + tmp->mInUnlinkOrDeletion = true; 1.2008 + 1.2009 + // Clear out our external resources 1.2010 + tmp->mExternalResourceMap.Shutdown(); 1.2011 + 1.2012 + nsAutoScriptBlocker scriptBlocker; 1.2013 + 1.2014 + nsINode::Unlink(tmp); 1.2015 + 1.2016 + // Unlink the mChildren nsAttrAndChildArray. 1.2017 + for (int32_t indx = int32_t(tmp->mChildren.ChildCount()) - 1; 1.2018 + indx >= 0; --indx) { 1.2019 + tmp->mChildren.ChildAt(indx)->UnbindFromTree(); 1.2020 + tmp->mChildren.RemoveChildAt(indx); 1.2021 + } 1.2022 + tmp->mFirstChild = nullptr; 1.2023 + 1.2024 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluator) 1.2025 + tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer 1.2026 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument) 1.2027 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref) 1.2028 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation) 1.2029 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps) 1.2030 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument) 1.2031 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder) 1.2032 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager) 1.2033 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner) 1.2034 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection) 1.2035 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry) 1.2036 + 1.2037 + tmp->mParentDocument = nullptr; 1.2038 + 1.2039 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages) 1.2040 + 1.2041 + 1.2042 + if (tmp->mBoxObjectTable) { 1.2043 + tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr); 1.2044 + delete tmp->mBoxObjectTable; 1.2045 + tmp->mBoxObjectTable = nullptr; 1.2046 + } 1.2047 + 1.2048 + if (tmp->mListenerManager) { 1.2049 + tmp->mListenerManager->Disconnect(); 1.2050 + tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER); 1.2051 + tmp->mListenerManager = nullptr; 1.2052 + } 1.2053 + 1.2054 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets) 1.2055 + 1.2056 + if (tmp->mStyleSheetSetList) { 1.2057 + tmp->mStyleSheetSetList->Disconnect(); 1.2058 + tmp->mStyleSheetSetList = nullptr; 1.2059 + } 1.2060 + 1.2061 + if (tmp->mSubDocuments) { 1.2062 + PL_DHashTableDestroy(tmp->mSubDocuments); 1.2063 + tmp->mSubDocuments = nullptr; 1.2064 + } 1.2065 + 1.2066 + tmp->mFrameRequestCallbacks.Clear(); 1.2067 + 1.2068 + tmp->mRadioGroups.Clear(); 1.2069 + 1.2070 + // nsDocument has a pretty complex destructor, so we're going to 1.2071 + // assume that *most* cycles you actually want to break somewhere 1.2072 + // else, and not unlink an awful lot here. 1.2073 + 1.2074 + tmp->mIdentifierMap.Clear(); 1.2075 + tmp->mExpandoAndGeneration.Unlink(); 1.2076 + 1.2077 + if (tmp->mAnimationController) { 1.2078 + tmp->mAnimationController->Unlink(); 1.2079 + } 1.2080 + 1.2081 + tmp->mPendingTitleChangeEvent.Revoke(); 1.2082 + 1.2083 + if (tmp->mCSSLoader) { 1.2084 + tmp->mCSSLoader->UnlinkCachedSheets(); 1.2085 + } 1.2086 + 1.2087 + for (uint32_t i = 0; i < tmp->mHostObjectURIs.Length(); ++i) { 1.2088 + nsHostObjectProtocolHandler::RemoveDataEntry(tmp->mHostObjectURIs[i]); 1.2089 + } 1.2090 + 1.2091 + tmp->mInUnlinkOrDeletion = false; 1.2092 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.2093 + 1.2094 +static bool sPrefsInitialized = false; 1.2095 +static uint32_t sOnloadDecodeLimit = 0; 1.2096 + 1.2097 +nsresult 1.2098 +nsDocument::Init() 1.2099 +{ 1.2100 + if (mCSSLoader || mStyleImageLoader || mNodeInfoManager || mScriptLoader) { 1.2101 + return NS_ERROR_ALREADY_INITIALIZED; 1.2102 + } 1.2103 + 1.2104 + if (!sPrefsInitialized) { 1.2105 + sPrefsInitialized = true; 1.2106 + Preferences::AddUintVarCache(&sOnloadDecodeLimit, "image.onload.decode.limit", 0); 1.2107 + } 1.2108 + 1.2109 + // Force initialization. 1.2110 + nsINode::nsSlots* slots = Slots(); 1.2111 + 1.2112 + // Prepend self as mutation-observer whether we need it or not (some 1.2113 + // subclasses currently do, other don't). This is because the code in 1.2114 + // nsNodeUtils always notifies the first observer first, expecting the 1.2115 + // first observer to be the document. 1.2116 + NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)), 1.2117 + NS_ERROR_OUT_OF_MEMORY); 1.2118 + 1.2119 + 1.2120 + mOnloadBlocker = new nsOnloadBlocker(); 1.2121 + mCSSLoader = new mozilla::css::Loader(this); 1.2122 + // Assume we're not quirky, until we know otherwise 1.2123 + mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards); 1.2124 + 1.2125 + mStyleImageLoader = new mozilla::css::ImageLoader(this); 1.2126 + 1.2127 + mNodeInfoManager = new nsNodeInfoManager(); 1.2128 + nsresult rv = mNodeInfoManager->Init(this); 1.2129 + NS_ENSURE_SUCCESS(rv, rv); 1.2130 + 1.2131 + // mNodeInfo keeps NodeInfoManager alive! 1.2132 + mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo(); 1.2133 + NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY); 1.2134 + NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_NODE, 1.2135 + "Bad NodeType in aNodeInfo"); 1.2136 + 1.2137 + NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!"); 1.2138 + 1.2139 + // If after creation the owner js global is not set for a document 1.2140 + // we use the default compartment for this document, instead of creating 1.2141 + // wrapper in some random compartment when the document is exposed to js 1.2142 + // via some events. 1.2143 + nsCOMPtr<nsIGlobalObject> global = xpc::GetJunkScopeGlobal(); 1.2144 + NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); 1.2145 + mScopeObject = do_GetWeakReference(global); 1.2146 + MOZ_ASSERT(mScopeObject); 1.2147 + 1.2148 + mScriptLoader = new nsScriptLoader(this); 1.2149 + 1.2150 + mozilla::HoldJSObjects(this); 1.2151 + 1.2152 + return NS_OK; 1.2153 +} 1.2154 + 1.2155 +void 1.2156 +nsIDocument::DeleteAllProperties() 1.2157 +{ 1.2158 + for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) { 1.2159 + PropertyTable(i)->DeleteAllProperties(); 1.2160 + } 1.2161 +} 1.2162 + 1.2163 +void 1.2164 +nsIDocument::DeleteAllPropertiesFor(nsINode* aNode) 1.2165 +{ 1.2166 + for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) { 1.2167 + PropertyTable(i)->DeleteAllPropertiesFor(aNode); 1.2168 + } 1.2169 +} 1.2170 + 1.2171 +nsPropertyTable* 1.2172 +nsIDocument::GetExtraPropertyTable(uint16_t aCategory) 1.2173 +{ 1.2174 + NS_ASSERTION(aCategory > 0, "Category 0 should have already been handled"); 1.2175 + while (aCategory >= mExtraPropertyTables.Length() + 1) { 1.2176 + mExtraPropertyTables.AppendElement(new nsPropertyTable()); 1.2177 + } 1.2178 + return mExtraPropertyTables[aCategory - 1]; 1.2179 +} 1.2180 + 1.2181 +bool 1.2182 +nsIDocument::IsVisibleConsideringAncestors() const 1.2183 +{ 1.2184 + const nsIDocument *parent = this; 1.2185 + do { 1.2186 + if (!parent->IsVisible()) { 1.2187 + return false; 1.2188 + } 1.2189 + } while ((parent = parent->GetParentDocument())); 1.2190 + 1.2191 + return true; 1.2192 + } 1.2193 + 1.2194 +void 1.2195 +nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) 1.2196 +{ 1.2197 + nsCOMPtr<nsIURI> uri; 1.2198 + nsCOMPtr<nsIPrincipal> principal; 1.2199 + if (aChannel) { 1.2200 + // Note: this code is duplicated in XULDocument::StartDocumentLoad and 1.2201 + // nsScriptSecurityManager::GetChannelPrincipal. 1.2202 + // Note: this should match nsDocShell::OnLoadingSite 1.2203 + NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); 1.2204 + 1.2205 + nsIScriptSecurityManager *securityManager = 1.2206 + nsContentUtils::GetSecurityManager(); 1.2207 + if (securityManager) { 1.2208 + securityManager->GetChannelPrincipal(aChannel, 1.2209 + getter_AddRefs(principal)); 1.2210 + } 1.2211 + } 1.2212 + 1.2213 + ResetToURI(uri, aLoadGroup, principal); 1.2214 + 1.2215 + nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel); 1.2216 + if (bag) { 1.2217 + nsCOMPtr<nsIURI> baseURI; 1.2218 + bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"), 1.2219 + NS_GET_IID(nsIURI), getter_AddRefs(baseURI)); 1.2220 + if (baseURI) { 1.2221 + mDocumentBaseURI = baseURI; 1.2222 + mChromeXHRDocBaseURI = baseURI; 1.2223 + } 1.2224 + } 1.2225 + 1.2226 + mChannel = aChannel; 1.2227 +} 1.2228 + 1.2229 +void 1.2230 +nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, 1.2231 + nsIPrincipal* aPrincipal) 1.2232 +{ 1.2233 + NS_PRECONDITION(aURI, "Null URI passed to ResetToURI"); 1.2234 + 1.2235 +#ifdef PR_LOGGING 1.2236 + if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) { 1.2237 + nsAutoCString spec; 1.2238 + aURI->GetSpec(spec); 1.2239 + PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get()); 1.2240 + } 1.2241 +#endif 1.2242 + 1.2243 + mSecurityInfo = nullptr; 1.2244 + 1.2245 + mDocumentLoadGroup = nullptr; 1.2246 + 1.2247 + // Delete references to sub-documents and kill the subdocument map, 1.2248 + // if any. It holds strong references 1.2249 + if (mSubDocuments) { 1.2250 + PL_DHashTableDestroy(mSubDocuments); 1.2251 + 1.2252 + mSubDocuments = nullptr; 1.2253 + } 1.2254 + 1.2255 + // Destroy link map now so we don't waste time removing 1.2256 + // links one by one 1.2257 + DestroyElementMaps(); 1.2258 + 1.2259 + bool oldVal = mInUnlinkOrDeletion; 1.2260 + mInUnlinkOrDeletion = true; 1.2261 + uint32_t count = mChildren.ChildCount(); 1.2262 + { // Scope for update 1.2263 + MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, true); 1.2264 + for (int32_t i = int32_t(count) - 1; i >= 0; i--) { 1.2265 + nsCOMPtr<nsIContent> content = mChildren.ChildAt(i); 1.2266 + 1.2267 + nsIContent* previousSibling = content->GetPreviousSibling(); 1.2268 + 1.2269 + if (nsINode::GetFirstChild() == content) { 1.2270 + mFirstChild = content->GetNextSibling(); 1.2271 + } 1.2272 + mChildren.RemoveChildAt(i); 1.2273 + nsNodeUtils::ContentRemoved(this, content, i, previousSibling); 1.2274 + content->UnbindFromTree(); 1.2275 + } 1.2276 + mCachedRootElement = nullptr; 1.2277 + } 1.2278 + mInUnlinkOrDeletion = oldVal; 1.2279 + 1.2280 + mRegistry = nullptr; 1.2281 + 1.2282 + // Reset our stylesheets 1.2283 + ResetStylesheetsToURI(aURI); 1.2284 + 1.2285 + // Release the listener manager 1.2286 + if (mListenerManager) { 1.2287 + mListenerManager->Disconnect(); 1.2288 + mListenerManager = nullptr; 1.2289 + } 1.2290 + 1.2291 + // Release the stylesheets list. 1.2292 + mDOMStyleSheets = nullptr; 1.2293 + 1.2294 + // Release our principal after tearing down the document, rather than before. 1.2295 + // This ensures that, during teardown, the document and the dying window (which 1.2296 + // already nulled out its document pointer and cached the principal) have 1.2297 + // matching principals. 1.2298 + SetPrincipal(nullptr); 1.2299 + 1.2300 + // Clear the original URI so SetDocumentURI sets it. 1.2301 + mOriginalURI = nullptr; 1.2302 + 1.2303 + SetDocumentURI(aURI); 1.2304 + mChromeXHRDocURI = aURI; 1.2305 + // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns 1.2306 + // mDocumentURI. 1.2307 + mDocumentBaseURI = nullptr; 1.2308 + mChromeXHRDocBaseURI = nullptr; 1.2309 + 1.2310 + if (aLoadGroup) { 1.2311 + mDocumentLoadGroup = do_GetWeakReference(aLoadGroup); 1.2312 + // there was an assertion here that aLoadGroup was not null. This 1.2313 + // is no longer valid: nsDocShell::SetDocument does not create a 1.2314 + // load group, and it works just fine 1.2315 + 1.2316 + // XXXbz what does "just fine" mean exactly? And given that there 1.2317 + // is no nsDocShell::SetDocument, what is this talking about? 1.2318 + } 1.2319 + 1.2320 + mLastModified.Truncate(); 1.2321 + // XXXbz I guess we're assuming that the caller will either pass in 1.2322 + // a channel with a useful type or call SetContentType? 1.2323 + SetContentTypeInternal(EmptyCString()); 1.2324 + mContentLanguage.Truncate(); 1.2325 + mBaseTarget.Truncate(); 1.2326 + mReferrer.Truncate(); 1.2327 + 1.2328 + mXMLDeclarationBits = 0; 1.2329 + 1.2330 + // Now get our new principal 1.2331 + if (aPrincipal) { 1.2332 + SetPrincipal(aPrincipal); 1.2333 + } else { 1.2334 + nsIScriptSecurityManager *securityManager = 1.2335 + nsContentUtils::GetSecurityManager(); 1.2336 + if (securityManager) { 1.2337 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.2338 + 1.2339 + if (!docShell && aLoadGroup) { 1.2340 + nsCOMPtr<nsIInterfaceRequestor> cbs; 1.2341 + aLoadGroup->GetNotificationCallbacks(getter_AddRefs(cbs)); 1.2342 + docShell = do_GetInterface(cbs); 1.2343 + } 1.2344 + 1.2345 + MOZ_ASSERT(docShell, 1.2346 + "must be in a docshell or pass in an explicit principal"); 1.2347 + 1.2348 + nsCOMPtr<nsIPrincipal> principal; 1.2349 + nsresult rv = securityManager-> 1.2350 + GetDocShellCodebasePrincipal(mDocumentURI, docShell, 1.2351 + getter_AddRefs(principal)); 1.2352 + if (NS_SUCCEEDED(rv)) { 1.2353 + SetPrincipal(principal); 1.2354 + } 1.2355 + } 1.2356 + } 1.2357 + 1.2358 + // Refresh the principal on the compartment. 1.2359 + nsPIDOMWindow* win = GetInnerWindow(); 1.2360 + if (win) { 1.2361 + win->RefreshCompartmentPrincipal(); 1.2362 + } 1.2363 +} 1.2364 + 1.2365 +void 1.2366 +nsDocument::RemoveDocStyleSheetsFromStyleSets() 1.2367 +{ 1.2368 + // The stylesheets should forget us 1.2369 + int32_t indx = mStyleSheets.Count(); 1.2370 + while (--indx >= 0) { 1.2371 + nsIStyleSheet* sheet = mStyleSheets[indx]; 1.2372 + sheet->SetOwningDocument(nullptr); 1.2373 + 1.2374 + if (sheet->IsApplicable()) { 1.2375 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.2376 + if (shell) { 1.2377 + shell->StyleSet()->RemoveDocStyleSheet(sheet); 1.2378 + } 1.2379 + } 1.2380 + // XXX Tell observers? 1.2381 + } 1.2382 +} 1.2383 + 1.2384 +void 1.2385 +nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray<nsIStyleSheet>& aSheets, nsStyleSet::sheetType aType) 1.2386 +{ 1.2387 + // The stylesheets should forget us 1.2388 + int32_t indx = aSheets.Count(); 1.2389 + while (--indx >= 0) { 1.2390 + nsIStyleSheet* sheet = aSheets[indx]; 1.2391 + sheet->SetOwningDocument(nullptr); 1.2392 + 1.2393 + if (sheet->IsApplicable()) { 1.2394 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.2395 + if (shell) { 1.2396 + shell->StyleSet()->RemoveStyleSheet(aType, sheet); 1.2397 + } 1.2398 + } 1.2399 + 1.2400 + // XXX Tell observers? 1.2401 + } 1.2402 + 1.2403 +} 1.2404 + 1.2405 +void 1.2406 +nsDocument::ResetStylesheetsToURI(nsIURI* aURI) 1.2407 +{ 1.2408 + MOZ_ASSERT(aURI); 1.2409 + 1.2410 + mozAutoDocUpdate upd(this, UPDATE_STYLE, true); 1.2411 + RemoveDocStyleSheetsFromStyleSets(); 1.2412 + RemoveStyleSheetsFromStyleSets(mCatalogSheets, nsStyleSet::eAgentSheet); 1.2413 + RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], nsStyleSet::eAgentSheet); 1.2414 + RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], nsStyleSet::eUserSheet); 1.2415 + RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], nsStyleSet::eDocSheet); 1.2416 + 1.2417 + // Release all the sheets 1.2418 + mStyleSheets.Clear(); 1.2419 + for (uint32_t i = 0; i < SheetTypeCount; ++i) 1.2420 + mAdditionalSheets[i].Clear(); 1.2421 + 1.2422 + // NOTE: We don't release the catalog sheets. It doesn't really matter 1.2423 + // now, but it could in the future -- in which case not releasing them 1.2424 + // is probably the right thing to do. 1.2425 + 1.2426 + // Now reset our inline style and attribute sheets. 1.2427 + if (mAttrStyleSheet) { 1.2428 + mAttrStyleSheet->Reset(); 1.2429 + mAttrStyleSheet->SetOwningDocument(this); 1.2430 + } else { 1.2431 + mAttrStyleSheet = new nsHTMLStyleSheet(this); 1.2432 + } 1.2433 + 1.2434 + if (!mStyleAttrStyleSheet) { 1.2435 + mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet(); 1.2436 + } 1.2437 + 1.2438 + // Now set up our style sets 1.2439 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.2440 + if (shell) { 1.2441 + FillStyleSet(shell->StyleSet()); 1.2442 + } 1.2443 +} 1.2444 + 1.2445 +static bool 1.2446 +AppendAuthorSheet(nsIStyleSheet *aSheet, void *aData) 1.2447 +{ 1.2448 + nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData); 1.2449 + styleSet->AppendStyleSheet(nsStyleSet::eDocSheet, aSheet); 1.2450 + return true; 1.2451 +} 1.2452 + 1.2453 +static void 1.2454 +AppendSheetsToStyleSet(nsStyleSet* aStyleSet, 1.2455 + const nsCOMArray<nsIStyleSheet>& aSheets, 1.2456 + nsStyleSet::sheetType aType) 1.2457 +{ 1.2458 + for (int32_t i = aSheets.Count() - 1; i >= 0; --i) { 1.2459 + aStyleSet->AppendStyleSheet(aType, aSheets[i]); 1.2460 + } 1.2461 +} 1.2462 + 1.2463 + 1.2464 +void 1.2465 +nsDocument::FillStyleSet(nsStyleSet* aStyleSet) 1.2466 +{ 1.2467 + NS_PRECONDITION(aStyleSet, "Must have a style set"); 1.2468 + NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0, 1.2469 + "Style set already has document sheets?"); 1.2470 + 1.2471 + // We could consider moving this to nsStyleSet::Init, to match its 1.2472 + // handling of the eAnimationSheet and eTransitionSheet levels. 1.2473 + aStyleSet->DirtyRuleProcessors(nsStyleSet::ePresHintSheet); 1.2474 + aStyleSet->DirtyRuleProcessors(nsStyleSet::eStyleAttrSheet); 1.2475 + 1.2476 + int32_t i; 1.2477 + for (i = mStyleSheets.Count() - 1; i >= 0; --i) { 1.2478 + nsIStyleSheet* sheet = mStyleSheets[i]; 1.2479 + if (sheet->IsApplicable()) { 1.2480 + aStyleSet->AddDocStyleSheet(sheet, this); 1.2481 + } 1.2482 + } 1.2483 + 1.2484 + nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance(); 1.2485 + if (sheetService) { 1.2486 + sheetService->AuthorStyleSheets()->EnumerateForwards(AppendAuthorSheet, 1.2487 + aStyleSet); 1.2488 + } 1.2489 + 1.2490 + for (i = mCatalogSheets.Count() - 1; i >= 0; --i) { 1.2491 + nsIStyleSheet* sheet = mCatalogSheets[i]; 1.2492 + if (sheet->IsApplicable()) { 1.2493 + aStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet); 1.2494 + } 1.2495 + } 1.2496 + 1.2497 + AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet], 1.2498 + nsStyleSet::eAgentSheet); 1.2499 + AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet], 1.2500 + nsStyleSet::eUserSheet); 1.2501 + AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet], 1.2502 + nsStyleSet::eDocSheet); 1.2503 +} 1.2504 + 1.2505 +nsresult 1.2506 +nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, 1.2507 + nsILoadGroup* aLoadGroup, 1.2508 + nsISupports* aContainer, 1.2509 + nsIStreamListener **aDocListener, 1.2510 + bool aReset, nsIContentSink* aSink) 1.2511 +{ 1.2512 +#ifdef PR_LOGGING 1.2513 + if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) { 1.2514 + nsCOMPtr<nsIURI> uri; 1.2515 + aChannel->GetURI(getter_AddRefs(uri)); 1.2516 + nsAutoCString spec; 1.2517 + if (uri) 1.2518 + uri->GetSpec(spec); 1.2519 + PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec.get()); 1.2520 + } 1.2521 +#endif 1.2522 + 1.2523 +#ifdef DEBUG 1.2524 + { 1.2525 + uint32_t appId; 1.2526 + nsresult rv = NodePrincipal()->GetAppId(&appId); 1.2527 + NS_ENSURE_SUCCESS(rv, rv); 1.2528 + MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID, 1.2529 + "Document should never have UNKNOWN_APP_ID"); 1.2530 + } 1.2531 +#endif 1.2532 + 1.2533 + MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED, 1.2534 + "Bad readyState"); 1.2535 + SetReadyStateInternal(READYSTATE_LOADING); 1.2536 + 1.2537 + if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) { 1.2538 + mLoadedAsData = true; 1.2539 + // We need to disable script & style loading in this case. 1.2540 + // We leave them disabled even in EndLoad(), and let anyone 1.2541 + // who puts the document on display to worry about enabling. 1.2542 + 1.2543 + // Do not load/process scripts when loading as data 1.2544 + ScriptLoader()->SetEnabled(false); 1.2545 + 1.2546 + // styles 1.2547 + CSSLoader()->SetEnabled(false); // Do not load/process styles when loading as data 1.2548 + } else if (nsCRT::strcmp("external-resource", aCommand) == 0) { 1.2549 + // Allow CSS, but not scripts 1.2550 + ScriptLoader()->SetEnabled(false); 1.2551 + } 1.2552 + 1.2553 + mMayStartLayout = false; 1.2554 + 1.2555 + mHaveInputEncoding = true; 1.2556 + 1.2557 + if (aReset) { 1.2558 + Reset(aChannel, aLoadGroup); 1.2559 + } 1.2560 + 1.2561 + nsAutoCString contentType; 1.2562 + nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel); 1.2563 + if ((bag && NS_SUCCEEDED(bag->GetPropertyAsACString( 1.2564 + NS_LITERAL_STRING("contentType"), contentType))) || 1.2565 + NS_SUCCEEDED(aChannel->GetContentType(contentType))) { 1.2566 + // XXX this is only necessary for viewsource: 1.2567 + nsACString::const_iterator start, end, semicolon; 1.2568 + contentType.BeginReading(start); 1.2569 + contentType.EndReading(end); 1.2570 + semicolon = start; 1.2571 + FindCharInReadable(';', semicolon, end); 1.2572 + SetContentTypeInternal(Substring(start, semicolon)); 1.2573 + } 1.2574 + 1.2575 + RetrieveRelevantHeaders(aChannel); 1.2576 + 1.2577 + mChannel = aChannel; 1.2578 + nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel); 1.2579 + if (inStrmChan) { 1.2580 + bool isSrcdocChannel; 1.2581 + inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel); 1.2582 + if (isSrcdocChannel) { 1.2583 + mIsSrcdocDocument = true; 1.2584 + } 1.2585 + } 1.2586 + 1.2587 + // If this document is being loaded by a docshell, copy its sandbox flags 1.2588 + // to the document. These are immutable after being set here. 1.2589 + nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aContainer); 1.2590 + 1.2591 + if (docShell) { 1.2592 + nsresult rv = docShell->GetSandboxFlags(&mSandboxFlags); 1.2593 + NS_ENSURE_SUCCESS(rv, rv); 1.2594 + } 1.2595 + 1.2596 + // If this is not a data document, set CSP. 1.2597 + if (!mLoadedAsData) { 1.2598 + nsresult rv = InitCSP(aChannel); 1.2599 + NS_ENSURE_SUCCESS(rv, rv); 1.2600 + } 1.2601 + 1.2602 + return NS_OK; 1.2603 +} 1.2604 + 1.2605 +void 1.2606 +CSPErrorQueue::Add(const char* aMessageName) 1.2607 +{ 1.2608 + mErrors.AppendElement(aMessageName); 1.2609 +} 1.2610 + 1.2611 +void 1.2612 +CSPErrorQueue::Flush(nsIDocument* aDocument) 1.2613 +{ 1.2614 + for (uint32_t i = 0; i < mErrors.Length(); i++) { 1.2615 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.2616 + NS_LITERAL_CSTRING("CSP"), aDocument, 1.2617 + nsContentUtils::eSECURITY_PROPERTIES, 1.2618 + mErrors[i]); 1.2619 + } 1.2620 + mErrors.Clear(); 1.2621 +} 1.2622 + 1.2623 +void 1.2624 +nsDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) 1.2625 +{ 1.2626 + for (uint32_t i = 0; i < aMessages.Length(); ++i) { 1.2627 + nsAutoString messageTag; 1.2628 + aMessages[i]->GetTag(messageTag); 1.2629 + 1.2630 + nsAutoString category; 1.2631 + aMessages[i]->GetCategory(category); 1.2632 + 1.2633 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.2634 + NS_ConvertUTF16toUTF8(category), 1.2635 + this, nsContentUtils::eSECURITY_PROPERTIES, 1.2636 + NS_ConvertUTF16toUTF8(messageTag).get()); 1.2637 + } 1.2638 +} 1.2639 + 1.2640 +static nsresult 1.2641 +AppendCSPFromHeader(nsIContentSecurityPolicy* csp, const nsAString& aHeaderValue, 1.2642 + nsIURI* aSelfURI, bool aReportOnly, bool aSpecCompliant) 1.2643 +{ 1.2644 + // Need to tokenize the header value since multiple headers could be 1.2645 + // concatenated into one comma-separated list of policies. 1.2646 + // See RFC2616 section 4.2 (last paragraph) 1.2647 + nsresult rv = NS_OK; 1.2648 + nsCharSeparatedTokenizer tokenizer(aHeaderValue, ','); 1.2649 + while (tokenizer.hasMoreTokens()) { 1.2650 + const nsSubstring& policy = tokenizer.nextToken(); 1.2651 + rv = csp->AppendPolicy(policy, aSelfURI, aReportOnly, aSpecCompliant); 1.2652 + NS_ENSURE_SUCCESS(rv, rv); 1.2653 +#ifdef PR_LOGGING 1.2654 + { 1.2655 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, 1.2656 + ("CSP refined with policy: \"%s\"", 1.2657 + NS_ConvertUTF16toUTF8(policy).get())); 1.2658 + } 1.2659 +#endif 1.2660 + } 1.2661 + return NS_OK; 1.2662 +} 1.2663 + 1.2664 +nsresult 1.2665 +nsDocument::InitCSP(nsIChannel* aChannel) 1.2666 +{ 1.2667 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.2668 + if (!CSPService::sCSPEnabled) { 1.2669 +#ifdef PR_LOGGING 1.2670 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, 1.2671 + ("CSP is disabled, skipping CSP init for document %p", this)); 1.2672 +#endif 1.2673 + return NS_OK; 1.2674 + } 1.2675 + 1.2676 + nsAutoCString tCspHeaderValue, tCspROHeaderValue; 1.2677 + nsAutoCString tCspOldHeaderValue, tCspOldROHeaderValue; 1.2678 + 1.2679 + nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); 1.2680 + if (httpChannel) { 1.2681 + httpChannel->GetResponseHeader( 1.2682 + NS_LITERAL_CSTRING("x-content-security-policy"), 1.2683 + tCspOldHeaderValue); 1.2684 + 1.2685 + httpChannel->GetResponseHeader( 1.2686 + NS_LITERAL_CSTRING("x-content-security-policy-report-only"), 1.2687 + tCspOldROHeaderValue); 1.2688 + 1.2689 + httpChannel->GetResponseHeader( 1.2690 + NS_LITERAL_CSTRING("content-security-policy"), 1.2691 + tCspHeaderValue); 1.2692 + 1.2693 + httpChannel->GetResponseHeader( 1.2694 + NS_LITERAL_CSTRING("content-security-policy-report-only"), 1.2695 + tCspROHeaderValue); 1.2696 + } 1.2697 + NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue); 1.2698 + NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue); 1.2699 + NS_ConvertASCIItoUTF16 cspOldHeaderValue(tCspOldHeaderValue); 1.2700 + NS_ConvertASCIItoUTF16 cspOldROHeaderValue(tCspOldROHeaderValue); 1.2701 + 1.2702 + // Only use the CSP 1.0 spec compliant headers if a pref to do so 1.2703 + // is set. This lets us turn on the 1.0 parser per platform. This 1.2704 + // pref is also set by the tests for 1.0 spec compliant CSP. 1.2705 + bool specCompliantEnabled = 1.2706 + Preferences::GetBool("security.csp.speccompliant"); 1.2707 + 1.2708 + // If spec compliant pref isn't set, pretend we never got these headers. 1.2709 + if ((!cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty()) && 1.2710 + !specCompliantEnabled) { 1.2711 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, 1.2712 + ("Got spec compliant CSP headers but pref was not set")); 1.2713 + cspHeaderValue.Truncate(); 1.2714 + cspROHeaderValue.Truncate(); 1.2715 + } 1.2716 + 1.2717 + // If both the new header AND the old header are present, warn that 1.2718 + // the old header will be ignored. Otherwise, if the old header is 1.2719 + // present, warn that it will be deprecated. 1.2720 + bool oldHeaderIsPresent = !cspOldHeaderValue.IsEmpty() || !cspOldROHeaderValue.IsEmpty(); 1.2721 + bool newHeaderIsPresent = !cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty(); 1.2722 + 1.2723 + if (oldHeaderIsPresent && newHeaderIsPresent) { 1.2724 + mCSPWebConsoleErrorQueue.Add("BothCSPHeadersPresent"); 1.2725 + } else if (oldHeaderIsPresent) { 1.2726 + mCSPWebConsoleErrorQueue.Add("OldCSPHeaderDeprecated"); 1.2727 + } 1.2728 + 1.2729 + // Figure out if we need to apply an app default CSP or a CSP from an app manifest 1.2730 + nsIPrincipal* principal = NodePrincipal(); 1.2731 + 1.2732 + uint16_t appStatus = principal->GetAppStatus(); 1.2733 + bool applyAppDefaultCSP = appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED || 1.2734 + appStatus == nsIPrincipal::APP_STATUS_CERTIFIED; 1.2735 + bool applyAppManifestCSP = false; 1.2736 + 1.2737 + nsAutoString appManifestCSP; 1.2738 + if (appStatus != nsIPrincipal::APP_STATUS_NOT_INSTALLED) { 1.2739 + nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); 1.2740 + if (appsService) { 1.2741 + uint32_t appId = 0; 1.2742 + if (NS_SUCCEEDED(principal->GetAppId(&appId))) { 1.2743 + appsService->GetCSPByLocalId(appId, appManifestCSP); 1.2744 + if (!appManifestCSP.IsEmpty()) { 1.2745 + applyAppManifestCSP = true; 1.2746 + } 1.2747 + } 1.2748 + } 1.2749 + } 1.2750 + 1.2751 + // If there's no CSP to apply, go ahead and return early 1.2752 + if (!applyAppDefaultCSP && 1.2753 + !applyAppManifestCSP && 1.2754 + cspHeaderValue.IsEmpty() && 1.2755 + cspROHeaderValue.IsEmpty() && 1.2756 + cspOldHeaderValue.IsEmpty() && 1.2757 + cspOldROHeaderValue.IsEmpty()) { 1.2758 +#ifdef PR_LOGGING 1.2759 + nsCOMPtr<nsIURI> chanURI; 1.2760 + aChannel->GetURI(getter_AddRefs(chanURI)); 1.2761 + nsAutoCString aspec; 1.2762 + chanURI->GetAsciiSpec(aspec); 1.2763 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, 1.2764 + ("no CSP for document, %s, %s", 1.2765 + aspec.get(), 1.2766 + applyAppDefaultCSP ? "is app" : "not an app")); 1.2767 +#endif 1.2768 + return NS_OK; 1.2769 + } 1.2770 + 1.2771 +#ifdef PR_LOGGING 1.2772 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Document is an app or CSP header specified %p", this)); 1.2773 +#endif 1.2774 + 1.2775 + nsresult rv; 1.2776 + 1.2777 + // If Document is an app check to see if we already set CSP and return early 1.2778 + // if that is indeed the case. 1.2779 + // 1.2780 + // In general (see bug 947831), we should not be setting CSP on a principal 1.2781 + // that aliases another document. For non-app code this is not a problem 1.2782 + // since we only share the underlying principal with nested browsing 1.2783 + // contexts for which a header cannot be set (e.g., about:blank and 1.2784 + // about:srcodoc iframes) and thus won't try to set the CSP again. This 1.2785 + // check ensures that we do not try to set CSP for an app. 1.2786 + if (applyAppDefaultCSP || applyAppManifestCSP) { 1.2787 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.2788 + rv = principal->GetCsp(getter_AddRefs(csp)); 1.2789 + NS_ENSURE_SUCCESS(rv, rv); 1.2790 + 1.2791 + if (csp) { 1.2792 +#ifdef PR_LOGGING 1.2793 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("%s %s %s", 1.2794 + "This document is sharing principal with another document.", 1.2795 + "Since the document is an app, CSP was already set.", 1.2796 + "Skipping attempt to set CSP.")); 1.2797 +#endif 1.2798 + return NS_OK; 1.2799 + } 1.2800 + } 1.2801 + 1.2802 + // create new CSP object 1.2803 + csp = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv); 1.2804 + 1.2805 + if (NS_FAILED(rv)) { 1.2806 +#ifdef PR_LOGGING 1.2807 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %x", rv)); 1.2808 +#endif 1.2809 + return rv; 1.2810 + } 1.2811 + 1.2812 + // used as a "self" identifier for the CSP. 1.2813 + nsCOMPtr<nsIURI> selfURI; 1.2814 + aChannel->GetURI(getter_AddRefs(selfURI)); 1.2815 + 1.2816 + // Store the request context for violation reports 1.2817 + csp->SetRequestContext(nullptr, nullptr, nullptr, aChannel); 1.2818 + 1.2819 + // ----- if the doc is an app and we want a default CSP, apply it. 1.2820 + if (applyAppDefaultCSP) { 1.2821 + nsAdoptingString appCSP; 1.2822 + if (appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED) { 1.2823 + appCSP = Preferences::GetString("security.apps.privileged.CSP.default"); 1.2824 + NS_ASSERTION(appCSP, "App, but no default CSP in security.apps.privileged.CSP.default"); 1.2825 + } else if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED) { 1.2826 + appCSP = Preferences::GetString("security.apps.certified.CSP.default"); 1.2827 + NS_ASSERTION(appCSP, "App, but no default CSP in security.apps.certified.CSP.default"); 1.2828 + } 1.2829 + 1.2830 + if (appCSP) { 1.2831 + // Use the 1.0 CSP parser for apps if the pref to do so is set. 1.2832 + csp->AppendPolicy(appCSP, selfURI, false, specCompliantEnabled); 1.2833 + } 1.2834 + } 1.2835 + 1.2836 + // ----- if the doc is an app and specifies a CSP in its manifest, apply it. 1.2837 + if (applyAppManifestCSP) { 1.2838 + // Use the 1.0 CSP parser for apps if the pref to do so is set. 1.2839 + csp->AppendPolicy(appManifestCSP, selfURI, false, specCompliantEnabled); 1.2840 + } 1.2841 + 1.2842 + // While we are supporting both CSP 1.0 and the x- headers, the 1.0 headers 1.2843 + // take priority. If both are present, the x-* headers are ignored. 1.2844 + 1.2845 + // ----- if there's a full-strength CSP header, apply it. 1.2846 + if (!cspHeaderValue.IsEmpty()) { 1.2847 + rv = AppendCSPFromHeader(csp, cspHeaderValue, selfURI, false, true); 1.2848 + NS_ENSURE_SUCCESS(rv, rv); 1.2849 + } else if (!cspOldHeaderValue.IsEmpty()) { 1.2850 + rv = AppendCSPFromHeader(csp, cspOldHeaderValue, selfURI, false, false); 1.2851 + NS_ENSURE_SUCCESS(rv, rv); 1.2852 + } 1.2853 + 1.2854 + // ----- if there's a report-only CSP header, apply it. 1.2855 + if (!cspROHeaderValue.IsEmpty()) { 1.2856 + rv = AppendCSPFromHeader(csp, cspROHeaderValue, selfURI, true, true); 1.2857 + NS_ENSURE_SUCCESS(rv, rv); 1.2858 + } else if (!cspOldROHeaderValue.IsEmpty()) { 1.2859 + rv = AppendCSPFromHeader(csp, cspOldROHeaderValue, selfURI, true, false); 1.2860 + NS_ENSURE_SUCCESS(rv, rv); 1.2861 + } 1.2862 + 1.2863 + // ----- Enforce frame-ancestor policy on any applied policies 1.2864 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.2865 + if (docShell) { 1.2866 + bool safeAncestry = false; 1.2867 + 1.2868 + // PermitsAncestry sends violation reports when necessary 1.2869 + rv = csp->PermitsAncestry(docShell, &safeAncestry); 1.2870 + NS_ENSURE_SUCCESS(rv, rv); 1.2871 + 1.2872 + if (!safeAncestry) { 1.2873 +#ifdef PR_LOGGING 1.2874 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, 1.2875 + ("CSP doesn't like frame's ancestry, not loading.")); 1.2876 +#endif 1.2877 + // stop! ERROR page! 1.2878 + aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION); 1.2879 + } 1.2880 + } 1.2881 + 1.2882 + rv = principal->SetCsp(csp); 1.2883 + NS_ENSURE_SUCCESS(rv, rv); 1.2884 +#ifdef PR_LOGGING 1.2885 + PR_LOG(gCspPRLog, PR_LOG_DEBUG, 1.2886 + ("Inserted CSP into principal %p", principal)); 1.2887 +#endif 1.2888 + 1.2889 + return NS_OK; 1.2890 +} 1.2891 + 1.2892 +void 1.2893 +nsDocument::StopDocumentLoad() 1.2894 +{ 1.2895 + if (mParser) { 1.2896 + mParserAborted = true; 1.2897 + mParser->Terminate(); 1.2898 + } 1.2899 +} 1.2900 + 1.2901 +void 1.2902 +nsDocument::SetDocumentURI(nsIURI* aURI) 1.2903 +{ 1.2904 + nsCOMPtr<nsIURI> oldBase = GetDocBaseURI(); 1.2905 + mDocumentURI = NS_TryToMakeImmutable(aURI); 1.2906 + nsIURI* newBase = GetDocBaseURI(); 1.2907 + 1.2908 + bool equalBases = false; 1.2909 + // Changing just the ref of a URI does not change how relative URIs would 1.2910 + // resolve wrt to it, so we can treat the bases as equal as long as they're 1.2911 + // equal ignoring the ref. 1.2912 + if (oldBase && newBase) { 1.2913 + oldBase->EqualsExceptRef(newBase, &equalBases); 1.2914 + } 1.2915 + else { 1.2916 + equalBases = !oldBase && !newBase; 1.2917 + } 1.2918 + 1.2919 + // If this is the first time we're setting the document's URI, set the 1.2920 + // document's original URI. 1.2921 + if (!mOriginalURI) 1.2922 + mOriginalURI = mDocumentURI; 1.2923 + 1.2924 + // If changing the document's URI changed the base URI of the document, we 1.2925 + // need to refresh the hrefs of all the links on the page. 1.2926 + if (!equalBases) { 1.2927 + RefreshLinkHrefs(); 1.2928 + } 1.2929 +} 1.2930 + 1.2931 +void 1.2932 +nsDocument::SetChromeXHRDocURI(nsIURI* aURI) 1.2933 +{ 1.2934 + mChromeXHRDocURI = aURI; 1.2935 +} 1.2936 + 1.2937 +void 1.2938 +nsDocument::SetChromeXHRDocBaseURI(nsIURI* aURI) 1.2939 +{ 1.2940 + mChromeXHRDocBaseURI = aURI; 1.2941 +} 1.2942 + 1.2943 +NS_IMETHODIMP 1.2944 +nsDocument::GetLastModified(nsAString& aLastModified) 1.2945 +{ 1.2946 + nsIDocument::GetLastModified(aLastModified); 1.2947 + return NS_OK; 1.2948 +} 1.2949 + 1.2950 +void 1.2951 +nsIDocument::GetLastModified(nsAString& aLastModified) const 1.2952 +{ 1.2953 + if (!mLastModified.IsEmpty()) { 1.2954 + aLastModified.Assign(mLastModified); 1.2955 + } else { 1.2956 + // If we for whatever reason failed to find the last modified time 1.2957 + // (or even the current time), fall back to what NS4.x returned. 1.2958 + aLastModified.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00")); 1.2959 + } 1.2960 +} 1.2961 + 1.2962 +void 1.2963 +nsDocument::AddToNameTable(Element *aElement, nsIAtom* aName) 1.2964 +{ 1.2965 + MOZ_ASSERT(nsGenericHTMLElement::ShouldExposeNameAsHTMLDocumentProperty(aElement), 1.2966 + "Only put elements that need to be exposed as document['name'] in " 1.2967 + "the named table."); 1.2968 + 1.2969 + nsIdentifierMapEntry *entry = 1.2970 + mIdentifierMap.PutEntry(nsDependentAtomString(aName)); 1.2971 + 1.2972 + // Null for out-of-memory 1.2973 + if (entry) { 1.2974 + if (!entry->HasNameElement() && 1.2975 + !entry->HasIdElementExposedAsHTMLDocumentProperty()) { 1.2976 + ++mExpandoAndGeneration.generation; 1.2977 + } 1.2978 + entry->AddNameElement(this, aElement); 1.2979 + } 1.2980 +} 1.2981 + 1.2982 +void 1.2983 +nsDocument::RemoveFromNameTable(Element *aElement, nsIAtom* aName) 1.2984 +{ 1.2985 + // Speed up document teardown 1.2986 + if (mIdentifierMap.Count() == 0) 1.2987 + return; 1.2988 + 1.2989 + nsIdentifierMapEntry *entry = 1.2990 + mIdentifierMap.GetEntry(nsDependentAtomString(aName)); 1.2991 + if (!entry) // Could be false if the element was anonymous, hence never added 1.2992 + return; 1.2993 + 1.2994 + entry->RemoveNameElement(aElement); 1.2995 + if (!entry->HasNameElement() && 1.2996 + !entry->HasIdElementExposedAsHTMLDocumentProperty()) { 1.2997 + ++mExpandoAndGeneration.generation; 1.2998 + } 1.2999 +} 1.3000 + 1.3001 +void 1.3002 +nsDocument::AddToIdTable(Element *aElement, nsIAtom* aId) 1.3003 +{ 1.3004 + nsIdentifierMapEntry *entry = 1.3005 + mIdentifierMap.PutEntry(nsDependentAtomString(aId)); 1.3006 + 1.3007 + if (entry) { /* True except on OOM */ 1.3008 + if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) && 1.3009 + !entry->HasNameElement() && 1.3010 + !entry->HasIdElementExposedAsHTMLDocumentProperty()) { 1.3011 + ++mExpandoAndGeneration.generation; 1.3012 + } 1.3013 + entry->AddIdElement(aElement); 1.3014 + } 1.3015 +} 1.3016 + 1.3017 +void 1.3018 +nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId) 1.3019 +{ 1.3020 + NS_ASSERTION(aId, "huhwhatnow?"); 1.3021 + 1.3022 + // Speed up document teardown 1.3023 + if (mIdentifierMap.Count() == 0) { 1.3024 + return; 1.3025 + } 1.3026 + 1.3027 + nsIdentifierMapEntry *entry = 1.3028 + mIdentifierMap.GetEntry(nsDependentAtomString(aId)); 1.3029 + if (!entry) // Can be null for XML elements with changing ids. 1.3030 + return; 1.3031 + 1.3032 + entry->RemoveIdElement(aElement); 1.3033 + if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) && 1.3034 + !entry->HasNameElement() && 1.3035 + !entry->HasIdElementExposedAsHTMLDocumentProperty()) { 1.3036 + ++mExpandoAndGeneration.generation; 1.3037 + } 1.3038 + if (entry->IsEmpty()) { 1.3039 + mIdentifierMap.RawRemoveEntry(entry); 1.3040 + } 1.3041 +} 1.3042 + 1.3043 +nsIPrincipal* 1.3044 +nsDocument::GetPrincipal() 1.3045 +{ 1.3046 + return NodePrincipal(); 1.3047 +} 1.3048 + 1.3049 +extern bool sDisablePrefetchHTTPSPref; 1.3050 + 1.3051 +void 1.3052 +nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal) 1.3053 +{ 1.3054 + if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) { 1.3055 + nsCOMPtr<nsIURI> uri; 1.3056 + aNewPrincipal->GetURI(getter_AddRefs(uri)); 1.3057 + bool isHTTPS; 1.3058 + if (!uri || NS_FAILED(uri->SchemeIs("https", &isHTTPS)) || 1.3059 + isHTTPS) { 1.3060 + mAllowDNSPrefetch = false; 1.3061 + } 1.3062 + } 1.3063 + mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal); 1.3064 +} 1.3065 + 1.3066 +NS_IMETHODIMP 1.3067 +nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache) 1.3068 +{ 1.3069 + NS_IF_ADDREF(*aApplicationCache = mApplicationCache); 1.3070 + 1.3071 + return NS_OK; 1.3072 +} 1.3073 + 1.3074 +NS_IMETHODIMP 1.3075 +nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache) 1.3076 +{ 1.3077 + mApplicationCache = aApplicationCache; 1.3078 + 1.3079 + return NS_OK; 1.3080 +} 1.3081 + 1.3082 +NS_IMETHODIMP 1.3083 +nsDocument::GetContentType(nsAString& aContentType) 1.3084 +{ 1.3085 + CopyUTF8toUTF16(GetContentTypeInternal(), aContentType); 1.3086 + 1.3087 + return NS_OK; 1.3088 +} 1.3089 + 1.3090 +void 1.3091 +nsDocument::SetContentType(const nsAString& aContentType) 1.3092 +{ 1.3093 + NS_ASSERTION(GetContentTypeInternal().IsEmpty() || 1.3094 + GetContentTypeInternal().Equals(NS_ConvertUTF16toUTF8(aContentType)), 1.3095 + "Do you really want to change the content-type?"); 1.3096 + 1.3097 + SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType)); 1.3098 +} 1.3099 + 1.3100 +nsresult 1.3101 +nsDocument::GetAllowPlugins(bool * aAllowPlugins) 1.3102 +{ 1.3103 + // First, we ask our docshell if it allows plugins. 1.3104 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.3105 + 1.3106 + if (docShell) { 1.3107 + docShell->GetAllowPlugins(aAllowPlugins); 1.3108 + 1.3109 + // If the docshell allows plugins, we check whether 1.3110 + // we are sandboxed and plugins should not be allowed. 1.3111 + if (*aAllowPlugins) 1.3112 + *aAllowPlugins = !(mSandboxFlags & SANDBOXED_PLUGINS); 1.3113 + } 1.3114 + 1.3115 + return NS_OK; 1.3116 +} 1.3117 + 1.3118 +already_AddRefed<UndoManager> 1.3119 +nsDocument::GetUndoManager() 1.3120 +{ 1.3121 + Element* rootElement = GetRootElement(); 1.3122 + if (!rootElement) { 1.3123 + return nullptr; 1.3124 + } 1.3125 + 1.3126 + if (!mUndoManager) { 1.3127 + mUndoManager = new UndoManager(rootElement); 1.3128 + } 1.3129 + 1.3130 + nsRefPtr<UndoManager> undoManager = mUndoManager; 1.3131 + return undoManager.forget(); 1.3132 +} 1.3133 + 1.3134 +/* Return true if the document is in the focused top-level window, and is an 1.3135 + * ancestor of the focused DOMWindow. */ 1.3136 +NS_IMETHODIMP 1.3137 +nsDocument::HasFocus(bool* aResult) 1.3138 +{ 1.3139 + ErrorResult rv; 1.3140 + *aResult = nsIDocument::HasFocus(rv); 1.3141 + return rv.ErrorCode(); 1.3142 +} 1.3143 + 1.3144 +bool 1.3145 +nsIDocument::HasFocus(ErrorResult& rv) const 1.3146 +{ 1.3147 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.3148 + if (!fm) { 1.3149 + rv.Throw(NS_ERROR_NOT_AVAILABLE); 1.3150 + return false; 1.3151 + } 1.3152 + 1.3153 + // Is there a focused DOMWindow? 1.3154 + nsCOMPtr<nsIDOMWindow> focusedWindow; 1.3155 + fm->GetFocusedWindow(getter_AddRefs(focusedWindow)); 1.3156 + if (!focusedWindow) { 1.3157 + return false; 1.3158 + } 1.3159 + 1.3160 + // Are we an ancestor of the focused DOMWindow? 1.3161 + nsCOMPtr<nsIDOMDocument> domDocument; 1.3162 + focusedWindow->GetDocument(getter_AddRefs(domDocument)); 1.3163 + nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument); 1.3164 + 1.3165 + for (nsIDocument* currentDoc = document; currentDoc; 1.3166 + currentDoc = currentDoc->GetParentDocument()) { 1.3167 + if (currentDoc == this) { 1.3168 + // Yes, we are an ancestor 1.3169 + return true; 1.3170 + } 1.3171 + } 1.3172 + 1.3173 + return false; 1.3174 +} 1.3175 + 1.3176 +NS_IMETHODIMP 1.3177 +nsDocument::GetReferrer(nsAString& aReferrer) 1.3178 +{ 1.3179 + nsIDocument::GetReferrer(aReferrer); 1.3180 + return NS_OK; 1.3181 +} 1.3182 + 1.3183 +void 1.3184 +nsIDocument::GetReferrer(nsAString& aReferrer) const 1.3185 +{ 1.3186 + if (mIsSrcdocDocument && mParentDocument) 1.3187 + mParentDocument->GetReferrer(aReferrer); 1.3188 + else 1.3189 + CopyUTF8toUTF16(mReferrer, aReferrer); 1.3190 +} 1.3191 + 1.3192 +nsresult 1.3193 +nsIDocument::GetSrcdocData(nsAString &aSrcdocData) 1.3194 +{ 1.3195 + if (mIsSrcdocDocument) { 1.3196 + nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel); 1.3197 + if (inStrmChan) { 1.3198 + return inStrmChan->GetSrcdocData(aSrcdocData); 1.3199 + } 1.3200 + } 1.3201 + aSrcdocData = NullString(); 1.3202 + return NS_OK; 1.3203 +} 1.3204 + 1.3205 +NS_IMETHODIMP 1.3206 +nsDocument::GetActiveElement(nsIDOMElement **aElement) 1.3207 +{ 1.3208 + nsCOMPtr<nsIDOMElement> el(do_QueryInterface(nsIDocument::GetActiveElement())); 1.3209 + el.forget(aElement); 1.3210 + return NS_OK; 1.3211 +} 1.3212 + 1.3213 +Element* 1.3214 +nsIDocument::GetActiveElement() 1.3215 +{ 1.3216 + // Get the focused element. 1.3217 + nsCOMPtr<nsPIDOMWindow> window = GetWindow(); 1.3218 + if (window) { 1.3219 + nsCOMPtr<nsPIDOMWindow> focusedWindow; 1.3220 + nsIContent* focusedContent = 1.3221 + nsFocusManager::GetFocusedDescendant(window, false, 1.3222 + getter_AddRefs(focusedWindow)); 1.3223 + // be safe and make sure the element is from this document 1.3224 + if (focusedContent && focusedContent->OwnerDoc() == this) { 1.3225 + if (focusedContent->ChromeOnlyAccess()) { 1.3226 + focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent(); 1.3227 + } 1.3228 + if (focusedContent) { 1.3229 + return focusedContent->AsElement(); 1.3230 + } 1.3231 + } 1.3232 + } 1.3233 + 1.3234 + // No focused element anywhere in this document. Try to get the BODY. 1.3235 + nsRefPtr<nsHTMLDocument> htmlDoc = AsHTMLDocument(); 1.3236 + if (htmlDoc) { 1.3237 + // Because of IE compatibility, return null when html document doesn't have 1.3238 + // a body. 1.3239 + return htmlDoc->GetBody(); 1.3240 + } 1.3241 + 1.3242 + // If we couldn't get a BODY, return the root element. 1.3243 + return GetDocumentElement(); 1.3244 +} 1.3245 + 1.3246 +NS_IMETHODIMP 1.3247 +nsDocument::GetCurrentScript(nsIDOMElement **aElement) 1.3248 +{ 1.3249 + nsCOMPtr<nsIDOMElement> el(do_QueryInterface(nsIDocument::GetCurrentScript())); 1.3250 + el.forget(aElement); 1.3251 + return NS_OK; 1.3252 +} 1.3253 + 1.3254 +Element* 1.3255 +nsIDocument::GetCurrentScript() 1.3256 +{ 1.3257 + nsCOMPtr<Element> el(do_QueryInterface(ScriptLoader()->GetCurrentScript())); 1.3258 + return el; 1.3259 +} 1.3260 + 1.3261 +NS_IMETHODIMP 1.3262 +nsDocument::ElementFromPoint(float aX, float aY, nsIDOMElement** aReturn) 1.3263 +{ 1.3264 + Element* el = nsIDocument::ElementFromPoint(aX, aY); 1.3265 + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el); 1.3266 + retval.forget(aReturn); 1.3267 + return NS_OK; 1.3268 +} 1.3269 + 1.3270 +Element* 1.3271 +nsIDocument::ElementFromPoint(float aX, float aY) 1.3272 +{ 1.3273 + return ElementFromPointHelper(aX, aY, false, true); 1.3274 +} 1.3275 + 1.3276 +Element* 1.3277 +nsDocument::ElementFromPointHelper(float aX, float aY, 1.3278 + bool aIgnoreRootScrollFrame, 1.3279 + bool aFlushLayout) 1.3280 +{ 1.3281 + // As per the the spec, we return null if either coord is negative 1.3282 + if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) { 1.3283 + return nullptr; 1.3284 + } 1.3285 + 1.3286 + nscoord x = nsPresContext::CSSPixelsToAppUnits(aX); 1.3287 + nscoord y = nsPresContext::CSSPixelsToAppUnits(aY); 1.3288 + nsPoint pt(x, y); 1.3289 + 1.3290 + // Make sure the layout information we get is up-to-date, and 1.3291 + // ensure we get a root frame (for everything but XUL) 1.3292 + if (aFlushLayout) 1.3293 + FlushPendingNotifications(Flush_Layout); 1.3294 + 1.3295 + nsIPresShell *ps = GetShell(); 1.3296 + if (!ps) { 1.3297 + return nullptr; 1.3298 + } 1.3299 + nsIFrame *rootFrame = ps->GetRootFrame(); 1.3300 + 1.3301 + // XUL docs, unlike HTML, have no frame tree until everything's done loading 1.3302 + if (!rootFrame) { 1.3303 + return nullptr; // return null to premature XUL callers as a reminder to wait 1.3304 + } 1.3305 + 1.3306 + nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, 1.3307 + nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC | 1.3308 + (aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0)); 1.3309 + if (!ptFrame) { 1.3310 + return nullptr; 1.3311 + } 1.3312 + 1.3313 + nsIContent* elem = GetContentInThisDocument(ptFrame); 1.3314 + if (elem && !elem->IsElement()) { 1.3315 + elem = elem->GetParent(); 1.3316 + } 1.3317 + return elem ? elem->AsElement() : nullptr; 1.3318 +} 1.3319 + 1.3320 +nsresult 1.3321 +nsDocument::NodesFromRectHelper(float aX, float aY, 1.3322 + float aTopSize, float aRightSize, 1.3323 + float aBottomSize, float aLeftSize, 1.3324 + bool aIgnoreRootScrollFrame, 1.3325 + bool aFlushLayout, 1.3326 + nsIDOMNodeList** aReturn) 1.3327 +{ 1.3328 + NS_ENSURE_ARG_POINTER(aReturn); 1.3329 + 1.3330 + nsSimpleContentList* elements = new nsSimpleContentList(this); 1.3331 + NS_ADDREF(elements); 1.3332 + *aReturn = elements; 1.3333 + 1.3334 + // Following the same behavior of elementFromPoint, 1.3335 + // we don't return anything if either coord is negative 1.3336 + if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) 1.3337 + return NS_OK; 1.3338 + 1.3339 + nscoord x = nsPresContext::CSSPixelsToAppUnits(aX - aLeftSize); 1.3340 + nscoord y = nsPresContext::CSSPixelsToAppUnits(aY - aTopSize); 1.3341 + nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1; 1.3342 + nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1; 1.3343 + 1.3344 + nsRect rect(x, y, w, h); 1.3345 + 1.3346 + // Make sure the layout information we get is up-to-date, and 1.3347 + // ensure we get a root frame (for everything but XUL) 1.3348 + if (aFlushLayout) { 1.3349 + FlushPendingNotifications(Flush_Layout); 1.3350 + } 1.3351 + 1.3352 + nsIPresShell *ps = GetShell(); 1.3353 + NS_ENSURE_STATE(ps); 1.3354 + nsIFrame *rootFrame = ps->GetRootFrame(); 1.3355 + 1.3356 + // XUL docs, unlike HTML, have no frame tree until everything's done loading 1.3357 + if (!rootFrame) 1.3358 + return NS_OK; // return nothing to premature XUL callers as a reminder to wait 1.3359 + 1.3360 + nsAutoTArray<nsIFrame*,8> outFrames; 1.3361 + nsLayoutUtils::GetFramesForArea(rootFrame, rect, outFrames, 1.3362 + nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC | 1.3363 + (aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0)); 1.3364 + 1.3365 + // Used to filter out repeated elements in sequence. 1.3366 + nsIContent* lastAdded = nullptr; 1.3367 + 1.3368 + for (uint32_t i = 0; i < outFrames.Length(); i++) { 1.3369 + nsIContent* node = GetContentInThisDocument(outFrames[i]); 1.3370 + 1.3371 + if (node && !node->IsElement() && !node->IsNodeOfType(nsINode::eTEXT)) { 1.3372 + // We have a node that isn't an element or a text node, 1.3373 + // use its parent content instead. 1.3374 + node = node->GetParent(); 1.3375 + } 1.3376 + if (node && node != lastAdded) { 1.3377 + elements->AppendElement(node); 1.3378 + lastAdded = node; 1.3379 + } 1.3380 + } 1.3381 + 1.3382 + return NS_OK; 1.3383 +} 1.3384 + 1.3385 +NS_IMETHODIMP 1.3386 +nsDocument::GetElementsByClassName(const nsAString& aClasses, 1.3387 + nsIDOMNodeList** aReturn) 1.3388 +{ 1.3389 + *aReturn = nsIDocument::GetElementsByClassName(aClasses).take(); 1.3390 + return NS_OK; 1.3391 +} 1.3392 + 1.3393 +already_AddRefed<nsContentList> 1.3394 +nsIDocument::GetElementsByClassName(const nsAString& aClasses) 1.3395 +{ 1.3396 + return nsContentUtils::GetElementsByClassName(this, aClasses); 1.3397 +} 1.3398 + 1.3399 +NS_IMETHODIMP 1.3400 +nsDocument::ReleaseCapture() 1.3401 +{ 1.3402 + nsIDocument::ReleaseCapture(); 1.3403 + return NS_OK; 1.3404 +} 1.3405 + 1.3406 +void 1.3407 +nsIDocument::ReleaseCapture() const 1.3408 +{ 1.3409 + // only release the capture if the caller can access it. This prevents a 1.3410 + // page from stopping a scrollbar grab for example. 1.3411 + nsCOMPtr<nsINode> node = nsIPresShell::GetCapturingContent(); 1.3412 + if (node && nsContentUtils::CanCallerAccess(node)) { 1.3413 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.3414 + } 1.3415 +} 1.3416 + 1.3417 +already_AddRefed<nsIURI> 1.3418 +nsIDocument::GetBaseURI(bool aTryUseXHRDocBaseURI) const 1.3419 +{ 1.3420 + nsCOMPtr<nsIURI> uri; 1.3421 + if (aTryUseXHRDocBaseURI && mChromeXHRDocBaseURI) { 1.3422 + uri = mChromeXHRDocBaseURI; 1.3423 + } else { 1.3424 + uri = GetDocBaseURI(); 1.3425 + } 1.3426 + 1.3427 + return uri.forget(); 1.3428 +} 1.3429 + 1.3430 +nsresult 1.3431 +nsDocument::SetBaseURI(nsIURI* aURI) 1.3432 +{ 1.3433 + if (!aURI && !mDocumentBaseURI) { 1.3434 + return NS_OK; 1.3435 + } 1.3436 + 1.3437 + // Don't do anything if the URI wasn't actually changed. 1.3438 + if (aURI && mDocumentBaseURI) { 1.3439 + bool equalBases = false; 1.3440 + mDocumentBaseURI->Equals(aURI, &equalBases); 1.3441 + if (equalBases) { 1.3442 + return NS_OK; 1.3443 + } 1.3444 + } 1.3445 + 1.3446 + if (aURI) { 1.3447 + mDocumentBaseURI = NS_TryToMakeImmutable(aURI); 1.3448 + } else { 1.3449 + mDocumentBaseURI = nullptr; 1.3450 + } 1.3451 + RefreshLinkHrefs(); 1.3452 + 1.3453 + return NS_OK; 1.3454 +} 1.3455 + 1.3456 +void 1.3457 +nsDocument::GetBaseTarget(nsAString &aBaseTarget) 1.3458 +{ 1.3459 + aBaseTarget = mBaseTarget; 1.3460 +} 1.3461 + 1.3462 +void 1.3463 +nsDocument::SetDocumentCharacterSet(const nsACString& aCharSetID) 1.3464 +{ 1.3465 + // XXX it would be a good idea to assert the sanity of the argument, 1.3466 + // but before we figure out what to do about non-Encoding Standard 1.3467 + // encodings in the charset menu and in mailnews, assertions are futile. 1.3468 + if (!mCharacterSet.Equals(aCharSetID)) { 1.3469 + mCharacterSet = aCharSetID; 1.3470 + 1.3471 + int32_t n = mCharSetObservers.Length(); 1.3472 + 1.3473 + for (int32_t i = 0; i < n; i++) { 1.3474 + nsIObserver* observer = mCharSetObservers.ElementAt(i); 1.3475 + 1.3476 + observer->Observe(static_cast<nsIDocument *>(this), "charset", 1.3477 + NS_ConvertASCIItoUTF16(aCharSetID).get()); 1.3478 + } 1.3479 + } 1.3480 +} 1.3481 + 1.3482 +nsresult 1.3483 +nsDocument::AddCharSetObserver(nsIObserver* aObserver) 1.3484 +{ 1.3485 + NS_ENSURE_ARG_POINTER(aObserver); 1.3486 + 1.3487 + NS_ENSURE_TRUE(mCharSetObservers.AppendElement(aObserver), NS_ERROR_FAILURE); 1.3488 + 1.3489 + return NS_OK; 1.3490 +} 1.3491 + 1.3492 +void 1.3493 +nsDocument::RemoveCharSetObserver(nsIObserver* aObserver) 1.3494 +{ 1.3495 + mCharSetObservers.RemoveElement(aObserver); 1.3496 +} 1.3497 + 1.3498 +void 1.3499 +nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const 1.3500 +{ 1.3501 + aData.Truncate(); 1.3502 + const nsDocHeaderData* data = mHeaderData; 1.3503 + while (data) { 1.3504 + if (data->mField == aHeaderField) { 1.3505 + aData = data->mData; 1.3506 + 1.3507 + break; 1.3508 + } 1.3509 + data = data->mNext; 1.3510 + } 1.3511 +} 1.3512 + 1.3513 +void 1.3514 +nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData) 1.3515 +{ 1.3516 + if (!aHeaderField) { 1.3517 + NS_ERROR("null headerField"); 1.3518 + return; 1.3519 + } 1.3520 + 1.3521 + if (!mHeaderData) { 1.3522 + if (!aData.IsEmpty()) { // don't bother storing empty string 1.3523 + mHeaderData = new nsDocHeaderData(aHeaderField, aData); 1.3524 + } 1.3525 + } 1.3526 + else { 1.3527 + nsDocHeaderData* data = mHeaderData; 1.3528 + nsDocHeaderData** lastPtr = &mHeaderData; 1.3529 + bool found = false; 1.3530 + do { // look for existing and replace 1.3531 + if (data->mField == aHeaderField) { 1.3532 + if (!aData.IsEmpty()) { 1.3533 + data->mData.Assign(aData); 1.3534 + } 1.3535 + else { // don't store empty string 1.3536 + *lastPtr = data->mNext; 1.3537 + data->mNext = nullptr; 1.3538 + delete data; 1.3539 + } 1.3540 + found = true; 1.3541 + 1.3542 + break; 1.3543 + } 1.3544 + lastPtr = &(data->mNext); 1.3545 + data = *lastPtr; 1.3546 + } while (data); 1.3547 + 1.3548 + if (!aData.IsEmpty() && !found) { 1.3549 + // didn't find, append 1.3550 + *lastPtr = new nsDocHeaderData(aHeaderField, aData); 1.3551 + } 1.3552 + } 1.3553 + 1.3554 + if (aHeaderField == nsGkAtoms::headerContentLanguage) { 1.3555 + CopyUTF16toUTF8(aData, mContentLanguage); 1.3556 + } 1.3557 + 1.3558 + if (aHeaderField == nsGkAtoms::headerDefaultStyle) { 1.3559 + // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per 1.3560 + // spec. 1.3561 + if (DOMStringIsNull(mLastStyleSheetSet)) { 1.3562 + // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet, 1.3563 + // per spec. The idea here is that we're changing our preferred set and 1.3564 + // that shouldn't change the value of lastStyleSheetSet. Also, we're 1.3565 + // using the Internal version so we can update the CSSLoader and not have 1.3566 + // to worry about null strings. 1.3567 + EnableStyleSheetsForSetInternal(aData, true); 1.3568 + } 1.3569 + } 1.3570 + 1.3571 + if (aHeaderField == nsGkAtoms::refresh) { 1.3572 + // We get into this code before we have a script global yet, so get to 1.3573 + // our container via mDocumentContainer. 1.3574 + nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer); 1.3575 + if (refresher) { 1.3576 + // Note: using mDocumentURI instead of mBaseURI here, for consistency 1.3577 + // (used to just use the current URI of our webnavigation, but that 1.3578 + // should really be the same thing). Note that this code can run 1.3579 + // before the current URI of the webnavigation has been updated, so we 1.3580 + // can't assert equality here. 1.3581 + refresher->SetupRefreshURIFromHeader(mDocumentURI, NodePrincipal(), 1.3582 + NS_ConvertUTF16toUTF8(aData)); 1.3583 + } 1.3584 + } 1.3585 + 1.3586 + if (aHeaderField == nsGkAtoms::headerDNSPrefetchControl && 1.3587 + mAllowDNSPrefetch) { 1.3588 + // Chromium treats any value other than 'on' (case insensitive) as 'off'. 1.3589 + mAllowDNSPrefetch = aData.IsEmpty() || aData.LowerCaseEqualsLiteral("on"); 1.3590 + } 1.3591 + 1.3592 + if (aHeaderField == nsGkAtoms::viewport || 1.3593 + aHeaderField == nsGkAtoms::handheldFriendly || 1.3594 + aHeaderField == nsGkAtoms::viewport_minimum_scale || 1.3595 + aHeaderField == nsGkAtoms::viewport_maximum_scale || 1.3596 + aHeaderField == nsGkAtoms::viewport_initial_scale || 1.3597 + aHeaderField == nsGkAtoms::viewport_height || 1.3598 + aHeaderField == nsGkAtoms::viewport_width || 1.3599 + aHeaderField == nsGkAtoms::viewport_user_scalable) { 1.3600 + mViewportType = Unknown; 1.3601 + } 1.3602 +} 1.3603 + 1.3604 +void 1.3605 +nsDocument::TryChannelCharset(nsIChannel *aChannel, 1.3606 + int32_t& aCharsetSource, 1.3607 + nsACString& aCharset, 1.3608 + nsHtml5TreeOpExecutor* aExecutor) 1.3609 +{ 1.3610 + if (aChannel) { 1.3611 + nsAutoCString charsetVal; 1.3612 + nsresult rv = aChannel->GetContentCharset(charsetVal); 1.3613 + if (NS_SUCCEEDED(rv)) { 1.3614 + nsAutoCString preferred; 1.3615 + if(EncodingUtils::FindEncodingForLabel(charsetVal, preferred)) { 1.3616 + aCharset = preferred; 1.3617 + aCharsetSource = kCharsetFromChannel; 1.3618 + return; 1.3619 + } else if (aExecutor && !charsetVal.IsEmpty()) { 1.3620 + aExecutor->ComplainAboutBogusProtocolCharset(this); 1.3621 + } 1.3622 + } 1.3623 + } 1.3624 +} 1.3625 + 1.3626 +already_AddRefed<nsIPresShell> 1.3627 +nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager, 1.3628 + nsStyleSet* aStyleSet) 1.3629 +{ 1.3630 + // Don't add anything here. Add it to |doCreateShell| instead. 1.3631 + // This exists so that subclasses can pass other values for the 4th 1.3632 + // parameter some of the time. 1.3633 + return doCreateShell(aContext, aViewManager, aStyleSet, 1.3634 + eCompatibility_FullStandards); 1.3635 +} 1.3636 + 1.3637 +already_AddRefed<nsIPresShell> 1.3638 +nsDocument::doCreateShell(nsPresContext* aContext, 1.3639 + nsViewManager* aViewManager, nsStyleSet* aStyleSet, 1.3640 + nsCompatibility aCompatMode) 1.3641 +{ 1.3642 + NS_ASSERTION(!mPresShell, "We have a presshell already!"); 1.3643 + 1.3644 + NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr); 1.3645 + 1.3646 + FillStyleSet(aStyleSet); 1.3647 + 1.3648 + nsRefPtr<PresShell> shell = new PresShell; 1.3649 + shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode); 1.3650 + 1.3651 + // Note: we don't hold a ref to the shell (it holds a ref to us) 1.3652 + mPresShell = shell; 1.3653 + 1.3654 + // Make sure to never paint if we belong to an invisible DocShell. 1.3655 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.3656 + if (docShell && docShell->IsInvisible()) 1.3657 + shell->SetNeverPainting(true); 1.3658 + 1.3659 + mExternalResourceMap.ShowViewers(); 1.3660 + 1.3661 + MaybeRescheduleAnimationFrameNotifications(); 1.3662 + 1.3663 + return shell.forget(); 1.3664 +} 1.3665 + 1.3666 +void 1.3667 +nsDocument::MaybeRescheduleAnimationFrameNotifications() 1.3668 +{ 1.3669 + if (!mPresShell || !IsEventHandlingEnabled()) { 1.3670 + // bail out for now, until one of those conditions changes 1.3671 + return; 1.3672 + } 1.3673 + 1.3674 + nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver(); 1.3675 + if (!mFrameRequestCallbacks.IsEmpty()) { 1.3676 + rd->ScheduleFrameRequestCallbacks(this); 1.3677 + } 1.3678 +} 1.3679 + 1.3680 +void 1.3681 +nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks) 1.3682 +{ 1.3683 + aCallbacks.AppendElements(mFrameRequestCallbacks); 1.3684 + mFrameRequestCallbacks.Clear(); 1.3685 +} 1.3686 + 1.3687 +PLDHashOperator RequestDiscardEnumerator(imgIRequest* aKey, 1.3688 + uint32_t aData, 1.3689 + void* userArg) 1.3690 +{ 1.3691 + aKey->RequestDiscard(); 1.3692 + return PL_DHASH_NEXT; 1.3693 +} 1.3694 + 1.3695 +void 1.3696 +nsDocument::DeleteShell() 1.3697 +{ 1.3698 + mExternalResourceMap.HideViewers(); 1.3699 + if (IsEventHandlingEnabled()) { 1.3700 + RevokeAnimationFrameNotifications(); 1.3701 + } 1.3702 + 1.3703 + // When our shell goes away, request that all our images be immediately 1.3704 + // discarded, so we don't carry around decoded image data for a document we 1.3705 + // no longer intend to paint. 1.3706 + mImageTracker.EnumerateRead(RequestDiscardEnumerator, nullptr); 1.3707 + 1.3708 + mPresShell = nullptr; 1.3709 +} 1.3710 + 1.3711 +void 1.3712 +nsDocument::RevokeAnimationFrameNotifications() 1.3713 +{ 1.3714 + if (!mFrameRequestCallbacks.IsEmpty()) { 1.3715 + mPresShell->GetPresContext()->RefreshDriver()-> 1.3716 + RevokeFrameRequestCallbacks(this); 1.3717 + } 1.3718 +} 1.3719 + 1.3720 +static void 1.3721 +SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) 1.3722 +{ 1.3723 + SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry); 1.3724 + 1.3725 + NS_RELEASE(e->mKey); 1.3726 + if (e->mSubDocument) { 1.3727 + e->mSubDocument->SetParentDocument(nullptr); 1.3728 + NS_RELEASE(e->mSubDocument); 1.3729 + } 1.3730 +} 1.3731 + 1.3732 +static bool 1.3733 +SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key) 1.3734 +{ 1.3735 + SubDocMapEntry *e = 1.3736 + const_cast<SubDocMapEntry *> 1.3737 + (static_cast<const SubDocMapEntry *>(entry)); 1.3738 + 1.3739 + e->mKey = const_cast<Element*>(static_cast<const Element*>(key)); 1.3740 + NS_ADDREF(e->mKey); 1.3741 + 1.3742 + e->mSubDocument = nullptr; 1.3743 + return true; 1.3744 +} 1.3745 + 1.3746 +nsresult 1.3747 +nsDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc) 1.3748 +{ 1.3749 + NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED); 1.3750 + 1.3751 + if (!aSubDoc) { 1.3752 + // aSubDoc is nullptr, remove the mapping 1.3753 + 1.3754 + if (mSubDocuments) { 1.3755 + SubDocMapEntry *entry = 1.3756 + static_cast<SubDocMapEntry*> 1.3757 + (PL_DHashTableOperate(mSubDocuments, aElement, 1.3758 + PL_DHASH_LOOKUP)); 1.3759 + 1.3760 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.3761 + PL_DHashTableRawRemove(mSubDocuments, entry); 1.3762 + } 1.3763 + } 1.3764 + } else { 1.3765 + if (!mSubDocuments) { 1.3766 + // Create a new hashtable 1.3767 + 1.3768 + static const PLDHashTableOps hash_table_ops = 1.3769 + { 1.3770 + PL_DHashAllocTable, 1.3771 + PL_DHashFreeTable, 1.3772 + PL_DHashVoidPtrKeyStub, 1.3773 + PL_DHashMatchEntryStub, 1.3774 + PL_DHashMoveEntryStub, 1.3775 + SubDocClearEntry, 1.3776 + PL_DHashFinalizeStub, 1.3777 + SubDocInitEntry 1.3778 + }; 1.3779 + 1.3780 + mSubDocuments = PL_NewDHashTable(&hash_table_ops, nullptr, 1.3781 + sizeof(SubDocMapEntry), 16); 1.3782 + if (!mSubDocuments) { 1.3783 + return NS_ERROR_OUT_OF_MEMORY; 1.3784 + } 1.3785 + } 1.3786 + 1.3787 + // Add a mapping to the hash table 1.3788 + SubDocMapEntry *entry = 1.3789 + static_cast<SubDocMapEntry*> 1.3790 + (PL_DHashTableOperate(mSubDocuments, aElement, 1.3791 + PL_DHASH_ADD)); 1.3792 + 1.3793 + if (!entry) { 1.3794 + return NS_ERROR_OUT_OF_MEMORY; 1.3795 + } 1.3796 + 1.3797 + if (entry->mSubDocument) { 1.3798 + entry->mSubDocument->SetParentDocument(nullptr); 1.3799 + 1.3800 + // Release the old sub document 1.3801 + NS_RELEASE(entry->mSubDocument); 1.3802 + } 1.3803 + 1.3804 + entry->mSubDocument = aSubDoc; 1.3805 + NS_ADDREF(entry->mSubDocument); 1.3806 + 1.3807 + aSubDoc->SetParentDocument(this); 1.3808 + } 1.3809 + 1.3810 + return NS_OK; 1.3811 +} 1.3812 + 1.3813 +nsIDocument* 1.3814 +nsDocument::GetSubDocumentFor(nsIContent *aContent) const 1.3815 +{ 1.3816 + if (mSubDocuments && aContent->IsElement()) { 1.3817 + SubDocMapEntry *entry = 1.3818 + static_cast<SubDocMapEntry*> 1.3819 + (PL_DHashTableOperate(mSubDocuments, aContent->AsElement(), 1.3820 + PL_DHASH_LOOKUP)); 1.3821 + 1.3822 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.3823 + return entry->mSubDocument; 1.3824 + } 1.3825 + } 1.3826 + 1.3827 + return nullptr; 1.3828 +} 1.3829 + 1.3830 +static PLDHashOperator 1.3831 +FindContentEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.3832 + uint32_t number, void *arg) 1.3833 +{ 1.3834 + SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr); 1.3835 + FindContentData *data = static_cast<FindContentData*>(arg); 1.3836 + 1.3837 + if (entry->mSubDocument == data->mSubDocument) { 1.3838 + data->mResult = entry->mKey; 1.3839 + 1.3840 + return PL_DHASH_STOP; 1.3841 + } 1.3842 + 1.3843 + return PL_DHASH_NEXT; 1.3844 +} 1.3845 + 1.3846 +Element* 1.3847 +nsDocument::FindContentForSubDocument(nsIDocument *aDocument) const 1.3848 +{ 1.3849 + NS_ENSURE_TRUE(aDocument, nullptr); 1.3850 + 1.3851 + if (!mSubDocuments) { 1.3852 + return nullptr; 1.3853 + } 1.3854 + 1.3855 + FindContentData data(aDocument); 1.3856 + PL_DHashTableEnumerate(mSubDocuments, FindContentEnumerator, &data); 1.3857 + 1.3858 + return data.mResult; 1.3859 +} 1.3860 + 1.3861 +bool 1.3862 +nsDocument::IsNodeOfType(uint32_t aFlags) const 1.3863 +{ 1.3864 + return !(aFlags & ~eDOCUMENT); 1.3865 +} 1.3866 + 1.3867 +Element* 1.3868 +nsIDocument::GetRootElement() const 1.3869 +{ 1.3870 + return (mCachedRootElement && mCachedRootElement->GetParentNode() == this) ? 1.3871 + mCachedRootElement : GetRootElementInternal(); 1.3872 +} 1.3873 + 1.3874 +Element* 1.3875 +nsDocument::GetRootElementInternal() const 1.3876 +{ 1.3877 + // Loop backwards because any non-elements, such as doctypes and PIs 1.3878 + // are likely to appear before the root element. 1.3879 + uint32_t i; 1.3880 + for (i = mChildren.ChildCount(); i > 0; --i) { 1.3881 + nsIContent* child = mChildren.ChildAt(i - 1); 1.3882 + if (child->IsElement()) { 1.3883 + const_cast<nsDocument*>(this)->mCachedRootElement = child->AsElement(); 1.3884 + return child->AsElement(); 1.3885 + } 1.3886 + } 1.3887 + 1.3888 + const_cast<nsDocument*>(this)->mCachedRootElement = nullptr; 1.3889 + return nullptr; 1.3890 +} 1.3891 + 1.3892 +nsIContent * 1.3893 +nsDocument::GetChildAt(uint32_t aIndex) const 1.3894 +{ 1.3895 + return mChildren.GetSafeChildAt(aIndex); 1.3896 +} 1.3897 + 1.3898 +int32_t 1.3899 +nsDocument::IndexOf(const nsINode* aPossibleChild) const 1.3900 +{ 1.3901 + return mChildren.IndexOfChild(aPossibleChild); 1.3902 +} 1.3903 + 1.3904 +uint32_t 1.3905 +nsDocument::GetChildCount() const 1.3906 +{ 1.3907 + return mChildren.ChildCount(); 1.3908 +} 1.3909 + 1.3910 +nsIContent * const * 1.3911 +nsDocument::GetChildArray(uint32_t* aChildCount) const 1.3912 +{ 1.3913 + return mChildren.GetChildArray(aChildCount); 1.3914 +} 1.3915 + 1.3916 + 1.3917 +nsresult 1.3918 +nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex, 1.3919 + bool aNotify) 1.3920 +{ 1.3921 + if (aKid->IsElement() && GetRootElement()) { 1.3922 + NS_WARNING("Inserting root element when we already have one"); 1.3923 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.3924 + } 1.3925 + 1.3926 + return doInsertChildAt(aKid, aIndex, aNotify, mChildren); 1.3927 +} 1.3928 + 1.3929 +nsresult 1.3930 +nsDocument::AppendChildTo(nsIContent* aKid, bool aNotify) 1.3931 +{ 1.3932 + // Make sure to _not_ call the subclass InsertChildAt here. If 1.3933 + // subclasses wanted to hook into this stuff, they would have 1.3934 + // overridden AppendChildTo. 1.3935 + // XXXbz maybe this should just be a non-virtual method on nsINode? 1.3936 + // Feels that way to me... 1.3937 + return nsDocument::InsertChildAt(aKid, GetChildCount(), aNotify); 1.3938 +} 1.3939 + 1.3940 +void 1.3941 +nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify) 1.3942 +{ 1.3943 + nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex); 1.3944 + if (!oldKid) { 1.3945 + return; 1.3946 + } 1.3947 + 1.3948 + if (oldKid->IsElement()) { 1.3949 + // Destroy the link map up front before we mess with the child list. 1.3950 + DestroyElementMaps(); 1.3951 + } 1.3952 + 1.3953 + doRemoveChildAt(aIndex, aNotify, oldKid, mChildren); 1.3954 + mCachedRootElement = nullptr; 1.3955 +} 1.3956 + 1.3957 +int32_t 1.3958 +nsDocument::GetNumberOfStyleSheets() const 1.3959 +{ 1.3960 + return mStyleSheets.Count(); 1.3961 +} 1.3962 + 1.3963 +nsIStyleSheet* 1.3964 +nsDocument::GetStyleSheetAt(int32_t aIndex) const 1.3965 +{ 1.3966 + NS_ENSURE_TRUE(0 <= aIndex && aIndex < mStyleSheets.Count(), nullptr); 1.3967 + return mStyleSheets[aIndex]; 1.3968 +} 1.3969 + 1.3970 +int32_t 1.3971 +nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const 1.3972 +{ 1.3973 + return mStyleSheets.IndexOf(aSheet); 1.3974 +} 1.3975 + 1.3976 +void 1.3977 +nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet) 1.3978 +{ 1.3979 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.3980 + if (shell) { 1.3981 + shell->StyleSet()->AddDocStyleSheet(aSheet, this); 1.3982 + } 1.3983 +} 1.3984 + 1.3985 +#define DO_STYLESHEET_NOTIFICATION(createFunc, concreteInterface, initMethod, type, ...) \ 1.3986 + do { \ 1.3987 + nsCOMPtr<nsIDOMEvent> event; \ 1.3988 + nsresult rv = createFunc(getter_AddRefs(event), this, \ 1.3989 + mPresShell ? \ 1.3990 + mPresShell->GetPresContext() : nullptr, \ 1.3991 + nullptr); \ 1.3992 + if (NS_FAILED(rv)) { \ 1.3993 + return; \ 1.3994 + } \ 1.3995 + nsCOMPtr<nsIDOMCSSStyleSheet> cssSheet(do_QueryInterface(aSheet)); \ 1.3996 + if (!cssSheet) { \ 1.3997 + return; \ 1.3998 + } \ 1.3999 + nsCOMPtr<concreteInterface> ssEvent(do_QueryInterface(event)); \ 1.4000 + MOZ_ASSERT(ssEvent); \ 1.4001 + ssEvent->initMethod(NS_LITERAL_STRING(type), true, true, \ 1.4002 + cssSheet, __VA_ARGS__); \ 1.4003 + event->SetTrusted(true); \ 1.4004 + event->SetTarget(this); \ 1.4005 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = \ 1.4006 + new AsyncEventDispatcher(this, event); \ 1.4007 + asyncDispatcher->mDispatchChromeOnly = true; \ 1.4008 + asyncDispatcher->PostDOMEvent(); \ 1.4009 + } while (0); 1.4010 + 1.4011 +void 1.4012 +nsDocument::NotifyStyleSheetAdded(nsIStyleSheet* aSheet, bool aDocumentSheet) 1.4013 +{ 1.4014 + NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, aDocumentSheet)); 1.4015 + 1.4016 + if (StyleSheetChangeEventsEnabled()) { 1.4017 + DO_STYLESHEET_NOTIFICATION(NS_NewDOMStyleSheetChangeEvent, 1.4018 + nsIDOMStyleSheetChangeEvent, 1.4019 + InitStyleSheetChangeEvent, 1.4020 + "StyleSheetAdded", 1.4021 + aDocumentSheet); 1.4022 + } 1.4023 +} 1.4024 + 1.4025 +void 1.4026 +nsDocument::NotifyStyleSheetRemoved(nsIStyleSheet* aSheet, bool aDocumentSheet) 1.4027 +{ 1.4028 + NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (this, aSheet, aDocumentSheet)); 1.4029 + 1.4030 + if (StyleSheetChangeEventsEnabled()) { 1.4031 + DO_STYLESHEET_NOTIFICATION(NS_NewDOMStyleSheetChangeEvent, 1.4032 + nsIDOMStyleSheetChangeEvent, 1.4033 + InitStyleSheetChangeEvent, 1.4034 + "StyleSheetRemoved", 1.4035 + aDocumentSheet); 1.4036 + } 1.4037 +} 1.4038 + 1.4039 +void 1.4040 +nsDocument::AddStyleSheet(nsIStyleSheet* aSheet) 1.4041 +{ 1.4042 + NS_PRECONDITION(aSheet, "null arg"); 1.4043 + mStyleSheets.AppendObject(aSheet); 1.4044 + aSheet->SetOwningDocument(this); 1.4045 + 1.4046 + if (aSheet->IsApplicable()) { 1.4047 + AddStyleSheetToStyleSets(aSheet); 1.4048 + } 1.4049 + 1.4050 + NotifyStyleSheetAdded(aSheet, true); 1.4051 +} 1.4052 + 1.4053 +void 1.4054 +nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet) 1.4055 +{ 1.4056 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.4057 + if (shell) { 1.4058 + shell->StyleSet()->RemoveDocStyleSheet(aSheet); 1.4059 + } 1.4060 +} 1.4061 + 1.4062 +void 1.4063 +nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet) 1.4064 +{ 1.4065 + NS_PRECONDITION(aSheet, "null arg"); 1.4066 + nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon 1.4067 + 1.4068 + if (!mStyleSheets.RemoveObject(aSheet)) { 1.4069 + NS_ASSERTION(mInUnlinkOrDeletion, "stylesheet not found"); 1.4070 + return; 1.4071 + } 1.4072 + 1.4073 + if (!mIsGoingAway) { 1.4074 + if (aSheet->IsApplicable()) { 1.4075 + RemoveStyleSheetFromStyleSets(aSheet); 1.4076 + } 1.4077 + 1.4078 + NotifyStyleSheetRemoved(aSheet, true); 1.4079 + } 1.4080 + 1.4081 + aSheet->SetOwningDocument(nullptr); 1.4082 +} 1.4083 + 1.4084 +void 1.4085 +nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets, 1.4086 + nsCOMArray<nsIStyleSheet>& aNewSheets) 1.4087 +{ 1.4088 + BeginUpdate(UPDATE_STYLE); 1.4089 + 1.4090 + // XXX Need to set the sheet on the ownernode, if any 1.4091 + NS_PRECONDITION(aOldSheets.Count() == aNewSheets.Count(), 1.4092 + "The lists must be the same length!"); 1.4093 + int32_t count = aOldSheets.Count(); 1.4094 + 1.4095 + nsCOMPtr<nsIStyleSheet> oldSheet; 1.4096 + int32_t i; 1.4097 + for (i = 0; i < count; ++i) { 1.4098 + oldSheet = aOldSheets[i]; 1.4099 + 1.4100 + // First remove the old sheet. 1.4101 + NS_ASSERTION(oldSheet, "None of the old sheets should be null"); 1.4102 + int32_t oldIndex = mStyleSheets.IndexOf(oldSheet); 1.4103 + RemoveStyleSheet(oldSheet); // This does the right notifications 1.4104 + 1.4105 + // Now put the new one in its place. If it's null, just ignore it. 1.4106 + nsIStyleSheet* newSheet = aNewSheets[i]; 1.4107 + if (newSheet) { 1.4108 + mStyleSheets.InsertObjectAt(newSheet, oldIndex); 1.4109 + newSheet->SetOwningDocument(this); 1.4110 + if (newSheet->IsApplicable()) { 1.4111 + AddStyleSheetToStyleSets(newSheet); 1.4112 + } 1.4113 + 1.4114 + NotifyStyleSheetAdded(newSheet, true); 1.4115 + } 1.4116 + } 1.4117 + 1.4118 + EndUpdate(UPDATE_STYLE); 1.4119 +} 1.4120 + 1.4121 +void 1.4122 +nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, int32_t aIndex) 1.4123 +{ 1.4124 + NS_PRECONDITION(aSheet, "null ptr"); 1.4125 + mStyleSheets.InsertObjectAt(aSheet, aIndex); 1.4126 + 1.4127 + aSheet->SetOwningDocument(this); 1.4128 + 1.4129 + if (aSheet->IsApplicable()) { 1.4130 + AddStyleSheetToStyleSets(aSheet); 1.4131 + } 1.4132 + 1.4133 + NotifyStyleSheetAdded(aSheet, true); 1.4134 +} 1.4135 + 1.4136 + 1.4137 +void 1.4138 +nsDocument::SetStyleSheetApplicableState(nsIStyleSheet* aSheet, 1.4139 + bool aApplicable) 1.4140 +{ 1.4141 + NS_PRECONDITION(aSheet, "null arg"); 1.4142 + 1.4143 + // If we're actually in the document style sheet list 1.4144 + if (-1 != mStyleSheets.IndexOf(aSheet)) { 1.4145 + if (aApplicable) { 1.4146 + AddStyleSheetToStyleSets(aSheet); 1.4147 + } else { 1.4148 + RemoveStyleSheetFromStyleSets(aSheet); 1.4149 + } 1.4150 + } 1.4151 + 1.4152 + // We have to always notify, since this will be called for sheets 1.4153 + // that are children of sheets in our style set, as well as some 1.4154 + // sheets for nsHTMLEditor. 1.4155 + 1.4156 + NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged, 1.4157 + (this, aSheet, aApplicable)); 1.4158 + 1.4159 + if (StyleSheetChangeEventsEnabled()) { 1.4160 + DO_STYLESHEET_NOTIFICATION(NS_NewDOMStyleSheetApplicableStateChangeEvent, 1.4161 + nsIDOMStyleSheetApplicableStateChangeEvent, 1.4162 + InitStyleSheetApplicableStateChangeEvent, 1.4163 + "StyleSheetApplicableStateChanged", 1.4164 + aApplicable); 1.4165 + } 1.4166 + 1.4167 + if (!mSSApplicableStateNotificationPending) { 1.4168 + nsRefPtr<nsIRunnable> notification = NS_NewRunnableMethod(this, 1.4169 + &nsDocument::NotifyStyleSheetApplicableStateChanged); 1.4170 + mSSApplicableStateNotificationPending = 1.4171 + NS_SUCCEEDED(NS_DispatchToCurrentThread(notification)); 1.4172 + } 1.4173 +} 1.4174 + 1.4175 +void 1.4176 +nsDocument::NotifyStyleSheetApplicableStateChanged() 1.4177 +{ 1.4178 + mSSApplicableStateNotificationPending = false; 1.4179 + nsCOMPtr<nsIObserverService> observerService = 1.4180 + mozilla::services::GetObserverService(); 1.4181 + if (observerService) { 1.4182 + observerService->NotifyObservers(static_cast<nsIDocument*>(this), 1.4183 + "style-sheet-applicable-state-changed", 1.4184 + nullptr); 1.4185 + } 1.4186 +} 1.4187 + 1.4188 +// These three functions are a lot like the implementation of the 1.4189 +// corresponding API for regular stylesheets. 1.4190 + 1.4191 +int32_t 1.4192 +nsDocument::GetNumberOfCatalogStyleSheets() const 1.4193 +{ 1.4194 + return mCatalogSheets.Count(); 1.4195 +} 1.4196 + 1.4197 +nsIStyleSheet* 1.4198 +nsDocument::GetCatalogStyleSheetAt(int32_t aIndex) const 1.4199 +{ 1.4200 + NS_ENSURE_TRUE(0 <= aIndex && aIndex < mCatalogSheets.Count(), nullptr); 1.4201 + return mCatalogSheets[aIndex]; 1.4202 +} 1.4203 + 1.4204 +void 1.4205 +nsDocument::AddCatalogStyleSheet(nsCSSStyleSheet* aSheet) 1.4206 +{ 1.4207 + mCatalogSheets.AppendObject(aSheet); 1.4208 + aSheet->SetOwningDocument(this); 1.4209 + aSheet->SetOwningNode(this); 1.4210 + 1.4211 + if (aSheet->IsApplicable()) { 1.4212 + // This is like |AddStyleSheetToStyleSets|, but for an agent sheet. 1.4213 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.4214 + if (shell) { 1.4215 + shell->StyleSet()->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet); 1.4216 + } 1.4217 + } 1.4218 + 1.4219 + NotifyStyleSheetAdded(aSheet, false); 1.4220 +} 1.4221 + 1.4222 +void 1.4223 +nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI) 1.4224 +{ 1.4225 + mozilla::css::Loader* cssLoader = CSSLoader(); 1.4226 + if (cssLoader->GetEnabled()) { 1.4227 + int32_t sheetCount = GetNumberOfCatalogStyleSheets(); 1.4228 + for (int32_t i = 0; i < sheetCount; i++) { 1.4229 + nsIStyleSheet* sheet = GetCatalogStyleSheetAt(i); 1.4230 + NS_ASSERTION(sheet, "unexpected null stylesheet in the document"); 1.4231 + if (sheet) { 1.4232 + nsAutoCString uriStr; 1.4233 + sheet->GetSheetURI()->GetSpec(uriStr); 1.4234 + if (uriStr.Equals(aStyleSheetURI)) 1.4235 + return; 1.4236 + } 1.4237 + } 1.4238 + 1.4239 + nsCOMPtr<nsIURI> uri; 1.4240 + NS_NewURI(getter_AddRefs(uri), aStyleSheetURI); 1.4241 + if (uri) { 1.4242 + nsRefPtr<nsCSSStyleSheet> sheet; 1.4243 + cssLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet)); 1.4244 + if (sheet) { 1.4245 + BeginUpdate(UPDATE_STYLE); 1.4246 + AddCatalogStyleSheet(sheet); 1.4247 + EndUpdate(UPDATE_STYLE); 1.4248 + } 1.4249 + } 1.4250 + } 1.4251 +} 1.4252 + 1.4253 +static nsStyleSet::sheetType 1.4254 +ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType) 1.4255 +{ 1.4256 + switch(aType) { 1.4257 + case nsIDocument::eAgentSheet: 1.4258 + return nsStyleSet::eAgentSheet; 1.4259 + case nsIDocument::eUserSheet: 1.4260 + return nsStyleSet::eUserSheet; 1.4261 + case nsIDocument::eAuthorSheet: 1.4262 + return nsStyleSet::eDocSheet; 1.4263 + default: 1.4264 + NS_ASSERTION(false, "wrong type"); 1.4265 + // we must return something although this should never happen 1.4266 + return nsStyleSet::eSheetTypeCount; 1.4267 + } 1.4268 +} 1.4269 + 1.4270 +static int32_t 1.4271 +FindSheet(const nsCOMArray<nsIStyleSheet>& aSheets, nsIURI* aSheetURI) 1.4272 +{ 1.4273 + for (int32_t i = aSheets.Count() - 1; i >= 0; i-- ) { 1.4274 + bool bEqual; 1.4275 + nsIURI* uri = aSheets[i]->GetSheetURI(); 1.4276 + 1.4277 + if (uri && NS_SUCCEEDED(uri->Equals(aSheetURI, &bEqual)) && bEqual) 1.4278 + return i; 1.4279 + } 1.4280 + 1.4281 + return -1; 1.4282 +} 1.4283 + 1.4284 +nsresult 1.4285 +nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) 1.4286 +{ 1.4287 + NS_PRECONDITION(aSheetURI, "null arg"); 1.4288 + 1.4289 + // Checking if we have loaded this one already. 1.4290 + if (FindSheet(mAdditionalSheets[aType], aSheetURI) >= 0) 1.4291 + return NS_ERROR_INVALID_ARG; 1.4292 + 1.4293 + // Loading the sheet sync. 1.4294 + nsRefPtr<mozilla::css::Loader> loader = new mozilla::css::Loader(); 1.4295 + 1.4296 + nsRefPtr<nsCSSStyleSheet> sheet; 1.4297 + nsresult rv = loader->LoadSheetSync(aSheetURI, aType == eAgentSheet, 1.4298 + true, getter_AddRefs(sheet)); 1.4299 + NS_ENSURE_SUCCESS(rv, rv); 1.4300 + 1.4301 + mAdditionalSheets[aType].AppendObject(sheet); 1.4302 + sheet->SetOwningDocument(this); 1.4303 + MOZ_ASSERT(sheet->IsApplicable()); 1.4304 + 1.4305 + BeginUpdate(UPDATE_STYLE); 1.4306 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.4307 + if (shell) { 1.4308 + nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType); 1.4309 + shell->StyleSet()->AppendStyleSheet(type, sheet); 1.4310 + } 1.4311 + 1.4312 + // Passing false, so documet.styleSheets.length will not be affected by 1.4313 + // these additional sheets. 1.4314 + NotifyStyleSheetAdded(sheet, false); 1.4315 + EndUpdate(UPDATE_STYLE); 1.4316 + 1.4317 + return NS_OK; 1.4318 +} 1.4319 + 1.4320 +void 1.4321 +nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) 1.4322 +{ 1.4323 + MOZ_ASSERT(aSheetURI); 1.4324 + 1.4325 + nsCOMArray<nsIStyleSheet>& sheets = mAdditionalSheets[aType]; 1.4326 + 1.4327 + int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI); 1.4328 + if (i >= 0) { 1.4329 + nsCOMPtr<nsIStyleSheet> sheetRef = sheets[i]; 1.4330 + sheets.RemoveObjectAt(i); 1.4331 + 1.4332 + BeginUpdate(UPDATE_STYLE); 1.4333 + if (!mIsGoingAway) { 1.4334 + MOZ_ASSERT(sheetRef->IsApplicable()); 1.4335 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.4336 + if (shell) { 1.4337 + nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType); 1.4338 + shell->StyleSet()->RemoveStyleSheet(type, sheetRef); 1.4339 + } 1.4340 + } 1.4341 + 1.4342 + // Passing false, so documet.styleSheets.length will not be affected by 1.4343 + // these additional sheets. 1.4344 + NotifyStyleSheetRemoved(sheetRef, false); 1.4345 + EndUpdate(UPDATE_STYLE); 1.4346 + 1.4347 + sheetRef->SetOwningDocument(nullptr); 1.4348 + } 1.4349 +} 1.4350 + 1.4351 +nsIStyleSheet* 1.4352 +nsDocument::FirstAdditionalAuthorSheet() 1.4353 +{ 1.4354 + return mAdditionalSheets[eAuthorSheet].SafeObjectAt(0); 1.4355 +} 1.4356 + 1.4357 +nsIGlobalObject* 1.4358 +nsDocument::GetScopeObject() const 1.4359 +{ 1.4360 + nsCOMPtr<nsIGlobalObject> scope(do_QueryReferent(mScopeObject)); 1.4361 + return scope; 1.4362 +} 1.4363 + 1.4364 +void 1.4365 +nsDocument::SetScopeObject(nsIGlobalObject* aGlobal) 1.4366 +{ 1.4367 + mScopeObject = do_GetWeakReference(aGlobal); 1.4368 + if (aGlobal) { 1.4369 + mHasHadScriptHandlingObject = true; 1.4370 + } 1.4371 +} 1.4372 + 1.4373 +static void 1.4374 +NotifyActivityChanged(nsIContent *aContent, void *aUnused) 1.4375 +{ 1.4376 + nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent)); 1.4377 + if (domMediaElem) { 1.4378 + HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aContent); 1.4379 + mediaElem->NotifyOwnerDocumentActivityChanged(); 1.4380 + } 1.4381 + nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aContent)); 1.4382 + if (objectLoadingContent) { 1.4383 + nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get()); 1.4384 + olc->NotifyOwnerDocumentActivityChanged(); 1.4385 + } 1.4386 +} 1.4387 + 1.4388 +void 1.4389 +nsIDocument::SetContainer(nsDocShell* aContainer) 1.4390 +{ 1.4391 + if (aContainer) { 1.4392 + mDocumentContainer = aContainer->asWeakPtr(); 1.4393 + } else { 1.4394 + mDocumentContainer = WeakPtr<nsDocShell>(); 1.4395 + } 1.4396 + 1.4397 + EnumerateFreezableElements(NotifyActivityChanged, nullptr); 1.4398 + if (!aContainer) { 1.4399 + return; 1.4400 + } 1.4401 + 1.4402 + // Get the Docshell 1.4403 + if (aContainer->ItemType() == nsIDocShellTreeItem::typeContent) { 1.4404 + // check if same type root 1.4405 + nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot; 1.4406 + aContainer->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot)); 1.4407 + NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!"); 1.4408 + 1.4409 + if (sameTypeRoot == aContainer) { 1.4410 + static_cast<nsDocument*>(this)->SetIsTopLevelContentDocument(true); 1.4411 + } 1.4412 + } 1.4413 +} 1.4414 + 1.4415 +nsISupports* 1.4416 +nsIDocument::GetContainer() const 1.4417 +{ 1.4418 + return static_cast<nsIDocShell*>(mDocumentContainer); 1.4419 +} 1.4420 + 1.4421 +void 1.4422 +nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) 1.4423 +{ 1.4424 +#ifdef DEBUG 1.4425 + { 1.4426 + nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobalObject)); 1.4427 + 1.4428 + NS_ASSERTION(!win || win->IsInnerWindow(), 1.4429 + "Script global object must be an inner window!"); 1.4430 + } 1.4431 +#endif 1.4432 + NS_ABORT_IF_FALSE(aScriptGlobalObject || !mAnimationController || 1.4433 + mAnimationController->IsPausedByType( 1.4434 + nsSMILTimeContainer::PAUSE_PAGEHIDE | 1.4435 + nsSMILTimeContainer::PAUSE_BEGIN), 1.4436 + "Clearing window pointer while animations are unpaused"); 1.4437 + 1.4438 + if (mScriptGlobalObject && !aScriptGlobalObject) { 1.4439 + // We're detaching from the window. We need to grab a pointer to 1.4440 + // our layout history state now. 1.4441 + mLayoutHistoryState = GetLayoutHistoryState(); 1.4442 + 1.4443 + if (mPresShell && !EventHandlingSuppressed()) { 1.4444 + RevokeAnimationFrameNotifications(); 1.4445 + } 1.4446 + 1.4447 + // Also make sure to remove our onload blocker now if we haven't done it yet 1.4448 + if (mOnloadBlockCount != 0) { 1.4449 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.4450 + if (loadGroup) { 1.4451 + loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK); 1.4452 + } 1.4453 + } 1.4454 + } 1.4455 + 1.4456 + mScriptGlobalObject = aScriptGlobalObject; 1.4457 + 1.4458 + if (aScriptGlobalObject) { 1.4459 + mHasHadScriptHandlingObject = true; 1.4460 + mHasHadDefaultView = true; 1.4461 + // Go back to using the docshell for the layout history state 1.4462 + mLayoutHistoryState = nullptr; 1.4463 + mScopeObject = do_GetWeakReference(aScriptGlobalObject); 1.4464 +#ifdef DEBUG 1.4465 + if (!mWillReparent) { 1.4466 + // We really shouldn't have a wrapper here but if we do we need to make sure 1.4467 + // it has the correct parent. 1.4468 + JSObject *obj = GetWrapperPreserveColor(); 1.4469 + if (obj) { 1.4470 + JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject(); 1.4471 + NS_ASSERTION(js::GetGlobalForObjectCrossCompartment(obj) == newScope, 1.4472 + "Wrong scope, this is really bad!"); 1.4473 + } 1.4474 + } 1.4475 +#endif 1.4476 + 1.4477 + if (mAllowDNSPrefetch) { 1.4478 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.4479 + if (docShell) { 1.4480 +#ifdef DEBUG 1.4481 + nsCOMPtr<nsIWebNavigation> webNav = 1.4482 + do_GetInterface(aScriptGlobalObject); 1.4483 + NS_ASSERTION(SameCOMIdentity(webNav, docShell), 1.4484 + "Unexpected container or script global?"); 1.4485 +#endif 1.4486 + bool allowDNSPrefetch; 1.4487 + docShell->GetAllowDNSPrefetch(&allowDNSPrefetch); 1.4488 + mAllowDNSPrefetch = allowDNSPrefetch; 1.4489 + } 1.4490 + } 1.4491 + 1.4492 + MaybeRescheduleAnimationFrameNotifications(); 1.4493 + mRegistry = new Registry(); 1.4494 + } 1.4495 + 1.4496 + // Remember the pointer to our window (or lack there of), to avoid 1.4497 + // having to QI every time it's asked for. 1.4498 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobalObject); 1.4499 + mWindow = window; 1.4500 + 1.4501 + // Now that we know what our window is, we can flush the CSP errors to the 1.4502 + // Web Console. We are flushing all messages that occured and were stored 1.4503 + // in the queue prior to this point. 1.4504 + FlushCSPWebConsoleErrorQueue(); 1.4505 + nsCOMPtr<nsIHttpChannelInternal> internalChannel = 1.4506 + do_QueryInterface(GetChannel()); 1.4507 + if (internalChannel) { 1.4508 + nsCOMArray<nsISecurityConsoleMessage> messages; 1.4509 + internalChannel->TakeAllSecurityMessages(messages); 1.4510 + SendToConsole(messages); 1.4511 + } 1.4512 + 1.4513 + // Set our visibility state, but do not fire the event. This is correct 1.4514 + // because either we're coming out of bfcache (in which case IsVisible() will 1.4515 + // still test false at this point and no state change will happen) or we're 1.4516 + // doing the initial document load and don't want to fire the event for this 1.4517 + // change. 1.4518 + mVisibilityState = GetVisibilityState(); 1.4519 +} 1.4520 + 1.4521 +nsIScriptGlobalObject* 1.4522 +nsDocument::GetScriptHandlingObjectInternal() const 1.4523 +{ 1.4524 + MOZ_ASSERT(!mScriptGlobalObject, 1.4525 + "Do not call this when mScriptGlobalObject is set!"); 1.4526 + if (mHasHadDefaultView) { 1.4527 + return nullptr; 1.4528 + } 1.4529 + 1.4530 + nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject = 1.4531 + do_QueryReferent(mScopeObject); 1.4532 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptHandlingObject); 1.4533 + if (win) { 1.4534 + NS_ASSERTION(win->IsInnerWindow(), "Should have inner window here!"); 1.4535 + nsPIDOMWindow* outer = win->GetOuterWindow(); 1.4536 + if (!outer || outer->GetCurrentInnerWindow() != win) { 1.4537 + NS_WARNING("Wrong inner/outer window combination!"); 1.4538 + return nullptr; 1.4539 + } 1.4540 + } 1.4541 + return scriptHandlingObject; 1.4542 +} 1.4543 +void 1.4544 +nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject) 1.4545 +{ 1.4546 + NS_ASSERTION(!mScriptGlobalObject || 1.4547 + mScriptGlobalObject == aScriptObject, 1.4548 + "Wrong script object!"); 1.4549 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aScriptObject); 1.4550 + NS_ASSERTION(!win || win->IsInnerWindow(), "Should have inner window here!"); 1.4551 + if (aScriptObject) { 1.4552 + mScopeObject = do_GetWeakReference(aScriptObject); 1.4553 + mHasHadScriptHandlingObject = true; 1.4554 + mHasHadDefaultView = false; 1.4555 + } 1.4556 +} 1.4557 + 1.4558 +bool 1.4559 +nsDocument::IsTopLevelContentDocument() 1.4560 +{ 1.4561 + return mIsTopLevelContentDocument; 1.4562 +} 1.4563 + 1.4564 +void 1.4565 +nsDocument::SetIsTopLevelContentDocument(bool aIsTopLevelContentDocument) 1.4566 +{ 1.4567 + mIsTopLevelContentDocument = aIsTopLevelContentDocument; 1.4568 +} 1.4569 + 1.4570 +nsPIDOMWindow * 1.4571 +nsDocument::GetWindowInternal() const 1.4572 +{ 1.4573 + MOZ_ASSERT(!mWindow, "This should not be called when mWindow is not null!"); 1.4574 + // Let's use mScriptGlobalObject. Even if the document is already removed from 1.4575 + // the docshell, the outer window might be still obtainable from the it. 1.4576 + nsCOMPtr<nsPIDOMWindow> win; 1.4577 + if (mRemovedFromDocShell) { 1.4578 + nsCOMPtr<nsIInterfaceRequestor> requestor(mDocumentContainer); 1.4579 + if (requestor) { 1.4580 + // The docshell returns the outer window we are done. 1.4581 + win = do_GetInterface(requestor); 1.4582 + } 1.4583 + } else { 1.4584 + win = do_QueryInterface(mScriptGlobalObject); 1.4585 + if (win) { 1.4586 + // mScriptGlobalObject is always the inner window, let's get the outer. 1.4587 + win = win->GetOuterWindow(); 1.4588 + } 1.4589 + } 1.4590 + 1.4591 + return win; 1.4592 +} 1.4593 + 1.4594 +nsScriptLoader* 1.4595 +nsDocument::ScriptLoader() 1.4596 +{ 1.4597 + return mScriptLoader; 1.4598 +} 1.4599 + 1.4600 +bool 1.4601 +nsDocument::InternalAllowXULXBL() 1.4602 +{ 1.4603 + if (nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal())) { 1.4604 + mAllowXULXBL = eTriTrue; 1.4605 + return true; 1.4606 + } 1.4607 + 1.4608 + mAllowXULXBL = eTriFalse; 1.4609 + return false; 1.4610 +} 1.4611 + 1.4612 +// Note: We don't hold a reference to the document observer; we assume 1.4613 +// that it has a live reference to the document. 1.4614 +void 1.4615 +nsDocument::AddObserver(nsIDocumentObserver* aObserver) 1.4616 +{ 1.4617 + NS_ASSERTION(mObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex, 1.4618 + "Observer already in the list"); 1.4619 + mObservers.AppendElement(aObserver); 1.4620 + AddMutationObserver(aObserver); 1.4621 +} 1.4622 + 1.4623 +bool 1.4624 +nsDocument::RemoveObserver(nsIDocumentObserver* aObserver) 1.4625 +{ 1.4626 + // If we're in the process of destroying the document (and we're 1.4627 + // informing the observers of the destruction), don't remove the 1.4628 + // observers from the list. This is not a big deal, since we 1.4629 + // don't hold a live reference to the observers. 1.4630 + if (!mInDestructor) { 1.4631 + RemoveMutationObserver(aObserver); 1.4632 + return mObservers.RemoveElement(aObserver); 1.4633 + } 1.4634 + 1.4635 + return mObservers.Contains(aObserver); 1.4636 +} 1.4637 + 1.4638 +void 1.4639 +nsDocument::MaybeEndOutermostXBLUpdate() 1.4640 +{ 1.4641 + // Only call BindingManager()->EndOutermostUpdate() when 1.4642 + // we're not in an update and it is safe to run scripts. 1.4643 + if (mUpdateNestLevel == 0 && mInXBLUpdate) { 1.4644 + if (nsContentUtils::IsSafeToRunScript()) { 1.4645 + mInXBLUpdate = false; 1.4646 + BindingManager()->EndOutermostUpdate(); 1.4647 + } else if (!mInDestructor) { 1.4648 + nsContentUtils::AddScriptRunner( 1.4649 + NS_NewRunnableMethod(this, &nsDocument::MaybeEndOutermostXBLUpdate)); 1.4650 + } 1.4651 + } 1.4652 +} 1.4653 + 1.4654 +void 1.4655 +nsDocument::BeginUpdate(nsUpdateType aUpdateType) 1.4656 +{ 1.4657 + if (mUpdateNestLevel == 0 && !mInXBLUpdate) { 1.4658 + mInXBLUpdate = true; 1.4659 + BindingManager()->BeginOutermostUpdate(); 1.4660 + } 1.4661 + 1.4662 + ++mUpdateNestLevel; 1.4663 + nsContentUtils::AddScriptBlocker(); 1.4664 + NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, aUpdateType)); 1.4665 +} 1.4666 + 1.4667 +void 1.4668 +nsDocument::EndUpdate(nsUpdateType aUpdateType) 1.4669 +{ 1.4670 + NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, aUpdateType)); 1.4671 + 1.4672 + nsContentUtils::RemoveScriptBlocker(); 1.4673 + 1.4674 + --mUpdateNestLevel; 1.4675 + 1.4676 + // This set of updates may have created XBL bindings. Let the 1.4677 + // binding manager know we're done. 1.4678 + MaybeEndOutermostXBLUpdate(); 1.4679 + 1.4680 + MaybeInitializeFinalizeFrameLoaders(); 1.4681 +} 1.4682 + 1.4683 +void 1.4684 +nsDocument::BeginLoad() 1.4685 +{ 1.4686 + // Block onload here to prevent having to deal with blocking and 1.4687 + // unblocking it while we know the document is loading. 1.4688 + BlockOnload(); 1.4689 + mDidFireDOMContentLoaded = false; 1.4690 + BlockDOMContentLoaded(); 1.4691 + 1.4692 + if (mScriptLoader) { 1.4693 + mScriptLoader->BeginDeferringScripts(); 1.4694 + } 1.4695 + 1.4696 + NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this)); 1.4697 +} 1.4698 + 1.4699 +void 1.4700 +nsDocument::ReportEmptyGetElementByIdArg() 1.4701 +{ 1.4702 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.4703 + NS_LITERAL_CSTRING("DOM"), this, 1.4704 + nsContentUtils::eDOM_PROPERTIES, 1.4705 + "EmptyGetElementByIdParam"); 1.4706 +} 1.4707 + 1.4708 +Element* 1.4709 +nsDocument::GetElementById(const nsAString& aElementId) 1.4710 +{ 1.4711 + if (!CheckGetElementByIdArg(aElementId)) { 1.4712 + return nullptr; 1.4713 + } 1.4714 + 1.4715 + nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId); 1.4716 + return entry ? entry->GetIdElement() : nullptr; 1.4717 +} 1.4718 + 1.4719 +const nsSmallVoidArray* 1.4720 +nsDocument::GetAllElementsForId(const nsAString& aElementId) const 1.4721 +{ 1.4722 + if (aElementId.IsEmpty()) { 1.4723 + return nullptr; 1.4724 + } 1.4725 + 1.4726 + nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId); 1.4727 + return entry ? entry->GetIdElements() : nullptr; 1.4728 +} 1.4729 + 1.4730 +NS_IMETHODIMP 1.4731 +nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn) 1.4732 +{ 1.4733 + Element *content = GetElementById(aId); 1.4734 + if (content) { 1.4735 + return CallQueryInterface(content, aReturn); 1.4736 + } 1.4737 + 1.4738 + *aReturn = nullptr; 1.4739 + 1.4740 + return NS_OK; 1.4741 +} 1.4742 + 1.4743 +Element* 1.4744 +nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver, 1.4745 + void* aData, bool aForImage) 1.4746 +{ 1.4747 + nsDependentAtomString id(aID); 1.4748 + 1.4749 + if (!CheckGetElementByIdArg(id)) 1.4750 + return nullptr; 1.4751 + 1.4752 + nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(id); 1.4753 + NS_ENSURE_TRUE(entry, nullptr); 1.4754 + 1.4755 + entry->AddContentChangeCallback(aObserver, aData, aForImage); 1.4756 + return aForImage ? entry->GetImageIdElement() : entry->GetIdElement(); 1.4757 +} 1.4758 + 1.4759 +void 1.4760 +nsDocument::RemoveIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver, 1.4761 + void* aData, bool aForImage) 1.4762 +{ 1.4763 + nsDependentAtomString id(aID); 1.4764 + 1.4765 + if (!CheckGetElementByIdArg(id)) 1.4766 + return; 1.4767 + 1.4768 + nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(id); 1.4769 + if (!entry) { 1.4770 + return; 1.4771 + } 1.4772 + 1.4773 + entry->RemoveContentChangeCallback(aObserver, aData, aForImage); 1.4774 +} 1.4775 + 1.4776 +NS_IMETHODIMP 1.4777 +nsDocument::MozSetImageElement(const nsAString& aImageElementId, 1.4778 + nsIDOMElement* aImageElement) 1.4779 +{ 1.4780 + nsCOMPtr<Element> el = do_QueryInterface(aImageElement); 1.4781 + MozSetImageElement(aImageElementId, el); 1.4782 + return NS_OK; 1.4783 +} 1.4784 + 1.4785 +void 1.4786 +nsDocument::MozSetImageElement(const nsAString& aImageElementId, 1.4787 + Element* aElement) 1.4788 +{ 1.4789 + if (aImageElementId.IsEmpty()) 1.4790 + return; 1.4791 + 1.4792 + // Hold a script blocker while calling SetImageElement since that can call 1.4793 + // out to id-observers 1.4794 + nsAutoScriptBlocker scriptBlocker; 1.4795 + 1.4796 + nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aImageElementId); 1.4797 + if (entry) { 1.4798 + entry->SetImageElement(aElement); 1.4799 + if (entry->IsEmpty()) { 1.4800 + mIdentifierMap.RemoveEntry(aImageElementId); 1.4801 + } 1.4802 + } 1.4803 +} 1.4804 + 1.4805 +Element* 1.4806 +nsDocument::LookupImageElement(const nsAString& aId) 1.4807 +{ 1.4808 + if (aId.IsEmpty()) 1.4809 + return nullptr; 1.4810 + 1.4811 + nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId); 1.4812 + return entry ? entry->GetImageIdElement() : nullptr; 1.4813 +} 1.4814 + 1.4815 +void 1.4816 +nsDocument::DispatchContentLoadedEvents() 1.4817 +{ 1.4818 + // If you add early returns from this method, make sure you're 1.4819 + // calling UnblockOnload properly. 1.4820 + 1.4821 + // Unpin references to preloaded images 1.4822 + mPreloadingImages.Clear(); 1.4823 + 1.4824 + if (mTiming) { 1.4825 + mTiming->NotifyDOMContentLoadedStart(nsIDocument::GetDocumentURI()); 1.4826 + } 1.4827 + 1.4828 + // Dispatch observer notification to notify observers document is interactive. 1.4829 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.4830 + nsIPrincipal *principal = GetPrincipal(); 1.4831 + os->NotifyObservers(static_cast<nsIDocument*>(this), 1.4832 + nsContentUtils::IsSystemPrincipal(principal) ? 1.4833 + "chrome-document-interactive" : 1.4834 + "content-document-interactive", 1.4835 + nullptr); 1.4836 + 1.4837 + // Fire a DOM event notifying listeners that this document has been 1.4838 + // loaded (excluding images and other loads initiated by this 1.4839 + // document). 1.4840 + nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this), 1.4841 + NS_LITERAL_STRING("DOMContentLoaded"), 1.4842 + true, true); 1.4843 + 1.4844 + if (mTiming) { 1.4845 + mTiming->NotifyDOMContentLoadedEnd(nsIDocument::GetDocumentURI()); 1.4846 + } 1.4847 + 1.4848 + // If this document is a [i]frame, fire a DOMFrameContentLoaded 1.4849 + // event on all parent documents notifying that the HTML (excluding 1.4850 + // other external files such as images and stylesheets) in a frame 1.4851 + // has finished loading. 1.4852 + 1.4853 + // target_frame is the [i]frame element that will be used as the 1.4854 + // target for the event. It's the [i]frame whose content is done 1.4855 + // loading. 1.4856 + nsCOMPtr<EventTarget> target_frame; 1.4857 + 1.4858 + if (mParentDocument) { 1.4859 + target_frame = mParentDocument->FindContentForSubDocument(this); 1.4860 + } 1.4861 + 1.4862 + if (target_frame) { 1.4863 + nsCOMPtr<nsIDocument> parent = mParentDocument; 1.4864 + do { 1.4865 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(parent); 1.4866 + 1.4867 + nsCOMPtr<nsIDOMEvent> event; 1.4868 + if (domDoc) { 1.4869 + domDoc->CreateEvent(NS_LITERAL_STRING("Events"), 1.4870 + getter_AddRefs(event)); 1.4871 + 1.4872 + } 1.4873 + 1.4874 + if (event) { 1.4875 + event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), true, 1.4876 + true); 1.4877 + 1.4878 + event->SetTarget(target_frame); 1.4879 + event->SetTrusted(true); 1.4880 + 1.4881 + // To dispatch this event we must manually call 1.4882 + // EventDispatcher::Dispatch() on the ancestor document since the 1.4883 + // target is not in the same document, so the event would never reach 1.4884 + // the ancestor document if we used the normal event 1.4885 + // dispatching code. 1.4886 + 1.4887 + WidgetEvent* innerEvent = event->GetInternalNSEvent(); 1.4888 + if (innerEvent) { 1.4889 + nsEventStatus status = nsEventStatus_eIgnore; 1.4890 + 1.4891 + nsIPresShell *shell = parent->GetShell(); 1.4892 + if (shell) { 1.4893 + nsRefPtr<nsPresContext> context = shell->GetPresContext(); 1.4894 + 1.4895 + if (context) { 1.4896 + EventDispatcher::Dispatch(parent, context, innerEvent, event, 1.4897 + &status); 1.4898 + } 1.4899 + } 1.4900 + } 1.4901 + } 1.4902 + 1.4903 + parent = parent->GetParentDocument(); 1.4904 + } while (parent); 1.4905 + } 1.4906 + 1.4907 + // If the document has a manifest attribute, fire a MozApplicationManifest 1.4908 + // event. 1.4909 + Element* root = GetRootElement(); 1.4910 + if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) { 1.4911 + nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this), 1.4912 + NS_LITERAL_STRING("MozApplicationManifest"), 1.4913 + true, true); 1.4914 + } 1.4915 + 1.4916 + UnblockOnload(true); 1.4917 +} 1.4918 + 1.4919 +void 1.4920 +nsDocument::EndLoad() 1.4921 +{ 1.4922 + // Drop the ref to our parser, if any, but keep hold of the sink so that we 1.4923 + // can flush it from FlushPendingNotifications as needed. We might have to 1.4924 + // do that to get a StartLayout() to happen. 1.4925 + if (mParser) { 1.4926 + mWeakSink = do_GetWeakReference(mParser->GetContentSink()); 1.4927 + mParser = nullptr; 1.4928 + } 1.4929 + 1.4930 + NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this)); 1.4931 + 1.4932 + UnblockDOMContentLoaded(); 1.4933 +} 1.4934 + 1.4935 +void 1.4936 +nsDocument::UnblockDOMContentLoaded() 1.4937 +{ 1.4938 + MOZ_ASSERT(mBlockDOMContentLoaded); 1.4939 + if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) { 1.4940 + return; 1.4941 + } 1.4942 + mDidFireDOMContentLoaded = true; 1.4943 + 1.4944 + MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE); 1.4945 + if (!mSynchronousDOMContentLoaded) { 1.4946 + nsRefPtr<nsIRunnable> ev = 1.4947 + NS_NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents); 1.4948 + NS_DispatchToCurrentThread(ev); 1.4949 + } else { 1.4950 + DispatchContentLoadedEvents(); 1.4951 + } 1.4952 +} 1.4953 + 1.4954 +void 1.4955 +nsDocument::ContentStateChanged(nsIContent* aContent, EventStates aStateMask) 1.4956 +{ 1.4957 + NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(), 1.4958 + "Someone forgot a scriptblocker"); 1.4959 + NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged, 1.4960 + (this, aContent, aStateMask)); 1.4961 +} 1.4962 + 1.4963 +void 1.4964 +nsDocument::DocumentStatesChanged(EventStates aStateMask) 1.4965 +{ 1.4966 + // Invalidate our cached state. 1.4967 + mGotDocumentState &= ~aStateMask; 1.4968 + mDocumentState &= ~aStateMask; 1.4969 + 1.4970 + NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged, (this, aStateMask)); 1.4971 +} 1.4972 + 1.4973 +void 1.4974 +nsDocument::StyleRuleChanged(nsIStyleSheet* aSheet, 1.4975 + nsIStyleRule* aOldStyleRule, 1.4976 + nsIStyleRule* aNewStyleRule) 1.4977 +{ 1.4978 + NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, 1.4979 + (this, aSheet, 1.4980 + aOldStyleRule, aNewStyleRule)); 1.4981 + 1.4982 + if (StyleSheetChangeEventsEnabled()) { 1.4983 + nsCOMPtr<css::Rule> rule = do_QueryInterface(aNewStyleRule); 1.4984 + DO_STYLESHEET_NOTIFICATION(NS_NewDOMStyleRuleChangeEvent, 1.4985 + nsIDOMStyleRuleChangeEvent, 1.4986 + InitStyleRuleChangeEvent, 1.4987 + "StyleRuleChanged", 1.4988 + rule ? rule->GetDOMRule() : nullptr); 1.4989 + } 1.4990 +} 1.4991 + 1.4992 +void 1.4993 +nsDocument::StyleRuleAdded(nsIStyleSheet* aSheet, 1.4994 + nsIStyleRule* aStyleRule) 1.4995 +{ 1.4996 + NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, 1.4997 + (this, aSheet, aStyleRule)); 1.4998 + 1.4999 + if (StyleSheetChangeEventsEnabled()) { 1.5000 + nsCOMPtr<css::Rule> rule = do_QueryInterface(aStyleRule); 1.5001 + DO_STYLESHEET_NOTIFICATION(NS_NewDOMStyleRuleChangeEvent, 1.5002 + nsIDOMStyleRuleChangeEvent, 1.5003 + InitStyleRuleChangeEvent, 1.5004 + "StyleRuleAdded", 1.5005 + rule ? rule->GetDOMRule() : nullptr); 1.5006 + } 1.5007 +} 1.5008 + 1.5009 +void 1.5010 +nsDocument::StyleRuleRemoved(nsIStyleSheet* aSheet, 1.5011 + nsIStyleRule* aStyleRule) 1.5012 +{ 1.5013 + NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, 1.5014 + (this, aSheet, aStyleRule)); 1.5015 + 1.5016 + if (StyleSheetChangeEventsEnabled()) { 1.5017 + nsCOMPtr<css::Rule> rule = do_QueryInterface(aStyleRule); 1.5018 + DO_STYLESHEET_NOTIFICATION(NS_NewDOMStyleRuleChangeEvent, 1.5019 + nsIDOMStyleRuleChangeEvent, 1.5020 + InitStyleRuleChangeEvent, 1.5021 + "StyleRuleRemoved", 1.5022 + rule ? rule->GetDOMRule() : nullptr); 1.5023 + } 1.5024 +} 1.5025 + 1.5026 +#undef DO_STYLESHEET_NOTIFICATION 1.5027 + 1.5028 + 1.5029 +// 1.5030 +// nsIDOMDocument interface 1.5031 +// 1.5032 +DocumentType* 1.5033 +nsIDocument::GetDoctype() const 1.5034 +{ 1.5035 + for (nsIContent* child = GetFirstChild(); 1.5036 + child; 1.5037 + child = child->GetNextSibling()) { 1.5038 + if (child->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { 1.5039 + return static_cast<DocumentType*>(child); 1.5040 + } 1.5041 + } 1.5042 + return nullptr; 1.5043 +} 1.5044 + 1.5045 +NS_IMETHODIMP 1.5046 +nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype) 1.5047 +{ 1.5048 + MOZ_ASSERT(aDoctype); 1.5049 + nsCOMPtr<nsIDOMDocumentType> doctype = nsIDocument::GetDoctype(); 1.5050 + doctype.forget(aDoctype); 1.5051 + return NS_OK; 1.5052 +} 1.5053 + 1.5054 +NS_IMETHODIMP 1.5055 +nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation) 1.5056 +{ 1.5057 + ErrorResult rv; 1.5058 + *aImplementation = GetImplementation(rv); 1.5059 + if (rv.Failed()) { 1.5060 + MOZ_ASSERT(!*aImplementation); 1.5061 + return rv.ErrorCode(); 1.5062 + } 1.5063 + NS_ADDREF(*aImplementation); 1.5064 + return NS_OK; 1.5065 +} 1.5066 + 1.5067 +DOMImplementation* 1.5068 +nsDocument::GetImplementation(ErrorResult& rv) 1.5069 +{ 1.5070 + if (!mDOMImplementation) { 1.5071 + nsCOMPtr<nsIURI> uri; 1.5072 + NS_NewURI(getter_AddRefs(uri), "about:blank"); 1.5073 + if (!uri) { 1.5074 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.5075 + return nullptr; 1.5076 + } 1.5077 + bool hasHadScriptObject = true; 1.5078 + nsIScriptGlobalObject* scriptObject = 1.5079 + GetScriptHandlingObject(hasHadScriptObject); 1.5080 + if (!scriptObject && hasHadScriptObject) { 1.5081 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5082 + return nullptr; 1.5083 + } 1.5084 + mDOMImplementation = new DOMImplementation(this, 1.5085 + scriptObject ? scriptObject : GetScopeObject(), uri, uri); 1.5086 + } 1.5087 + 1.5088 + return mDOMImplementation; 1.5089 +} 1.5090 + 1.5091 +NS_IMETHODIMP 1.5092 +nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement) 1.5093 +{ 1.5094 + NS_ENSURE_ARG_POINTER(aDocumentElement); 1.5095 + 1.5096 + Element* root = GetRootElement(); 1.5097 + if (root) { 1.5098 + return CallQueryInterface(root, aDocumentElement); 1.5099 + } 1.5100 + 1.5101 + *aDocumentElement = nullptr; 1.5102 + 1.5103 + return NS_OK; 1.5104 +} 1.5105 + 1.5106 +NS_IMETHODIMP 1.5107 +nsDocument::CreateElement(const nsAString& aTagName, 1.5108 + nsIDOMElement** aReturn) 1.5109 +{ 1.5110 + *aReturn = nullptr; 1.5111 + ErrorResult rv; 1.5112 + nsCOMPtr<Element> element = nsIDocument::CreateElement(aTagName, rv); 1.5113 + NS_ENSURE_FALSE(rv.Failed(), rv.ErrorCode()); 1.5114 + return CallQueryInterface(element, aReturn); 1.5115 +} 1.5116 + 1.5117 +bool IsLowercaseASCII(const nsAString& aValue) 1.5118 +{ 1.5119 + int32_t len = aValue.Length(); 1.5120 + for (int32_t i = 0; i < len; ++i) { 1.5121 + char16_t c = aValue[i]; 1.5122 + if (!(0x0061 <= (c) && ((c) <= 0x007a))) { 1.5123 + return false; 1.5124 + } 1.5125 + } 1.5126 + return true; 1.5127 +} 1.5128 + 1.5129 +already_AddRefed<Element> 1.5130 +nsIDocument::CreateElement(const nsAString& aTagName, ErrorResult& rv) 1.5131 +{ 1.5132 + rv = nsContentUtils::CheckQName(aTagName, false); 1.5133 + if (rv.Failed()) { 1.5134 + return nullptr; 1.5135 + } 1.5136 + 1.5137 + bool needsLowercase = IsHTML() && !IsLowercaseASCII(aTagName); 1.5138 + nsAutoString lcTagName; 1.5139 + if (needsLowercase) { 1.5140 + nsContentUtils::ASCIIToLower(aTagName, lcTagName); 1.5141 + } 1.5142 + 1.5143 + nsCOMPtr<nsIContent> content; 1.5144 + rv = CreateElem(needsLowercase ? lcTagName : aTagName, 1.5145 + nullptr, mDefaultElementType, getter_AddRefs(content)); 1.5146 + if (rv.Failed()) { 1.5147 + return nullptr; 1.5148 + } 1.5149 + return dont_AddRef(content.forget().take()->AsElement()); 1.5150 +} 1.5151 + 1.5152 +void 1.5153 +nsDocument::SwizzleCustomElement(Element* aElement, 1.5154 + const nsAString& aTypeExtension, 1.5155 + uint32_t aNamespaceID, 1.5156 + ErrorResult& rv) 1.5157 +{ 1.5158 + nsCOMPtr<nsIAtom> typeAtom(do_GetAtom(aTypeExtension)); 1.5159 + nsCOMPtr<nsIAtom> tagAtom = aElement->Tag(); 1.5160 + if (!mRegistry || tagAtom == typeAtom) { 1.5161 + return; 1.5162 + } 1.5163 + 1.5164 + CustomElementDefinition* data; 1.5165 + CustomElementHashKey key(aNamespaceID, typeAtom); 1.5166 + if (!mRegistry->mCustomDefinitions.Get(&key, &data)) { 1.5167 + // The type extension doesn't exist in the registry, 1.5168 + // thus we don't need to swizzle, but it is possibly 1.5169 + // an upgrade candidate. 1.5170 + RegisterUnresolvedElement(aElement, typeAtom); 1.5171 + return; 1.5172 + } 1.5173 + 1.5174 + if (data->mLocalName != tagAtom) { 1.5175 + // The element doesn't match the local name for the 1.5176 + // definition, thus the element isn't a custom element 1.5177 + // and we don't need to do anything more. 1.5178 + return; 1.5179 + } 1.5180 + 1.5181 + if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::is)) { 1.5182 + // Swizzling in the parser happens after the "is" attribute is added. 1.5183 + aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, aTypeExtension, true); 1.5184 + } 1.5185 + 1.5186 + // Enqueuing the created callback will set the CustomElementData on the 1.5187 + // element, causing prototype swizzling to occur in Element::WrapObject. 1.5188 + EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data); 1.5189 +} 1.5190 + 1.5191 +already_AddRefed<Element> 1.5192 +nsDocument::CreateElement(const nsAString& aTagName, 1.5193 + const nsAString& aTypeExtension, 1.5194 + ErrorResult& rv) 1.5195 +{ 1.5196 + nsRefPtr<Element> elem = nsIDocument::CreateElement(aTagName, rv); 1.5197 + if (rv.Failed()) { 1.5198 + return nullptr; 1.5199 + } 1.5200 + 1.5201 + SwizzleCustomElement(elem, aTypeExtension, 1.5202 + GetDefaultNamespaceID(), rv); 1.5203 + if (rv.Failed()) { 1.5204 + return nullptr; 1.5205 + } 1.5206 + 1.5207 + return elem.forget(); 1.5208 +} 1.5209 + 1.5210 +NS_IMETHODIMP 1.5211 +nsDocument::CreateElementNS(const nsAString& aNamespaceURI, 1.5212 + const nsAString& aQualifiedName, 1.5213 + nsIDOMElement** aReturn) 1.5214 +{ 1.5215 + *aReturn = nullptr; 1.5216 + ErrorResult rv; 1.5217 + nsCOMPtr<Element> element = 1.5218 + nsIDocument::CreateElementNS(aNamespaceURI, aQualifiedName, rv); 1.5219 + NS_ENSURE_FALSE(rv.Failed(), rv.ErrorCode()); 1.5220 + return CallQueryInterface(element, aReturn); 1.5221 +} 1.5222 + 1.5223 +already_AddRefed<Element> 1.5224 +nsIDocument::CreateElementNS(const nsAString& aNamespaceURI, 1.5225 + const nsAString& aQualifiedName, 1.5226 + ErrorResult& rv) 1.5227 +{ 1.5228 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.5229 + rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, 1.5230 + aQualifiedName, 1.5231 + mNodeInfoManager, 1.5232 + nsIDOMNode::ELEMENT_NODE, 1.5233 + getter_AddRefs(nodeInfo)); 1.5234 + if (rv.Failed()) { 1.5235 + return nullptr; 1.5236 + } 1.5237 + 1.5238 + nsCOMPtr<Element> element; 1.5239 + rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), 1.5240 + NOT_FROM_PARSER); 1.5241 + if (rv.Failed()) { 1.5242 + return nullptr; 1.5243 + } 1.5244 + return element.forget(); 1.5245 +} 1.5246 + 1.5247 +already_AddRefed<Element> 1.5248 +nsDocument::CreateElementNS(const nsAString& aNamespaceURI, 1.5249 + const nsAString& aQualifiedName, 1.5250 + const nsAString& aTypeExtension, 1.5251 + ErrorResult& rv) 1.5252 +{ 1.5253 + nsRefPtr<Element> elem = nsIDocument::CreateElementNS(aNamespaceURI, 1.5254 + aQualifiedName, 1.5255 + rv); 1.5256 + if (rv.Failed()) { 1.5257 + return nullptr; 1.5258 + } 1.5259 + 1.5260 + int32_t nameSpaceId = kNameSpaceID_Wildcard; 1.5261 + if (!aNamespaceURI.EqualsLiteral("*")) { 1.5262 + rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, 1.5263 + nameSpaceId); 1.5264 + if (rv.Failed()) { 1.5265 + return nullptr; 1.5266 + } 1.5267 + } 1.5268 + 1.5269 + SwizzleCustomElement(elem, aTypeExtension, nameSpaceId, rv); 1.5270 + if (rv.Failed()) { 1.5271 + return nullptr; 1.5272 + } 1.5273 + 1.5274 + return elem.forget(); 1.5275 +} 1.5276 + 1.5277 +NS_IMETHODIMP 1.5278 +nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn) 1.5279 +{ 1.5280 + *aReturn = nsIDocument::CreateTextNode(aData).take(); 1.5281 + return NS_OK; 1.5282 +} 1.5283 + 1.5284 +already_AddRefed<nsTextNode> 1.5285 +nsIDocument::CreateTextNode(const nsAString& aData) const 1.5286 +{ 1.5287 + nsRefPtr<nsTextNode> text = new nsTextNode(mNodeInfoManager); 1.5288 + // Don't notify; this node is still being created. 1.5289 + text->SetText(aData, false); 1.5290 + return text.forget(); 1.5291 +} 1.5292 + 1.5293 +NS_IMETHODIMP 1.5294 +nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn) 1.5295 +{ 1.5296 + *aReturn = nsIDocument::CreateDocumentFragment().take(); 1.5297 + return NS_OK; 1.5298 +} 1.5299 + 1.5300 +already_AddRefed<DocumentFragment> 1.5301 +nsIDocument::CreateDocumentFragment() const 1.5302 +{ 1.5303 + nsRefPtr<DocumentFragment> frag = new DocumentFragment(mNodeInfoManager); 1.5304 + return frag.forget(); 1.5305 +} 1.5306 + 1.5307 +NS_IMETHODIMP 1.5308 +nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn) 1.5309 +{ 1.5310 + *aReturn = nsIDocument::CreateComment(aData).take(); 1.5311 + return NS_OK; 1.5312 +} 1.5313 + 1.5314 +// Unfortunately, bareword "Comment" is ambiguous with some Mac system headers. 1.5315 +already_AddRefed<dom::Comment> 1.5316 +nsIDocument::CreateComment(const nsAString& aData) const 1.5317 +{ 1.5318 + nsRefPtr<dom::Comment> comment = new dom::Comment(mNodeInfoManager); 1.5319 + 1.5320 + // Don't notify; this node is still being created. 1.5321 + comment->SetText(aData, false); 1.5322 + return comment.forget(); 1.5323 +} 1.5324 + 1.5325 +NS_IMETHODIMP 1.5326 +nsDocument::CreateCDATASection(const nsAString& aData, 1.5327 + nsIDOMCDATASection** aReturn) 1.5328 +{ 1.5329 + NS_ENSURE_ARG_POINTER(aReturn); 1.5330 + ErrorResult rv; 1.5331 + *aReturn = nsIDocument::CreateCDATASection(aData, rv).take(); 1.5332 + return rv.ErrorCode(); 1.5333 +} 1.5334 + 1.5335 +already_AddRefed<CDATASection> 1.5336 +nsIDocument::CreateCDATASection(const nsAString& aData, 1.5337 + ErrorResult& rv) 1.5338 +{ 1.5339 + if (IsHTML()) { 1.5340 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.5341 + return nullptr; 1.5342 + } 1.5343 + 1.5344 + if (FindInReadable(NS_LITERAL_STRING("]]>"), aData)) { 1.5345 + rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR); 1.5346 + return nullptr; 1.5347 + } 1.5348 + 1.5349 + nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager); 1.5350 + 1.5351 + // Don't notify; this node is still being created. 1.5352 + cdata->SetText(aData, false); 1.5353 + 1.5354 + return cdata.forget(); 1.5355 +} 1.5356 + 1.5357 +NS_IMETHODIMP 1.5358 +nsDocument::CreateProcessingInstruction(const nsAString& aTarget, 1.5359 + const nsAString& aData, 1.5360 + nsIDOMProcessingInstruction** aReturn) 1.5361 +{ 1.5362 + ErrorResult rv; 1.5363 + *aReturn = 1.5364 + nsIDocument::CreateProcessingInstruction(aTarget, aData, rv).take(); 1.5365 + return rv.ErrorCode(); 1.5366 +} 1.5367 + 1.5368 +already_AddRefed<ProcessingInstruction> 1.5369 +nsIDocument::CreateProcessingInstruction(const nsAString& aTarget, 1.5370 + const nsAString& aData, 1.5371 + ErrorResult& rv) const 1.5372 +{ 1.5373 + nsresult res = nsContentUtils::CheckQName(aTarget, false); 1.5374 + if (NS_FAILED(res)) { 1.5375 + rv.Throw(res); 1.5376 + return nullptr; 1.5377 + } 1.5378 + 1.5379 + if (FindInReadable(NS_LITERAL_STRING("?>"), aData)) { 1.5380 + rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR); 1.5381 + return nullptr; 1.5382 + } 1.5383 + 1.5384 + nsRefPtr<ProcessingInstruction> pi = 1.5385 + NS_NewXMLProcessingInstruction(mNodeInfoManager, aTarget, aData); 1.5386 + 1.5387 + return pi.forget(); 1.5388 +} 1.5389 + 1.5390 +NS_IMETHODIMP 1.5391 +nsDocument::CreateAttribute(const nsAString& aName, 1.5392 + nsIDOMAttr** aReturn) 1.5393 +{ 1.5394 + ErrorResult rv; 1.5395 + *aReturn = nsIDocument::CreateAttribute(aName, rv).take(); 1.5396 + return rv.ErrorCode(); 1.5397 +} 1.5398 + 1.5399 +already_AddRefed<Attr> 1.5400 +nsIDocument::CreateAttribute(const nsAString& aName, ErrorResult& rv) 1.5401 +{ 1.5402 + WarnOnceAbout(eCreateAttribute); 1.5403 + 1.5404 + if (!mNodeInfoManager) { 1.5405 + rv.Throw(NS_ERROR_NOT_INITIALIZED); 1.5406 + return nullptr; 1.5407 + } 1.5408 + 1.5409 + nsresult res = nsContentUtils::CheckQName(aName, false); 1.5410 + if (NS_FAILED(res)) { 1.5411 + rv.Throw(res); 1.5412 + return nullptr; 1.5413 + } 1.5414 + 1.5415 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.5416 + res = mNodeInfoManager->GetNodeInfo(aName, nullptr, kNameSpaceID_None, 1.5417 + nsIDOMNode::ATTRIBUTE_NODE, 1.5418 + getter_AddRefs(nodeInfo)); 1.5419 + if (NS_FAILED(res)) { 1.5420 + rv.Throw(res); 1.5421 + return nullptr; 1.5422 + } 1.5423 + 1.5424 + nsRefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(), 1.5425 + EmptyString(), false); 1.5426 + return attribute.forget(); 1.5427 +} 1.5428 + 1.5429 +NS_IMETHODIMP 1.5430 +nsDocument::CreateAttributeNS(const nsAString & aNamespaceURI, 1.5431 + const nsAString & aQualifiedName, 1.5432 + nsIDOMAttr **aResult) 1.5433 +{ 1.5434 + ErrorResult rv; 1.5435 + *aResult = 1.5436 + nsIDocument::CreateAttributeNS(aNamespaceURI, aQualifiedName, rv).take(); 1.5437 + return rv.ErrorCode(); 1.5438 +} 1.5439 + 1.5440 +already_AddRefed<Attr> 1.5441 +nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI, 1.5442 + const nsAString& aQualifiedName, 1.5443 + ErrorResult& rv) 1.5444 +{ 1.5445 + WarnOnceAbout(eCreateAttributeNS); 1.5446 + 1.5447 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.5448 + rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, 1.5449 + aQualifiedName, 1.5450 + mNodeInfoManager, 1.5451 + nsIDOMNode::ATTRIBUTE_NODE, 1.5452 + getter_AddRefs(nodeInfo)); 1.5453 + if (rv.Failed()) { 1.5454 + return nullptr; 1.5455 + } 1.5456 + 1.5457 + nsRefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(), 1.5458 + EmptyString(), true); 1.5459 + return attribute.forget(); 1.5460 +} 1.5461 + 1.5462 +bool 1.5463 +nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp) 1.5464 +{ 1.5465 + JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp); 1.5466 + 1.5467 + JS::Rooted<JSObject*> global(aCx, 1.5468 + JS_GetGlobalForObject(aCx, &args.callee())); 1.5469 + nsCOMPtr<nsPIDOMWindow> window = do_QueryWrapper(aCx, global); 1.5470 + MOZ_ASSERT(window, "Should have a non-null window"); 1.5471 + 1.5472 + nsDocument* document = static_cast<nsDocument*>(window->GetDoc()); 1.5473 + 1.5474 + // Function name is the type of the custom element. 1.5475 + JSString* jsFunName = 1.5476 + JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev())); 1.5477 + nsDependentJSString elemName; 1.5478 + if (!elemName.init(aCx, jsFunName)) { 1.5479 + return true; 1.5480 + } 1.5481 + 1.5482 + nsCOMPtr<nsIAtom> typeAtom(do_GetAtom(elemName)); 1.5483 + CustomElementHashKey key(kNameSpaceID_Unknown, typeAtom); 1.5484 + CustomElementDefinition* definition; 1.5485 + if (!document->mRegistry || 1.5486 + !document->mRegistry->mCustomDefinitions.Get(&key, &definition)) { 1.5487 + return true; 1.5488 + } 1.5489 + 1.5490 + nsDependentAtomString localName(definition->mLocalName); 1.5491 + 1.5492 + nsCOMPtr<nsIContent> newElement; 1.5493 + nsresult rv = document->CreateElem(localName, nullptr, 1.5494 + definition->mNamespaceID, 1.5495 + getter_AddRefs(newElement)); 1.5496 + NS_ENSURE_SUCCESS(rv, true); 1.5497 + 1.5498 + ErrorResult errorResult; 1.5499 + nsCOMPtr<Element> element = do_QueryInterface(newElement); 1.5500 + document->SwizzleCustomElement(element, elemName, definition->mNamespaceID, 1.5501 + errorResult); 1.5502 + if (errorResult.Failed()) { 1.5503 + return true; 1.5504 + } 1.5505 + 1.5506 + rv = nsContentUtils::WrapNative(aCx, newElement, newElement, args.rval()); 1.5507 + NS_ENSURE_SUCCESS(rv, true); 1.5508 + 1.5509 + return true; 1.5510 +} 1.5511 + 1.5512 +bool 1.5513 +nsDocument::IsRegisterElementEnabled(JSContext* aCx, JSObject* aObject) 1.5514 +{ 1.5515 + JS::Rooted<JSObject*> obj(aCx, aObject); 1.5516 + return Preferences::GetBool("dom.webcomponents.enabled") || 1.5517 + IsInCertifiedApp(aCx, obj); 1.5518 +} 1.5519 + 1.5520 +nsresult 1.5521 +nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName) 1.5522 +{ 1.5523 + if (!mRegistry) { 1.5524 + return NS_OK; 1.5525 + } 1.5526 + 1.5527 + nsINodeInfo* info = aElement->NodeInfo(); 1.5528 + 1.5529 + // Candidate may be a custom element through extension, 1.5530 + // in which case the custom element type name will not 1.5531 + // match the element tag name. e.g. <button is="x-button">. 1.5532 + nsCOMPtr<nsIAtom> typeName = aTypeName; 1.5533 + if (!typeName) { 1.5534 + typeName = info->NameAtom(); 1.5535 + } 1.5536 + 1.5537 + CustomElementHashKey key(info->NamespaceID(), typeName); 1.5538 + if (mRegistry->mCustomDefinitions.Get(&key)) { 1.5539 + return NS_OK; 1.5540 + } 1.5541 + 1.5542 + nsTArray<nsRefPtr<Element>>* unresolved; 1.5543 + mRegistry->mCandidatesMap.Get(&key, &unresolved); 1.5544 + if (!unresolved) { 1.5545 + unresolved = new nsTArray<nsRefPtr<Element>>(); 1.5546 + // Ownership of unresolved is taken by mCandidatesMap. 1.5547 + mRegistry->mCandidatesMap.Put(&key, unresolved); 1.5548 + } 1.5549 + 1.5550 + nsRefPtr<Element>* elem = unresolved->AppendElement(); 1.5551 + *elem = aElement; 1.5552 + 1.5553 + return NS_OK; 1.5554 +} 1.5555 + 1.5556 +namespace { 1.5557 + 1.5558 +class ProcessStackRunner MOZ_FINAL : public nsIRunnable 1.5559 +{ 1.5560 + public: 1.5561 + ProcessStackRunner(bool aIsBaseQueue = false) 1.5562 + : mIsBaseQueue(aIsBaseQueue) 1.5563 + { 1.5564 + } 1.5565 + NS_DECL_ISUPPORTS 1.5566 + NS_IMETHOD Run() MOZ_OVERRIDE 1.5567 + { 1.5568 + nsDocument::ProcessTopElementQueue(mIsBaseQueue); 1.5569 + return NS_OK; 1.5570 + } 1.5571 + bool mIsBaseQueue; 1.5572 +}; 1.5573 + 1.5574 +NS_IMPL_ISUPPORTS(ProcessStackRunner, nsIRunnable); 1.5575 + 1.5576 +} // anonymous namespace 1.5577 + 1.5578 +void 1.5579 +nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, 1.5580 + Element* aCustomElement, 1.5581 + LifecycleCallbackArgs* aArgs, 1.5582 + CustomElementDefinition* aDefinition) 1.5583 +{ 1.5584 + if (!mRegistry) { 1.5585 + // The element might not belong to a document that 1.5586 + // has a browsing context, and thus no registry. 1.5587 + return; 1.5588 + } 1.5589 + 1.5590 + CustomElementData* elementData = aCustomElement->GetCustomElementData(); 1.5591 + 1.5592 + // Let DEFINITION be ELEMENT's definition 1.5593 + CustomElementDefinition* definition = aDefinition; 1.5594 + if (!definition) { 1.5595 + nsINodeInfo* info = aCustomElement->NodeInfo(); 1.5596 + 1.5597 + // Make sure we get the correct definition in case the element 1.5598 + // is a extended custom element e.g. <button is="x-button">. 1.5599 + nsCOMPtr<nsIAtom> typeAtom = elementData ? 1.5600 + elementData->mType.get() : info->NameAtom(); 1.5601 + 1.5602 + CustomElementHashKey key(info->NamespaceID(), typeAtom); 1.5603 + if (!mRegistry->mCustomDefinitions.Get(&key, &definition) || 1.5604 + definition->mLocalName != info->NameAtom()) { 1.5605 + // Trying to enqueue a callback for an element that is not 1.5606 + // a custom element. We are done, nothing to do. 1.5607 + return; 1.5608 + } 1.5609 + } 1.5610 + 1.5611 + if (!elementData) { 1.5612 + // Create the custom element data the first time 1.5613 + // that we try to enqueue a callback. 1.5614 + elementData = new CustomElementData(definition->mType); 1.5615 + // aCustomElement takes ownership of elementData 1.5616 + aCustomElement->SetCustomElementData(elementData); 1.5617 + MOZ_ASSERT(aType == nsIDocument::eCreated, 1.5618 + "First callback should be the created callback"); 1.5619 + } 1.5620 + 1.5621 + // Let CALLBACK be the callback associated with the key NAME in CALLBACKS. 1.5622 + CallbackFunction* func = nullptr; 1.5623 + switch (aType) { 1.5624 + case nsIDocument::eCreated: 1.5625 + if (definition->mCallbacks->mCreatedCallback.WasPassed()) { 1.5626 + func = definition->mCallbacks->mCreatedCallback.Value(); 1.5627 + } 1.5628 + break; 1.5629 + 1.5630 + case nsIDocument::eAttached: 1.5631 + if (definition->mCallbacks->mAttachedCallback.WasPassed()) { 1.5632 + func = definition->mCallbacks->mAttachedCallback.Value(); 1.5633 + } 1.5634 + break; 1.5635 + 1.5636 + case nsIDocument::eDetached: 1.5637 + if (definition->mCallbacks->mDetachedCallback.WasPassed()) { 1.5638 + func = definition->mCallbacks->mDetachedCallback.Value(); 1.5639 + } 1.5640 + break; 1.5641 + 1.5642 + case nsIDocument::eAttributeChanged: 1.5643 + if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) { 1.5644 + func = definition->mCallbacks->mAttributeChangedCallback.Value(); 1.5645 + } 1.5646 + break; 1.5647 + } 1.5648 + 1.5649 + // If there is no such callback, stop. 1.5650 + if (!func) { 1.5651 + return; 1.5652 + } 1.5653 + 1.5654 + if (aType == nsIDocument::eCreated) { 1.5655 + elementData->mCreatedCallbackInvoked = false; 1.5656 + } else if (!elementData->mCreatedCallbackInvoked) { 1.5657 + // Callbacks other than created callback must not be enqueued 1.5658 + // until after the created callback has been invoked. 1.5659 + return; 1.5660 + } 1.5661 + 1.5662 + // Add CALLBACK to ELEMENT's callback queue. 1.5663 + CustomElementCallback* callback = new CustomElementCallback(aCustomElement, 1.5664 + aType, 1.5665 + func, 1.5666 + elementData); 1.5667 + // Ownership of callback is taken by mCallbackQueue. 1.5668 + elementData->mCallbackQueue.AppendElement(callback); 1.5669 + if (aArgs) { 1.5670 + callback->SetArgs(*aArgs); 1.5671 + } 1.5672 + 1.5673 + if (!elementData->mElementIsBeingCreated) { 1.5674 + CustomElementData* lastData = 1.5675 + sProcessingStack.ref().SafeLastElement(nullptr); 1.5676 + 1.5677 + // A new element queue needs to be pushed if the queue at the 1.5678 + // top of the stack is associated with another microtask level. 1.5679 + // Don't push a queue for the level 0 microtask (base element queue) 1.5680 + // because we don't want to process the queue until the 1.5681 + // microtask checkpoint. 1.5682 + bool shouldPushElementQueue = nsContentUtils::MicroTaskLevel() > 0 && 1.5683 + (!lastData || lastData->mAssociatedMicroTask < 1.5684 + static_cast<int32_t>(nsContentUtils::MicroTaskLevel())); 1.5685 + 1.5686 + // Push a new element queue onto the processing stack when appropriate 1.5687 + // (when we enter a new microtask). 1.5688 + if (shouldPushElementQueue) { 1.5689 + // Push a sentinel value on the processing stack to mark the 1.5690 + // boundary between the element queues. 1.5691 + sProcessingStack.ref().AppendElement((CustomElementData*) nullptr); 1.5692 + } 1.5693 + 1.5694 + sProcessingStack.ref().AppendElement(elementData); 1.5695 + elementData->mAssociatedMicroTask = 1.5696 + static_cast<int32_t>(nsContentUtils::MicroTaskLevel()); 1.5697 + 1.5698 + // Add a script runner to pop and process the element queue at 1.5699 + // the top of the processing stack. 1.5700 + if (shouldPushElementQueue) { 1.5701 + // Lifecycle callbacks enqueued by user agent implementation 1.5702 + // should be invoked prior to returning control back to script. 1.5703 + // Create a script runner to process the top of the processing 1.5704 + // stack as soon as it is safe to run script. 1.5705 + nsContentUtils::AddScriptRunner(new ProcessStackRunner()); 1.5706 + } 1.5707 + } 1.5708 +} 1.5709 + 1.5710 +// static 1.5711 +void 1.5712 +nsDocument::ProcessBaseElementQueue() 1.5713 +{ 1.5714 + // Prevent re-entrance. Also, if a microtask checkpoint is reached 1.5715 + // and there is no processing stack to process, then we are done. 1.5716 + if (sProcessingBaseElementQueue || sProcessingStack.empty()) { 1.5717 + return; 1.5718 + } 1.5719 + 1.5720 + MOZ_ASSERT(nsContentUtils::MicroTaskLevel() == 0); 1.5721 + sProcessingBaseElementQueue = true; 1.5722 + nsContentUtils::AddScriptRunner(new ProcessStackRunner(true)); 1.5723 +} 1.5724 + 1.5725 +// static 1.5726 +void 1.5727 +nsDocument::ProcessTopElementQueue(bool aIsBaseQueue) 1.5728 +{ 1.5729 + MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); 1.5730 + 1.5731 + nsTArray<CustomElementData*>& stack = sProcessingStack.ref(); 1.5732 + uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr); 1.5733 + 1.5734 + if (aIsBaseQueue && firstQueue != 0) { 1.5735 + return; 1.5736 + } 1.5737 + 1.5738 + for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) { 1.5739 + // Callback queue may have already been processed in an earlier 1.5740 + // element queue or in an element queue that was popped 1.5741 + // off more recently. 1.5742 + if (stack[i]->mAssociatedMicroTask != -1) { 1.5743 + stack[i]->RunCallbackQueue(); 1.5744 + stack[i]->mAssociatedMicroTask = -1; 1.5745 + } 1.5746 + } 1.5747 + 1.5748 + // If this was actually the base element queue, don't bother trying to pop 1.5749 + // the first "queue" marker (sentinel). 1.5750 + if (firstQueue != 0) { 1.5751 + stack.SetLength(firstQueue); 1.5752 + } else { 1.5753 + // Don't pop sentinel for base element queue. 1.5754 + stack.SetLength(1); 1.5755 + sProcessingBaseElementQueue = false; 1.5756 + } 1.5757 +} 1.5758 + 1.5759 +bool 1.5760 +nsDocument::RegisterEnabled() 1.5761 +{ 1.5762 + static bool sPrefValue = 1.5763 + Preferences::GetBool("dom.webcomponents.enabled", false); 1.5764 + return sPrefValue; 1.5765 +} 1.5766 + 1.5767 +// static 1.5768 +Maybe<nsTArray<mozilla::dom::CustomElementData*>> 1.5769 +nsDocument::sProcessingStack; 1.5770 + 1.5771 +// static 1.5772 +bool 1.5773 +nsDocument::sProcessingBaseElementQueue; 1.5774 + 1.5775 +void 1.5776 +nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType, 1.5777 + const ElementRegistrationOptions& aOptions, 1.5778 + JS::MutableHandle<JSObject*> aRetval, 1.5779 + ErrorResult& rv) 1.5780 +{ 1.5781 + if (!mRegistry) { 1.5782 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.5783 + return; 1.5784 + } 1.5785 + 1.5786 + Registry::DefinitionMap& definitions = mRegistry->mCustomDefinitions; 1.5787 + 1.5788 + // Unconditionally convert TYPE to lowercase. 1.5789 + nsAutoString lcType; 1.5790 + nsContentUtils::ASCIIToLower(aType, lcType); 1.5791 + 1.5792 + // Only convert NAME to lowercase in HTML documents. Note that NAME is 1.5793 + // options.extends. 1.5794 + nsAutoString lcName; 1.5795 + if (IsHTML()) { 1.5796 + nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName); 1.5797 + } else { 1.5798 + lcName.Assign(aOptions.mExtends); 1.5799 + } 1.5800 + 1.5801 + nsCOMPtr<nsIAtom> typeAtom(do_GetAtom(lcType)); 1.5802 + if (!nsContentUtils::IsCustomElementName(typeAtom)) { 1.5803 + rv.Throw(NS_ERROR_DOM_SYNTAX_ERR); 1.5804 + return; 1.5805 + } 1.5806 + 1.5807 + // If there already exists a definition with the same TYPE, set ERROR to 1.5808 + // DuplicateDefinition and stop. 1.5809 + // Note that we need to find existing custom elements from either namespace. 1.5810 + CustomElementHashKey duplicateFinder(kNameSpaceID_Unknown, typeAtom); 1.5811 + if (definitions.Get(&duplicateFinder)) { 1.5812 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.5813 + return; 1.5814 + } 1.5815 + 1.5816 + nsIGlobalObject* sgo = GetScopeObject(); 1.5817 + if (!sgo) { 1.5818 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5819 + return; 1.5820 + } 1.5821 + JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject()); 1.5822 + 1.5823 + JSAutoCompartment ac(aCx, global); 1.5824 + 1.5825 + JS::Handle<JSObject*> htmlProto( 1.5826 + HTMLElementBinding::GetProtoObject(aCx, global)); 1.5827 + if (!htmlProto) { 1.5828 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.5829 + return; 1.5830 + } 1.5831 + 1.5832 + int32_t namespaceID = kNameSpaceID_XHTML; 1.5833 + JS::Rooted<JSObject*> protoObject(aCx); 1.5834 + if (!aOptions.mPrototype) { 1.5835 + protoObject = JS_NewObject(aCx, nullptr, htmlProto, JS::NullPtr()); 1.5836 + if (!protoObject) { 1.5837 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5838 + return; 1.5839 + } 1.5840 + } else { 1.5841 + // If a prototype is provided, we must check to ensure that it is from the 1.5842 + // same browsing context as us. 1.5843 + protoObject = aOptions.mPrototype; 1.5844 + if (JS_GetGlobalForObject(aCx, protoObject) != global) { 1.5845 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.5846 + return; 1.5847 + } 1.5848 + 1.5849 + // If PROTOTYPE is already an interface prototype object for any interface 1.5850 + // object or PROTOTYPE has a non-configurable property named constructor, 1.5851 + // throw a NotSupportedError and stop. 1.5852 + const js::Class* clasp = js::GetObjectClass(protoObject); 1.5853 + if (IsDOMIfaceAndProtoClass(clasp)) { 1.5854 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.5855 + return; 1.5856 + } 1.5857 + 1.5858 + JS::Rooted<JSPropertyDescriptor> descRoot(aCx); 1.5859 + JS::MutableHandle<JSPropertyDescriptor> desc(&descRoot); 1.5860 + if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) { 1.5861 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5862 + return; 1.5863 + } 1.5864 + 1.5865 + // Check if non-configurable 1.5866 + if (desc.isPermanent()) { 1.5867 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.5868 + return; 1.5869 + } 1.5870 + 1.5871 + JS::Handle<JSObject*> svgProto( 1.5872 + SVGElementBinding::GetProtoObject(aCx, global)); 1.5873 + if (!svgProto) { 1.5874 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.5875 + return; 1.5876 + } 1.5877 + 1.5878 + JS::Rooted<JSObject*> protoProto(aCx, protoObject); 1.5879 + 1.5880 + // If PROTOTYPE's interface inherits from SVGElement, set NAMESPACE to SVG 1.5881 + // Namespace. 1.5882 + while (protoProto) { 1.5883 + if (protoProto == htmlProto) { 1.5884 + break; 1.5885 + } 1.5886 + 1.5887 + if (protoProto == svgProto) { 1.5888 + namespaceID = kNameSpaceID_SVG; 1.5889 + break; 1.5890 + } 1.5891 + 1.5892 + if (!JS_GetPrototype(aCx, protoProto, &protoProto)) { 1.5893 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5894 + return; 1.5895 + } 1.5896 + } 1.5897 + } 1.5898 + 1.5899 + // If name was provided and not null... 1.5900 + nsCOMPtr<nsIAtom> nameAtom; 1.5901 + if (!lcName.IsEmpty()) { 1.5902 + // Let BASE be the element interface for NAME and NAMESPACE. 1.5903 + bool known = false; 1.5904 + nameAtom = do_GetAtom(lcName); 1.5905 + if (namespaceID == kNameSpaceID_XHTML) { 1.5906 + nsIParserService* ps = nsContentUtils::GetParserService(); 1.5907 + if (!ps) { 1.5908 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5909 + return; 1.5910 + } 1.5911 + 1.5912 + known = 1.5913 + ps->HTMLCaseSensitiveAtomTagToId(nameAtom) != eHTMLTag_userdefined; 1.5914 + } else { 1.5915 + known = SVGElementFactory::Exists(nameAtom); 1.5916 + } 1.5917 + 1.5918 + // If BASE does not exist or is an interface for a custom element, set ERROR 1.5919 + // to InvalidName and stop. 1.5920 + // If BASE exists, then it cannot be an interface for a custom element. 1.5921 + if (!known) { 1.5922 + rv.Throw(NS_ERROR_DOM_SYNTAX_ERR); 1.5923 + return; 1.5924 + } 1.5925 + } else { 1.5926 + // If NAMESPACE is SVG Namespace, set ERROR to InvalidName and stop. 1.5927 + if (namespaceID == kNameSpaceID_SVG) { 1.5928 + rv.Throw(NS_ERROR_UNEXPECTED); 1.5929 + return; 1.5930 + } 1.5931 + 1.5932 + nameAtom = typeAtom; 1.5933 + } 1.5934 + 1.5935 + nsAutoPtr<LifecycleCallbacks> callbacksHolder(new LifecycleCallbacks()); 1.5936 + JS::RootedValue rootedv(aCx, JS::ObjectValue(*protoObject)); 1.5937 + if (!callbacksHolder->Init(aCx, rootedv)) { 1.5938 + rv.Throw(NS_ERROR_FAILURE); 1.5939 + return; 1.5940 + } 1.5941 + 1.5942 + // Associate the definition with the custom element. 1.5943 + CustomElementHashKey key(namespaceID, typeAtom); 1.5944 + LifecycleCallbacks* callbacks = callbacksHolder.forget(); 1.5945 + CustomElementDefinition* definition = 1.5946 + new CustomElementDefinition(protoObject, 1.5947 + typeAtom, 1.5948 + nameAtom, 1.5949 + callbacks, 1.5950 + namespaceID, 1.5951 + 0 /* TODO dependent on HTML imports. Bug 877072 */); 1.5952 + definitions.Put(&key, definition); 1.5953 + 1.5954 + // Do element upgrade. 1.5955 + nsAutoPtr<nsTArray<nsRefPtr<Element>>> candidates; 1.5956 + mRegistry->mCandidatesMap.RemoveAndForget(&key, candidates); 1.5957 + if (candidates) { 1.5958 + for (size_t i = 0; i < candidates->Length(); ++i) { 1.5959 + Element *elem = candidates->ElementAt(i); 1.5960 + 1.5961 + // Make sure that the element name matches the name in the definition. 1.5962 + // (e.g. a definition for x-button extending button should match 1.5963 + // <button is="x-button"> but not <x-button>. 1.5964 + if (elem->NodeInfo()->NameAtom() != nameAtom) { 1.5965 + // Skip over this element because definition does not apply. 1.5966 + continue; 1.5967 + } 1.5968 + 1.5969 + nsWrapperCache* cache; 1.5970 + CallQueryInterface(elem, &cache); 1.5971 + MOZ_ASSERT(cache, "Element doesn't support wrapper cache?"); 1.5972 + 1.5973 + JS::RootedObject wrapper(aCx); 1.5974 + if ((wrapper = cache->GetWrapper())) { 1.5975 + if (!JS_SetPrototype(aCx, wrapper, protoObject)) { 1.5976 + continue; 1.5977 + } 1.5978 + } 1.5979 + 1.5980 + EnqueueLifecycleCallback(nsIDocument::eCreated, elem, nullptr, definition); 1.5981 + if (elem->GetCurrentDoc()) { 1.5982 + // Normally callbacks can not be enqueued until the created 1.5983 + // callback has been invoked, however, the attached callback 1.5984 + // in element upgrade is an exception so pretend the created 1.5985 + // callback has been invoked. 1.5986 + elem->GetCustomElementData()->mCreatedCallbackInvoked = true; 1.5987 + 1.5988 + EnqueueLifecycleCallback(nsIDocument::eAttached, elem, nullptr, definition); 1.5989 + } 1.5990 + } 1.5991 + } 1.5992 + 1.5993 + // Create constructor to return. Store the name of the custom element as the 1.5994 + // name of the function. 1.5995 + JSFunction* constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0, 1.5996 + JSFUN_CONSTRUCTOR, JS::NullPtr(), 1.5997 + NS_ConvertUTF16toUTF8(lcType).get()); 1.5998 + if (!constructor) { 1.5999 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.6000 + return; 1.6001 + } 1.6002 + 1.6003 + aRetval.set(JS_GetFunctionObject(constructor)); 1.6004 +} 1.6005 + 1.6006 +void 1.6007 +nsDocument::UseRegistryFromDocument(nsIDocument* aDocument) 1.6008 +{ 1.6009 + nsDocument* doc = static_cast<nsDocument*>(aDocument); 1.6010 + MOZ_ASSERT(!mRegistry, "There should be no existing registry."); 1.6011 + mRegistry = doc->mRegistry; 1.6012 +} 1.6013 + 1.6014 +NS_IMETHODIMP 1.6015 +nsDocument::GetElementsByTagName(const nsAString& aTagname, 1.6016 + nsIDOMNodeList** aReturn) 1.6017 +{ 1.6018 + nsRefPtr<nsContentList> list = GetElementsByTagName(aTagname); 1.6019 + NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); 1.6020 + 1.6021 + // transfer ref to aReturn 1.6022 + list.forget(aReturn); 1.6023 + return NS_OK; 1.6024 +} 1.6025 + 1.6026 +already_AddRefed<nsContentList> 1.6027 +nsIDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, 1.6028 + const nsAString& aLocalName, 1.6029 + ErrorResult& aResult) 1.6030 +{ 1.6031 + int32_t nameSpaceId = kNameSpaceID_Wildcard; 1.6032 + 1.6033 + if (!aNamespaceURI.EqualsLiteral("*")) { 1.6034 + aResult = 1.6035 + nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI, 1.6036 + nameSpaceId); 1.6037 + if (aResult.Failed()) { 1.6038 + return nullptr; 1.6039 + } 1.6040 + } 1.6041 + 1.6042 + NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!"); 1.6043 + 1.6044 + return NS_GetContentList(this, nameSpaceId, aLocalName); 1.6045 +} 1.6046 + 1.6047 +NS_IMETHODIMP 1.6048 +nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, 1.6049 + const nsAString& aLocalName, 1.6050 + nsIDOMNodeList** aReturn) 1.6051 +{ 1.6052 + ErrorResult rv; 1.6053 + nsRefPtr<nsContentList> list = 1.6054 + nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv); 1.6055 + if (rv.Failed()) { 1.6056 + return rv.ErrorCode(); 1.6057 + } 1.6058 + 1.6059 + // transfer ref to aReturn 1.6060 + list.forget(aReturn); 1.6061 + return NS_OK; 1.6062 +} 1.6063 + 1.6064 +NS_IMETHODIMP 1.6065 +nsDocument::GetAsync(bool *aAsync) 1.6066 +{ 1.6067 + NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!"); 1.6068 + 1.6069 + return NS_ERROR_NOT_IMPLEMENTED; 1.6070 +} 1.6071 + 1.6072 +NS_IMETHODIMP 1.6073 +nsDocument::SetAsync(bool aAsync) 1.6074 +{ 1.6075 + NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!"); 1.6076 + 1.6077 + return NS_ERROR_NOT_IMPLEMENTED; 1.6078 +} 1.6079 + 1.6080 +NS_IMETHODIMP 1.6081 +nsDocument::Load(const nsAString& aUrl, bool *aReturn) 1.6082 +{ 1.6083 + NS_ERROR("nsDocument::Load() should be overriden by subclass!"); 1.6084 + 1.6085 + return NS_ERROR_NOT_IMPLEMENTED; 1.6086 +} 1.6087 + 1.6088 +NS_IMETHODIMP 1.6089 +nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) 1.6090 +{ 1.6091 + NS_ADDREF(*aStyleSheets = StyleSheets()); 1.6092 + return NS_OK; 1.6093 +} 1.6094 + 1.6095 +StyleSheetList* 1.6096 +nsDocument::StyleSheets() 1.6097 +{ 1.6098 + if (!mDOMStyleSheets) { 1.6099 + mDOMStyleSheets = new nsDOMStyleSheetList(this); 1.6100 + } 1.6101 + return mDOMStyleSheets; 1.6102 +} 1.6103 + 1.6104 +NS_IMETHODIMP 1.6105 +nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet) 1.6106 +{ 1.6107 + nsIDocument::GetSelectedStyleSheetSet(aSheetSet); 1.6108 + return NS_OK; 1.6109 +} 1.6110 + 1.6111 +void 1.6112 +nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet) 1.6113 +{ 1.6114 + aSheetSet.Truncate(); 1.6115 + 1.6116 + // Look through our sheets, find the selected set title 1.6117 + int32_t count = GetNumberOfStyleSheets(); 1.6118 + nsAutoString title; 1.6119 + for (int32_t index = 0; index < count; index++) { 1.6120 + nsIStyleSheet* sheet = GetStyleSheetAt(index); 1.6121 + NS_ASSERTION(sheet, "Null sheet in sheet list!"); 1.6122 + 1.6123 + nsCOMPtr<nsIDOMStyleSheet> domSheet = do_QueryInterface(sheet); 1.6124 + NS_ASSERTION(domSheet, "Sheet must QI to nsIDOMStyleSheet"); 1.6125 + bool disabled; 1.6126 + domSheet->GetDisabled(&disabled); 1.6127 + if (disabled) { 1.6128 + // Disabled sheets don't affect the currently selected set 1.6129 + continue; 1.6130 + } 1.6131 + 1.6132 + sheet->GetTitle(title); 1.6133 + 1.6134 + if (aSheetSet.IsEmpty()) { 1.6135 + aSheetSet = title; 1.6136 + } else if (!title.IsEmpty() && !aSheetSet.Equals(title)) { 1.6137 + // Sheets from multiple sets enabled; return null string, per spec. 1.6138 + SetDOMStringToNull(aSheetSet); 1.6139 + return; 1.6140 + } 1.6141 + } 1.6142 +} 1.6143 + 1.6144 +NS_IMETHODIMP 1.6145 +nsDocument::SetMozSelectedStyleSheetSet(const nsAString& aSheetSet) 1.6146 +{ 1.6147 + SetSelectedStyleSheetSet(aSheetSet); 1.6148 + return NS_OK; 1.6149 +} 1.6150 + 1.6151 +void 1.6152 +nsDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet) 1.6153 +{ 1.6154 + if (DOMStringIsNull(aSheetSet)) { 1.6155 + return; 1.6156 + } 1.6157 + 1.6158 + // Must update mLastStyleSheetSet before doing anything else with stylesheets 1.6159 + // or CSSLoaders. 1.6160 + mLastStyleSheetSet = aSheetSet; 1.6161 + EnableStyleSheetsForSetInternal(aSheetSet, true); 1.6162 +} 1.6163 + 1.6164 +NS_IMETHODIMP 1.6165 +nsDocument::GetLastStyleSheetSet(nsAString& aSheetSet) 1.6166 +{ 1.6167 + nsString sheetSet; 1.6168 + GetLastStyleSheetSet(sheetSet); 1.6169 + aSheetSet = sheetSet; 1.6170 + return NS_OK; 1.6171 +} 1.6172 + 1.6173 +void 1.6174 +nsDocument::GetLastStyleSheetSet(nsString& aSheetSet) 1.6175 +{ 1.6176 + aSheetSet = mLastStyleSheetSet; 1.6177 +} 1.6178 + 1.6179 +NS_IMETHODIMP 1.6180 +nsDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet) 1.6181 +{ 1.6182 + nsIDocument::GetPreferredStyleSheetSet(aSheetSet); 1.6183 + return NS_OK; 1.6184 +} 1.6185 + 1.6186 +void 1.6187 +nsIDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet) 1.6188 +{ 1.6189 + GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet); 1.6190 +} 1.6191 + 1.6192 +NS_IMETHODIMP 1.6193 +nsDocument::GetStyleSheetSets(nsISupports** aList) 1.6194 +{ 1.6195 + NS_ADDREF(*aList = StyleSheetSets()); 1.6196 + return NS_OK; 1.6197 +} 1.6198 + 1.6199 +DOMStringList* 1.6200 +nsDocument::StyleSheetSets() 1.6201 +{ 1.6202 + if (!mStyleSheetSetList) { 1.6203 + mStyleSheetSetList = new nsDOMStyleSheetSetList(this); 1.6204 + } 1.6205 + return mStyleSheetSetList; 1.6206 +} 1.6207 + 1.6208 +NS_IMETHODIMP 1.6209 +nsDocument::MozEnableStyleSheetsForSet(const nsAString& aSheetSet) 1.6210 +{ 1.6211 + EnableStyleSheetsForSet(aSheetSet); 1.6212 + return NS_OK; 1.6213 +} 1.6214 + 1.6215 +void 1.6216 +nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet) 1.6217 +{ 1.6218 + // Per spec, passing in null is a no-op. 1.6219 + if (!DOMStringIsNull(aSheetSet)) { 1.6220 + // Note: must make sure to not change the CSSLoader's preferred sheet -- 1.6221 + // that value should be equal to either our lastStyleSheetSet (if that's 1.6222 + // non-null) or to our preferredStyleSheetSet. And this method doesn't 1.6223 + // change either of those. 1.6224 + EnableStyleSheetsForSetInternal(aSheetSet, false); 1.6225 + } 1.6226 +} 1.6227 + 1.6228 +void 1.6229 +nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet, 1.6230 + bool aUpdateCSSLoader) 1.6231 +{ 1.6232 + BeginUpdate(UPDATE_STYLE); 1.6233 + int32_t count = GetNumberOfStyleSheets(); 1.6234 + nsAutoString title; 1.6235 + for (int32_t index = 0; index < count; index++) { 1.6236 + nsIStyleSheet* sheet = GetStyleSheetAt(index); 1.6237 + NS_ASSERTION(sheet, "Null sheet in sheet list!"); 1.6238 + sheet->GetTitle(title); 1.6239 + if (!title.IsEmpty()) { 1.6240 + sheet->SetEnabled(title.Equals(aSheetSet)); 1.6241 + } 1.6242 + } 1.6243 + if (aUpdateCSSLoader) { 1.6244 + CSSLoader()->SetPreferredSheet(aSheetSet); 1.6245 + } 1.6246 + EndUpdate(UPDATE_STYLE); 1.6247 +} 1.6248 + 1.6249 +NS_IMETHODIMP 1.6250 +nsDocument::GetCharacterSet(nsAString& aCharacterSet) 1.6251 +{ 1.6252 + nsIDocument::GetCharacterSet(aCharacterSet); 1.6253 + return NS_OK; 1.6254 +} 1.6255 + 1.6256 +void 1.6257 +nsIDocument::GetCharacterSet(nsAString& aCharacterSet) const 1.6258 +{ 1.6259 + CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet); 1.6260 +} 1.6261 + 1.6262 +NS_IMETHODIMP 1.6263 +nsDocument::ImportNode(nsIDOMNode* aImportedNode, 1.6264 + bool aDeep, 1.6265 + uint8_t aArgc, 1.6266 + nsIDOMNode** aResult) 1.6267 +{ 1.6268 + if (aArgc == 0) { 1.6269 + aDeep = true; 1.6270 + } 1.6271 + 1.6272 + *aResult = nullptr; 1.6273 + 1.6274 + nsCOMPtr<nsINode> imported = do_QueryInterface(aImportedNode); 1.6275 + NS_ENSURE_TRUE(imported, NS_ERROR_UNEXPECTED); 1.6276 + 1.6277 + ErrorResult rv; 1.6278 + nsCOMPtr<nsINode> result = nsIDocument::ImportNode(*imported, aDeep, rv); 1.6279 + if (rv.Failed()) { 1.6280 + return rv.ErrorCode(); 1.6281 + } 1.6282 + 1.6283 + NS_ADDREF(*aResult = result->AsDOMNode()); 1.6284 + return NS_OK; 1.6285 +} 1.6286 + 1.6287 +already_AddRefed<nsINode> 1.6288 +nsIDocument::ImportNode(nsINode& aNode, bool aDeep, ErrorResult& rv) const 1.6289 +{ 1.6290 + nsINode* imported = &aNode; 1.6291 + 1.6292 + switch (imported->NodeType()) { 1.6293 + case nsIDOMNode::ATTRIBUTE_NODE: 1.6294 + case nsIDOMNode::DOCUMENT_FRAGMENT_NODE: 1.6295 + case nsIDOMNode::ELEMENT_NODE: 1.6296 + case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: 1.6297 + case nsIDOMNode::TEXT_NODE: 1.6298 + case nsIDOMNode::CDATA_SECTION_NODE: 1.6299 + case nsIDOMNode::COMMENT_NODE: 1.6300 + case nsIDOMNode::DOCUMENT_TYPE_NODE: 1.6301 + { 1.6302 + nsCOMPtr<nsINode> newNode; 1.6303 + nsCOMArray<nsINode> nodesWithProperties; 1.6304 + rv = nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager, 1.6305 + nodesWithProperties, getter_AddRefs(newNode)); 1.6306 + if (rv.Failed()) { 1.6307 + return nullptr; 1.6308 + } 1.6309 + 1.6310 + nsIDocument *ownerDoc = imported->OwnerDoc(); 1.6311 + rv = nsNodeUtils::CallUserDataHandlers(nodesWithProperties, ownerDoc, 1.6312 + nsIDOMUserDataHandler::NODE_IMPORTED, 1.6313 + true); 1.6314 + if (rv.Failed()) { 1.6315 + return nullptr; 1.6316 + } 1.6317 + 1.6318 + return newNode.forget(); 1.6319 + } 1.6320 + default: 1.6321 + { 1.6322 + NS_WARNING("Don't know how to clone this nodetype for importNode."); 1.6323 + 1.6324 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.6325 + } 1.6326 + } 1.6327 + 1.6328 + return nullptr; 1.6329 +} 1.6330 + 1.6331 +NS_IMETHODIMP 1.6332 +nsDocument::LoadBindingDocument(const nsAString& aURI) 1.6333 +{ 1.6334 + ErrorResult rv; 1.6335 + nsIDocument::LoadBindingDocument(aURI, rv); 1.6336 + return rv.ErrorCode(); 1.6337 +} 1.6338 + 1.6339 +void 1.6340 +nsIDocument::LoadBindingDocument(const nsAString& aURI, ErrorResult& rv) 1.6341 +{ 1.6342 + nsCOMPtr<nsIURI> uri; 1.6343 + rv = NS_NewURI(getter_AddRefs(uri), aURI, 1.6344 + mCharacterSet.get(), 1.6345 + GetDocBaseURI()); 1.6346 + if (rv.Failed()) { 1.6347 + return; 1.6348 + } 1.6349 + 1.6350 + // Figure out the right principal to use 1.6351 + nsCOMPtr<nsIPrincipal> subject; 1.6352 + nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); 1.6353 + if (secMan) { 1.6354 + rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject)); 1.6355 + if (rv.Failed()) { 1.6356 + return; 1.6357 + } 1.6358 + } 1.6359 + 1.6360 + if (!subject) { 1.6361 + // Fall back to our principal. Or should we fall back to the null 1.6362 + // principal? The latter would just mean no binding loads.... 1.6363 + subject = NodePrincipal(); 1.6364 + } 1.6365 + 1.6366 + BindingManager()->LoadBindingDocument(this, uri, subject); 1.6367 +} 1.6368 + 1.6369 +NS_IMETHODIMP 1.6370 +nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult) 1.6371 +{ 1.6372 + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); 1.6373 + NS_ENSURE_ARG_POINTER(node); 1.6374 + 1.6375 + Element* bindingParent = nsIDocument::GetBindingParent(*node); 1.6376 + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(bindingParent); 1.6377 + retval.forget(aResult); 1.6378 + return NS_OK; 1.6379 +} 1.6380 + 1.6381 +Element* 1.6382 +nsIDocument::GetBindingParent(nsINode& aNode) 1.6383 +{ 1.6384 + nsCOMPtr<nsIContent> content(do_QueryInterface(&aNode)); 1.6385 + if (!content) 1.6386 + return nullptr; 1.6387 + 1.6388 + nsIContent* bindingParent = content->GetBindingParent(); 1.6389 + return bindingParent ? bindingParent->AsElement() : nullptr; 1.6390 +} 1.6391 + 1.6392 +static Element* 1.6393 +GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName, 1.6394 + const nsAString& aAttrValue, bool aUniversalMatch) 1.6395 +{ 1.6396 + if (aUniversalMatch ? aContent->HasAttr(kNameSpaceID_None, aAttrName) : 1.6397 + aContent->AttrValueIs(kNameSpaceID_None, aAttrName, 1.6398 + aAttrValue, eCaseMatters)) { 1.6399 + return aContent->AsElement(); 1.6400 + } 1.6401 + 1.6402 + for (nsIContent* child = aContent->GetFirstChild(); 1.6403 + child; 1.6404 + child = child->GetNextSibling()) { 1.6405 + 1.6406 + Element* matchedElement = 1.6407 + GetElementByAttribute(child, aAttrName, aAttrValue, aUniversalMatch); 1.6408 + if (matchedElement) 1.6409 + return matchedElement; 1.6410 + } 1.6411 + 1.6412 + return nullptr; 1.6413 +} 1.6414 + 1.6415 +Element* 1.6416 +nsDocument::GetAnonymousElementByAttribute(nsIContent* aElement, 1.6417 + nsIAtom* aAttrName, 1.6418 + const nsAString& aAttrValue) const 1.6419 +{ 1.6420 + nsINodeList* nodeList = BindingManager()->GetAnonymousNodesFor(aElement); 1.6421 + if (!nodeList) 1.6422 + return nullptr; 1.6423 + 1.6424 + uint32_t length = 0; 1.6425 + nodeList->GetLength(&length); 1.6426 + 1.6427 + bool universalMatch = aAttrValue.EqualsLiteral("*"); 1.6428 + 1.6429 + for (uint32_t i = 0; i < length; ++i) { 1.6430 + nsIContent* current = nodeList->Item(i); 1.6431 + Element* matchedElm = 1.6432 + GetElementByAttribute(current, aAttrName, aAttrValue, universalMatch); 1.6433 + if (matchedElm) 1.6434 + return matchedElm; 1.6435 + } 1.6436 + 1.6437 + return nullptr; 1.6438 +} 1.6439 + 1.6440 +NS_IMETHODIMP 1.6441 +nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement, 1.6442 + const nsAString& aAttrName, 1.6443 + const nsAString& aAttrValue, 1.6444 + nsIDOMElement** aResult) 1.6445 +{ 1.6446 + nsCOMPtr<Element> element = do_QueryInterface(aElement); 1.6447 + NS_ENSURE_ARG_POINTER(element); 1.6448 + 1.6449 + Element* anonEl = 1.6450 + nsIDocument::GetAnonymousElementByAttribute(*element, aAttrName, 1.6451 + aAttrValue); 1.6452 + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(anonEl); 1.6453 + retval.forget(aResult); 1.6454 + return NS_OK; 1.6455 +} 1.6456 + 1.6457 +Element* 1.6458 +nsIDocument::GetAnonymousElementByAttribute(Element& aElement, 1.6459 + const nsAString& aAttrName, 1.6460 + const nsAString& aAttrValue) 1.6461 +{ 1.6462 + nsCOMPtr<nsIAtom> attribute = do_GetAtom(aAttrName); 1.6463 + 1.6464 + return GetAnonymousElementByAttribute(&aElement, attribute, aAttrValue); 1.6465 +} 1.6466 + 1.6467 + 1.6468 +NS_IMETHODIMP 1.6469 +nsDocument::GetAnonymousNodes(nsIDOMElement* aElement, 1.6470 + nsIDOMNodeList** aResult) 1.6471 +{ 1.6472 + *aResult = nullptr; 1.6473 + 1.6474 + nsCOMPtr<nsIContent> content(do_QueryInterface(aElement)); 1.6475 + return BindingManager()->GetAnonymousNodesFor(content, aResult); 1.6476 +} 1.6477 + 1.6478 +nsINodeList* 1.6479 +nsIDocument::GetAnonymousNodes(Element& aElement) 1.6480 +{ 1.6481 + return BindingManager()->GetAnonymousNodesFor(&aElement); 1.6482 +} 1.6483 + 1.6484 +NS_IMETHODIMP 1.6485 +nsDocument::CreateRange(nsIDOMRange** aReturn) 1.6486 +{ 1.6487 + ErrorResult rv; 1.6488 + *aReturn = nsIDocument::CreateRange(rv).take(); 1.6489 + return rv.ErrorCode(); 1.6490 +} 1.6491 + 1.6492 +already_AddRefed<nsRange> 1.6493 +nsIDocument::CreateRange(ErrorResult& rv) 1.6494 +{ 1.6495 + nsRefPtr<nsRange> range = new nsRange(this); 1.6496 + nsresult res = range->Set(this, 0, this, 0); 1.6497 + if (NS_FAILED(res)) { 1.6498 + rv.Throw(res); 1.6499 + return nullptr; 1.6500 + } 1.6501 + 1.6502 + return range.forget(); 1.6503 +} 1.6504 + 1.6505 +NS_IMETHODIMP 1.6506 +nsDocument::CreateNodeIterator(nsIDOMNode *aRoot, 1.6507 + uint32_t aWhatToShow, 1.6508 + nsIDOMNodeFilter *aFilter, 1.6509 + uint8_t aOptionalArgc, 1.6510 + nsIDOMNodeIterator **_retval) 1.6511 +{ 1.6512 + *_retval = nullptr; 1.6513 + 1.6514 + if (!aOptionalArgc) { 1.6515 + aWhatToShow = nsIDOMNodeFilter::SHOW_ALL; 1.6516 + } 1.6517 + 1.6518 + if (!aRoot) { 1.6519 + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; 1.6520 + } 1.6521 + 1.6522 + nsCOMPtr<nsINode> root = do_QueryInterface(aRoot); 1.6523 + NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED); 1.6524 + 1.6525 + ErrorResult rv; 1.6526 + NodeFilterHolder holder(aFilter); 1.6527 + *_retval = nsIDocument::CreateNodeIterator(*root, aWhatToShow, holder, 1.6528 + rv).take(); 1.6529 + return rv.ErrorCode(); 1.6530 +} 1.6531 + 1.6532 +already_AddRefed<NodeIterator> 1.6533 +nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow, 1.6534 + NodeFilter* aFilter, 1.6535 + ErrorResult& rv) const 1.6536 +{ 1.6537 + NodeFilterHolder holder(aFilter); 1.6538 + return CreateNodeIterator(aRoot, aWhatToShow, holder, rv); 1.6539 +} 1.6540 + 1.6541 +already_AddRefed<NodeIterator> 1.6542 +nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow, 1.6543 + const NodeFilterHolder& aFilter, 1.6544 + ErrorResult& rv) const 1.6545 +{ 1.6546 + nsINode* root = &aRoot; 1.6547 + nsRefPtr<NodeIterator> iterator = new NodeIterator(root, aWhatToShow, 1.6548 + aFilter); 1.6549 + return iterator.forget(); 1.6550 +} 1.6551 + 1.6552 +NS_IMETHODIMP 1.6553 +nsDocument::CreateTreeWalker(nsIDOMNode *aRoot, 1.6554 + uint32_t aWhatToShow, 1.6555 + nsIDOMNodeFilter *aFilter, 1.6556 + uint8_t aOptionalArgc, 1.6557 + nsIDOMTreeWalker **_retval) 1.6558 +{ 1.6559 + *_retval = nullptr; 1.6560 + 1.6561 + if (!aOptionalArgc) { 1.6562 + aWhatToShow = nsIDOMNodeFilter::SHOW_ALL; 1.6563 + } 1.6564 + 1.6565 + nsCOMPtr<nsINode> root = do_QueryInterface(aRoot); 1.6566 + NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.6567 + 1.6568 + ErrorResult rv; 1.6569 + NodeFilterHolder holder(aFilter); 1.6570 + *_retval = nsIDocument::CreateTreeWalker(*root, aWhatToShow, holder, 1.6571 + rv).take(); 1.6572 + return rv.ErrorCode(); 1.6573 +} 1.6574 + 1.6575 +already_AddRefed<TreeWalker> 1.6576 +nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow, 1.6577 + NodeFilter* aFilter, 1.6578 + ErrorResult& rv) const 1.6579 +{ 1.6580 + NodeFilterHolder holder(aFilter); 1.6581 + return CreateTreeWalker(aRoot, aWhatToShow, holder, rv); 1.6582 +} 1.6583 + 1.6584 +already_AddRefed<TreeWalker> 1.6585 +nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow, 1.6586 + const NodeFilterHolder& aFilter, 1.6587 + ErrorResult& rv) const 1.6588 +{ 1.6589 + nsINode* root = &aRoot; 1.6590 + nsRefPtr<TreeWalker> walker = new TreeWalker(root, aWhatToShow, aFilter); 1.6591 + return walker.forget(); 1.6592 +} 1.6593 + 1.6594 + 1.6595 +NS_IMETHODIMP 1.6596 +nsDocument::GetDefaultView(nsIDOMWindow** aDefaultView) 1.6597 +{ 1.6598 + *aDefaultView = nullptr; 1.6599 + nsCOMPtr<nsPIDOMWindow> win = GetWindow(); 1.6600 + win.forget(aDefaultView); 1.6601 + return NS_OK; 1.6602 +} 1.6603 + 1.6604 +NS_IMETHODIMP 1.6605 +nsDocument::GetLocation(nsIDOMLocation **_retval) 1.6606 +{ 1.6607 + *_retval = nsIDocument::GetLocation().take(); 1.6608 + return NS_OK; 1.6609 +} 1.6610 + 1.6611 +already_AddRefed<nsIDOMLocation> 1.6612 +nsIDocument::GetLocation() const 1.6613 +{ 1.6614 + nsCOMPtr<nsIDOMWindow> w = do_QueryInterface(mScriptGlobalObject); 1.6615 + 1.6616 + if (!w) { 1.6617 + return nullptr; 1.6618 + } 1.6619 + 1.6620 + nsCOMPtr<nsIDOMLocation> loc; 1.6621 + w->GetLocation(getter_AddRefs(loc)); 1.6622 + return loc.forget(); 1.6623 +} 1.6624 + 1.6625 +Element* 1.6626 +nsIDocument::GetHtmlElement() const 1.6627 +{ 1.6628 + Element* rootElement = GetRootElement(); 1.6629 + if (rootElement && rootElement->IsHTML(nsGkAtoms::html)) 1.6630 + return rootElement; 1.6631 + return nullptr; 1.6632 +} 1.6633 + 1.6634 +Element* 1.6635 +nsIDocument::GetHtmlChildElement(nsIAtom* aTag) 1.6636 +{ 1.6637 + Element* html = GetHtmlElement(); 1.6638 + if (!html) 1.6639 + return nullptr; 1.6640 + 1.6641 + // Look for the element with aTag inside html. This needs to run 1.6642 + // forwards to find the first such element. 1.6643 + for (nsIContent* child = html->GetFirstChild(); 1.6644 + child; 1.6645 + child = child->GetNextSibling()) { 1.6646 + if (child->IsHTML(aTag)) 1.6647 + return child->AsElement(); 1.6648 + } 1.6649 + return nullptr; 1.6650 +} 1.6651 + 1.6652 +nsIContent* 1.6653 +nsDocument::GetTitleContent(uint32_t aNamespace) 1.6654 +{ 1.6655 + // mMayHaveTitleElement will have been set to true if any HTML or SVG 1.6656 + // <title> element has been bound to this document. So if it's false, 1.6657 + // we know there is nothing to do here. This avoids us having to search 1.6658 + // the whole DOM if someone calls document.title on a large document 1.6659 + // without a title. 1.6660 + if (!mMayHaveTitleElement) 1.6661 + return nullptr; 1.6662 + 1.6663 + nsRefPtr<nsContentList> list = 1.6664 + NS_GetContentList(this, aNamespace, NS_LITERAL_STRING("title")); 1.6665 + 1.6666 + return list->Item(0, false); 1.6667 +} 1.6668 + 1.6669 +void 1.6670 +nsDocument::GetTitleFromElement(uint32_t aNamespace, nsAString& aTitle) 1.6671 +{ 1.6672 + nsIContent* title = GetTitleContent(aNamespace); 1.6673 + if (!title) 1.6674 + return; 1.6675 + if(!nsContentUtils::GetNodeTextContent(title, false, aTitle)) 1.6676 + NS_RUNTIMEABORT("OOM"); 1.6677 +} 1.6678 + 1.6679 +NS_IMETHODIMP 1.6680 +nsDocument::GetTitle(nsAString& aTitle) 1.6681 +{ 1.6682 + nsString title; 1.6683 + GetTitle(title); 1.6684 + aTitle = title; 1.6685 + return NS_OK; 1.6686 +} 1.6687 + 1.6688 +void 1.6689 +nsDocument::GetTitle(nsString& aTitle) 1.6690 +{ 1.6691 + aTitle.Truncate(); 1.6692 + 1.6693 + nsIContent *rootElement = GetRootElement(); 1.6694 + if (!rootElement) 1.6695 + return; 1.6696 + 1.6697 + nsAutoString tmp; 1.6698 + 1.6699 + switch (rootElement->GetNameSpaceID()) { 1.6700 +#ifdef MOZ_XUL 1.6701 + case kNameSpaceID_XUL: 1.6702 + rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp); 1.6703 + break; 1.6704 +#endif 1.6705 + case kNameSpaceID_SVG: 1.6706 + if (rootElement->Tag() == nsGkAtoms::svg) { 1.6707 + GetTitleFromElement(kNameSpaceID_SVG, tmp); 1.6708 + break; 1.6709 + } // else fall through 1.6710 + default: 1.6711 + GetTitleFromElement(kNameSpaceID_XHTML, tmp); 1.6712 + break; 1.6713 + } 1.6714 + 1.6715 + tmp.CompressWhitespace(); 1.6716 + aTitle = tmp; 1.6717 +} 1.6718 + 1.6719 +NS_IMETHODIMP 1.6720 +nsDocument::SetTitle(const nsAString& aTitle) 1.6721 +{ 1.6722 + Element *rootElement = GetRootElement(); 1.6723 + if (!rootElement) 1.6724 + return NS_OK; 1.6725 + 1.6726 + switch (rootElement->GetNameSpaceID()) { 1.6727 + case kNameSpaceID_SVG: 1.6728 + return NS_OK; // SVG doesn't support setting a title 1.6729 +#ifdef MOZ_XUL 1.6730 + case kNameSpaceID_XUL: 1.6731 + return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title, 1.6732 + aTitle, true); 1.6733 +#endif 1.6734 + } 1.6735 + 1.6736 + // Batch updates so that mutation events don't change "the title 1.6737 + // element" under us 1.6738 + mozAutoDocUpdate updateBatch(this, UPDATE_CONTENT_MODEL, true); 1.6739 + 1.6740 + nsIContent* title = GetTitleContent(kNameSpaceID_XHTML); 1.6741 + if (!title) { 1.6742 + Element *head = GetHeadElement(); 1.6743 + if (!head) 1.6744 + return NS_OK; 1.6745 + 1.6746 + { 1.6747 + nsCOMPtr<nsINodeInfo> titleInfo; 1.6748 + titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr, 1.6749 + kNameSpaceID_XHTML, 1.6750 + nsIDOMNode::ELEMENT_NODE); 1.6751 + title = NS_NewHTMLTitleElement(titleInfo.forget()); 1.6752 + if (!title) 1.6753 + return NS_OK; 1.6754 + } 1.6755 + 1.6756 + head->AppendChildTo(title, true); 1.6757 + } 1.6758 + 1.6759 + return nsContentUtils::SetNodeTextContent(title, aTitle, false); 1.6760 +} 1.6761 + 1.6762 +void 1.6763 +nsDocument::SetTitle(const nsAString& aTitle, ErrorResult& rv) 1.6764 +{ 1.6765 + rv = SetTitle(aTitle); 1.6766 +} 1.6767 + 1.6768 +void 1.6769 +nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement) 1.6770 +{ 1.6771 + NS_ASSERTION(!mInUnlinkOrDeletion || !aBoundTitleElement, 1.6772 + "Setting a title while unlinking or destroying the element?"); 1.6773 + if (mInUnlinkOrDeletion) { 1.6774 + return; 1.6775 + } 1.6776 + 1.6777 + if (aBoundTitleElement) { 1.6778 + mMayHaveTitleElement = true; 1.6779 + } 1.6780 + if (mPendingTitleChangeEvent.IsPending()) 1.6781 + return; 1.6782 + 1.6783 + nsRefPtr<nsRunnableMethod<nsDocument, void, false> > event = 1.6784 + NS_NewNonOwningRunnableMethod(this, 1.6785 + &nsDocument::DoNotifyPossibleTitleChange); 1.6786 + nsresult rv = NS_DispatchToCurrentThread(event); 1.6787 + if (NS_SUCCEEDED(rv)) { 1.6788 + mPendingTitleChangeEvent = event; 1.6789 + } 1.6790 +} 1.6791 + 1.6792 +void 1.6793 +nsDocument::DoNotifyPossibleTitleChange() 1.6794 +{ 1.6795 + mPendingTitleChangeEvent.Forget(); 1.6796 + mHaveFiredTitleChange = true; 1.6797 + 1.6798 + nsAutoString title; 1.6799 + GetTitle(title); 1.6800 + 1.6801 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.6802 + if (shell) { 1.6803 + nsCOMPtr<nsISupports> container = 1.6804 + shell->GetPresContext()->GetContainerWeak(); 1.6805 + if (container) { 1.6806 + nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container); 1.6807 + if (docShellWin) { 1.6808 + docShellWin->SetTitle(title.get()); 1.6809 + } 1.6810 + } 1.6811 + } 1.6812 + 1.6813 + // Fire a DOM event for the title change. 1.6814 + nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this), 1.6815 + NS_LITERAL_STRING("DOMTitleChanged"), 1.6816 + true, true); 1.6817 +} 1.6818 + 1.6819 +already_AddRefed<nsIBoxObject> 1.6820 +nsDocument::GetBoxObjectFor(Element* aElement, ErrorResult& aRv) 1.6821 +{ 1.6822 + if (!aElement) { 1.6823 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.6824 + return nullptr; 1.6825 + } 1.6826 + 1.6827 + nsIDocument* doc = aElement->OwnerDoc(); 1.6828 + if (doc != this) { 1.6829 + aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); 1.6830 + return nullptr; 1.6831 + } 1.6832 + 1.6833 + if (!mHasWarnedAboutBoxObjects && !aElement->IsXUL()) { 1.6834 + mHasWarnedAboutBoxObjects = true; 1.6835 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.6836 + NS_LITERAL_CSTRING("BoxObjects"), this, 1.6837 + nsContentUtils::eDOM_PROPERTIES, 1.6838 + "UseOfGetBoxObjectForWarning"); 1.6839 + } 1.6840 + 1.6841 + if (!mBoxObjectTable) { 1.6842 + mBoxObjectTable = new nsInterfaceHashtable<nsPtrHashKey<nsIContent>, nsPIBoxObject>(12); 1.6843 + } else { 1.6844 + nsCOMPtr<nsPIBoxObject> boxObject = mBoxObjectTable->Get(aElement); 1.6845 + if (boxObject) { 1.6846 + return boxObject.forget(); 1.6847 + } 1.6848 + } 1.6849 + 1.6850 + int32_t namespaceID; 1.6851 + nsCOMPtr<nsIAtom> tag = BindingManager()->ResolveTag(aElement, &namespaceID); 1.6852 + 1.6853 + nsAutoCString contractID("@mozilla.org/layout/xul-boxobject"); 1.6854 + if (namespaceID == kNameSpaceID_XUL) { 1.6855 + if (tag == nsGkAtoms::browser || 1.6856 + tag == nsGkAtoms::editor || 1.6857 + tag == nsGkAtoms::iframe) 1.6858 + contractID += "-container"; 1.6859 + else if (tag == nsGkAtoms::menu) 1.6860 + contractID += "-menu"; 1.6861 + else if (tag == nsGkAtoms::popup || 1.6862 + tag == nsGkAtoms::menupopup || 1.6863 + tag == nsGkAtoms::panel || 1.6864 + tag == nsGkAtoms::tooltip) 1.6865 + contractID += "-popup"; 1.6866 + else if (tag == nsGkAtoms::tree) 1.6867 + contractID += "-tree"; 1.6868 + else if (tag == nsGkAtoms::listbox) 1.6869 + contractID += "-listbox"; 1.6870 + else if (tag == nsGkAtoms::scrollbox) 1.6871 + contractID += "-scrollbox"; 1.6872 + } 1.6873 + contractID += ";1"; 1.6874 + 1.6875 + nsCOMPtr<nsPIBoxObject> boxObject(do_CreateInstance(contractID.get())); 1.6876 + if (!boxObject) { 1.6877 + aRv.Throw(NS_ERROR_FAILURE); 1.6878 + return nullptr; 1.6879 + } 1.6880 + 1.6881 + boxObject->Init(aElement); 1.6882 + 1.6883 + if (mBoxObjectTable) { 1.6884 + mBoxObjectTable->Put(aElement, boxObject.get()); 1.6885 + } 1.6886 + 1.6887 + return boxObject.forget(); 1.6888 +} 1.6889 + 1.6890 +void 1.6891 +nsDocument::ClearBoxObjectFor(nsIContent* aContent) 1.6892 +{ 1.6893 + if (mBoxObjectTable) { 1.6894 + nsPIBoxObject *boxObject = mBoxObjectTable->GetWeak(aContent); 1.6895 + if (boxObject) { 1.6896 + boxObject->Clear(); 1.6897 + mBoxObjectTable->Remove(aContent); 1.6898 + } 1.6899 + } 1.6900 +} 1.6901 + 1.6902 +void 1.6903 +nsDocument::FlushSkinBindings() 1.6904 +{ 1.6905 + BindingManager()->FlushSkinBindings(); 1.6906 +} 1.6907 + 1.6908 +nsresult 1.6909 +nsDocument::InitializeFrameLoader(nsFrameLoader* aLoader) 1.6910 +{ 1.6911 + mInitializableFrameLoaders.RemoveElement(aLoader); 1.6912 + // Don't even try to initialize. 1.6913 + if (mInDestructor) { 1.6914 + NS_WARNING("Trying to initialize a frame loader while" 1.6915 + "document is being deleted"); 1.6916 + return NS_ERROR_FAILURE; 1.6917 + } 1.6918 + 1.6919 + mInitializableFrameLoaders.AppendElement(aLoader); 1.6920 + if (!mFrameLoaderRunner) { 1.6921 + mFrameLoaderRunner = 1.6922 + NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); 1.6923 + NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY); 1.6924 + nsContentUtils::AddScriptRunner(mFrameLoaderRunner); 1.6925 + } 1.6926 + return NS_OK; 1.6927 +} 1.6928 + 1.6929 +nsresult 1.6930 +nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader) 1.6931 +{ 1.6932 + mInitializableFrameLoaders.RemoveElement(aLoader); 1.6933 + if (mInDestructor) { 1.6934 + return NS_ERROR_FAILURE; 1.6935 + } 1.6936 + 1.6937 + mFinalizableFrameLoaders.AppendElement(aLoader); 1.6938 + if (!mFrameLoaderRunner) { 1.6939 + mFrameLoaderRunner = 1.6940 + NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); 1.6941 + NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY); 1.6942 + nsContentUtils::AddScriptRunner(mFrameLoaderRunner); 1.6943 + } 1.6944 + return NS_OK; 1.6945 +} 1.6946 + 1.6947 +void 1.6948 +nsDocument::MaybeInitializeFinalizeFrameLoaders() 1.6949 +{ 1.6950 + if (mDelayFrameLoaderInitialization || mUpdateNestLevel != 0) { 1.6951 + // This method will be recalled when mUpdateNestLevel drops to 0, 1.6952 + // or when !mDelayFrameLoaderInitialization. 1.6953 + mFrameLoaderRunner = nullptr; 1.6954 + return; 1.6955 + } 1.6956 + 1.6957 + // We're not in an update, but it is not safe to run scripts, so 1.6958 + // postpone frameloader initialization and finalization. 1.6959 + if (!nsContentUtils::IsSafeToRunScript()) { 1.6960 + if (!mInDestructor && !mFrameLoaderRunner && 1.6961 + (mInitializableFrameLoaders.Length() || 1.6962 + mFinalizableFrameLoaders.Length())) { 1.6963 + mFrameLoaderRunner = 1.6964 + NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); 1.6965 + nsContentUtils::AddScriptRunner(mFrameLoaderRunner); 1.6966 + } 1.6967 + return; 1.6968 + } 1.6969 + mFrameLoaderRunner = nullptr; 1.6970 + 1.6971 + // Don't use a temporary array for mInitializableFrameLoaders, because 1.6972 + // loading a frame may cause some other frameloader to be removed from the 1.6973 + // array. But be careful to keep the loader alive when starting the load! 1.6974 + while (mInitializableFrameLoaders.Length()) { 1.6975 + nsRefPtr<nsFrameLoader> loader = mInitializableFrameLoaders[0]; 1.6976 + mInitializableFrameLoaders.RemoveElementAt(0); 1.6977 + NS_ASSERTION(loader, "null frameloader in the array?"); 1.6978 + loader->ReallyStartLoading(); 1.6979 + } 1.6980 + 1.6981 + uint32_t length = mFinalizableFrameLoaders.Length(); 1.6982 + if (length > 0) { 1.6983 + nsTArray<nsRefPtr<nsFrameLoader> > loaders; 1.6984 + mFinalizableFrameLoaders.SwapElements(loaders); 1.6985 + for (uint32_t i = 0; i < length; ++i) { 1.6986 + loaders[i]->Finalize(); 1.6987 + } 1.6988 + } 1.6989 +} 1.6990 + 1.6991 +void 1.6992 +nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell* aShell) 1.6993 +{ 1.6994 + uint32_t length = mInitializableFrameLoaders.Length(); 1.6995 + for (uint32_t i = 0; i < length; ++i) { 1.6996 + if (mInitializableFrameLoaders[i]->GetExistingDocShell() == aShell) { 1.6997 + mInitializableFrameLoaders.RemoveElementAt(i); 1.6998 + return; 1.6999 + } 1.7000 + } 1.7001 +} 1.7002 + 1.7003 +bool 1.7004 +nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell) 1.7005 +{ 1.7006 + if (aShell) { 1.7007 + uint32_t length = mFinalizableFrameLoaders.Length(); 1.7008 + for (uint32_t i = 0; i < length; ++i) { 1.7009 + if (mFinalizableFrameLoaders[i]->GetExistingDocShell() == aShell) { 1.7010 + return true; 1.7011 + } 1.7012 + } 1.7013 + } 1.7014 + return false; 1.7015 +} 1.7016 + 1.7017 +nsIDocument* 1.7018 +nsDocument::RequestExternalResource(nsIURI* aURI, 1.7019 + nsINode* aRequestingNode, 1.7020 + ExternalResourceLoad** aPendingLoad) 1.7021 +{ 1.7022 + NS_PRECONDITION(aURI, "Must have a URI"); 1.7023 + NS_PRECONDITION(aRequestingNode, "Must have a node"); 1.7024 + if (mDisplayDocument) { 1.7025 + return mDisplayDocument->RequestExternalResource(aURI, 1.7026 + aRequestingNode, 1.7027 + aPendingLoad); 1.7028 + } 1.7029 + 1.7030 + return mExternalResourceMap.RequestResource(aURI, aRequestingNode, 1.7031 + this, aPendingLoad); 1.7032 +} 1.7033 + 1.7034 +void 1.7035 +nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData) 1.7036 +{ 1.7037 + mExternalResourceMap.EnumerateResources(aCallback, aData); 1.7038 +} 1.7039 + 1.7040 +nsSMILAnimationController* 1.7041 +nsDocument::GetAnimationController() 1.7042 +{ 1.7043 + // We create the animation controller lazily because most documents won't want 1.7044 + // one and only SVG documents and the like will call this 1.7045 + if (mAnimationController) 1.7046 + return mAnimationController; 1.7047 + // Refuse to create an Animation Controller for data documents. 1.7048 + if (mLoadedAsData || mLoadedAsInteractiveData) 1.7049 + return nullptr; 1.7050 + 1.7051 + mAnimationController = new nsSMILAnimationController(this); 1.7052 + 1.7053 + // If there's a presContext then check the animation mode and pause if 1.7054 + // necessary. 1.7055 + nsIPresShell *shell = GetShell(); 1.7056 + if (mAnimationController && shell) { 1.7057 + nsPresContext *context = shell->GetPresContext(); 1.7058 + if (context && 1.7059 + context->ImageAnimationMode() == imgIContainer::kDontAnimMode) { 1.7060 + mAnimationController->Pause(nsSMILTimeContainer::PAUSE_USERPREF); 1.7061 + } 1.7062 + } 1.7063 + 1.7064 + // If we're hidden (or being hidden), notify the newly-created animation 1.7065 + // controller. (Skip this check for SVG-as-an-image documents, though, 1.7066 + // because they don't get OnPageShow / OnPageHide calls). 1.7067 + if (!mIsShowing && !mIsBeingUsedAsImage) { 1.7068 + mAnimationController->OnPageHide(); 1.7069 + } 1.7070 + 1.7071 + return mAnimationController; 1.7072 +} 1.7073 + 1.7074 +/** 1.7075 + * Retrieve the "direction" property of the document. 1.7076 + * 1.7077 + * @lina 01/09/2001 1.7078 + */ 1.7079 +NS_IMETHODIMP 1.7080 +nsDocument::GetDir(nsAString& aDirection) 1.7081 +{ 1.7082 + nsIDocument::GetDir(aDirection); 1.7083 + return NS_OK; 1.7084 +} 1.7085 + 1.7086 +void 1.7087 +nsIDocument::GetDir(nsAString& aDirection) const 1.7088 +{ 1.7089 + aDirection.Truncate(); 1.7090 + Element* rootElement = GetHtmlElement(); 1.7091 + if (rootElement) { 1.7092 + static_cast<nsGenericHTMLElement*>(rootElement)->GetDir(aDirection); 1.7093 + } 1.7094 +} 1.7095 + 1.7096 +/** 1.7097 + * Set the "direction" property of the document. 1.7098 + * 1.7099 + * @lina 01/09/2001 1.7100 + */ 1.7101 +NS_IMETHODIMP 1.7102 +nsDocument::SetDir(const nsAString& aDirection) 1.7103 +{ 1.7104 + nsIDocument::SetDir(aDirection); 1.7105 + return NS_OK; 1.7106 +} 1.7107 + 1.7108 +void 1.7109 +nsIDocument::SetDir(const nsAString& aDirection) 1.7110 +{ 1.7111 + Element* rootElement = GetHtmlElement(); 1.7112 + if (rootElement) { 1.7113 + rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, 1.7114 + aDirection, true); 1.7115 + } 1.7116 +} 1.7117 + 1.7118 +NS_IMETHODIMP 1.7119 +nsDocument::GetInputEncoding(nsAString& aInputEncoding) 1.7120 +{ 1.7121 + nsIDocument::GetInputEncoding(aInputEncoding); 1.7122 + return NS_OK; 1.7123 +} 1.7124 + 1.7125 +void 1.7126 +nsIDocument::GetInputEncoding(nsAString& aInputEncoding) 1.7127 +{ 1.7128 + // Not const function, because WarnOnceAbout is not a const method 1.7129 + WarnOnceAbout(eInputEncoding); 1.7130 + if (mHaveInputEncoding) { 1.7131 + return GetCharacterSet(aInputEncoding); 1.7132 + } 1.7133 + 1.7134 + SetDOMStringToNull(aInputEncoding); 1.7135 +} 1.7136 + 1.7137 +NS_IMETHODIMP 1.7138 +nsDocument::GetMozSyntheticDocument(bool *aSyntheticDocument) 1.7139 +{ 1.7140 + *aSyntheticDocument = mIsSyntheticDocument; 1.7141 + return NS_OK; 1.7142 +} 1.7143 + 1.7144 +NS_IMETHODIMP 1.7145 +nsDocument::GetDocumentURI(nsAString& aDocumentURI) 1.7146 +{ 1.7147 + nsString temp; 1.7148 + nsIDocument::GetDocumentURI(temp); 1.7149 + aDocumentURI = temp; 1.7150 + return NS_OK; 1.7151 +} 1.7152 + 1.7153 +void 1.7154 +nsIDocument::GetDocumentURI(nsString& aDocumentURI) const 1.7155 +{ 1.7156 + if (mDocumentURI) { 1.7157 + nsAutoCString uri; 1.7158 + mDocumentURI->GetSpec(uri); 1.7159 + CopyUTF8toUTF16(uri, aDocumentURI); 1.7160 + } else { 1.7161 + aDocumentURI.Truncate(); 1.7162 + } 1.7163 +} 1.7164 + 1.7165 +// Alias of above 1.7166 +NS_IMETHODIMP 1.7167 +nsDocument::GetURL(nsAString& aURL) 1.7168 +{ 1.7169 + return GetDocumentURI(aURL); 1.7170 +} 1.7171 + 1.7172 +void 1.7173 +nsIDocument::GetURL(nsString& aURL) const 1.7174 +{ 1.7175 + return GetDocumentURI(aURL); 1.7176 +} 1.7177 + 1.7178 +void 1.7179 +nsIDocument::GetDocumentURIFromJS(nsString& aDocumentURI) const 1.7180 +{ 1.7181 + if (!mChromeXHRDocURI || !nsContentUtils::IsCallerChrome()) { 1.7182 + return GetDocumentURI(aDocumentURI); 1.7183 + } 1.7184 + 1.7185 + nsAutoCString uri; 1.7186 + mChromeXHRDocURI->GetSpec(uri); 1.7187 + CopyUTF8toUTF16(uri, aDocumentURI); 1.7188 +} 1.7189 + 1.7190 +nsIURI* 1.7191 +nsIDocument::GetDocumentURIObject() const 1.7192 +{ 1.7193 + if (!mChromeXHRDocURI) { 1.7194 + return GetDocumentURI(); 1.7195 + } 1.7196 + 1.7197 + return mChromeXHRDocURI; 1.7198 +} 1.7199 + 1.7200 + 1.7201 +// readonly attribute DOMString compatMode; 1.7202 +// Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are 1.7203 +// in almost standards or full standards mode. See bug 105640. This was 1.7204 +// implemented to match MSIE's compatMode property. 1.7205 +NS_IMETHODIMP 1.7206 +nsDocument::GetCompatMode(nsAString& aCompatMode) 1.7207 +{ 1.7208 + nsString temp; 1.7209 + nsIDocument::GetCompatMode(temp); 1.7210 + aCompatMode = temp; 1.7211 + return NS_OK; 1.7212 +} 1.7213 + 1.7214 +void 1.7215 +nsIDocument::GetCompatMode(nsString& aCompatMode) const 1.7216 +{ 1.7217 + NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks || 1.7218 + mCompatMode == eCompatibility_AlmostStandards || 1.7219 + mCompatMode == eCompatibility_FullStandards, 1.7220 + "mCompatMode is neither quirks nor strict for this document"); 1.7221 + 1.7222 + if (mCompatMode == eCompatibility_NavQuirks) { 1.7223 + aCompatMode.AssignLiteral("BackCompat"); 1.7224 + } else { 1.7225 + aCompatMode.AssignLiteral("CSS1Compat"); 1.7226 + } 1.7227 +} 1.7228 + 1.7229 +static void BlastSubtreeToPieces(nsINode *aNode); 1.7230 + 1.7231 +PLDHashOperator 1.7232 +BlastFunc(nsAttrHashKey::KeyType aKey, Attr *aData, void* aUserArg) 1.7233 +{ 1.7234 + nsCOMPtr<nsIAttribute> *attr = 1.7235 + static_cast<nsCOMPtr<nsIAttribute>*>(aUserArg); 1.7236 + 1.7237 + *attr = aData; 1.7238 + 1.7239 + NS_ASSERTION(attr->get(), 1.7240 + "non-nsIAttribute somehow made it into the hashmap?!"); 1.7241 + 1.7242 + return PL_DHASH_STOP; 1.7243 +} 1.7244 + 1.7245 +static void 1.7246 +BlastSubtreeToPieces(nsINode *aNode) 1.7247 +{ 1.7248 + if (aNode->IsElement()) { 1.7249 + Element *element = aNode->AsElement(); 1.7250 + const nsDOMAttributeMap *map = element->GetAttributeMap(); 1.7251 + if (map) { 1.7252 + nsCOMPtr<nsIAttribute> attr; 1.7253 + while (map->Enumerate(BlastFunc, &attr) > 0) { 1.7254 + BlastSubtreeToPieces(attr); 1.7255 + 1.7256 +#ifdef DEBUG 1.7257 + nsresult rv = 1.7258 +#endif 1.7259 + element->UnsetAttr(attr->NodeInfo()->NamespaceID(), 1.7260 + attr->NodeInfo()->NameAtom(), 1.7261 + false); 1.7262 + 1.7263 + // XXX Should we abort here? 1.7264 + NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, UnsetAttr shouldn't fail!"); 1.7265 + } 1.7266 + } 1.7267 + } 1.7268 + 1.7269 + uint32_t count = aNode->GetChildCount(); 1.7270 + for (uint32_t i = 0; i < count; ++i) { 1.7271 + BlastSubtreeToPieces(aNode->GetFirstChild()); 1.7272 + aNode->RemoveChildAt(0, false); 1.7273 + } 1.7274 +} 1.7275 + 1.7276 + 1.7277 +class nsUserDataCaller : public nsRunnable 1.7278 +{ 1.7279 +public: 1.7280 + nsUserDataCaller(nsCOMArray<nsINode>& aNodesWithProperties, 1.7281 + nsIDocument* aOwnerDoc) 1.7282 + : mNodesWithProperties(aNodesWithProperties), 1.7283 + mOwnerDoc(aOwnerDoc) 1.7284 + { 1.7285 + } 1.7286 + 1.7287 + NS_IMETHOD Run() 1.7288 + { 1.7289 + nsNodeUtils::CallUserDataHandlers(mNodesWithProperties, mOwnerDoc, 1.7290 + nsIDOMUserDataHandler::NODE_ADOPTED, 1.7291 + false); 1.7292 + return NS_OK; 1.7293 + } 1.7294 + 1.7295 +private: 1.7296 + nsCOMArray<nsINode> mNodesWithProperties; 1.7297 + nsCOMPtr<nsIDocument> mOwnerDoc; 1.7298 +}; 1.7299 + 1.7300 +NS_IMETHODIMP 1.7301 +nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) 1.7302 +{ 1.7303 + *aResult = nullptr; 1.7304 + 1.7305 + nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode); 1.7306 + NS_ENSURE_TRUE(adoptedNode, NS_ERROR_UNEXPECTED); 1.7307 + 1.7308 + ErrorResult rv; 1.7309 + nsINode* result = nsIDocument::AdoptNode(*adoptedNode, rv); 1.7310 + if (rv.Failed()) { 1.7311 + return rv.ErrorCode(); 1.7312 + } 1.7313 + 1.7314 + NS_ADDREF(*aResult = result->AsDOMNode()); 1.7315 + return NS_OK; 1.7316 +} 1.7317 + 1.7318 +nsINode* 1.7319 +nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv) 1.7320 +{ 1.7321 + nsINode* adoptedNode = &aAdoptedNode; 1.7322 + 1.7323 + // Scope firing mutation events so that we don't carry any state that 1.7324 + // might be stale 1.7325 + { 1.7326 + nsINode* parent = adoptedNode->GetParentNode(); 1.7327 + if (parent) { 1.7328 + nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent, 1.7329 + adoptedNode->OwnerDoc()); 1.7330 + } 1.7331 + } 1.7332 + 1.7333 + nsAutoScriptBlocker scriptBlocker; 1.7334 + 1.7335 + switch (adoptedNode->NodeType()) { 1.7336 + case nsIDOMNode::ATTRIBUTE_NODE: 1.7337 + { 1.7338 + // Remove from ownerElement. 1.7339 + nsRefPtr<Attr> adoptedAttr = static_cast<Attr*>(adoptedNode); 1.7340 + 1.7341 + nsCOMPtr<Element> ownerElement = adoptedAttr->GetOwnerElement(rv); 1.7342 + if (rv.Failed()) { 1.7343 + return nullptr; 1.7344 + } 1.7345 + 1.7346 + if (ownerElement) { 1.7347 + nsRefPtr<Attr> newAttr = 1.7348 + ownerElement->RemoveAttributeNode(*adoptedAttr, rv); 1.7349 + if (rv.Failed()) { 1.7350 + return nullptr; 1.7351 + } 1.7352 + 1.7353 + newAttr.swap(adoptedAttr); 1.7354 + } 1.7355 + 1.7356 + break; 1.7357 + } 1.7358 + case nsIDOMNode::DOCUMENT_FRAGMENT_NODE: 1.7359 + case nsIDOMNode::ELEMENT_NODE: 1.7360 + case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: 1.7361 + case nsIDOMNode::TEXT_NODE: 1.7362 + case nsIDOMNode::CDATA_SECTION_NODE: 1.7363 + case nsIDOMNode::COMMENT_NODE: 1.7364 + case nsIDOMNode::DOCUMENT_TYPE_NODE: 1.7365 + { 1.7366 + // Don't allow adopting a node's anonymous subtree out from under it. 1.7367 + if (adoptedNode->AsContent()->IsRootOfAnonymousSubtree()) { 1.7368 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.7369 + return nullptr; 1.7370 + } 1.7371 + 1.7372 + // We don't want to adopt an element into its own contentDocument or into 1.7373 + // a descendant contentDocument, so we check if the frameElement of this 1.7374 + // document or any of its parents is the adopted node or one of its 1.7375 + // descendants. 1.7376 + nsIDocument *doc = this; 1.7377 + do { 1.7378 + nsPIDOMWindow *win = doc->GetWindow(); 1.7379 + if (win) { 1.7380 + nsCOMPtr<nsINode> node = 1.7381 + do_QueryInterface(win->GetFrameElementInternal()); 1.7382 + if (node && 1.7383 + nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) { 1.7384 + rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.7385 + return nullptr; 1.7386 + } 1.7387 + } 1.7388 + } while ((doc = doc->GetParentDocument())); 1.7389 + 1.7390 + // Remove from parent. 1.7391 + nsCOMPtr<nsINode> parent = adoptedNode->GetParentNode(); 1.7392 + if (parent) { 1.7393 + int32_t idx = parent->IndexOf(adoptedNode); 1.7394 + MOZ_ASSERT(idx >= 0); 1.7395 + parent->RemoveChildAt(idx, true); 1.7396 + } else { 1.7397 + MOZ_ASSERT(!adoptedNode->IsInDoc()); 1.7398 + 1.7399 + // If we're adopting a node that's not in a document, it might still 1.7400 + // have a binding applied. Remove the binding from the element now 1.7401 + // that it's getting adopted into a new document. 1.7402 + // TODO Fully tear down the binding. 1.7403 + adoptedNode->AsContent()->SetXBLBinding(nullptr); 1.7404 + } 1.7405 + 1.7406 + break; 1.7407 + } 1.7408 + case nsIDOMNode::DOCUMENT_NODE: 1.7409 + { 1.7410 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.7411 + return nullptr; 1.7412 + } 1.7413 + default: 1.7414 + { 1.7415 + NS_WARNING("Don't know how to adopt this nodetype for adoptNode."); 1.7416 + 1.7417 + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.7418 + return nullptr; 1.7419 + } 1.7420 + } 1.7421 + 1.7422 + nsCOMPtr<nsIDocument> oldDocument = adoptedNode->OwnerDoc(); 1.7423 + bool sameDocument = oldDocument == this; 1.7424 + 1.7425 + AutoJSContext cx; 1.7426 + JS::Rooted<JSObject*> newScope(cx, nullptr); 1.7427 + if (!sameDocument) { 1.7428 + newScope = GetWrapper(); 1.7429 + if (!newScope && GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) { 1.7430 + // Make sure cx is in a semi-sane compartment before we call WrapNative. 1.7431 + // It's kind of irrelevant, given that we're passing aAllowWrapping = 1.7432 + // false, and documents should always insist on being wrapped in an 1.7433 + // canonical scope. But we try to pass something sane anyway. 1.7434 + JSAutoCompartment ac(cx, GetScopeObject()->GetGlobalJSObject()); 1.7435 + JS::Rooted<JS::Value> v(cx); 1.7436 + rv = nsContentUtils::WrapNative(cx, this, this, &v, 1.7437 + /* aAllowWrapping = */ false); 1.7438 + if (rv.Failed()) 1.7439 + return nullptr; 1.7440 + newScope = &v.toObject(); 1.7441 + } 1.7442 + } 1.7443 + 1.7444 + nsCOMArray<nsINode> nodesWithProperties; 1.7445 + rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager, 1.7446 + newScope, nodesWithProperties); 1.7447 + if (rv.Failed()) { 1.7448 + // Disconnect all nodes from their parents, since some have the old document 1.7449 + // as their ownerDocument and some have this as their ownerDocument. 1.7450 + BlastSubtreeToPieces(adoptedNode); 1.7451 + 1.7452 + if (!sameDocument && oldDocument) { 1.7453 + uint32_t count = nodesWithProperties.Count(); 1.7454 + for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) { 1.7455 + for (uint32_t i = 0; i < count; ++i) { 1.7456 + // Remove all properties. 1.7457 + oldDocument->PropertyTable(j)-> 1.7458 + DeleteAllPropertiesFor(nodesWithProperties[i]); 1.7459 + } 1.7460 + } 1.7461 + } 1.7462 + 1.7463 + return nullptr; 1.7464 + } 1.7465 + 1.7466 + uint32_t count = nodesWithProperties.Count(); 1.7467 + if (!sameDocument && oldDocument) { 1.7468 + for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) { 1.7469 + nsPropertyTable *oldTable = oldDocument->PropertyTable(j); 1.7470 + nsPropertyTable *newTable = PropertyTable(j); 1.7471 + for (uint32_t i = 0; i < count; ++i) { 1.7472 + rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i], 1.7473 + newTable); 1.7474 + } 1.7475 + } 1.7476 + 1.7477 + if (rv.Failed()) { 1.7478 + // Disconnect all nodes from their parents. 1.7479 + BlastSubtreeToPieces(adoptedNode); 1.7480 + 1.7481 + return nullptr; 1.7482 + } 1.7483 + } 1.7484 + 1.7485 + if (nodesWithProperties.Count()) { 1.7486 + nsContentUtils::AddScriptRunner(new nsUserDataCaller(nodesWithProperties, 1.7487 + this)); 1.7488 + } 1.7489 + 1.7490 + NS_ASSERTION(adoptedNode->OwnerDoc() == this, 1.7491 + "Should still be in the document we just got adopted into"); 1.7492 + 1.7493 + return adoptedNode; 1.7494 +} 1.7495 + 1.7496 +nsViewportInfo 1.7497 +nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize) 1.7498 +{ 1.7499 + // In cases where the width of the CSS viewport is less than or equal to the width 1.7500 + // of the display (i.e. width <= device-width) then we disable double-tap-to-zoom 1.7501 + // behaviour. See bug 941995 for details. 1.7502 + 1.7503 + switch (mViewportType) { 1.7504 + case DisplayWidthHeight: 1.7505 + return nsViewportInfo(aDisplaySize); 1.7506 + case DisplayWidthHeightNoZoom: 1.7507 + return nsViewportInfo(aDisplaySize, /*allowZoom*/ false, /*allowDoubleTapZoom*/ false); 1.7508 + case Unknown: 1.7509 + { 1.7510 + nsAutoString viewport; 1.7511 + GetHeaderData(nsGkAtoms::viewport, viewport); 1.7512 + if (viewport.IsEmpty()) { 1.7513 + // If the docType specifies that we are on a site optimized for mobile, 1.7514 + // then we want to return specially crafted defaults for the viewport info. 1.7515 + nsCOMPtr<nsIDOMDocumentType> docType; 1.7516 + nsresult rv = GetDoctype(getter_AddRefs(docType)); 1.7517 + if (NS_SUCCEEDED(rv) && docType) { 1.7518 + nsAutoString docId; 1.7519 + rv = docType->GetPublicId(docId); 1.7520 + if (NS_SUCCEEDED(rv)) { 1.7521 + if ((docId.Find("WAP") != -1) || 1.7522 + (docId.Find("Mobile") != -1) || 1.7523 + (docId.Find("WML") != -1)) 1.7524 + { 1.7525 + // We're making an assumption that the docType can't change here 1.7526 + mViewportType = DisplayWidthHeight; 1.7527 + return nsViewportInfo(aDisplaySize, /*allowZoom*/true, /*allowDoubleTapZoom*/false); 1.7528 + } 1.7529 + } 1.7530 + } 1.7531 + 1.7532 + nsAutoString handheldFriendly; 1.7533 + GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly); 1.7534 + if (handheldFriendly.EqualsLiteral("true")) { 1.7535 + mViewportType = DisplayWidthHeight; 1.7536 + return nsViewportInfo(aDisplaySize, /*allowZoom*/true, /*allowDoubleTapZoom*/false); 1.7537 + } 1.7538 + 1.7539 + // Bug 940036. This is bad. When FirefoxOS was built, apps installed 1.7540 + // where not using the AsyncPanZoom code. As a result a lot of apps 1.7541 + // in the marketplace does not use it yet and instead are built to 1.7542 + // render correctly in FirefoxOS only. For a smooth transition the above 1.7543 + // code force installed apps to render as if they have a viewport with 1.7544 + // content="width=device-width, height=device-height, user-scalable=no". 1.7545 + // This could be safely remove once it is known that most apps in the 1.7546 + // marketplace use it and that users does not use an old version of the 1.7547 + // app that does not use it. 1.7548 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.7549 + if (docShell && docShell->GetIsApp()) { 1.7550 + nsString uri; 1.7551 + GetDocumentURI(uri); 1.7552 + if (!uri.EqualsLiteral("about:blank")) { 1.7553 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.7554 + NS_LITERAL_CSTRING("DOM"), this, 1.7555 + nsContentUtils::eDOM_PROPERTIES, 1.7556 + "ImplicitMetaViewportTagFallback"); 1.7557 + } 1.7558 + mViewportType = DisplayWidthHeightNoZoom; 1.7559 + return nsViewportInfo(aDisplaySize, /*allowZoom*/false, /*allowDoubleTapZoom*/false); 1.7560 + } 1.7561 + } 1.7562 + 1.7563 + nsAutoString minScaleStr; 1.7564 + GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr); 1.7565 + 1.7566 + nsresult errorCode; 1.7567 + mScaleMinFloat = LayoutDeviceToScreenScale(minScaleStr.ToFloat(&errorCode)); 1.7568 + 1.7569 + if (NS_FAILED(errorCode)) { 1.7570 + mScaleMinFloat = kViewportMinScale; 1.7571 + } 1.7572 + 1.7573 + mScaleMinFloat = mozilla::clamped( 1.7574 + mScaleMinFloat, kViewportMinScale, kViewportMaxScale); 1.7575 + 1.7576 + nsAutoString maxScaleStr; 1.7577 + GetHeaderData(nsGkAtoms::viewport_maximum_scale, maxScaleStr); 1.7578 + 1.7579 + // We define a special error code variable for the scale and max scale, 1.7580 + // because they are used later (see the width calculations). 1.7581 + nsresult scaleMaxErrorCode; 1.7582 + mScaleMaxFloat = LayoutDeviceToScreenScale(maxScaleStr.ToFloat(&scaleMaxErrorCode)); 1.7583 + 1.7584 + if (NS_FAILED(scaleMaxErrorCode)) { 1.7585 + mScaleMaxFloat = kViewportMaxScale; 1.7586 + } 1.7587 + 1.7588 + mScaleMaxFloat = mozilla::clamped( 1.7589 + mScaleMaxFloat, kViewportMinScale, kViewportMaxScale); 1.7590 + 1.7591 + nsAutoString scaleStr; 1.7592 + GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr); 1.7593 + 1.7594 + nsresult scaleErrorCode; 1.7595 + mScaleFloat = LayoutDeviceToScreenScale(scaleStr.ToFloat(&scaleErrorCode)); 1.7596 + 1.7597 + nsAutoString widthStr, heightStr; 1.7598 + 1.7599 + GetHeaderData(nsGkAtoms::viewport_height, heightStr); 1.7600 + GetHeaderData(nsGkAtoms::viewport_width, widthStr); 1.7601 + 1.7602 + mAutoSize = false; 1.7603 + 1.7604 + if (widthStr.EqualsLiteral("device-width")) { 1.7605 + mAutoSize = true; 1.7606 + } 1.7607 + 1.7608 + if (widthStr.IsEmpty() && 1.7609 + (heightStr.EqualsLiteral("device-height") || 1.7610 + (mScaleFloat.scale == 1.0))) 1.7611 + { 1.7612 + mAutoSize = true; 1.7613 + } 1.7614 + 1.7615 + nsresult widthErrorCode, heightErrorCode; 1.7616 + mViewportSize.width = widthStr.ToInteger(&widthErrorCode); 1.7617 + mViewportSize.height = heightStr.ToInteger(&heightErrorCode); 1.7618 + 1.7619 + // If width or height has not been set to a valid number by this point, 1.7620 + // fall back to a default value. 1.7621 + mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportSize.width > 0); 1.7622 + mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportSize.height > 0); 1.7623 + 1.7624 + mAllowZoom = true; 1.7625 + nsAutoString userScalable; 1.7626 + GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable); 1.7627 + 1.7628 + if ((userScalable.EqualsLiteral("0")) || 1.7629 + (userScalable.EqualsLiteral("no")) || 1.7630 + (userScalable.EqualsLiteral("false"))) { 1.7631 + mAllowZoom = false; 1.7632 + } 1.7633 + mAllowDoubleTapZoom = mAllowZoom; 1.7634 + 1.7635 + mScaleStrEmpty = scaleStr.IsEmpty(); 1.7636 + mWidthStrEmpty = widthStr.IsEmpty(); 1.7637 + mValidScaleFloat = !scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode); 1.7638 + mValidMaxScale = !maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode); 1.7639 + 1.7640 + mViewportType = Specified; 1.7641 + } 1.7642 + case Specified: 1.7643 + default: 1.7644 + CSSIntSize size = mViewportSize; 1.7645 + 1.7646 + if (!mValidWidth) { 1.7647 + if (mValidHeight && !aDisplaySize.IsEmpty()) { 1.7648 + size.width = int32_t(size.height * aDisplaySize.width / aDisplaySize.height); 1.7649 + } else { 1.7650 + size.width = Preferences::GetInt("browser.viewport.desktopWidth", 1.7651 + kViewportDefaultScreenWidth); 1.7652 + } 1.7653 + } 1.7654 + 1.7655 + if (!mValidHeight) { 1.7656 + if (!aDisplaySize.IsEmpty()) { 1.7657 + size.height = int32_t(size.width * aDisplaySize.height / aDisplaySize.width); 1.7658 + } else { 1.7659 + size.height = size.width; 1.7660 + } 1.7661 + } 1.7662 + // Now convert the scale into device pixels per CSS pixel. 1.7663 + nsIWidget *widget = nsContentUtils::WidgetForDocument(this); 1.7664 + CSSToLayoutDeviceScale pixelRatio = widget ? widget->GetDefaultScale() 1.7665 + : CSSToLayoutDeviceScale(1.0f); 1.7666 + CSSToScreenScale scaleFloat = mScaleFloat * pixelRatio; 1.7667 + CSSToScreenScale scaleMinFloat = mScaleMinFloat * pixelRatio; 1.7668 + CSSToScreenScale scaleMaxFloat = mScaleMaxFloat * pixelRatio; 1.7669 + 1.7670 + if (mAutoSize) { 1.7671 + // aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size. 1.7672 + CSSToScreenScale defaultPixelScale = pixelRatio * LayoutDeviceToScreenScale(1.0f); 1.7673 + size = mozilla::gfx::RoundedToInt(ScreenSize(aDisplaySize) / defaultPixelScale); 1.7674 + } 1.7675 + 1.7676 + size.width = clamped(size.width, kViewportMinSize.width, kViewportMaxSize.width); 1.7677 + 1.7678 + // Also recalculate the default zoom, if it wasn't specified in the metadata, 1.7679 + // and the width is specified. 1.7680 + if (mScaleStrEmpty && !mWidthStrEmpty) { 1.7681 + CSSToScreenScale defaultScale(float(aDisplaySize.width) / float(size.width)); 1.7682 + scaleFloat = (scaleFloat > defaultScale) ? scaleFloat : defaultScale; 1.7683 + } 1.7684 + 1.7685 + size.height = clamped(size.height, kViewportMinSize.height, kViewportMaxSize.height); 1.7686 + 1.7687 + // We need to perform a conversion, but only if the initial or maximum 1.7688 + // scale were set explicitly by the user. 1.7689 + if (mValidScaleFloat) { 1.7690 + CSSIntSize displaySize = RoundedToInt(ScreenSize(aDisplaySize) / scaleFloat); 1.7691 + size.width = std::max(size.width, displaySize.width); 1.7692 + size.height = std::max(size.height, displaySize.height); 1.7693 + } else if (mValidMaxScale) { 1.7694 + CSSIntSize displaySize = RoundedToInt(ScreenSize(aDisplaySize) / scaleMaxFloat); 1.7695 + size.width = std::max(size.width, displaySize.width); 1.7696 + size.height = std::max(size.height, displaySize.height); 1.7697 + } 1.7698 + 1.7699 + return nsViewportInfo(scaleFloat, scaleMinFloat, scaleMaxFloat, size, 1.7700 + mAutoSize, mAllowZoom, mAllowDoubleTapZoom); 1.7701 + } 1.7702 +} 1.7703 + 1.7704 +EventListenerManager* 1.7705 +nsDocument::GetOrCreateListenerManager() 1.7706 +{ 1.7707 + if (!mListenerManager) { 1.7708 + mListenerManager = 1.7709 + new EventListenerManager(static_cast<EventTarget*>(this)); 1.7710 + SetFlags(NODE_HAS_LISTENERMANAGER); 1.7711 + } 1.7712 + 1.7713 + return mListenerManager; 1.7714 +} 1.7715 + 1.7716 +EventListenerManager* 1.7717 +nsDocument::GetExistingListenerManager() const 1.7718 +{ 1.7719 + return mListenerManager; 1.7720 +} 1.7721 + 1.7722 +nsresult 1.7723 +nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.7724 +{ 1.7725 + aVisitor.mCanHandle = true; 1.7726 + // FIXME! This is a hack to make middle mouse paste working also in Editor. 1.7727 + // Bug 329119 1.7728 + aVisitor.mForceContentDispatch = true; 1.7729 + 1.7730 + // Load events must not propagate to |window| object, see bug 335251. 1.7731 + if (aVisitor.mEvent->message != NS_LOAD) { 1.7732 + nsGlobalWindow* window = static_cast<nsGlobalWindow*>(GetWindow()); 1.7733 + aVisitor.mParentTarget = 1.7734 + window ? window->GetTargetForEventTargetChain() : nullptr; 1.7735 + } 1.7736 + return NS_OK; 1.7737 +} 1.7738 + 1.7739 +NS_IMETHODIMP 1.7740 +nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn) 1.7741 +{ 1.7742 + NS_ENSURE_ARG_POINTER(aReturn); 1.7743 + ErrorResult rv; 1.7744 + *aReturn = nsIDocument::CreateEvent(aEventType, rv).take(); 1.7745 + return rv.ErrorCode(); 1.7746 +} 1.7747 + 1.7748 +already_AddRefed<Event> 1.7749 +nsIDocument::CreateEvent(const nsAString& aEventType, ErrorResult& rv) const 1.7750 +{ 1.7751 + nsIPresShell *shell = GetShell(); 1.7752 + 1.7753 + nsPresContext *presContext = nullptr; 1.7754 + 1.7755 + if (shell) { 1.7756 + // Retrieve the context 1.7757 + presContext = shell->GetPresContext(); 1.7758 + } 1.7759 + 1.7760 + // Create event even without presContext. 1.7761 + nsCOMPtr<nsIDOMEvent> ev; 1.7762 + rv = EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this), 1.7763 + presContext, nullptr, aEventType, 1.7764 + getter_AddRefs(ev)); 1.7765 + if (!ev) { 1.7766 + return nullptr; 1.7767 + } 1.7768 + WidgetEvent* e = ev->GetInternalNSEvent(); 1.7769 + e->mFlags.mBubbles = false; 1.7770 + e->mFlags.mCancelable = false; 1.7771 + return dont_AddRef(ev.forget().take()->InternalDOMEvent()); 1.7772 +} 1.7773 + 1.7774 +void 1.7775 +nsDocument::FlushPendingNotifications(mozFlushType aType) 1.7776 +{ 1.7777 + nsDocumentOnStack dos(this); 1.7778 + 1.7779 + // We need to flush the sink for non-HTML documents (because the XML 1.7780 + // parser still does insertion with deferred notifications). We 1.7781 + // also need to flush the sink if this is a layout-related flush, to 1.7782 + // make sure that layout is started as needed. But we can skip that 1.7783 + // part if we have no presshell or if it's already done an initial 1.7784 + // reflow. 1.7785 + if ((!IsHTML() || 1.7786 + (aType > Flush_ContentAndNotify && mPresShell && 1.7787 + !mPresShell->DidInitialize())) && 1.7788 + (mParser || mWeakSink)) { 1.7789 + nsCOMPtr<nsIContentSink> sink; 1.7790 + if (mParser) { 1.7791 + sink = mParser->GetContentSink(); 1.7792 + } else { 1.7793 + sink = do_QueryReferent(mWeakSink); 1.7794 + if (!sink) { 1.7795 + mWeakSink = nullptr; 1.7796 + } 1.7797 + } 1.7798 + // Determine if it is safe to flush the sink notifications 1.7799 + // by determining if it safe to flush all the presshells. 1.7800 + if (sink && (aType == Flush_Content || IsSafeToFlush())) { 1.7801 + sink->FlushPendingNotifications(aType); 1.7802 + } 1.7803 + } 1.7804 + 1.7805 + // Should we be flushing pending binding constructors in here? 1.7806 + 1.7807 + if (aType <= Flush_ContentAndNotify) { 1.7808 + // Nothing to do here 1.7809 + return; 1.7810 + } 1.7811 + 1.7812 + // If we have a parent we must flush the parent too to ensure that our 1.7813 + // container is reflowed if its size was changed. But if it's not safe to 1.7814 + // flush ourselves, then don't flush the parent, since that can cause things 1.7815 + // like resizes of our frame's widget, which we can't handle while flushing 1.7816 + // is unsafe. 1.7817 + // Since media queries mean that a size change of our container can 1.7818 + // affect style, we need to promote a style flush on ourself to a 1.7819 + // layout flush on our parent, since we need our container to be the 1.7820 + // correct size to determine the correct style. 1.7821 + if (mParentDocument && IsSafeToFlush()) { 1.7822 + mozFlushType parentType = aType; 1.7823 + if (aType >= Flush_Style) 1.7824 + parentType = std::max(Flush_Layout, aType); 1.7825 + mParentDocument->FlushPendingNotifications(parentType); 1.7826 + } 1.7827 + 1.7828 + // We can optimize away getting our presshell and calling 1.7829 + // FlushPendingNotifications on it if we don't need a flush of the sort we're 1.7830 + // looking at. The one exception is if mInFlush is true, because in that 1.7831 + // case we might have set mNeedStyleFlush and mNeedLayoutFlush to false 1.7832 + // already but the presshell hasn't actually done the corresponding work yet. 1.7833 + // So if mInFlush and reentering this code, we need to flush the presshell. 1.7834 + if (mNeedStyleFlush || 1.7835 + (mNeedLayoutFlush && aType >= Flush_InterruptibleLayout) || 1.7836 + aType >= Flush_Display || 1.7837 + mInFlush) { 1.7838 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.7839 + if (shell) { 1.7840 + mNeedStyleFlush = false; 1.7841 + mNeedLayoutFlush = mNeedLayoutFlush && (aType < Flush_InterruptibleLayout); 1.7842 + // mInFlush is a bitfield, so can't us AutoRestore here. But we 1.7843 + // need to keep track of multi-level reentry correctly, so need 1.7844 + // to restore the old mInFlush value. 1.7845 + bool oldInFlush = mInFlush; 1.7846 + mInFlush = true; 1.7847 + shell->FlushPendingNotifications(aType); 1.7848 + mInFlush = oldInFlush; 1.7849 + } 1.7850 + } 1.7851 +} 1.7852 + 1.7853 +static bool 1.7854 +Copy(nsIDocument* aDocument, void* aData) 1.7855 +{ 1.7856 + nsTArray<nsCOMPtr<nsIDocument> >* resources = 1.7857 + static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData); 1.7858 + resources->AppendElement(aDocument); 1.7859 + return true; 1.7860 +} 1.7861 + 1.7862 +void 1.7863 +nsDocument::FlushExternalResources(mozFlushType aType) 1.7864 +{ 1.7865 + NS_ASSERTION(aType >= Flush_Style, 1.7866 + "should only need to flush for style or higher in external resources"); 1.7867 + if (GetDisplayDocument()) { 1.7868 + return; 1.7869 + } 1.7870 + nsTArray<nsCOMPtr<nsIDocument> > resources; 1.7871 + EnumerateExternalResources(Copy, &resources); 1.7872 + 1.7873 + for (uint32_t i = 0; i < resources.Length(); i++) { 1.7874 + resources[i]->FlushPendingNotifications(aType); 1.7875 + } 1.7876 +} 1.7877 + 1.7878 +void 1.7879 +nsDocument::SetXMLDeclaration(const char16_t *aVersion, 1.7880 + const char16_t *aEncoding, 1.7881 + const int32_t aStandalone) 1.7882 +{ 1.7883 + if (!aVersion || *aVersion == '\0') { 1.7884 + mXMLDeclarationBits = 0; 1.7885 + return; 1.7886 + } 1.7887 + 1.7888 + mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS; 1.7889 + 1.7890 + if (aEncoding && *aEncoding != '\0') { 1.7891 + mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS; 1.7892 + } 1.7893 + 1.7894 + if (aStandalone == 1) { 1.7895 + mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS | 1.7896 + XML_DECLARATION_BITS_STANDALONE_YES; 1.7897 + } 1.7898 + else if (aStandalone == 0) { 1.7899 + mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS; 1.7900 + } 1.7901 +} 1.7902 + 1.7903 +void 1.7904 +nsDocument::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding, 1.7905 + nsAString& aStandalone) 1.7906 +{ 1.7907 + aVersion.Truncate(); 1.7908 + aEncoding.Truncate(); 1.7909 + aStandalone.Truncate(); 1.7910 + 1.7911 + if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) { 1.7912 + return; 1.7913 + } 1.7914 + 1.7915 + // always until we start supporting 1.1 etc. 1.7916 + aVersion.AssignLiteral("1.0"); 1.7917 + 1.7918 + if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) { 1.7919 + // This is what we have stored, not necessarily what was written 1.7920 + // in the original 1.7921 + GetCharacterSet(aEncoding); 1.7922 + } 1.7923 + 1.7924 + if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) { 1.7925 + if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) { 1.7926 + aStandalone.AssignLiteral("yes"); 1.7927 + } else { 1.7928 + aStandalone.AssignLiteral("no"); 1.7929 + } 1.7930 + } 1.7931 +} 1.7932 + 1.7933 +bool 1.7934 +nsDocument::IsScriptEnabled() 1.7935 +{ 1.7936 + // If this document is sandboxed without 'allow-scripts' 1.7937 + // script is not enabled 1.7938 + if (mSandboxFlags & SANDBOXED_SCRIPTS) { 1.7939 + return false; 1.7940 + } 1.7941 + 1.7942 + nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); 1.7943 + NS_ENSURE_TRUE(sm, false); 1.7944 + 1.7945 + nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow()); 1.7946 + NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), false); 1.7947 + 1.7948 + return sm->ScriptAllowed(globalObject->GetGlobalJSObject()); 1.7949 +} 1.7950 + 1.7951 +nsRadioGroupStruct* 1.7952 +nsDocument::GetRadioGroupInternal(const nsAString& aName) const 1.7953 +{ 1.7954 +#ifdef DEBUG 1.7955 + if (IsHTML()) { 1.7956 + nsAutoString lcName; 1.7957 + ToLowerCase(aName, lcName); 1.7958 + MOZ_ASSERT(aName == lcName); 1.7959 + } 1.7960 +#endif 1.7961 + 1.7962 + nsRadioGroupStruct* radioGroup; 1.7963 + if (!mRadioGroups.Get(aName, &radioGroup)) { 1.7964 + return nullptr; 1.7965 + } 1.7966 + 1.7967 + return radioGroup; 1.7968 +} 1.7969 + 1.7970 +nsRadioGroupStruct* 1.7971 +nsDocument::GetRadioGroup(const nsAString& aName) const 1.7972 +{ 1.7973 + nsAutoString tmKey(aName); 1.7974 + if (IsHTML()) { 1.7975 + ToLowerCase(tmKey); //should case-insensitive. 1.7976 + } 1.7977 + 1.7978 + return GetRadioGroupInternal(tmKey); 1.7979 +} 1.7980 + 1.7981 +nsRadioGroupStruct* 1.7982 +nsDocument::GetOrCreateRadioGroup(const nsAString& aName) 1.7983 +{ 1.7984 + nsAutoString tmKey(aName); 1.7985 + if (IsHTML()) { 1.7986 + ToLowerCase(tmKey); //should case-insensitive. 1.7987 + } 1.7988 + 1.7989 + if (nsRadioGroupStruct* radioGroup = GetRadioGroupInternal(tmKey)) { 1.7990 + return radioGroup; 1.7991 + } 1.7992 + 1.7993 + nsAutoPtr<nsRadioGroupStruct> newRadioGroup(new nsRadioGroupStruct()); 1.7994 + mRadioGroups.Put(tmKey, newRadioGroup); 1.7995 + 1.7996 + return newRadioGroup.forget(); 1.7997 +} 1.7998 + 1.7999 +void 1.8000 +nsDocument::SetCurrentRadioButton(const nsAString& aName, 1.8001 + HTMLInputElement* aRadio) 1.8002 +{ 1.8003 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8004 + radioGroup->mSelectedRadioButton = aRadio; 1.8005 +} 1.8006 + 1.8007 +HTMLInputElement* 1.8008 +nsDocument::GetCurrentRadioButton(const nsAString& aName) 1.8009 +{ 1.8010 + return GetOrCreateRadioGroup(aName)->mSelectedRadioButton; 1.8011 +} 1.8012 + 1.8013 +NS_IMETHODIMP 1.8014 +nsDocument::GetNextRadioButton(const nsAString& aName, 1.8015 + const bool aPrevious, 1.8016 + HTMLInputElement* aFocusedRadio, 1.8017 + HTMLInputElement** aRadioOut) 1.8018 +{ 1.8019 + // XXX Can we combine the HTML radio button method impls of 1.8020 + // nsDocument and nsHTMLFormControl? 1.8021 + // XXX Why is HTML radio button stuff in nsDocument, as 1.8022 + // opposed to nsHTMLDocument? 1.8023 + *aRadioOut = nullptr; 1.8024 + 1.8025 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8026 + 1.8027 + // Return the radio button relative to the focused radio button. 1.8028 + // If no radio is focused, get the radio relative to the selected one. 1.8029 + nsRefPtr<HTMLInputElement> currentRadio; 1.8030 + if (aFocusedRadio) { 1.8031 + currentRadio = aFocusedRadio; 1.8032 + } 1.8033 + else { 1.8034 + currentRadio = radioGroup->mSelectedRadioButton; 1.8035 + if (!currentRadio) { 1.8036 + return NS_ERROR_FAILURE; 1.8037 + } 1.8038 + } 1.8039 + int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio); 1.8040 + if (index < 0) { 1.8041 + return NS_ERROR_FAILURE; 1.8042 + } 1.8043 + 1.8044 + int32_t numRadios = radioGroup->mRadioButtons.Count(); 1.8045 + nsRefPtr<HTMLInputElement> radio; 1.8046 + do { 1.8047 + if (aPrevious) { 1.8048 + if (--index < 0) { 1.8049 + index = numRadios -1; 1.8050 + } 1.8051 + } 1.8052 + else if (++index >= numRadios) { 1.8053 + index = 0; 1.8054 + } 1.8055 + NS_ASSERTION(static_cast<nsGenericHTMLFormElement*>(radioGroup->mRadioButtons[index])->IsHTML(nsGkAtoms::input), 1.8056 + "mRadioButtons holding a non-radio button"); 1.8057 + radio = static_cast<HTMLInputElement*>(radioGroup->mRadioButtons[index]); 1.8058 + } while (radio->Disabled() && radio != currentRadio); 1.8059 + 1.8060 + radio.forget(aRadioOut); 1.8061 + return NS_OK; 1.8062 +} 1.8063 + 1.8064 +void 1.8065 +nsDocument::AddToRadioGroup(const nsAString& aName, 1.8066 + nsIFormControl* aRadio) 1.8067 +{ 1.8068 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8069 + radioGroup->mRadioButtons.AppendObject(aRadio); 1.8070 + 1.8071 + nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio); 1.8072 + NS_ASSERTION(element, "radio controls have to be content elements"); 1.8073 + if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) { 1.8074 + radioGroup->mRequiredRadioCount++; 1.8075 + } 1.8076 +} 1.8077 + 1.8078 +void 1.8079 +nsDocument::RemoveFromRadioGroup(const nsAString& aName, 1.8080 + nsIFormControl* aRadio) 1.8081 +{ 1.8082 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8083 + radioGroup->mRadioButtons.RemoveObject(aRadio); 1.8084 + 1.8085 + nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio); 1.8086 + NS_ASSERTION(element, "radio controls have to be content elements"); 1.8087 + if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) { 1.8088 + NS_ASSERTION(radioGroup->mRequiredRadioCount != 0, 1.8089 + "mRequiredRadioCount about to wrap below 0!"); 1.8090 + radioGroup->mRequiredRadioCount--; 1.8091 + } 1.8092 +} 1.8093 + 1.8094 +NS_IMETHODIMP 1.8095 +nsDocument::WalkRadioGroup(const nsAString& aName, 1.8096 + nsIRadioVisitor* aVisitor, 1.8097 + bool aFlushContent) 1.8098 +{ 1.8099 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8100 + 1.8101 + for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) { 1.8102 + if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) { 1.8103 + return NS_OK; 1.8104 + } 1.8105 + } 1.8106 + 1.8107 + return NS_OK; 1.8108 +} 1.8109 + 1.8110 +uint32_t 1.8111 +nsDocument::GetRequiredRadioCount(const nsAString& aName) const 1.8112 +{ 1.8113 + nsRadioGroupStruct* radioGroup = GetRadioGroup(aName); 1.8114 + return radioGroup ? radioGroup->mRequiredRadioCount : 0; 1.8115 +} 1.8116 + 1.8117 +void 1.8118 +nsDocument::RadioRequiredChanged(const nsAString& aName, nsIFormControl* aRadio) 1.8119 +{ 1.8120 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8121 + 1.8122 + nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio); 1.8123 + NS_ASSERTION(element, "radio controls have to be content elements"); 1.8124 + if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) { 1.8125 + radioGroup->mRequiredRadioCount++; 1.8126 + } else { 1.8127 + NS_ASSERTION(radioGroup->mRequiredRadioCount != 0, 1.8128 + "mRequiredRadioCount about to wrap below 0!"); 1.8129 + radioGroup->mRequiredRadioCount--; 1.8130 + } 1.8131 +} 1.8132 + 1.8133 +bool 1.8134 +nsDocument::GetValueMissingState(const nsAString& aName) const 1.8135 +{ 1.8136 + nsRadioGroupStruct* radioGroup = GetRadioGroup(aName); 1.8137 + return radioGroup && radioGroup->mGroupSuffersFromValueMissing; 1.8138 +} 1.8139 + 1.8140 +void 1.8141 +nsDocument::SetValueMissingState(const nsAString& aName, bool aValue) 1.8142 +{ 1.8143 + nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName); 1.8144 + radioGroup->mGroupSuffersFromValueMissing = aValue; 1.8145 +} 1.8146 + 1.8147 +void 1.8148 +nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel) 1.8149 +{ 1.8150 + nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); 1.8151 + PRTime modDate = 0; 1.8152 + nsresult rv; 1.8153 + 1.8154 + if (httpChannel) { 1.8155 + nsAutoCString tmp; 1.8156 + rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), 1.8157 + tmp); 1.8158 + 1.8159 + if (NS_SUCCEEDED(rv)) { 1.8160 + PRTime time; 1.8161 + PRStatus st = PR_ParseTimeString(tmp.get(), true, &time); 1.8162 + if (st == PR_SUCCESS) { 1.8163 + modDate = time; 1.8164 + } 1.8165 + } 1.8166 + 1.8167 + // The misspelled key 'referer' is as per the HTTP spec 1.8168 + rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("referer"), 1.8169 + mReferrer); 1.8170 + if (NS_FAILED(rv)) { 1.8171 + mReferrer.Truncate(); 1.8172 + } 1.8173 + 1.8174 + static const char *const headers[] = { 1.8175 + "default-style", 1.8176 + "content-style-type", 1.8177 + "content-language", 1.8178 + "content-disposition", 1.8179 + "refresh", 1.8180 + "x-dns-prefetch-control", 1.8181 + "x-frame-options", 1.8182 + // add more http headers if you need 1.8183 + // XXXbz don't add content-location support without reading bug 1.8184 + // 238654 and its dependencies/dups first. 1.8185 + 0 1.8186 + }; 1.8187 + 1.8188 + nsAutoCString headerVal; 1.8189 + const char *const *name = headers; 1.8190 + while (*name) { 1.8191 + rv = 1.8192 + httpChannel->GetResponseHeader(nsDependentCString(*name), headerVal); 1.8193 + if (NS_SUCCEEDED(rv) && !headerVal.IsEmpty()) { 1.8194 + nsCOMPtr<nsIAtom> key = do_GetAtom(*name); 1.8195 + SetHeaderData(key, NS_ConvertASCIItoUTF16(headerVal)); 1.8196 + } 1.8197 + ++name; 1.8198 + } 1.8199 + } else { 1.8200 + nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(aChannel); 1.8201 + if (fileChannel) { 1.8202 + nsCOMPtr<nsIFile> file; 1.8203 + fileChannel->GetFile(getter_AddRefs(file)); 1.8204 + if (file) { 1.8205 + PRTime msecs; 1.8206 + rv = file->GetLastModifiedTime(&msecs); 1.8207 + 1.8208 + if (NS_SUCCEEDED(rv)) { 1.8209 + modDate = msecs * int64_t(PR_USEC_PER_MSEC); 1.8210 + } 1.8211 + } 1.8212 + } else { 1.8213 + nsAutoCString contentDisp; 1.8214 + rv = aChannel->GetContentDispositionHeader(contentDisp); 1.8215 + if (NS_SUCCEEDED(rv)) { 1.8216 + SetHeaderData(nsGkAtoms::headerContentDisposition, 1.8217 + NS_ConvertASCIItoUTF16(contentDisp)); 1.8218 + } 1.8219 + } 1.8220 + } 1.8221 + 1.8222 + if (modDate == 0) { 1.8223 + // We got nothing from our attempt to ask nsIFileChannel and 1.8224 + // nsIHttpChannel for the last modified time. Return the current 1.8225 + // time. 1.8226 + modDate = PR_Now(); 1.8227 + } 1.8228 + 1.8229 + mLastModified.Truncate(); 1.8230 + if (modDate != 0) { 1.8231 + PRExplodedTime prtime; 1.8232 + PR_ExplodeTime(modDate, PR_LocalTimeParameters, &prtime); 1.8233 + // "MM/DD/YYYY hh:mm:ss" 1.8234 + char formatedTime[24]; 1.8235 + if (PR_snprintf(formatedTime, sizeof(formatedTime), 1.8236 + "%02ld/%02ld/%04hd %02ld:%02ld:%02ld", 1.8237 + prtime.tm_month + 1, prtime.tm_mday, prtime.tm_year, 1.8238 + prtime.tm_hour , prtime.tm_min, prtime.tm_sec)) { 1.8239 + CopyASCIItoUTF16(nsDependentCString(formatedTime), mLastModified); 1.8240 + } 1.8241 + } 1.8242 +} 1.8243 + 1.8244 +nsresult 1.8245 +nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix, int32_t aNamespaceID, 1.8246 + nsIContent **aResult) 1.8247 +{ 1.8248 +#ifdef DEBUG 1.8249 + nsAutoString qName; 1.8250 + if (aPrefix) { 1.8251 + aPrefix->ToString(qName); 1.8252 + qName.Append(':'); 1.8253 + } 1.8254 + qName.Append(aName); 1.8255 + 1.8256 + // Note: "a:b:c" is a valid name in non-namespaces XML, and 1.8257 + // nsDocument::CreateElement can call us with such a name and no prefix, 1.8258 + // which would cause an error if we just used true here. 1.8259 + bool nsAware = aPrefix != nullptr || aNamespaceID != GetDefaultNamespaceID(); 1.8260 + NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName, nsAware)), 1.8261 + "Don't pass invalid prefixes to nsDocument::CreateElem, " 1.8262 + "check caller."); 1.8263 +#endif 1.8264 + 1.8265 + *aResult = nullptr; 1.8266 + 1.8267 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.8268 + mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID, 1.8269 + nsIDOMNode::ELEMENT_NODE, 1.8270 + getter_AddRefs(nodeInfo)); 1.8271 + NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY); 1.8272 + 1.8273 + nsCOMPtr<Element> element; 1.8274 + nsresult rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), 1.8275 + NOT_FROM_PARSER); 1.8276 + element.forget(aResult); 1.8277 + return rv; 1.8278 +} 1.8279 + 1.8280 +bool 1.8281 +nsDocument::IsSafeToFlush() const 1.8282 +{ 1.8283 + nsIPresShell* shell = GetShell(); 1.8284 + if (!shell) 1.8285 + return true; 1.8286 + 1.8287 + return shell->IsSafeToFlush(); 1.8288 +} 1.8289 + 1.8290 +void 1.8291 +nsDocument::Sanitize() 1.8292 +{ 1.8293 + // Sanitize the document by resetting all password fields and any form 1.8294 + // fields with autocomplete=off to their default values. We do this now, 1.8295 + // instead of when the presentation is restored, to offer some protection 1.8296 + // in case there is ever an exploit that allows a cached document to be 1.8297 + // accessed from a different document. 1.8298 + 1.8299 + // First locate all input elements, regardless of whether they are 1.8300 + // in a form, and reset the password and autocomplete=off elements. 1.8301 + 1.8302 + nsRefPtr<nsContentList> nodes = GetElementsByTagName(NS_LITERAL_STRING("input")); 1.8303 + 1.8304 + nsCOMPtr<nsIContent> item; 1.8305 + nsAutoString value; 1.8306 + 1.8307 + uint32_t length = nodes->Length(true); 1.8308 + for (uint32_t i = 0; i < length; ++i) { 1.8309 + NS_ASSERTION(nodes->Item(i), "null item in node list!"); 1.8310 + 1.8311 + nsRefPtr<HTMLInputElement> input = HTMLInputElement::FromContentOrNull(nodes->Item(i)); 1.8312 + if (!input) 1.8313 + continue; 1.8314 + 1.8315 + bool resetValue = false; 1.8316 + 1.8317 + input->GetAttribute(NS_LITERAL_STRING("autocomplete"), value); 1.8318 + if (value.LowerCaseEqualsLiteral("off")) { 1.8319 + resetValue = true; 1.8320 + } else { 1.8321 + input->GetType(value); 1.8322 + if (value.LowerCaseEqualsLiteral("password")) 1.8323 + resetValue = true; 1.8324 + } 1.8325 + 1.8326 + if (resetValue) { 1.8327 + input->Reset(); 1.8328 + } 1.8329 + } 1.8330 + 1.8331 + // Now locate all _form_ elements that have autocomplete=off and reset them 1.8332 + nodes = GetElementsByTagName(NS_LITERAL_STRING("form")); 1.8333 + 1.8334 + length = nodes->Length(true); 1.8335 + for (uint32_t i = 0; i < length; ++i) { 1.8336 + NS_ASSERTION(nodes->Item(i), "null item in nodelist"); 1.8337 + 1.8338 + nsCOMPtr<nsIDOMHTMLFormElement> form = do_QueryInterface(nodes->Item(i)); 1.8339 + if (!form) 1.8340 + continue; 1.8341 + 1.8342 + nodes->Item(i)->AsElement()->GetAttr(kNameSpaceID_None, 1.8343 + nsGkAtoms::autocomplete, value); 1.8344 + if (value.LowerCaseEqualsLiteral("off")) 1.8345 + form->Reset(); 1.8346 + } 1.8347 +} 1.8348 + 1.8349 +struct SubDocEnumArgs 1.8350 +{ 1.8351 + nsIDocument::nsSubDocEnumFunc callback; 1.8352 + void *data; 1.8353 +}; 1.8354 + 1.8355 +static PLDHashOperator 1.8356 +SubDocHashEnum(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.8357 + uint32_t number, void *arg) 1.8358 +{ 1.8359 + SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr); 1.8360 + SubDocEnumArgs *args = static_cast<SubDocEnumArgs*>(arg); 1.8361 + 1.8362 + nsIDocument *subdoc = entry->mSubDocument; 1.8363 + bool next = subdoc ? args->callback(subdoc, args->data) : true; 1.8364 + 1.8365 + return next ? PL_DHASH_NEXT : PL_DHASH_STOP; 1.8366 +} 1.8367 + 1.8368 +void 1.8369 +nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback, void *aData) 1.8370 +{ 1.8371 + if (mSubDocuments) { 1.8372 + SubDocEnumArgs args = { aCallback, aData }; 1.8373 + PL_DHashTableEnumerate(mSubDocuments, SubDocHashEnum, &args); 1.8374 + } 1.8375 +} 1.8376 + 1.8377 +static PLDHashOperator 1.8378 +CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.8379 + uint32_t number, void *arg) 1.8380 +{ 1.8381 + SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr); 1.8382 + bool *canCacheArg = static_cast<bool*>(arg); 1.8383 + 1.8384 + nsIDocument *subdoc = entry->mSubDocument; 1.8385 + 1.8386 + // The aIgnoreRequest we were passed is only for us, so don't pass it on. 1.8387 + bool canCache = subdoc ? subdoc->CanSavePresentation(nullptr) : false; 1.8388 + if (!canCache) { 1.8389 + *canCacheArg = false; 1.8390 + return PL_DHASH_STOP; 1.8391 + } 1.8392 + 1.8393 + return PL_DHASH_NEXT; 1.8394 +} 1.8395 + 1.8396 +#ifdef DEBUG_bryner 1.8397 +#define DEBUG_PAGE_CACHE 1.8398 +#endif 1.8399 + 1.8400 +bool 1.8401 +nsDocument::CanSavePresentation(nsIRequest *aNewRequest) 1.8402 +{ 1.8403 + if (EventHandlingSuppressed()) { 1.8404 + return false; 1.8405 + } 1.8406 + 1.8407 + nsPIDOMWindow* win = GetInnerWindow(); 1.8408 + if (win && win->TimeoutSuspendCount()) { 1.8409 + return false; 1.8410 + } 1.8411 + 1.8412 + // Check our event listener manager for unload/beforeunload listeners. 1.8413 + nsCOMPtr<EventTarget> piTarget = do_QueryInterface(mScriptGlobalObject); 1.8414 + if (piTarget) { 1.8415 + EventListenerManager* manager = piTarget->GetExistingListenerManager(); 1.8416 + if (manager && manager->HasUnloadListeners()) { 1.8417 + return false; 1.8418 + } 1.8419 + } 1.8420 + 1.8421 + // Check if we have pending network requests 1.8422 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.8423 + if (loadGroup) { 1.8424 + nsCOMPtr<nsISimpleEnumerator> requests; 1.8425 + loadGroup->GetRequests(getter_AddRefs(requests)); 1.8426 + 1.8427 + bool hasMore = false; 1.8428 + 1.8429 + // We want to bail out if we have any requests other than aNewRequest (or 1.8430 + // in the case when aNewRequest is a part of a multipart response the base 1.8431 + // channel the multipart response is coming in on). 1.8432 + nsCOMPtr<nsIChannel> baseChannel; 1.8433 + nsCOMPtr<nsIMultiPartChannel> part(do_QueryInterface(aNewRequest)); 1.8434 + if (part) { 1.8435 + part->GetBaseChannel(getter_AddRefs(baseChannel)); 1.8436 + } 1.8437 + 1.8438 + while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) { 1.8439 + nsCOMPtr<nsISupports> elem; 1.8440 + requests->GetNext(getter_AddRefs(elem)); 1.8441 + 1.8442 + nsCOMPtr<nsIRequest> request = do_QueryInterface(elem); 1.8443 + if (request && request != aNewRequest && request != baseChannel) { 1.8444 +#ifdef DEBUG_PAGE_CACHE 1.8445 + nsAutoCString requestName, docSpec; 1.8446 + request->GetName(requestName); 1.8447 + if (mDocumentURI) 1.8448 + mDocumentURI->GetSpec(docSpec); 1.8449 + 1.8450 + printf("document %s has request %s\n", 1.8451 + docSpec.get(), requestName.get()); 1.8452 +#endif 1.8453 + return false; 1.8454 + } 1.8455 + } 1.8456 + } 1.8457 + 1.8458 + // Check if we have running offline storage transactions 1.8459 + quota::QuotaManager* quotaManager = 1.8460 + win ? quota::QuotaManager::Get() : nullptr; 1.8461 + if (quotaManager && quotaManager->HasOpenTransactions(win)) { 1.8462 + return false; 1.8463 + } 1.8464 + 1.8465 +#ifdef MOZ_MEDIA_NAVIGATOR 1.8466 + // Check if we have active GetUserMedia use 1.8467 + if (MediaManager::Exists() && win && 1.8468 + MediaManager::Get()->IsWindowStillActive(win->WindowID())) { 1.8469 + return false; 1.8470 + } 1.8471 +#endif // MOZ_MEDIA_NAVIGATOR 1.8472 + 1.8473 +#ifdef MOZ_WEBRTC 1.8474 + // Check if we have active PeerConnections 1.8475 + nsCOMPtr<IPeerConnectionManager> pcManager = 1.8476 + do_GetService(IPEERCONNECTION_MANAGER_CONTRACTID); 1.8477 + 1.8478 + if (pcManager && win) { 1.8479 + bool active; 1.8480 + pcManager->HasActivePeerConnection(win->WindowID(), &active); 1.8481 + if (active) { 1.8482 + return false; 1.8483 + } 1.8484 + } 1.8485 +#endif // MOZ_WEBRTC 1.8486 + 1.8487 + bool canCache = true; 1.8488 + if (mSubDocuments) 1.8489 + PL_DHashTableEnumerate(mSubDocuments, CanCacheSubDocument, &canCache); 1.8490 + 1.8491 + return canCache; 1.8492 +} 1.8493 + 1.8494 +void 1.8495 +nsDocument::Destroy() 1.8496 +{ 1.8497 + // The ContentViewer wants to release the document now. So, tell our content 1.8498 + // to drop any references to the document so that it can be destroyed. 1.8499 + if (mIsGoingAway) 1.8500 + return; 1.8501 + 1.8502 + mIsGoingAway = true; 1.8503 + 1.8504 + RemovedFromDocShell(); 1.8505 + 1.8506 + bool oldVal = mInUnlinkOrDeletion; 1.8507 + mInUnlinkOrDeletion = true; 1.8508 + uint32_t i, count = mChildren.ChildCount(); 1.8509 + for (i = 0; i < count; ++i) { 1.8510 + mChildren.ChildAt(i)->DestroyContent(); 1.8511 + } 1.8512 + mInUnlinkOrDeletion = oldVal; 1.8513 + 1.8514 + mLayoutHistoryState = nullptr; 1.8515 + 1.8516 + // Shut down our external resource map. We might not need this for 1.8517 + // leak-fixing if we fix nsDocumentViewer to do cycle-collection, but 1.8518 + // tearing down all those frame trees right now is the right thing to do. 1.8519 + mExternalResourceMap.Shutdown(); 1.8520 + 1.8521 + mRegistry = nullptr; 1.8522 + 1.8523 + // XXX We really should let cycle collection do this, but that currently still 1.8524 + // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684). 1.8525 + ReleaseWrapper(static_cast<nsINode*>(this)); 1.8526 +} 1.8527 + 1.8528 +void 1.8529 +nsDocument::RemovedFromDocShell() 1.8530 +{ 1.8531 + if (mRemovedFromDocShell) 1.8532 + return; 1.8533 + 1.8534 + mRemovedFromDocShell = true; 1.8535 + EnumerateFreezableElements(NotifyActivityChanged, nullptr); 1.8536 + 1.8537 + uint32_t i, count = mChildren.ChildCount(); 1.8538 + for (i = 0; i < count; ++i) { 1.8539 + mChildren.ChildAt(i)->SaveSubtreeState(); 1.8540 + } 1.8541 +} 1.8542 + 1.8543 +already_AddRefed<nsILayoutHistoryState> 1.8544 +nsDocument::GetLayoutHistoryState() const 1.8545 +{ 1.8546 + nsCOMPtr<nsILayoutHistoryState> state; 1.8547 + if (!mScriptGlobalObject) { 1.8548 + state = mLayoutHistoryState; 1.8549 + } else { 1.8550 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.8551 + if (docShell) { 1.8552 + docShell->GetLayoutHistoryState(getter_AddRefs(state)); 1.8553 + } 1.8554 + } 1.8555 + 1.8556 + return state.forget(); 1.8557 +} 1.8558 + 1.8559 +void 1.8560 +nsDocument::EnsureOnloadBlocker() 1.8561 +{ 1.8562 + // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup 1.8563 + // -- it's not ours. 1.8564 + if (mOnloadBlockCount != 0 && mScriptGlobalObject) { 1.8565 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.8566 + if (loadGroup) { 1.8567 + // Check first to see if mOnloadBlocker is in the loadgroup. 1.8568 + nsCOMPtr<nsISimpleEnumerator> requests; 1.8569 + loadGroup->GetRequests(getter_AddRefs(requests)); 1.8570 + 1.8571 + bool hasMore = false; 1.8572 + while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) { 1.8573 + nsCOMPtr<nsISupports> elem; 1.8574 + requests->GetNext(getter_AddRefs(elem)); 1.8575 + nsCOMPtr<nsIRequest> request = do_QueryInterface(elem); 1.8576 + if (request && request == mOnloadBlocker) { 1.8577 + return; 1.8578 + } 1.8579 + } 1.8580 + 1.8581 + // Not in the loadgroup, so add it. 1.8582 + loadGroup->AddRequest(mOnloadBlocker, nullptr); 1.8583 + } 1.8584 + } 1.8585 +} 1.8586 + 1.8587 +void 1.8588 +nsDocument::AsyncBlockOnload() 1.8589 +{ 1.8590 + while (mAsyncOnloadBlockCount) { 1.8591 + --mAsyncOnloadBlockCount; 1.8592 + BlockOnload(); 1.8593 + } 1.8594 +} 1.8595 + 1.8596 +void 1.8597 +nsDocument::BlockOnload() 1.8598 +{ 1.8599 + if (mDisplayDocument) { 1.8600 + mDisplayDocument->BlockOnload(); 1.8601 + return; 1.8602 + } 1.8603 + 1.8604 + // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup 1.8605 + // -- it's not ours. 1.8606 + if (mOnloadBlockCount == 0 && mScriptGlobalObject) { 1.8607 + if (!nsContentUtils::IsSafeToRunScript()) { 1.8608 + // Because AddRequest may lead to OnStateChange calls in chrome, 1.8609 + // block onload only when there are no script blockers. 1.8610 + ++mAsyncOnloadBlockCount; 1.8611 + if (mAsyncOnloadBlockCount == 1) { 1.8612 + bool success = nsContentUtils::AddScriptRunner( 1.8613 + NS_NewRunnableMethod(this, &nsDocument::AsyncBlockOnload)); 1.8614 + 1.8615 + // The script runner shouldn't fail to add. But if somebody broke 1.8616 + // something and it does, we'll thrash at 100% cpu forever. The best 1.8617 + // response is just to ignore the onload blocking request. See bug 579535. 1.8618 + if (!success) { 1.8619 + NS_WARNING("Disaster! Onload blocking script runner failed to add - expect bad things!"); 1.8620 + mAsyncOnloadBlockCount = 0; 1.8621 + } 1.8622 + } 1.8623 + return; 1.8624 + } 1.8625 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.8626 + if (loadGroup) { 1.8627 + loadGroup->AddRequest(mOnloadBlocker, nullptr); 1.8628 + } 1.8629 + } 1.8630 + ++mOnloadBlockCount; 1.8631 +} 1.8632 + 1.8633 +void 1.8634 +nsDocument::UnblockOnload(bool aFireSync) 1.8635 +{ 1.8636 + if (mDisplayDocument) { 1.8637 + mDisplayDocument->UnblockOnload(aFireSync); 1.8638 + return; 1.8639 + } 1.8640 + 1.8641 + if (mOnloadBlockCount == 0 && mAsyncOnloadBlockCount == 0) { 1.8642 + NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call"); 1.8643 + return; 1.8644 + } 1.8645 + 1.8646 + --mOnloadBlockCount; 1.8647 + 1.8648 + if (mOnloadBlockCount == 0) { 1.8649 + if (mScriptGlobalObject) { 1.8650 + // Only manipulate the loadgroup in this case, because if mScriptGlobalObject 1.8651 + // is null, it's not ours. 1.8652 + if (aFireSync && mAsyncOnloadBlockCount == 0) { 1.8653 + // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it 1.8654 + ++mOnloadBlockCount; 1.8655 + DoUnblockOnload(); 1.8656 + } else { 1.8657 + PostUnblockOnloadEvent(); 1.8658 + } 1.8659 + } else if (mIsBeingUsedAsImage) { 1.8660 + // To correctly unblock onload for a document that contains an SVG 1.8661 + // image, we need to know when all of the SVG document's resources are 1.8662 + // done loading, in a way comparable to |window.onload|. We fire this 1.8663 + // event to indicate that the SVG should be considered fully loaded. 1.8664 + // Because scripting is disabled on SVG-as-image documents, this event 1.8665 + // is not accessible to content authors. (See bug 837135.) 1.8666 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.8667 + new AsyncEventDispatcher(this, 1.8668 + NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"), 1.8669 + false, 1.8670 + false); 1.8671 + asyncDispatcher->PostDOMEvent(); 1.8672 + } 1.8673 + } 1.8674 +} 1.8675 + 1.8676 +class nsUnblockOnloadEvent : public nsRunnable { 1.8677 +public: 1.8678 + nsUnblockOnloadEvent(nsDocument *doc) : mDoc(doc) {} 1.8679 + NS_IMETHOD Run() { 1.8680 + mDoc->DoUnblockOnload(); 1.8681 + return NS_OK; 1.8682 + } 1.8683 +private: 1.8684 + nsRefPtr<nsDocument> mDoc; 1.8685 +}; 1.8686 + 1.8687 +void 1.8688 +nsDocument::PostUnblockOnloadEvent() 1.8689 +{ 1.8690 + nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this); 1.8691 + nsresult rv = NS_DispatchToCurrentThread(evt); 1.8692 + if (NS_SUCCEEDED(rv)) { 1.8693 + // Stabilize block count so we don't post more events while this one is up 1.8694 + ++mOnloadBlockCount; 1.8695 + } else { 1.8696 + NS_WARNING("failed to dispatch nsUnblockOnloadEvent"); 1.8697 + } 1.8698 +} 1.8699 + 1.8700 +void 1.8701 +nsDocument::DoUnblockOnload() 1.8702 +{ 1.8703 + NS_PRECONDITION(!mDisplayDocument, 1.8704 + "Shouldn't get here for resource document"); 1.8705 + NS_PRECONDITION(mOnloadBlockCount != 0, 1.8706 + "Shouldn't have a count of zero here, since we stabilized in " 1.8707 + "PostUnblockOnloadEvent"); 1.8708 + 1.8709 + --mOnloadBlockCount; 1.8710 + 1.8711 + if (mOnloadBlockCount != 0) { 1.8712 + // We blocked again after the last unblock. Nothing to do here. We'll 1.8713 + // post a new event when we unblock again. 1.8714 + return; 1.8715 + } 1.8716 + 1.8717 + if (mAsyncOnloadBlockCount != 0) { 1.8718 + // We need to wait until the async onload block has been handled. 1.8719 + PostUnblockOnloadEvent(); 1.8720 + } 1.8721 + 1.8722 + // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup 1.8723 + // -- it's not ours. 1.8724 + if (mScriptGlobalObject) { 1.8725 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.8726 + if (loadGroup) { 1.8727 + loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK); 1.8728 + } 1.8729 + } 1.8730 +} 1.8731 + 1.8732 +nsIContent* 1.8733 +nsDocument::GetContentInThisDocument(nsIFrame* aFrame) const 1.8734 +{ 1.8735 + for (nsIFrame* f = aFrame; f; 1.8736 + f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) { 1.8737 + nsIContent* content = f->GetContent(); 1.8738 + if (!content || content->IsInAnonymousSubtree()) 1.8739 + continue; 1.8740 + 1.8741 + if (content->OwnerDoc() == this) { 1.8742 + return content; 1.8743 + } 1.8744 + // We must be in a subdocument so jump directly to the root frame. 1.8745 + // GetParentOrPlaceholderForCrossDoc gets called immediately to jump up to 1.8746 + // the containing document. 1.8747 + f = f->PresContext()->GetPresShell()->GetRootFrame(); 1.8748 + } 1.8749 + 1.8750 + return nullptr; 1.8751 +} 1.8752 + 1.8753 +void 1.8754 +nsDocument::DispatchPageTransition(EventTarget* aDispatchTarget, 1.8755 + const nsAString& aType, 1.8756 + bool aPersisted) 1.8757 +{ 1.8758 + if (aDispatchTarget) { 1.8759 + nsCOMPtr<nsIDOMEvent> event; 1.8760 + CreateEvent(NS_LITERAL_STRING("pagetransition"), getter_AddRefs(event)); 1.8761 + nsCOMPtr<nsIDOMPageTransitionEvent> ptEvent = do_QueryInterface(event); 1.8762 + if (ptEvent && NS_SUCCEEDED(ptEvent->InitPageTransitionEvent(aType, true, 1.8763 + true, 1.8764 + aPersisted))) { 1.8765 + event->SetTrusted(true); 1.8766 + event->SetTarget(this); 1.8767 + EventDispatcher::DispatchDOMEvent(aDispatchTarget, nullptr, event, 1.8768 + nullptr, nullptr); 1.8769 + } 1.8770 + } 1.8771 +} 1.8772 + 1.8773 +static bool 1.8774 +NotifyPageShow(nsIDocument* aDocument, void* aData) 1.8775 +{ 1.8776 + const bool* aPersistedPtr = static_cast<const bool*>(aData); 1.8777 + aDocument->OnPageShow(*aPersistedPtr, nullptr); 1.8778 + return true; 1.8779 +} 1.8780 + 1.8781 +void 1.8782 +nsDocument::OnPageShow(bool aPersisted, 1.8783 + EventTarget* aDispatchStartTarget) 1.8784 +{ 1.8785 + mVisible = true; 1.8786 + 1.8787 + EnumerateFreezableElements(NotifyActivityChanged, nullptr); 1.8788 + EnumerateExternalResources(NotifyPageShow, &aPersisted); 1.8789 + 1.8790 + Element* root = GetRootElement(); 1.8791 + if (aPersisted && root) { 1.8792 + // Send out notifications that our <link> elements are attached. 1.8793 + nsRefPtr<nsContentList> links = NS_GetContentList(root, 1.8794 + kNameSpaceID_XHTML, 1.8795 + NS_LITERAL_STRING("link")); 1.8796 + 1.8797 + uint32_t linkCount = links->Length(true); 1.8798 + for (uint32_t i = 0; i < linkCount; ++i) { 1.8799 + static_cast<HTMLLinkElement*>(links->Item(i, false))->LinkAdded(); 1.8800 + } 1.8801 + } 1.8802 + 1.8803 + // See nsIDocument 1.8804 + if (!aDispatchStartTarget) { 1.8805 + // Set mIsShowing before firing events, in case those event handlers 1.8806 + // move us around. 1.8807 + mIsShowing = true; 1.8808 + } 1.8809 + 1.8810 + if (mAnimationController) { 1.8811 + mAnimationController->OnPageShow(); 1.8812 + } 1.8813 + 1.8814 + if (aPersisted) { 1.8815 + SetImagesNeedAnimating(true); 1.8816 + } 1.8817 + 1.8818 + UpdateVisibilityState(); 1.8819 + 1.8820 + nsCOMPtr<EventTarget> target = aDispatchStartTarget; 1.8821 + if (!target) { 1.8822 + target = do_QueryInterface(GetWindow()); 1.8823 + } 1.8824 + 1.8825 + // Dispatch observer notification to notify observers page is shown. 1.8826 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.8827 + nsIPrincipal *principal = GetPrincipal(); 1.8828 + os->NotifyObservers(static_cast<nsIDocument*>(this), 1.8829 + nsContentUtils::IsSystemPrincipal(principal) ? 1.8830 + "chrome-page-shown" : 1.8831 + "content-page-shown", 1.8832 + nullptr); 1.8833 + 1.8834 + 1.8835 + DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted); 1.8836 +} 1.8837 + 1.8838 +static bool 1.8839 +NotifyPageHide(nsIDocument* aDocument, void* aData) 1.8840 +{ 1.8841 + const bool* aPersistedPtr = static_cast<const bool*>(aData); 1.8842 + aDocument->OnPageHide(*aPersistedPtr, nullptr); 1.8843 + return true; 1.8844 +} 1.8845 + 1.8846 +static void 1.8847 +DispatchFullScreenChange(nsIDocument* aTarget) 1.8848 +{ 1.8849 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.8850 + new AsyncEventDispatcher(aTarget, 1.8851 + NS_LITERAL_STRING("mozfullscreenchange"), 1.8852 + true, 1.8853 + false); 1.8854 + asyncDispatcher->PostDOMEvent(); 1.8855 +} 1.8856 + 1.8857 +void 1.8858 +nsDocument::OnPageHide(bool aPersisted, 1.8859 + EventTarget* aDispatchStartTarget) 1.8860 +{ 1.8861 + // Send out notifications that our <link> elements are detached, 1.8862 + // but only if this is not a full unload. 1.8863 + Element* root = GetRootElement(); 1.8864 + if (aPersisted && root) { 1.8865 + nsRefPtr<nsContentList> links = NS_GetContentList(root, 1.8866 + kNameSpaceID_XHTML, 1.8867 + NS_LITERAL_STRING("link")); 1.8868 + 1.8869 + uint32_t linkCount = links->Length(true); 1.8870 + for (uint32_t i = 0; i < linkCount; ++i) { 1.8871 + static_cast<HTMLLinkElement*>(links->Item(i, false))->LinkRemoved(); 1.8872 + } 1.8873 + } 1.8874 + 1.8875 + // See nsIDocument 1.8876 + if (!aDispatchStartTarget) { 1.8877 + // Set mIsShowing before firing events, in case those event handlers 1.8878 + // move us around. 1.8879 + mIsShowing = false; 1.8880 + } 1.8881 + 1.8882 + if (mAnimationController) { 1.8883 + mAnimationController->OnPageHide(); 1.8884 + } 1.8885 + 1.8886 + if (aPersisted) { 1.8887 + SetImagesNeedAnimating(false); 1.8888 + } 1.8889 + 1.8890 + MozExitPointerLock(); 1.8891 + 1.8892 + // Now send out a PageHide event. 1.8893 + nsCOMPtr<EventTarget> target = aDispatchStartTarget; 1.8894 + if (!target) { 1.8895 + target = do_QueryInterface(GetWindow()); 1.8896 + } 1.8897 + 1.8898 + // Dispatch observer notification to notify observers page is hidden. 1.8899 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.8900 + nsIPrincipal *principal = GetPrincipal(); 1.8901 + os->NotifyObservers(static_cast<nsIDocument*>(this), 1.8902 + nsContentUtils::IsSystemPrincipal(principal) ? 1.8903 + "chrome-page-hidden" : 1.8904 + "content-page-hidden", 1.8905 + nullptr); 1.8906 + 1.8907 + DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted); 1.8908 + 1.8909 + mVisible = false; 1.8910 + 1.8911 + UpdateVisibilityState(); 1.8912 + 1.8913 + EnumerateExternalResources(NotifyPageHide, &aPersisted); 1.8914 + EnumerateFreezableElements(NotifyActivityChanged, nullptr); 1.8915 + 1.8916 + if (IsFullScreenDoc()) { 1.8917 + // If this document was fullscreen, we should exit fullscreen in this 1.8918 + // doctree branch. This ensures that if the user navigates while in 1.8919 + // fullscreen mode we don't leave its still visible ancestor documents 1.8920 + // in fullscreen mode. So exit fullscreen in the document's fullscreen 1.8921 + // root document, as this will exit fullscreen in all the root's 1.8922 + // descendant documents. Note that documents are removed from the 1.8923 + // doctree by the time OnPageHide() is called, so we must store a 1.8924 + // reference to the root (in nsDocument::mFullscreenRoot) since we can't 1.8925 + // just traverse the doctree to get the root. 1.8926 + nsIDocument::ExitFullscreen(this, /* async */ false); 1.8927 + 1.8928 + // Since the document is removed from the doctree before OnPageHide() is 1.8929 + // called, ExitFullscreen() can't traverse from the root down to *this* 1.8930 + // document, so we must manually call CleanupFullscreenState() below too. 1.8931 + // Note that CleanupFullscreenState() clears nsDocument::mFullscreenRoot, 1.8932 + // so we *must* call it after ExitFullscreen(), not before. 1.8933 + // OnPageHide() is called in every hidden (i.e. descendant) document, 1.8934 + // so calling CleanupFullscreenState() here will ensure all hidden 1.8935 + // documents have their fullscreen state reset. 1.8936 + CleanupFullscreenState(); 1.8937 + 1.8938 + // If anyone was listening to this document's state, advertizing the state 1.8939 + // change would be the least of the politeness. 1.8940 + DispatchFullScreenChange(this); 1.8941 + } 1.8942 +} 1.8943 + 1.8944 +void 1.8945 +nsDocument::WillDispatchMutationEvent(nsINode* aTarget) 1.8946 +{ 1.8947 + NS_ASSERTION(mSubtreeModifiedDepth != 0 || 1.8948 + mSubtreeModifiedTargets.Count() == 0, 1.8949 + "mSubtreeModifiedTargets not cleared after dispatching?"); 1.8950 + ++mSubtreeModifiedDepth; 1.8951 + if (aTarget) { 1.8952 + // MayDispatchMutationEvent is often called just before this method, 1.8953 + // so it has already appended the node to mSubtreeModifiedTargets. 1.8954 + int32_t count = mSubtreeModifiedTargets.Count(); 1.8955 + if (!count || mSubtreeModifiedTargets[count - 1] != aTarget) { 1.8956 + mSubtreeModifiedTargets.AppendObject(aTarget); 1.8957 + } 1.8958 + } 1.8959 +} 1.8960 + 1.8961 +void 1.8962 +nsDocument::MutationEventDispatched(nsINode* aTarget) 1.8963 +{ 1.8964 + --mSubtreeModifiedDepth; 1.8965 + if (mSubtreeModifiedDepth == 0) { 1.8966 + int32_t count = mSubtreeModifiedTargets.Count(); 1.8967 + if (!count) { 1.8968 + return; 1.8969 + } 1.8970 + 1.8971 + nsCOMPtr<nsPIDOMWindow> window; 1.8972 + window = do_QueryInterface(GetWindow()); 1.8973 + if (window && 1.8974 + !window->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) { 1.8975 + mSubtreeModifiedTargets.Clear(); 1.8976 + return; 1.8977 + } 1.8978 + 1.8979 + nsCOMArray<nsINode> realTargets; 1.8980 + for (int32_t i = 0; i < count; ++i) { 1.8981 + nsINode* possibleTarget = mSubtreeModifiedTargets[i]; 1.8982 + nsCOMPtr<nsIContent> content = do_QueryInterface(possibleTarget); 1.8983 + if (content && content->ChromeOnlyAccess()) { 1.8984 + continue; 1.8985 + } 1.8986 + 1.8987 + nsINode* commonAncestor = nullptr; 1.8988 + int32_t realTargetCount = realTargets.Count(); 1.8989 + for (int32_t j = 0; j < realTargetCount; ++j) { 1.8990 + commonAncestor = 1.8991 + nsContentUtils::GetCommonAncestor(possibleTarget, realTargets[j]); 1.8992 + if (commonAncestor) { 1.8993 + realTargets.ReplaceObjectAt(commonAncestor, j); 1.8994 + break; 1.8995 + } 1.8996 + } 1.8997 + if (!commonAncestor) { 1.8998 + realTargets.AppendObject(possibleTarget); 1.8999 + } 1.9000 + } 1.9001 + 1.9002 + mSubtreeModifiedTargets.Clear(); 1.9003 + 1.9004 + int32_t realTargetCount = realTargets.Count(); 1.9005 + for (int32_t k = 0; k < realTargetCount; ++k) { 1.9006 + InternalMutationEvent mutation(true, NS_MUTATION_SUBTREEMODIFIED); 1.9007 + (new AsyncEventDispatcher(realTargets[k], mutation))-> 1.9008 + RunDOMEventWhenSafe(); 1.9009 + } 1.9010 + } 1.9011 +} 1.9012 + 1.9013 +void 1.9014 +nsDocument::AddStyleRelevantLink(Link* aLink) 1.9015 +{ 1.9016 + NS_ASSERTION(aLink, "Passing in a null link. Expect crashes RSN!"); 1.9017 +#ifdef DEBUG 1.9018 + nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink); 1.9019 + NS_ASSERTION(!entry, "Document already knows about this Link!"); 1.9020 + mStyledLinksCleared = false; 1.9021 +#endif 1.9022 + (void)mStyledLinks.PutEntry(aLink); 1.9023 +} 1.9024 + 1.9025 +void 1.9026 +nsDocument::ForgetLink(Link* aLink) 1.9027 +{ 1.9028 + NS_ASSERTION(aLink, "Passing in a null link. Expect crashes RSN!"); 1.9029 +#ifdef DEBUG 1.9030 + nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink); 1.9031 + NS_ASSERTION(entry || mStyledLinksCleared, 1.9032 + "Document knows nothing about this Link!"); 1.9033 +#endif 1.9034 + (void)mStyledLinks.RemoveEntry(aLink); 1.9035 +} 1.9036 + 1.9037 +void 1.9038 +nsDocument::DestroyElementMaps() 1.9039 +{ 1.9040 +#ifdef DEBUG 1.9041 + mStyledLinksCleared = true; 1.9042 +#endif 1.9043 + mStyledLinks.Clear(); 1.9044 + mIdentifierMap.Clear(); 1.9045 + ++mExpandoAndGeneration.generation; 1.9046 +} 1.9047 + 1.9048 +static 1.9049 +PLDHashOperator 1.9050 +EnumerateStyledLinks(nsPtrHashKey<Link>* aEntry, void* aArray) 1.9051 +{ 1.9052 + LinkArray* array = static_cast<LinkArray*>(aArray); 1.9053 + (void)array->AppendElement(aEntry->GetKey()); 1.9054 + return PL_DHASH_NEXT; 1.9055 +} 1.9056 + 1.9057 +void 1.9058 +nsDocument::RefreshLinkHrefs() 1.9059 +{ 1.9060 + // Get a list of all links we know about. We will reset them, which will 1.9061 + // remove them from the document, so we need a copy of what is in the 1.9062 + // hashtable. 1.9063 + LinkArray linksToNotify(mStyledLinks.Count()); 1.9064 + (void)mStyledLinks.EnumerateEntries(EnumerateStyledLinks, &linksToNotify); 1.9065 + 1.9066 + // Reset all of our styled links. 1.9067 + nsAutoScriptBlocker scriptBlocker; 1.9068 + for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) { 1.9069 + linksToNotify[i]->ResetLinkState(true, linksToNotify[i]->ElementHasHref()); 1.9070 + } 1.9071 +} 1.9072 + 1.9073 +nsresult 1.9074 +nsDocument::CloneDocHelper(nsDocument* clone) const 1.9075 +{ 1.9076 + clone->mIsStaticDocument = mCreatingStaticClone; 1.9077 + 1.9078 + // Init document 1.9079 + nsresult rv = clone->Init(); 1.9080 + NS_ENSURE_SUCCESS(rv, rv); 1.9081 + 1.9082 + // Set URI/principal 1.9083 + clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI()); 1.9084 + clone->SetChromeXHRDocURI(mChromeXHRDocURI); 1.9085 + // Must set the principal first, since SetBaseURI checks it. 1.9086 + clone->SetPrincipal(NodePrincipal()); 1.9087 + clone->mDocumentBaseURI = mDocumentBaseURI; 1.9088 + clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI); 1.9089 + 1.9090 + if (mCreatingStaticClone) { 1.9091 + nsCOMPtr<nsILoadGroup> loadGroup; 1.9092 + 1.9093 + // |mDocumentContainer| is the container of the document that is being 1.9094 + // created and not the original container. See CreateStaticClone function(). 1.9095 + nsCOMPtr<nsIDocumentLoader> docLoader(mDocumentContainer); 1.9096 + if (docLoader) { 1.9097 + docLoader->GetLoadGroup(getter_AddRefs(loadGroup)); 1.9098 + } 1.9099 + nsCOMPtr<nsIChannel> channel = GetChannel(); 1.9100 + if (channel && loadGroup) { 1.9101 + clone->Reset(channel, loadGroup); 1.9102 + } else { 1.9103 + nsIURI* uri = static_cast<const nsIDocument*>(this)->GetDocumentURI(); 1.9104 + if (uri) { 1.9105 + clone->ResetToURI(uri, loadGroup, NodePrincipal()); 1.9106 + } 1.9107 + } 1.9108 + clone->SetContainer(mDocumentContainer); 1.9109 + } 1.9110 + 1.9111 + // Set scripting object 1.9112 + bool hasHadScriptObject = true; 1.9113 + nsIScriptGlobalObject* scriptObject = 1.9114 + GetScriptHandlingObject(hasHadScriptObject); 1.9115 + NS_ENSURE_STATE(scriptObject || !hasHadScriptObject); 1.9116 + if (scriptObject) { 1.9117 + clone->SetScriptHandlingObject(scriptObject); 1.9118 + } else { 1.9119 + clone->SetScopeObject(GetScopeObject()); 1.9120 + } 1.9121 + // Make the clone a data document 1.9122 + clone->SetLoadedAsData(true); 1.9123 + 1.9124 + // Misc state 1.9125 + 1.9126 + // State from nsIDocument 1.9127 + clone->mCharacterSet = mCharacterSet; 1.9128 + clone->mCharacterSetSource = mCharacterSetSource; 1.9129 + clone->mCompatMode = mCompatMode; 1.9130 + clone->mBidiOptions = mBidiOptions; 1.9131 + clone->mContentLanguage = mContentLanguage; 1.9132 + clone->SetContentTypeInternal(GetContentTypeInternal()); 1.9133 + clone->mSecurityInfo = mSecurityInfo; 1.9134 + 1.9135 + // State from nsDocument 1.9136 + clone->mIsRegularHTML = mIsRegularHTML; 1.9137 + clone->mXMLDeclarationBits = mXMLDeclarationBits; 1.9138 + clone->mBaseTarget = mBaseTarget; 1.9139 + return NS_OK; 1.9140 +} 1.9141 + 1.9142 +void 1.9143 +nsDocument::SetReadyStateInternal(ReadyState rs) 1.9144 +{ 1.9145 + mReadyState = rs; 1.9146 + if (rs == READYSTATE_UNINITIALIZED) { 1.9147 + // Transition back to uninitialized happens only to keep assertions happy 1.9148 + // right before readyState transitions to something else. Make this 1.9149 + // transition undetectable by Web content. 1.9150 + return; 1.9151 + } 1.9152 + if (mTiming) { 1.9153 + switch (rs) { 1.9154 + case READYSTATE_LOADING: 1.9155 + mTiming->NotifyDOMLoading(nsIDocument::GetDocumentURI()); 1.9156 + break; 1.9157 + case READYSTATE_INTERACTIVE: 1.9158 + mTiming->NotifyDOMInteractive(nsIDocument::GetDocumentURI()); 1.9159 + break; 1.9160 + case READYSTATE_COMPLETE: 1.9161 + mTiming->NotifyDOMComplete(nsIDocument::GetDocumentURI()); 1.9162 + break; 1.9163 + default: 1.9164 + NS_WARNING("Unexpected ReadyState value"); 1.9165 + break; 1.9166 + } 1.9167 + } 1.9168 + // At the time of loading start, we don't have timing object, record time. 1.9169 + if (READYSTATE_LOADING == rs) { 1.9170 + mLoadingTimeStamp = mozilla::TimeStamp::Now(); 1.9171 + } 1.9172 + 1.9173 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.9174 + new AsyncEventDispatcher(this, NS_LITERAL_STRING("readystatechange"), 1.9175 + false, false); 1.9176 + asyncDispatcher->RunDOMEventWhenSafe(); 1.9177 +} 1.9178 + 1.9179 +NS_IMETHODIMP 1.9180 +nsDocument::GetReadyState(nsAString& aReadyState) 1.9181 +{ 1.9182 + nsIDocument::GetReadyState(aReadyState); 1.9183 + return NS_OK; 1.9184 +} 1.9185 + 1.9186 +void 1.9187 +nsIDocument::GetReadyState(nsAString& aReadyState) const 1.9188 +{ 1.9189 + switch(mReadyState) { 1.9190 + case READYSTATE_LOADING : 1.9191 + aReadyState.Assign(NS_LITERAL_STRING("loading")); 1.9192 + break; 1.9193 + case READYSTATE_INTERACTIVE : 1.9194 + aReadyState.Assign(NS_LITERAL_STRING("interactive")); 1.9195 + break; 1.9196 + case READYSTATE_COMPLETE : 1.9197 + aReadyState.Assign(NS_LITERAL_STRING("complete")); 1.9198 + break; 1.9199 + default: 1.9200 + aReadyState.Assign(NS_LITERAL_STRING("uninitialized")); 1.9201 + } 1.9202 +} 1.9203 + 1.9204 +namespace { 1.9205 + 1.9206 +struct SuppressArgs 1.9207 +{ 1.9208 + nsIDocument::SuppressionType mWhat; 1.9209 + uint32_t mIncrease; 1.9210 +}; 1.9211 + 1.9212 +} 1.9213 + 1.9214 +static bool 1.9215 +SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData) 1.9216 +{ 1.9217 + SuppressArgs* args = static_cast<SuppressArgs*>(aData); 1.9218 + aDocument->SuppressEventHandling(args->mWhat, args->mIncrease); 1.9219 + return true; 1.9220 +} 1.9221 + 1.9222 +void 1.9223 +nsDocument::SuppressEventHandling(nsIDocument::SuppressionType aWhat, 1.9224 + uint32_t aIncrease) 1.9225 +{ 1.9226 + if (mEventsSuppressed == 0 && mAnimationsPaused == 0 && 1.9227 + aIncrease != 0 && mPresShell && mScriptGlobalObject) { 1.9228 + RevokeAnimationFrameNotifications(); 1.9229 + } 1.9230 + 1.9231 + if (aWhat == eAnimationsOnly) { 1.9232 + mAnimationsPaused += aIncrease; 1.9233 + } else { 1.9234 + mEventsSuppressed += aIncrease; 1.9235 + } 1.9236 + 1.9237 + SuppressArgs args = { aWhat, aIncrease }; 1.9238 + EnumerateSubDocuments(SuppressEventHandlingInDocument, &args); 1.9239 +} 1.9240 + 1.9241 +static void 1.9242 +FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments, 1.9243 + bool aFireEvents) 1.9244 +{ 1.9245 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.9246 + if (!fm) 1.9247 + return; 1.9248 + 1.9249 + for (uint32_t i = 0; i < aDocuments.Length(); ++i) { 1.9250 + // NB: Don't bother trying to fire delayed events on documents that were 1.9251 + // closed before this event ran. 1.9252 + if (!aDocuments[i]->EventHandlingSuppressed()) { 1.9253 + fm->FireDelayedEvents(aDocuments[i]); 1.9254 + nsCOMPtr<nsIPresShell> shell = aDocuments[i]->GetShell(); 1.9255 + if (shell) { 1.9256 + // Only fire events for active documents. 1.9257 + bool fire = aFireEvents && 1.9258 + aDocuments[i]->GetInnerWindow() && 1.9259 + aDocuments[i]->GetInnerWindow()->IsCurrentInnerWindow(); 1.9260 + shell->FireOrClearDelayedEvents(fire); 1.9261 + } 1.9262 + } 1.9263 + } 1.9264 +} 1.9265 + 1.9266 +void 1.9267 +nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr) 1.9268 +{ 1.9269 + // Early exit if the img is already present in the img-cache 1.9270 + // which indicates that the "real" load has already started and 1.9271 + // that we shouldn't preload it. 1.9272 + int16_t blockingStatus; 1.9273 + if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) || 1.9274 + !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this), 1.9275 + this, NodePrincipal(), &blockingStatus)) { 1.9276 + return; 1.9277 + } 1.9278 + 1.9279 + nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL; 1.9280 + switch (Element::StringToCORSMode(aCrossOriginAttr)) { 1.9281 + case CORS_NONE: 1.9282 + // Nothing to do 1.9283 + break; 1.9284 + case CORS_ANONYMOUS: 1.9285 + loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS; 1.9286 + break; 1.9287 + case CORS_USE_CREDENTIALS: 1.9288 + loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS; 1.9289 + break; 1.9290 + default: 1.9291 + MOZ_CRASH("Unknown CORS mode!"); 1.9292 + } 1.9293 + 1.9294 + // Image not in cache - trigger preload 1.9295 + nsRefPtr<imgRequestProxy> request; 1.9296 + nsresult rv = 1.9297 + nsContentUtils::LoadImage(uri, 1.9298 + this, 1.9299 + NodePrincipal(), 1.9300 + mDocumentURI, // uri of document used as referrer 1.9301 + nullptr, // no observer 1.9302 + loadFlags, 1.9303 + NS_LITERAL_STRING("img"), 1.9304 + getter_AddRefs(request)); 1.9305 + 1.9306 + // Pin image-reference to avoid evicting it from the img-cache before 1.9307 + // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and 1.9308 + // unlink 1.9309 + if (NS_SUCCEEDED(rv)) { 1.9310 + mPreloadingImages.AppendObject(request); 1.9311 + } 1.9312 +} 1.9313 + 1.9314 +EventStates 1.9315 +nsDocument::GetDocumentState() 1.9316 +{ 1.9317 + if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_RTL_LOCALE)) { 1.9318 + if (IsDocumentRightToLeft()) { 1.9319 + mDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE; 1.9320 + } 1.9321 + mGotDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE; 1.9322 + } 1.9323 + if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) { 1.9324 + nsIPresShell* shell = GetShell(); 1.9325 + if (shell && shell->GetPresContext() && 1.9326 + shell->GetPresContext()->IsTopLevelWindowInactive()) { 1.9327 + mDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE; 1.9328 + } 1.9329 + mGotDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE; 1.9330 + } 1.9331 + return mDocumentState; 1.9332 +} 1.9333 + 1.9334 +namespace { 1.9335 + 1.9336 +/** 1.9337 + * Stub for LoadSheet(), since all we want is to get the sheet into 1.9338 + * the CSSLoader's style cache 1.9339 + */ 1.9340 +class StubCSSLoaderObserver MOZ_FINAL : public nsICSSLoaderObserver { 1.9341 +public: 1.9342 + NS_IMETHOD 1.9343 + StyleSheetLoaded(nsCSSStyleSheet*, bool, nsresult) 1.9344 + { 1.9345 + return NS_OK; 1.9346 + } 1.9347 + NS_DECL_ISUPPORTS 1.9348 +}; 1.9349 +NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver) 1.9350 + 1.9351 +} 1.9352 + 1.9353 +void 1.9354 +nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset, 1.9355 + const nsAString& aCrossOriginAttr) 1.9356 +{ 1.9357 + // The CSSLoader will retain this object after we return. 1.9358 + nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver(); 1.9359 + 1.9360 + // Charset names are always ASCII. 1.9361 + CSSLoader()->LoadSheet(uri, NodePrincipal(), 1.9362 + NS_LossyConvertUTF16toASCII(charset), 1.9363 + obs, 1.9364 + Element::StringToCORSMode(aCrossOriginAttr)); 1.9365 +} 1.9366 + 1.9367 +nsresult 1.9368 +nsDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet, 1.9369 + nsCSSStyleSheet** sheet) 1.9370 +{ 1.9371 + return CSSLoader()->LoadSheetSync(uri, isAgentSheet, isAgentSheet, sheet); 1.9372 +} 1.9373 + 1.9374 +class nsDelayedEventDispatcher : public nsRunnable 1.9375 +{ 1.9376 +public: 1.9377 + nsDelayedEventDispatcher(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments) 1.9378 + { 1.9379 + mDocuments.SwapElements(aDocuments); 1.9380 + } 1.9381 + virtual ~nsDelayedEventDispatcher() {} 1.9382 + 1.9383 + NS_IMETHOD Run() 1.9384 + { 1.9385 + FireOrClearDelayedEvents(mDocuments, true); 1.9386 + return NS_OK; 1.9387 + } 1.9388 + 1.9389 +private: 1.9390 + nsTArray<nsCOMPtr<nsIDocument> > mDocuments; 1.9391 +}; 1.9392 + 1.9393 +namespace { 1.9394 + 1.9395 +struct UnsuppressArgs 1.9396 +{ 1.9397 + UnsuppressArgs(nsIDocument::SuppressionType aWhat) 1.9398 + : mWhat(aWhat) 1.9399 + { 1.9400 + } 1.9401 + 1.9402 + nsIDocument::SuppressionType mWhat; 1.9403 + nsTArray<nsCOMPtr<nsIDocument>> mDocs; 1.9404 +}; 1.9405 + 1.9406 +} 1.9407 + 1.9408 +static bool 1.9409 +GetAndUnsuppressSubDocuments(nsIDocument* aDocument, 1.9410 + void* aData) 1.9411 +{ 1.9412 + UnsuppressArgs* args = static_cast<UnsuppressArgs*>(aData); 1.9413 + if (args->mWhat != nsIDocument::eAnimationsOnly && 1.9414 + aDocument->EventHandlingSuppressed() > 0) { 1.9415 + static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression(); 1.9416 + } else if (args->mWhat == nsIDocument::eAnimationsOnly && 1.9417 + aDocument->AnimationsPaused()) { 1.9418 + static_cast<nsDocument*>(aDocument)->ResumeAnimations(); 1.9419 + } 1.9420 + 1.9421 + if (args->mWhat != nsIDocument::eAnimationsOnly) { 1.9422 + // No need to remember documents if we only care about animation frames. 1.9423 + args->mDocs.AppendElement(aDocument); 1.9424 + } 1.9425 + 1.9426 + aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, aData); 1.9427 + return true; 1.9428 +} 1.9429 + 1.9430 +void 1.9431 +nsDocument::UnsuppressEventHandlingAndFireEvents(nsIDocument::SuppressionType aWhat, 1.9432 + bool aFireEvents) 1.9433 +{ 1.9434 + UnsuppressArgs args(aWhat); 1.9435 + GetAndUnsuppressSubDocuments(this, &args); 1.9436 + 1.9437 + if (aWhat == nsIDocument::eAnimationsOnly) { 1.9438 + // No need to fire events if we only care about animations here. 1.9439 + return; 1.9440 + } 1.9441 + 1.9442 + if (aFireEvents) { 1.9443 + NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(args.mDocs)); 1.9444 + } else { 1.9445 + FireOrClearDelayedEvents(args.mDocs, false); 1.9446 + } 1.9447 +} 1.9448 + 1.9449 +nsISupports* 1.9450 +nsDocument::GetCurrentContentSink() 1.9451 +{ 1.9452 + return mParser ? mParser->GetContentSink() : nullptr; 1.9453 +} 1.9454 + 1.9455 +nsIDocument* 1.9456 +nsDocument::GetTemplateContentsOwner() 1.9457 +{ 1.9458 + if (!mTemplateContentsOwner) { 1.9459 + bool hasHadScriptObject = true; 1.9460 + nsIScriptGlobalObject* scriptObject = 1.9461 + GetScriptHandlingObject(hasHadScriptObject); 1.9462 + NS_ENSURE_TRUE(scriptObject || !hasHadScriptObject, nullptr); 1.9463 + 1.9464 + nsCOMPtr<nsIDOMDocument> domDocument; 1.9465 + nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument), 1.9466 + EmptyString(), // aNamespaceURI 1.9467 + EmptyString(), // aQualifiedName 1.9468 + nullptr, // aDoctype 1.9469 + nsIDocument::GetDocumentURI(), 1.9470 + nsIDocument::GetDocBaseURI(), 1.9471 + NodePrincipal(), 1.9472 + true, // aLoadedAsData 1.9473 + scriptObject, // aEventObject 1.9474 + DocumentFlavorHTML); 1.9475 + NS_ENSURE_SUCCESS(rv, nullptr); 1.9476 + 1.9477 + mTemplateContentsOwner = do_QueryInterface(domDocument); 1.9478 + NS_ENSURE_TRUE(mTemplateContentsOwner, nullptr); 1.9479 + 1.9480 + mTemplateContentsOwner->SetScriptHandlingObject(scriptObject); 1.9481 + 1.9482 + // Set |doc| as the template contents owner of itself so that 1.9483 + // |doc| is the template contents owner of template elements created 1.9484 + // by |doc|. 1.9485 + nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get()); 1.9486 + doc->mTemplateContentsOwner = doc; 1.9487 + } 1.9488 + 1.9489 + return mTemplateContentsOwner; 1.9490 +} 1.9491 + 1.9492 +void 1.9493 +nsDocument::RegisterHostObjectUri(const nsACString& aUri) 1.9494 +{ 1.9495 + mHostObjectURIs.AppendElement(aUri); 1.9496 +} 1.9497 + 1.9498 +void 1.9499 +nsDocument::UnregisterHostObjectUri(const nsACString& aUri) 1.9500 +{ 1.9501 + mHostObjectURIs.RemoveElement(aUri); 1.9502 +} 1.9503 + 1.9504 +void 1.9505 +nsDocument::SetScrollToRef(nsIURI *aDocumentURI) 1.9506 +{ 1.9507 + if (!aDocumentURI) { 1.9508 + return; 1.9509 + } 1.9510 + 1.9511 + nsAutoCString ref; 1.9512 + 1.9513 + // Since all URI's that pass through here aren't URL's we can't 1.9514 + // rely on the nsIURI implementation for providing a way for 1.9515 + // finding the 'ref' part of the URI, we'll haveto revert to 1.9516 + // string routines for finding the data past '#' 1.9517 + 1.9518 + aDocumentURI->GetSpec(ref); 1.9519 + 1.9520 + nsReadingIterator<char> start, end; 1.9521 + 1.9522 + ref.BeginReading(start); 1.9523 + ref.EndReading(end); 1.9524 + 1.9525 + if (FindCharInReadable('#', start, end)) { 1.9526 + ++start; // Skip over the '#' 1.9527 + 1.9528 + mScrollToRef = Substring(start, end); 1.9529 + } 1.9530 +} 1.9531 + 1.9532 +void 1.9533 +nsDocument::ScrollToRef() 1.9534 +{ 1.9535 + if (mScrolledToRefAlready) { 1.9536 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.9537 + if (shell) { 1.9538 + shell->ScrollToAnchor(); 1.9539 + } 1.9540 + return; 1.9541 + } 1.9542 + 1.9543 + if (mScrollToRef.IsEmpty()) { 1.9544 + return; 1.9545 + } 1.9546 + 1.9547 + char* tmpstr = ToNewCString(mScrollToRef); 1.9548 + if (!tmpstr) { 1.9549 + return; 1.9550 + } 1.9551 + 1.9552 + nsUnescape(tmpstr); 1.9553 + nsAutoCString unescapedRef; 1.9554 + unescapedRef.Assign(tmpstr); 1.9555 + nsMemory::Free(tmpstr); 1.9556 + 1.9557 + nsresult rv = NS_ERROR_FAILURE; 1.9558 + // We assume that the bytes are in UTF-8, as it says in the spec: 1.9559 + // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1 1.9560 + NS_ConvertUTF8toUTF16 ref(unescapedRef); 1.9561 + 1.9562 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.9563 + if (shell) { 1.9564 + // Check an empty string which might be caused by the UTF-8 conversion 1.9565 + if (!ref.IsEmpty()) { 1.9566 + // Note that GoToAnchor will handle flushing layout as needed. 1.9567 + rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef); 1.9568 + } else { 1.9569 + rv = NS_ERROR_FAILURE; 1.9570 + } 1.9571 + 1.9572 + // If UTF-8 URI failed then try to assume the string as a 1.9573 + // document's charset. 1.9574 + 1.9575 + if (NS_FAILED(rv)) { 1.9576 + const nsACString &docCharset = GetDocumentCharacterSet(); 1.9577 + 1.9578 + rv = nsContentUtils::ConvertStringFromEncoding(docCharset, 1.9579 + unescapedRef, 1.9580 + ref); 1.9581 + 1.9582 + if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { 1.9583 + rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef); 1.9584 + } 1.9585 + } 1.9586 + if (NS_SUCCEEDED(rv)) { 1.9587 + mScrolledToRefAlready = true; 1.9588 + } 1.9589 + } 1.9590 +} 1.9591 + 1.9592 +void 1.9593 +nsDocument::ResetScrolledToRefAlready() 1.9594 +{ 1.9595 + mScrolledToRefAlready = false; 1.9596 +} 1.9597 + 1.9598 +void 1.9599 +nsDocument::SetChangeScrollPosWhenScrollingToRef(bool aValue) 1.9600 +{ 1.9601 + mChangeScrollPosWhenScrollingToRef = aValue; 1.9602 +} 1.9603 + 1.9604 +void 1.9605 +nsIDocument::RegisterFreezableElement(nsIContent* aContent) 1.9606 +{ 1.9607 + if (!mFreezableElements) { 1.9608 + mFreezableElements = new nsTHashtable<nsPtrHashKey<nsIContent> >(); 1.9609 + if (!mFreezableElements) 1.9610 + return; 1.9611 + } 1.9612 + mFreezableElements->PutEntry(aContent); 1.9613 +} 1.9614 + 1.9615 +bool 1.9616 +nsIDocument::UnregisterFreezableElement(nsIContent* aContent) 1.9617 +{ 1.9618 + if (!mFreezableElements) 1.9619 + return false; 1.9620 + if (!mFreezableElements->GetEntry(aContent)) 1.9621 + return false; 1.9622 + mFreezableElements->RemoveEntry(aContent); 1.9623 + return true; 1.9624 +} 1.9625 + 1.9626 +struct EnumerateFreezablesData { 1.9627 + nsIDocument::FreezableElementEnumerator mEnumerator; 1.9628 + void* mData; 1.9629 +}; 1.9630 + 1.9631 +static PLDHashOperator 1.9632 +EnumerateFreezables(nsPtrHashKey<nsIContent>* aEntry, void* aData) 1.9633 +{ 1.9634 + EnumerateFreezablesData* data = static_cast<EnumerateFreezablesData*>(aData); 1.9635 + data->mEnumerator(aEntry->GetKey(), data->mData); 1.9636 + return PL_DHASH_NEXT; 1.9637 +} 1.9638 + 1.9639 +void 1.9640 +nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator, 1.9641 + void* aData) 1.9642 +{ 1.9643 + if (!mFreezableElements) 1.9644 + return; 1.9645 + EnumerateFreezablesData data = { aEnumerator, aData }; 1.9646 + mFreezableElements->EnumerateEntries(EnumerateFreezables, &data); 1.9647 +} 1.9648 + 1.9649 +void 1.9650 +nsIDocument::RegisterPendingLinkUpdate(Link* aLink) 1.9651 +{ 1.9652 + MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden); 1.9653 + mLinksToUpdate.PutEntry(aLink); 1.9654 + mHasLinksToUpdate = true; 1.9655 +} 1.9656 + 1.9657 +void 1.9658 +nsIDocument::UnregisterPendingLinkUpdate(Link* aLink) 1.9659 +{ 1.9660 + MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden); 1.9661 + if (!mHasLinksToUpdate) 1.9662 + return; 1.9663 + 1.9664 + mLinksToUpdate.RemoveEntry(aLink); 1.9665 +} 1.9666 + 1.9667 +static PLDHashOperator 1.9668 +EnumeratePendingLinkUpdates(nsPtrHashKey<Link>* aEntry, void* aData) 1.9669 +{ 1.9670 + aEntry->GetKey()->GetElement()->UpdateLinkState(aEntry->GetKey()->LinkState()); 1.9671 + return PL_DHASH_NEXT; 1.9672 +} 1.9673 + 1.9674 +void 1.9675 +nsIDocument::FlushPendingLinkUpdates() 1.9676 +{ 1.9677 + MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden); 1.9678 + if (!mHasLinksToUpdate) 1.9679 + return; 1.9680 + 1.9681 +#ifdef DEBUG 1.9682 + AutoRestore<bool> saved(mIsLinkUpdateRegistrationsForbidden); 1.9683 + mIsLinkUpdateRegistrationsForbidden = true; 1.9684 +#endif 1.9685 + mLinksToUpdate.EnumerateEntries(EnumeratePendingLinkUpdates, nullptr); 1.9686 + mLinksToUpdate.Clear(); 1.9687 + mHasLinksToUpdate = false; 1.9688 +} 1.9689 + 1.9690 +already_AddRefed<nsIDocument> 1.9691 +nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer) 1.9692 +{ 1.9693 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(this); 1.9694 + NS_ENSURE_TRUE(domDoc, nullptr); 1.9695 + mCreatingStaticClone = true; 1.9696 + 1.9697 + // Make document use different container during cloning. 1.9698 + nsRefPtr<nsDocShell> originalShell = mDocumentContainer.get(); 1.9699 + SetContainer(static_cast<nsDocShell*>(aCloneContainer)); 1.9700 + nsCOMPtr<nsIDOMNode> clonedNode; 1.9701 + nsresult rv = domDoc->CloneNode(true, 1, getter_AddRefs(clonedNode)); 1.9702 + SetContainer(originalShell); 1.9703 + 1.9704 + nsCOMPtr<nsIDocument> clonedDoc; 1.9705 + if (NS_SUCCEEDED(rv)) { 1.9706 + clonedDoc = do_QueryInterface(clonedNode); 1.9707 + if (clonedDoc) { 1.9708 + if (IsStaticDocument()) { 1.9709 + clonedDoc->mOriginalDocument = mOriginalDocument; 1.9710 + } else { 1.9711 + clonedDoc->mOriginalDocument = this; 1.9712 + } 1.9713 + int32_t sheetsCount = GetNumberOfStyleSheets(); 1.9714 + for (int32_t i = 0; i < sheetsCount; ++i) { 1.9715 + nsRefPtr<nsCSSStyleSheet> sheet = do_QueryObject(GetStyleSheetAt(i)); 1.9716 + if (sheet) { 1.9717 + if (sheet->IsApplicable()) { 1.9718 + nsRefPtr<nsCSSStyleSheet> clonedSheet = 1.9719 + sheet->Clone(nullptr, nullptr, clonedDoc, nullptr); 1.9720 + NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!"); 1.9721 + if (clonedSheet) { 1.9722 + clonedDoc->AddStyleSheet(clonedSheet); 1.9723 + } 1.9724 + } 1.9725 + } 1.9726 + } 1.9727 + 1.9728 + sheetsCount = GetNumberOfCatalogStyleSheets(); 1.9729 + for (int32_t i = 0; i < sheetsCount; ++i) { 1.9730 + nsRefPtr<nsCSSStyleSheet> sheet = 1.9731 + do_QueryObject(GetCatalogStyleSheetAt(i)); 1.9732 + if (sheet) { 1.9733 + if (sheet->IsApplicable()) { 1.9734 + nsRefPtr<nsCSSStyleSheet> clonedSheet = 1.9735 + sheet->Clone(nullptr, nullptr, clonedDoc, nullptr); 1.9736 + NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!"); 1.9737 + if (clonedSheet) { 1.9738 + clonedDoc->AddCatalogStyleSheet(clonedSheet); 1.9739 + } 1.9740 + } 1.9741 + } 1.9742 + } 1.9743 + } 1.9744 + } 1.9745 + mCreatingStaticClone = false; 1.9746 + return clonedDoc.forget(); 1.9747 +} 1.9748 + 1.9749 +nsresult 1.9750 +nsIDocument::ScheduleFrameRequestCallback(const FrameRequestCallbackHolder& aCallback, 1.9751 + int32_t *aHandle) 1.9752 +{ 1.9753 + if (mFrameRequestCallbackCounter == INT32_MAX) { 1.9754 + // Can't increment without overflowing; bail out 1.9755 + return NS_ERROR_NOT_AVAILABLE; 1.9756 + } 1.9757 + int32_t newHandle = ++mFrameRequestCallbackCounter; 1.9758 + 1.9759 + bool alreadyRegistered = !mFrameRequestCallbacks.IsEmpty(); 1.9760 + DebugOnly<FrameRequest*> request = 1.9761 + mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle)); 1.9762 + NS_ASSERTION(request, "This is supposed to be infallible!"); 1.9763 + if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled()) { 1.9764 + mPresShell->GetPresContext()->RefreshDriver()-> 1.9765 + ScheduleFrameRequestCallbacks(this); 1.9766 + } 1.9767 + 1.9768 + *aHandle = newHandle; 1.9769 + return NS_OK; 1.9770 +} 1.9771 + 1.9772 +void 1.9773 +nsIDocument::CancelFrameRequestCallback(int32_t aHandle) 1.9774 +{ 1.9775 + // mFrameRequestCallbacks is stored sorted by handle 1.9776 + if (mFrameRequestCallbacks.RemoveElementSorted(aHandle) && 1.9777 + mFrameRequestCallbacks.IsEmpty() && 1.9778 + mPresShell && IsEventHandlingEnabled()) { 1.9779 + mPresShell->GetPresContext()->RefreshDriver()-> 1.9780 + RevokeFrameRequestCallbacks(this); 1.9781 + } 1.9782 +} 1.9783 + 1.9784 +nsresult 1.9785 +nsDocument::GetStateObject(nsIVariant** aState) 1.9786 +{ 1.9787 + // Get the document's current state object. This is the object backing both 1.9788 + // history.state and popStateEvent.state. 1.9789 + // 1.9790 + // mStateObjectContainer may be null; this just means that there's no 1.9791 + // current state object. 1.9792 + 1.9793 + nsCOMPtr<nsIVariant> stateObj; 1.9794 + if (!mStateObjectCached && mStateObjectContainer) { 1.9795 + AutoJSContext cx; 1.9796 + nsIGlobalObject* sgo = GetScopeObject(); 1.9797 + NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED); 1.9798 + JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject()); 1.9799 + NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED); 1.9800 + JSAutoCompartment ac(cx, global); 1.9801 + 1.9802 + mStateObjectContainer-> 1.9803 + DeserializeToVariant(cx, getter_AddRefs(mStateObjectCached)); 1.9804 + } 1.9805 + 1.9806 + NS_IF_ADDREF(*aState = mStateObjectCached); 1.9807 + 1.9808 + return NS_OK; 1.9809 +} 1.9810 + 1.9811 +nsDOMNavigationTiming* 1.9812 +nsDocument::GetNavigationTiming() const 1.9813 +{ 1.9814 + return mTiming; 1.9815 +} 1.9816 + 1.9817 +nsresult 1.9818 +nsDocument::SetNavigationTiming(nsDOMNavigationTiming* aTiming) 1.9819 +{ 1.9820 + mTiming = aTiming; 1.9821 + if (!mLoadingTimeStamp.IsNull() && mTiming) { 1.9822 + mTiming->SetDOMLoadingTimeStamp(nsIDocument::GetDocumentURI(), mLoadingTimeStamp); 1.9823 + } 1.9824 + return NS_OK; 1.9825 +} 1.9826 + 1.9827 +Element* 1.9828 +nsDocument::FindImageMap(const nsAString& aUseMapValue) 1.9829 +{ 1.9830 + if (aUseMapValue.IsEmpty()) { 1.9831 + return nullptr; 1.9832 + } 1.9833 + 1.9834 + nsAString::const_iterator start, end; 1.9835 + aUseMapValue.BeginReading(start); 1.9836 + aUseMapValue.EndReading(end); 1.9837 + 1.9838 + int32_t hash = aUseMapValue.FindChar('#'); 1.9839 + if (hash < 0) { 1.9840 + return nullptr; 1.9841 + } 1.9842 + // aUsemap contains a '#', set start to point right after the '#' 1.9843 + start.advance(hash + 1); 1.9844 + 1.9845 + if (start == end) { 1.9846 + return nullptr; // aUsemap == "#" 1.9847 + } 1.9848 + 1.9849 + const nsAString& mapName = Substring(start, end); 1.9850 + 1.9851 + if (!mImageMaps) { 1.9852 + mImageMaps = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::map, nsGkAtoms::map); 1.9853 + } 1.9854 + 1.9855 + uint32_t i, n = mImageMaps->Length(true); 1.9856 + nsString name; 1.9857 + for (i = 0; i < n; ++i) { 1.9858 + nsIContent* map = mImageMaps->Item(i); 1.9859 + if (map->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, mapName, 1.9860 + eCaseMatters) || 1.9861 + (map->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name) && 1.9862 + mapName.Equals(name, nsCaseInsensitiveStringComparator()))) { 1.9863 + return map->AsElement(); 1.9864 + } 1.9865 + } 1.9866 + 1.9867 + return nullptr; 1.9868 +} 1.9869 + 1.9870 +#define DEPRECATED_OPERATION(_op) #_op "Warning", 1.9871 +static const char* kWarnings[] = { 1.9872 +#include "nsDeprecatedOperationList.h" 1.9873 + nullptr 1.9874 +}; 1.9875 +#undef DEPRECATED_OPERATION 1.9876 + 1.9877 +void 1.9878 +nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation, 1.9879 + bool asError /* = false */) 1.9880 +{ 1.9881 + static_assert(eDeprecatedOperationCount <= 64, 1.9882 + "Too many deprecated operations"); 1.9883 + if (mWarnedAbout & (1ull << aOperation)) { 1.9884 + return; 1.9885 + } 1.9886 + mWarnedAbout |= (1ull << aOperation); 1.9887 + uint32_t flags = asError ? nsIScriptError::errorFlag 1.9888 + : nsIScriptError::warningFlag; 1.9889 + nsContentUtils::ReportToConsole(flags, 1.9890 + NS_LITERAL_CSTRING("DOM Core"), this, 1.9891 + nsContentUtils::eDOM_PROPERTIES, 1.9892 + kWarnings[aOperation]); 1.9893 +} 1.9894 + 1.9895 +nsresult 1.9896 +nsDocument::AddImage(imgIRequest* aImage) 1.9897 +{ 1.9898 + NS_ENSURE_ARG_POINTER(aImage); 1.9899 + 1.9900 + // See if the image is already in the hashtable. If it is, get the old count. 1.9901 + uint32_t oldCount = 0; 1.9902 + mImageTracker.Get(aImage, &oldCount); 1.9903 + 1.9904 + // Put the image in the hashtable, with the proper count. 1.9905 + mImageTracker.Put(aImage, oldCount + 1); 1.9906 + 1.9907 + nsresult rv = NS_OK; 1.9908 + 1.9909 + // If this is the first insertion and we're locking images, lock this image 1.9910 + // too. 1.9911 + if (oldCount == 0) { 1.9912 + if (mLockingImages) 1.9913 + rv = aImage->LockImage(); 1.9914 + if (NS_SUCCEEDED(rv) && (!sOnloadDecodeLimit || 1.9915 + mImageTracker.Count() < sOnloadDecodeLimit)) 1.9916 + rv = aImage->StartDecoding(); 1.9917 + } 1.9918 + 1.9919 + // If this is the first insertion and we're animating images, request 1.9920 + // that this image be animated too. 1.9921 + if (oldCount == 0 && mAnimatingImages) { 1.9922 + nsresult rv2 = aImage->IncrementAnimationConsumers(); 1.9923 + rv = NS_SUCCEEDED(rv) ? rv2 : rv; 1.9924 + } 1.9925 + 1.9926 + return rv; 1.9927 +} 1.9928 + 1.9929 +nsresult 1.9930 +nsDocument::RemoveImage(imgIRequest* aImage, uint32_t aFlags) 1.9931 +{ 1.9932 + NS_ENSURE_ARG_POINTER(aImage); 1.9933 + 1.9934 + // Get the old count. It should exist and be > 0. 1.9935 + uint32_t count = 0; 1.9936 + DebugOnly<bool> found = mImageTracker.Get(aImage, &count); 1.9937 + NS_ABORT_IF_FALSE(found, "Removing image that wasn't in the tracker!"); 1.9938 + NS_ABORT_IF_FALSE(count > 0, "Entry in the cache tracker with count 0!"); 1.9939 + 1.9940 + // We're removing, so decrement the count. 1.9941 + count--; 1.9942 + 1.9943 + // If the count is now zero, remove from the tracker. 1.9944 + // Otherwise, set the new value. 1.9945 + if (count != 0) { 1.9946 + mImageTracker.Put(aImage, count); 1.9947 + return NS_OK; 1.9948 + } 1.9949 + 1.9950 + mImageTracker.Remove(aImage); 1.9951 + 1.9952 + nsresult rv = NS_OK; 1.9953 + 1.9954 + // Now that we're no longer tracking this image, unlock it if we'd 1.9955 + // previously locked it. 1.9956 + if (mLockingImages) { 1.9957 + rv = aImage->UnlockImage(); 1.9958 + } 1.9959 + 1.9960 + // If we're animating images, remove our request to animate this one. 1.9961 + if (mAnimatingImages) { 1.9962 + nsresult rv2 = aImage->DecrementAnimationConsumers(); 1.9963 + rv = NS_SUCCEEDED(rv) ? rv2 : rv; 1.9964 + } 1.9965 + 1.9966 + if (aFlags & REQUEST_DISCARD) { 1.9967 + // Request that the image be discarded if nobody else holds a lock on it. 1.9968 + // Do this even if !mLockingImages, because even if we didn't just unlock 1.9969 + // this image, it might still be a candidate for discarding. 1.9970 + aImage->RequestDiscard(); 1.9971 + } 1.9972 + 1.9973 + return rv; 1.9974 +} 1.9975 + 1.9976 +nsresult 1.9977 +nsDocument::AddPlugin(nsIObjectLoadingContent* aPlugin) 1.9978 +{ 1.9979 + MOZ_ASSERT(aPlugin); 1.9980 + if (!mPlugins.PutEntry(aPlugin)) { 1.9981 + return NS_ERROR_OUT_OF_MEMORY; 1.9982 + } 1.9983 + return NS_OK; 1.9984 +} 1.9985 + 1.9986 +void 1.9987 +nsDocument::RemovePlugin(nsIObjectLoadingContent* aPlugin) 1.9988 +{ 1.9989 + MOZ_ASSERT(aPlugin); 1.9990 + mPlugins.RemoveEntry(aPlugin); 1.9991 +} 1.9992 + 1.9993 +static bool 1.9994 +AllSubDocumentPluginEnum(nsIDocument* aDocument, void* userArg) 1.9995 +{ 1.9996 + nsTArray<nsIObjectLoadingContent*>* plugins = 1.9997 + reinterpret_cast< nsTArray<nsIObjectLoadingContent*>* >(userArg); 1.9998 + MOZ_ASSERT(plugins); 1.9999 + aDocument->GetPlugins(*plugins); 1.10000 + return true; 1.10001 +} 1.10002 + 1.10003 +static PLDHashOperator 1.10004 +AllPluginEnum(nsPtrHashKey<nsIObjectLoadingContent>* aPlugin, void* userArg) 1.10005 +{ 1.10006 + nsTArray<nsIObjectLoadingContent*>* allPlugins = 1.10007 + reinterpret_cast< nsTArray<nsIObjectLoadingContent*>* >(userArg); 1.10008 + MOZ_ASSERT(allPlugins); 1.10009 + allPlugins->AppendElement(aPlugin->GetKey()); 1.10010 + return PL_DHASH_NEXT; 1.10011 +} 1.10012 + 1.10013 +void 1.10014 +nsDocument::GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins) 1.10015 +{ 1.10016 + aPlugins.SetCapacity(aPlugins.Length() + mPlugins.Count()); 1.10017 + mPlugins.EnumerateEntries(AllPluginEnum, &aPlugins); 1.10018 + EnumerateSubDocuments(AllSubDocumentPluginEnum, &aPlugins); 1.10019 +} 1.10020 + 1.10021 +PLDHashOperator LockEnumerator(imgIRequest* aKey, 1.10022 + uint32_t aData, 1.10023 + void* userArg) 1.10024 +{ 1.10025 + aKey->LockImage(); 1.10026 + aKey->RequestDecode(); 1.10027 + return PL_DHASH_NEXT; 1.10028 +} 1.10029 + 1.10030 +PLDHashOperator UnlockEnumerator(imgIRequest* aKey, 1.10031 + uint32_t aData, 1.10032 + void* userArg) 1.10033 +{ 1.10034 + aKey->UnlockImage(); 1.10035 + return PL_DHASH_NEXT; 1.10036 +} 1.10037 + 1.10038 + 1.10039 +nsresult 1.10040 +nsDocument::SetImageLockingState(bool aLocked) 1.10041 +{ 1.10042 + if (XRE_GetProcessType() == GeckoProcessType_Content && 1.10043 + !Preferences::GetBool("image.mem.allow_locking_in_content_processes", true)) { 1.10044 + return NS_OK; 1.10045 + } 1.10046 + 1.10047 + // If there's no change, there's nothing to do. 1.10048 + if (mLockingImages == aLocked) 1.10049 + return NS_OK; 1.10050 + 1.10051 + // Otherwise, iterate over our images and perform the appropriate action. 1.10052 + mImageTracker.EnumerateRead(aLocked ? LockEnumerator 1.10053 + : UnlockEnumerator, 1.10054 + nullptr); 1.10055 + 1.10056 + // Update state. 1.10057 + mLockingImages = aLocked; 1.10058 + 1.10059 + return NS_OK; 1.10060 +} 1.10061 + 1.10062 +PLDHashOperator IncrementAnimationEnumerator(imgIRequest* aKey, 1.10063 + uint32_t aData, 1.10064 + void* userArg) 1.10065 +{ 1.10066 + aKey->IncrementAnimationConsumers(); 1.10067 + return PL_DHASH_NEXT; 1.10068 +} 1.10069 + 1.10070 +PLDHashOperator DecrementAnimationEnumerator(imgIRequest* aKey, 1.10071 + uint32_t aData, 1.10072 + void* userArg) 1.10073 +{ 1.10074 + aKey->DecrementAnimationConsumers(); 1.10075 + return PL_DHASH_NEXT; 1.10076 +} 1.10077 + 1.10078 +void 1.10079 +nsDocument::SetImagesNeedAnimating(bool aAnimating) 1.10080 +{ 1.10081 + // If there's no change, there's nothing to do. 1.10082 + if (mAnimatingImages == aAnimating) 1.10083 + return; 1.10084 + 1.10085 + // Otherwise, iterate over our images and perform the appropriate action. 1.10086 + mImageTracker.EnumerateRead(aAnimating ? IncrementAnimationEnumerator 1.10087 + : DecrementAnimationEnumerator, 1.10088 + nullptr); 1.10089 + 1.10090 + // Update state. 1.10091 + mAnimatingImages = aAnimating; 1.10092 +} 1.10093 + 1.10094 +already_AddRefed<Touch> 1.10095 +nsIDocument::CreateTouch(nsIDOMWindow* aView, 1.10096 + EventTarget* aTarget, 1.10097 + int32_t aIdentifier, 1.10098 + int32_t aPageX, int32_t aPageY, 1.10099 + int32_t aScreenX, int32_t aScreenY, 1.10100 + int32_t aClientX, int32_t aClientY, 1.10101 + int32_t aRadiusX, int32_t aRadiusY, 1.10102 + float aRotationAngle, 1.10103 + float aForce) 1.10104 +{ 1.10105 + nsRefPtr<Touch> touch = new Touch(aTarget, 1.10106 + aIdentifier, 1.10107 + aPageX, aPageY, 1.10108 + aScreenX, aScreenY, 1.10109 + aClientX, aClientY, 1.10110 + aRadiusX, aRadiusY, 1.10111 + aRotationAngle, 1.10112 + aForce); 1.10113 + return touch.forget(); 1.10114 +} 1.10115 + 1.10116 +already_AddRefed<TouchList> 1.10117 +nsIDocument::CreateTouchList() 1.10118 +{ 1.10119 + nsRefPtr<TouchList> retval = new TouchList(ToSupports(this)); 1.10120 + return retval.forget(); 1.10121 +} 1.10122 + 1.10123 +already_AddRefed<TouchList> 1.10124 +nsIDocument::CreateTouchList(Touch& aTouch, 1.10125 + const Sequence<OwningNonNull<Touch> >& aTouches) 1.10126 +{ 1.10127 + nsRefPtr<TouchList> retval = new TouchList(ToSupports(this)); 1.10128 + retval->Append(&aTouch); 1.10129 + for (uint32_t i = 0; i < aTouches.Length(); ++i) { 1.10130 + retval->Append(aTouches[i].get()); 1.10131 + } 1.10132 + return retval.forget(); 1.10133 +} 1.10134 + 1.10135 +already_AddRefed<TouchList> 1.10136 +nsIDocument::CreateTouchList(const Sequence<OwningNonNull<Touch> >& aTouches) 1.10137 +{ 1.10138 + nsRefPtr<TouchList> retval = new TouchList(ToSupports(this)); 1.10139 + for (uint32_t i = 0; i < aTouches.Length(); ++i) { 1.10140 + retval->Append(aTouches[i].get()); 1.10141 + } 1.10142 + return retval.forget(); 1.10143 +} 1.10144 + 1.10145 +already_AddRefed<nsDOMCaretPosition> 1.10146 +nsIDocument::CaretPositionFromPoint(float aX, float aY) 1.10147 +{ 1.10148 + nscoord x = nsPresContext::CSSPixelsToAppUnits(aX); 1.10149 + nscoord y = nsPresContext::CSSPixelsToAppUnits(aY); 1.10150 + nsPoint pt(x, y); 1.10151 + 1.10152 + FlushPendingNotifications(Flush_Layout); 1.10153 + 1.10154 + nsIPresShell *ps = GetShell(); 1.10155 + if (!ps) { 1.10156 + return nullptr; 1.10157 + } 1.10158 + 1.10159 + nsIFrame *rootFrame = ps->GetRootFrame(); 1.10160 + 1.10161 + // XUL docs, unlike HTML, have no frame tree until everything's done loading 1.10162 + if (!rootFrame) { 1.10163 + return nullptr; 1.10164 + } 1.10165 + 1.10166 + nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, 1.10167 + nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC); 1.10168 + if (!ptFrame) { 1.10169 + return nullptr; 1.10170 + } 1.10171 + 1.10172 + // GetContentOffsetsFromPoint requires frame-relative coordinates, so we need 1.10173 + // to adjust to frame-relative coordinates before we can perform this call. 1.10174 + // It should also not take into account the padding of the frame. 1.10175 + nsPoint adjustedPoint = pt - ptFrame->GetOffsetTo(rootFrame); 1.10176 + 1.10177 + nsFrame::ContentOffsets offsets = 1.10178 + ptFrame->GetContentOffsetsFromPoint(adjustedPoint); 1.10179 + 1.10180 + nsCOMPtr<nsIContent> node = offsets.content; 1.10181 + uint32_t offset = offsets.offset; 1.10182 + nsCOMPtr<nsIContent> anonNode = node; 1.10183 + bool nodeIsAnonymous = node && node->IsInNativeAnonymousSubtree(); 1.10184 + if (nodeIsAnonymous) { 1.10185 + node = ptFrame->GetContent(); 1.10186 + nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent(); 1.10187 + nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(nonanon); 1.10188 + nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon); 1.10189 + bool isText; 1.10190 + if (textArea || (input && 1.10191 + NS_SUCCEEDED(input->MozIsTextField(false, &isText)) && 1.10192 + isText)) { 1.10193 + // If the anonymous content node has a child, then we need to make sure 1.10194 + // that we get the appropriate child, as otherwise the offset may not be 1.10195 + // correct when we construct a range for it. 1.10196 + nsCOMPtr<nsIContent> firstChild = anonNode->GetFirstChild(); 1.10197 + if (firstChild) { 1.10198 + anonNode = firstChild; 1.10199 + } 1.10200 + 1.10201 + if (textArea) { 1.10202 + offset = nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame, offset); 1.10203 + } 1.10204 + 1.10205 + node = nonanon; 1.10206 + } else { 1.10207 + node = nullptr; 1.10208 + offset = 0; 1.10209 + } 1.10210 + } 1.10211 + 1.10212 + nsRefPtr<nsDOMCaretPosition> aCaretPos = new nsDOMCaretPosition(node, offset); 1.10213 + if (nodeIsAnonymous) { 1.10214 + aCaretPos->SetAnonymousContentNode(anonNode); 1.10215 + } 1.10216 + return aCaretPos.forget(); 1.10217 +} 1.10218 + 1.10219 +NS_IMETHODIMP 1.10220 +nsDocument::CaretPositionFromPoint(float aX, float aY, nsISupports** aCaretPos) 1.10221 +{ 1.10222 + NS_ENSURE_ARG_POINTER(aCaretPos); 1.10223 + *aCaretPos = nsIDocument::CaretPositionFromPoint(aX, aY).take(); 1.10224 + return NS_OK; 1.10225 +} 1.10226 + 1.10227 +void 1.10228 +nsIDocument::ObsoleteSheet(nsIURI *aSheetURI, ErrorResult& rv) 1.10229 +{ 1.10230 + nsresult res = CSSLoader()->ObsoleteSheet(aSheetURI); 1.10231 + if (NS_FAILED(res)) { 1.10232 + rv.Throw(res); 1.10233 + } 1.10234 +} 1.10235 + 1.10236 +void 1.10237 +nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv) 1.10238 +{ 1.10239 + nsCOMPtr<nsIURI> uri; 1.10240 + nsresult res = NS_NewURI(getter_AddRefs(uri), aSheetURI); 1.10241 + if (NS_FAILED(res)) { 1.10242 + rv.Throw(res); 1.10243 + return; 1.10244 + } 1.10245 + res = CSSLoader()->ObsoleteSheet(uri); 1.10246 + if (NS_FAILED(res)) { 1.10247 + rv.Throw(res); 1.10248 + } 1.10249 +} 1.10250 + 1.10251 +nsIHTMLCollection* 1.10252 +nsIDocument::Children() 1.10253 +{ 1.10254 + if (!mChildrenCollection) { 1.10255 + mChildrenCollection = new nsContentList(this, kNameSpaceID_Wildcard, 1.10256 + nsGkAtoms::_asterix, 1.10257 + nsGkAtoms::_asterix, 1.10258 + false); 1.10259 + } 1.10260 + 1.10261 + return mChildrenCollection; 1.10262 +} 1.10263 + 1.10264 +uint32_t 1.10265 +nsIDocument::ChildElementCount() 1.10266 +{ 1.10267 + return Children()->Length(); 1.10268 +} 1.10269 + 1.10270 +namespace mozilla { 1.10271 + 1.10272 +// Singleton class to manage the list of fullscreen documents which are the 1.10273 +// root of a branch which contains fullscreen documents. We maintain this list 1.10274 +// so that we can easily exit all windows from fullscreen when the user 1.10275 +// presses the escape key. 1.10276 +class FullscreenRoots { 1.10277 +public: 1.10278 + // Adds a root to the manager. Adding a root multiple times does not result 1.10279 + // in duplicate entries for that item, only one. 1.10280 + static void Add(nsIDocument* aRoot); 1.10281 + 1.10282 + // Iterates over every root in the root list, and calls aFunction, passing 1.10283 + // each root once to aFunction. It is safe to call Add() and Remove() while 1.10284 + // iterating over the list (i.e. in aFunction). Documents that are removed 1.10285 + // from the manager during traversal are not traversed, and documents that 1.10286 + // are added to the manager during traversal are also not traversed. 1.10287 + static void ForEach(void(*aFunction)(nsIDocument* aDoc)); 1.10288 + 1.10289 + // Removes a specific root from the manager. 1.10290 + static void Remove(nsIDocument* aRoot); 1.10291 + 1.10292 + // Returns true if all roots added to the list have been removed. 1.10293 + static bool IsEmpty(); 1.10294 + 1.10295 +private: 1.10296 + 1.10297 + FullscreenRoots() { 1.10298 + MOZ_COUNT_CTOR(FullscreenRoots); 1.10299 + } 1.10300 + ~FullscreenRoots() { 1.10301 + MOZ_COUNT_DTOR(FullscreenRoots); 1.10302 + } 1.10303 + 1.10304 + enum { 1.10305 + NotFound = uint32_t(-1) 1.10306 + }; 1.10307 + // Looks in mRoots for aRoot. Returns the index if found, otherwise NotFound. 1.10308 + static uint32_t Find(nsIDocument* aRoot); 1.10309 + 1.10310 + // Returns true if aRoot is in the list of fullscreen roots. 1.10311 + static bool Contains(nsIDocument* aRoot); 1.10312 + 1.10313 + // Singleton instance of the FullscreenRoots. This is instantiated when a 1.10314 + // root is added, and it is deleted when the last root is removed. 1.10315 + static FullscreenRoots* sInstance; 1.10316 + 1.10317 + // List of weak pointers to roots. 1.10318 + nsTArray<nsWeakPtr> mRoots; 1.10319 +}; 1.10320 + 1.10321 +FullscreenRoots* FullscreenRoots::sInstance = nullptr; 1.10322 + 1.10323 +/* static */ 1.10324 +void 1.10325 +FullscreenRoots::ForEach(void(*aFunction)(nsIDocument* aDoc)) 1.10326 +{ 1.10327 + if (!sInstance) { 1.10328 + return; 1.10329 + } 1.10330 + // Create a copy of the roots array, and iterate over the copy. This is so 1.10331 + // that if an element is removed from mRoots we don't mess up our iteration. 1.10332 + nsTArray<nsWeakPtr> roots(sInstance->mRoots); 1.10333 + // Call aFunction on all entries. 1.10334 + for (uint32_t i = 0; i < roots.Length(); i++) { 1.10335 + nsCOMPtr<nsIDocument> root = do_QueryReferent(roots[i]); 1.10336 + // Check that the root isn't in the manager. This is so that new additions 1.10337 + // while we were running don't get traversed. 1.10338 + if (root && FullscreenRoots::Contains(root)) { 1.10339 + aFunction(root); 1.10340 + } 1.10341 + } 1.10342 +} 1.10343 + 1.10344 +/* static */ 1.10345 +bool 1.10346 +FullscreenRoots::Contains(nsIDocument* aRoot) 1.10347 +{ 1.10348 + return FullscreenRoots::Find(aRoot) != NotFound; 1.10349 +} 1.10350 + 1.10351 +/* static */ 1.10352 +void 1.10353 +FullscreenRoots::Add(nsIDocument* aRoot) 1.10354 +{ 1.10355 + if (!FullscreenRoots::Contains(aRoot)) { 1.10356 + if (!sInstance) { 1.10357 + sInstance = new FullscreenRoots(); 1.10358 + } 1.10359 + nsWeakPtr weakRoot = do_GetWeakReference(aRoot); 1.10360 + sInstance->mRoots.AppendElement(weakRoot); 1.10361 + } 1.10362 +} 1.10363 + 1.10364 +/* static */ 1.10365 +uint32_t 1.10366 +FullscreenRoots::Find(nsIDocument* aRoot) 1.10367 +{ 1.10368 + if (!sInstance) { 1.10369 + return NotFound; 1.10370 + } 1.10371 + nsTArray<nsWeakPtr>& roots = sInstance->mRoots; 1.10372 + for (uint32_t i = 0; i < roots.Length(); i++) { 1.10373 + nsCOMPtr<nsIDocument> otherRoot(do_QueryReferent(roots[i])); 1.10374 + if (otherRoot == aRoot) { 1.10375 + return i; 1.10376 + } 1.10377 + } 1.10378 + return NotFound; 1.10379 +} 1.10380 + 1.10381 +/* static */ 1.10382 +void 1.10383 +FullscreenRoots::Remove(nsIDocument* aRoot) 1.10384 +{ 1.10385 + uint32_t index = Find(aRoot); 1.10386 + NS_ASSERTION(index != NotFound, 1.10387 + "Should only try to remove roots which are still added!"); 1.10388 + if (index == NotFound || !sInstance) { 1.10389 + return; 1.10390 + } 1.10391 + sInstance->mRoots.RemoveElementAt(index); 1.10392 + if (sInstance->mRoots.IsEmpty()) { 1.10393 + delete sInstance; 1.10394 + sInstance = nullptr; 1.10395 + } 1.10396 +} 1.10397 + 1.10398 +/* static */ 1.10399 +bool 1.10400 +FullscreenRoots::IsEmpty() 1.10401 +{ 1.10402 + return !sInstance; 1.10403 +} 1.10404 + 1.10405 +} // end namespace mozilla. 1.10406 +using mozilla::FullscreenRoots; 1.10407 + 1.10408 +nsIDocument* 1.10409 +nsDocument::GetFullscreenRoot() 1.10410 +{ 1.10411 + nsCOMPtr<nsIDocument> root = do_QueryReferent(mFullscreenRoot); 1.10412 + return root; 1.10413 +} 1.10414 + 1.10415 +void 1.10416 +nsDocument::SetFullscreenRoot(nsIDocument* aRoot) 1.10417 +{ 1.10418 + mFullscreenRoot = do_GetWeakReference(aRoot); 1.10419 +} 1.10420 + 1.10421 +NS_IMETHODIMP 1.10422 +nsDocument::MozCancelFullScreen() 1.10423 +{ 1.10424 + nsIDocument::MozCancelFullScreen(); 1.10425 + return NS_OK; 1.10426 +} 1.10427 + 1.10428 +void 1.10429 +nsIDocument::MozCancelFullScreen() 1.10430 +{ 1.10431 + RestorePreviousFullScreenState(); 1.10432 +} 1.10433 + 1.10434 +// Runnable to set window full-screen mode. Used as a script runner 1.10435 +// to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to 1.10436 +// run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event 1.10437 +// (handled in chome code) which is unsafe to run if this is called in 1.10438 +// Element::UnbindFromTree(). 1.10439 +class nsSetWindowFullScreen : public nsRunnable { 1.10440 +public: 1.10441 + nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue) 1.10442 + : mDoc(aDoc), mValue(aValue) {} 1.10443 + 1.10444 + NS_IMETHOD Run() 1.10445 + { 1.10446 + if (mDoc->GetWindow()) { 1.10447 + mDoc->GetWindow()->SetFullScreenInternal(mValue, false); 1.10448 + } 1.10449 + return NS_OK; 1.10450 + } 1.10451 + 1.10452 +private: 1.10453 + nsCOMPtr<nsIDocument> mDoc; 1.10454 + bool mValue; 1.10455 +}; 1.10456 + 1.10457 +static nsIDocument* 1.10458 +GetFullscreenRootDocument(nsIDocument* aDoc) 1.10459 +{ 1.10460 + if (!aDoc) { 1.10461 + return nullptr; 1.10462 + } 1.10463 + nsIDocument* doc = aDoc; 1.10464 + nsIDocument* parent; 1.10465 + while ((parent = doc->GetParentDocument()) && 1.10466 + (!nsContentUtils::IsFullscreenApiContentOnly() || 1.10467 + !nsContentUtils::IsChromeDoc(parent))) { 1.10468 + doc = parent; 1.10469 + } 1.10470 + return doc; 1.10471 +} 1.10472 + 1.10473 +static void 1.10474 +SetWindowFullScreen(nsIDocument* aDoc, bool aValue) 1.10475 +{ 1.10476 + // Maintain list of fullscreen root documents. 1.10477 + nsCOMPtr<nsIDocument> root = GetFullscreenRootDocument(aDoc); 1.10478 + if (aValue) { 1.10479 + FullscreenRoots::Add(root); 1.10480 + } else { 1.10481 + FullscreenRoots::Remove(root); 1.10482 + } 1.10483 + if (!nsContentUtils::IsFullscreenApiContentOnly()) { 1.10484 + nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue)); 1.10485 + } 1.10486 +} 1.10487 + 1.10488 +class nsCallExitFullscreen : public nsRunnable { 1.10489 +public: 1.10490 + nsCallExitFullscreen(nsIDocument* aDoc) 1.10491 + : mDoc(aDoc) {} 1.10492 + NS_IMETHOD Run() 1.10493 + { 1.10494 + nsDocument::ExitFullscreen(mDoc); 1.10495 + return NS_OK; 1.10496 + } 1.10497 +private: 1.10498 + nsCOMPtr<nsIDocument> mDoc; 1.10499 +}; 1.10500 + 1.10501 +/* static */ 1.10502 +void 1.10503 +nsIDocument::ExitFullscreen(nsIDocument* aDoc, bool aRunAsync) 1.10504 +{ 1.10505 + if (aDoc && !aDoc->IsFullScreenDoc()) { 1.10506 + return; 1.10507 + } 1.10508 + if (aRunAsync) { 1.10509 + NS_DispatchToCurrentThread(new nsCallExitFullscreen(aDoc)); 1.10510 + return; 1.10511 + } 1.10512 + nsDocument::ExitFullscreen(aDoc); 1.10513 +} 1.10514 + 1.10515 +// Returns true if the document is a direct child of a cross process parent 1.10516 +// mozbrowser iframe. This is the case when the document has a null parent, 1.10517 +// and its DocShell reports that it is a browser frame. 1.10518 +static bool 1.10519 +HasCrossProcessParent(nsIDocument* aDocument) 1.10520 +{ 1.10521 + if (XRE_GetProcessType() != GeckoProcessType_Content) { 1.10522 + return false; 1.10523 + } 1.10524 + if (aDocument->GetParentDocument() != nullptr) { 1.10525 + return false; 1.10526 + } 1.10527 + nsPIDOMWindow* win = aDocument->GetWindow(); 1.10528 + if (!win) { 1.10529 + return false; 1.10530 + } 1.10531 + nsCOMPtr<nsIDocShell> docShell = win->GetDocShell(); 1.10532 + if (!docShell) { 1.10533 + return false; 1.10534 + } 1.10535 + return docShell->GetIsBrowserOrApp(); 1.10536 +} 1.10537 + 1.10538 +static bool 1.10539 +CountFullscreenSubDocuments(nsIDocument* aDoc, void* aData) 1.10540 +{ 1.10541 + if (aDoc->IsFullScreenDoc()) { 1.10542 + uint32_t* count = static_cast<uint32_t*>(aData); 1.10543 + (*count)++; 1.10544 + } 1.10545 + return true; 1.10546 +} 1.10547 + 1.10548 +static uint32_t 1.10549 +CountFullscreenSubDocuments(nsIDocument* aDoc) 1.10550 +{ 1.10551 + uint32_t count = 0; 1.10552 + aDoc->EnumerateSubDocuments(CountFullscreenSubDocuments, &count); 1.10553 + return count; 1.10554 +} 1.10555 + 1.10556 +bool 1.10557 +nsDocument::IsFullscreenLeaf() 1.10558 +{ 1.10559 + // A fullscreen leaf document is fullscreen, and has no fullscreen 1.10560 + // subdocuments. 1.10561 + if (!IsFullScreenDoc()) { 1.10562 + return false; 1.10563 + } 1.10564 + return CountFullscreenSubDocuments(this) == 0; 1.10565 +} 1.10566 + 1.10567 +static bool 1.10568 +ResetFullScreen(nsIDocument* aDocument, void* aData) 1.10569 +{ 1.10570 + if (aDocument->IsFullScreenDoc()) { 1.10571 + NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1, 1.10572 + "Should have at most 1 fullscreen subdocument."); 1.10573 + static_cast<nsDocument*>(aDocument)->CleanupFullscreenState(); 1.10574 + NS_ASSERTION(!aDocument->IsFullScreenDoc(), "Should reset full-screen"); 1.10575 + nsTArray<nsIDocument*>* changed = reinterpret_cast<nsTArray<nsIDocument*>*>(aData); 1.10576 + changed->AppendElement(aDocument); 1.10577 + 1.10578 + if (HasCrossProcessParent(aDocument)) { 1.10579 + // We're at the top of the content-process side doc tree. Ask the parent 1.10580 + // process to exit fullscreen. 1.10581 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10582 + os->NotifyObservers(aDocument, "ask-parent-to-exit-fullscreen", nullptr); 1.10583 + } 1.10584 + 1.10585 + // Dispatch a notification so that if this document has any 1.10586 + // cross-process subdocuments, they'll be notified to exit fullscreen. 1.10587 + // The BrowserElementParent listens for this event and performs the 1.10588 + // cross process notification if it has a remote child process. 1.10589 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10590 + os->NotifyObservers(aDocument, "ask-children-to-exit-fullscreen", nullptr); 1.10591 + 1.10592 + aDocument->EnumerateSubDocuments(ResetFullScreen, aData); 1.10593 + } 1.10594 + return true; 1.10595 +} 1.10596 + 1.10597 +static void 1.10598 +ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc) 1.10599 +{ 1.10600 + MOZ_ASSERT(aMaybeNotARootDoc); 1.10601 + nsCOMPtr<nsIDocument> root = aMaybeNotARootDoc->GetFullscreenRoot(); 1.10602 + NS_ASSERTION(root, "Should have root when in fullscreen!"); 1.10603 + if (!root) { 1.10604 + return; 1.10605 + } 1.10606 + NS_ASSERTION(root->IsFullScreenDoc(), 1.10607 + "Fullscreen root should be a fullscreen doc..."); 1.10608 + 1.10609 + // Stores a list of documents to which we must dispatch "mozfullscreenchange". 1.10610 + // We're required by the spec to dispatch the events in leaf-to-root 1.10611 + // order when exiting fullscreen, but we traverse the doctree in a 1.10612 + // root-to-leaf order, so we save references to the documents we must 1.10613 + // dispatch to so that we dispatch in the specified order. 1.10614 + nsAutoTArray<nsIDocument*, 8> changed; 1.10615 + 1.10616 + // Walk the tree of fullscreen documents, and reset their fullscreen state. 1.10617 + ResetFullScreen(root, static_cast<void*>(&changed)); 1.10618 + 1.10619 + // Dispatch "mozfullscreenchange" events. Note this loop is in reverse 1.10620 + // order so that the events for the leaf document arrives before the root 1.10621 + // document, as required by the spec. 1.10622 + for (uint32_t i = 0; i < changed.Length(); ++i) { 1.10623 + DispatchFullScreenChange(changed[changed.Length() - i - 1]); 1.10624 + } 1.10625 + 1.10626 + NS_ASSERTION(!root->IsFullScreenDoc(), 1.10627 + "Fullscreen root should no longer be a fullscreen doc..."); 1.10628 + 1.10629 + // Move the top-level window out of fullscreen mode. 1.10630 + SetWindowFullScreen(root, false); 1.10631 +} 1.10632 + 1.10633 +/* static */ 1.10634 +void 1.10635 +nsDocument::ExitFullscreen(nsIDocument* aDoc) 1.10636 +{ 1.10637 + // Unlock the pointer, if it's locked. 1.10638 + nsCOMPtr<Element> pointerLockedElement = 1.10639 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.10640 + if (pointerLockedElement) { 1.10641 + UnlockPointer(); 1.10642 + } 1.10643 + 1.10644 + if (aDoc) { 1.10645 + ExitFullscreenInDocTree(aDoc); 1.10646 + return; 1.10647 + } 1.10648 + 1.10649 + // Clear fullscreen stacks in all fullscreen roots' descendant documents. 1.10650 + FullscreenRoots::ForEach(&ExitFullscreenInDocTree); 1.10651 + NS_ASSERTION(FullscreenRoots::IsEmpty(), 1.10652 + "Should have exited all fullscreen roots from fullscreen"); 1.10653 +} 1.10654 + 1.10655 +bool 1.10656 +GetFullscreenLeaf(nsIDocument* aDoc, void* aData) 1.10657 +{ 1.10658 + if (aDoc->IsFullscreenLeaf()) { 1.10659 + nsIDocument** result = static_cast<nsIDocument**>(aData); 1.10660 + *result = aDoc; 1.10661 + return false; 1.10662 + } else if (aDoc->IsFullScreenDoc()) { 1.10663 + aDoc->EnumerateSubDocuments(GetFullscreenLeaf, aData); 1.10664 + } 1.10665 + return true; 1.10666 +} 1.10667 + 1.10668 +static nsIDocument* 1.10669 +GetFullscreenLeaf(nsIDocument* aDoc) 1.10670 +{ 1.10671 + nsIDocument* leaf = nullptr; 1.10672 + GetFullscreenLeaf(aDoc, &leaf); 1.10673 + if (leaf) { 1.10674 + return leaf; 1.10675 + } 1.10676 + // Otherwise we could be either in a non-fullscreen doc tree, or we're 1.10677 + // below the fullscreen doc. Start the search from the root. 1.10678 + nsIDocument* root = GetFullscreenRootDocument(aDoc); 1.10679 + // Check that the root is actually fullscreen so we don't waste time walking 1.10680 + // around its descendants. 1.10681 + if (!root->IsFullScreenDoc()) { 1.10682 + return nullptr; 1.10683 + } 1.10684 + GetFullscreenLeaf(root, &leaf); 1.10685 + return leaf; 1.10686 +} 1.10687 + 1.10688 +void 1.10689 +nsDocument::RestorePreviousFullScreenState() 1.10690 +{ 1.10691 + NS_ASSERTION(!IsFullScreenDoc() || !FullscreenRoots::IsEmpty(), 1.10692 + "Should have at least 1 fullscreen root when fullscreen!"); 1.10693 + NS_ASSERTION(!nsContentUtils::IsFullscreenApiContentOnly() || 1.10694 + !nsContentUtils::IsChromeDoc(this), 1.10695 + "Should not run RestorePreviousFullScreenState() on " 1.10696 + "chrome document when fullscreen is content only"); 1.10697 + 1.10698 + if (!IsFullScreenDoc() || !GetWindow() || FullscreenRoots::IsEmpty()) { 1.10699 + return; 1.10700 + } 1.10701 + 1.10702 + // If fullscreen mode is updated the pointer should be unlocked 1.10703 + nsCOMPtr<Element> pointerLockedElement = 1.10704 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.10705 + if (pointerLockedElement) { 1.10706 + UnlockPointer(); 1.10707 + } 1.10708 + 1.10709 + nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this); 1.10710 + 1.10711 + // The fullscreen document may contain a <iframe mozbrowser> element which 1.10712 + // has a cross process child. So send a notification so that its browser 1.10713 + // parent will send a message to its child process to also exit fullscreen. 1.10714 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10715 + os->NotifyObservers(fullScreenDoc, "ask-children-to-exit-fullscreen", nullptr); 1.10716 + 1.10717 + // Clear full-screen stacks in all descendant in process documents, bottom up. 1.10718 + nsIDocument* doc = fullScreenDoc; 1.10719 + while (doc != this) { 1.10720 + NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc"); 1.10721 + static_cast<nsDocument*>(doc)->CleanupFullscreenState(); 1.10722 + UnlockPointer(); 1.10723 + DispatchFullScreenChange(doc); 1.10724 + doc = doc->GetParentDocument(); 1.10725 + } 1.10726 + 1.10727 + // Roll-back full-screen state to previous full-screen element. 1.10728 + NS_ASSERTION(doc == this, "Must have reached this doc."); 1.10729 + while (doc != nullptr) { 1.10730 + static_cast<nsDocument*>(doc)->FullScreenStackPop(); 1.10731 + UnlockPointer(); 1.10732 + DispatchFullScreenChange(doc); 1.10733 + if (static_cast<nsDocument*>(doc)->mFullScreenStack.IsEmpty()) { 1.10734 + if (HasCrossProcessParent(doc)) { 1.10735 + // Send notification to the parent process to tell it to rollback to 1.10736 + // the previous fullscreen elements in its fullscreen element stacks. 1.10737 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10738 + os->NotifyObservers(doc, "ask-parent-to-rollback-fullscreen", nullptr); 1.10739 + } 1.10740 + // Full-screen stack in document is empty. Go back up to the parent 1.10741 + // document. We'll pop the containing element off its stack, and use 1.10742 + // its next full-screen element as the full-screen element. 1.10743 + static_cast<nsDocument*>(doc)->CleanupFullscreenState(); 1.10744 + doc = doc->GetParentDocument(); 1.10745 + } else { 1.10746 + // Else we popped the top of the stack, and there's still another 1.10747 + // element in there, so that will become the full-screen element. 1.10748 + if (fullScreenDoc != doc) { 1.10749 + // We've popped so enough off the stack that we've rolled back to 1.10750 + // a fullscreen element in a parent document. If this document isn't 1.10751 + // approved for fullscreen, or if it's cross origin, dispatch an 1.10752 + // event to chrome so it knows to show the authorization/warning UI. 1.10753 + if (!nsContentUtils::HaveEqualPrincipals(fullScreenDoc, doc) || 1.10754 + (!nsContentUtils::IsSitePermAllow(doc->NodePrincipal(), "fullscreen") && 1.10755 + !static_cast<nsDocument*>(doc)->mIsApprovedForFullscreen)) { 1.10756 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.10757 + new AsyncEventDispatcher(doc, 1.10758 + NS_LITERAL_STRING("MozEnteredDomFullscreen"), 1.10759 + true, 1.10760 + true); 1.10761 + asyncDispatcher->PostDOMEvent(); 1.10762 + } 1.10763 + } 1.10764 + 1.10765 + if (!nsContentUtils::HaveEqualPrincipals(doc, fullScreenDoc)) { 1.10766 + // The origin which is fullscreen changed. Send a notification to 1.10767 + // the root process so that a warning or approval UI can be shown 1.10768 + // as necessary. 1.10769 + nsAutoString origin; 1.10770 + nsContentUtils::GetUTFOrigin(doc->NodePrincipal(), origin); 1.10771 + nsIDocument* root = GetFullscreenRootDocument(doc); 1.10772 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10773 + os->NotifyObservers(root, "fullscreen-origin-change", origin.get()); 1.10774 + } 1.10775 + 1.10776 + break; 1.10777 + } 1.10778 + } 1.10779 + 1.10780 + if (doc == nullptr) { 1.10781 + // We moved all documents in this doctree out of fullscreen mode, 1.10782 + // move the top-level window out of fullscreen mode. 1.10783 + NS_ASSERTION(!GetFullscreenRootDocument(this)->IsFullScreenDoc(), 1.10784 + "Should have cleared all docs' stacks"); 1.10785 + SetWindowFullScreen(this, false); 1.10786 + } 1.10787 +} 1.10788 + 1.10789 +bool 1.10790 +nsDocument::IsFullScreenDoc() 1.10791 +{ 1.10792 + return GetFullScreenElement() != nullptr; 1.10793 +} 1.10794 + 1.10795 +class nsCallRequestFullScreen : public nsRunnable 1.10796 +{ 1.10797 +public: 1.10798 + nsCallRequestFullScreen(Element* aElement) 1.10799 + : mElement(aElement), 1.10800 + mDoc(aElement->OwnerDoc()), 1.10801 + mWasCallerChrome(nsContentUtils::IsCallerChrome()), 1.10802 + mHadRequestPending(static_cast<nsDocument*>(mDoc.get())-> 1.10803 + mAsyncFullscreenPending) 1.10804 + { 1.10805 + static_cast<nsDocument*>(mDoc.get())-> 1.10806 + mAsyncFullscreenPending = true; 1.10807 + } 1.10808 + 1.10809 + NS_IMETHOD Run() 1.10810 + { 1.10811 + static_cast<nsDocument*>(mDoc.get())-> 1.10812 + mAsyncFullscreenPending = mHadRequestPending; 1.10813 + nsDocument* doc = static_cast<nsDocument*>(mDoc.get()); 1.10814 + doc->RequestFullScreen(mElement, 1.10815 + mWasCallerChrome, 1.10816 + /* aNotifyOnOriginChange */ true); 1.10817 + return NS_OK; 1.10818 + } 1.10819 + 1.10820 + nsRefPtr<Element> mElement; 1.10821 + nsCOMPtr<nsIDocument> mDoc; 1.10822 + bool mWasCallerChrome; 1.10823 + bool mHadRequestPending; 1.10824 +}; 1.10825 + 1.10826 +void 1.10827 +nsDocument::AsyncRequestFullScreen(Element* aElement) 1.10828 +{ 1.10829 + NS_ASSERTION(aElement, 1.10830 + "Must pass non-null element to nsDocument::AsyncRequestFullScreen"); 1.10831 + if (!aElement) { 1.10832 + return; 1.10833 + } 1.10834 + // Request full-screen asynchronously. 1.10835 + nsCOMPtr<nsIRunnable> event(new nsCallRequestFullScreen(aElement)); 1.10836 + NS_DispatchToCurrentThread(event); 1.10837 +} 1.10838 + 1.10839 +static void 1.10840 +LogFullScreenDenied(bool aLogFailure, const char* aMessage, nsIDocument* aDoc) 1.10841 +{ 1.10842 + if (!aLogFailure) { 1.10843 + return; 1.10844 + } 1.10845 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.10846 + new AsyncEventDispatcher(aDoc, 1.10847 + NS_LITERAL_STRING("mozfullscreenerror"), 1.10848 + true, 1.10849 + false); 1.10850 + asyncDispatcher->PostDOMEvent(); 1.10851 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.10852 + NS_LITERAL_CSTRING("DOM"), aDoc, 1.10853 + nsContentUtils::eDOM_PROPERTIES, 1.10854 + aMessage); 1.10855 +} 1.10856 + 1.10857 +nsresult 1.10858 +nsDocument::AddFullscreenApprovedObserver() 1.10859 +{ 1.10860 + if (mHasFullscreenApprovedObserver || 1.10861 + !Preferences::GetBool("full-screen-api.approval-required")) { 1.10862 + return NS_OK; 1.10863 + } 1.10864 + 1.10865 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10866 + NS_ENSURE_TRUE(os, NS_ERROR_FAILURE); 1.10867 + 1.10868 + nsresult res = os->AddObserver(this, "fullscreen-approved", true); 1.10869 + NS_ENSURE_SUCCESS(res, res); 1.10870 + 1.10871 + mHasFullscreenApprovedObserver = true; 1.10872 + 1.10873 + return NS_OK; 1.10874 +} 1.10875 + 1.10876 +nsresult 1.10877 +nsDocument::RemoveFullscreenApprovedObserver() 1.10878 +{ 1.10879 + if (!mHasFullscreenApprovedObserver) { 1.10880 + return NS_OK; 1.10881 + } 1.10882 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.10883 + NS_ENSURE_TRUE(os, NS_ERROR_FAILURE); 1.10884 + 1.10885 + nsresult res = os->RemoveObserver(this, "fullscreen-approved"); 1.10886 + NS_ENSURE_SUCCESS(res, res); 1.10887 + 1.10888 + mHasFullscreenApprovedObserver = false; 1.10889 + 1.10890 + return NS_OK; 1.10891 +} 1.10892 + 1.10893 +void 1.10894 +nsDocument::CleanupFullscreenState() 1.10895 +{ 1.10896 + if (!mFullScreenStack.IsEmpty()) { 1.10897 + // The top element in the full-screen stack will have full-screen 1.10898 + // style bits set on it and its ancestors. Remove the style bits. 1.10899 + // Note the non-top elements won't have the style bits set. 1.10900 + Element* top = FullScreenStackTop(); 1.10901 + NS_ASSERTION(top, "Should have a top when full-screen stack isn't empty"); 1.10902 + if (top) { 1.10903 + EventStateManager::SetFullScreenState(top, false); 1.10904 + } 1.10905 + mFullScreenStack.Clear(); 1.10906 + } 1.10907 + SetApprovedForFullscreen(false); 1.10908 + RemoveFullscreenApprovedObserver(); 1.10909 + mFullscreenRoot = nullptr; 1.10910 +} 1.10911 + 1.10912 +bool 1.10913 +nsDocument::FullScreenStackPush(Element* aElement) 1.10914 +{ 1.10915 + NS_ASSERTION(aElement, "Must pass non-null to FullScreenStackPush()"); 1.10916 + Element* top = FullScreenStackTop(); 1.10917 + if (top == aElement || !aElement) { 1.10918 + return false; 1.10919 + } 1.10920 + if (top) { 1.10921 + // We're pushing a new element onto the full-screen stack, so we must 1.10922 + // remove the ancestor and full-screen styles from the former top of the 1.10923 + // stack. 1.10924 + EventStateManager::SetFullScreenState(top, false); 1.10925 + } 1.10926 + EventStateManager::SetFullScreenState(aElement, true); 1.10927 + nsWeakPtr weakElement = do_GetWeakReference(aElement); 1.10928 + mFullScreenStack.AppendElement(weakElement); 1.10929 + NS_ASSERTION(GetFullScreenElement() == aElement, "Should match"); 1.10930 + return true; 1.10931 +} 1.10932 + 1.10933 +void 1.10934 +nsDocument::FullScreenStackPop() 1.10935 +{ 1.10936 + if (mFullScreenStack.IsEmpty()) { 1.10937 + return; 1.10938 + } 1.10939 + 1.10940 + // Remove styles from existing top element. 1.10941 + Element* top = FullScreenStackTop(); 1.10942 + EventStateManager::SetFullScreenState(top, false); 1.10943 + 1.10944 + // Remove top element. Note the remaining top element in the stack 1.10945 + // will not have full-screen style bits set, so we will need to restore 1.10946 + // them on the new top element before returning. 1.10947 + uint32_t last = mFullScreenStack.Length() - 1; 1.10948 + mFullScreenStack.RemoveElementAt(last); 1.10949 + 1.10950 + // Pop from the stack null elements (references to elements which have 1.10951 + // been GC'd since they were added to the stack) and elements which are 1.10952 + // no longer in this document. 1.10953 + while (!mFullScreenStack.IsEmpty()) { 1.10954 + Element* element = FullScreenStackTop(); 1.10955 + if (!element || !element->IsInDoc() || element->OwnerDoc() != this) { 1.10956 + NS_ASSERTION(!element->IsFullScreenAncestor(), 1.10957 + "Should have already removed full-screen styles"); 1.10958 + uint32_t last = mFullScreenStack.Length() - 1; 1.10959 + mFullScreenStack.RemoveElementAt(last); 1.10960 + } else { 1.10961 + // The top element of the stack is now an in-doc element. Apply the 1.10962 + // full-screen styles and return. 1.10963 + EventStateManager::SetFullScreenState(element, true); 1.10964 + break; 1.10965 + } 1.10966 + } 1.10967 +} 1.10968 + 1.10969 +Element* 1.10970 +nsDocument::FullScreenStackTop() 1.10971 +{ 1.10972 + if (mFullScreenStack.IsEmpty()) { 1.10973 + return nullptr; 1.10974 + } 1.10975 + uint32_t last = mFullScreenStack.Length() - 1; 1.10976 + nsCOMPtr<Element> element(do_QueryReferent(mFullScreenStack[last])); 1.10977 + NS_ASSERTION(element, "Should have full-screen element!"); 1.10978 + NS_ASSERTION(element->IsInDoc(), "Full-screen element should be in doc"); 1.10979 + NS_ASSERTION(element->OwnerDoc() == this, "Full-screen element should be in this doc"); 1.10980 + return element; 1.10981 +} 1.10982 + 1.10983 +// Returns true if aDoc is in the focused tab in the active window. 1.10984 +static bool 1.10985 +IsInActiveTab(nsIDocument* aDoc) 1.10986 +{ 1.10987 + nsCOMPtr<nsIDocShell> docshell = aDoc->GetDocShell(); 1.10988 + if (!docshell) { 1.10989 + return false; 1.10990 + } 1.10991 + 1.10992 + bool isActive = false; 1.10993 + docshell->GetIsActive(&isActive); 1.10994 + if (!isActive) { 1.10995 + return false; 1.10996 + } 1.10997 + 1.10998 + nsCOMPtr<nsIDocShellTreeItem> rootItem; 1.10999 + docshell->GetRootTreeItem(getter_AddRefs(rootItem)); 1.11000 + if (!rootItem) { 1.11001 + return false; 1.11002 + } 1.11003 + nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem); 1.11004 + if (!rootWin) { 1.11005 + return false; 1.11006 + } 1.11007 + 1.11008 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.11009 + if (!fm) { 1.11010 + return false; 1.11011 + } 1.11012 + 1.11013 + nsCOMPtr<nsIDOMWindow> activeWindow; 1.11014 + fm->GetActiveWindow(getter_AddRefs(activeWindow)); 1.11015 + if (!activeWindow) { 1.11016 + return false; 1.11017 + } 1.11018 + 1.11019 + return activeWindow == rootWin; 1.11020 +} 1.11021 + 1.11022 +nsresult nsDocument::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement, 1.11023 + const nsAString& aOrigin) 1.11024 +{ 1.11025 + // Ensure the frame element is the fullscreen element in this document. 1.11026 + // If the frame element is already the fullscreen element in this document, 1.11027 + // this has no effect. 1.11028 + nsCOMPtr<nsIContent> content(do_QueryInterface(aFrameElement)); 1.11029 + RequestFullScreen(content->AsElement(), 1.11030 + /* aWasCallerChrome */ false, 1.11031 + /* aNotifyOnOriginChange */ false); 1.11032 + 1.11033 + // Origin changed in child process, send notifiction, so that chrome can 1.11034 + // update the UI to reflect the fullscreen origin change if necessary. 1.11035 + // The BrowserElementChild listens on this, and forwards it over its 1.11036 + // parent process, where it is redispatched. Chrome (in the root process, 1.11037 + // which could be *this* process) listens for this notification so that 1.11038 + // it can show a warning or approval UI. 1.11039 + if (!aOrigin.IsEmpty()) { 1.11040 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.11041 + os->NotifyObservers(GetFullscreenRootDocument(this), 1.11042 + "fullscreen-origin-change", 1.11043 + PromiseFlatString(aOrigin).get()); 1.11044 + } 1.11045 + 1.11046 + return NS_OK; 1.11047 +} 1.11048 + 1.11049 +nsresult nsDocument::RemoteFrameFullscreenReverted() 1.11050 +{ 1.11051 + RestorePreviousFullScreenState(); 1.11052 + return NS_OK; 1.11053 +} 1.11054 + 1.11055 +void 1.11056 +nsDocument::RequestFullScreen(Element* aElement, 1.11057 + bool aWasCallerChrome, 1.11058 + bool aNotifyOnOriginChange) 1.11059 +{ 1.11060 + NS_ASSERTION(aElement, 1.11061 + "Must pass non-null element to nsDocument::RequestFullScreen"); 1.11062 + if (!aElement || aElement == GetFullScreenElement()) { 1.11063 + return; 1.11064 + } 1.11065 + if (!aElement->IsInDoc()) { 1.11066 + LogFullScreenDenied(true, "FullScreenDeniedNotInDocument", this); 1.11067 + return; 1.11068 + } 1.11069 + if (aElement->OwnerDoc() != this) { 1.11070 + LogFullScreenDenied(true, "FullScreenDeniedMovedDocument", this); 1.11071 + return; 1.11072 + } 1.11073 + if (!GetWindow()) { 1.11074 + LogFullScreenDenied(true, "FullScreenDeniedLostWindow", this); 1.11075 + return; 1.11076 + } 1.11077 + if (nsContentUtils::IsFullscreenApiContentOnly() && 1.11078 + nsContentUtils::IsChromeDoc(this)) { 1.11079 + // Block fullscreen requests in the chrome document when the fullscreen API 1.11080 + // is configured for content only. 1.11081 + LogFullScreenDenied(true, "FullScreenDeniedContentOnly", this); 1.11082 + return; 1.11083 + } 1.11084 + if (!IsFullScreenEnabled(aWasCallerChrome, true)) { 1.11085 + // IsFullScreenEnabled calls LogFullScreenDenied, no need to log. 1.11086 + return; 1.11087 + } 1.11088 + if (GetFullScreenElement() && 1.11089 + !nsContentUtils::ContentIsDescendantOf(aElement, GetFullScreenElement())) { 1.11090 + // If this document is full-screen, only grant full-screen requests from 1.11091 + // a descendant of the current full-screen element. 1.11092 + LogFullScreenDenied(true, "FullScreenDeniedNotDescendant", this); 1.11093 + return; 1.11094 + } 1.11095 + if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) { 1.11096 + LogFullScreenDenied(true, "FullScreenDeniedNotFocusedTab", this); 1.11097 + return; 1.11098 + } 1.11099 + // Deny requests when a windowed plugin is focused. 1.11100 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.11101 + if (!fm) { 1.11102 + NS_WARNING("Failed to retrieve focus manager in full-screen request."); 1.11103 + return; 1.11104 + } 1.11105 + nsCOMPtr<nsIDOMElement> focusedElement; 1.11106 + fm->GetFocusedElement(getter_AddRefs(focusedElement)); 1.11107 + if (focusedElement) { 1.11108 + nsCOMPtr<nsIContent> content = do_QueryInterface(focusedElement); 1.11109 + if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(content)) { 1.11110 + LogFullScreenDenied(true, "FullScreenDeniedFocusedPlugin", this); 1.11111 + return; 1.11112 + } 1.11113 + } 1.11114 + 1.11115 + // Stash a reference to any existing fullscreen doc, we'll use this later 1.11116 + // to detect if the origin which is fullscreen has changed. 1.11117 + nsCOMPtr<nsIDocument> previousFullscreenDoc = GetFullscreenLeaf(this); 1.11118 + 1.11119 + AddFullscreenApprovedObserver(); 1.11120 + 1.11121 + // Stores a list of documents which we must dispatch "mozfullscreenchange" 1.11122 + // too. We're required by the spec to dispatch the events in root-to-leaf 1.11123 + // order, but we traverse the doctree in a leaf-to-root order, so we save 1.11124 + // references to the documents we must dispatch to so that we get the order 1.11125 + // as specified. 1.11126 + nsAutoTArray<nsIDocument*, 8> changed; 1.11127 + 1.11128 + // Remember the root document, so that if a full-screen document is hidden 1.11129 + // we can reset full-screen state in the remaining visible full-screen documents. 1.11130 + nsIDocument* fullScreenRootDoc = GetFullscreenRootDocument(this); 1.11131 + if (fullScreenRootDoc->IsFullScreenDoc()) { 1.11132 + // A document is already in fullscreen, unlock the mouse pointer 1.11133 + // before setting a new document to fullscreen 1.11134 + UnlockPointer(); 1.11135 + } 1.11136 + 1.11137 + // If a document is already in fullscreen, then unlock the mouse pointer 1.11138 + // before setting a new document to fullscreen 1.11139 + nsCOMPtr<Element> pointerLockedElement = 1.11140 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.11141 + if (pointerLockedElement) { 1.11142 + UnlockPointer(); 1.11143 + } 1.11144 + 1.11145 + // Set the full-screen element. This sets the full-screen style on the 1.11146 + // element, and the full-screen-ancestor styles on ancestors of the element 1.11147 + // in this document. 1.11148 + DebugOnly<bool> x = FullScreenStackPush(aElement); 1.11149 + NS_ASSERTION(x, "Full-screen state of requesting doc should always change!"); 1.11150 + changed.AppendElement(this); 1.11151 + 1.11152 + // Propagate up the document hierarchy, setting the full-screen element as 1.11153 + // the element's container in ancestor documents. This also sets the 1.11154 + // appropriate css styles as well. Note we don't propagate down the 1.11155 + // document hierarchy, the full-screen element (or its container) is not 1.11156 + // visible there. Stop when we reach the root document. 1.11157 + nsIDocument* child = this; 1.11158 + while (true) { 1.11159 + child->SetFullscreenRoot(fullScreenRootDoc); 1.11160 + NS_ASSERTION(child->GetFullscreenRoot() == fullScreenRootDoc, 1.11161 + "Fullscreen root should be set!"); 1.11162 + if (child == fullScreenRootDoc) { 1.11163 + break; 1.11164 + } 1.11165 + nsIDocument* parent = child->GetParentDocument(); 1.11166 + Element* element = parent->FindContentForSubDocument(child)->AsElement(); 1.11167 + if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) { 1.11168 + changed.AppendElement(parent); 1.11169 + child = parent; 1.11170 + } else { 1.11171 + // We've reached either the root, or a point in the doctree where the 1.11172 + // new full-screen element container is the same as the previous 1.11173 + // full-screen element's container. No more changes need to be made 1.11174 + // to the full-screen stacks of documents further up the tree. 1.11175 + break; 1.11176 + } 1.11177 + } 1.11178 + 1.11179 + // Dispatch "mozfullscreenchange" events. Note this loop is in reverse 1.11180 + // order so that the events for the root document arrives before the leaf 1.11181 + // document, as required by the spec. 1.11182 + for (uint32_t i = 0; i < changed.Length(); ++i) { 1.11183 + DispatchFullScreenChange(changed[changed.Length() - i - 1]); 1.11184 + } 1.11185 + 1.11186 + // If this document hasn't already been approved in this session, 1.11187 + // check to see if the user has granted the fullscreen access 1.11188 + // to the document's principal's host, if it has one. Note that documents 1.11189 + // in web apps which are the same origin as the web app are considered 1.11190 + // trusted and so are automatically approved. 1.11191 + if (!mIsApprovedForFullscreen) { 1.11192 + mIsApprovedForFullscreen = 1.11193 + !Preferences::GetBool("full-screen-api.approval-required") || 1.11194 + NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED || 1.11195 + nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen"); 1.11196 + } 1.11197 + 1.11198 + // If this document, or a document with the same principal has not 1.11199 + // already been approved for fullscreen this fullscreen-session, dispatch 1.11200 + // an event so that chrome knows to pop up a warning/approval UI. 1.11201 + // Note previousFullscreenDoc=nullptr upon first entry, so we always 1.11202 + // take this path on the first time we enter fullscreen in a fullscreen 1.11203 + // session. 1.11204 + if (!mIsApprovedForFullscreen || 1.11205 + !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) { 1.11206 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.11207 + new AsyncEventDispatcher(this, 1.11208 + NS_LITERAL_STRING("MozEnteredDomFullscreen"), 1.11209 + true, 1.11210 + true); 1.11211 + asyncDispatcher->PostDOMEvent(); 1.11212 + } 1.11213 + 1.11214 +#ifdef DEBUG 1.11215 + // Note assertions must run before SetWindowFullScreen() as that does 1.11216 + // synchronous event dispatch which can run script which exits full-screen! 1.11217 + NS_ASSERTION(GetFullScreenElement() == aElement, 1.11218 + "Full-screen element should be the requested element!"); 1.11219 + NS_ASSERTION(IsFullScreenDoc(), "Should be full-screen doc"); 1.11220 + nsCOMPtr<nsIDOMElement> fse; 1.11221 + GetMozFullScreenElement(getter_AddRefs(fse)); 1.11222 + nsCOMPtr<nsIContent> c(do_QueryInterface(fse)); 1.11223 + NS_ASSERTION(c->AsElement() == aElement, 1.11224 + "GetMozFullScreenElement should match GetFullScreenElement()"); 1.11225 +#endif 1.11226 + 1.11227 + // The origin which is fullscreen changed, send a notifiction so that the 1.11228 + // root document knows the origin of the document which requested fullscreen. 1.11229 + // This is used for the fullscreen approval UI. If we're in a child 1.11230 + // process, the root BrowserElementChild listens for this notification, 1.11231 + // and forwards it across to its BrowserElementParent, which 1.11232 + // re-broadcasts the message for the root document in its process. 1.11233 + if (aNotifyOnOriginChange && 1.11234 + !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) { 1.11235 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.11236 + nsIDocument* root = GetFullscreenRootDocument(this); 1.11237 + nsAutoString origin; 1.11238 + nsContentUtils::GetUTFOrigin(NodePrincipal(), origin); 1.11239 + os->NotifyObservers(root, "fullscreen-origin-change", origin.get()); 1.11240 + } 1.11241 + 1.11242 + // Make the window full-screen. Note we must make the state changes above 1.11243 + // before making the window full-screen, as then the document reports as 1.11244 + // being in full-screen mode when the chrome "fullscreen" event fires, 1.11245 + // enabling chrome to distinguish between browser and dom full-screen 1.11246 + // modes. Also note that nsGlobalWindow::SetFullScreen() (which 1.11247 + // SetWindowFullScreen() calls) proxies to the root window in its hierarchy, 1.11248 + // and does not operate on the a per-nsIDOMWindow basis. 1.11249 + SetWindowFullScreen(this, true); 1.11250 +} 1.11251 + 1.11252 +NS_IMETHODIMP 1.11253 +nsDocument::GetMozFullScreenElement(nsIDOMElement **aFullScreenElement) 1.11254 +{ 1.11255 + ErrorResult rv; 1.11256 + Element* el = GetMozFullScreenElement(rv); 1.11257 + if (rv.Failed()) { 1.11258 + return rv.ErrorCode(); 1.11259 + } 1.11260 + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el); 1.11261 + retval.forget(aFullScreenElement); 1.11262 + return NS_OK; 1.11263 +} 1.11264 + 1.11265 +Element* 1.11266 +nsDocument::GetMozFullScreenElement(ErrorResult& rv) 1.11267 +{ 1.11268 + if (IsFullScreenDoc()) { 1.11269 + // Must have a full-screen element while in full-screen mode. 1.11270 + Element* el = GetFullScreenElement(); 1.11271 + if (!el) { 1.11272 + rv.Throw(NS_ERROR_UNEXPECTED); 1.11273 + } 1.11274 + return el; 1.11275 + } 1.11276 + return nullptr; 1.11277 +} 1.11278 + 1.11279 +Element* 1.11280 +nsDocument::GetFullScreenElement() 1.11281 +{ 1.11282 + Element* element = FullScreenStackTop(); 1.11283 + NS_ASSERTION(!element || 1.11284 + element->IsFullScreenAncestor(), 1.11285 + "Fullscreen element should have fullscreen styles applied"); 1.11286 + return element; 1.11287 +} 1.11288 + 1.11289 +NS_IMETHODIMP 1.11290 +nsDocument::GetMozFullScreen(bool *aFullScreen) 1.11291 +{ 1.11292 + *aFullScreen = MozFullScreen(); 1.11293 + return NS_OK; 1.11294 +} 1.11295 + 1.11296 +NS_IMETHODIMP 1.11297 +nsDocument::GetMozFullScreenEnabled(bool *aFullScreen) 1.11298 +{ 1.11299 + NS_ENSURE_ARG_POINTER(aFullScreen); 1.11300 + *aFullScreen = MozFullScreenEnabled(); 1.11301 + return NS_OK; 1.11302 +} 1.11303 + 1.11304 +bool 1.11305 +nsDocument::MozFullScreenEnabled() 1.11306 +{ 1.11307 + return IsFullScreenEnabled(nsContentUtils::IsCallerChrome(), false); 1.11308 +} 1.11309 + 1.11310 +static bool 1.11311 +HasFullScreenSubDocument(nsIDocument* aDoc) 1.11312 +{ 1.11313 + uint32_t count = CountFullscreenSubDocuments(aDoc); 1.11314 + NS_ASSERTION(count <= 1, "Fullscreen docs should have at most 1 fullscreen child!"); 1.11315 + return count >= 1; 1.11316 +} 1.11317 + 1.11318 +bool 1.11319 +nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure) 1.11320 +{ 1.11321 + if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome) { 1.11322 + // Chrome code can always use the full-screen API, provided it's not 1.11323 + // explicitly disabled. Note IsCallerChrome() returns true when running 1.11324 + // in an nsRunnable, so don't use GetMozFullScreenEnabled() from an 1.11325 + // nsRunnable! 1.11326 + return true; 1.11327 + } 1.11328 + 1.11329 + if (!nsContentUtils::IsFullScreenApiEnabled()) { 1.11330 + LogFullScreenDenied(aLogFailure, "FullScreenDeniedDisabled", this); 1.11331 + return false; 1.11332 + } 1.11333 + if (!IsVisible()) { 1.11334 + LogFullScreenDenied(aLogFailure, "FullScreenDeniedHidden", this); 1.11335 + return false; 1.11336 + } 1.11337 + if (HasFullScreenSubDocument(this)) { 1.11338 + LogFullScreenDenied(aLogFailure, "FullScreenDeniedSubDocFullScreen", this); 1.11339 + return false; 1.11340 + } 1.11341 + 1.11342 + // Ensure that all ancestor <iframe> elements have the allowfullscreen 1.11343 + // boolean attribute set. 1.11344 + nsCOMPtr<nsIDocShell> docShell(mDocumentContainer); 1.11345 + bool allowed = false; 1.11346 + if (docShell) { 1.11347 + docShell->GetFullscreenAllowed(&allowed); 1.11348 + } 1.11349 + if (!allowed) { 1.11350 + LogFullScreenDenied(aLogFailure, "FullScreenDeniedIframeNotAllowed", this); 1.11351 + } 1.11352 + 1.11353 + return allowed; 1.11354 +} 1.11355 + 1.11356 +static void 1.11357 +DispatchPointerLockChange(nsIDocument* aTarget) 1.11358 +{ 1.11359 + if (!aTarget) { 1.11360 + return; 1.11361 + } 1.11362 + 1.11363 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.11364 + new AsyncEventDispatcher(aTarget, 1.11365 + NS_LITERAL_STRING("mozpointerlockchange"), 1.11366 + true, 1.11367 + false); 1.11368 + asyncDispatcher->PostDOMEvent(); 1.11369 +} 1.11370 + 1.11371 +static void 1.11372 +DispatchPointerLockError(nsIDocument* aTarget) 1.11373 +{ 1.11374 + if (!aTarget) { 1.11375 + return; 1.11376 + } 1.11377 + 1.11378 + nsRefPtr<AsyncEventDispatcher> asyncDispatcher = 1.11379 + new AsyncEventDispatcher(aTarget, 1.11380 + NS_LITERAL_STRING("mozpointerlockerror"), 1.11381 + true, 1.11382 + false); 1.11383 + asyncDispatcher->PostDOMEvent(); 1.11384 +} 1.11385 + 1.11386 +mozilla::StaticRefPtr<nsPointerLockPermissionRequest> gPendingPointerLockRequest; 1.11387 + 1.11388 +class nsPointerLockPermissionRequest : public nsRunnable, 1.11389 + public nsIContentPermissionRequest 1.11390 +{ 1.11391 +public: 1.11392 + nsPointerLockPermissionRequest(Element* aElement, bool aUserInputOrChromeCaller) 1.11393 + : mElement(do_GetWeakReference(aElement)), 1.11394 + mDocument(do_GetWeakReference(aElement->OwnerDoc())), 1.11395 + mUserInputOrChromeCaller(aUserInputOrChromeCaller) {} 1.11396 + 1.11397 + virtual ~nsPointerLockPermissionRequest() {} 1.11398 + 1.11399 + NS_DECL_ISUPPORTS 1.11400 + NS_DECL_NSICONTENTPERMISSIONREQUEST 1.11401 + 1.11402 + NS_IMETHOD Run() 1.11403 + { 1.11404 + nsCOMPtr<Element> e = do_QueryReferent(mElement); 1.11405 + nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument); 1.11406 + if (!e || !d || gPendingPointerLockRequest != this || 1.11407 + e->GetCurrentDoc() != d) { 1.11408 + Handled(); 1.11409 + DispatchPointerLockError(d); 1.11410 + return NS_OK; 1.11411 + } 1.11412 + 1.11413 + // We're about to enter fullscreen mode. 1.11414 + nsDocument* doc = static_cast<nsDocument*>(d.get()); 1.11415 + if (doc->mAsyncFullscreenPending || 1.11416 + (doc->mHasFullscreenApprovedObserver && !doc->mIsApprovedForFullscreen)) { 1.11417 + // We're still waiting for approval. 1.11418 + return NS_OK; 1.11419 + } 1.11420 + 1.11421 + if (doc->mIsApprovedForFullscreen || doc->mAllowRelocking) { 1.11422 + Allow(JS::UndefinedHandleValue); 1.11423 + return NS_OK; 1.11424 + } 1.11425 + 1.11426 + // In non-fullscreen mode user input (or chrome caller) is required! 1.11427 + // Also, don't let the page to try to get the permission too many times. 1.11428 + if (!mUserInputOrChromeCaller || 1.11429 + doc->mCancelledPointerLockRequests > 2) { 1.11430 + Handled(); 1.11431 + DispatchPointerLockError(d); 1.11432 + return NS_OK; 1.11433 + } 1.11434 + 1.11435 + // Handling a request from user input in non-fullscreen mode. 1.11436 + // Do a normal permission check. 1.11437 + nsCOMPtr<nsIContentPermissionPrompt> prompt = 1.11438 + do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); 1.11439 + if (prompt) { 1.11440 + prompt->Prompt(this); 1.11441 + } 1.11442 + 1.11443 + return NS_OK; 1.11444 + } 1.11445 + 1.11446 + void Handled() 1.11447 + { 1.11448 + mElement = nullptr; 1.11449 + mDocument = nullptr; 1.11450 + if (gPendingPointerLockRequest == this) { 1.11451 + gPendingPointerLockRequest = nullptr; 1.11452 + } 1.11453 + } 1.11454 + 1.11455 + nsWeakPtr mElement; 1.11456 + nsWeakPtr mDocument; 1.11457 + bool mUserInputOrChromeCaller; 1.11458 +}; 1.11459 + 1.11460 +NS_IMPL_ISUPPORTS_INHERITED(nsPointerLockPermissionRequest, 1.11461 + nsRunnable, 1.11462 + nsIContentPermissionRequest) 1.11463 + 1.11464 +NS_IMETHODIMP 1.11465 +nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes) 1.11466 +{ 1.11467 + nsTArray<nsString> emptyOptions; 1.11468 + return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"), 1.11469 + NS_LITERAL_CSTRING("unused"), 1.11470 + emptyOptions, 1.11471 + aTypes); 1.11472 +} 1.11473 + 1.11474 +NS_IMETHODIMP 1.11475 +nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal) 1.11476 +{ 1.11477 + nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument); 1.11478 + if (d) { 1.11479 + NS_ADDREF(*aPrincipal = d->NodePrincipal()); 1.11480 + } 1.11481 + return NS_OK; 1.11482 +} 1.11483 + 1.11484 +NS_IMETHODIMP 1.11485 +nsPointerLockPermissionRequest::GetWindow(nsIDOMWindow** aWindow) 1.11486 +{ 1.11487 + nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument); 1.11488 + if (d) { 1.11489 + NS_IF_ADDREF(*aWindow = d->GetInnerWindow()); 1.11490 + } 1.11491 + return NS_OK; 1.11492 +} 1.11493 + 1.11494 +NS_IMETHODIMP 1.11495 +nsPointerLockPermissionRequest::GetElement(nsIDOMElement** aElement) 1.11496 +{ 1.11497 + // It is enough to implement GetWindow. 1.11498 + *aElement = nullptr; 1.11499 + return NS_OK; 1.11500 +} 1.11501 + 1.11502 +NS_IMETHODIMP 1.11503 +nsPointerLockPermissionRequest::Cancel() 1.11504 +{ 1.11505 + nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument); 1.11506 + Handled(); 1.11507 + if (d) { 1.11508 + static_cast<nsDocument*>(d.get())->mCancelledPointerLockRequests++; 1.11509 + DispatchPointerLockError(d); 1.11510 + } 1.11511 + return NS_OK; 1.11512 +} 1.11513 + 1.11514 +NS_IMETHODIMP 1.11515 +nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices) 1.11516 +{ 1.11517 + MOZ_ASSERT(aChoices.isUndefined()); 1.11518 + 1.11519 + nsCOMPtr<Element> e = do_QueryReferent(mElement); 1.11520 + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); 1.11521 + nsDocument* d = static_cast<nsDocument*>(doc.get()); 1.11522 + if (!e || !d || gPendingPointerLockRequest != this || 1.11523 + e->GetCurrentDoc() != d || 1.11524 + (!mUserInputOrChromeCaller && !d->mIsApprovedForFullscreen)) { 1.11525 + Handled(); 1.11526 + DispatchPointerLockError(d); 1.11527 + return NS_OK; 1.11528 + } 1.11529 + 1.11530 + // Mark handled here so that we don't need to call it everywhere below. 1.11531 + Handled(); 1.11532 + 1.11533 + nsCOMPtr<Element> pointerLockedElement = 1.11534 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.11535 + if (e == pointerLockedElement) { 1.11536 + DispatchPointerLockChange(d); 1.11537 + return NS_OK; 1.11538 + } 1.11539 + 1.11540 + // Note, we must bypass focus change, so pass true as the last parameter! 1.11541 + if (!d->ShouldLockPointer(e, pointerLockedElement, true)) { 1.11542 + DispatchPointerLockError(d); 1.11543 + return NS_OK; 1.11544 + } 1.11545 + 1.11546 + if (!d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) { 1.11547 + DispatchPointerLockError(d); 1.11548 + return NS_OK; 1.11549 + } 1.11550 + 1.11551 + d->mCancelledPointerLockRequests = 0; 1.11552 + e->SetPointerLock(); 1.11553 + EventStateManager::sPointerLockedElement = do_GetWeakReference(e); 1.11554 + EventStateManager::sPointerLockedDoc = do_GetWeakReference(doc); 1.11555 + NS_ASSERTION(EventStateManager::sPointerLockedElement && 1.11556 + EventStateManager::sPointerLockedDoc, 1.11557 + "aElement and this should support weak references!"); 1.11558 + 1.11559 + DispatchPointerLockChange(d); 1.11560 + return NS_OK; 1.11561 +} 1.11562 + 1.11563 +void 1.11564 +nsDocument::SetApprovedForFullscreen(bool aIsApproved) 1.11565 +{ 1.11566 + mIsApprovedForFullscreen = aIsApproved; 1.11567 +} 1.11568 + 1.11569 +nsresult 1.11570 +nsDocument::Observe(nsISupports *aSubject, 1.11571 + const char *aTopic, 1.11572 + const char16_t *aData) 1.11573 +{ 1.11574 + if (strcmp("fullscreen-approved", aTopic) == 0) { 1.11575 + nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject)); 1.11576 + if (subject != this) { 1.11577 + return NS_OK; 1.11578 + } 1.11579 + SetApprovedForFullscreen(true); 1.11580 + if (gPendingPointerLockRequest) { 1.11581 + // We have a request pending. Create a clone of it and re-dispatch so that 1.11582 + // Run() method gets called again. 1.11583 + nsCOMPtr<Element> el = 1.11584 + do_QueryReferent(gPendingPointerLockRequest->mElement); 1.11585 + nsCOMPtr<nsIDocument> doc = 1.11586 + do_QueryReferent(gPendingPointerLockRequest->mDocument); 1.11587 + bool userInputOrChromeCaller = 1.11588 + gPendingPointerLockRequest->mUserInputOrChromeCaller; 1.11589 + gPendingPointerLockRequest->Handled(); 1.11590 + if (doc == this && el && el->GetCurrentDoc() == doc) { 1.11591 + nsPointerLockPermissionRequest* clone = 1.11592 + new nsPointerLockPermissionRequest(el, userInputOrChromeCaller); 1.11593 + gPendingPointerLockRequest = clone; 1.11594 + nsCOMPtr<nsIRunnable> r = gPendingPointerLockRequest.get(); 1.11595 + NS_DispatchToMainThread(r); 1.11596 + } 1.11597 + } 1.11598 + } 1.11599 + return NS_OK; 1.11600 +} 1.11601 + 1.11602 +void 1.11603 +nsDocument::RequestPointerLock(Element* aElement) 1.11604 +{ 1.11605 + NS_ASSERTION(aElement, 1.11606 + "Must pass non-null element to nsDocument::RequestPointerLock"); 1.11607 + 1.11608 + nsCOMPtr<Element> pointerLockedElement = 1.11609 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.11610 + if (aElement == pointerLockedElement) { 1.11611 + DispatchPointerLockChange(this); 1.11612 + return; 1.11613 + } 1.11614 + 1.11615 + if (!ShouldLockPointer(aElement, pointerLockedElement)) { 1.11616 + DispatchPointerLockError(this); 1.11617 + return; 1.11618 + } 1.11619 + 1.11620 + bool userInputOrChromeCaller = EventStateManager::IsHandlingUserInput() || 1.11621 + nsContentUtils::IsCallerChrome(); 1.11622 + 1.11623 + gPendingPointerLockRequest = 1.11624 + new nsPointerLockPermissionRequest(aElement, userInputOrChromeCaller); 1.11625 + nsCOMPtr<nsIRunnable> r = gPendingPointerLockRequest.get(); 1.11626 + NS_DispatchToMainThread(r); 1.11627 +} 1.11628 + 1.11629 +bool 1.11630 +nsDocument::ShouldLockPointer(Element* aElement, Element* aCurrentLock, 1.11631 + bool aNoFocusCheck) 1.11632 +{ 1.11633 + // Check if pointer lock pref is enabled 1.11634 + if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) { 1.11635 + NS_WARNING("ShouldLockPointer(): Pointer Lock pref not enabled"); 1.11636 + return false; 1.11637 + } 1.11638 + 1.11639 + if (aCurrentLock && aCurrentLock->OwnerDoc() != aElement->OwnerDoc()) { 1.11640 + NS_WARNING("ShouldLockPointer(): Existing pointer lock element in a different document"); 1.11641 + return false; 1.11642 + } 1.11643 + 1.11644 + if (!aElement->IsInDoc()) { 1.11645 + NS_WARNING("ShouldLockPointer(): Element without Document"); 1.11646 + return false; 1.11647 + } 1.11648 + 1.11649 + if (mSandboxFlags & SANDBOXED_POINTER_LOCK) { 1.11650 + NS_WARNING("ShouldLockPointer(): Document is sandboxed and doesn't allow pointer-lock"); 1.11651 + return false; 1.11652 + } 1.11653 + 1.11654 + // Check if the element is in a document with a docshell. 1.11655 + nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc(); 1.11656 + if (!ownerDoc->GetContainer()) { 1.11657 + return false; 1.11658 + } 1.11659 + nsCOMPtr<nsPIDOMWindow> ownerWindow = ownerDoc->GetWindow(); 1.11660 + if (!ownerWindow) { 1.11661 + return false; 1.11662 + } 1.11663 + nsCOMPtr<nsPIDOMWindow> ownerInnerWindow = ownerDoc->GetInnerWindow(); 1.11664 + if (!ownerInnerWindow) { 1.11665 + return false; 1.11666 + } 1.11667 + if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) { 1.11668 + return false; 1.11669 + } 1.11670 + 1.11671 + nsCOMPtr<nsIDOMWindow> top; 1.11672 + ownerWindow->GetScriptableTop(getter_AddRefs(top)); 1.11673 + nsCOMPtr<nsPIDOMWindow> piTop = do_QueryInterface(top); 1.11674 + if (!piTop || !piTop->GetExtantDoc() || 1.11675 + piTop->GetExtantDoc()->Hidden()) { 1.11676 + NS_WARNING("ShouldLockPointer(): Top document isn't visible."); 1.11677 + return false; 1.11678 + } 1.11679 + 1.11680 + if (!aNoFocusCheck) { 1.11681 + mozilla::ErrorResult rv; 1.11682 + if (!piTop->GetExtantDoc()->HasFocus(rv)) { 1.11683 + NS_WARNING("ShouldLockPointer(): Top document isn't focused."); 1.11684 + return false; 1.11685 + } 1.11686 + } 1.11687 + 1.11688 + return true; 1.11689 +} 1.11690 + 1.11691 +bool 1.11692 +nsDocument::SetPointerLock(Element* aElement, int aCursorStyle) 1.11693 +{ 1.11694 + // NOTE: aElement will be nullptr when unlocking. 1.11695 + nsCOMPtr<nsPIDOMWindow> window = GetWindow(); 1.11696 + if (!window) { 1.11697 + NS_WARNING("SetPointerLock(): No Window"); 1.11698 + return false; 1.11699 + } 1.11700 + 1.11701 + nsIDocShell *docShell = window->GetDocShell(); 1.11702 + if (!docShell) { 1.11703 + NS_WARNING("SetPointerLock(): No DocShell (window already closed?)"); 1.11704 + return false; 1.11705 + } 1.11706 + 1.11707 + nsRefPtr<nsPresContext> presContext; 1.11708 + docShell->GetPresContext(getter_AddRefs(presContext)); 1.11709 + if (!presContext) { 1.11710 + NS_WARNING("SetPointerLock(): Unable to get presContext in \ 1.11711 + domWindow->GetDocShell()->GetPresContext()"); 1.11712 + return false; 1.11713 + } 1.11714 + 1.11715 + nsCOMPtr<nsIPresShell> shell = presContext->PresShell(); 1.11716 + if (!shell) { 1.11717 + NS_WARNING("SetPointerLock(): Unable to find presContext->PresShell()"); 1.11718 + return false; 1.11719 + } 1.11720 + 1.11721 + nsIFrame* rootFrame = shell->GetRootFrame(); 1.11722 + if (!rootFrame) { 1.11723 + NS_WARNING("SetPointerLock(): Unable to get root frame"); 1.11724 + return false; 1.11725 + } 1.11726 + 1.11727 + nsCOMPtr<nsIWidget> widget = rootFrame->GetNearestWidget(); 1.11728 + if (!widget) { 1.11729 + NS_WARNING("SetPointerLock(): Unable to find widget in \ 1.11730 + shell->GetRootFrame()->GetNearestWidget();"); 1.11731 + return false; 1.11732 + } 1.11733 + 1.11734 + if (aElement && (aElement->OwnerDoc() != this)) { 1.11735 + NS_WARNING("SetPointerLock(): Element not in this document."); 1.11736 + return false; 1.11737 + } 1.11738 + 1.11739 + // Hide the cursor and set pointer lock for future mouse events 1.11740 + nsRefPtr<EventStateManager> esm = presContext->EventStateManager(); 1.11741 + esm->SetCursor(aCursorStyle, nullptr, false, 1.11742 + 0.0f, 0.0f, widget, true); 1.11743 + esm->SetPointerLock(widget, aElement); 1.11744 + 1.11745 + return true; 1.11746 +} 1.11747 + 1.11748 +void 1.11749 +nsDocument::UnlockPointer(nsIDocument* aDoc) 1.11750 +{ 1.11751 + if (!EventStateManager::sIsPointerLocked) { 1.11752 + return; 1.11753 + } 1.11754 + 1.11755 + nsCOMPtr<nsIDocument> pointerLockedDoc = 1.11756 + do_QueryReferent(EventStateManager::sPointerLockedDoc); 1.11757 + if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) { 1.11758 + return; 1.11759 + } 1.11760 + nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get()); 1.11761 + if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) { 1.11762 + return; 1.11763 + } 1.11764 + 1.11765 + nsCOMPtr<Element> pointerLockedElement = 1.11766 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.11767 + if (pointerLockedElement) { 1.11768 + pointerLockedElement->ClearPointerLock(); 1.11769 + } 1.11770 + 1.11771 + EventStateManager::sPointerLockedElement = nullptr; 1.11772 + EventStateManager::sPointerLockedDoc = nullptr; 1.11773 + static_cast<nsDocument*>(pointerLockedDoc.get())->mAllowRelocking = !!aDoc; 1.11774 + gPendingPointerLockRequest = nullptr; 1.11775 + DispatchPointerLockChange(pointerLockedDoc); 1.11776 +} 1.11777 + 1.11778 +void 1.11779 +nsIDocument::UnlockPointer(nsIDocument* aDoc) 1.11780 +{ 1.11781 + nsDocument::UnlockPointer(aDoc); 1.11782 +} 1.11783 + 1.11784 +NS_IMETHODIMP 1.11785 +nsDocument::MozExitPointerLock() 1.11786 +{ 1.11787 + nsIDocument::MozExitPointerLock(); 1.11788 + return NS_OK; 1.11789 +} 1.11790 + 1.11791 +NS_IMETHODIMP 1.11792 +nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement) 1.11793 +{ 1.11794 + Element* el = nsIDocument::GetMozPointerLockElement(); 1.11795 + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el); 1.11796 + retval.forget(aPointerLockedElement); 1.11797 + return NS_OK; 1.11798 +} 1.11799 + 1.11800 +Element* 1.11801 +nsIDocument::GetMozPointerLockElement() 1.11802 +{ 1.11803 + nsCOMPtr<Element> pointerLockedElement = 1.11804 + do_QueryReferent(EventStateManager::sPointerLockedElement); 1.11805 + if (!pointerLockedElement) { 1.11806 + return nullptr; 1.11807 + } 1.11808 + 1.11809 + // Make sure pointer locked element is in the same document. 1.11810 + nsCOMPtr<nsIDocument> pointerLockedDoc = 1.11811 + do_QueryReferent(EventStateManager::sPointerLockedDoc); 1.11812 + if (pointerLockedDoc != this) { 1.11813 + return nullptr; 1.11814 + } 1.11815 + 1.11816 + return pointerLockedElement; 1.11817 +} 1.11818 + 1.11819 +void 1.11820 +nsDocument::XPCOMShutdown() 1.11821 +{ 1.11822 + gPendingPointerLockRequest = nullptr; 1.11823 + sProcessingStack.destroyIfConstructed(); 1.11824 +} 1.11825 + 1.11826 +void 1.11827 +nsDocument::UpdateVisibilityState() 1.11828 +{ 1.11829 + dom::VisibilityState oldState = mVisibilityState; 1.11830 + mVisibilityState = GetVisibilityState(); 1.11831 + if (oldState != mVisibilityState) { 1.11832 + nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this), 1.11833 + NS_LITERAL_STRING("visibilitychange"), 1.11834 + /* bubbles = */ true, 1.11835 + /* cancelable = */ false); 1.11836 + nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this), 1.11837 + NS_LITERAL_STRING("mozvisibilitychange"), 1.11838 + /* bubbles = */ true, 1.11839 + /* cancelable = */ false); 1.11840 + 1.11841 + EnumerateFreezableElements(NotifyActivityChanged, nullptr); 1.11842 + } 1.11843 +} 1.11844 + 1.11845 +VisibilityState 1.11846 +nsDocument::GetVisibilityState() const 1.11847 +{ 1.11848 + // We have to check a few pieces of information here: 1.11849 + // 1) Are we in bfcache (!IsVisible())? If so, nothing else matters. 1.11850 + // 2) Do we have an outer window? If not, we're hidden. Note that we don't 1.11851 + // want to use GetWindow here because it does weird groveling for windows 1.11852 + // in some cases. 1.11853 + // 3) Is our outer window background? If so, we're hidden. 1.11854 + // Otherwise, we're visible. 1.11855 + if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() || 1.11856 + mWindow->GetOuterWindow()->IsBackground()) { 1.11857 + return dom::VisibilityState::Hidden; 1.11858 + } 1.11859 + 1.11860 + return dom::VisibilityState::Visible; 1.11861 +} 1.11862 + 1.11863 +/* virtual */ void 1.11864 +nsDocument::PostVisibilityUpdateEvent() 1.11865 +{ 1.11866 + nsCOMPtr<nsIRunnable> event = 1.11867 + NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState); 1.11868 + NS_DispatchToMainThread(event); 1.11869 +} 1.11870 + 1.11871 +NS_IMETHODIMP 1.11872 +nsDocument::GetMozHidden(bool* aHidden) 1.11873 +{ 1.11874 + *aHidden = MozHidden(); 1.11875 + return NS_OK; 1.11876 +} 1.11877 + 1.11878 +NS_IMETHODIMP 1.11879 +nsDocument::GetHidden(bool* aHidden) 1.11880 +{ 1.11881 + *aHidden = Hidden(); 1.11882 + return NS_OK; 1.11883 +} 1.11884 + 1.11885 +NS_IMETHODIMP 1.11886 +nsDocument::GetMozVisibilityState(nsAString& aState) 1.11887 +{ 1.11888 + WarnOnceAbout(ePrefixedVisibilityAPI); 1.11889 + return GetVisibilityState(aState); 1.11890 +} 1.11891 + 1.11892 +NS_IMETHODIMP 1.11893 +nsDocument::GetVisibilityState(nsAString& aState) 1.11894 +{ 1.11895 + const EnumEntry& entry = 1.11896 + VisibilityStateValues::strings[static_cast<int>(mVisibilityState)]; 1.11897 + aState.AssignASCII(entry.value, entry.length); 1.11898 + return NS_OK; 1.11899 +} 1.11900 + 1.11901 +/* virtual */ void 1.11902 +nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const 1.11903 +{ 1.11904 + aWindowSizes->mDOMOtherSize += 1.11905 + nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf); 1.11906 + 1.11907 + if (mPresShell) { 1.11908 + mPresShell->AddSizeOfIncludingThis(aWindowSizes->mMallocSizeOf, 1.11909 + &aWindowSizes->mArenaStats, 1.11910 + &aWindowSizes->mLayoutPresShellSize, 1.11911 + &aWindowSizes->mLayoutStyleSetsSize, 1.11912 + &aWindowSizes->mLayoutTextRunsSize, 1.11913 + &aWindowSizes->mLayoutPresContextSize); 1.11914 + } 1.11915 + 1.11916 + aWindowSizes->mPropertyTablesSize += 1.11917 + mPropertyTable.SizeOfExcludingThis(aWindowSizes->mMallocSizeOf); 1.11918 + for (uint32_t i = 0, count = mExtraPropertyTables.Length(); 1.11919 + i < count; ++i) { 1.11920 + aWindowSizes->mPropertyTablesSize += 1.11921 + mExtraPropertyTables[i]->SizeOfExcludingThis(aWindowSizes->mMallocSizeOf); 1.11922 + } 1.11923 + 1.11924 + if (EventListenerManager* elm = GetExistingListenerManager()) { 1.11925 + aWindowSizes->mDOMEventListenersCount += elm->ListenerCount(); 1.11926 + } 1.11927 + 1.11928 + // Measurement of the following members may be added later if DMD finds it 1.11929 + // is worthwhile: 1.11930 + // - many! 1.11931 +} 1.11932 + 1.11933 +void 1.11934 +nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const 1.11935 +{ 1.11936 + aWindowSizes->mDOMOtherSize += aWindowSizes->mMallocSizeOf(this); 1.11937 + DocAddSizeOfExcludingThis(aWindowSizes); 1.11938 +} 1.11939 + 1.11940 +static size_t 1.11941 +SizeOfStyleSheetsElementIncludingThis(nsIStyleSheet* aStyleSheet, 1.11942 + MallocSizeOf aMallocSizeOf, 1.11943 + void* aData) 1.11944 +{ 1.11945 + return aStyleSheet->SizeOfIncludingThis(aMallocSizeOf); 1.11946 +} 1.11947 + 1.11948 +size_t 1.11949 +nsDocument::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.11950 +{ 1.11951 + // This SizeOfExcludingThis() overrides the one from nsINode. But 1.11952 + // nsDocuments can only appear at the top of the DOM tree, and we use the 1.11953 + // specialized DocAddSizeOfExcludingThis() in that case. So this should never 1.11954 + // be called. 1.11955 + MOZ_CRASH(); 1.11956 +} 1.11957 + 1.11958 +void 1.11959 +nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const 1.11960 +{ 1.11961 + nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes); 1.11962 + 1.11963 + for (nsIContent* node = nsINode::GetFirstChild(); 1.11964 + node; 1.11965 + node = node->GetNextNode(this)) 1.11966 + { 1.11967 + size_t nodeSize = node->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf); 1.11968 + size_t* p; 1.11969 + 1.11970 + switch (node->NodeType()) { 1.11971 + case nsIDOMNode::ELEMENT_NODE: 1.11972 + p = &aWindowSizes->mDOMElementNodesSize; 1.11973 + break; 1.11974 + case nsIDOMNode::TEXT_NODE: 1.11975 + p = &aWindowSizes->mDOMTextNodesSize; 1.11976 + break; 1.11977 + case nsIDOMNode::CDATA_SECTION_NODE: 1.11978 + p = &aWindowSizes->mDOMCDATANodesSize; 1.11979 + break; 1.11980 + case nsIDOMNode::COMMENT_NODE: 1.11981 + p = &aWindowSizes->mDOMCommentNodesSize; 1.11982 + break; 1.11983 + default: 1.11984 + p = &aWindowSizes->mDOMOtherSize; 1.11985 + break; 1.11986 + } 1.11987 + 1.11988 + *p += nodeSize; 1.11989 + 1.11990 + if (EventListenerManager* elm = node->GetExistingListenerManager()) { 1.11991 + aWindowSizes->mDOMEventListenersCount += elm->ListenerCount(); 1.11992 + } 1.11993 + } 1.11994 + 1.11995 + aWindowSizes->mStyleSheetsSize += 1.11996 + mStyleSheets.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis, 1.11997 + aWindowSizes->mMallocSizeOf); 1.11998 + aWindowSizes->mStyleSheetsSize += 1.11999 + mCatalogSheets.SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis, 1.12000 + aWindowSizes->mMallocSizeOf); 1.12001 + aWindowSizes->mStyleSheetsSize += 1.12002 + mAdditionalSheets[eAgentSheet]. 1.12003 + SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis, 1.12004 + aWindowSizes->mMallocSizeOf); 1.12005 + aWindowSizes->mStyleSheetsSize += 1.12006 + mAdditionalSheets[eUserSheet]. 1.12007 + SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis, 1.12008 + aWindowSizes->mMallocSizeOf); 1.12009 + aWindowSizes->mStyleSheetsSize += 1.12010 + mAdditionalSheets[eAuthorSheet]. 1.12011 + SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis, 1.12012 + aWindowSizes->mMallocSizeOf); 1.12013 + // Lumping in the loader with the style-sheets size is not ideal, 1.12014 + // but most of the things in there are in fact stylesheets, so it 1.12015 + // doesn't seem worthwhile to separate it out. 1.12016 + aWindowSizes->mStyleSheetsSize += 1.12017 + CSSLoader()->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf); 1.12018 + 1.12019 + aWindowSizes->mDOMOtherSize += 1.12020 + mAttrStyleSheet ? 1.12021 + mAttrStyleSheet->DOMSizeOfIncludingThis(aWindowSizes->mMallocSizeOf) : 1.12022 + 0; 1.12023 + 1.12024 + aWindowSizes->mDOMOtherSize += 1.12025 + mStyledLinks.SizeOfExcludingThis(nullptr, aWindowSizes->mMallocSizeOf); 1.12026 + 1.12027 + aWindowSizes->mDOMOtherSize += 1.12028 + mIdentifierMap.SizeOfExcludingThis(nsIdentifierMapEntry::SizeOfExcludingThis, 1.12029 + aWindowSizes->mMallocSizeOf); 1.12030 + 1.12031 + // Measurement of the following members may be added later if DMD finds it 1.12032 + // is worthwhile: 1.12033 + // - many! 1.12034 +} 1.12035 + 1.12036 +NS_IMETHODIMP 1.12037 +nsDocument::QuerySelector(const nsAString& aSelector, nsIDOMElement **aReturn) 1.12038 +{ 1.12039 + return nsINode::QuerySelector(aSelector, aReturn); 1.12040 +} 1.12041 + 1.12042 +NS_IMETHODIMP 1.12043 +nsDocument::QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn) 1.12044 +{ 1.12045 + return nsINode::QuerySelectorAll(aSelector, aReturn); 1.12046 +} 1.12047 + 1.12048 +already_AddRefed<nsIDocument> 1.12049 +nsIDocument::Constructor(const GlobalObject& aGlobal, 1.12050 + ErrorResult& rv) 1.12051 +{ 1.12052 + nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); 1.12053 + if (!global) { 1.12054 + rv.Throw(NS_ERROR_UNEXPECTED); 1.12055 + return nullptr; 1.12056 + } 1.12057 + 1.12058 + nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(aGlobal.GetAsSupports()); 1.12059 + if (!prin) { 1.12060 + rv.Throw(NS_ERROR_UNEXPECTED); 1.12061 + return nullptr; 1.12062 + } 1.12063 + 1.12064 + nsCOMPtr<nsIURI> uri; 1.12065 + NS_NewURI(getter_AddRefs(uri), "about:blank"); 1.12066 + if (!uri) { 1.12067 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.12068 + return nullptr; 1.12069 + } 1.12070 + 1.12071 + nsCOMPtr<nsIDOMDocument> document; 1.12072 + nsresult res = 1.12073 + NS_NewDOMDocument(getter_AddRefs(document), 1.12074 + NullString(), 1.12075 + EmptyString(), 1.12076 + nullptr, 1.12077 + uri, 1.12078 + uri, 1.12079 + prin->GetPrincipal(), 1.12080 + true, 1.12081 + global, 1.12082 + DocumentFlavorLegacyGuess); 1.12083 + if (NS_FAILED(res)) { 1.12084 + rv.Throw(res); 1.12085 + return nullptr; 1.12086 + } 1.12087 + 1.12088 + nsCOMPtr<nsIDocument> doc = do_QueryInterface(document); 1.12089 + doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE); 1.12090 + 1.12091 + return doc.forget(); 1.12092 +} 1.12093 + 1.12094 +already_AddRefed<nsIDOMXPathExpression> 1.12095 +nsIDocument::CreateExpression(const nsAString& aExpression, 1.12096 + nsIDOMXPathNSResolver* aResolver, 1.12097 + ErrorResult& rv) 1.12098 +{ 1.12099 + return XPathEvaluator()->CreateExpression(aExpression, aResolver, rv); 1.12100 +} 1.12101 + 1.12102 +already_AddRefed<nsIDOMXPathNSResolver> 1.12103 +nsIDocument::CreateNSResolver(nsINode* aNodeResolver, 1.12104 + ErrorResult& rv) 1.12105 +{ 1.12106 + return XPathEvaluator()->CreateNSResolver(aNodeResolver, rv); 1.12107 +} 1.12108 + 1.12109 +already_AddRefed<nsISupports> 1.12110 +nsIDocument::Evaluate(const nsAString& aExpression, nsINode* aContextNode, 1.12111 + nsIDOMXPathNSResolver* aResolver, uint16_t aType, 1.12112 + nsISupports* aResult, ErrorResult& rv) 1.12113 +{ 1.12114 + return XPathEvaluator()->Evaluate(aExpression, aContextNode, aResolver, aType, 1.12115 + aResult, rv); 1.12116 +} 1.12117 + 1.12118 +NS_IMETHODIMP 1.12119 +nsDocument::CreateExpression(const nsAString& aExpression, 1.12120 + nsIDOMXPathNSResolver* aResolver, 1.12121 + nsIDOMXPathExpression** aResult) 1.12122 +{ 1.12123 + return XPathEvaluator()->CreateExpression(aExpression, aResolver, aResult); 1.12124 +} 1.12125 + 1.12126 +NS_IMETHODIMP 1.12127 +nsDocument::CreateNSResolver(nsIDOMNode* aNodeResolver, 1.12128 + nsIDOMXPathNSResolver** aResult) 1.12129 +{ 1.12130 + return XPathEvaluator()->CreateNSResolver(aNodeResolver, aResult); 1.12131 +} 1.12132 + 1.12133 +NS_IMETHODIMP 1.12134 +nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode, 1.12135 + nsIDOMXPathNSResolver* aResolver, uint16_t aType, 1.12136 + nsISupports* aInResult, nsISupports** aResult) 1.12137 +{ 1.12138 + return XPathEvaluator()->Evaluate(aExpression, aContextNode, aResolver, aType, 1.12139 + aInResult, aResult); 1.12140 +} 1.12141 + 1.12142 +// This is just a hack around the fact that window.document is not 1.12143 +// [Unforgeable] yet. 1.12144 +JSObject* 1.12145 +nsIDocument::WrapObject(JSContext *aCx) 1.12146 +{ 1.12147 + MOZ_ASSERT(IsDOMBinding()); 1.12148 + 1.12149 + JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx)); 1.12150 + if (!obj) { 1.12151 + return nullptr; 1.12152 + } 1.12153 + 1.12154 + nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetInnerWindow()); 1.12155 + if (!win) { 1.12156 + // No window, nothing else to do here 1.12157 + return obj; 1.12158 + } 1.12159 + 1.12160 + if (this != win->GetExtantDoc()) { 1.12161 + // We're not the current document; we're also done here 1.12162 + return obj; 1.12163 + } 1.12164 + 1.12165 + JSAutoCompartment ac(aCx, obj); 1.12166 + 1.12167 + JS::Rooted<JS::Value> winVal(aCx); 1.12168 + nsresult rv = nsContentUtils::WrapNative(aCx, win, &NS_GET_IID(nsIDOMWindow), 1.12169 + &winVal, 1.12170 + false); 1.12171 + if (NS_FAILED(rv)) { 1.12172 + Throw(aCx, rv); 1.12173 + return nullptr; 1.12174 + } 1.12175 + 1.12176 + NS_NAMED_LITERAL_STRING(doc_str, "document"); 1.12177 + 1.12178 + if (!JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal), doc_str.get(), 1.12179 + doc_str.Length(), JS::ObjectValue(*obj), 1.12180 + JS_PropertyStub, JS_StrictPropertyStub, 1.12181 + JSPROP_READONLY | JSPROP_ENUMERATE)) { 1.12182 + return nullptr; 1.12183 + } 1.12184 + 1.12185 + return obj; 1.12186 +} 1.12187 + 1.12188 +XPathEvaluator* 1.12189 +nsIDocument::XPathEvaluator() 1.12190 +{ 1.12191 + if (!mXPathEvaluator) { 1.12192 + mXPathEvaluator = new dom::XPathEvaluator(this); 1.12193 + } 1.12194 + return mXPathEvaluator; 1.12195 +} 1.12196 + 1.12197 +already_AddRefed<nsIDocumentEncoder> 1.12198 +nsIDocument::GetCachedEncoder() 1.12199 +{ 1.12200 + return mCachedEncoder.forget(); 1.12201 +} 1.12202 + 1.12203 +void 1.12204 +nsIDocument::SetCachedEncoder(already_AddRefed<nsIDocumentEncoder> aEncoder) 1.12205 +{ 1.12206 + mCachedEncoder = aEncoder; 1.12207 +} 1.12208 + 1.12209 +void 1.12210 +nsIDocument::SetContentTypeInternal(const nsACString& aType) 1.12211 +{ 1.12212 + mCachedEncoder = nullptr; 1.12213 + mContentType = aType; 1.12214 +} 1.12215 + 1.12216 +nsILoadContext* 1.12217 +nsIDocument::GetLoadContext() const 1.12218 +{ 1.12219 + return mDocumentContainer; 1.12220 +} 1.12221 + 1.12222 +nsIDocShell* 1.12223 +nsIDocument::GetDocShell() const 1.12224 +{ 1.12225 + return mDocumentContainer; 1.12226 +} 1.12227 + 1.12228 +void 1.12229 +nsIDocument::SetStateObject(nsIStructuredCloneContainer *scContainer) 1.12230 +{ 1.12231 + mStateObjectContainer = scContainer; 1.12232 + mStateObjectCached = nullptr; 1.12233 +} 1.12234 + 1.12235 +already_AddRefed<Element> 1.12236 +nsIDocument::CreateHTMLElement(nsIAtom* aTag) 1.12237 +{ 1.12238 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.12239 + nodeInfo = mNodeInfoManager->GetNodeInfo(aTag, nullptr, kNameSpaceID_XHTML, 1.12240 + nsIDOMNode::ELEMENT_NODE); 1.12241 + MOZ_ASSERT(nodeInfo, "GetNodeInfo should never fail"); 1.12242 + 1.12243 + nsCOMPtr<Element> element; 1.12244 + DebugOnly<nsresult> rv = NS_NewHTMLElement(getter_AddRefs(element), 1.12245 + nodeInfo.forget(), 1.12246 + mozilla::dom::NOT_FROM_PARSER); 1.12247 + 1.12248 + MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_NewHTMLElement should never fail"); 1.12249 + return element.forget(); 1.12250 +} 1.12251 + 1.12252 +bool 1.12253 +MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData) 1.12254 +{ 1.12255 + nsCOMArray<nsIDocument>* documents = 1.12256 + static_cast<nsCOMArray<nsIDocument>*>(aData); 1.12257 + if (aDoc) { 1.12258 + aDoc->SetIsInSyncOperation(true); 1.12259 + documents->AppendObject(aDoc); 1.12260 + aDoc->EnumerateSubDocuments(MarkDocumentTreeToBeInSyncOperation, aData); 1.12261 + } 1.12262 + return true; 1.12263 +} 1.12264 + 1.12265 +nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc) 1.12266 +{ 1.12267 + mMicroTaskLevel = nsContentUtils::MicroTaskLevel(); 1.12268 + nsContentUtils::SetMicroTaskLevel(0); 1.12269 + if (aDoc) { 1.12270 + nsPIDOMWindow* win = aDoc->GetWindow(); 1.12271 + if (win) { 1.12272 + nsCOMPtr<nsIDOMWindow> topWindow; 1.12273 + win->GetTop(getter_AddRefs(topWindow)); 1.12274 + nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow); 1.12275 + if (top) { 1.12276 + nsCOMPtr<nsIDocument> doc = top->GetExtantDoc(); 1.12277 + MarkDocumentTreeToBeInSyncOperation(doc, &mDocuments); 1.12278 + } 1.12279 + } 1.12280 + } 1.12281 +} 1.12282 + 1.12283 +nsAutoSyncOperation::~nsAutoSyncOperation() 1.12284 +{ 1.12285 + for (int32_t i = 0; i < mDocuments.Count(); ++i) { 1.12286 + mDocuments[i]->SetIsInSyncOperation(false); 1.12287 + } 1.12288 + nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel); 1.12289 +} 1.12290 +