1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/html/document/src/nsHTMLDocument.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3632 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=2 et tw=80: */ 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 +#include "nsHTMLDocument.h" 1.11 + 1.12 +#include "mozilla/DebugOnly.h" 1.13 +#include "mozilla/dom/HTMLAllCollection.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "nsGlobalWindow.h" 1.16 +#include "nsXPIDLString.h" 1.17 +#include "nsPrintfCString.h" 1.18 +#include "nsReadableUtils.h" 1.19 +#include "nsUnicharUtils.h" 1.20 +#include "nsIHTMLContentSink.h" 1.21 +#include "nsIXMLContentSink.h" 1.22 +#include "nsHTMLParts.h" 1.23 +#include "nsHTMLStyleSheet.h" 1.24 +#include "nsGkAtoms.h" 1.25 +#include "nsIPresShell.h" 1.26 +#include "nsPresContext.h" 1.27 +#include "nsIDOMNode.h" // for Find 1.28 +#include "nsIDOMNodeList.h" 1.29 +#include "nsIDOMElement.h" 1.30 +#include "nsPIDOMWindow.h" 1.31 +#include "nsDOMString.h" 1.32 +#include "nsIStreamListener.h" 1.33 +#include "nsIURI.h" 1.34 +#include "nsIIOService.h" 1.35 +#include "nsNetUtil.h" 1.36 +#include "nsIContentViewerContainer.h" 1.37 +#include "nsIContentViewer.h" 1.38 +#include "nsIMarkupDocumentViewer.h" 1.39 +#include "nsDocShell.h" 1.40 +#include "nsDocShellLoadTypes.h" 1.41 +#include "nsIWebNavigation.h" 1.42 +#include "nsIBaseWindow.h" 1.43 +#include "nsIWebShellServices.h" 1.44 +#include "nsIScriptContext.h" 1.45 +#include "nsIXPConnect.h" 1.46 +#include "nsContentList.h" 1.47 +#include "nsError.h" 1.48 +#include "nsIPrincipal.h" 1.49 +#include "nsJSPrincipals.h" 1.50 +#include "nsIScriptSecurityManager.h" 1.51 +#include "nsAttrName.h" 1.52 +#include "nsNodeUtils.h" 1.53 + 1.54 +#include "nsNetCID.h" 1.55 +#include "nsICookieService.h" 1.56 + 1.57 +#include "nsIServiceManager.h" 1.58 +#include "nsIConsoleService.h" 1.59 +#include "nsIComponentManager.h" 1.60 +#include "nsParserCIID.h" 1.61 +#include "nsIDOMHTMLElement.h" 1.62 +#include "nsIDOMHTMLHeadElement.h" 1.63 +#include "nsNameSpaceManager.h" 1.64 +#include "nsGenericHTMLElement.h" 1.65 +#include "mozilla/css/Loader.h" 1.66 +#include "nsIHttpChannel.h" 1.67 +#include "nsIFile.h" 1.68 +#include "nsFrameSelection.h" 1.69 +#include "nsISelectionPrivate.h"//for toStringwithformat code 1.70 + 1.71 +#include "nsContentUtils.h" 1.72 +#include "nsJSUtils.h" 1.73 +#include "nsIDocumentInlines.h" 1.74 +#include "nsIDocumentEncoder.h" //for outputting selection 1.75 +#include "nsICachingChannel.h" 1.76 +#include "nsIContentViewer.h" 1.77 +#include "nsIWyciwygChannel.h" 1.78 +#include "nsIScriptElement.h" 1.79 +#include "nsIScriptError.h" 1.80 +#include "nsIMutableArray.h" 1.81 +#include "nsArrayUtils.h" 1.82 +#include "nsIEffectiveTLDService.h" 1.83 + 1.84 +//AHMED 12-2 1.85 +#include "nsBidiUtils.h" 1.86 + 1.87 +#include "mozilla/dom/EncodingUtils.h" 1.88 +#include "mozilla/dom/FallbackEncoding.h" 1.89 +#include "nsIEditingSession.h" 1.90 +#include "nsIEditor.h" 1.91 +#include "nsNodeInfoManager.h" 1.92 +#include "nsIPlaintextEditor.h" 1.93 +#include "nsIHTMLEditor.h" 1.94 +#include "nsIEditorStyleSheets.h" 1.95 +#include "nsIInlineSpellChecker.h" 1.96 +#include "nsRange.h" 1.97 +#include "mozAutoDocUpdate.h" 1.98 +#include "nsCCUncollectableMarker.h" 1.99 +#include "nsHtml5Module.h" 1.100 +#include "prprf.h" 1.101 +#include "mozilla/dom/Element.h" 1.102 +#include "mozilla/Preferences.h" 1.103 +#include "nsMimeTypes.h" 1.104 +#include "nsIRequest.h" 1.105 +#include "nsHtml5TreeOpExecutor.h" 1.106 +#include "nsHtml5Parser.h" 1.107 +#include "nsIDOMJSWindow.h" 1.108 +#include "nsSandboxFlags.h" 1.109 +#include "nsIImageDocument.h" 1.110 +#include "mozilla/dom/HTMLBodyElement.h" 1.111 +#include "mozilla/dom/HTMLDocumentBinding.h" 1.112 +#include "nsCharsetSource.h" 1.113 +#include "nsIStringBundle.h" 1.114 +#include "nsDOMClassInfo.h" 1.115 + 1.116 +using namespace mozilla; 1.117 +using namespace mozilla::dom; 1.118 + 1.119 +#define NS_MAX_DOCUMENT_WRITE_DEPTH 20 1.120 + 1.121 +#include "prtime.h" 1.122 + 1.123 +//#define DEBUG_charset 1.124 + 1.125 +static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); 1.126 + 1.127 +uint32_t nsHTMLDocument::gWyciwygSessionCnt = 0; 1.128 + 1.129 +// this function will return false if the command is not recognized 1.130 +// inCommandID will be converted as necessary for internal operations 1.131 +// inParam will be converted as necessary for internal operations 1.132 +// outParam will be Empty if no parameter is needed or if returning a boolean 1.133 +// outIsBoolean will determine whether to send param as a boolean or string 1.134 +// outBooleanParam will not be set unless outIsBoolean 1.135 +static bool ConvertToMidasInternalCommand(const nsAString & inCommandID, 1.136 + const nsAString & inParam, 1.137 + nsACString& outCommandID, 1.138 + nsACString& outParam, 1.139 + bool& isBoolean, 1.140 + bool& boolValue); 1.141 + 1.142 +static bool ConvertToMidasInternalCommand(const nsAString & inCommandID, 1.143 + nsACString& outCommandID); 1.144 + 1.145 +// ================================================================== 1.146 +// = 1.147 +// ================================================================== 1.148 +static nsresult 1.149 +RemoveFromAgentSheets(nsCOMArray<nsIStyleSheet> &aAgentSheets, const nsAString& url) 1.150 +{ 1.151 + nsCOMPtr<nsIURI> uri; 1.152 + nsresult rv = NS_NewURI(getter_AddRefs(uri), url); 1.153 + NS_ENSURE_SUCCESS(rv, rv); 1.154 + 1.155 + for (int32_t i = aAgentSheets.Count() - 1; i >= 0; --i) { 1.156 + nsIStyleSheet* sheet = aAgentSheets[i]; 1.157 + nsIURI* sheetURI = sheet->GetSheetURI(); 1.158 + 1.159 + bool equals = false; 1.160 + uri->Equals(sheetURI, &equals); 1.161 + if (equals) { 1.162 + aAgentSheets.RemoveObjectAt(i); 1.163 + } 1.164 + } 1.165 + 1.166 + return NS_OK; 1.167 +} 1.168 + 1.169 +nsresult 1.170 +NS_NewHTMLDocument(nsIDocument** aInstancePtrResult, bool aLoadedAsData) 1.171 +{ 1.172 + nsRefPtr<nsHTMLDocument> doc = new nsHTMLDocument(); 1.173 + 1.174 + nsresult rv = doc->Init(); 1.175 + 1.176 + if (NS_FAILED(rv)) { 1.177 + *aInstancePtrResult = nullptr; 1.178 + return rv; 1.179 + } 1.180 + 1.181 + doc->SetLoadedAsData(aLoadedAsData); 1.182 + doc.forget(aInstancePtrResult); 1.183 + 1.184 + return NS_OK; 1.185 +} 1.186 + 1.187 + // NOTE! nsDocument::operator new() zeroes out all members, so don't 1.188 + // bother initializing members to 0. 1.189 + 1.190 +nsHTMLDocument::nsHTMLDocument() 1.191 + : nsDocument("text/html") 1.192 +{ 1.193 + // NOTE! nsDocument::operator new() zeroes out all members, so don't 1.194 + // bother initializing members to 0. 1.195 + 1.196 + mIsRegularHTML = true; 1.197 + mDefaultElementType = kNameSpaceID_XHTML; 1.198 + mCompatMode = eCompatibility_NavQuirks; 1.199 +} 1.200 + 1.201 +nsHTMLDocument::~nsHTMLDocument() 1.202 +{ 1.203 +} 1.204 + 1.205 +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsHTMLDocument, nsDocument, 1.206 + mAll, 1.207 + mImages, 1.208 + mApplets, 1.209 + mEmbeds, 1.210 + mLinks, 1.211 + mAnchors, 1.212 + mScripts, 1.213 + mForms, 1.214 + mFormControls, 1.215 + mWyciwygChannel, 1.216 + mMidasCommandManager) 1.217 + 1.218 +NS_IMPL_ADDREF_INHERITED(nsHTMLDocument, nsDocument) 1.219 +NS_IMPL_RELEASE_INHERITED(nsHTMLDocument, nsDocument) 1.220 + 1.221 +// QueryInterface implementation for nsHTMLDocument 1.222 +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLDocument) 1.223 + NS_INTERFACE_TABLE_INHERITED(nsHTMLDocument, nsIHTMLDocument, 1.224 + nsIDOMHTMLDocument) 1.225 +NS_INTERFACE_TABLE_TAIL_INHERITING(nsDocument) 1.226 + 1.227 +JSObject* 1.228 +nsHTMLDocument::WrapNode(JSContext* aCx) 1.229 +{ 1.230 + return HTMLDocumentBinding::Wrap(aCx, this); 1.231 +} 1.232 + 1.233 +nsresult 1.234 +nsHTMLDocument::Init() 1.235 +{ 1.236 + nsresult rv = nsDocument::Init(); 1.237 + NS_ENSURE_SUCCESS(rv, rv); 1.238 + 1.239 + // Now reset the compatibility mode of the CSSLoader 1.240 + // to match our compat mode. 1.241 + CSSLoader()->SetCompatibilityMode(mCompatMode); 1.242 + 1.243 + return NS_OK; 1.244 +} 1.245 + 1.246 + 1.247 +void 1.248 +nsHTMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) 1.249 +{ 1.250 + nsDocument::Reset(aChannel, aLoadGroup); 1.251 + 1.252 + if (aChannel) { 1.253 + aChannel->GetLoadFlags(&mLoadFlags); 1.254 + } 1.255 +} 1.256 + 1.257 +void 1.258 +nsHTMLDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, 1.259 + nsIPrincipal* aPrincipal) 1.260 +{ 1.261 + mLoadFlags = nsIRequest::LOAD_NORMAL; 1.262 + 1.263 + nsDocument::ResetToURI(aURI, aLoadGroup, aPrincipal); 1.264 + 1.265 + mImages = nullptr; 1.266 + mApplets = nullptr; 1.267 + mEmbeds = nullptr; 1.268 + mLinks = nullptr; 1.269 + mAnchors = nullptr; 1.270 + mScripts = nullptr; 1.271 + 1.272 + mForms = nullptr; 1.273 + 1.274 + NS_ASSERTION(!mWyciwygChannel, 1.275 + "nsHTMLDocument::Reset() - Wyciwyg Channel still exists!"); 1.276 + 1.277 + mWyciwygChannel = nullptr; 1.278 + 1.279 + // Make the content type default to "text/html", we are a HTML 1.280 + // document, after all. Once we start getting data, this may be 1.281 + // changed. 1.282 + SetContentTypeInternal(nsDependentCString("text/html")); 1.283 +} 1.284 + 1.285 +already_AddRefed<nsIPresShell> 1.286 +nsHTMLDocument::CreateShell(nsPresContext* aContext, 1.287 + nsViewManager* aViewManager, 1.288 + nsStyleSet* aStyleSet) 1.289 +{ 1.290 + return doCreateShell(aContext, aViewManager, aStyleSet, mCompatMode); 1.291 +} 1.292 + 1.293 +void 1.294 +nsHTMLDocument::TryHintCharset(nsIMarkupDocumentViewer* aMarkupDV, 1.295 + int32_t& aCharsetSource, nsACString& aCharset) 1.296 +{ 1.297 + if (aMarkupDV) { 1.298 + int32_t requestCharsetSource; 1.299 + nsresult rv = aMarkupDV->GetHintCharacterSetSource(&requestCharsetSource); 1.300 + 1.301 + if(NS_SUCCEEDED(rv) && kCharsetUninitialized != requestCharsetSource) { 1.302 + nsAutoCString requestCharset; 1.303 + rv = aMarkupDV->GetHintCharacterSet(requestCharset); 1.304 + aMarkupDV->SetHintCharacterSetSource((int32_t)(kCharsetUninitialized)); 1.305 + 1.306 + if(requestCharsetSource <= aCharsetSource) 1.307 + return; 1.308 + 1.309 + if(NS_SUCCEEDED(rv) && EncodingUtils::IsAsciiCompatible(requestCharset)) { 1.310 + aCharsetSource = requestCharsetSource; 1.311 + aCharset = requestCharset; 1.312 + 1.313 + return; 1.314 + } 1.315 + } 1.316 + } 1.317 + return; 1.318 +} 1.319 + 1.320 + 1.321 +void 1.322 +nsHTMLDocument::TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV, 1.323 + nsIDocShell* aDocShell, 1.324 + int32_t& aCharsetSource, 1.325 + nsACString& aCharset) 1.326 +{ 1.327 + nsresult rv = NS_OK; 1.328 + 1.329 + if(kCharsetFromUserForced <= aCharsetSource) 1.330 + return; 1.331 + 1.332 + // mCharacterSet not updated yet for channel, so check aCharset, too. 1.333 + if (WillIgnoreCharsetOverride() || !EncodingUtils::IsAsciiCompatible(aCharset)) { 1.334 + return; 1.335 + } 1.336 + 1.337 + nsAutoCString forceCharsetFromDocShell; 1.338 + if (aMarkupDV) { 1.339 + // XXX mailnews-only 1.340 + rv = aMarkupDV->GetForceCharacterSet(forceCharsetFromDocShell); 1.341 + } 1.342 + 1.343 + if(NS_SUCCEEDED(rv) && 1.344 + !forceCharsetFromDocShell.IsEmpty() && 1.345 + EncodingUtils::IsAsciiCompatible(forceCharsetFromDocShell)) { 1.346 + aCharset = forceCharsetFromDocShell; 1.347 + aCharsetSource = kCharsetFromUserForced; 1.348 + return; 1.349 + } 1.350 + 1.351 + if (aDocShell) { 1.352 + // This is the Character Encoding menu code path in Firefox 1.353 + nsAutoCString charset; 1.354 + rv = aDocShell->GetForcedCharset(charset); 1.355 + 1.356 + if (NS_SUCCEEDED(rv) && !charset.IsEmpty()) { 1.357 + if (!EncodingUtils::IsAsciiCompatible(charset)) { 1.358 + return; 1.359 + } 1.360 + aCharset = charset; 1.361 + aCharsetSource = kCharsetFromUserForced; 1.362 + aDocShell->SetForcedCharset(NS_LITERAL_CSTRING("")); 1.363 + } 1.364 + } 1.365 +} 1.366 + 1.367 +void 1.368 +nsHTMLDocument::TryCacheCharset(nsICachingChannel* aCachingChannel, 1.369 + int32_t& aCharsetSource, 1.370 + nsACString& aCharset) 1.371 +{ 1.372 + nsresult rv; 1.373 + 1.374 + if (kCharsetFromCache <= aCharsetSource) { 1.375 + return; 1.376 + } 1.377 + 1.378 + nsCString cachedCharset; 1.379 + rv = aCachingChannel->GetCacheTokenCachedCharset(cachedCharset); 1.380 + // Check EncodingUtils::IsAsciiCompatible() even in the cache case, because the value 1.381 + // might be stale and in the case of a stale charset that is not a rough 1.382 + // ASCII superset, the parser has no way to recover. 1.383 + if (NS_SUCCEEDED(rv) && 1.384 + !cachedCharset.IsEmpty() && 1.385 + EncodingUtils::IsAsciiCompatible(cachedCharset)) 1.386 + { 1.387 + aCharset = cachedCharset; 1.388 + aCharsetSource = kCharsetFromCache; 1.389 + } 1.390 +} 1.391 + 1.392 +void 1.393 +nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell, 1.394 + int32_t& aCharsetSource, 1.395 + nsACString& aCharset) 1.396 +{ 1.397 + if (!aDocShell) { 1.398 + return; 1.399 + } 1.400 + if (aCharsetSource >= kCharsetFromParentForced) { 1.401 + return; 1.402 + } 1.403 + 1.404 + int32_t parentSource; 1.405 + nsAutoCString parentCharset; 1.406 + nsCOMPtr<nsIPrincipal> parentPrincipal; 1.407 + aDocShell->GetParentCharset(parentCharset, 1.408 + &parentSource, 1.409 + getter_AddRefs(parentPrincipal)); 1.410 + if (parentCharset.IsEmpty()) { 1.411 + return; 1.412 + } 1.413 + if (kCharsetFromParentForced == parentSource || 1.414 + kCharsetFromUserForced == parentSource) { 1.415 + if (WillIgnoreCharsetOverride() || 1.416 + !EncodingUtils::IsAsciiCompatible(aCharset) || // if channel said UTF-16 1.417 + !EncodingUtils::IsAsciiCompatible(parentCharset)) { 1.418 + return; 1.419 + } 1.420 + aCharset.Assign(parentCharset); 1.421 + aCharsetSource = kCharsetFromParentForced; 1.422 + return; 1.423 + } 1.424 + 1.425 + if (aCharsetSource >= kCharsetFromParentFrame) { 1.426 + return; 1.427 + } 1.428 + 1.429 + if (kCharsetFromCache <= parentSource) { 1.430 + // Make sure that's OK 1.431 + if (!NodePrincipal()->Equals(parentPrincipal) || 1.432 + !EncodingUtils::IsAsciiCompatible(parentCharset)) { 1.433 + return; 1.434 + } 1.435 + 1.436 + aCharset.Assign(parentCharset); 1.437 + aCharsetSource = kCharsetFromParentFrame; 1.438 + } 1.439 +} 1.440 + 1.441 +void 1.442 +nsHTMLDocument::TryTLD(int32_t& aCharsetSource, nsACString& aCharset) 1.443 +{ 1.444 + if (aCharsetSource >= kCharsetFromTopLevelDomain) { 1.445 + return; 1.446 + } 1.447 + if (!FallbackEncoding::sGuessFallbackFromTopLevelDomain) { 1.448 + return; 1.449 + } 1.450 + if (!mDocumentURI) { 1.451 + return; 1.452 + } 1.453 + nsAutoCString host; 1.454 + mDocumentURI->GetAsciiHost(host); 1.455 + if (host.IsEmpty()) { 1.456 + return; 1.457 + } 1.458 + // First let's see if the host is DNS-absolute and ends with a dot and 1.459 + // get rid of that one. 1.460 + if (host.Last() == '.') { 1.461 + host.SetLength(host.Length() - 1); 1.462 + if (host.IsEmpty()) { 1.463 + return; 1.464 + } 1.465 + } 1.466 + // If we still have a dot, the host is weird, so let's continue only 1.467 + // if we have something other than a dot now. 1.468 + if (host.Last() == '.') { 1.469 + return; 1.470 + } 1.471 + int32_t index = host.RFindChar('.'); 1.472 + if (index == kNotFound) { 1.473 + // We have an intranet host, Gecko-internal URL or an IPv6 address. 1.474 + return; 1.475 + } 1.476 + // Since the string didn't end with a dot and we found a dot, 1.477 + // there is at least one character between the dot and the end of 1.478 + // the string, so taking the substring below is safe. 1.479 + nsAutoCString tld; 1.480 + ToLowerCase(Substring(host, index + 1, host.Length() - (index + 1)), tld); 1.481 + // Reject generic TLDs and country TLDs that need more research 1.482 + if (!FallbackEncoding::IsParticipatingTopLevelDomain(tld)) { 1.483 + return; 1.484 + } 1.485 + // Check if we have an IPv4 address 1.486 + bool seenNonDigit = false; 1.487 + for (size_t i = 0; i < tld.Length(); ++i) { 1.488 + char c = tld.CharAt(i); 1.489 + if (c < '0' || c > '9') { 1.490 + seenNonDigit = true; 1.491 + break; 1.492 + } 1.493 + } 1.494 + if (!seenNonDigit) { 1.495 + return; 1.496 + } 1.497 + aCharsetSource = kCharsetFromTopLevelDomain; 1.498 + FallbackEncoding::FromTopLevelDomain(tld, aCharset); 1.499 +} 1.500 + 1.501 +void 1.502 +nsHTMLDocument::TryFallback(int32_t& aCharsetSource, nsACString& aCharset) 1.503 +{ 1.504 + if (kCharsetFromFallback <= aCharsetSource) 1.505 + return; 1.506 + 1.507 + aCharsetSource = kCharsetFromFallback; 1.508 + FallbackEncoding::FromLocale(aCharset); 1.509 +} 1.510 + 1.511 +void 1.512 +nsHTMLDocument::SetDocumentCharacterSet(const nsACString& aCharSetID) 1.513 +{ 1.514 + nsDocument::SetDocumentCharacterSet(aCharSetID); 1.515 + // Make sure to stash this charset on our channel as needed if it's a wyciwyg 1.516 + // channel. 1.517 + nsCOMPtr<nsIWyciwygChannel> wyciwygChannel = do_QueryInterface(mChannel); 1.518 + if (wyciwygChannel) { 1.519 + wyciwygChannel->SetCharsetAndSource(GetDocumentCharacterSetSource(), 1.520 + aCharSetID); 1.521 + } 1.522 +} 1.523 + 1.524 +nsresult 1.525 +nsHTMLDocument::StartDocumentLoad(const char* aCommand, 1.526 + nsIChannel* aChannel, 1.527 + nsILoadGroup* aLoadGroup, 1.528 + nsISupports* aContainer, 1.529 + nsIStreamListener **aDocListener, 1.530 + bool aReset, 1.531 + nsIContentSink* aSink) 1.532 +{ 1.533 + if (!aCommand) { 1.534 + MOZ_ASSERT(false, "Command is mandatory"); 1.535 + return NS_ERROR_INVALID_POINTER; 1.536 + } 1.537 + if (aSink) { 1.538 + MOZ_ASSERT(false, "Got a sink override. Should not happen for HTML doc."); 1.539 + return NS_ERROR_INVALID_ARG; 1.540 + } 1.541 + if (!mIsRegularHTML) { 1.542 + MOZ_ASSERT(false, "Must not set HTML doc to XHTML mode before load start."); 1.543 + return NS_ERROR_DOM_INVALID_STATE_ERR; 1.544 + } 1.545 + 1.546 + nsAutoCString contentType; 1.547 + aChannel->GetContentType(contentType); 1.548 + 1.549 + bool view = !strcmp(aCommand, "view") || 1.550 + !strcmp(aCommand, "external-resource"); 1.551 + bool viewSource = !strcmp(aCommand, "view-source"); 1.552 + bool asData = !strcmp(aCommand, kLoadAsData); 1.553 + if(!(view || viewSource || asData)) { 1.554 + MOZ_ASSERT(false, "Bad parser command"); 1.555 + return NS_ERROR_INVALID_ARG; 1.556 + } 1.557 + 1.558 + bool html = contentType.EqualsLiteral(TEXT_HTML); 1.559 + bool xhtml = !html && contentType.EqualsLiteral(APPLICATION_XHTML_XML); 1.560 + bool plainText = !html && !xhtml && nsContentUtils::IsPlainTextType(contentType); 1.561 + if (!(html || xhtml || plainText || viewSource)) { 1.562 + MOZ_ASSERT(false, "Channel with bad content type."); 1.563 + return NS_ERROR_INVALID_ARG; 1.564 + } 1.565 + 1.566 + bool loadAsHtml5 = true; 1.567 + 1.568 + if (!viewSource && xhtml) { 1.569 + // We're parsing XHTML as XML, remember that. 1.570 + mIsRegularHTML = false; 1.571 + mCompatMode = eCompatibility_FullStandards; 1.572 + loadAsHtml5 = false; 1.573 + } 1.574 + 1.575 + // TODO: Proper about:blank treatment is bug 543435 1.576 + if (loadAsHtml5 && view) { 1.577 + // mDocumentURI hasn't been set, yet, so get the URI from the channel 1.578 + nsCOMPtr<nsIURI> uri; 1.579 + aChannel->GetOriginalURI(getter_AddRefs(uri)); 1.580 + // Adapted from nsDocShell: 1.581 + // GetSpec can be expensive for some URIs, so check the scheme first. 1.582 + bool isAbout = false; 1.583 + if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) { 1.584 + nsAutoCString str; 1.585 + uri->GetSpec(str); 1.586 + if (str.EqualsLiteral("about:blank")) { 1.587 + loadAsHtml5 = false; 1.588 + } 1.589 + } 1.590 + } 1.591 + 1.592 + CSSLoader()->SetCompatibilityMode(mCompatMode); 1.593 + 1.594 + nsresult rv = nsDocument::StartDocumentLoad(aCommand, 1.595 + aChannel, aLoadGroup, 1.596 + aContainer, 1.597 + aDocListener, aReset); 1.598 + if (NS_FAILED(rv)) { 1.599 + return rv; 1.600 + } 1.601 + 1.602 + // Store the security info for future use with wyciwyg channels. 1.603 + aChannel->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); 1.604 + 1.605 + nsCOMPtr<nsIURI> uri; 1.606 + rv = aChannel->GetURI(getter_AddRefs(uri)); 1.607 + if (NS_FAILED(rv)) { 1.608 + return rv; 1.609 + } 1.610 + 1.611 + nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel); 1.612 + 1.613 + if (loadAsHtml5) { 1.614 + mParser = nsHtml5Module::NewHtml5Parser(); 1.615 + if (plainText) { 1.616 + if (viewSource) { 1.617 + mParser->MarkAsNotScriptCreated("view-source-plain"); 1.618 + } else { 1.619 + mParser->MarkAsNotScriptCreated("plain-text"); 1.620 + } 1.621 + } else if (viewSource && !html) { 1.622 + mParser->MarkAsNotScriptCreated("view-source-xml"); 1.623 + } else { 1.624 + mParser->MarkAsNotScriptCreated(aCommand); 1.625 + } 1.626 + } else { 1.627 + mParser = do_CreateInstance(kCParserCID, &rv); 1.628 + NS_ENSURE_SUCCESS(rv, rv); 1.629 + } 1.630 + 1.631 + // Look for the parent document. Note that at this point we don't have our 1.632 + // content viewer set up yet, and therefore do not have a useful 1.633 + // mParentDocument. 1.634 + 1.635 + // in this block of code, if we get an error result, we return it 1.636 + // but if we get a null pointer, that's perfectly legal for parent 1.637 + // and parentContentViewer 1.638 + nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer)); 1.639 + nsCOMPtr<nsIDocShellTreeItem> parentAsItem; 1.640 + if (docShell) { 1.641 + docShell->GetSameTypeParent(getter_AddRefs(parentAsItem)); 1.642 + } 1.643 + 1.644 + nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem)); 1.645 + nsCOMPtr<nsIContentViewer> parentContentViewer; 1.646 + if (parent) { 1.647 + rv = parent->GetContentViewer(getter_AddRefs(parentContentViewer)); 1.648 + NS_ENSURE_SUCCESS(rv, rv); 1.649 + } 1.650 + 1.651 + nsCOMPtr<nsIMarkupDocumentViewer> muCV; 1.652 + nsCOMPtr<nsIContentViewer> cv; 1.653 + if (docShell) { 1.654 + docShell->GetContentViewer(getter_AddRefs(cv)); 1.655 + } 1.656 + if (cv) { 1.657 + muCV = do_QueryInterface(cv); 1.658 + } else { 1.659 + muCV = do_QueryInterface(parentContentViewer); 1.660 + } 1.661 + 1.662 + nsAutoCString urlSpec; 1.663 + uri->GetSpec(urlSpec); 1.664 +#ifdef DEBUG_charset 1.665 + printf("Determining charset for %s\n", urlSpec.get()); 1.666 +#endif 1.667 + 1.668 + // These are the charset source and charset for our document 1.669 + int32_t charsetSource; 1.670 + nsAutoCString charset; 1.671 + 1.672 + // These are the charset source and charset for the parser. This can differ 1.673 + // from that for the document if the channel is a wyciwyg channel. 1.674 + int32_t parserCharsetSource; 1.675 + nsAutoCString parserCharset; 1.676 + 1.677 + nsCOMPtr<nsIWyciwygChannel> wyciwygChannel; 1.678 + 1.679 + // For error reporting 1.680 + nsHtml5TreeOpExecutor* executor = nullptr; 1.681 + if (loadAsHtml5) { 1.682 + executor = static_cast<nsHtml5TreeOpExecutor*> (mParser->GetContentSink()); 1.683 + } 1.684 + 1.685 + if (!IsHTML() || !docShell) { // no docshell for text/html XHR 1.686 + charsetSource = IsHTML() ? kCharsetFromFallback 1.687 + : kCharsetFromDocTypeDefault; 1.688 + charset.AssignLiteral("UTF-8"); 1.689 + TryChannelCharset(aChannel, charsetSource, charset, executor); 1.690 + parserCharsetSource = charsetSource; 1.691 + parserCharset = charset; 1.692 + } else { 1.693 + NS_ASSERTION(docShell, "Unexpected null value"); 1.694 + 1.695 + charsetSource = kCharsetUninitialized; 1.696 + wyciwygChannel = do_QueryInterface(aChannel); 1.697 + 1.698 + // The following will try to get the character encoding from various 1.699 + // sources. Each Try* function will return early if the source is already 1.700 + // at least as large as any of the sources it might look at. Some of 1.701 + // these functions (like TryHintCharset and TryParentCharset) can set 1.702 + // charsetSource to various values depending on where the charset they 1.703 + // end up finding originally comes from. 1.704 + 1.705 + // Don't actually get the charset from the channel if this is a 1.706 + // wyciwyg channel; it'll always be UTF-16 1.707 + if (!wyciwygChannel) { 1.708 + // Otherwise, try the channel's charset (e.g., charset from HTTP 1.709 + // "Content-Type" header) first. This way, we get to reject overrides in 1.710 + // TryParentCharset and TryUserForcedCharset if the channel said UTF-16. 1.711 + // This is to avoid socially engineered XSS by adding user-supplied 1.712 + // content to a UTF-16 site such that the byte have a dangerous 1.713 + // interpretation as ASCII and the user can be lured to using the 1.714 + // charset menu. 1.715 + TryChannelCharset(aChannel, charsetSource, charset, executor); 1.716 + } 1.717 + 1.718 + TryUserForcedCharset(muCV, docShell, charsetSource, charset); 1.719 + 1.720 + TryHintCharset(muCV, charsetSource, charset); // XXX mailnews-only 1.721 + TryParentCharset(docShell, charsetSource, charset); 1.722 + 1.723 + if (cachingChan && !urlSpec.IsEmpty()) { 1.724 + TryCacheCharset(cachingChan, charsetSource, charset); 1.725 + } 1.726 + 1.727 + TryTLD(charsetSource, charset); 1.728 + TryFallback(charsetSource, charset); 1.729 + 1.730 + if (wyciwygChannel) { 1.731 + // We know for sure that the parser needs to be using UTF16. 1.732 + parserCharset = "UTF-16"; 1.733 + parserCharsetSource = charsetSource < kCharsetFromChannel ? 1.734 + kCharsetFromChannel : charsetSource; 1.735 + 1.736 + nsAutoCString cachedCharset; 1.737 + int32_t cachedSource; 1.738 + rv = wyciwygChannel->GetCharsetAndSource(&cachedSource, cachedCharset); 1.739 + if (NS_SUCCEEDED(rv)) { 1.740 + if (cachedSource > charsetSource) { 1.741 + charsetSource = cachedSource; 1.742 + charset = cachedCharset; 1.743 + } 1.744 + } else { 1.745 + // Don't propagate this error. 1.746 + rv = NS_OK; 1.747 + } 1.748 + 1.749 + } else { 1.750 + parserCharset = charset; 1.751 + parserCharsetSource = charsetSource; 1.752 + } 1.753 + } 1.754 + 1.755 + SetDocumentCharacterSetSource(charsetSource); 1.756 + SetDocumentCharacterSet(charset); 1.757 + 1.758 + if (cachingChan) { 1.759 + NS_ASSERTION(charset == parserCharset, 1.760 + "How did those end up different here? wyciwyg channels are " 1.761 + "not nsICachingChannel"); 1.762 + rv = cachingChan->SetCacheTokenCachedCharset(charset); 1.763 + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "cannot SetMetaDataElement"); 1.764 + rv = NS_OK; // don't propagate error 1.765 + } 1.766 + 1.767 + // Set the parser as the stream listener for the document loader... 1.768 + rv = NS_OK; 1.769 + nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener(); 1.770 + listener.forget(aDocListener); 1.771 + 1.772 +#ifdef DEBUG_charset 1.773 + printf(" charset = %s source %d\n", 1.774 + charset.get(), charsetSource); 1.775 +#endif 1.776 + mParser->SetDocumentCharset(parserCharset, parserCharsetSource); 1.777 + mParser->SetCommand(aCommand); 1.778 + 1.779 + if (!IsHTML()) { 1.780 + MOZ_ASSERT(!loadAsHtml5); 1.781 + nsCOMPtr<nsIXMLContentSink> xmlsink; 1.782 + NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri, 1.783 + docShell, aChannel); 1.784 + mParser->SetContentSink(xmlsink); 1.785 + } else { 1.786 + if (loadAsHtml5) { 1.787 + nsHtml5Module::Initialize(mParser, this, uri, docShell, aChannel); 1.788 + } else { 1.789 + // about:blank *only* 1.790 + nsCOMPtr<nsIHTMLContentSink> htmlsink; 1.791 + NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri, 1.792 + docShell, aChannel); 1.793 + mParser->SetContentSink(htmlsink); 1.794 + } 1.795 + } 1.796 + 1.797 + if (plainText && !nsContentUtils::IsChildOfSameType(this) && 1.798 + Preferences::GetBool("plain_text.wrap_long_lines")) { 1.799 + nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); 1.800 + NS_ASSERTION(NS_SUCCEEDED(rv) && bundleService, "The bundle service could not be loaded"); 1.801 + nsCOMPtr<nsIStringBundle> bundle; 1.802 + rv = bundleService->CreateBundle("chrome://global/locale/browser.properties", 1.803 + getter_AddRefs(bundle)); 1.804 + NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/browser.properties could not be loaded"); 1.805 + nsXPIDLString title; 1.806 + if (bundle) { 1.807 + bundle->GetStringFromName(MOZ_UTF16("plainText.wordWrap"), getter_Copies(title)); 1.808 + } 1.809 + SetSelectedStyleSheetSet(title); 1.810 + } 1.811 + 1.812 + // parser the content of the URI 1.813 + mParser->Parse(uri, nullptr, (void *)this); 1.814 + 1.815 + return rv; 1.816 +} 1.817 + 1.818 +void 1.819 +nsHTMLDocument::StopDocumentLoad() 1.820 +{ 1.821 + BlockOnload(); 1.822 + 1.823 + // Remove the wyciwyg channel request from the document load group 1.824 + // that we added in Open() if Open() was called on this doc. 1.825 + RemoveWyciwygChannel(); 1.826 + NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): " 1.827 + "nsIWyciwygChannel could not be removed!"); 1.828 + 1.829 + nsDocument::StopDocumentLoad(); 1.830 + UnblockOnload(false); 1.831 + return; 1.832 +} 1.833 + 1.834 +void 1.835 +nsHTMLDocument::BeginLoad() 1.836 +{ 1.837 + if (IsEditingOn()) { 1.838 + // Reset() blows away all event listeners in the document, and our 1.839 + // editor relies heavily on those. Midas is turned on, to make it 1.840 + // work, re-initialize it to give it a chance to add its event 1.841 + // listeners again. 1.842 + 1.843 + TurnEditingOff(); 1.844 + EditingStateChanged(); 1.845 + } 1.846 + nsDocument::BeginLoad(); 1.847 +} 1.848 + 1.849 +void 1.850 +nsHTMLDocument::EndLoad() 1.851 +{ 1.852 + bool turnOnEditing = 1.853 + mParser && (HasFlag(NODE_IS_EDITABLE) || mContentEditableCount > 0); 1.854 + // Note: nsDocument::EndLoad nulls out mParser. 1.855 + nsDocument::EndLoad(); 1.856 + if (turnOnEditing) { 1.857 + EditingStateChanged(); 1.858 + } 1.859 +} 1.860 + 1.861 +void 1.862 +nsHTMLDocument::SetCompatibilityMode(nsCompatibility aMode) 1.863 +{ 1.864 + NS_ASSERTION(IsHTML() || aMode == eCompatibility_FullStandards, 1.865 + "Bad compat mode for XHTML document!"); 1.866 + 1.867 + mCompatMode = aMode; 1.868 + CSSLoader()->SetCompatibilityMode(mCompatMode); 1.869 + nsCOMPtr<nsIPresShell> shell = GetShell(); 1.870 + if (shell) { 1.871 + nsPresContext *pc = shell->GetPresContext(); 1.872 + if (pc) { 1.873 + pc->CompatibilityModeChanged(); 1.874 + } 1.875 + } 1.876 +} 1.877 + 1.878 +// 1.879 +// nsIDOMHTMLDocument interface implementation 1.880 +// 1.881 +already_AddRefed<nsIURI> 1.882 +nsHTMLDocument::GetDomainURI() 1.883 +{ 1.884 + nsIPrincipal* principal = NodePrincipal(); 1.885 + 1.886 + nsCOMPtr<nsIURI> uri; 1.887 + principal->GetDomain(getter_AddRefs(uri)); 1.888 + if (uri) { 1.889 + return uri.forget(); 1.890 + } 1.891 + 1.892 + principal->GetURI(getter_AddRefs(uri)); 1.893 + return uri.forget(); 1.894 +} 1.895 + 1.896 + 1.897 +NS_IMETHODIMP 1.898 +nsHTMLDocument::GetDomain(nsAString& aDomain) 1.899 +{ 1.900 + ErrorResult rv; 1.901 + GetDomain(aDomain, rv); 1.902 + return rv.ErrorCode(); 1.903 +} 1.904 + 1.905 +void 1.906 +nsHTMLDocument::GetDomain(nsAString& aDomain, ErrorResult& rv) 1.907 +{ 1.908 + nsCOMPtr<nsIURI> uri = GetDomainURI(); 1.909 + 1.910 + if (!uri) { 1.911 + rv.Throw(NS_ERROR_FAILURE); 1.912 + return; 1.913 + } 1.914 + 1.915 + nsAutoCString hostName; 1.916 + 1.917 + if (NS_SUCCEEDED(uri->GetHost(hostName))) { 1.918 + CopyUTF8toUTF16(hostName, aDomain); 1.919 + } else { 1.920 + // If we can't get the host from the URI (e.g. about:, javascript:, 1.921 + // etc), just return an null string. 1.922 + SetDOMStringToNull(aDomain); 1.923 + } 1.924 +} 1.925 + 1.926 +NS_IMETHODIMP 1.927 +nsHTMLDocument::SetDomain(const nsAString& aDomain) 1.928 +{ 1.929 + ErrorResult rv; 1.930 + SetDomain(aDomain, rv); 1.931 + return rv.ErrorCode(); 1.932 +} 1.933 + 1.934 +void 1.935 +nsHTMLDocument::SetDomain(const nsAString& aDomain, ErrorResult& rv) 1.936 +{ 1.937 + if (mSandboxFlags & SANDBOXED_DOMAIN) { 1.938 + // We're sandboxed; disallow setting domain 1.939 + rv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.940 + return; 1.941 + } 1.942 + 1.943 + if (aDomain.IsEmpty()) { 1.944 + rv.Throw(NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN); 1.945 + return; 1.946 + } 1.947 + 1.948 + // Create new URI 1.949 + nsCOMPtr<nsIURI> uri = GetDomainURI(); 1.950 + 1.951 + if (!uri) { 1.952 + rv.Throw(NS_ERROR_FAILURE); 1.953 + return; 1.954 + } 1.955 + 1.956 + nsAutoCString newURIString; 1.957 + if (NS_FAILED(uri->GetScheme(newURIString))) { 1.958 + rv.Throw(NS_ERROR_FAILURE); 1.959 + return; 1.960 + } 1.961 + nsAutoCString path; 1.962 + if (NS_FAILED(uri->GetPath(path))) { 1.963 + rv.Throw(NS_ERROR_FAILURE); 1.964 + return; 1.965 + } 1.966 + newURIString.AppendLiteral("://"); 1.967 + AppendUTF16toUTF8(aDomain, newURIString); 1.968 + newURIString.Append(path); 1.969 + 1.970 + nsCOMPtr<nsIURI> newURI; 1.971 + if (NS_FAILED(NS_NewURI(getter_AddRefs(newURI), newURIString))) { 1.972 + rv.Throw(NS_ERROR_FAILURE); 1.973 + return; 1.974 + } 1.975 + 1.976 + // Check new domain - must be a superdomain of the current host 1.977 + // For example, a page from foo.bar.com may set domain to bar.com, 1.978 + // but not to ar.com, baz.com, or fi.foo.bar.com. 1.979 + nsAutoCString current, domain; 1.980 + if (NS_FAILED(uri->GetAsciiHost(current))) 1.981 + current.Truncate(); 1.982 + if (NS_FAILED(newURI->GetAsciiHost(domain))) 1.983 + domain.Truncate(); 1.984 + 1.985 + bool ok = current.Equals(domain); 1.986 + if (current.Length() > domain.Length() && 1.987 + StringEndsWith(current, domain) && 1.988 + current.CharAt(current.Length() - domain.Length() - 1) == '.') { 1.989 + // We're golden if the new domain is the current page's base domain or a 1.990 + // subdomain of it. 1.991 + nsCOMPtr<nsIEffectiveTLDService> tldService = 1.992 + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); 1.993 + if (!tldService) { 1.994 + rv.Throw(NS_ERROR_NOT_AVAILABLE); 1.995 + return; 1.996 + } 1.997 + 1.998 + nsAutoCString currentBaseDomain; 1.999 + ok = NS_SUCCEEDED(tldService->GetBaseDomain(uri, 0, currentBaseDomain)); 1.1000 + NS_ASSERTION(StringEndsWith(domain, currentBaseDomain) == 1.1001 + (domain.Length() >= currentBaseDomain.Length()), 1.1002 + "uh-oh! slight optimization wasn't valid somehow!"); 1.1003 + ok = ok && domain.Length() >= currentBaseDomain.Length(); 1.1004 + } 1.1005 + if (!ok) { 1.1006 + // Error: illegal domain 1.1007 + rv.Throw(NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN); 1.1008 + return; 1.1009 + } 1.1010 + 1.1011 + rv = NodePrincipal()->SetDomain(newURI); 1.1012 +} 1.1013 + 1.1014 +nsGenericHTMLElement* 1.1015 +nsHTMLDocument::GetBody() 1.1016 +{ 1.1017 + Element* html = GetHtmlElement(); 1.1018 + if (!html) { 1.1019 + return nullptr; 1.1020 + } 1.1021 + 1.1022 + for (nsIContent* child = html->GetFirstChild(); 1.1023 + child; 1.1024 + child = child->GetNextSibling()) { 1.1025 + if (child->IsHTML(nsGkAtoms::body) || child->IsHTML(nsGkAtoms::frameset)) { 1.1026 + return static_cast<nsGenericHTMLElement*>(child); 1.1027 + } 1.1028 + } 1.1029 + 1.1030 + return nullptr; 1.1031 +} 1.1032 + 1.1033 +NS_IMETHODIMP 1.1034 +nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody) 1.1035 +{ 1.1036 + *aBody = nullptr; 1.1037 + 1.1038 + nsIContent *body = GetBody(); 1.1039 + 1.1040 + return body ? CallQueryInterface(body, aBody) : NS_OK; 1.1041 +} 1.1042 + 1.1043 +NS_IMETHODIMP 1.1044 +nsHTMLDocument::SetBody(nsIDOMHTMLElement* aBody) 1.1045 +{ 1.1046 + nsCOMPtr<nsIContent> newBody = do_QueryInterface(aBody); 1.1047 + MOZ_ASSERT(!newBody || newBody->IsHTML(), 1.1048 + "How could we be an nsIContent but not actually HTML here?"); 1.1049 + ErrorResult rv; 1.1050 + SetBody(static_cast<nsGenericHTMLElement*>(newBody.get()), rv); 1.1051 + return rv.ErrorCode(); 1.1052 +} 1.1053 + 1.1054 +void 1.1055 +nsHTMLDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv) 1.1056 +{ 1.1057 + Element* root = GetRootElement(); 1.1058 + 1.1059 + // The body element must be either a body tag or a frameset tag. And we must 1.1060 + // have a html root tag, otherwise GetBody will not return the newly set 1.1061 + // body. 1.1062 + if (!newBody || !(newBody->Tag() == nsGkAtoms::body || 1.1063 + newBody->Tag() == nsGkAtoms::frameset) || 1.1064 + !root || !root->IsHTML() || 1.1065 + root->Tag() != nsGkAtoms::html) { 1.1066 + rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1067 + return; 1.1068 + } 1.1069 + 1.1070 + // Use DOM methods so that we pass through the appropriate security checks. 1.1071 + nsCOMPtr<Element> currentBody = GetBodyElement(); 1.1072 + if (currentBody) { 1.1073 + root->ReplaceChild(*newBody, *currentBody, rv); 1.1074 + } else { 1.1075 + root->AppendChild(*newBody, rv); 1.1076 + } 1.1077 +} 1.1078 + 1.1079 +NS_IMETHODIMP 1.1080 +nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead) 1.1081 +{ 1.1082 + *aHead = nullptr; 1.1083 + 1.1084 + Element* head = GetHeadElement(); 1.1085 + 1.1086 + return head ? CallQueryInterface(head, aHead) : NS_OK; 1.1087 +} 1.1088 + 1.1089 +NS_IMETHODIMP 1.1090 +nsHTMLDocument::GetImages(nsIDOMHTMLCollection** aImages) 1.1091 +{ 1.1092 + NS_ADDREF(*aImages = Images()); 1.1093 + return NS_OK; 1.1094 +} 1.1095 + 1.1096 +nsIHTMLCollection* 1.1097 +nsHTMLDocument::Images() 1.1098 +{ 1.1099 + if (!mImages) { 1.1100 + mImages = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::img, nsGkAtoms::img); 1.1101 + } 1.1102 + return mImages; 1.1103 +} 1.1104 + 1.1105 +NS_IMETHODIMP 1.1106 +nsHTMLDocument::GetApplets(nsIDOMHTMLCollection** aApplets) 1.1107 +{ 1.1108 + NS_ADDREF(*aApplets = Applets()); 1.1109 + return NS_OK; 1.1110 +} 1.1111 + 1.1112 +nsIHTMLCollection* 1.1113 +nsHTMLDocument::Applets() 1.1114 +{ 1.1115 + if (!mApplets) { 1.1116 + mApplets = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::applet, nsGkAtoms::applet); 1.1117 + } 1.1118 + return mApplets; 1.1119 +} 1.1120 + 1.1121 +bool 1.1122 +nsHTMLDocument::MatchLinks(nsIContent *aContent, int32_t aNamespaceID, 1.1123 + nsIAtom* aAtom, void* aData) 1.1124 +{ 1.1125 + nsIDocument* doc = aContent->GetCurrentDoc(); 1.1126 + 1.1127 + if (doc) { 1.1128 + NS_ASSERTION(aContent->IsInDoc(), 1.1129 + "This method should never be called on content nodes that " 1.1130 + "are not in a document!"); 1.1131 +#ifdef DEBUG 1.1132 + { 1.1133 + nsCOMPtr<nsIHTMLDocument> htmldoc = 1.1134 + do_QueryInterface(aContent->GetCurrentDoc()); 1.1135 + NS_ASSERTION(htmldoc, 1.1136 + "Huh, how did this happen? This should only be used with " 1.1137 + "HTML documents!"); 1.1138 + } 1.1139 +#endif 1.1140 + 1.1141 + nsINodeInfo *ni = aContent->NodeInfo(); 1.1142 + 1.1143 + nsIAtom *localName = ni->NameAtom(); 1.1144 + if (ni->NamespaceID() == kNameSpaceID_XHTML && 1.1145 + (localName == nsGkAtoms::a || localName == nsGkAtoms::area)) { 1.1146 + return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::href); 1.1147 + } 1.1148 + } 1.1149 + 1.1150 + return false; 1.1151 +} 1.1152 + 1.1153 +NS_IMETHODIMP 1.1154 +nsHTMLDocument::GetLinks(nsIDOMHTMLCollection** aLinks) 1.1155 +{ 1.1156 + NS_ADDREF(*aLinks = Links()); 1.1157 + return NS_OK; 1.1158 +} 1.1159 + 1.1160 +nsIHTMLCollection* 1.1161 +nsHTMLDocument::Links() 1.1162 +{ 1.1163 + if (!mLinks) { 1.1164 + mLinks = new nsContentList(this, MatchLinks, nullptr, nullptr); 1.1165 + } 1.1166 + return mLinks; 1.1167 +} 1.1168 + 1.1169 +bool 1.1170 +nsHTMLDocument::MatchAnchors(nsIContent *aContent, int32_t aNamespaceID, 1.1171 + nsIAtom* aAtom, void* aData) 1.1172 +{ 1.1173 + NS_ASSERTION(aContent->IsInDoc(), 1.1174 + "This method should never be called on content nodes that " 1.1175 + "are not in a document!"); 1.1176 +#ifdef DEBUG 1.1177 + { 1.1178 + nsCOMPtr<nsIHTMLDocument> htmldoc = 1.1179 + do_QueryInterface(aContent->GetCurrentDoc()); 1.1180 + NS_ASSERTION(htmldoc, 1.1181 + "Huh, how did this happen? This should only be used with " 1.1182 + "HTML documents!"); 1.1183 + } 1.1184 +#endif 1.1185 + 1.1186 + if (aContent->NodeInfo()->Equals(nsGkAtoms::a, kNameSpaceID_XHTML)) { 1.1187 + return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::name); 1.1188 + } 1.1189 + 1.1190 + return false; 1.1191 +} 1.1192 + 1.1193 +NS_IMETHODIMP 1.1194 +nsHTMLDocument::GetAnchors(nsIDOMHTMLCollection** aAnchors) 1.1195 +{ 1.1196 + NS_ADDREF(*aAnchors = Anchors()); 1.1197 + return NS_OK; 1.1198 +} 1.1199 + 1.1200 +nsIHTMLCollection* 1.1201 +nsHTMLDocument::Anchors() 1.1202 +{ 1.1203 + if (!mAnchors) { 1.1204 + mAnchors = new nsContentList(this, MatchAnchors, nullptr, nullptr); 1.1205 + } 1.1206 + return mAnchors; 1.1207 +} 1.1208 + 1.1209 +NS_IMETHODIMP 1.1210 +nsHTMLDocument::GetScripts(nsIDOMHTMLCollection** aScripts) 1.1211 +{ 1.1212 + NS_ADDREF(*aScripts = Scripts()); 1.1213 + return NS_OK; 1.1214 +} 1.1215 + 1.1216 +nsIHTMLCollection* 1.1217 +nsHTMLDocument::Scripts() 1.1218 +{ 1.1219 + if (!mScripts) { 1.1220 + mScripts = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::script, nsGkAtoms::script); 1.1221 + } 1.1222 + return mScripts; 1.1223 +} 1.1224 + 1.1225 +NS_IMETHODIMP 1.1226 +nsHTMLDocument::GetCookie(nsAString& aCookie) 1.1227 +{ 1.1228 + ErrorResult rv; 1.1229 + GetCookie(aCookie, rv); 1.1230 + return rv.ErrorCode(); 1.1231 +} 1.1232 + 1.1233 +void 1.1234 +nsHTMLDocument::GetCookie(nsAString& aCookie, ErrorResult& rv) 1.1235 +{ 1.1236 + aCookie.Truncate(); // clear current cookie in case service fails; 1.1237 + // no cookie isn't an error condition. 1.1238 + 1.1239 + if (mDisableCookieAccess) { 1.1240 + return; 1.1241 + } 1.1242 + 1.1243 + // If the document's sandboxed origin flag is set, access to read cookies 1.1244 + // is prohibited. 1.1245 + if (mSandboxFlags & SANDBOXED_ORIGIN) { 1.1246 + rv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.1247 + return; 1.1248 + } 1.1249 + 1.1250 + // not having a cookie service isn't an error 1.1251 + nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID); 1.1252 + if (service) { 1.1253 + // Get a URI from the document principal. We use the original 1.1254 + // codebase in case the codebase was changed by SetDomain 1.1255 + nsCOMPtr<nsIURI> codebaseURI; 1.1256 + NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); 1.1257 + 1.1258 + if (!codebaseURI) { 1.1259 + // Document's principal is not a codebase (may be system), so 1.1260 + // can't set cookies 1.1261 + 1.1262 + return; 1.1263 + } 1.1264 + 1.1265 + nsXPIDLCString cookie; 1.1266 + service->GetCookieString(codebaseURI, mChannel, getter_Copies(cookie)); 1.1267 + // CopyUTF8toUTF16 doesn't handle error 1.1268 + // because it assumes that the input is valid. 1.1269 + nsContentUtils::ConvertStringFromEncoding(NS_LITERAL_CSTRING("UTF-8"), 1.1270 + cookie, aCookie); 1.1271 + } 1.1272 +} 1.1273 + 1.1274 +NS_IMETHODIMP 1.1275 +nsHTMLDocument::SetCookie(const nsAString& aCookie) 1.1276 +{ 1.1277 + ErrorResult rv; 1.1278 + SetCookie(aCookie, rv); 1.1279 + return rv.ErrorCode(); 1.1280 +} 1.1281 + 1.1282 +void 1.1283 +nsHTMLDocument::SetCookie(const nsAString& aCookie, ErrorResult& rv) 1.1284 +{ 1.1285 + if (mDisableCookieAccess) { 1.1286 + return; 1.1287 + } 1.1288 + 1.1289 + // If the document's sandboxed origin flag is set, access to write cookies 1.1290 + // is prohibited. 1.1291 + if (mSandboxFlags & SANDBOXED_ORIGIN) { 1.1292 + rv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.1293 + return; 1.1294 + } 1.1295 + 1.1296 + // not having a cookie service isn't an error 1.1297 + nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID); 1.1298 + if (service && mDocumentURI) { 1.1299 + // The for getting the URI matches nsNavigator::GetCookieEnabled 1.1300 + nsCOMPtr<nsIURI> codebaseURI; 1.1301 + NodePrincipal()->GetURI(getter_AddRefs(codebaseURI)); 1.1302 + 1.1303 + if (!codebaseURI) { 1.1304 + // Document's principal is not a codebase (may be system), so 1.1305 + // can't set cookies 1.1306 + 1.1307 + return; 1.1308 + } 1.1309 + 1.1310 + NS_ConvertUTF16toUTF8 cookie(aCookie); 1.1311 + service->SetCookieString(codebaseURI, nullptr, cookie.get(), mChannel); 1.1312 + } 1.1313 +} 1.1314 + 1.1315 +NS_IMETHODIMP 1.1316 +nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl, 1.1317 + const nsAString& aReplaceOrName, 1.1318 + const nsAString& aFeatures, 1.1319 + JSContext* cx, uint8_t aOptionalArgCount, 1.1320 + nsISupports** aReturn) 1.1321 +{ 1.1322 + // When called with 3 or more arguments, document.open() calls window.open(). 1.1323 + if (aOptionalArgCount > 2) { 1.1324 + ErrorResult rv; 1.1325 + *aReturn = Open(cx, aContentTypeOrUrl, aReplaceOrName, aFeatures, 1.1326 + false, rv).take(); 1.1327 + return rv.ErrorCode(); 1.1328 + } 1.1329 + 1.1330 + nsString type; 1.1331 + if (aOptionalArgCount > 0) { 1.1332 + type = aContentTypeOrUrl; 1.1333 + } else { 1.1334 + type.AssignLiteral("text/html"); 1.1335 + } 1.1336 + nsString replace; 1.1337 + if (aOptionalArgCount > 1) { 1.1338 + replace = aReplaceOrName; 1.1339 + } 1.1340 + ErrorResult rv; 1.1341 + *aReturn = Open(cx, type, replace, rv).take(); 1.1342 + return rv.ErrorCode(); 1.1343 +} 1.1344 + 1.1345 +already_AddRefed<nsIDOMWindow> 1.1346 +nsHTMLDocument::Open(JSContext* /* unused */, 1.1347 + const nsAString& aURL, 1.1348 + const nsAString& aName, 1.1349 + const nsAString& aFeatures, 1.1350 + bool aReplace, 1.1351 + ErrorResult& rv) 1.1352 +{ 1.1353 + NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)), 1.1354 + "XOW should have caught this!"); 1.1355 + 1.1356 + nsCOMPtr<nsIDOMWindow> window = GetInnerWindow(); 1.1357 + if (!window) { 1.1358 + rv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); 1.1359 + return nullptr; 1.1360 + } 1.1361 + nsCOMPtr<nsIDOMJSWindow> win = do_QueryInterface(window); 1.1362 + nsCOMPtr<nsIDOMWindow> newWindow; 1.1363 + // XXXbz We ignore aReplace for now. 1.1364 + rv = win->OpenJS(aURL, aName, aFeatures, getter_AddRefs(newWindow)); 1.1365 + return newWindow.forget(); 1.1366 +} 1.1367 + 1.1368 +already_AddRefed<nsIDocument> 1.1369 +nsHTMLDocument::Open(JSContext* cx, 1.1370 + const nsAString& aType, 1.1371 + const nsAString& aReplace, 1.1372 + ErrorResult& rv) 1.1373 +{ 1.1374 + NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)), 1.1375 + "XOW should have caught this!"); 1.1376 + if (!IsHTML() || mDisableDocWrite) { 1.1377 + // No calling document.open() on XHTML 1.1378 + rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.1379 + return nullptr; 1.1380 + } 1.1381 + 1.1382 + nsAutoCString contentType; 1.1383 + contentType.AssignLiteral("text/html"); 1.1384 + 1.1385 + nsAutoString type; 1.1386 + nsContentUtils::ASCIIToLower(aType, type); 1.1387 + nsAutoCString actualType, dummy; 1.1388 + NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy); 1.1389 + if (!actualType.EqualsLiteral("text/html") && 1.1390 + !type.EqualsLiteral("replace")) { 1.1391 + contentType.AssignLiteral("text/plain"); 1.1392 + } 1.1393 + 1.1394 + // If we already have a parser we ignore the document.open call. 1.1395 + if (mParser || mParserAborted) { 1.1396 + // The WHATWG spec says: "If the document has an active parser that isn't 1.1397 + // a script-created parser, and the insertion point associated with that 1.1398 + // parser's input stream is not undefined (that is, it does point to 1.1399 + // somewhere in the input stream), then the method does nothing. Abort 1.1400 + // these steps and return the Document object on which the method was 1.1401 + // invoked." 1.1402 + // Note that aborting a parser leaves the parser "active" with its 1.1403 + // insertion point "not undefined". We track this using mParserAborted, 1.1404 + // because aborting a parser nulls out mParser. 1.1405 + nsCOMPtr<nsIDocument> ret = this; 1.1406 + return ret.forget(); 1.1407 + } 1.1408 + 1.1409 + // No calling document.open() without a script global object 1.1410 + if (!mScriptGlobalObject) { 1.1411 + nsCOMPtr<nsIDocument> ret = this; 1.1412 + return ret.forget(); 1.1413 + } 1.1414 + 1.1415 + nsPIDOMWindow* outer = GetWindow(); 1.1416 + if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) { 1.1417 + nsCOMPtr<nsIDocument> ret = this; 1.1418 + return ret.forget(); 1.1419 + } 1.1420 + 1.1421 + // check whether we're in the middle of unload. If so, ignore this call. 1.1422 + nsCOMPtr<nsIDocShell> shell(mDocumentContainer); 1.1423 + if (!shell) { 1.1424 + // We won't be able to create a parser anyway. 1.1425 + nsCOMPtr<nsIDocument> ret = this; 1.1426 + return ret.forget(); 1.1427 + } 1.1428 + 1.1429 + bool inUnload; 1.1430 + shell->GetIsInUnload(&inUnload); 1.1431 + if (inUnload) { 1.1432 + nsCOMPtr<nsIDocument> ret = this; 1.1433 + return ret.forget(); 1.1434 + } 1.1435 + 1.1436 + // Note: We want to use GetDocumentFromContext here because this document 1.1437 + // should inherit the security information of the document that's opening us, 1.1438 + // (since if it's secure, then it's presumably trusted). 1.1439 + nsCOMPtr<nsIDocument> callerDoc = nsContentUtils::GetDocumentFromContext(); 1.1440 + if (!callerDoc) { 1.1441 + // If we're called from C++ or in some other way without an originating 1.1442 + // document we can't do a document.open w/o changing the principal of the 1.1443 + // document to something like about:blank (as that's the only sane thing to 1.1444 + // do when we don't know the origin of this call), and since we can't 1.1445 + // change the principals of a document for security reasons we'll have to 1.1446 + // refuse to go ahead with this call. 1.1447 + 1.1448 + rv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.1449 + return nullptr; 1.1450 + } 1.1451 + 1.1452 + // Grab a reference to the calling documents security info (if any) 1.1453 + // and URIs as they may be lost in the call to Reset(). 1.1454 + nsCOMPtr<nsISupports> securityInfo = callerDoc->GetSecurityInfo(); 1.1455 + nsCOMPtr<nsIURI> uri = callerDoc->GetDocumentURI(); 1.1456 + nsCOMPtr<nsIURI> baseURI = callerDoc->GetBaseURI(); 1.1457 + nsCOMPtr<nsIPrincipal> callerPrincipal = callerDoc->NodePrincipal(); 1.1458 + nsCOMPtr<nsIChannel> callerChannel = callerDoc->GetChannel(); 1.1459 + 1.1460 + // We're called from script. Make sure the script is from the same 1.1461 + // origin, not just that the caller can access the document. This is 1.1462 + // needed to keep document principals from ever changing, which is 1.1463 + // needed because of the way we use our XOW code, and is a sane 1.1464 + // thing to do anyways. 1.1465 + 1.1466 + bool equals = false; 1.1467 + if (NS_FAILED(callerPrincipal->Equals(NodePrincipal(), &equals)) || 1.1468 + !equals) { 1.1469 + 1.1470 +#ifdef DEBUG 1.1471 + nsCOMPtr<nsIURI> callerDocURI = callerDoc->GetDocumentURI(); 1.1472 + nsCOMPtr<nsIURI> thisURI = nsIDocument::GetDocumentURI(); 1.1473 + nsAutoCString callerSpec; 1.1474 + nsAutoCString thisSpec; 1.1475 + if (callerDocURI) { 1.1476 + callerDocURI->GetSpec(callerSpec); 1.1477 + } 1.1478 + if (thisURI) { 1.1479 + thisURI->GetSpec(thisSpec); 1.1480 + } 1.1481 + printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get()); 1.1482 +#endif 1.1483 + 1.1484 + rv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.1485 + return nullptr; 1.1486 + } 1.1487 + 1.1488 + // Stop current loads targeted at the window this document is in. 1.1489 + if (mScriptGlobalObject) { 1.1490 + nsCOMPtr<nsIContentViewer> cv; 1.1491 + shell->GetContentViewer(getter_AddRefs(cv)); 1.1492 + 1.1493 + if (cv) { 1.1494 + bool okToUnload; 1.1495 + if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) { 1.1496 + // We don't want to unload, so stop here, but don't throw an 1.1497 + // exception. 1.1498 + nsCOMPtr<nsIDocument> ret = this; 1.1499 + return ret.forget(); 1.1500 + } 1.1501 + } 1.1502 + 1.1503 + nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell)); 1.1504 + webnav->Stop(nsIWebNavigation::STOP_NETWORK); 1.1505 + 1.1506 + // The Stop call may have cancelled the onload blocker request or prevented 1.1507 + // it from getting added, so we need to make sure it gets added to the 1.1508 + // document again otherwise the document could have a non-zero onload block 1.1509 + // count without the onload blocker request being in the loadgroup. 1.1510 + EnsureOnloadBlocker(); 1.1511 + } 1.1512 + 1.1513 + // The open occurred after the document finished loading. 1.1514 + // So we reset the document and create a new one. 1.1515 + nsCOMPtr<nsIChannel> channel; 1.1516 + nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup); 1.1517 + 1.1518 + rv = NS_NewChannel(getter_AddRefs(channel), uri, nullptr, group); 1.1519 + 1.1520 + if (rv.Failed()) { 1.1521 + return nullptr; 1.1522 + } 1.1523 + 1.1524 + // We can't depend on channels implementing property bags, so do our 1.1525 + // base URI manually after reset. 1.1526 + 1.1527 + // Set the caller principal, if any, on the channel so that we'll 1.1528 + // make sure to use it when we reset. 1.1529 + rv = channel->SetOwner(callerPrincipal); 1.1530 + if (rv.Failed()) { 1.1531 + return nullptr; 1.1532 + } 1.1533 + 1.1534 + if (callerChannel) { 1.1535 + nsLoadFlags callerLoadFlags; 1.1536 + rv = callerChannel->GetLoadFlags(&callerLoadFlags); 1.1537 + if (rv.Failed()) { 1.1538 + return nullptr; 1.1539 + } 1.1540 + 1.1541 + nsLoadFlags loadFlags; 1.1542 + rv = channel->GetLoadFlags(&loadFlags); 1.1543 + if (rv.Failed()) { 1.1544 + return nullptr; 1.1545 + } 1.1546 + 1.1547 + loadFlags |= callerLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING; 1.1548 + 1.1549 + rv = channel->SetLoadFlags(loadFlags); 1.1550 + if (rv.Failed()) { 1.1551 + return nullptr; 1.1552 + } 1.1553 + 1.1554 + // If the user has allowed mixed content on the rootDoc, then we should propogate it 1.1555 + // down to the new document channel. 1.1556 + bool rootHasSecureConnection = false; 1.1557 + bool allowMixedContent = false; 1.1558 + bool isDocShellRoot = false; 1.1559 + nsresult rvalue = shell->GetAllowMixedContentAndConnectionData(&rootHasSecureConnection, &allowMixedContent, &isDocShellRoot); 1.1560 + if (NS_SUCCEEDED(rvalue) && allowMixedContent && isDocShellRoot) { 1.1561 + shell->SetMixedContentChannel(channel); 1.1562 + } 1.1563 + } 1.1564 + 1.1565 + // Before we reset the doc notify the globalwindow of the change, 1.1566 + // but only if we still have a window (i.e. our window object the 1.1567 + // current inner window in our outer window). 1.1568 + 1.1569 + // Hold onto ourselves on the offchance that we're down to one ref 1.1570 + nsCOMPtr<nsIDocument> kungFuDeathGrip = this; 1.1571 + 1.1572 + nsPIDOMWindow *window = GetInnerWindow(); 1.1573 + if (window) { 1.1574 + // Remember the old scope in case the call to SetNewDocument changes it. 1.1575 + nsCOMPtr<nsIScriptGlobalObject> oldScope(do_QueryReferent(mScopeObject)); 1.1576 + 1.1577 +#ifdef DEBUG 1.1578 + bool willReparent = mWillReparent; 1.1579 + mWillReparent = true; 1.1580 +#endif 1.1581 + 1.1582 + // Should this pass true for aForceReuseInnerWindow? 1.1583 + rv = window->SetNewDocument(this, nullptr, false); 1.1584 + if (rv.Failed()) { 1.1585 + return nullptr; 1.1586 + } 1.1587 + 1.1588 +#ifdef DEBUG 1.1589 + mWillReparent = willReparent; 1.1590 +#endif 1.1591 + 1.1592 + // Now make sure we're not flagged as the initial document anymore, now 1.1593 + // that we've had stuff done to us. From now on, if anyone tries to 1.1594 + // document.open() us, they get a new inner window. 1.1595 + SetIsInitialDocument(false); 1.1596 + 1.1597 + nsCOMPtr<nsIScriptGlobalObject> newScope(do_QueryReferent(mScopeObject)); 1.1598 + JS::Rooted<JSObject*> wrapper(cx, GetWrapper()); 1.1599 + if (oldScope && newScope != oldScope && wrapper) { 1.1600 + JSAutoCompartment ac(cx, wrapper); 1.1601 + rv = mozilla::dom::ReparentWrapper(cx, wrapper); 1.1602 + if (rv.Failed()) { 1.1603 + return nullptr; 1.1604 + } 1.1605 + nsIXPConnect *xpc = nsContentUtils::XPConnect(); 1.1606 + rv = xpc->RescueOrphansInScope(cx, oldScope->GetGlobalJSObject()); 1.1607 + if (rv.Failed()) { 1.1608 + return nullptr; 1.1609 + } 1.1610 + } 1.1611 + } 1.1612 + 1.1613 + mDidDocumentOpen = true; 1.1614 + 1.1615 + // Call Reset(), this will now do the full reset 1.1616 + Reset(channel, group); 1.1617 + if (baseURI) { 1.1618 + mDocumentBaseURI = baseURI; 1.1619 + } 1.1620 + 1.1621 + // Store the security info of the caller now that we're done 1.1622 + // resetting the document. 1.1623 + mSecurityInfo = securityInfo; 1.1624 + 1.1625 + mParserAborted = false; 1.1626 + mParser = nsHtml5Module::NewHtml5Parser(); 1.1627 + nsHtml5Module::Initialize(mParser, this, uri, shell, channel); 1.1628 + 1.1629 + // This will be propagated to the parser when someone actually calls write() 1.1630 + SetContentTypeInternal(contentType); 1.1631 + 1.1632 + // Prepare the docshell and the document viewer for the impending 1.1633 + // out of band document.write() 1.1634 + shell->PrepareForNewContentModel(); 1.1635 + 1.1636 + // Now check whether we were opened with a "replace" argument. If 1.1637 + // so, we need to tell the docshell to not create a new history 1.1638 + // entry for this load. Otherwise, make sure that we're doing a normal load, 1.1639 + // not whatever type of load was previously done on this docshell. 1.1640 + shell->SetLoadType(aReplace.LowerCaseEqualsLiteral("replace") ? 1.1641 + LOAD_NORMAL_REPLACE : LOAD_NORMAL); 1.1642 + 1.1643 + nsCOMPtr<nsIContentViewer> cv; 1.1644 + shell->GetContentViewer(getter_AddRefs(cv)); 1.1645 + if (cv) { 1.1646 + cv->LoadStart(this); 1.1647 + } 1.1648 + 1.1649 + // Add a wyciwyg channel request into the document load group 1.1650 + NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Open(): wyciwyg " 1.1651 + "channel already exists!"); 1.1652 + 1.1653 + // In case the editor is listening and will see the new channel 1.1654 + // being added, make sure mWriteLevel is non-zero so that the editor 1.1655 + // knows that document.open/write/close() is being called on this 1.1656 + // document. 1.1657 + ++mWriteLevel; 1.1658 + 1.1659 + CreateAndAddWyciwygChannel(); 1.1660 + 1.1661 + --mWriteLevel; 1.1662 + 1.1663 + SetReadyStateInternal(nsIDocument::READYSTATE_LOADING); 1.1664 + 1.1665 + // After changing everything around, make sure that the principal on the 1.1666 + // document's compartment exactly matches NodePrincipal(). 1.1667 + DebugOnly<JSObject*> wrapper = GetWrapperPreserveColor(); 1.1668 + MOZ_ASSERT_IF(wrapper, 1.1669 + JS_GetCompartmentPrincipals(js::GetObjectCompartment(wrapper)) == 1.1670 + nsJSPrincipals::get(NodePrincipal())); 1.1671 + 1.1672 + return kungFuDeathGrip.forget(); 1.1673 +} 1.1674 + 1.1675 +NS_IMETHODIMP 1.1676 +nsHTMLDocument::Clear() 1.1677 +{ 1.1678 + // This method has been deprecated 1.1679 + return NS_OK; 1.1680 +} 1.1681 + 1.1682 +NS_IMETHODIMP 1.1683 +nsHTMLDocument::Close() 1.1684 +{ 1.1685 + ErrorResult rv; 1.1686 + Close(rv); 1.1687 + return rv.ErrorCode(); 1.1688 +} 1.1689 + 1.1690 +void 1.1691 +nsHTMLDocument::Close(ErrorResult& rv) 1.1692 +{ 1.1693 + if (!IsHTML()) { 1.1694 + // No calling document.close() on XHTML! 1.1695 + 1.1696 + rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.1697 + return; 1.1698 + } 1.1699 + 1.1700 + if (!mParser || !mParser->IsScriptCreated()) { 1.1701 + return; 1.1702 + } 1.1703 + 1.1704 + ++mWriteLevel; 1.1705 + rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse( 1.1706 + EmptyString(), nullptr, GetContentTypeInternal(), true); 1.1707 + --mWriteLevel; 1.1708 + 1.1709 + // Even if that Parse() call failed, do the rest of this method 1.1710 + 1.1711 + // XXX Make sure that all the document.written content is 1.1712 + // reflowed. We should remove this call once we change 1.1713 + // nsHTMLDocument::OpenCommon() so that it completely destroys the 1.1714 + // earlier document's content and frame hierarchy. Right now, it 1.1715 + // re-uses the earlier document's root content object and 1.1716 + // corresponding frame objects. These re-used frame objects think 1.1717 + // that they have already been reflowed, so they drop initial 1.1718 + // reflows. For certain cases of document.written content, like a 1.1719 + // frameset document, the dropping of the initial reflow means 1.1720 + // that we end up in document.close() without appended any reflow 1.1721 + // commands to the reflow queue and, consequently, without adding 1.1722 + // the dummy layout request to the load group. Since the dummy 1.1723 + // layout request is not added to the load group, the onload 1.1724 + // handler of the frameset fires before the frames get reflowed 1.1725 + // and loaded. That is the long explanation for why we need this 1.1726 + // one line of code here! 1.1727 + // XXXbz as far as I can tell this may not be needed anymore; all 1.1728 + // the testcases in bug 57636 pass without this line... Leaving 1.1729 + // it be for now, though. In any case, there's no reason to do 1.1730 + // this if we have no presshell, since in that case none of the 1.1731 + // above about reusing frames applies. 1.1732 + // 1.1733 + // XXXhsivonen keeping this around for bug 577508 / 253951 still :-( 1.1734 + if (GetShell()) { 1.1735 + FlushPendingNotifications(Flush_Layout); 1.1736 + } 1.1737 + 1.1738 + // Removing the wyciwygChannel here is wrong when document.close() is 1.1739 + // called from within the document itself. However, legacy requires the 1.1740 + // channel to be removed here. Otherwise, the load event never fires. 1.1741 + NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove " 1.1742 + "nonexistent wyciwyg channel!"); 1.1743 + RemoveWyciwygChannel(); 1.1744 + NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): " 1.1745 + "nsIWyciwygChannel could not be removed!"); 1.1746 +} 1.1747 + 1.1748 +void 1.1749 +nsHTMLDocument::WriteCommon(JSContext *cx, 1.1750 + const Sequence<nsString>& aText, 1.1751 + bool aNewlineTerminate, 1.1752 + mozilla::ErrorResult& rv) 1.1753 +{ 1.1754 + // Fast path the common case 1.1755 + if (aText.Length() == 1) { 1.1756 + rv = WriteCommon(cx, aText[0], aNewlineTerminate); 1.1757 + } else { 1.1758 + // XXXbz it would be nice if we could pass all the strings to the parser 1.1759 + // without having to do all this copying and then ask it to start 1.1760 + // parsing.... 1.1761 + nsString text; 1.1762 + for (uint32_t i = 0; i < aText.Length(); ++i) { 1.1763 + text.Append(aText[i]); 1.1764 + } 1.1765 + rv = WriteCommon(cx, text, aNewlineTerminate); 1.1766 + } 1.1767 +} 1.1768 + 1.1769 +nsresult 1.1770 +nsHTMLDocument::WriteCommon(JSContext *cx, 1.1771 + const nsAString& aText, 1.1772 + bool aNewlineTerminate) 1.1773 +{ 1.1774 + mTooDeepWriteRecursion = 1.1775 + (mWriteLevel > NS_MAX_DOCUMENT_WRITE_DEPTH || mTooDeepWriteRecursion); 1.1776 + NS_ENSURE_STATE(!mTooDeepWriteRecursion); 1.1777 + 1.1778 + if (!IsHTML() || mDisableDocWrite) { 1.1779 + // No calling document.write*() on XHTML! 1.1780 + 1.1781 + return NS_ERROR_DOM_INVALID_STATE_ERR; 1.1782 + } 1.1783 + 1.1784 + if (mParserAborted) { 1.1785 + // Hixie says aborting the parser doesn't undefine the insertion point. 1.1786 + // However, since we null out mParser in that case, we track the 1.1787 + // theoretically defined insertion point using mParserAborted. 1.1788 + return NS_OK; 1.1789 + } 1.1790 + 1.1791 + nsresult rv = NS_OK; 1.1792 + 1.1793 + void *key = GenerateParserKey(); 1.1794 + if (mParser && !mParser->IsInsertionPointDefined()) { 1.1795 + if (mExternalScriptsBeingEvaluated) { 1.1796 + // Instead of implying a call to document.open(), ignore the call. 1.1797 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.1798 + NS_LITERAL_CSTRING("DOM Events"), this, 1.1799 + nsContentUtils::eDOM_PROPERTIES, 1.1800 + "DocumentWriteIgnored", 1.1801 + nullptr, 0, 1.1802 + mDocumentURI); 1.1803 + return NS_OK; 1.1804 + } 1.1805 + mParser->Terminate(); 1.1806 + NS_ASSERTION(!mParser, "mParser should have been null'd out"); 1.1807 + } 1.1808 + 1.1809 + if (!mParser) { 1.1810 + if (mExternalScriptsBeingEvaluated) { 1.1811 + // Instead of implying a call to document.open(), ignore the call. 1.1812 + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, 1.1813 + NS_LITERAL_CSTRING("DOM Events"), this, 1.1814 + nsContentUtils::eDOM_PROPERTIES, 1.1815 + "DocumentWriteIgnored", 1.1816 + nullptr, 0, 1.1817 + mDocumentURI); 1.1818 + return NS_OK; 1.1819 + } 1.1820 + nsCOMPtr<nsISupports> ignored; 1.1821 + rv = Open(NS_LITERAL_STRING("text/html"), EmptyString(), EmptyString(), cx, 1.1822 + 1, getter_AddRefs(ignored)); 1.1823 + 1.1824 + // If Open() fails, or if it didn't create a parser (as it won't 1.1825 + // if the user chose to not discard the current document through 1.1826 + // onbeforeunload), don't write anything. 1.1827 + if (NS_FAILED(rv) || !mParser) { 1.1828 + return rv; 1.1829 + } 1.1830 + NS_ABORT_IF_FALSE(!JS_IsExceptionPending(cx), 1.1831 + "Open() succeeded but JS exception is pending"); 1.1832 + } 1.1833 + 1.1834 + static NS_NAMED_LITERAL_STRING(new_line, "\n"); 1.1835 + 1.1836 + // Save the data in cache if the write isn't from within the doc 1.1837 + if (mWyciwygChannel && !key) { 1.1838 + if (!aText.IsEmpty()) { 1.1839 + mWyciwygChannel->WriteToCacheEntry(aText); 1.1840 + } 1.1841 + 1.1842 + if (aNewlineTerminate) { 1.1843 + mWyciwygChannel->WriteToCacheEntry(new_line); 1.1844 + } 1.1845 + } 1.1846 + 1.1847 + ++mWriteLevel; 1.1848 + 1.1849 + // This could be done with less code, but for performance reasons it 1.1850 + // makes sense to have the code for two separate Parse() calls here 1.1851 + // since the concatenation of strings costs more than we like. And 1.1852 + // why pay that price when we don't need to? 1.1853 + if (aNewlineTerminate) { 1.1854 + rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse( 1.1855 + aText + new_line, key, GetContentTypeInternal(), false); 1.1856 + } else { 1.1857 + rv = (static_cast<nsHtml5Parser*>(mParser.get()))->Parse( 1.1858 + aText, key, GetContentTypeInternal(), false); 1.1859 + } 1.1860 + 1.1861 + --mWriteLevel; 1.1862 + 1.1863 + mTooDeepWriteRecursion = (mWriteLevel != 0 && mTooDeepWriteRecursion); 1.1864 + 1.1865 + return rv; 1.1866 +} 1.1867 + 1.1868 +NS_IMETHODIMP 1.1869 +nsHTMLDocument::Write(const nsAString& aText, JSContext *cx) 1.1870 +{ 1.1871 + return WriteCommon(cx, aText, false); 1.1872 +} 1.1873 + 1.1874 +void 1.1875 +nsHTMLDocument::Write(JSContext* cx, const Sequence<nsString>& aText, 1.1876 + ErrorResult& rv) 1.1877 +{ 1.1878 + WriteCommon(cx, aText, false, rv); 1.1879 +} 1.1880 + 1.1881 +NS_IMETHODIMP 1.1882 +nsHTMLDocument::Writeln(const nsAString& aText, JSContext *cx) 1.1883 +{ 1.1884 + return WriteCommon(cx, aText, true); 1.1885 +} 1.1886 + 1.1887 +void 1.1888 +nsHTMLDocument::Writeln(JSContext* cx, const Sequence<nsString>& aText, 1.1889 + ErrorResult& rv) 1.1890 +{ 1.1891 + WriteCommon(cx, aText, true, rv); 1.1892 +} 1.1893 + 1.1894 +bool 1.1895 +nsHTMLDocument::MatchNameAttribute(nsIContent* aContent, int32_t aNamespaceID, 1.1896 + nsIAtom* aAtom, void* aData) 1.1897 +{ 1.1898 + NS_PRECONDITION(aContent, "Must have content node to work with!"); 1.1899 + nsString* elementName = static_cast<nsString*>(aData); 1.1900 + return 1.1901 + aContent->GetNameSpaceID() == kNameSpaceID_XHTML && 1.1902 + aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, 1.1903 + *elementName, eCaseMatters); 1.1904 +} 1.1905 + 1.1906 +/* static */ 1.1907 +void* 1.1908 +nsHTMLDocument::UseExistingNameString(nsINode* aRootNode, const nsString* aName) 1.1909 +{ 1.1910 + return const_cast<nsString*>(aName); 1.1911 +} 1.1912 + 1.1913 +NS_IMETHODIMP 1.1914 +nsHTMLDocument::GetElementsByName(const nsAString& aElementName, 1.1915 + nsIDOMNodeList** aReturn) 1.1916 +{ 1.1917 + *aReturn = GetElementsByName(aElementName).take(); 1.1918 + return NS_OK; 1.1919 +} 1.1920 + 1.1921 +static bool MatchItems(nsIContent* aContent, int32_t aNameSpaceID, 1.1922 + nsIAtom* aAtom, void* aData) 1.1923 +{ 1.1924 + if (!(aContent->IsElement() && aContent->AsElement()->IsHTML())) { 1.1925 + return false; 1.1926 + } 1.1927 + 1.1928 + nsGenericHTMLElement* elem = static_cast<nsGenericHTMLElement*>(aContent); 1.1929 + if (!elem->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope) || 1.1930 + elem->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) { 1.1931 + return false; 1.1932 + } 1.1933 + 1.1934 + nsTArray<nsCOMPtr<nsIAtom> >* tokens = static_cast<nsTArray<nsCOMPtr<nsIAtom> >*>(aData); 1.1935 + if (tokens->IsEmpty()) { 1.1936 + return true; 1.1937 + } 1.1938 + 1.1939 + const nsAttrValue* attr = elem->GetParsedAttr(nsGkAtoms::itemtype); 1.1940 + if (!attr) 1.1941 + return false; 1.1942 + 1.1943 + for (uint32_t i = 0; i < tokens->Length(); i++) { 1.1944 + if (!attr->Contains(tokens->ElementAt(i), eCaseMatters)) { 1.1945 + return false; 1.1946 + } 1.1947 + } 1.1948 + return true; 1.1949 +} 1.1950 + 1.1951 +static void DestroyTokens(void* aData) 1.1952 +{ 1.1953 + nsTArray<nsCOMPtr<nsIAtom> >* tokens = static_cast<nsTArray<nsCOMPtr<nsIAtom> >*>(aData); 1.1954 + delete tokens; 1.1955 +} 1.1956 + 1.1957 +static void* CreateTokens(nsINode* aRootNode, const nsString* types) 1.1958 +{ 1.1959 + nsTArray<nsCOMPtr<nsIAtom> >* tokens = new nsTArray<nsCOMPtr<nsIAtom> >(); 1.1960 + nsAString::const_iterator iter, end; 1.1961 + types->BeginReading(iter); 1.1962 + types->EndReading(end); 1.1963 + 1.1964 + // skip initial whitespace 1.1965 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1966 + ++iter; 1.1967 + } 1.1968 + 1.1969 + // parse the tokens 1.1970 + while (iter != end) { 1.1971 + nsAString::const_iterator start(iter); 1.1972 + 1.1973 + do { 1.1974 + ++iter; 1.1975 + } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); 1.1976 + 1.1977 + nsCOMPtr<nsIAtom> token = do_GetAtom(Substring(start, iter)); 1.1978 + tokens->AppendElement(token); 1.1979 + 1.1980 + // skip whitespace 1.1981 + while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) { 1.1982 + ++iter; 1.1983 + } 1.1984 + } 1.1985 + return tokens; 1.1986 +} 1.1987 + 1.1988 +NS_IMETHODIMP 1.1989 +nsHTMLDocument::GetItems(const nsAString& types, nsIDOMNodeList** aReturn) 1.1990 +{ 1.1991 + *aReturn = GetItems(types).take(); 1.1992 + return NS_OK; 1.1993 +} 1.1994 + 1.1995 +already_AddRefed<nsINodeList> 1.1996 +nsHTMLDocument::GetItems(const nsAString& aTypeNames) 1.1997 +{ 1.1998 + return NS_GetFuncStringNodeList(this, MatchItems, DestroyTokens, CreateTokens, 1.1999 + aTypeNames); 1.2000 +} 1.2001 + 1.2002 +void 1.2003 +nsHTMLDocument::AddedForm() 1.2004 +{ 1.2005 + ++mNumForms; 1.2006 +} 1.2007 + 1.2008 +void 1.2009 +nsHTMLDocument::RemovedForm() 1.2010 +{ 1.2011 + --mNumForms; 1.2012 +} 1.2013 + 1.2014 +int32_t 1.2015 +nsHTMLDocument::GetNumFormsSynchronous() 1.2016 +{ 1.2017 + return mNumForms; 1.2018 +} 1.2019 + 1.2020 +NS_IMETHODIMP 1.2021 +nsHTMLDocument::GetAlinkColor(nsAString& aAlinkColor) 1.2022 +{ 1.2023 + aAlinkColor.Truncate(); 1.2024 + 1.2025 + HTMLBodyElement* body = GetBodyElement(); 1.2026 + if (body) { 1.2027 + body->GetALink(aAlinkColor); 1.2028 + } 1.2029 + 1.2030 + return NS_OK; 1.2031 +} 1.2032 + 1.2033 +NS_IMETHODIMP 1.2034 +nsHTMLDocument::SetAlinkColor(const nsAString& aAlinkColor) 1.2035 +{ 1.2036 + HTMLBodyElement* body = GetBodyElement(); 1.2037 + if (body) { 1.2038 + body->SetALink(aAlinkColor); 1.2039 + } 1.2040 + 1.2041 + return NS_OK; 1.2042 +} 1.2043 + 1.2044 +NS_IMETHODIMP 1.2045 +nsHTMLDocument::GetLinkColor(nsAString& aLinkColor) 1.2046 +{ 1.2047 + aLinkColor.Truncate(); 1.2048 + 1.2049 + HTMLBodyElement* body = GetBodyElement(); 1.2050 + if (body) { 1.2051 + body->GetLink(aLinkColor); 1.2052 + } 1.2053 + 1.2054 + return NS_OK; 1.2055 +} 1.2056 + 1.2057 +NS_IMETHODIMP 1.2058 +nsHTMLDocument::SetLinkColor(const nsAString& aLinkColor) 1.2059 +{ 1.2060 + HTMLBodyElement* body = GetBodyElement(); 1.2061 + if (body) { 1.2062 + body->SetLink(aLinkColor); 1.2063 + } 1.2064 + 1.2065 + return NS_OK; 1.2066 +} 1.2067 + 1.2068 +NS_IMETHODIMP 1.2069 +nsHTMLDocument::GetVlinkColor(nsAString& aVlinkColor) 1.2070 +{ 1.2071 + aVlinkColor.Truncate(); 1.2072 + 1.2073 + HTMLBodyElement* body = GetBodyElement(); 1.2074 + if (body) { 1.2075 + body->GetVLink(aVlinkColor); 1.2076 + } 1.2077 + 1.2078 + return NS_OK; 1.2079 +} 1.2080 + 1.2081 +NS_IMETHODIMP 1.2082 +nsHTMLDocument::SetVlinkColor(const nsAString& aVlinkColor) 1.2083 +{ 1.2084 + HTMLBodyElement* body = GetBodyElement(); 1.2085 + if (body) { 1.2086 + body->SetVLink(aVlinkColor); 1.2087 + } 1.2088 + 1.2089 + return NS_OK; 1.2090 +} 1.2091 + 1.2092 +NS_IMETHODIMP 1.2093 +nsHTMLDocument::GetBgColor(nsAString& aBgColor) 1.2094 +{ 1.2095 + aBgColor.Truncate(); 1.2096 + 1.2097 + HTMLBodyElement* body = GetBodyElement(); 1.2098 + if (body) { 1.2099 + body->GetBgColor(aBgColor); 1.2100 + } 1.2101 + 1.2102 + return NS_OK; 1.2103 +} 1.2104 + 1.2105 +NS_IMETHODIMP 1.2106 +nsHTMLDocument::SetBgColor(const nsAString& aBgColor) 1.2107 +{ 1.2108 + HTMLBodyElement* body = GetBodyElement(); 1.2109 + if (body) { 1.2110 + body->SetBgColor(aBgColor); 1.2111 + } 1.2112 + 1.2113 + return NS_OK; 1.2114 +} 1.2115 + 1.2116 +NS_IMETHODIMP 1.2117 +nsHTMLDocument::GetFgColor(nsAString& aFgColor) 1.2118 +{ 1.2119 + aFgColor.Truncate(); 1.2120 + 1.2121 + HTMLBodyElement* body = GetBodyElement(); 1.2122 + if (body) { 1.2123 + body->GetText(aFgColor); 1.2124 + } 1.2125 + 1.2126 + return NS_OK; 1.2127 +} 1.2128 + 1.2129 +NS_IMETHODIMP 1.2130 +nsHTMLDocument::SetFgColor(const nsAString& aFgColor) 1.2131 +{ 1.2132 + HTMLBodyElement* body = GetBodyElement(); 1.2133 + if (body) { 1.2134 + body->SetText(aFgColor); 1.2135 + } 1.2136 + 1.2137 + return NS_OK; 1.2138 +} 1.2139 + 1.2140 + 1.2141 +NS_IMETHODIMP 1.2142 +nsHTMLDocument::GetEmbeds(nsIDOMHTMLCollection** aEmbeds) 1.2143 +{ 1.2144 + NS_ADDREF(*aEmbeds = Embeds()); 1.2145 + return NS_OK; 1.2146 +} 1.2147 + 1.2148 +nsIHTMLCollection* 1.2149 +nsHTMLDocument::Embeds() 1.2150 +{ 1.2151 + if (!mEmbeds) { 1.2152 + mEmbeds = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::embed, nsGkAtoms::embed); 1.2153 + } 1.2154 + return mEmbeds; 1.2155 +} 1.2156 + 1.2157 +NS_IMETHODIMP 1.2158 +nsHTMLDocument::GetSelection(nsISelection** aReturn) 1.2159 +{ 1.2160 + ErrorResult rv; 1.2161 + NS_IF_ADDREF(*aReturn = GetSelection(rv)); 1.2162 + return rv.ErrorCode(); 1.2163 +} 1.2164 + 1.2165 +Selection* 1.2166 +nsHTMLDocument::GetSelection(ErrorResult& aRv) 1.2167 +{ 1.2168 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetScopeObject()); 1.2169 + if (!window) { 1.2170 + return nullptr; 1.2171 + } 1.2172 + 1.2173 + NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!"); 1.2174 + if (!window->IsCurrentInnerWindow()) { 1.2175 + return nullptr; 1.2176 + } 1.2177 + 1.2178 + return static_cast<nsGlobalWindow*>(window.get())->GetSelection(aRv); 1.2179 +} 1.2180 + 1.2181 +NS_IMETHODIMP 1.2182 +nsHTMLDocument::CaptureEvents() 1.2183 +{ 1.2184 + WarnOnceAbout(nsIDocument::eUseOfCaptureEvents); 1.2185 + return NS_OK; 1.2186 +} 1.2187 + 1.2188 +NS_IMETHODIMP 1.2189 +nsHTMLDocument::ReleaseEvents() 1.2190 +{ 1.2191 + WarnOnceAbout(nsIDocument::eUseOfReleaseEvents); 1.2192 + return NS_OK; 1.2193 +} 1.2194 + 1.2195 +// Mapped to document.embeds for NS4 compatibility 1.2196 +NS_IMETHODIMP 1.2197 +nsHTMLDocument::GetPlugins(nsIDOMHTMLCollection** aPlugins) 1.2198 +{ 1.2199 + *aPlugins = nullptr; 1.2200 + 1.2201 + return GetEmbeds(aPlugins); 1.2202 +} 1.2203 + 1.2204 +nsIHTMLCollection* 1.2205 +nsHTMLDocument::Plugins() 1.2206 +{ 1.2207 + return Embeds(); 1.2208 +} 1.2209 + 1.2210 +nsISupports* 1.2211 +nsHTMLDocument::ResolveName(const nsAString& aName, nsWrapperCache **aCache) 1.2212 +{ 1.2213 + nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName); 1.2214 + if (!entry) { 1.2215 + *aCache = nullptr; 1.2216 + return nullptr; 1.2217 + } 1.2218 + 1.2219 + nsBaseContentList *list = entry->GetNameContentList(); 1.2220 + uint32_t length = list ? list->Length() : 0; 1.2221 + 1.2222 + if (length > 0) { 1.2223 + if (length == 1) { 1.2224 + // Only one element in the list, return the element instead of returning 1.2225 + // the list. 1.2226 + nsIContent *node = list->Item(0); 1.2227 + *aCache = node; 1.2228 + return node; 1.2229 + } 1.2230 + 1.2231 + // The list contains more than one element, return the whole list. 1.2232 + *aCache = list; 1.2233 + return list; 1.2234 + } 1.2235 + 1.2236 + // No named items were found, see if there's one registerd by id for aName. 1.2237 + Element *e = entry->GetIdElement(); 1.2238 + 1.2239 + if (e && nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(e)) { 1.2240 + *aCache = e; 1.2241 + return e; 1.2242 + } 1.2243 + 1.2244 + *aCache = nullptr; 1.2245 + return nullptr; 1.2246 +} 1.2247 + 1.2248 +void 1.2249 +nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound, 1.2250 + JS::MutableHandle<JSObject*> aRetval, 1.2251 + ErrorResult& rv) 1.2252 +{ 1.2253 + nsWrapperCache* cache; 1.2254 + nsISupports* supp = ResolveName(aName, &cache); 1.2255 + if (!supp) { 1.2256 + aFound = false; 1.2257 + aRetval.set(nullptr); 1.2258 + return; 1.2259 + } 1.2260 + 1.2261 + JS::Rooted<JS::Value> val(cx); 1.2262 + // XXXbz Should we call the (slightly misnamed, really) WrapNativeParent 1.2263 + // here? 1.2264 + if (!dom::WrapObject(cx, supp, cache, nullptr, &val)) { 1.2265 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.2266 + return; 1.2267 + } 1.2268 + aFound = true; 1.2269 + aRetval.set(&val.toObject()); 1.2270 +} 1.2271 + 1.2272 +bool 1.2273 +nsHTMLDocument::NameIsEnumerable(const nsAString& aName) 1.2274 +{ 1.2275 + return true; 1.2276 +} 1.2277 + 1.2278 +static PLDHashOperator 1.2279 +IdentifierMapEntryAddNames(nsIdentifierMapEntry* aEntry, void* aArg) 1.2280 +{ 1.2281 + nsTArray<nsString>* aNames = static_cast<nsTArray<nsString>*>(aArg); 1.2282 + if (aEntry->HasNameElement() || 1.2283 + aEntry->HasIdElementExposedAsHTMLDocumentProperty()) { 1.2284 + aNames->AppendElement(aEntry->GetKey()); 1.2285 + } 1.2286 + return PL_DHASH_NEXT; 1.2287 +} 1.2288 + 1.2289 +void 1.2290 +nsHTMLDocument::GetSupportedNames(unsigned, nsTArray<nsString>& aNames) 1.2291 +{ 1.2292 + mIdentifierMap.EnumerateEntries(IdentifierMapEntryAddNames, &aNames); 1.2293 +} 1.2294 + 1.2295 +//---------------------------- 1.2296 + 1.2297 +// forms related stuff 1.2298 + 1.2299 +NS_IMETHODIMP 1.2300 +nsHTMLDocument::GetForms(nsIDOMHTMLCollection** aForms) 1.2301 +{ 1.2302 + NS_ADDREF(*aForms = nsHTMLDocument::GetForms()); 1.2303 + return NS_OK; 1.2304 +} 1.2305 + 1.2306 +nsContentList* 1.2307 +nsHTMLDocument::GetForms() 1.2308 +{ 1.2309 + if (!mForms) { 1.2310 + mForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form, nsGkAtoms::form); 1.2311 + } 1.2312 + 1.2313 + return mForms; 1.2314 +} 1.2315 + 1.2316 +static bool MatchFormControls(nsIContent* aContent, int32_t aNamespaceID, 1.2317 + nsIAtom* aAtom, void* aData) 1.2318 +{ 1.2319 + return aContent->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL); 1.2320 +} 1.2321 + 1.2322 +nsContentList* 1.2323 +nsHTMLDocument::GetFormControls() 1.2324 +{ 1.2325 + if (!mFormControls) { 1.2326 + mFormControls = new nsContentList(this, MatchFormControls, nullptr, nullptr); 1.2327 + } 1.2328 + 1.2329 + return mFormControls; 1.2330 +} 1.2331 + 1.2332 +nsresult 1.2333 +nsHTMLDocument::CreateAndAddWyciwygChannel(void) 1.2334 +{ 1.2335 + nsresult rv = NS_OK; 1.2336 + nsAutoCString url, originalSpec; 1.2337 + 1.2338 + mDocumentURI->GetSpec(originalSpec); 1.2339 + 1.2340 + // Generate the wyciwyg url 1.2341 + url = NS_LITERAL_CSTRING("wyciwyg://") 1.2342 + + nsPrintfCString("%d", gWyciwygSessionCnt++) 1.2343 + + NS_LITERAL_CSTRING("/") 1.2344 + + originalSpec; 1.2345 + 1.2346 + nsCOMPtr<nsIURI> wcwgURI; 1.2347 + NS_NewURI(getter_AddRefs(wcwgURI), url); 1.2348 + 1.2349 + // Create the nsIWyciwygChannel to store out-of-band 1.2350 + // document.write() script to cache 1.2351 + nsCOMPtr<nsIChannel> channel; 1.2352 + // Create a wyciwyg Channel 1.2353 + rv = NS_NewChannel(getter_AddRefs(channel), wcwgURI); 1.2354 + NS_ENSURE_SUCCESS(rv, rv); 1.2355 + 1.2356 + mWyciwygChannel = do_QueryInterface(channel); 1.2357 + 1.2358 + mWyciwygChannel->SetSecurityInfo(mSecurityInfo); 1.2359 + 1.2360 + // Note: we want to treat this like a "previous document" hint so that, 1.2361 + // e.g. a <meta> tag in the document.write content can override it. 1.2362 + SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc); 1.2363 + mWyciwygChannel->SetCharsetAndSource(kCharsetFromHintPrevDoc, 1.2364 + GetDocumentCharacterSet()); 1.2365 + 1.2366 + // Use our new principal 1.2367 + channel->SetOwner(NodePrincipal()); 1.2368 + 1.2369 + // Inherit load flags from the original document's channel 1.2370 + channel->SetLoadFlags(mLoadFlags); 1.2371 + 1.2372 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.2373 + 1.2374 + // Use the Parent document's loadgroup to trigger load notifications 1.2375 + if (loadGroup && channel) { 1.2376 + rv = channel->SetLoadGroup(loadGroup); 1.2377 + NS_ENSURE_SUCCESS(rv, rv); 1.2378 + 1.2379 + nsLoadFlags loadFlags = 0; 1.2380 + channel->GetLoadFlags(&loadFlags); 1.2381 + loadFlags |= nsIChannel::LOAD_DOCUMENT_URI; 1.2382 + channel->SetLoadFlags(loadFlags); 1.2383 + 1.2384 + channel->SetOriginalURI(wcwgURI); 1.2385 + 1.2386 + rv = loadGroup->AddRequest(mWyciwygChannel, nullptr); 1.2387 + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to add request to load group."); 1.2388 + } 1.2389 + 1.2390 + return rv; 1.2391 +} 1.2392 + 1.2393 +nsresult 1.2394 +nsHTMLDocument::RemoveWyciwygChannel(void) 1.2395 +{ 1.2396 + nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup(); 1.2397 + 1.2398 + // note there can be a write request without a load group if 1.2399 + // this is a synchronously constructed about:blank document 1.2400 + if (loadGroup && mWyciwygChannel) { 1.2401 + mWyciwygChannel->CloseCacheEntry(NS_OK); 1.2402 + loadGroup->RemoveRequest(mWyciwygChannel, nullptr, NS_OK); 1.2403 + } 1.2404 + 1.2405 + mWyciwygChannel = nullptr; 1.2406 + 1.2407 + return NS_OK; 1.2408 +} 1.2409 + 1.2410 +void * 1.2411 +nsHTMLDocument::GenerateParserKey(void) 1.2412 +{ 1.2413 + if (!mScriptLoader) { 1.2414 + // If we don't have a script loader, then the parser probably isn't parsing 1.2415 + // anything anyway, so just return null. 1.2416 + return nullptr; 1.2417 + } 1.2418 + 1.2419 + // The script loader provides us with the currently executing script element, 1.2420 + // which is guaranteed to be unique per script. 1.2421 + nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript(); 1.2422 + if (script && mParser && mParser->IsScriptCreated()) { 1.2423 + nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser(); 1.2424 + if (creatorParser != mParser) { 1.2425 + // Make scripts that aren't inserted by the active parser of this document 1.2426 + // participate in the context of the script that document.open()ed 1.2427 + // this document. 1.2428 + return nullptr; 1.2429 + } 1.2430 + } 1.2431 + return script; 1.2432 +} 1.2433 + 1.2434 +/* attribute DOMString designMode; */ 1.2435 +NS_IMETHODIMP 1.2436 +nsHTMLDocument::GetDesignMode(nsAString & aDesignMode) 1.2437 +{ 1.2438 + if (HasFlag(NODE_IS_EDITABLE)) { 1.2439 + aDesignMode.AssignLiteral("on"); 1.2440 + } 1.2441 + else { 1.2442 + aDesignMode.AssignLiteral("off"); 1.2443 + } 1.2444 + return NS_OK; 1.2445 +} 1.2446 + 1.2447 +void 1.2448 +nsHTMLDocument::MaybeEditingStateChanged() 1.2449 +{ 1.2450 + if (!mPendingMaybeEditingStateChanged && 1.2451 + mUpdateNestLevel == 0 && (mContentEditableCount > 0) != IsEditingOn()) { 1.2452 + if (nsContentUtils::IsSafeToRunScript()) { 1.2453 + EditingStateChanged(); 1.2454 + } else if (!mInDestructor) { 1.2455 + nsContentUtils::AddScriptRunner( 1.2456 + NS_NewRunnableMethod(this, &nsHTMLDocument::MaybeEditingStateChanged)); 1.2457 + } 1.2458 + } 1.2459 +} 1.2460 + 1.2461 +void 1.2462 +nsHTMLDocument::EndUpdate(nsUpdateType aUpdateType) 1.2463 +{ 1.2464 + const bool reset = !mPendingMaybeEditingStateChanged; 1.2465 + mPendingMaybeEditingStateChanged = true; 1.2466 + nsDocument::EndUpdate(aUpdateType); 1.2467 + if (reset) { 1.2468 + mPendingMaybeEditingStateChanged = false; 1.2469 + } 1.2470 + MaybeEditingStateChanged(); 1.2471 +} 1.2472 + 1.2473 + 1.2474 +// Helper class, used below in ChangeContentEditableCount(). 1.2475 +class DeferredContentEditableCountChangeEvent : public nsRunnable 1.2476 +{ 1.2477 +public: 1.2478 + DeferredContentEditableCountChangeEvent(nsHTMLDocument *aDoc, 1.2479 + nsIContent *aElement) 1.2480 + : mDoc(aDoc) 1.2481 + , mElement(aElement) 1.2482 + { 1.2483 + } 1.2484 + 1.2485 + NS_IMETHOD Run() { 1.2486 + if (mElement && mElement->OwnerDoc() == mDoc) { 1.2487 + mDoc->DeferredContentEditableCountChange(mElement); 1.2488 + } 1.2489 + return NS_OK; 1.2490 + } 1.2491 + 1.2492 +private: 1.2493 + nsRefPtr<nsHTMLDocument> mDoc; 1.2494 + nsCOMPtr<nsIContent> mElement; 1.2495 +}; 1.2496 + 1.2497 +nsresult 1.2498 +nsHTMLDocument::ChangeContentEditableCount(nsIContent *aElement, 1.2499 + int32_t aChange) 1.2500 +{ 1.2501 + NS_ASSERTION(int32_t(mContentEditableCount) + aChange >= 0, 1.2502 + "Trying to decrement too much."); 1.2503 + 1.2504 + mContentEditableCount += aChange; 1.2505 + 1.2506 + nsContentUtils::AddScriptRunner( 1.2507 + new DeferredContentEditableCountChangeEvent(this, aElement)); 1.2508 + 1.2509 + return NS_OK; 1.2510 +} 1.2511 + 1.2512 +void 1.2513 +nsHTMLDocument::DeferredContentEditableCountChange(nsIContent *aElement) 1.2514 +{ 1.2515 + if (mParser || 1.2516 + (mUpdateNestLevel > 0 && (mContentEditableCount > 0) != IsEditingOn())) { 1.2517 + return; 1.2518 + } 1.2519 + 1.2520 + EditingState oldState = mEditingState; 1.2521 + 1.2522 + nsresult rv = EditingStateChanged(); 1.2523 + NS_ENSURE_SUCCESS_VOID(rv); 1.2524 + 1.2525 + if (oldState == mEditingState && mEditingState == eContentEditable) { 1.2526 + // We just changed the contentEditable state of a node, we need to reset 1.2527 + // the spellchecking state of that node. 1.2528 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement); 1.2529 + if (node) { 1.2530 + nsPIDOMWindow *window = GetWindow(); 1.2531 + if (!window) 1.2532 + return; 1.2533 + 1.2534 + nsIDocShell *docshell = window->GetDocShell(); 1.2535 + if (!docshell) 1.2536 + return; 1.2537 + 1.2538 + nsCOMPtr<nsIEditor> editor; 1.2539 + docshell->GetEditor(getter_AddRefs(editor)); 1.2540 + if (editor) { 1.2541 + nsRefPtr<nsRange> range = new nsRange(aElement); 1.2542 + rv = range->SelectNode(node); 1.2543 + if (NS_FAILED(rv)) { 1.2544 + // The node might be detached from the document at this point, 1.2545 + // which would cause this call to fail. In this case, we can 1.2546 + // safely ignore the contenteditable count change. 1.2547 + return; 1.2548 + } 1.2549 + 1.2550 + nsCOMPtr<nsIInlineSpellChecker> spellChecker; 1.2551 + rv = editor->GetInlineSpellChecker(false, 1.2552 + getter_AddRefs(spellChecker)); 1.2553 + NS_ENSURE_SUCCESS_VOID(rv); 1.2554 + 1.2555 + if (spellChecker) { 1.2556 + rv = spellChecker->SpellCheckRange(range); 1.2557 + } 1.2558 + } 1.2559 + } 1.2560 + } 1.2561 +} 1.2562 + 1.2563 +HTMLAllCollection* 1.2564 +nsHTMLDocument::All() 1.2565 +{ 1.2566 + if (!mAll) { 1.2567 + mAll = new HTMLAllCollection(this); 1.2568 + } 1.2569 + return mAll; 1.2570 +} 1.2571 + 1.2572 +void 1.2573 +nsHTMLDocument::GetAll(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval, 1.2574 + ErrorResult& aRv) 1.2575 +{ 1.2576 + aRetval.set(All()->GetObject(aCx, aRv)); 1.2577 +} 1.2578 + 1.2579 +static void 1.2580 +NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument) 1.2581 +{ 1.2582 + for (nsIContent* child = aNode->GetFirstChild(); 1.2583 + child; 1.2584 + child = child->GetNextSibling()) { 1.2585 + if (child->IsElement()) { 1.2586 + child->AsElement()->UpdateState(true); 1.2587 + } 1.2588 + NotifyEditableStateChange(child, aDocument); 1.2589 + } 1.2590 +} 1.2591 + 1.2592 +void 1.2593 +nsHTMLDocument::TearingDownEditor(nsIEditor *aEditor) 1.2594 +{ 1.2595 + if (IsEditingOn()) { 1.2596 + EditingState oldState = mEditingState; 1.2597 + mEditingState = eTearingDown; 1.2598 + 1.2599 + nsCOMPtr<nsIPresShell> presShell = GetShell(); 1.2600 + if (!presShell) 1.2601 + return; 1.2602 + 1.2603 + nsCOMArray<nsIStyleSheet> agentSheets; 1.2604 + presShell->GetAgentStyleSheets(agentSheets); 1.2605 + 1.2606 + RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/contenteditable.css")); 1.2607 + if (oldState == eDesignMode) 1.2608 + RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css")); 1.2609 + 1.2610 + presShell->SetAgentStyleSheets(agentSheets); 1.2611 + 1.2612 + presShell->ReconstructStyleData(); 1.2613 + } 1.2614 +} 1.2615 + 1.2616 +nsresult 1.2617 +nsHTMLDocument::TurnEditingOff() 1.2618 +{ 1.2619 + NS_ASSERTION(mEditingState != eOff, "Editing is already off."); 1.2620 + 1.2621 + nsPIDOMWindow *window = GetWindow(); 1.2622 + if (!window) 1.2623 + return NS_ERROR_FAILURE; 1.2624 + 1.2625 + nsIDocShell *docshell = window->GetDocShell(); 1.2626 + if (!docshell) 1.2627 + return NS_ERROR_FAILURE; 1.2628 + 1.2629 + nsresult rv; 1.2630 + nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv); 1.2631 + NS_ENSURE_SUCCESS(rv, rv); 1.2632 + 1.2633 + // turn editing off 1.2634 + rv = editSession->TearDownEditorOnWindow(window); 1.2635 + NS_ENSURE_SUCCESS(rv, rv); 1.2636 + 1.2637 + mEditingState = eOff; 1.2638 + 1.2639 + return NS_OK; 1.2640 +} 1.2641 + 1.2642 +static bool HasPresShell(nsPIDOMWindow *aWindow) 1.2643 +{ 1.2644 + nsIDocShell *docShell = aWindow->GetDocShell(); 1.2645 + if (!docShell) 1.2646 + return false; 1.2647 + return docShell->GetPresShell() != nullptr; 1.2648 +} 1.2649 + 1.2650 +nsresult 1.2651 +nsHTMLDocument::SetEditingState(EditingState aState) 1.2652 +{ 1.2653 + mEditingState = aState; 1.2654 + return NS_OK; 1.2655 +} 1.2656 + 1.2657 +nsresult 1.2658 +nsHTMLDocument::EditingStateChanged() 1.2659 +{ 1.2660 + if (mRemovedFromDocShell) { 1.2661 + return NS_OK; 1.2662 + } 1.2663 + 1.2664 + if (mEditingState == eSettingUp || mEditingState == eTearingDown) { 1.2665 + // XXX We shouldn't recurse. 1.2666 + return NS_OK; 1.2667 + } 1.2668 + 1.2669 + bool designMode = HasFlag(NODE_IS_EDITABLE); 1.2670 + EditingState newState = designMode ? eDesignMode : 1.2671 + (mContentEditableCount > 0 ? eContentEditable : eOff); 1.2672 + if (mEditingState == newState) { 1.2673 + // No changes in editing mode. 1.2674 + return NS_OK; 1.2675 + } 1.2676 + 1.2677 + if (newState == eOff) { 1.2678 + // Editing is being turned off. 1.2679 + nsAutoScriptBlocker scriptBlocker; 1.2680 + NotifyEditableStateChange(this, this); 1.2681 + return TurnEditingOff(); 1.2682 + } 1.2683 + 1.2684 + // Flush out style changes on our _parent_ document, if any, so that 1.2685 + // our check for a presshell won't get stale information. 1.2686 + if (mParentDocument) { 1.2687 + mParentDocument->FlushPendingNotifications(Flush_Style); 1.2688 + } 1.2689 + 1.2690 + // get editing session, make sure this is a strong reference so the 1.2691 + // window can't get deleted during the rest of this call. 1.2692 + nsCOMPtr<nsPIDOMWindow> window = GetWindow(); 1.2693 + if (!window) 1.2694 + return NS_ERROR_FAILURE; 1.2695 + 1.2696 + nsIDocShell *docshell = window->GetDocShell(); 1.2697 + if (!docshell) 1.2698 + return NS_ERROR_FAILURE; 1.2699 + 1.2700 + nsresult rv; 1.2701 + nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv); 1.2702 + NS_ENSURE_SUCCESS(rv, rv); 1.2703 + 1.2704 + nsCOMPtr<nsIEditor> existingEditor; 1.2705 + editSession->GetEditorForWindow(window, getter_AddRefs(existingEditor)); 1.2706 + if (existingEditor) { 1.2707 + // We might already have an editor if it was set up for mail, let's see 1.2708 + // if this is actually the case. 1.2709 + nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(existingEditor); 1.2710 + NS_ABORT_IF_FALSE(htmlEditor, "If we have an editor, it must be an HTML editor"); 1.2711 + uint32_t flags = 0; 1.2712 + existingEditor->GetFlags(&flags); 1.2713 + if (flags & nsIPlaintextEditor::eEditorMailMask) { 1.2714 + // We already have a mail editor, then we should not attempt to create 1.2715 + // another one. 1.2716 + return NS_OK; 1.2717 + } 1.2718 + } 1.2719 + 1.2720 + if (!HasPresShell(window)) { 1.2721 + // We should not make the window editable or setup its editor. 1.2722 + // It's probably style=display:none. 1.2723 + return NS_OK; 1.2724 + } 1.2725 + 1.2726 + bool makeWindowEditable = mEditingState == eOff; 1.2727 + bool updateState = false; 1.2728 + bool spellRecheckAll = false; 1.2729 + nsCOMPtr<nsIEditor> editor; 1.2730 + 1.2731 + { 1.2732 + EditingState oldState = mEditingState; 1.2733 + nsAutoEditingState push(this, eSettingUp); 1.2734 + 1.2735 + if (makeWindowEditable) { 1.2736 + // Editing is being turned on (through designMode or contentEditable) 1.2737 + // Turn on editor. 1.2738 + // XXX This can cause flushing which can change the editing state, so make 1.2739 + // sure to avoid recursing. 1.2740 + rv = editSession->MakeWindowEditable(window, "html", false, false, 1.2741 + true); 1.2742 + NS_ENSURE_SUCCESS(rv, rv); 1.2743 + } 1.2744 + 1.2745 + // XXX Need to call TearDownEditorOnWindow for all failures. 1.2746 + docshell->GetEditor(getter_AddRefs(editor)); 1.2747 + if (!editor) 1.2748 + return NS_ERROR_FAILURE; 1.2749 + 1.2750 + nsCOMPtr<nsIPresShell> presShell = GetShell(); 1.2751 + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); 1.2752 + 1.2753 + // If we're entering the design mode, put the selection at the beginning of 1.2754 + // the document for compatibility reasons. 1.2755 + if (designMode && oldState == eOff) { 1.2756 + editor->BeginningOfDocument(); 1.2757 + } 1.2758 + 1.2759 + nsCOMArray<nsIStyleSheet> agentSheets; 1.2760 + rv = presShell->GetAgentStyleSheets(agentSheets); 1.2761 + NS_ENSURE_SUCCESS(rv, rv); 1.2762 + 1.2763 + nsCOMPtr<nsIURI> uri; 1.2764 + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/contenteditable.css")); 1.2765 + NS_ENSURE_SUCCESS(rv, rv); 1.2766 + 1.2767 + nsRefPtr<nsCSSStyleSheet> sheet; 1.2768 + rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet)); 1.2769 + NS_ENSURE_TRUE(sheet, rv); 1.2770 + 1.2771 + bool result = agentSheets.AppendObject(sheet); 1.2772 + NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY); 1.2773 + 1.2774 + // Should we update the editable state of all the nodes in the document? We 1.2775 + // need to do this when the designMode value changes, as that overrides 1.2776 + // specific states on the elements. 1.2777 + if (designMode) { 1.2778 + // designMode is being turned on (overrides contentEditable). 1.2779 + rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/designmode.css")); 1.2780 + NS_ENSURE_SUCCESS(rv, rv); 1.2781 + 1.2782 + rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet)); 1.2783 + NS_ENSURE_TRUE(sheet, rv); 1.2784 + 1.2785 + result = agentSheets.AppendObject(sheet); 1.2786 + NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY); 1.2787 + 1.2788 + updateState = true; 1.2789 + spellRecheckAll = oldState == eContentEditable; 1.2790 + } 1.2791 + else if (oldState == eDesignMode) { 1.2792 + // designMode is being turned off (contentEditable is still on). 1.2793 + RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css")); 1.2794 + 1.2795 + updateState = true; 1.2796 + } 1.2797 + 1.2798 + rv = presShell->SetAgentStyleSheets(agentSheets); 1.2799 + NS_ENSURE_SUCCESS(rv, rv); 1.2800 + 1.2801 + presShell->ReconstructStyleData(); 1.2802 + } 1.2803 + 1.2804 + mEditingState = newState; 1.2805 + 1.2806 + if (makeWindowEditable) { 1.2807 + // Set the editor to not insert br's on return when in p 1.2808 + // elements by default. 1.2809 + // XXX Do we only want to do this for designMode? 1.2810 + bool unused; 1.2811 + rv = ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), false, 1.2812 + NS_LITERAL_STRING("false"), &unused); 1.2813 + 1.2814 + if (NS_FAILED(rv)) { 1.2815 + // Editor setup failed. Editing is not on after all. 1.2816 + // XXX Should we reset the editable flag on nodes? 1.2817 + editSession->TearDownEditorOnWindow(window); 1.2818 + mEditingState = eOff; 1.2819 + 1.2820 + return rv; 1.2821 + } 1.2822 + } 1.2823 + 1.2824 + if (updateState) { 1.2825 + nsAutoScriptBlocker scriptBlocker; 1.2826 + NotifyEditableStateChange(this, this); 1.2827 + } 1.2828 + 1.2829 + // Resync the editor's spellcheck state. 1.2830 + if (spellRecheckAll) { 1.2831 + nsCOMPtr<nsISelectionController> selcon; 1.2832 + nsresult rv = editor->GetSelectionController(getter_AddRefs(selcon)); 1.2833 + NS_ENSURE_SUCCESS(rv, rv); 1.2834 + 1.2835 + nsCOMPtr<nsISelection> spellCheckSelection; 1.2836 + rv = selcon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK, 1.2837 + getter_AddRefs(spellCheckSelection)); 1.2838 + if (NS_SUCCEEDED(rv)) { 1.2839 + spellCheckSelection->RemoveAllRanges(); 1.2840 + } 1.2841 + } 1.2842 + editor->SyncRealTimeSpell(); 1.2843 + 1.2844 + return NS_OK; 1.2845 +} 1.2846 + 1.2847 +NS_IMETHODIMP 1.2848 +nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode) 1.2849 +{ 1.2850 + ErrorResult rv; 1.2851 + SetDesignMode(aDesignMode, rv); 1.2852 + return rv.ErrorCode(); 1.2853 +} 1.2854 + 1.2855 +void 1.2856 +nsHTMLDocument::SetDesignMode(const nsAString& aDesignMode, ErrorResult& rv) 1.2857 +{ 1.2858 + if (!nsContentUtils::IsCallerChrome()) { 1.2859 + nsCOMPtr<nsIPrincipal> subject; 1.2860 + nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager(); 1.2861 + rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject)); 1.2862 + if (rv.Failed()) { 1.2863 + return; 1.2864 + } 1.2865 + if (subject) { 1.2866 + bool subsumes; 1.2867 + rv = subject->Subsumes(NodePrincipal(), &subsumes); 1.2868 + if (rv.Failed()) { 1.2869 + return; 1.2870 + } 1.2871 + 1.2872 + if (!subsumes) { 1.2873 + rv.Throw(NS_ERROR_DOM_PROP_ACCESS_DENIED); 1.2874 + return; 1.2875 + } 1.2876 + } 1.2877 + } 1.2878 + 1.2879 + bool editableMode = HasFlag(NODE_IS_EDITABLE); 1.2880 + if (aDesignMode.LowerCaseEqualsASCII(editableMode ? "off" : "on")) { 1.2881 + SetEditableFlag(!editableMode); 1.2882 + 1.2883 + rv = EditingStateChanged(); 1.2884 + } 1.2885 +} 1.2886 + 1.2887 +nsresult 1.2888 +nsHTMLDocument::GetMidasCommandManager(nsICommandManager** aCmdMgr) 1.2889 +{ 1.2890 + // initialize return value 1.2891 + NS_ENSURE_ARG_POINTER(aCmdMgr); 1.2892 + 1.2893 + // check if we have it cached 1.2894 + if (mMidasCommandManager) { 1.2895 + NS_ADDREF(*aCmdMgr = mMidasCommandManager); 1.2896 + return NS_OK; 1.2897 + } 1.2898 + 1.2899 + *aCmdMgr = nullptr; 1.2900 + 1.2901 + nsPIDOMWindow *window = GetWindow(); 1.2902 + if (!window) 1.2903 + return NS_ERROR_FAILURE; 1.2904 + 1.2905 + nsIDocShell *docshell = window->GetDocShell(); 1.2906 + if (!docshell) 1.2907 + return NS_ERROR_FAILURE; 1.2908 + 1.2909 + mMidasCommandManager = do_GetInterface(docshell); 1.2910 + if (!mMidasCommandManager) 1.2911 + return NS_ERROR_FAILURE; 1.2912 + 1.2913 + NS_ADDREF(*aCmdMgr = mMidasCommandManager); 1.2914 + 1.2915 + return NS_OK; 1.2916 +} 1.2917 + 1.2918 + 1.2919 +struct MidasCommand { 1.2920 + const char* incomingCommandString; 1.2921 + const char* internalCommandString; 1.2922 + const char* internalParamString; 1.2923 + bool useNewParam; 1.2924 + bool convertToBoolean; 1.2925 +}; 1.2926 + 1.2927 +static const struct MidasCommand gMidasCommandTable[] = { 1.2928 + { "bold", "cmd_bold", "", true, false }, 1.2929 + { "italic", "cmd_italic", "", true, false }, 1.2930 + { "underline", "cmd_underline", "", true, false }, 1.2931 + { "strikethrough", "cmd_strikethrough", "", true, false }, 1.2932 + { "subscript", "cmd_subscript", "", true, false }, 1.2933 + { "superscript", "cmd_superscript", "", true, false }, 1.2934 + { "cut", "cmd_cut", "", true, false }, 1.2935 + { "copy", "cmd_copy", "", true, false }, 1.2936 + { "paste", "cmd_paste", "", true, false }, 1.2937 + { "delete", "cmd_deleteCharBackward", "", true, false }, 1.2938 + { "forwarddelete", "cmd_deleteCharForward", "", true, false }, 1.2939 + { "selectall", "cmd_selectAll", "", true, false }, 1.2940 + { "undo", "cmd_undo", "", true, false }, 1.2941 + { "redo", "cmd_redo", "", true, false }, 1.2942 + { "indent", "cmd_indent", "", true, false }, 1.2943 + { "outdent", "cmd_outdent", "", true, false }, 1.2944 + { "backcolor", "cmd_highlight", "", false, false }, 1.2945 + { "forecolor", "cmd_fontColor", "", false, false }, 1.2946 + { "hilitecolor", "cmd_highlight", "", false, false }, 1.2947 + { "fontname", "cmd_fontFace", "", false, false }, 1.2948 + { "fontsize", "cmd_fontSize", "", false, false }, 1.2949 + { "increasefontsize", "cmd_increaseFont", "", false, false }, 1.2950 + { "decreasefontsize", "cmd_decreaseFont", "", false, false }, 1.2951 + { "inserthorizontalrule", "cmd_insertHR", "", true, false }, 1.2952 + { "createlink", "cmd_insertLinkNoUI", "", false, false }, 1.2953 + { "insertimage", "cmd_insertImageNoUI", "", false, false }, 1.2954 + { "inserthtml", "cmd_insertHTML", "", false, false }, 1.2955 + { "inserttext", "cmd_insertText", "", false, false }, 1.2956 + { "gethtml", "cmd_getContents", "", false, false }, 1.2957 + { "justifyleft", "cmd_align", "left", true, false }, 1.2958 + { "justifyright", "cmd_align", "right", true, false }, 1.2959 + { "justifycenter", "cmd_align", "center", true, false }, 1.2960 + { "justifyfull", "cmd_align", "justify", true, false }, 1.2961 + { "removeformat", "cmd_removeStyles", "", true, false }, 1.2962 + { "unlink", "cmd_removeLinks", "", true, false }, 1.2963 + { "insertorderedlist", "cmd_ol", "", true, false }, 1.2964 + { "insertunorderedlist", "cmd_ul", "", true, false }, 1.2965 + { "insertparagraph", "cmd_paragraphState", "p", true, false }, 1.2966 + { "formatblock", "cmd_paragraphState", "", false, false }, 1.2967 + { "heading", "cmd_paragraphState", "", false, false }, 1.2968 + { "styleWithCSS", "cmd_setDocumentUseCSS", "", false, true }, 1.2969 + { "contentReadOnly", "cmd_setDocumentReadOnly", "", false, true }, 1.2970 + { "insertBrOnReturn", "cmd_insertBrOnReturn", "", false, true }, 1.2971 + { "enableObjectResizing", "cmd_enableObjectResizing", "", false, true }, 1.2972 + { "enableInlineTableEditing", "cmd_enableInlineTableEditing", "", false, true }, 1.2973 +#if 0 1.2974 +// no editor support to remove alignments right now 1.2975 + { "justifynone", "cmd_align", "", true, false }, 1.2976 + 1.2977 +// the following will need special review before being turned on 1.2978 + { "saveas", "cmd_saveAs", "", true, false }, 1.2979 + { "print", "cmd_print", "", true, false }, 1.2980 +#endif 1.2981 + { nullptr, nullptr, nullptr, false, false } 1.2982 +}; 1.2983 + 1.2984 +#define MidasCommandCount ((sizeof(gMidasCommandTable) / sizeof(struct MidasCommand)) - 1) 1.2985 + 1.2986 +static const char* const gBlocks[] = { 1.2987 + "ADDRESS", 1.2988 + "BLOCKQUOTE", 1.2989 + "DD", 1.2990 + "DIV", 1.2991 + "DL", 1.2992 + "DT", 1.2993 + "H1", 1.2994 + "H2", 1.2995 + "H3", 1.2996 + "H4", 1.2997 + "H5", 1.2998 + "H6", 1.2999 + "P", 1.3000 + "PRE" 1.3001 +}; 1.3002 + 1.3003 +static bool 1.3004 +ConvertToMidasInternalCommandInner(const nsAString& inCommandID, 1.3005 + const nsAString& inParam, 1.3006 + nsACString& outCommandID, 1.3007 + nsACString& outParam, 1.3008 + bool& outIsBoolean, 1.3009 + bool& outBooleanValue, 1.3010 + bool aIgnoreParams) 1.3011 +{ 1.3012 + NS_ConvertUTF16toUTF8 convertedCommandID(inCommandID); 1.3013 + 1.3014 + // Hack to support old boolean commands that were backwards (see bug 301490). 1.3015 + bool invertBool = false; 1.3016 + if (convertedCommandID.LowerCaseEqualsLiteral("usecss")) { 1.3017 + convertedCommandID.Assign("styleWithCSS"); 1.3018 + invertBool = true; 1.3019 + } else if (convertedCommandID.LowerCaseEqualsLiteral("readonly")) { 1.3020 + convertedCommandID.Assign("contentReadOnly"); 1.3021 + invertBool = true; 1.3022 + } 1.3023 + 1.3024 + uint32_t i; 1.3025 + bool found = false; 1.3026 + for (i = 0; i < MidasCommandCount; ++i) { 1.3027 + if (convertedCommandID.Equals(gMidasCommandTable[i].incomingCommandString, 1.3028 + nsCaseInsensitiveCStringComparator())) { 1.3029 + found = true; 1.3030 + break; 1.3031 + } 1.3032 + } 1.3033 + 1.3034 + if (!found) { 1.3035 + // reset results if the command is not found in our table 1.3036 + outCommandID.SetLength(0); 1.3037 + outParam.SetLength(0); 1.3038 + outIsBoolean = false; 1.3039 + return false; 1.3040 + } 1.3041 + 1.3042 + // set outCommandID (what we use internally) 1.3043 + outCommandID.Assign(gMidasCommandTable[i].internalCommandString); 1.3044 + 1.3045 + // set outParam & outIsBoolean based on flags from the table 1.3046 + outIsBoolean = gMidasCommandTable[i].convertToBoolean; 1.3047 + 1.3048 + if (aIgnoreParams) { 1.3049 + // No further work to do 1.3050 + return true; 1.3051 + } 1.3052 + 1.3053 + if (gMidasCommandTable[i].useNewParam) { 1.3054 + // Just have to copy it, no checking 1.3055 + outParam.Assign(gMidasCommandTable[i].internalParamString); 1.3056 + return true; 1.3057 + } 1.3058 + 1.3059 + // handle checking of param passed in 1.3060 + if (outIsBoolean) { 1.3061 + // If this is a boolean value and it's not explicitly false (e.g. no value) 1.3062 + // we default to "true". For old backwards commands we invert the check (see 1.3063 + // bug 301490). 1.3064 + if (invertBool) { 1.3065 + outBooleanValue = inParam.LowerCaseEqualsLiteral("false"); 1.3066 + } else { 1.3067 + outBooleanValue = !inParam.LowerCaseEqualsLiteral("false"); 1.3068 + } 1.3069 + outParam.Truncate(); 1.3070 + 1.3071 + return true; 1.3072 + } 1.3073 + 1.3074 + // String parameter -- see if we need to convert it (necessary for 1.3075 + // cmd_paragraphState and cmd_fontSize) 1.3076 + if (outCommandID.EqualsLiteral("cmd_paragraphState")) { 1.3077 + const char16_t* start = inParam.BeginReading(); 1.3078 + const char16_t* end = inParam.EndReading(); 1.3079 + if (start != end && *start == '<' && *(end - 1) == '>') { 1.3080 + ++start; 1.3081 + --end; 1.3082 + } 1.3083 + 1.3084 + NS_ConvertUTF16toUTF8 convertedParam(Substring(start, end)); 1.3085 + uint32_t j; 1.3086 + for (j = 0; j < ArrayLength(gBlocks); ++j) { 1.3087 + if (convertedParam.Equals(gBlocks[j], 1.3088 + nsCaseInsensitiveCStringComparator())) { 1.3089 + outParam.Assign(gBlocks[j]); 1.3090 + break; 1.3091 + } 1.3092 + } 1.3093 + 1.3094 + if (j == ArrayLength(gBlocks)) { 1.3095 + outParam.Truncate(); 1.3096 + } 1.3097 + } else if (outCommandID.EqualsLiteral("cmd_fontSize")) { 1.3098 + // Per editing spec as of April 23, 2012, we need to reject the value if 1.3099 + // it's not a valid floating-point number surrounded by optional whitespace. 1.3100 + // Otherwise, we parse it as a legacy font size. For now, we just parse as 1.3101 + // a legacy font size regardless (matching WebKit) -- bug 747879. 1.3102 + outParam.Truncate(); 1.3103 + int32_t size = nsContentUtils::ParseLegacyFontSize(inParam); 1.3104 + if (size) { 1.3105 + outParam.AppendInt(size); 1.3106 + } 1.3107 + } else { 1.3108 + CopyUTF16toUTF8(inParam, outParam); 1.3109 + } 1.3110 + 1.3111 + return true; 1.3112 +} 1.3113 + 1.3114 +static bool 1.3115 +ConvertToMidasInternalCommand(const nsAString & inCommandID, 1.3116 + const nsAString & inParam, 1.3117 + nsACString& outCommandID, 1.3118 + nsACString& outParam, 1.3119 + bool& outIsBoolean, 1.3120 + bool& outBooleanValue) 1.3121 +{ 1.3122 + return ConvertToMidasInternalCommandInner(inCommandID, inParam, outCommandID, 1.3123 + outParam, outIsBoolean, 1.3124 + outBooleanValue, false); 1.3125 +} 1.3126 + 1.3127 +static bool 1.3128 +ConvertToMidasInternalCommand(const nsAString & inCommandID, 1.3129 + nsACString& outCommandID) 1.3130 +{ 1.3131 + nsAutoCString dummyCString; 1.3132 + nsAutoString dummyString; 1.3133 + bool dummyBool; 1.3134 + return ConvertToMidasInternalCommandInner(inCommandID, dummyString, 1.3135 + outCommandID, dummyCString, 1.3136 + dummyBool, dummyBool, true); 1.3137 +} 1.3138 + 1.3139 +/* TODO: don't let this call do anything if the page is not done loading */ 1.3140 +/* boolean execCommand(in DOMString commandID, in boolean doShowUI, 1.3141 + in DOMString value); */ 1.3142 +NS_IMETHODIMP 1.3143 +nsHTMLDocument::ExecCommand(const nsAString& commandID, 1.3144 + bool doShowUI, 1.3145 + const nsAString& value, 1.3146 + bool* _retval) 1.3147 +{ 1.3148 + ErrorResult rv; 1.3149 + *_retval = ExecCommand(commandID, doShowUI, value, rv); 1.3150 + return rv.ErrorCode(); 1.3151 +} 1.3152 + 1.3153 +bool 1.3154 +nsHTMLDocument::ExecCommand(const nsAString& commandID, 1.3155 + bool doShowUI, 1.3156 + const nsAString& value, 1.3157 + ErrorResult& rv) 1.3158 +{ 1.3159 + // for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go() 1.3160 + // this might add some ugly JS dependencies? 1.3161 + 1.3162 + nsAutoCString cmdToDispatch, paramStr; 1.3163 + bool isBool, boolVal; 1.3164 + if (!ConvertToMidasInternalCommand(commandID, value, 1.3165 + cmdToDispatch, paramStr, 1.3166 + isBool, boolVal)) { 1.3167 + return false; 1.3168 + } 1.3169 + 1.3170 + // if editing is not on, bail 1.3171 + if (!IsEditingOnAfterFlush()) { 1.3172 + rv.Throw(NS_ERROR_FAILURE); 1.3173 + return false; 1.3174 + } 1.3175 + 1.3176 + // if they are requesting UI from us, let's fail since we have no UI 1.3177 + if (doShowUI) { 1.3178 + return false; 1.3179 + } 1.3180 + 1.3181 + if (commandID.LowerCaseEqualsLiteral("gethtml")) { 1.3182 + rv.Throw(NS_ERROR_FAILURE); 1.3183 + return false; 1.3184 + } 1.3185 + 1.3186 + bool restricted = commandID.LowerCaseEqualsLiteral("cut") || 1.3187 + commandID.LowerCaseEqualsLiteral("copy")|| 1.3188 + commandID.LowerCaseEqualsLiteral("paste"); 1.3189 + if (restricted && !nsContentUtils::IsCallerChrome()) { 1.3190 + rv = NS_ERROR_DOM_SECURITY_ERR; 1.3191 + return false; 1.3192 + } 1.3193 + 1.3194 + // get command manager and dispatch command to our window if it's acceptable 1.3195 + nsCOMPtr<nsICommandManager> cmdMgr; 1.3196 + GetMidasCommandManager(getter_AddRefs(cmdMgr)); 1.3197 + if (!cmdMgr) { 1.3198 + rv.Throw(NS_ERROR_FAILURE); 1.3199 + return false; 1.3200 + } 1.3201 + 1.3202 + nsIDOMWindow* window = GetWindow(); 1.3203 + if (!window) { 1.3204 + rv.Throw(NS_ERROR_FAILURE); 1.3205 + return false; 1.3206 + } 1.3207 + 1.3208 + if ((cmdToDispatch.EqualsLiteral("cmd_fontSize") || 1.3209 + cmdToDispatch.EqualsLiteral("cmd_insertImageNoUI") || 1.3210 + cmdToDispatch.EqualsLiteral("cmd_insertLinkNoUI") || 1.3211 + cmdToDispatch.EqualsLiteral("cmd_paragraphState")) && 1.3212 + paramStr.IsEmpty()) { 1.3213 + // Invalid value, return false 1.3214 + return false; 1.3215 + } 1.3216 + 1.3217 + // Return false for disabled commands (bug 760052) 1.3218 + bool enabled = false; 1.3219 + cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, &enabled); 1.3220 + if (!enabled) { 1.3221 + return false; 1.3222 + } 1.3223 + 1.3224 + if (!isBool && paramStr.IsEmpty()) { 1.3225 + rv = cmdMgr->DoCommand(cmdToDispatch.get(), nullptr, window); 1.3226 + } else { 1.3227 + // we have a command that requires a parameter, create params 1.3228 + nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance( 1.3229 + NS_COMMAND_PARAMS_CONTRACTID); 1.3230 + if (!cmdParams) { 1.3231 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.3232 + return false; 1.3233 + } 1.3234 + 1.3235 + if (isBool) { 1.3236 + rv = cmdParams->SetBooleanValue("state_attribute", boolVal); 1.3237 + } else if (cmdToDispatch.EqualsLiteral("cmd_fontFace")) { 1.3238 + rv = cmdParams->SetStringValue("state_attribute", value); 1.3239 + } else if (cmdToDispatch.EqualsLiteral("cmd_insertHTML") || 1.3240 + cmdToDispatch.EqualsLiteral("cmd_insertText")) { 1.3241 + rv = cmdParams->SetStringValue("state_data", value); 1.3242 + } else { 1.3243 + rv = cmdParams->SetCStringValue("state_attribute", paramStr.get()); 1.3244 + } 1.3245 + if (rv.Failed()) { 1.3246 + return false; 1.3247 + } 1.3248 + rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window); 1.3249 + } 1.3250 + 1.3251 + return !rv.Failed(); 1.3252 +} 1.3253 + 1.3254 +/* boolean queryCommandEnabled(in DOMString commandID); */ 1.3255 +NS_IMETHODIMP 1.3256 +nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, 1.3257 + bool* _retval) 1.3258 +{ 1.3259 + ErrorResult rv; 1.3260 + *_retval = QueryCommandEnabled(commandID, rv); 1.3261 + return rv.ErrorCode(); 1.3262 +} 1.3263 + 1.3264 +bool 1.3265 +nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, ErrorResult& rv) 1.3266 +{ 1.3267 + nsAutoCString cmdToDispatch; 1.3268 + if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) { 1.3269 + return false; 1.3270 + } 1.3271 + 1.3272 + // if editing is not on, bail 1.3273 + if (!IsEditingOnAfterFlush()) { 1.3274 + rv.Throw(NS_ERROR_FAILURE); 1.3275 + return false; 1.3276 + } 1.3277 + 1.3278 + // get command manager and dispatch command to our window if it's acceptable 1.3279 + nsCOMPtr<nsICommandManager> cmdMgr; 1.3280 + GetMidasCommandManager(getter_AddRefs(cmdMgr)); 1.3281 + if (!cmdMgr) { 1.3282 + rv.Throw(NS_ERROR_FAILURE); 1.3283 + return false; 1.3284 + } 1.3285 + 1.3286 + nsIDOMWindow* window = GetWindow(); 1.3287 + if (!window) { 1.3288 + rv.Throw(NS_ERROR_FAILURE); 1.3289 + return false; 1.3290 + } 1.3291 + 1.3292 + bool retval; 1.3293 + rv = cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, &retval); 1.3294 + return retval; 1.3295 +} 1.3296 + 1.3297 +/* boolean queryCommandIndeterm (in DOMString commandID); */ 1.3298 +NS_IMETHODIMP 1.3299 +nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID, 1.3300 + bool *_retval) 1.3301 +{ 1.3302 + ErrorResult rv; 1.3303 + *_retval = QueryCommandIndeterm(commandID, rv); 1.3304 + return rv.ErrorCode(); 1.3305 +} 1.3306 + 1.3307 +bool 1.3308 +nsHTMLDocument::QueryCommandIndeterm(const nsAString& commandID, ErrorResult& rv) 1.3309 +{ 1.3310 + nsAutoCString cmdToDispatch; 1.3311 + if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) { 1.3312 + return false; 1.3313 + } 1.3314 + 1.3315 + // if editing is not on, bail 1.3316 + if (!IsEditingOnAfterFlush()) { 1.3317 + rv.Throw(NS_ERROR_FAILURE); 1.3318 + return false; 1.3319 + } 1.3320 + 1.3321 + // get command manager and dispatch command to our window if it's acceptable 1.3322 + nsCOMPtr<nsICommandManager> cmdMgr; 1.3323 + GetMidasCommandManager(getter_AddRefs(cmdMgr)); 1.3324 + if (!cmdMgr) { 1.3325 + rv.Throw(NS_ERROR_FAILURE); 1.3326 + return false; 1.3327 + } 1.3328 + 1.3329 + nsIDOMWindow* window = GetWindow(); 1.3330 + if (!window) { 1.3331 + rv.Throw(NS_ERROR_FAILURE); 1.3332 + return false; 1.3333 + } 1.3334 + 1.3335 + nsresult res; 1.3336 + nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance( 1.3337 + NS_COMMAND_PARAMS_CONTRACTID, &res); 1.3338 + if (NS_FAILED(res)) { 1.3339 + rv.Throw(res); 1.3340 + return false; 1.3341 + } 1.3342 + 1.3343 + rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams); 1.3344 + if (rv.Failed()) { 1.3345 + return false; 1.3346 + } 1.3347 + 1.3348 + // If command does not have a state_mixed value, this call fails and sets 1.3349 + // retval to false. This is fine -- we want to return false in that case 1.3350 + // anyway (bug 738385), so we just don't throw regardless. 1.3351 + bool retval = false; 1.3352 + cmdParams->GetBooleanValue("state_mixed", &retval); 1.3353 + return retval; 1.3354 +} 1.3355 + 1.3356 +/* boolean queryCommandState(in DOMString commandID); */ 1.3357 +NS_IMETHODIMP 1.3358 +nsHTMLDocument::QueryCommandState(const nsAString & commandID, bool *_retval) 1.3359 +{ 1.3360 + ErrorResult rv; 1.3361 + *_retval = QueryCommandState(commandID, rv); 1.3362 + return rv.ErrorCode(); 1.3363 +} 1.3364 + 1.3365 +bool 1.3366 +nsHTMLDocument::QueryCommandState(const nsAString& commandID, ErrorResult& rv) 1.3367 +{ 1.3368 + nsAutoCString cmdToDispatch, paramToCheck; 1.3369 + bool dummy, dummy2; 1.3370 + if (!ConvertToMidasInternalCommand(commandID, commandID, 1.3371 + cmdToDispatch, paramToCheck, 1.3372 + dummy, dummy2)) { 1.3373 + return false; 1.3374 + } 1.3375 + 1.3376 + // if editing is not on, bail 1.3377 + if (!IsEditingOnAfterFlush()) { 1.3378 + rv.Throw(NS_ERROR_FAILURE); 1.3379 + return false; 1.3380 + } 1.3381 + 1.3382 + // get command manager and dispatch command to our window if it's acceptable 1.3383 + nsCOMPtr<nsICommandManager> cmdMgr; 1.3384 + GetMidasCommandManager(getter_AddRefs(cmdMgr)); 1.3385 + if (!cmdMgr) { 1.3386 + rv.Throw(NS_ERROR_FAILURE); 1.3387 + return false; 1.3388 + } 1.3389 + 1.3390 + nsIDOMWindow* window = GetWindow(); 1.3391 + if (!window) { 1.3392 + rv.Throw(NS_ERROR_FAILURE); 1.3393 + return false; 1.3394 + } 1.3395 + 1.3396 + if (commandID.LowerCaseEqualsLiteral("usecss")) { 1.3397 + // Per spec, state is supported for styleWithCSS but not useCSS, so we just 1.3398 + // return false always. 1.3399 + return false; 1.3400 + } 1.3401 + 1.3402 + nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance( 1.3403 + NS_COMMAND_PARAMS_CONTRACTID); 1.3404 + if (!cmdParams) { 1.3405 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.3406 + return false; 1.3407 + } 1.3408 + 1.3409 + rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams); 1.3410 + if (rv.Failed()) { 1.3411 + return false; 1.3412 + } 1.3413 + 1.3414 + // handle alignment as a special case (possibly other commands too?) 1.3415 + // Alignment is special because the external api is individual 1.3416 + // commands but internally we use cmd_align with different 1.3417 + // parameters. When getting the state of this command, we need to 1.3418 + // return the boolean for this particular alignment rather than the 1.3419 + // string of 'which alignment is this?' 1.3420 + if (cmdToDispatch.EqualsLiteral("cmd_align")) { 1.3421 + char * actualAlignmentType = nullptr; 1.3422 + rv = cmdParams->GetCStringValue("state_attribute", &actualAlignmentType); 1.3423 + bool retval = false; 1.3424 + if (!rv.Failed() && actualAlignmentType && actualAlignmentType[0]) { 1.3425 + retval = paramToCheck.Equals(actualAlignmentType); 1.3426 + } 1.3427 + if (actualAlignmentType) { 1.3428 + nsMemory::Free(actualAlignmentType); 1.3429 + } 1.3430 + return retval; 1.3431 + } 1.3432 + 1.3433 + // If command does not have a state_all value, this call fails and sets 1.3434 + // retval to false. This is fine -- we want to return false in that case 1.3435 + // anyway (bug 738385), so we just succeed and return false regardless. 1.3436 + bool retval = false; 1.3437 + cmdParams->GetBooleanValue("state_all", &retval); 1.3438 + return retval; 1.3439 +} 1.3440 + 1.3441 +/* boolean queryCommandSupported(in DOMString commandID); */ 1.3442 +NS_IMETHODIMP 1.3443 +nsHTMLDocument::QueryCommandSupported(const nsAString & commandID, 1.3444 + bool *_retval) 1.3445 +{ 1.3446 + *_retval = QueryCommandSupported(commandID); 1.3447 + return NS_OK; 1.3448 +} 1.3449 + 1.3450 +bool 1.3451 +nsHTMLDocument::QueryCommandSupported(const nsAString& commandID) 1.3452 +{ 1.3453 + // commandID is supported if it can be converted to a Midas command 1.3454 + nsAutoCString cmdToDispatch; 1.3455 + return ConvertToMidasInternalCommand(commandID, cmdToDispatch); 1.3456 +} 1.3457 + 1.3458 +/* DOMString queryCommandValue(in DOMString commandID); */ 1.3459 +NS_IMETHODIMP 1.3460 +nsHTMLDocument::QueryCommandValue(const nsAString & commandID, 1.3461 + nsAString &_retval) 1.3462 +{ 1.3463 + ErrorResult rv; 1.3464 + QueryCommandValue(commandID, _retval, rv); 1.3465 + return rv.ErrorCode(); 1.3466 +} 1.3467 + 1.3468 +void 1.3469 +nsHTMLDocument::QueryCommandValue(const nsAString& commandID, 1.3470 + nsAString& aValue, 1.3471 + ErrorResult& rv) 1.3472 +{ 1.3473 + aValue.Truncate(); 1.3474 + 1.3475 + nsAutoCString cmdToDispatch, paramStr; 1.3476 + if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) { 1.3477 + // Return empty string 1.3478 + return; 1.3479 + } 1.3480 + 1.3481 + // if editing is not on, bail 1.3482 + if (!IsEditingOnAfterFlush()) { 1.3483 + rv.Throw(NS_ERROR_FAILURE); 1.3484 + return; 1.3485 + } 1.3486 + 1.3487 + // get command manager and dispatch command to our window if it's acceptable 1.3488 + nsCOMPtr<nsICommandManager> cmdMgr; 1.3489 + GetMidasCommandManager(getter_AddRefs(cmdMgr)); 1.3490 + if (!cmdMgr) { 1.3491 + rv.Throw(NS_ERROR_FAILURE); 1.3492 + return; 1.3493 + } 1.3494 + 1.3495 + nsIDOMWindow* window = GetWindow(); 1.3496 + if (!window) { 1.3497 + rv.Throw(NS_ERROR_FAILURE); 1.3498 + return; 1.3499 + } 1.3500 + 1.3501 + // create params 1.3502 + nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance( 1.3503 + NS_COMMAND_PARAMS_CONTRACTID); 1.3504 + if (!cmdParams) { 1.3505 + rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.3506 + return; 1.3507 + } 1.3508 + 1.3509 + // this is a special command since we are calling DoCommand rather than 1.3510 + // GetCommandState like the other commands 1.3511 + if (cmdToDispatch.EqualsLiteral("cmd_getContents")) { 1.3512 + rv = cmdParams->SetBooleanValue("selection_only", true); 1.3513 + if (rv.Failed()) { 1.3514 + return; 1.3515 + } 1.3516 + rv = cmdParams->SetCStringValue("format", "text/html"); 1.3517 + if (rv.Failed()) { 1.3518 + return; 1.3519 + } 1.3520 + rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window); 1.3521 + if (rv.Failed()) { 1.3522 + return; 1.3523 + } 1.3524 + rv = cmdParams->GetStringValue("result", aValue); 1.3525 + return; 1.3526 + } 1.3527 + 1.3528 + rv = cmdParams->SetCStringValue("state_attribute", paramStr.get()); 1.3529 + if (rv.Failed()) { 1.3530 + return; 1.3531 + } 1.3532 + 1.3533 + rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams); 1.3534 + if (rv.Failed()) { 1.3535 + return; 1.3536 + } 1.3537 + 1.3538 + // If command does not have a state_attribute value, this call fails, and 1.3539 + // aValue will wind up being the empty string. This is fine -- we want to 1.3540 + // return "" in that case anyway (bug 738385), so we just return NS_OK 1.3541 + // regardless. 1.3542 + nsXPIDLCString cStringResult; 1.3543 + cmdParams->GetCStringValue("state_attribute", 1.3544 + getter_Copies(cStringResult)); 1.3545 + CopyUTF8toUTF16(cStringResult, aValue); 1.3546 +} 1.3547 + 1.3548 +nsresult 1.3549 +nsHTMLDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const 1.3550 +{ 1.3551 + NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager, 1.3552 + "Can't import this document into another document!"); 1.3553 + 1.3554 + nsRefPtr<nsHTMLDocument> clone = new nsHTMLDocument(); 1.3555 + nsresult rv = CloneDocHelper(clone.get()); 1.3556 + NS_ENSURE_SUCCESS(rv, rv); 1.3557 + 1.3558 + // State from nsHTMLDocument 1.3559 + clone->mLoadFlags = mLoadFlags; 1.3560 + 1.3561 + return CallQueryInterface(clone.get(), aResult); 1.3562 +} 1.3563 + 1.3564 +bool 1.3565 +nsHTMLDocument::IsEditingOnAfterFlush() 1.3566 +{ 1.3567 + nsIDocument* doc = GetParentDocument(); 1.3568 + if (doc) { 1.3569 + // Make sure frames are up to date, since that can affect whether 1.3570 + // we're editable. 1.3571 + doc->FlushPendingNotifications(Flush_Frames); 1.3572 + } 1.3573 + 1.3574 + return IsEditingOn(); 1.3575 +} 1.3576 + 1.3577 +void 1.3578 +nsHTMLDocument::RemovedFromDocShell() 1.3579 +{ 1.3580 + mEditingState = eOff; 1.3581 + nsDocument::RemovedFromDocShell(); 1.3582 +} 1.3583 + 1.3584 +/* virtual */ void 1.3585 +nsHTMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const 1.3586 +{ 1.3587 + nsDocument::DocAddSizeOfExcludingThis(aWindowSizes); 1.3588 + 1.3589 + // Measurement of the following members may be added later if DMD finds it is 1.3590 + // worthwhile: 1.3591 + // - mImages 1.3592 + // - mApplets 1.3593 + // - mEmbeds 1.3594 + // - mLinks 1.3595 + // - mAnchors 1.3596 + // - mScripts 1.3597 + // - mForms 1.3598 + // - mFormControls 1.3599 + // - mWyciwygChannel 1.3600 + // - mMidasCommandManager 1.3601 +} 1.3602 + 1.3603 +bool 1.3604 +nsHTMLDocument::WillIgnoreCharsetOverride() 1.3605 +{ 1.3606 + if (!mIsRegularHTML) { 1.3607 + return true; 1.3608 + } 1.3609 + if (mCharacterSetSource == kCharsetFromByteOrderMark) { 1.3610 + return true; 1.3611 + } 1.3612 + if (!EncodingUtils::IsAsciiCompatible(mCharacterSet)) { 1.3613 + return true; 1.3614 + } 1.3615 + nsCOMPtr<nsIWyciwygChannel> wyciwyg = do_QueryInterface(mChannel); 1.3616 + if (wyciwyg) { 1.3617 + return true; 1.3618 + } 1.3619 + nsIURI* uri = GetOriginalURI(); 1.3620 + if (uri) { 1.3621 + bool schemeIs = false; 1.3622 + uri->SchemeIs("about", &schemeIs); 1.3623 + if (schemeIs) { 1.3624 + return true; 1.3625 + } 1.3626 + bool isResource; 1.3627 + nsresult rv = NS_URIChainHasFlags(uri, 1.3628 + nsIProtocolHandler::URI_IS_UI_RESOURCE, 1.3629 + &isResource); 1.3630 + if (NS_FAILED(rv) || isResource) { 1.3631 + return true; 1.3632 + } 1.3633 + } 1.3634 + return false; 1.3635 +}