content/html/document/src/nsHTMLDocument.cpp

changeset 0
6474c204b198
     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 +}

mercurial