1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=2 et tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : * Kathleen Brade <brade@netscape.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "mozilla/Util.h"
42 :
43 : #include "nsCOMPtr.h"
44 : #include "nsXPIDLString.h"
45 : #include "nsPrintfCString.h"
46 : #include "nsReadableUtils.h"
47 : #include "nsUnicharUtils.h"
48 : #include "nsHTMLDocument.h"
49 : #include "nsIHTMLContentSink.h"
50 : #include "nsIXMLContentSink.h"
51 : #include "nsHTMLParts.h"
52 : #include "nsHTMLStyleSheet.h"
53 : #include "nsGkAtoms.h"
54 : #include "nsIPresShell.h"
55 : #include "nsPresContext.h"
56 : #include "nsIDOMNode.h" // for Find
57 : #include "nsIDOMNodeList.h"
58 : #include "nsIDOMElement.h"
59 : #include "nsPIDOMWindow.h"
60 : #include "nsDOMString.h"
61 : #include "nsIStreamListener.h"
62 : #include "nsIURI.h"
63 : #include "nsIIOService.h"
64 : #include "nsNetUtil.h"
65 : #include "nsIContentViewerContainer.h"
66 : #include "nsIContentViewer.h"
67 : #include "nsIMarkupDocumentViewer.h"
68 : #include "nsIDocShell.h"
69 : #include "nsIDocShellTreeItem.h"
70 : #include "nsDocShellLoadTypes.h"
71 : #include "nsIWebNavigation.h"
72 : #include "nsIBaseWindow.h"
73 : #include "nsIWebShellServices.h"
74 : #include "nsIScriptContext.h"
75 : #include "nsIXPConnect.h"
76 : #include "nsContentList.h"
77 : #include "nsDOMError.h"
78 : #include "nsIPrincipal.h"
79 : #include "nsIScriptSecurityManager.h"
80 : #include "nsAttrName.h"
81 : #include "nsNodeUtils.h"
82 :
83 : #include "nsNetCID.h"
84 : #include "nsIIOService.h"
85 : #include "nsICookieService.h"
86 :
87 : #include "nsIServiceManager.h"
88 : #include "nsIConsoleService.h"
89 : #include "nsIComponentManager.h"
90 : #include "nsParserCIID.h"
91 : #include "nsIDOMHTMLElement.h"
92 : #include "nsIDOMHTMLBodyElement.h"
93 : #include "nsIDOMHTMLHeadElement.h"
94 : #include "nsINameSpaceManager.h"
95 : #include "nsGenericHTMLElement.h"
96 : #include "mozilla/css/Loader.h"
97 : #include "nsIHttpChannel.h"
98 : #include "nsIFile.h"
99 : #include "nsEventListenerManager.h"
100 : #include "nsFrameSelection.h"
101 : #include "nsISelectionPrivate.h"//for toStringwithformat code
102 :
103 : #include "nsContentUtils.h"
104 : #include "nsJSUtils.h"
105 : #include "nsIDocumentEncoder.h" //for outputting selection
106 : #include "nsICachingChannel.h"
107 : #include "nsIJSContextStack.h"
108 : #include "nsIContentViewer.h"
109 : #include "nsIWyciwygChannel.h"
110 : #include "nsIScriptElement.h"
111 : #include "nsIScriptError.h"
112 : #include "nsIMutableArray.h"
113 : #include "nsArrayUtils.h"
114 : #include "nsIEffectiveTLDService.h"
115 :
116 : #include "nsIPrompt.h"
117 : //AHMED 12-2
118 : #include "nsBidiUtils.h"
119 :
120 : #include "nsIEditingSession.h"
121 : #include "nsIEditor.h"
122 : #include "nsNodeInfoManager.h"
123 : #include "nsIPlaintextEditor.h"
124 : #include "nsIHTMLEditor.h"
125 : #include "nsIEditorDocShell.h"
126 : #include "nsIEditorStyleSheets.h"
127 : #include "nsIInlineSpellChecker.h"
128 : #include "nsRange.h"
129 : #include "mozAutoDocUpdate.h"
130 : #include "nsCCUncollectableMarker.h"
131 : #include "nsHtml5Module.h"
132 : #include "prprf.h"
133 : #include "mozilla/dom/Element.h"
134 : #include "mozilla/Preferences.h"
135 : #include "nsMimeTypes.h"
136 : #include "nsIRequest.h"
137 :
138 : using namespace mozilla;
139 : using namespace mozilla::dom;
140 :
141 : #define NS_MAX_DOCUMENT_WRITE_DEPTH 20
142 :
143 : #include "prmem.h"
144 : #include "prtime.h"
145 :
146 : // Find/Search Includes
147 : const PRInt32 kForward = 0;
148 : const PRInt32 kBackward = 1;
149 :
150 : //#define DEBUG_charset
151 :
152 : static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
153 :
154 : PRUint32 nsHTMLDocument::gWyciwygSessionCnt = 0;
155 :
156 : // this function will return false if the command is not recognized
157 : // inCommandID will be converted as necessary for internal operations
158 : // inParam will be converted as necessary for internal operations
159 : // outParam will be Empty if no parameter is needed or if returning a boolean
160 : // outIsBoolean will determine whether to send param as a boolean or string
161 : // outBooleanParam will not be set unless outIsBoolean
162 : static bool ConvertToMidasInternalCommand(const nsAString & inCommandID,
163 : const nsAString & inParam,
164 : nsACString& outCommandID,
165 : nsACString& outParam,
166 : bool& isBoolean,
167 : bool& boolValue);
168 :
169 : static bool ConvertToMidasInternalCommand(const nsAString & inCommandID,
170 : nsACString& outCommandID);
171 :
172 : // ==================================================================
173 : // =
174 : // ==================================================================
175 : static void
176 0 : ReportUseOfDeprecatedMethod(nsHTMLDocument* aDoc, const char* aWarning)
177 : {
178 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
179 : "DOM Events", aDoc,
180 : nsContentUtils::eDOM_PROPERTIES,
181 0 : aWarning);
182 0 : }
183 :
184 : static nsresult
185 0 : RemoveFromAgentSheets(nsCOMArray<nsIStyleSheet> &aAgentSheets, const nsAString& url)
186 : {
187 0 : nsCOMPtr<nsIURI> uri;
188 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
189 0 : NS_ENSURE_SUCCESS(rv, rv);
190 :
191 0 : for (PRInt32 i = aAgentSheets.Count() - 1; i >= 0; --i) {
192 0 : nsIStyleSheet* sheet = aAgentSheets[i];
193 0 : nsIURI* sheetURI = sheet->GetSheetURI();
194 :
195 0 : bool equals = false;
196 0 : uri->Equals(sheetURI, &equals);
197 0 : if (equals) {
198 0 : aAgentSheets.RemoveObjectAt(i);
199 : }
200 : }
201 :
202 0 : return NS_OK;
203 : }
204 :
205 : nsresult
206 234 : NS_NewHTMLDocument(nsIDocument** aInstancePtrResult)
207 : {
208 234 : nsHTMLDocument* doc = new nsHTMLDocument();
209 234 : NS_ENSURE_TRUE(doc, NS_ERROR_OUT_OF_MEMORY);
210 :
211 234 : NS_ADDREF(doc);
212 234 : nsresult rv = doc->Init();
213 :
214 234 : if (NS_FAILED(rv)) {
215 0 : NS_RELEASE(doc);
216 : }
217 :
218 234 : *aInstancePtrResult = doc;
219 :
220 234 : return rv;
221 : }
222 :
223 : // NOTE! nsDocument::operator new() zeroes out all members, so don't
224 : // bother initializing members to 0.
225 :
226 234 : nsHTMLDocument::nsHTMLDocument()
227 234 : : nsDocument("text/html")
228 : {
229 : // NOTE! nsDocument::operator new() zeroes out all members, so don't
230 : // bother initializing members to 0.
231 :
232 234 : mIsRegularHTML = true;
233 234 : mDefaultElementType = kNameSpaceID_XHTML;
234 234 : mCompatMode = eCompatibility_NavQuirks;
235 234 : }
236 :
237 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLDocument)
238 :
239 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
240 238 : NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
241 : "Shouldn't traverse nsHTMLDocument!");
242 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mImages)
243 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplets)
244 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEmbeds)
245 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLinks)
246 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAnchors)
247 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScripts)
248 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mForms, nsIDOMNodeList)
249 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFormControls,
250 : nsIDOMNodeList)
251 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWyciwygChannel)
252 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMidasCommandManager)
253 238 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
254 :
255 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
256 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImages)
257 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplets)
258 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEmbeds)
259 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLinks)
260 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAnchors)
261 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScripts)
262 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mForms)
263 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFormControls)
264 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWyciwygChannel)
265 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMidasCommandManager)
266 234 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
267 :
268 9594 : NS_IMPL_ADDREF_INHERITED(nsHTMLDocument, nsDocument)
269 9594 : NS_IMPL_RELEASE_INHERITED(nsHTMLDocument, nsDocument)
270 :
271 :
272 0 : DOMCI_NODE_DATA(HTMLDocument, nsHTMLDocument)
273 :
274 : // QueryInterface implementation for nsHTMLDocument
275 15561 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLDocument)
276 : NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsHTMLDocument)
277 : NS_INTERFACE_TABLE_ENTRY(nsHTMLDocument, nsIHTMLDocument)
278 : NS_INTERFACE_TABLE_ENTRY(nsHTMLDocument, nsIDOMHTMLDocument)
279 9052 : NS_OFFSET_AND_INTERFACE_TABLE_END
280 9052 : NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
281 5776 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLDocument)
282 5776 : NS_INTERFACE_MAP_END_INHERITING(nsDocument)
283 :
284 :
285 : nsresult
286 234 : nsHTMLDocument::Init()
287 : {
288 234 : nsresult rv = nsDocument::Init();
289 234 : NS_ENSURE_SUCCESS(rv, rv);
290 :
291 : // Now reset the compatibility mode of the CSSLoader
292 : // to match our compat mode.
293 234 : CSSLoader()->SetCompatibilityMode(mCompatMode);
294 :
295 234 : return NS_OK;
296 : }
297 :
298 :
299 : void
300 0 : nsHTMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
301 : {
302 0 : nsDocument::Reset(aChannel, aLoadGroup);
303 :
304 0 : if (aChannel) {
305 0 : aChannel->GetLoadFlags(&mLoadFlags);
306 : }
307 0 : }
308 :
309 : void
310 0 : nsHTMLDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
311 : nsIPrincipal* aPrincipal)
312 : {
313 0 : mLoadFlags = nsIRequest::LOAD_NORMAL;
314 :
315 0 : nsDocument::ResetToURI(aURI, aLoadGroup, aPrincipal);
316 :
317 0 : mImages = nsnull;
318 0 : mApplets = nsnull;
319 0 : mEmbeds = nsnull;
320 0 : mLinks = nsnull;
321 0 : mAnchors = nsnull;
322 0 : mScripts = nsnull;
323 :
324 0 : mForms = nsnull;
325 :
326 0 : NS_ASSERTION(!mWyciwygChannel,
327 : "nsHTMLDocument::Reset() - Wyciwyg Channel still exists!");
328 :
329 0 : mWyciwygChannel = nsnull;
330 :
331 : // Make the content type default to "text/html", we are a HTML
332 : // document, after all. Once we start getting data, this may be
333 : // changed.
334 0 : SetContentTypeInternal(nsDependentCString("text/html"));
335 0 : }
336 :
337 : nsresult
338 0 : nsHTMLDocument::CreateShell(nsPresContext* aContext,
339 : nsIViewManager* aViewManager,
340 : nsStyleSet* aStyleSet,
341 : nsIPresShell** aInstancePtrResult)
342 : {
343 : return doCreateShell(aContext, aViewManager, aStyleSet, mCompatMode,
344 0 : aInstancePtrResult);
345 : }
346 :
347 : // The following Try*Charset will return false only if the charset source
348 : // should be considered (ie. aCharsetSource < thisCharsetSource) but we failed
349 : // to get the charset from this source.
350 :
351 : bool
352 0 : nsHTMLDocument::TryHintCharset(nsIMarkupDocumentViewer* aMarkupDV,
353 : PRInt32& aCharsetSource, nsACString& aCharset)
354 : {
355 0 : if (aMarkupDV) {
356 : PRInt32 requestCharsetSource;
357 0 : nsresult rv = aMarkupDV->GetHintCharacterSetSource(&requestCharsetSource);
358 :
359 0 : if(NS_SUCCEEDED(rv) && kCharsetUninitialized != requestCharsetSource) {
360 0 : nsCAutoString requestCharset;
361 0 : rv = aMarkupDV->GetHintCharacterSet(requestCharset);
362 0 : aMarkupDV->SetHintCharacterSetSource((PRInt32)(kCharsetUninitialized));
363 :
364 0 : if(requestCharsetSource <= aCharsetSource)
365 0 : return true;
366 :
367 0 : if(NS_SUCCEEDED(rv)) {
368 0 : aCharsetSource = requestCharsetSource;
369 0 : aCharset = requestCharset;
370 :
371 0 : return true;
372 : }
373 : }
374 : }
375 0 : return false;
376 : }
377 :
378 :
379 : bool
380 0 : nsHTMLDocument::TryUserForcedCharset(nsIMarkupDocumentViewer* aMarkupDV,
381 : nsIDocShell* aDocShell,
382 : PRInt32& aCharsetSource,
383 : nsACString& aCharset)
384 : {
385 0 : nsresult rv = NS_OK;
386 :
387 0 : if(kCharsetFromUserForced <= aCharsetSource)
388 0 : return true;
389 :
390 0 : nsCAutoString forceCharsetFromDocShell;
391 0 : if (aMarkupDV) {
392 0 : rv = aMarkupDV->GetForceCharacterSet(forceCharsetFromDocShell);
393 : }
394 :
395 0 : if(NS_SUCCEEDED(rv) && !forceCharsetFromDocShell.IsEmpty()) {
396 0 : aCharset = forceCharsetFromDocShell;
397 : //TODO: we should define appropriate constant for force charset
398 0 : aCharsetSource = kCharsetFromUserForced;
399 0 : } else if (aDocShell) {
400 0 : nsCOMPtr<nsIAtom> csAtom;
401 0 : aDocShell->GetForcedCharset(getter_AddRefs(csAtom));
402 0 : if (csAtom) {
403 0 : csAtom->ToUTF8String(aCharset);
404 0 : aCharsetSource = kCharsetFromUserForced;
405 0 : aDocShell->SetForcedCharset(nsnull);
406 0 : return true;
407 : }
408 : }
409 :
410 0 : return false;
411 : }
412 :
413 : bool
414 0 : nsHTMLDocument::TryCacheCharset(nsICachingChannel* aCachingChannel,
415 : PRInt32& aCharsetSource,
416 : nsACString& aCharset)
417 : {
418 : nsresult rv;
419 :
420 0 : if (kCharsetFromCache <= aCharsetSource) {
421 0 : return true;
422 : }
423 :
424 0 : nsCString cachedCharset;
425 0 : rv = aCachingChannel->GetCacheTokenCachedCharset(cachedCharset);
426 0 : if (NS_SUCCEEDED(rv) && !cachedCharset.IsEmpty())
427 : {
428 0 : aCharset = cachedCharset;
429 0 : aCharsetSource = kCharsetFromCache;
430 :
431 0 : return true;
432 : }
433 :
434 0 : return false;
435 : }
436 :
437 : static bool
438 0 : CheckSameOrigin(nsINode* aNode1, nsINode* aNode2)
439 : {
440 0 : NS_PRECONDITION(aNode1, "Null node?");
441 0 : NS_PRECONDITION(aNode2, "Null node?");
442 :
443 : bool equal;
444 : return
445 0 : NS_SUCCEEDED(aNode1->NodePrincipal()->
446 : Equals(aNode2->NodePrincipal(), &equal)) &&
447 0 : equal;
448 : }
449 :
450 : bool
451 0 : nsHTMLDocument::TryParentCharset(nsIDocShell* aDocShell,
452 : nsIDocument* aParentDocument,
453 : PRInt32& aCharsetSource,
454 : nsACString& aCharset)
455 : {
456 0 : if (aDocShell) {
457 : PRInt32 source;
458 0 : nsCOMPtr<nsIAtom> csAtom;
459 : PRInt32 parentSource;
460 0 : aDocShell->GetParentCharsetSource(&parentSource);
461 0 : if (kCharsetFromParentForced <= parentSource)
462 0 : source = kCharsetFromParentForced;
463 0 : else if (kCharsetFromHintPrevDoc == parentSource) {
464 : // Make sure that's OK
465 0 : if (!aParentDocument || !CheckSameOrigin(this, aParentDocument)) {
466 0 : return false;
467 : }
468 :
469 : // if parent is posted doc, set this prevent autodections
470 : // I'm not sure this makes much sense... but whatever.
471 0 : source = kCharsetFromHintPrevDoc;
472 : }
473 0 : else if (kCharsetFromCache <= parentSource) {
474 : // Make sure that's OK
475 0 : if (!aParentDocument || !CheckSameOrigin(this, aParentDocument)) {
476 0 : return false;
477 : }
478 :
479 0 : source = kCharsetFromParentFrame;
480 : }
481 : else
482 0 : return false;
483 :
484 0 : if (source < aCharsetSource)
485 0 : return true;
486 :
487 0 : aDocShell->GetParentCharset(getter_AddRefs(csAtom));
488 0 : if (csAtom) {
489 0 : csAtom->ToUTF8String(aCharset);
490 0 : aCharsetSource = source;
491 0 : return true;
492 : }
493 : }
494 0 : return false;
495 : }
496 :
497 : bool
498 0 : nsHTMLDocument::UseWeakDocTypeDefault(PRInt32& aCharsetSource,
499 : nsACString& aCharset)
500 : {
501 0 : if (kCharsetFromWeakDocTypeDefault <= aCharsetSource)
502 0 : return true;
503 : // fallback value in case docshell return error
504 0 : aCharset.AssignLiteral("ISO-8859-1");
505 :
506 : const nsAdoptingCString& defCharset =
507 0 : Preferences::GetLocalizedCString("intl.charset.default");
508 :
509 0 : if (!defCharset.IsEmpty()) {
510 0 : aCharset = defCharset;
511 0 : aCharsetSource = kCharsetFromWeakDocTypeDefault;
512 : }
513 0 : return true;
514 : }
515 :
516 : bool
517 0 : nsHTMLDocument::TryDefaultCharset( nsIMarkupDocumentViewer* aMarkupDV,
518 : PRInt32& aCharsetSource,
519 : nsACString& aCharset)
520 : {
521 0 : if(kCharsetFromUserDefault <= aCharsetSource)
522 0 : return true;
523 :
524 0 : nsCAutoString defaultCharsetFromDocShell;
525 0 : if (aMarkupDV) {
526 : nsresult rv =
527 0 : aMarkupDV->GetDefaultCharacterSet(defaultCharsetFromDocShell);
528 0 : if(NS_SUCCEEDED(rv)) {
529 0 : aCharset = defaultCharsetFromDocShell;
530 :
531 0 : aCharsetSource = kCharsetFromUserDefault;
532 0 : return true;
533 : }
534 : }
535 0 : return false;
536 : }
537 :
538 : void
539 234 : nsHTMLDocument::SetDocumentCharacterSet(const nsACString& aCharSetID)
540 : {
541 234 : nsDocument::SetDocumentCharacterSet(aCharSetID);
542 : // Make sure to stash this charset on our channel as needed if it's a wyciwyg
543 : // channel.
544 468 : nsCOMPtr<nsIWyciwygChannel> wyciwygChannel = do_QueryInterface(mChannel);
545 234 : if (wyciwygChannel) {
546 0 : wyciwygChannel->SetCharsetAndSource(GetDocumentCharacterSetSource(),
547 0 : aCharSetID);
548 : }
549 234 : }
550 :
551 : nsresult
552 0 : nsHTMLDocument::StartDocumentLoad(const char* aCommand,
553 : nsIChannel* aChannel,
554 : nsILoadGroup* aLoadGroup,
555 : nsISupports* aContainer,
556 : nsIStreamListener **aDocListener,
557 : bool aReset,
558 : nsIContentSink* aSink)
559 : {
560 0 : if (!aCommand) {
561 0 : MOZ_ASSERT(false, "Command is mandatory");
562 0 : return NS_ERROR_INVALID_POINTER;
563 : }
564 0 : if (aSink) {
565 0 : MOZ_ASSERT(false, "Got a sink override. Should not happen for HTML doc.");
566 0 : return NS_ERROR_INVALID_ARG;
567 : }
568 0 : if (!mIsRegularHTML) {
569 0 : MOZ_ASSERT(false, "Must not set HTML doc to XHTML mode before load start.");
570 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
571 : }
572 :
573 0 : nsCAutoString contentType;
574 0 : aChannel->GetContentType(contentType);
575 :
576 0 : bool view = !strcmp(aCommand, "view") ||
577 0 : !strcmp(aCommand, "external-resource");
578 0 : bool viewSource = !strcmp(aCommand, "view-source");
579 0 : bool asData = !strcmp(aCommand, kLoadAsData);
580 0 : if(!(view || viewSource || asData)) {
581 0 : MOZ_ASSERT(false, "Bad parser command");
582 0 : return NS_ERROR_INVALID_ARG;
583 : }
584 :
585 0 : bool html = contentType.EqualsLiteral(TEXT_HTML);
586 0 : bool xhtml = !html && contentType.EqualsLiteral(APPLICATION_XHTML_XML);
587 0 : bool plainText = !html && !xhtml && (contentType.EqualsLiteral(TEXT_PLAIN) ||
588 0 : contentType.EqualsLiteral(TEXT_CSS) ||
589 0 : contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
590 0 : contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
591 0 : contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
592 0 : contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
593 0 : contentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
594 0 : contentType.EqualsLiteral(APPLICATION_JSON));
595 0 : if (!(html || xhtml || plainText || viewSource)) {
596 0 : MOZ_ASSERT(false, "Channel with bad content type.");
597 0 : return NS_ERROR_INVALID_ARG;
598 : }
599 :
600 0 : bool loadAsHtml5 = true;
601 :
602 0 : if (!viewSource && xhtml) {
603 : // We're parsing XHTML as XML, remember that.
604 0 : mIsRegularHTML = false;
605 0 : mCompatMode = eCompatibility_FullStandards;
606 0 : loadAsHtml5 = false;
607 : }
608 :
609 : // TODO: Proper about:blank treatment is bug 543435
610 0 : if (loadAsHtml5 && view) {
611 : // mDocumentURI hasn't been set, yet, so get the URI from the channel
612 0 : nsCOMPtr<nsIURI> uri;
613 0 : aChannel->GetOriginalURI(getter_AddRefs(uri));
614 : // Adapted from nsDocShell:
615 : // GetSpec can be expensive for some URIs, so check the scheme first.
616 0 : bool isAbout = false;
617 0 : if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
618 0 : nsCAutoString str;
619 0 : uri->GetSpec(str);
620 0 : if (str.EqualsLiteral("about:blank")) {
621 0 : loadAsHtml5 = false;
622 : }
623 : }
624 : }
625 :
626 0 : CSSLoader()->SetCompatibilityMode(mCompatMode);
627 :
628 : nsresult rv = nsDocument::StartDocumentLoad(aCommand,
629 : aChannel, aLoadGroup,
630 : aContainer,
631 0 : aDocListener, aReset);
632 0 : if (NS_FAILED(rv)) {
633 0 : return rv;
634 : }
635 :
636 : // Store the security info for future use with wyciwyg channels.
637 0 : aChannel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
638 :
639 0 : nsCOMPtr<nsIURI> uri;
640 0 : rv = aChannel->GetURI(getter_AddRefs(uri));
641 0 : if (NS_FAILED(rv)) {
642 0 : return rv;
643 : }
644 :
645 0 : nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel);
646 :
647 0 : if (loadAsHtml5) {
648 0 : mParser = nsHtml5Module::NewHtml5Parser();
649 0 : if (plainText) {
650 0 : if (viewSource) {
651 0 : mParser->MarkAsNotScriptCreated("view-source-plain");
652 : } else {
653 0 : mParser->MarkAsNotScriptCreated("plain-text");
654 : }
655 0 : } else if (viewSource && !html) {
656 0 : mParser->MarkAsNotScriptCreated("view-source-xml");
657 : } else {
658 0 : mParser->MarkAsNotScriptCreated(aCommand);
659 : }
660 : } else {
661 0 : mParser = do_CreateInstance(kCParserCID, &rv);
662 0 : NS_ENSURE_SUCCESS(rv, rv);
663 : }
664 :
665 0 : PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
666 :
667 : // Look for the parent document. Note that at this point we don't have our
668 : // content viewer set up yet, and therefore do not have a useful
669 : // mParentDocument.
670 :
671 : // in this block of code, if we get an error result, we return it
672 : // but if we get a null pointer, that's perfectly legal for parent
673 : // and parentContentViewer
674 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
675 :
676 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
677 :
678 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
679 0 : if (docShellAsItem) {
680 0 : docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
681 : }
682 :
683 0 : nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
684 0 : nsCOMPtr<nsIDocument> parentDocument;
685 0 : nsCOMPtr<nsIContentViewer> parentContentViewer;
686 0 : if (parent) {
687 0 : rv = parent->GetContentViewer(getter_AddRefs(parentContentViewer));
688 0 : NS_ENSURE_SUCCESS(rv, rv);
689 0 : if (parentContentViewer) {
690 0 : parentDocument = parentContentViewer->GetDocument();
691 : }
692 : }
693 :
694 : //
695 : // The following logic is mirrored in nsWebShell::Embed!
696 : //
697 0 : nsCOMPtr<nsIMarkupDocumentViewer> muCV;
698 0 : bool muCVIsParent = false;
699 0 : nsCOMPtr<nsIContentViewer> cv;
700 0 : if (docShell) {
701 0 : docShell->GetContentViewer(getter_AddRefs(cv));
702 : }
703 0 : if (cv) {
704 0 : muCV = do_QueryInterface(cv);
705 : } else {
706 0 : muCV = do_QueryInterface(parentContentViewer);
707 0 : if (muCV) {
708 0 : muCVIsParent = true;
709 : }
710 : }
711 :
712 0 : nsCAutoString urlSpec;
713 0 : uri->GetSpec(urlSpec);
714 : #ifdef DEBUG_charset
715 : printf("Determining charset for %s\n", urlSpec.get());
716 : #endif
717 :
718 : // These are the charset source and charset for our document
719 : PRInt32 charsetSource;
720 0 : nsCAutoString charset;
721 :
722 : // These are the charset source and charset for the parser. This can differ
723 : // from that for the document if the channel is a wyciwyg channel.
724 : PRInt32 parserCharsetSource;
725 0 : nsCAutoString parserCharset;
726 :
727 0 : nsCOMPtr<nsIWyciwygChannel> wyciwygChannel;
728 :
729 0 : if (!IsHTML() || !docShell) { // no docshell for text/html XHR
730 0 : charsetSource = IsHTML() ? kCharsetFromWeakDocTypeDefault
731 0 : : kCharsetFromDocTypeDefault;
732 0 : charset.AssignLiteral("UTF-8");
733 0 : TryChannelCharset(aChannel, charsetSource, charset);
734 0 : parserCharsetSource = charsetSource;
735 0 : parserCharset = charset;
736 : } else {
737 0 : NS_ASSERTION(docShell && docShellAsItem, "Unexpected null value");
738 :
739 0 : charsetSource = kCharsetUninitialized;
740 0 : wyciwygChannel = do_QueryInterface(aChannel);
741 :
742 : // The following charset resolving calls has implied knowledge
743 : // about charset source priority order. Each try will return true
744 : // if the source is higher or equal to the source as its name
745 : // describes. Some try call might change charset source to
746 : // multiple values, like TryHintCharset and TryParentCharset. It
747 : // should be always safe to try more sources.
748 0 : if (!TryUserForcedCharset(muCV, docShell, charsetSource, charset)) {
749 0 : TryHintCharset(muCV, charsetSource, charset);
750 0 : TryParentCharset(docShell, parentDocument, charsetSource, charset);
751 :
752 : // Don't actually get the charset from the channel if this is a
753 : // wyciwyg channel; it'll always be UTF-16
754 0 : if (!wyciwygChannel &&
755 0 : TryChannelCharset(aChannel, charsetSource, charset)) {
756 : // Use the channel's charset (e.g., charset from HTTP
757 : // "Content-Type" header).
758 : }
759 0 : else if (cachingChan && !urlSpec.IsEmpty() &&
760 0 : TryCacheCharset(cachingChan, charsetSource, charset)) {
761 : // Use the cache's charset.
762 : }
763 0 : else if (TryDefaultCharset(muCV, charsetSource, charset)) {
764 : // Use the default charset.
765 : // previous document charset might be inherited as default charset.
766 : }
767 : else {
768 : // Use the weak doc type default charset
769 0 : UseWeakDocTypeDefault(charsetSource, charset);
770 : }
771 : }
772 :
773 0 : bool isPostPage = false;
774 : // check if current doc is from POST command
775 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
776 0 : if (httpChannel) {
777 0 : nsCAutoString methodStr;
778 0 : rv = httpChannel->GetRequestMethod(methodStr);
779 0 : isPostPage = (NS_SUCCEEDED(rv) &&
780 0 : methodStr.EqualsLiteral("POST"));
781 : }
782 :
783 0 : if (isPostPage && muCV && kCharsetFromHintPrevDoc > charsetSource) {
784 0 : nsCAutoString requestCharset;
785 0 : muCV->GetPrevDocCharacterSet(requestCharset);
786 0 : if (!requestCharset.IsEmpty()) {
787 0 : charsetSource = kCharsetFromHintPrevDoc;
788 0 : charset = requestCharset;
789 : }
790 : }
791 :
792 0 : if (wyciwygChannel) {
793 : // We know for sure that the parser needs to be using UTF16.
794 0 : parserCharset = "UTF-16";
795 : parserCharsetSource = charsetSource < kCharsetFromChannel ?
796 0 : kCharsetFromChannel : charsetSource;
797 :
798 0 : nsCAutoString cachedCharset;
799 : PRInt32 cachedSource;
800 0 : rv = wyciwygChannel->GetCharsetAndSource(&cachedSource, cachedCharset);
801 0 : if (NS_SUCCEEDED(rv)) {
802 0 : if (cachedSource > charsetSource) {
803 0 : charsetSource = cachedSource;
804 0 : charset = cachedCharset;
805 : }
806 : } else {
807 : // Don't propagate this error.
808 0 : rv = NS_OK;
809 : }
810 :
811 : } else {
812 0 : parserCharset = charset;
813 0 : parserCharsetSource = charsetSource;
814 : }
815 :
816 : // ahmed
817 : // Check if 864 but in Implicit mode !
818 0 : if ((textType == IBMBIDI_TEXTTYPE_LOGICAL) &&
819 0 : (charset.LowerCaseEqualsLiteral("ibm864"))) {
820 0 : charset.AssignLiteral("IBM864i");
821 : }
822 : }
823 :
824 0 : SetDocumentCharacterSetSource(charsetSource);
825 0 : SetDocumentCharacterSet(charset);
826 :
827 : // set doc charset to muCV for next document.
828 : // Don't propagate this back up to the parent document if we have one.
829 0 : if (muCV && !muCVIsParent)
830 0 : muCV->SetPrevDocCharacterSet(charset);
831 :
832 0 : if (cachingChan) {
833 0 : NS_ASSERTION(charset == parserCharset,
834 : "How did those end up different here? wyciwyg channels are "
835 : "not nsICachingChannel");
836 0 : rv = cachingChan->SetCacheTokenCachedCharset(charset);
837 0 : NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "cannot SetMetaDataElement");
838 0 : rv = NS_OK; // don't propagate error
839 : }
840 :
841 : // Set the parser as the stream listener for the document loader...
842 0 : rv = NS_OK;
843 0 : nsCOMPtr<nsIStreamListener> listener = mParser->GetStreamListener();
844 0 : listener.forget(aDocListener);
845 :
846 : #ifdef DEBUG_charset
847 : printf(" charset = %s source %d\n",
848 : charset.get(), charsetSource);
849 : #endif
850 0 : mParser->SetDocumentCharset(parserCharset, parserCharsetSource);
851 0 : mParser->SetCommand(aCommand);
852 :
853 0 : if (!IsHTML()) {
854 0 : MOZ_ASSERT(!loadAsHtml5);
855 0 : nsCOMPtr<nsIXMLContentSink> xmlsink;
856 0 : NS_NewXMLContentSink(getter_AddRefs(xmlsink), this, uri,
857 0 : docShell, aChannel);
858 0 : mParser->SetContentSink(xmlsink);
859 : } else {
860 0 : if (loadAsHtml5) {
861 0 : nsHtml5Module::Initialize(mParser, this, uri, docShell, aChannel);
862 : } else {
863 : // about:blank *only*
864 0 : nsCOMPtr<nsIHTMLContentSink> htmlsink;
865 0 : NS_NewHTMLContentSink(getter_AddRefs(htmlsink), this, uri,
866 0 : docShell, aChannel);
867 0 : mParser->SetContentSink(htmlsink);
868 : }
869 : }
870 :
871 : // parser the content of the URI
872 0 : mParser->Parse(uri, nsnull, (void *)this);
873 :
874 0 : return rv;
875 : }
876 :
877 : void
878 0 : nsHTMLDocument::StopDocumentLoad()
879 : {
880 0 : BlockOnload();
881 :
882 : // Remove the wyciwyg channel request from the document load group
883 : // that we added in Open() if Open() was called on this doc.
884 0 : RemoveWyciwygChannel();
885 0 : NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
886 : "nsIWyciwygChannel could not be removed!");
887 :
888 0 : nsDocument::StopDocumentLoad();
889 0 : UnblockOnload(false);
890 : return;
891 : }
892 :
893 : void
894 0 : nsHTMLDocument::BeginLoad()
895 : {
896 0 : if (IsEditingOn()) {
897 : // Reset() blows away all event listeners in the document, and our
898 : // editor relies heavily on those. Midas is turned on, to make it
899 : // work, re-initialize it to give it a chance to add its event
900 : // listeners again.
901 :
902 0 : TurnEditingOff();
903 0 : EditingStateChanged();
904 : }
905 0 : nsDocument::BeginLoad();
906 0 : }
907 :
908 : void
909 0 : nsHTMLDocument::EndLoad()
910 : {
911 : bool turnOnEditing =
912 0 : mParser && (HasFlag(NODE_IS_EDITABLE) || mContentEditableCount > 0);
913 : // Note: nsDocument::EndLoad nulls out mParser.
914 0 : nsDocument::EndLoad();
915 0 : if (turnOnEditing) {
916 0 : EditingStateChanged();
917 : }
918 0 : }
919 :
920 : void
921 468 : nsHTMLDocument::SetCompatibilityMode(nsCompatibility aMode)
922 : {
923 468 : NS_ASSERTION(IsHTML() || aMode == eCompatibility_FullStandards,
924 : "Bad compat mode for XHTML document!");
925 :
926 468 : mCompatMode = aMode;
927 468 : CSSLoader()->SetCompatibilityMode(mCompatMode);
928 936 : nsCOMPtr<nsIPresShell> shell = GetShell();
929 468 : if (shell) {
930 0 : nsPresContext *pc = shell->GetPresContext();
931 0 : if (pc) {
932 0 : pc->CompatibilityModeChanged();
933 : }
934 : }
935 468 : }
936 :
937 : //
938 : // nsIDOMHTMLDocument interface implementation
939 : //
940 : void
941 0 : nsHTMLDocument::GetDomainURI(nsIURI **aURI)
942 : {
943 0 : nsIPrincipal *principal = NodePrincipal();
944 :
945 0 : principal->GetDomain(aURI);
946 0 : if (!*aURI) {
947 0 : principal->GetURI(aURI);
948 : }
949 0 : }
950 :
951 :
952 : NS_IMETHODIMP
953 0 : nsHTMLDocument::GetDomain(nsAString& aDomain)
954 : {
955 0 : nsCOMPtr<nsIURI> uri;
956 0 : GetDomainURI(getter_AddRefs(uri));
957 :
958 0 : if (!uri) {
959 0 : return NS_ERROR_FAILURE;
960 : }
961 :
962 0 : nsCAutoString hostName;
963 :
964 0 : if (NS_SUCCEEDED(uri->GetHost(hostName))) {
965 0 : CopyUTF8toUTF16(hostName, aDomain);
966 : } else {
967 : // If we can't get the host from the URI (e.g. about:, javascript:,
968 : // etc), just return an null string.
969 0 : SetDOMStringToNull(aDomain);
970 : }
971 :
972 0 : return NS_OK;
973 : }
974 :
975 : NS_IMETHODIMP
976 0 : nsHTMLDocument::SetDomain(const nsAString& aDomain)
977 : {
978 0 : if (aDomain.IsEmpty())
979 0 : return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN;
980 :
981 : // Create new URI
982 0 : nsCOMPtr<nsIURI> uri;
983 0 : GetDomainURI(getter_AddRefs(uri));
984 :
985 0 : if (!uri) {
986 0 : return NS_ERROR_FAILURE;
987 : }
988 :
989 0 : nsCAutoString newURIString;
990 0 : if (NS_FAILED(uri->GetScheme(newURIString)))
991 0 : return NS_ERROR_FAILURE;
992 0 : nsCAutoString path;
993 0 : if (NS_FAILED(uri->GetPath(path)))
994 0 : return NS_ERROR_FAILURE;
995 0 : newURIString.AppendLiteral("://");
996 0 : AppendUTF16toUTF8(aDomain, newURIString);
997 0 : newURIString.Append(path);
998 :
999 0 : nsCOMPtr<nsIURI> newURI;
1000 0 : if (NS_FAILED(NS_NewURI(getter_AddRefs(newURI), newURIString)))
1001 0 : return NS_ERROR_FAILURE;
1002 :
1003 : // Check new domain - must be a superdomain of the current host
1004 : // For example, a page from foo.bar.com may set domain to bar.com,
1005 : // but not to ar.com, baz.com, or fi.foo.bar.com.
1006 0 : nsCAutoString current, domain;
1007 0 : if (NS_FAILED(uri->GetAsciiHost(current)))
1008 0 : current.Truncate();
1009 0 : if (NS_FAILED(newURI->GetAsciiHost(domain)))
1010 0 : domain.Truncate();
1011 :
1012 0 : bool ok = current.Equals(domain);
1013 0 : if (current.Length() > domain.Length() &&
1014 0 : StringEndsWith(current, domain) &&
1015 0 : current.CharAt(current.Length() - domain.Length() - 1) == '.') {
1016 : // We're golden if the new domain is the current page's base domain or a
1017 : // subdomain of it.
1018 : nsCOMPtr<nsIEffectiveTLDService> tldService =
1019 0 : do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
1020 0 : if (!tldService)
1021 0 : return NS_ERROR_NOT_AVAILABLE;
1022 :
1023 0 : nsCAutoString currentBaseDomain;
1024 0 : ok = NS_SUCCEEDED(tldService->GetBaseDomain(uri, 0, currentBaseDomain));
1025 0 : NS_ASSERTION(StringEndsWith(domain, currentBaseDomain) ==
1026 : (domain.Length() >= currentBaseDomain.Length()),
1027 : "uh-oh! slight optimization wasn't valid somehow!");
1028 0 : ok = ok && domain.Length() >= currentBaseDomain.Length();
1029 : }
1030 0 : if (!ok) {
1031 : // Error: illegal domain
1032 0 : return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN;
1033 : }
1034 :
1035 0 : return NodePrincipal()->SetDomain(newURI);
1036 : }
1037 :
1038 : NS_IMETHODIMP
1039 0 : nsHTMLDocument::GetURL(nsAString& aURL)
1040 : {
1041 0 : nsCAutoString str;
1042 :
1043 0 : if (mDocumentURI) {
1044 0 : mDocumentURI->GetSpec(str);
1045 : }
1046 :
1047 0 : CopyUTF8toUTF16(str, aURL);
1048 :
1049 0 : return NS_OK;
1050 : }
1051 :
1052 : nsIContent*
1053 0 : nsHTMLDocument::GetBody()
1054 : {
1055 0 : Element* body = GetBodyElement();
1056 :
1057 0 : if (body) {
1058 : // There is a body element, return that as the body.
1059 0 : return body;
1060 : }
1061 :
1062 : // The document is most likely a frameset document so look for the
1063 : // outer most frameset element
1064 : nsRefPtr<nsContentList> nodeList =
1065 0 : NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("frameset"));
1066 :
1067 0 : return nodeList->GetNodeAt(0);
1068 : }
1069 :
1070 : NS_IMETHODIMP
1071 0 : nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody)
1072 : {
1073 0 : *aBody = nsnull;
1074 :
1075 0 : nsIContent *body = GetBody();
1076 :
1077 0 : return body ? CallQueryInterface(body, aBody) : NS_OK;
1078 : }
1079 :
1080 : NS_IMETHODIMP
1081 0 : nsHTMLDocument::SetBody(nsIDOMHTMLElement* aBody)
1082 : {
1083 0 : nsCOMPtr<nsIContent> newBody = do_QueryInterface(aBody);
1084 0 : Element* root = GetRootElement();
1085 :
1086 : // The body element must be either a body tag or a frameset tag. And we must
1087 : // have a html root tag, otherwise GetBody will not return the newly set
1088 : // body.
1089 0 : if (!newBody || !(newBody->Tag() == nsGkAtoms::body ||
1090 0 : newBody->Tag() == nsGkAtoms::frameset) ||
1091 0 : !root || !root->IsHTML() ||
1092 0 : root->Tag() != nsGkAtoms::html) {
1093 0 : return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1094 : }
1095 :
1096 0 : nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(root);
1097 0 : nsCOMPtr<nsIDOMNode> tmp;
1098 :
1099 : // Use DOM methods so that we pass through the appropriate security checks.
1100 0 : nsCOMPtr<nsIDOMNode> currentBody = do_QueryInterface(GetBodyElement());
1101 0 : if (currentBody) {
1102 0 : return rootElem->ReplaceChild(aBody, currentBody, getter_AddRefs(tmp));
1103 : }
1104 :
1105 0 : return rootElem->AppendChild(aBody, getter_AddRefs(tmp));
1106 : }
1107 :
1108 : NS_IMETHODIMP
1109 0 : nsHTMLDocument::GetHead(nsIDOMHTMLHeadElement** aHead)
1110 : {
1111 0 : *aHead = nsnull;
1112 :
1113 0 : Element* head = GetHeadElement();
1114 :
1115 0 : return head ? CallQueryInterface(head, aHead) : NS_OK;
1116 : }
1117 :
1118 : NS_IMETHODIMP
1119 0 : nsHTMLDocument::GetImages(nsIDOMHTMLCollection** aImages)
1120 : {
1121 0 : if (!mImages) {
1122 0 : mImages = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::img, nsGkAtoms::img);
1123 : }
1124 :
1125 0 : *aImages = mImages;
1126 0 : NS_ADDREF(*aImages);
1127 :
1128 0 : return NS_OK;
1129 : }
1130 :
1131 : NS_IMETHODIMP
1132 0 : nsHTMLDocument::GetApplets(nsIDOMHTMLCollection** aApplets)
1133 : {
1134 0 : if (!mApplets) {
1135 0 : mApplets = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::applet, nsGkAtoms::applet);
1136 : }
1137 :
1138 0 : *aApplets = mApplets;
1139 0 : NS_ADDREF(*aApplets);
1140 :
1141 0 : return NS_OK;
1142 : }
1143 :
1144 : bool
1145 0 : nsHTMLDocument::MatchLinks(nsIContent *aContent, PRInt32 aNamespaceID,
1146 : nsIAtom* aAtom, void* aData)
1147 : {
1148 0 : nsIDocument* doc = aContent->GetCurrentDoc();
1149 :
1150 0 : if (doc) {
1151 0 : NS_ASSERTION(aContent->IsInDoc(),
1152 : "This method should never be called on content nodes that "
1153 : "are not in a document!");
1154 : #ifdef DEBUG
1155 : {
1156 : nsCOMPtr<nsIHTMLDocument> htmldoc =
1157 0 : do_QueryInterface(aContent->GetCurrentDoc());
1158 0 : NS_ASSERTION(htmldoc,
1159 : "Huh, how did this happen? This should only be used with "
1160 : "HTML documents!");
1161 : }
1162 : #endif
1163 :
1164 0 : nsINodeInfo *ni = aContent->NodeInfo();
1165 :
1166 0 : nsIAtom *localName = ni->NameAtom();
1167 0 : if (ni->NamespaceID() == kNameSpaceID_XHTML &&
1168 : (localName == nsGkAtoms::a || localName == nsGkAtoms::area)) {
1169 0 : return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::href);
1170 : }
1171 : }
1172 :
1173 0 : return false;
1174 : }
1175 :
1176 : NS_IMETHODIMP
1177 0 : nsHTMLDocument::GetLinks(nsIDOMHTMLCollection** aLinks)
1178 : {
1179 0 : if (!mLinks) {
1180 0 : mLinks = new nsContentList(this, MatchLinks, nsnull, nsnull);
1181 : }
1182 :
1183 0 : *aLinks = mLinks;
1184 0 : NS_ADDREF(*aLinks);
1185 :
1186 0 : return NS_OK;
1187 : }
1188 :
1189 : bool
1190 0 : nsHTMLDocument::MatchAnchors(nsIContent *aContent, PRInt32 aNamespaceID,
1191 : nsIAtom* aAtom, void* aData)
1192 : {
1193 0 : NS_ASSERTION(aContent->IsInDoc(),
1194 : "This method should never be called on content nodes that "
1195 : "are not in a document!");
1196 : #ifdef DEBUG
1197 : {
1198 : nsCOMPtr<nsIHTMLDocument> htmldoc =
1199 0 : do_QueryInterface(aContent->GetCurrentDoc());
1200 0 : NS_ASSERTION(htmldoc,
1201 : "Huh, how did this happen? This should only be used with "
1202 : "HTML documents!");
1203 : }
1204 : #endif
1205 :
1206 0 : if (aContent->NodeInfo()->Equals(nsGkAtoms::a, kNameSpaceID_XHTML)) {
1207 0 : return aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::name);
1208 : }
1209 :
1210 0 : return false;
1211 : }
1212 :
1213 : NS_IMETHODIMP
1214 0 : nsHTMLDocument::GetAnchors(nsIDOMHTMLCollection** aAnchors)
1215 : {
1216 0 : if (!mAnchors) {
1217 0 : mAnchors = new nsContentList(this, MatchAnchors, nsnull, nsnull);
1218 : }
1219 :
1220 0 : *aAnchors = mAnchors;
1221 0 : NS_ADDREF(*aAnchors);
1222 :
1223 0 : return NS_OK;
1224 : }
1225 :
1226 : NS_IMETHODIMP
1227 0 : nsHTMLDocument::GetScripts(nsIDOMHTMLCollection** aScripts)
1228 : {
1229 0 : if (!mScripts) {
1230 0 : mScripts = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::script, nsGkAtoms::script);
1231 : }
1232 :
1233 0 : *aScripts = mScripts;
1234 0 : NS_ADDREF(*aScripts);
1235 :
1236 0 : return NS_OK;
1237 : }
1238 :
1239 : NS_IMETHODIMP
1240 0 : nsHTMLDocument::GetCookie(nsAString& aCookie)
1241 : {
1242 0 : aCookie.Truncate(); // clear current cookie in case service fails;
1243 : // no cookie isn't an error condition.
1244 :
1245 0 : if (mDisableCookieAccess) {
1246 0 : return NS_OK;
1247 : }
1248 :
1249 : // not having a cookie service isn't an error
1250 0 : nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
1251 0 : if (service) {
1252 : // Get a URI from the document principal. We use the original
1253 : // codebase in case the codebase was changed by SetDomain
1254 0 : nsCOMPtr<nsIURI> codebaseURI;
1255 0 : NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
1256 :
1257 0 : if (!codebaseURI) {
1258 : // Document's principal is not a codebase (may be system), so
1259 : // can't set cookies
1260 :
1261 0 : return NS_OK;
1262 : }
1263 :
1264 0 : nsXPIDLCString cookie;
1265 0 : service->GetCookieString(codebaseURI, mChannel, getter_Copies(cookie));
1266 0 : CopyASCIItoUTF16(cookie, aCookie);
1267 : }
1268 :
1269 0 : return NS_OK;
1270 : }
1271 :
1272 : NS_IMETHODIMP
1273 0 : nsHTMLDocument::SetCookie(const nsAString& aCookie)
1274 : {
1275 0 : if (mDisableCookieAccess) {
1276 0 : return NS_OK;
1277 : }
1278 :
1279 : // not having a cookie service isn't an error
1280 0 : nsCOMPtr<nsICookieService> service = do_GetService(NS_COOKIESERVICE_CONTRACTID);
1281 0 : if (service && mDocumentURI) {
1282 0 : nsCOMPtr<nsIPrompt> prompt;
1283 0 : nsCOMPtr<nsPIDOMWindow> window = GetWindow();
1284 0 : if (window) {
1285 0 : window->GetPrompter(getter_AddRefs(prompt));
1286 : }
1287 :
1288 : // The for getting the URI matches nsNavigator::GetCookieEnabled
1289 0 : nsCOMPtr<nsIURI> codebaseURI;
1290 0 : NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
1291 :
1292 0 : if (!codebaseURI) {
1293 : // Document's principal is not a codebase (may be system), so
1294 : // can't set cookies
1295 :
1296 0 : return NS_OK;
1297 : }
1298 :
1299 0 : NS_LossyConvertUTF16toASCII cookie(aCookie);
1300 0 : service->SetCookieString(codebaseURI, prompt, cookie.get(), mChannel);
1301 : }
1302 :
1303 0 : return NS_OK;
1304 : }
1305 :
1306 : NS_IMETHODIMP
1307 0 : nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
1308 : const nsAString& aReplaceOrName,
1309 : const nsAString& aFeatures,
1310 : JSContext* cx, PRUint8 aOptionalArgCount,
1311 : nsISupports** aReturn)
1312 : {
1313 0 : NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
1314 : "XOW should have caught this!");
1315 :
1316 : // When called with 3 or more arguments, document.open() calls window.open().
1317 0 : if (aOptionalArgCount > 2) {
1318 0 : nsCOMPtr<nsIDOMWindow> window = GetWindowInternal();
1319 0 : if (!window) {
1320 0 : return NS_OK;
1321 : }
1322 0 : nsCOMPtr<nsIDOMWindow> newWindow;
1323 0 : nsresult rv = window->Open(aContentTypeOrUrl, aReplaceOrName, aFeatures,
1324 0 : getter_AddRefs(newWindow));
1325 0 : *aReturn = newWindow.forget().get();
1326 0 : return rv;
1327 : }
1328 :
1329 0 : if (!IsHTML() || mDisableDocWrite) {
1330 : // No calling document.open() on XHTML
1331 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
1332 : }
1333 :
1334 0 : nsCAutoString contentType;
1335 0 : contentType.AssignLiteral("text/html");
1336 0 : if (aOptionalArgCount > 0) {
1337 0 : nsAutoString type;
1338 0 : nsContentUtils::ASCIIToLower(aContentTypeOrUrl, type);
1339 0 : nsCAutoString actualType, dummy;
1340 0 : NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
1341 0 : if (!actualType.EqualsLiteral("text/html") &&
1342 0 : !type.EqualsLiteral("replace")) {
1343 0 : contentType.AssignLiteral("text/plain");
1344 : }
1345 : }
1346 :
1347 : // If we already have a parser we ignore the document.open call.
1348 0 : if (mParser) {
1349 0 : return NS_OK;
1350 : }
1351 :
1352 : // No calling document.open() without a script global object
1353 0 : if (!mScriptGlobalObject) {
1354 0 : return NS_OK;
1355 : }
1356 :
1357 0 : nsPIDOMWindow* outer = GetWindow();
1358 0 : if (!outer || (GetInnerWindow() != outer->GetCurrentInnerWindow())) {
1359 0 : return NS_OK;
1360 : }
1361 :
1362 : // check whether we're in the middle of unload. If so, ignore this call.
1363 0 : nsCOMPtr<nsIDocShell> shell = do_QueryReferent(mDocumentContainer);
1364 0 : if (!shell) {
1365 : // We won't be able to create a parser anyway.
1366 0 : return NS_OK;
1367 : }
1368 :
1369 : bool inUnload;
1370 0 : shell->GetIsInUnload(&inUnload);
1371 0 : if (inUnload) {
1372 0 : return NS_OK;
1373 : }
1374 :
1375 : // Note: We want to use GetDocumentFromContext here because this document
1376 : // should inherit the security information of the document that's opening us,
1377 : // (since if it's secure, then it's presumably trusted).
1378 : nsCOMPtr<nsIDocument> callerDoc =
1379 0 : do_QueryInterface(nsContentUtils::GetDocumentFromContext());
1380 0 : if (!callerDoc) {
1381 : // If we're called from C++ or in some other way without an originating
1382 : // document we can't do a document.open w/o changing the principal of the
1383 : // document to something like about:blank (as that's the only sane thing to
1384 : // do when we don't know the origin of this call), and since we can't
1385 : // change the principals of a document for security reasons we'll have to
1386 : // refuse to go ahead with this call.
1387 :
1388 0 : return NS_ERROR_DOM_SECURITY_ERR;
1389 : }
1390 :
1391 : // Grab a reference to the calling documents security info (if any)
1392 : // and URIs as they may be lost in the call to Reset().
1393 0 : nsCOMPtr<nsISupports> securityInfo = callerDoc->GetSecurityInfo();
1394 0 : nsCOMPtr<nsIURI> uri = callerDoc->GetDocumentURI();
1395 0 : nsCOMPtr<nsIURI> baseURI = callerDoc->GetBaseURI();
1396 0 : nsCOMPtr<nsIPrincipal> callerPrincipal = callerDoc->NodePrincipal();
1397 0 : nsCOMPtr<nsIChannel> callerChannel = callerDoc->GetChannel();
1398 :
1399 : // We're called from script. Make sure the script is from the same
1400 : // origin, not just that the caller can access the document. This is
1401 : // needed to keep document principals from ever changing, which is
1402 : // needed because of the way we use our XOW code, and is a sane
1403 : // thing to do anyways.
1404 :
1405 0 : bool equals = false;
1406 0 : if (NS_FAILED(callerPrincipal->Equals(NodePrincipal(), &equals)) ||
1407 0 : !equals) {
1408 :
1409 : #ifdef DEBUG
1410 0 : nsCOMPtr<nsIURI> callerDocURI = callerDoc->GetDocumentURI();
1411 0 : nsCOMPtr<nsIURI> thisURI = nsIDocument::GetDocumentURI();
1412 0 : nsCAutoString callerSpec;
1413 0 : nsCAutoString thisSpec;
1414 0 : if (callerDocURI) {
1415 0 : callerDocURI->GetSpec(callerSpec);
1416 : }
1417 0 : if (thisURI) {
1418 0 : thisURI->GetSpec(thisSpec);
1419 : }
1420 0 : printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
1421 : #endif
1422 :
1423 0 : return NS_ERROR_DOM_SECURITY_ERR;
1424 : }
1425 :
1426 : // Stop current loads targeted at the window this document is in.
1427 0 : if (mScriptGlobalObject) {
1428 0 : nsCOMPtr<nsIContentViewer> cv;
1429 0 : shell->GetContentViewer(getter_AddRefs(cv));
1430 :
1431 0 : if (cv) {
1432 : bool okToUnload;
1433 0 : if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) {
1434 : // We don't want to unload, so stop here, but don't throw an
1435 : // exception.
1436 0 : return NS_OK;
1437 : }
1438 : }
1439 :
1440 0 : nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell));
1441 0 : webnav->Stop(nsIWebNavigation::STOP_NETWORK);
1442 :
1443 : // The Stop call may have cancelled the onload blocker request or prevented
1444 : // it from getting added, so we need to make sure it gets added to the
1445 : // document again otherwise the document could have a non-zero onload block
1446 : // count without the onload blocker request being in the loadgroup.
1447 0 : EnsureOnloadBlocker();
1448 : }
1449 :
1450 : // The open occurred after the document finished loading.
1451 : // So we reset the document and create a new one.
1452 0 : nsCOMPtr<nsIChannel> channel;
1453 0 : nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
1454 :
1455 0 : nsresult rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, group);
1456 :
1457 0 : if (NS_FAILED(rv)) {
1458 0 : return rv;
1459 : }
1460 :
1461 : // We can't depend on channels implementing property bags, so do our
1462 : // base URI manually after reset.
1463 :
1464 : // Set the caller principal, if any, on the channel so that we'll
1465 : // make sure to use it when we reset.
1466 0 : rv = channel->SetOwner(callerPrincipal);
1467 0 : NS_ENSURE_SUCCESS(rv, rv);
1468 :
1469 0 : if (callerChannel) {
1470 : nsLoadFlags callerLoadFlags;
1471 0 : rv = callerChannel->GetLoadFlags(&callerLoadFlags);
1472 0 : NS_ENSURE_SUCCESS(rv, rv);
1473 :
1474 : nsLoadFlags loadFlags;
1475 0 : rv = channel->GetLoadFlags(&loadFlags);
1476 0 : NS_ENSURE_SUCCESS(rv, rv);
1477 :
1478 0 : loadFlags |= callerLoadFlags & nsIRequest::INHIBIT_PERSISTENT_CACHING;
1479 :
1480 0 : rv = channel->SetLoadFlags(loadFlags);
1481 0 : NS_ENSURE_SUCCESS(rv, rv);
1482 : }
1483 :
1484 : // Before we reset the doc notify the globalwindow of the change,
1485 : // but only if we still have a window (i.e. our window object the
1486 : // current inner window in our outer window).
1487 :
1488 : // Hold onto ourselves on the offchance that we're down to one ref
1489 : nsCOMPtr<nsIDOMDocument> kungFuDeathGrip =
1490 0 : do_QueryInterface((nsIHTMLDocument*)this);
1491 :
1492 0 : nsPIDOMWindow *window = GetInnerWindow();
1493 0 : if (window) {
1494 : // Remember the old scope in case the call to SetNewDocument changes it.
1495 0 : nsCOMPtr<nsIScriptGlobalObject> oldScope(do_QueryReferent(mScopeObject));
1496 :
1497 : #ifdef DEBUG
1498 0 : bool willReparent = mWillReparent;
1499 0 : mWillReparent = true;
1500 : #endif
1501 :
1502 : // Should this pass true for aForceReuseInnerWindow?
1503 0 : rv = window->SetNewDocument(this, nsnull, false);
1504 0 : NS_ENSURE_SUCCESS(rv, rv);
1505 :
1506 : #ifdef DEBUG
1507 0 : mWillReparent = willReparent;
1508 : #endif
1509 :
1510 : // Now make sure we're not flagged as the initial document anymore, now
1511 : // that we've had stuff done to us. From now on, if anyone tries to
1512 : // document.open() us, they get a new inner window.
1513 0 : SetIsInitialDocument(false);
1514 :
1515 0 : nsCOMPtr<nsIScriptGlobalObject> newScope(do_QueryReferent(mScopeObject));
1516 0 : if (oldScope && newScope != oldScope) {
1517 0 : rv = nsContentUtils::ReparentContentWrappersInScope(cx, oldScope, newScope);
1518 0 : NS_ENSURE_SUCCESS(rv, rv);
1519 : }
1520 : }
1521 :
1522 : // Call Reset(), this will now do the full reset
1523 0 : Reset(channel, group);
1524 0 : if (baseURI) {
1525 0 : mDocumentBaseURI = baseURI;
1526 : }
1527 :
1528 : // Store the security info of the caller now that we're done
1529 : // resetting the document.
1530 0 : mSecurityInfo = securityInfo;
1531 :
1532 0 : mParserAborted = false;
1533 0 : mParser = nsHtml5Module::NewHtml5Parser();
1534 0 : nsHtml5Module::Initialize(mParser, this, uri, shell, channel);
1535 0 : rv = NS_OK;
1536 :
1537 : // This will be propagated to the parser when someone actually calls write()
1538 0 : SetContentTypeInternal(contentType);
1539 :
1540 : // Prepare the docshell and the document viewer for the impending
1541 : // out of band document.write()
1542 0 : shell->PrepareForNewContentModel();
1543 :
1544 : // Now check whether we were opened with a "replace" argument. If
1545 : // so, we need to tell the docshell to not create a new history
1546 : // entry for this load. Otherwise, make sure that we're doing a normal load,
1547 : // not whatever type of load was previously done on this docshell.
1548 0 : shell->SetLoadType(
1549 0 : (aOptionalArgCount > 1 && aReplaceOrName.EqualsLiteral("replace"))
1550 0 : ? LOAD_NORMAL_REPLACE : LOAD_NORMAL);
1551 :
1552 0 : nsCOMPtr<nsIContentViewer> cv;
1553 0 : shell->GetContentViewer(getter_AddRefs(cv));
1554 0 : if (cv) {
1555 0 : cv->LoadStart(static_cast<nsIHTMLDocument *>(this));
1556 : }
1557 :
1558 : // Add a wyciwyg channel request into the document load group
1559 0 : NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Open(): wyciwyg "
1560 : "channel already exists!");
1561 :
1562 : // In case the editor is listening and will see the new channel
1563 : // being added, make sure mWriteLevel is non-zero so that the editor
1564 : // knows that document.open/write/close() is being called on this
1565 : // document.
1566 0 : ++mWriteLevel;
1567 :
1568 0 : CreateAndAddWyciwygChannel();
1569 :
1570 0 : --mWriteLevel;
1571 :
1572 0 : NS_ENSURE_SUCCESS(rv, rv);
1573 0 : return CallQueryInterface(this, aReturn);
1574 : }
1575 :
1576 : NS_IMETHODIMP
1577 0 : nsHTMLDocument::Clear()
1578 : {
1579 : // This method has been deprecated
1580 0 : return NS_OK;
1581 : }
1582 :
1583 : NS_IMETHODIMP
1584 0 : nsHTMLDocument::Close()
1585 : {
1586 0 : if (!IsHTML()) {
1587 : // No calling document.close() on XHTML!
1588 :
1589 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
1590 : }
1591 :
1592 0 : if (!mParser || !mParser->IsScriptCreated()) {
1593 0 : return NS_OK;
1594 : }
1595 :
1596 0 : ++mWriteLevel;
1597 0 : nsresult rv = mParser->Parse(EmptyString(), nsnull,
1598 0 : GetContentTypeInternal(), true);
1599 0 : --mWriteLevel;
1600 :
1601 : // XXX Make sure that all the document.written content is
1602 : // reflowed. We should remove this call once we change
1603 : // nsHTMLDocument::OpenCommon() so that it completely destroys the
1604 : // earlier document's content and frame hierarchy. Right now, it
1605 : // re-uses the earlier document's root content object and
1606 : // corresponding frame objects. These re-used frame objects think
1607 : // that they have already been reflowed, so they drop initial
1608 : // reflows. For certain cases of document.written content, like a
1609 : // frameset document, the dropping of the initial reflow means
1610 : // that we end up in document.close() without appended any reflow
1611 : // commands to the reflow queue and, consequently, without adding
1612 : // the dummy layout request to the load group. Since the dummy
1613 : // layout request is not added to the load group, the onload
1614 : // handler of the frameset fires before the frames get reflowed
1615 : // and loaded. That is the long explanation for why we need this
1616 : // one line of code here!
1617 : // XXXbz as far as I can tell this may not be needed anymore; all
1618 : // the testcases in bug 57636 pass without this line... Leaving
1619 : // it be for now, though. In any case, there's no reason to do
1620 : // this if we have no presshell, since in that case none of the
1621 : // above about reusing frames applies.
1622 : //
1623 : // XXXhsivonen keeping this around for bug 577508 / 253951 still :-(
1624 0 : if (GetShell()) {
1625 0 : FlushPendingNotifications(Flush_Layout);
1626 : }
1627 :
1628 : // Removing the wyciwygChannel here is wrong when document.close() is
1629 : // called from within the document itself. However, legacy requires the
1630 : // channel to be removed here. Otherwise, the load event never fires.
1631 0 : NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::Close(): Trying to remove "
1632 : "nonexistent wyciwyg channel!");
1633 0 : RemoveWyciwygChannel();
1634 0 : NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Close(): "
1635 : "nsIWyciwygChannel could not be removed!");
1636 0 : return rv;
1637 : }
1638 :
1639 : nsresult
1640 0 : nsHTMLDocument::WriteCommon(JSContext *cx,
1641 : const nsAString& aText,
1642 : bool aNewlineTerminate)
1643 : {
1644 : mTooDeepWriteRecursion =
1645 0 : (mWriteLevel > NS_MAX_DOCUMENT_WRITE_DEPTH || mTooDeepWriteRecursion);
1646 0 : NS_ENSURE_STATE(!mTooDeepWriteRecursion);
1647 :
1648 0 : if (!IsHTML() || mDisableDocWrite) {
1649 : // No calling document.write*() on XHTML!
1650 :
1651 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
1652 : }
1653 :
1654 0 : if (mParserAborted) {
1655 : // Hixie says aborting the parser doesn't undefine the insertion point.
1656 : // However, since we null out mParser in that case, we track the
1657 : // theoretically defined insertion point using mParserAborted.
1658 0 : return NS_OK;
1659 : }
1660 :
1661 0 : nsresult rv = NS_OK;
1662 :
1663 0 : void *key = GenerateParserKey();
1664 0 : if (mParser && !mParser->IsInsertionPointDefined()) {
1665 0 : if (mExternalScriptsBeingEvaluated) {
1666 : // Instead of implying a call to document.open(), ignore the call.
1667 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
1668 : "DOM Events", this,
1669 : nsContentUtils::eDOM_PROPERTIES,
1670 : "DocumentWriteIgnored",
1671 : nsnull, 0,
1672 0 : mDocumentURI);
1673 0 : return NS_OK;
1674 : }
1675 0 : mParser->Terminate();
1676 0 : NS_ASSERTION(!mParser, "mParser should have been null'd out");
1677 : }
1678 :
1679 0 : if (!mParser) {
1680 0 : if (mExternalScriptsBeingEvaluated) {
1681 : // Instead of implying a call to document.open(), ignore the call.
1682 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
1683 : "DOM Events", this,
1684 : nsContentUtils::eDOM_PROPERTIES,
1685 : "DocumentWriteIgnored",
1686 : nsnull, 0,
1687 0 : mDocumentURI);
1688 0 : return NS_OK;
1689 : }
1690 0 : nsCOMPtr<nsISupports> ignored;
1691 0 : rv = Open(NS_LITERAL_STRING("text/html"), EmptyString(), EmptyString(), cx,
1692 0 : 1, getter_AddRefs(ignored));
1693 :
1694 : // If Open() fails, or if it didn't create a parser (as it won't
1695 : // if the user chose to not discard the current document through
1696 : // onbeforeunload), don't write anything.
1697 0 : if (NS_FAILED(rv) || !mParser) {
1698 0 : return rv;
1699 : }
1700 0 : NS_ABORT_IF_FALSE(!JS_IsExceptionPending(cx),
1701 : "Open() succeeded but JS exception is pending");
1702 : }
1703 :
1704 0 : static NS_NAMED_LITERAL_STRING(new_line, "\n");
1705 :
1706 : // Save the data in cache if the write isn't from within the doc
1707 0 : if (mWyciwygChannel && !key) {
1708 0 : if (!aText.IsEmpty()) {
1709 0 : mWyciwygChannel->WriteToCacheEntry(aText);
1710 : }
1711 :
1712 0 : if (aNewlineTerminate) {
1713 0 : mWyciwygChannel->WriteToCacheEntry(new_line);
1714 : }
1715 : }
1716 :
1717 0 : ++mWriteLevel;
1718 :
1719 : // This could be done with less code, but for performance reasons it
1720 : // makes sense to have the code for two separate Parse() calls here
1721 : // since the concatenation of strings costs more than we like. And
1722 : // why pay that price when we don't need to?
1723 0 : if (aNewlineTerminate) {
1724 0 : rv = mParser->Parse(aText + new_line,
1725 0 : key, GetContentTypeInternal(),
1726 0 : false);
1727 : } else {
1728 0 : rv = mParser->Parse(aText,
1729 0 : key, GetContentTypeInternal(),
1730 0 : false);
1731 : }
1732 :
1733 0 : --mWriteLevel;
1734 :
1735 0 : mTooDeepWriteRecursion = (mWriteLevel != 0 && mTooDeepWriteRecursion);
1736 :
1737 0 : return rv;
1738 : }
1739 :
1740 : NS_IMETHODIMP
1741 0 : nsHTMLDocument::Write(const nsAString& aText, JSContext *cx)
1742 : {
1743 0 : return WriteCommon(cx, aText, false);
1744 : }
1745 :
1746 : NS_IMETHODIMP
1747 0 : nsHTMLDocument::Writeln(const nsAString& aText, JSContext *cx)
1748 : {
1749 0 : return WriteCommon(cx, aText, true);
1750 : }
1751 :
1752 : bool
1753 0 : nsHTMLDocument::MatchNameAttribute(nsIContent* aContent, PRInt32 aNamespaceID,
1754 : nsIAtom* aAtom, void* aData)
1755 : {
1756 0 : NS_PRECONDITION(aContent, "Must have content node to work with!");
1757 0 : nsString* elementName = static_cast<nsString*>(aData);
1758 : return
1759 0 : aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
1760 : aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
1761 0 : *elementName, eCaseMatters);
1762 : }
1763 :
1764 : /* static */
1765 : void*
1766 0 : nsHTMLDocument::UseExistingNameString(nsINode* aRootNode, const nsString* aName)
1767 : {
1768 0 : return const_cast<nsString*>(aName);
1769 : }
1770 :
1771 : NS_IMETHODIMP
1772 0 : nsHTMLDocument::GetElementsByName(const nsAString& aElementName,
1773 : nsIDOMNodeList** aReturn)
1774 : {
1775 0 : nsRefPtr<nsContentList> list = GetElementsByName(aElementName);
1776 0 : NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
1777 :
1778 : // Transfer ownership
1779 0 : list.forget(aReturn);
1780 :
1781 0 : return NS_OK;
1782 : }
1783 :
1784 : void
1785 0 : nsHTMLDocument::AddedForm()
1786 : {
1787 0 : ++mNumForms;
1788 0 : }
1789 :
1790 : void
1791 0 : nsHTMLDocument::RemovedForm()
1792 : {
1793 0 : --mNumForms;
1794 0 : }
1795 :
1796 : PRInt32
1797 0 : nsHTMLDocument::GetNumFormsSynchronous()
1798 : {
1799 0 : return mNumForms;
1800 : }
1801 :
1802 : NS_IMETHODIMP
1803 0 : nsHTMLDocument::GetAlinkColor(nsAString& aAlinkColor)
1804 : {
1805 0 : aAlinkColor.Truncate();
1806 :
1807 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1808 0 : if (body) {
1809 0 : body->GetALink(aAlinkColor);
1810 : }
1811 :
1812 0 : return NS_OK;
1813 : }
1814 :
1815 : NS_IMETHODIMP
1816 0 : nsHTMLDocument::SetAlinkColor(const nsAString& aAlinkColor)
1817 : {
1818 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1819 0 : if (body) {
1820 0 : body->SetALink(aAlinkColor);
1821 : }
1822 :
1823 0 : return NS_OK;
1824 : }
1825 :
1826 : NS_IMETHODIMP
1827 0 : nsHTMLDocument::GetLinkColor(nsAString& aLinkColor)
1828 : {
1829 0 : aLinkColor.Truncate();
1830 :
1831 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1832 0 : if (body) {
1833 0 : body->GetLink(aLinkColor);
1834 : }
1835 :
1836 0 : return NS_OK;
1837 : }
1838 :
1839 : NS_IMETHODIMP
1840 0 : nsHTMLDocument::SetLinkColor(const nsAString& aLinkColor)
1841 : {
1842 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1843 0 : if (body) {
1844 0 : body->SetLink(aLinkColor);
1845 : }
1846 :
1847 0 : return NS_OK;
1848 : }
1849 :
1850 : NS_IMETHODIMP
1851 0 : nsHTMLDocument::GetVlinkColor(nsAString& aVlinkColor)
1852 : {
1853 0 : aVlinkColor.Truncate();
1854 :
1855 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1856 0 : if (body) {
1857 0 : body->GetVLink(aVlinkColor);
1858 : }
1859 :
1860 0 : return NS_OK;
1861 : }
1862 :
1863 : NS_IMETHODIMP
1864 0 : nsHTMLDocument::SetVlinkColor(const nsAString& aVlinkColor)
1865 : {
1866 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1867 0 : if (body) {
1868 0 : body->SetVLink(aVlinkColor);
1869 : }
1870 :
1871 0 : return NS_OK;
1872 : }
1873 :
1874 : NS_IMETHODIMP
1875 0 : nsHTMLDocument::GetBgColor(nsAString& aBgColor)
1876 : {
1877 0 : aBgColor.Truncate();
1878 :
1879 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1880 0 : if (body) {
1881 0 : body->GetBgColor(aBgColor);
1882 : }
1883 :
1884 0 : return NS_OK;
1885 : }
1886 :
1887 : NS_IMETHODIMP
1888 0 : nsHTMLDocument::SetBgColor(const nsAString& aBgColor)
1889 : {
1890 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1891 0 : if (body) {
1892 0 : body->SetBgColor(aBgColor);
1893 : }
1894 :
1895 0 : return NS_OK;
1896 : }
1897 :
1898 : NS_IMETHODIMP
1899 0 : nsHTMLDocument::GetFgColor(nsAString& aFgColor)
1900 : {
1901 0 : aFgColor.Truncate();
1902 :
1903 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1904 0 : if (body) {
1905 0 : body->GetText(aFgColor);
1906 : }
1907 :
1908 0 : return NS_OK;
1909 : }
1910 :
1911 : NS_IMETHODIMP
1912 0 : nsHTMLDocument::SetFgColor(const nsAString& aFgColor)
1913 : {
1914 0 : nsCOMPtr<nsIDOMHTMLBodyElement> body = do_QueryInterface(GetBodyElement());
1915 0 : if (body) {
1916 0 : body->SetText(aFgColor);
1917 : }
1918 :
1919 0 : return NS_OK;
1920 : }
1921 :
1922 :
1923 : NS_IMETHODIMP
1924 0 : nsHTMLDocument::GetEmbeds(nsIDOMHTMLCollection** aEmbeds)
1925 : {
1926 0 : if (!mEmbeds) {
1927 0 : mEmbeds = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::embed, nsGkAtoms::embed);
1928 : }
1929 :
1930 0 : *aEmbeds = mEmbeds;
1931 0 : NS_ADDREF(*aEmbeds);
1932 :
1933 0 : return NS_OK;
1934 : }
1935 :
1936 : NS_IMETHODIMP
1937 0 : nsHTMLDocument::GetSelection(nsISelection** aReturn)
1938 : {
1939 0 : nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetScopeObject());
1940 0 : nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(window);
1941 0 : NS_ENSURE_TRUE(pwin, NS_OK);
1942 0 : NS_ASSERTION(pwin->IsInnerWindow(), "Should have inner window here!");
1943 0 : NS_ENSURE_TRUE(pwin->GetOuterWindow() &&
1944 : pwin->GetOuterWindow()->GetCurrentInnerWindow() == pwin,
1945 : NS_OK);
1946 :
1947 0 : return window->GetSelection(aReturn);
1948 :
1949 : }
1950 :
1951 : NS_IMETHODIMP
1952 0 : nsHTMLDocument::CaptureEvents(PRInt32 aEventFlags)
1953 : {
1954 0 : ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
1955 0 : return NS_OK;
1956 : }
1957 :
1958 : NS_IMETHODIMP
1959 0 : nsHTMLDocument::ReleaseEvents(PRInt32 aEventFlags)
1960 : {
1961 0 : ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
1962 0 : return NS_OK;
1963 : }
1964 :
1965 : NS_IMETHODIMP
1966 0 : nsHTMLDocument::RouteEvent(nsIDOMEvent* aEvt)
1967 : {
1968 0 : ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
1969 0 : return NS_OK;
1970 : }
1971 :
1972 : // readonly attribute DOMString compatMode;
1973 : // Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
1974 : // in almost standards or full standards mode. See bug 105640. This was
1975 : // implemented to match MSIE's compatMode property
1976 : NS_IMETHODIMP
1977 0 : nsHTMLDocument::GetCompatMode(nsAString& aCompatMode)
1978 : {
1979 0 : NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks ||
1980 : mCompatMode == eCompatibility_AlmostStandards ||
1981 : mCompatMode == eCompatibility_FullStandards,
1982 : "mCompatMode is neither quirks nor strict for this document");
1983 :
1984 0 : if (mCompatMode == eCompatibility_NavQuirks) {
1985 0 : aCompatMode.AssignLiteral("BackCompat");
1986 : } else {
1987 0 : aCompatMode.AssignLiteral("CSS1Compat");
1988 : }
1989 :
1990 0 : return NS_OK;
1991 : }
1992 :
1993 : // Mapped to document.embeds for NS4 compatibility
1994 : NS_IMETHODIMP
1995 0 : nsHTMLDocument::GetPlugins(nsIDOMHTMLCollection** aPlugins)
1996 : {
1997 0 : *aPlugins = nsnull;
1998 :
1999 0 : return GetEmbeds(aPlugins);
2000 : }
2001 :
2002 : nsresult
2003 0 : nsHTMLDocument::ResolveName(const nsAString& aName,
2004 : nsIContent *aForm,
2005 : nsISupports **aResult,
2006 : nsWrapperCache **aCache)
2007 : {
2008 0 : *aResult = nsnull;
2009 0 : *aCache = nsnull;
2010 :
2011 0 : nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
2012 0 : if (!entry) {
2013 0 : return NS_OK;
2014 : }
2015 :
2016 0 : PRUint32 length = 0;
2017 0 : nsBaseContentList *list = entry->GetNameContentList();
2018 0 : if (list) {
2019 0 : list->GetLength(&length);
2020 : }
2021 :
2022 0 : if (length > 0) {
2023 0 : if (length == 1) {
2024 : // Only one element in the list, return the element instead of
2025 : // returning the list
2026 :
2027 0 : nsIContent *node = list->GetNodeAt(0);
2028 0 : if (!aForm || nsContentUtils::BelongsInForm(aForm, node)) {
2029 0 : NS_ADDREF(*aResult = node);
2030 0 : *aCache = node;
2031 : }
2032 :
2033 0 : return NS_OK;
2034 : }
2035 :
2036 : // The list contains more than one element, return the whole
2037 : // list, unless...
2038 :
2039 0 : if (aForm) {
2040 : // ... we're called from a form, in that case we create a
2041 : // nsFormContentList which will filter out the elements in the
2042 : // list that don't belong to aForm
2043 :
2044 0 : nsFormContentList *fc_list = new nsFormContentList(aForm, *list);
2045 0 : NS_ENSURE_TRUE(fc_list, NS_ERROR_OUT_OF_MEMORY);
2046 :
2047 : PRUint32 len;
2048 0 : fc_list->GetLength(&len);
2049 :
2050 0 : if (len < 2) {
2051 : // After the nsFormContentList is done filtering there's either
2052 : // nothing or one element in the list. Return that element, or null
2053 : // if there's no element in the list.
2054 :
2055 0 : nsIContent *node = fc_list->GetNodeAt(0);
2056 :
2057 0 : NS_IF_ADDREF(*aResult = node);
2058 0 : *aCache = node;
2059 :
2060 0 : delete fc_list;
2061 :
2062 0 : return NS_OK;
2063 : }
2064 :
2065 0 : list = fc_list;
2066 : }
2067 :
2068 0 : return CallQueryInterface(list, aResult);
2069 : }
2070 :
2071 : // No named items were found, see if there's one registerd by id for
2072 : // aName. If we get this far, FindNamedItems() will have been called
2073 : // for aName, so we're guaranteed that if there is an element with
2074 : // the id aName, it'll be entry's IdContent.
2075 :
2076 0 : Element *e = entry->GetIdElement();
2077 :
2078 0 : if (e && e->IsHTML()) {
2079 0 : nsIAtom *tag = e->Tag();
2080 :
2081 0 : if ((tag == nsGkAtoms::embed ||
2082 : tag == nsGkAtoms::img ||
2083 : tag == nsGkAtoms::object ||
2084 : tag == nsGkAtoms::applet) &&
2085 0 : (!aForm || nsContentUtils::BelongsInForm(aForm, e))) {
2086 0 : NS_ADDREF(*aResult = e);
2087 0 : *aCache = e;
2088 : }
2089 : }
2090 :
2091 0 : return NS_OK;
2092 : }
2093 :
2094 : //----------------------------
2095 :
2096 : // forms related stuff
2097 :
2098 : NS_IMETHODIMP
2099 0 : nsHTMLDocument::GetForms(nsIDOMHTMLCollection** aForms)
2100 : {
2101 0 : nsContentList *forms = nsHTMLDocument::GetForms();
2102 0 : if (!forms)
2103 0 : return NS_ERROR_OUT_OF_MEMORY;
2104 :
2105 0 : NS_ADDREF(*aForms = forms);
2106 0 : return NS_OK;
2107 : }
2108 :
2109 : nsContentList*
2110 0 : nsHTMLDocument::GetForms()
2111 : {
2112 0 : if (!mForms) {
2113 0 : mForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form, nsGkAtoms::form);
2114 : }
2115 :
2116 0 : return mForms;
2117 : }
2118 :
2119 0 : static bool MatchFormControls(nsIContent* aContent, PRInt32 aNamespaceID,
2120 : nsIAtom* aAtom, void* aData)
2121 : {
2122 0 : return aContent->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL);
2123 : }
2124 :
2125 : nsContentList*
2126 0 : nsHTMLDocument::GetFormControls()
2127 : {
2128 0 : if (!mFormControls) {
2129 0 : mFormControls = new nsContentList(this, MatchFormControls, nsnull, nsnull);
2130 : }
2131 :
2132 0 : return mFormControls;
2133 : }
2134 :
2135 : nsresult
2136 0 : nsHTMLDocument::CreateAndAddWyciwygChannel(void)
2137 : {
2138 0 : nsresult rv = NS_OK;
2139 0 : nsCAutoString url, originalSpec;
2140 :
2141 0 : mDocumentURI->GetSpec(originalSpec);
2142 :
2143 : // Generate the wyciwyg url
2144 0 : url = NS_LITERAL_CSTRING("wyciwyg://")
2145 0 : + nsPrintfCString("%d", gWyciwygSessionCnt++)
2146 0 : + NS_LITERAL_CSTRING("/")
2147 0 : + originalSpec;
2148 :
2149 0 : nsCOMPtr<nsIURI> wcwgURI;
2150 0 : NS_NewURI(getter_AddRefs(wcwgURI), url);
2151 :
2152 : // Create the nsIWyciwygChannel to store out-of-band
2153 : // document.write() script to cache
2154 0 : nsCOMPtr<nsIChannel> channel;
2155 : // Create a wyciwyg Channel
2156 0 : rv = NS_NewChannel(getter_AddRefs(channel), wcwgURI);
2157 0 : NS_ENSURE_SUCCESS(rv, rv);
2158 :
2159 0 : mWyciwygChannel = do_QueryInterface(channel);
2160 :
2161 0 : mWyciwygChannel->SetSecurityInfo(mSecurityInfo);
2162 :
2163 : // Note: we want to treat this like a "previous document" hint so that,
2164 : // e.g. a <meta> tag in the document.write content can override it.
2165 0 : SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc);
2166 0 : mWyciwygChannel->SetCharsetAndSource(kCharsetFromHintPrevDoc,
2167 0 : GetDocumentCharacterSet());
2168 :
2169 : // Use our new principal
2170 0 : channel->SetOwner(NodePrincipal());
2171 :
2172 : // Inherit load flags from the original document's channel
2173 0 : channel->SetLoadFlags(mLoadFlags);
2174 :
2175 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
2176 :
2177 : // Use the Parent document's loadgroup to trigger load notifications
2178 0 : if (loadGroup && channel) {
2179 0 : rv = channel->SetLoadGroup(loadGroup);
2180 0 : NS_ENSURE_SUCCESS(rv, rv);
2181 :
2182 0 : nsLoadFlags loadFlags = 0;
2183 0 : channel->GetLoadFlags(&loadFlags);
2184 0 : loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
2185 0 : channel->SetLoadFlags(loadFlags);
2186 :
2187 0 : channel->SetOriginalURI(wcwgURI);
2188 :
2189 0 : rv = loadGroup->AddRequest(mWyciwygChannel, nsnull);
2190 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to add request to load group.");
2191 : }
2192 :
2193 0 : return rv;
2194 : }
2195 :
2196 : nsresult
2197 0 : nsHTMLDocument::RemoveWyciwygChannel(void)
2198 : {
2199 0 : nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
2200 :
2201 : // note there can be a write request without a load group if
2202 : // this is a synchronously constructed about:blank document
2203 0 : if (loadGroup && mWyciwygChannel) {
2204 0 : mWyciwygChannel->CloseCacheEntry(NS_OK);
2205 0 : loadGroup->RemoveRequest(mWyciwygChannel, nsnull, NS_OK);
2206 : }
2207 :
2208 0 : mWyciwygChannel = nsnull;
2209 :
2210 0 : return NS_OK;
2211 : }
2212 :
2213 : void *
2214 0 : nsHTMLDocument::GenerateParserKey(void)
2215 : {
2216 0 : if (!mScriptLoader) {
2217 : // If we don't have a script loader, then the parser probably isn't parsing
2218 : // anything anyway, so just return null.
2219 0 : return nsnull;
2220 : }
2221 :
2222 : // The script loader provides us with the currently executing script element,
2223 : // which is guaranteed to be unique per script.
2224 0 : nsIScriptElement* script = mScriptLoader->GetCurrentParserInsertedScript();
2225 0 : if (script && mParser && mParser->IsScriptCreated()) {
2226 0 : nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
2227 0 : if (creatorParser != mParser) {
2228 : // Make scripts that aren't inserted by the active parser of this document
2229 : // participate in the context of the script that document.open()ed
2230 : // this document.
2231 0 : return nsnull;
2232 : }
2233 : }
2234 0 : return script;
2235 : }
2236 :
2237 : /* attribute DOMString designMode; */
2238 : NS_IMETHODIMP
2239 0 : nsHTMLDocument::GetDesignMode(nsAString & aDesignMode)
2240 : {
2241 0 : if (HasFlag(NODE_IS_EDITABLE)) {
2242 0 : aDesignMode.AssignLiteral("on");
2243 : }
2244 : else {
2245 0 : aDesignMode.AssignLiteral("off");
2246 : }
2247 0 : return NS_OK;
2248 : }
2249 :
2250 : void
2251 246 : nsHTMLDocument::MaybeEditingStateChanged()
2252 : {
2253 246 : if (mUpdateNestLevel == 0 && (mContentEditableCount > 0) != IsEditingOn()) {
2254 0 : if (nsContentUtils::IsSafeToRunScript()) {
2255 0 : EditingStateChanged();
2256 0 : } else if (!mInDestructor) {
2257 : nsContentUtils::AddScriptRunner(
2258 0 : NS_NewRunnableMethod(this, &nsHTMLDocument::MaybeEditingStateChanged));
2259 : }
2260 : }
2261 246 : }
2262 :
2263 : void
2264 246 : nsHTMLDocument::EndUpdate(nsUpdateType aUpdateType)
2265 : {
2266 246 : nsDocument::EndUpdate(aUpdateType);
2267 :
2268 246 : MaybeEditingStateChanged();
2269 246 : }
2270 :
2271 :
2272 : // Helper class, used below in ChangeContentEditableCount().
2273 : class DeferredContentEditableCountChangeEvent : public nsRunnable
2274 0 : {
2275 : public:
2276 0 : DeferredContentEditableCountChangeEvent(nsHTMLDocument *aDoc,
2277 : nsIContent *aElement)
2278 : : mDoc(aDoc)
2279 0 : , mElement(aElement)
2280 : {
2281 0 : }
2282 :
2283 0 : NS_IMETHOD Run() {
2284 0 : if (mElement && mElement->OwnerDoc() == mDoc) {
2285 0 : mDoc->DeferredContentEditableCountChange(mElement);
2286 : }
2287 0 : return NS_OK;
2288 : }
2289 :
2290 : private:
2291 : nsRefPtr<nsHTMLDocument> mDoc;
2292 : nsCOMPtr<nsIContent> mElement;
2293 : };
2294 :
2295 : nsresult
2296 0 : nsHTMLDocument::ChangeContentEditableCount(nsIContent *aElement,
2297 : PRInt32 aChange)
2298 : {
2299 : NS_ASSERTION(mContentEditableCount + aChange >= 0,
2300 : "Trying to decrement too much.");
2301 :
2302 0 : mContentEditableCount += aChange;
2303 :
2304 : nsContentUtils::AddScriptRunner(
2305 0 : new DeferredContentEditableCountChangeEvent(this, aElement));
2306 :
2307 0 : return NS_OK;
2308 : }
2309 :
2310 : void
2311 0 : nsHTMLDocument::DeferredContentEditableCountChange(nsIContent *aElement)
2312 : {
2313 0 : if (mParser ||
2314 0 : (mUpdateNestLevel > 0 && (mContentEditableCount > 0) != IsEditingOn())) {
2315 0 : return;
2316 : }
2317 :
2318 0 : EditingState oldState = mEditingState;
2319 :
2320 0 : nsresult rv = EditingStateChanged();
2321 0 : NS_ENSURE_SUCCESS(rv, );
2322 :
2323 0 : if (oldState == mEditingState && mEditingState == eContentEditable) {
2324 : // We just changed the contentEditable state of a node, we need to reset
2325 : // the spellchecking state of that node.
2326 0 : nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
2327 0 : if (node) {
2328 0 : nsPIDOMWindow *window = GetWindow();
2329 0 : if (!window)
2330 : return;
2331 :
2332 0 : nsIDocShell *docshell = window->GetDocShell();
2333 0 : if (!docshell)
2334 : return;
2335 :
2336 : nsCOMPtr<nsIEditorDocShell> editorDocShell =
2337 0 : do_QueryInterface(docshell, &rv);
2338 0 : NS_ENSURE_SUCCESS(rv, );
2339 :
2340 0 : nsCOMPtr<nsIEditor> editor;
2341 0 : editorDocShell->GetEditor(getter_AddRefs(editor));
2342 0 : if (editor) {
2343 0 : nsRefPtr<nsRange> range = new nsRange();
2344 0 : rv = range->SelectNode(node);
2345 0 : if (NS_FAILED(rv)) {
2346 : // The node might be detached from the document at this point,
2347 : // which would cause this call to fail. In this case, we can
2348 : // safely ignore the contenteditable count change.
2349 : return;
2350 : }
2351 :
2352 0 : nsCOMPtr<nsIInlineSpellChecker> spellChecker;
2353 0 : rv = editor->GetInlineSpellChecker(false,
2354 0 : getter_AddRefs(spellChecker));
2355 0 : NS_ENSURE_SUCCESS(rv, );
2356 :
2357 0 : if (spellChecker) {
2358 0 : rv = spellChecker->SpellCheckRange(range);
2359 : }
2360 : }
2361 : }
2362 : }
2363 : }
2364 :
2365 : static bool
2366 0 : DocAllResultMatch(nsIContent* aContent, PRInt32 aNamespaceID, nsIAtom* aAtom,
2367 : void* aData)
2368 : {
2369 0 : if (aContent->GetID() == aAtom) {
2370 0 : return true;
2371 : }
2372 :
2373 0 : nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent);
2374 0 : if (!elm) {
2375 0 : return false;
2376 : }
2377 :
2378 0 : nsIAtom* tag = elm->Tag();
2379 0 : if (tag != nsGkAtoms::a &&
2380 : tag != nsGkAtoms::applet &&
2381 : tag != nsGkAtoms::button &&
2382 : tag != nsGkAtoms::embed &&
2383 : tag != nsGkAtoms::form &&
2384 : tag != nsGkAtoms::iframe &&
2385 : tag != nsGkAtoms::img &&
2386 : tag != nsGkAtoms::input &&
2387 : tag != nsGkAtoms::map &&
2388 : tag != nsGkAtoms::meta &&
2389 : tag != nsGkAtoms::object &&
2390 : tag != nsGkAtoms::select &&
2391 : tag != nsGkAtoms::textarea) {
2392 0 : return false;
2393 : }
2394 :
2395 0 : const nsAttrValue* val = elm->GetParsedAttr(nsGkAtoms::name);
2396 0 : return val && val->Type() == nsAttrValue::eAtom &&
2397 0 : val->GetAtomValue() == aAtom;
2398 : }
2399 :
2400 :
2401 : nsISupports*
2402 0 : nsHTMLDocument::GetDocumentAllResult(const nsAString& aID,
2403 : nsWrapperCache** aCache,
2404 : nsresult *aResult)
2405 : {
2406 0 : *aCache = nsnull;
2407 0 : *aResult = NS_OK;
2408 :
2409 0 : nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
2410 0 : if (!entry) {
2411 0 : *aResult = NS_ERROR_OUT_OF_MEMORY;
2412 :
2413 0 : return nsnull;
2414 : }
2415 :
2416 0 : Element* root = GetRootElement();
2417 0 : if (!root) {
2418 0 : return nsnull;
2419 : }
2420 :
2421 0 : nsRefPtr<nsContentList> docAllList = entry->GetDocAllList();
2422 0 : if (!docAllList) {
2423 0 : nsCOMPtr<nsIAtom> id = do_GetAtom(aID);
2424 :
2425 : docAllList = new nsContentList(root, DocAllResultMatch,
2426 0 : nsnull, nsnull, true, id);
2427 0 : entry->SetDocAllList(docAllList);
2428 : }
2429 :
2430 : // Check if there are more than 1 entries. Do this by getting the second one
2431 : // rather than the length since getting the length always requires walking
2432 : // the entire document.
2433 :
2434 0 : nsIContent* cont = docAllList->Item(1, true);
2435 0 : if (cont) {
2436 0 : *aCache = docAllList;
2437 0 : return static_cast<nsINodeList*>(docAllList);
2438 : }
2439 :
2440 : // There's only 0 or 1 items. Return the first one or null.
2441 0 : *aCache = cont = docAllList->Item(0, true);
2442 :
2443 0 : return cont;
2444 : }
2445 :
2446 : static void
2447 0 : NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument)
2448 : {
2449 0 : for (nsIContent* child = aNode->GetFirstChild();
2450 : child;
2451 0 : child = child->GetNextSibling()) {
2452 0 : if (child->IsElement()) {
2453 0 : child->AsElement()->UpdateState(true);
2454 : }
2455 0 : NotifyEditableStateChange(child, aDocument);
2456 : }
2457 0 : }
2458 :
2459 : void
2460 0 : nsHTMLDocument::TearingDownEditor(nsIEditor *aEditor)
2461 : {
2462 0 : if (IsEditingOn()) {
2463 0 : EditingState oldState = mEditingState;
2464 0 : mEditingState = eTearingDown;
2465 :
2466 0 : nsCOMPtr<nsIPresShell> presShell = GetShell();
2467 0 : if (!presShell)
2468 : return;
2469 :
2470 0 : nsCOMArray<nsIStyleSheet> agentSheets;
2471 0 : presShell->GetAgentStyleSheets(agentSheets);
2472 :
2473 0 : RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
2474 0 : if (oldState == eDesignMode)
2475 0 : RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
2476 :
2477 0 : presShell->SetAgentStyleSheets(agentSheets);
2478 :
2479 0 : presShell->ReconstructStyleData();
2480 : }
2481 : }
2482 :
2483 : nsresult
2484 0 : nsHTMLDocument::TurnEditingOff()
2485 : {
2486 0 : NS_ASSERTION(mEditingState != eOff, "Editing is already off.");
2487 :
2488 0 : nsPIDOMWindow *window = GetWindow();
2489 0 : if (!window)
2490 0 : return NS_ERROR_FAILURE;
2491 :
2492 0 : nsIDocShell *docshell = window->GetDocShell();
2493 0 : if (!docshell)
2494 0 : return NS_ERROR_FAILURE;
2495 :
2496 : nsresult rv;
2497 0 : nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv);
2498 0 : NS_ENSURE_SUCCESS(rv, rv);
2499 :
2500 : // turn editing off
2501 0 : rv = editSession->TearDownEditorOnWindow(window);
2502 0 : NS_ENSURE_SUCCESS(rv, rv);
2503 :
2504 0 : mEditingState = eOff;
2505 :
2506 0 : return NS_OK;
2507 : }
2508 :
2509 0 : static bool HasPresShell(nsPIDOMWindow *aWindow)
2510 : {
2511 0 : nsIDocShell *docShell = aWindow->GetDocShell();
2512 0 : if (!docShell)
2513 0 : return false;
2514 0 : nsCOMPtr<nsIPresShell> presShell;
2515 0 : docShell->GetPresShell(getter_AddRefs(presShell));
2516 0 : return presShell != nsnull;
2517 : }
2518 :
2519 : nsresult
2520 0 : nsHTMLDocument::SetEditingState(EditingState aState)
2521 : {
2522 0 : mEditingState = aState;
2523 0 : return NS_OK;
2524 : }
2525 :
2526 : nsresult
2527 0 : nsHTMLDocument::EditingStateChanged()
2528 : {
2529 0 : if (mRemovedFromDocShell) {
2530 0 : return NS_OK;
2531 : }
2532 :
2533 0 : if (mEditingState == eSettingUp || mEditingState == eTearingDown) {
2534 : // XXX We shouldn't recurse.
2535 0 : return NS_OK;
2536 : }
2537 :
2538 0 : bool designMode = HasFlag(NODE_IS_EDITABLE);
2539 : EditingState newState = designMode ? eDesignMode :
2540 0 : (mContentEditableCount > 0 ? eContentEditable : eOff);
2541 0 : if (mEditingState == newState) {
2542 : // No changes in editing mode.
2543 0 : return NS_OK;
2544 : }
2545 :
2546 0 : if (newState == eOff) {
2547 : // Editing is being turned off.
2548 0 : nsAutoScriptBlocker scriptBlocker;
2549 0 : NotifyEditableStateChange(this, this);
2550 0 : return TurnEditingOff();
2551 : }
2552 :
2553 : // Flush out style changes on our _parent_ document, if any, so that
2554 : // our check for a presshell won't get stale information.
2555 0 : if (mParentDocument) {
2556 0 : mParentDocument->FlushPendingNotifications(Flush_Style);
2557 : }
2558 :
2559 : // get editing session, make sure this is a strong reference so the
2560 : // window can't get deleted during the rest of this call.
2561 0 : nsCOMPtr<nsPIDOMWindow> window = GetWindow();
2562 0 : if (!window)
2563 0 : return NS_ERROR_FAILURE;
2564 :
2565 0 : nsIDocShell *docshell = window->GetDocShell();
2566 0 : if (!docshell)
2567 0 : return NS_ERROR_FAILURE;
2568 :
2569 : nsresult rv;
2570 0 : nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv);
2571 0 : NS_ENSURE_SUCCESS(rv, rv);
2572 :
2573 0 : nsCOMPtr<nsIEditor> existingEditor;
2574 0 : editSession->GetEditorForWindow(window, getter_AddRefs(existingEditor));
2575 0 : if (existingEditor) {
2576 : // We might already have an editor if it was set up for mail, let's see
2577 : // if this is actually the case.
2578 0 : nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(existingEditor);
2579 0 : NS_ABORT_IF_FALSE(htmlEditor, "If we have an editor, it must be an HTML editor");
2580 0 : PRUint32 flags = 0;
2581 0 : existingEditor->GetFlags(&flags);
2582 0 : if (flags & nsIPlaintextEditor::eEditorMailMask) {
2583 : // We already have a mail editor, then we should not attempt to create
2584 : // another one.
2585 0 : return NS_OK;
2586 : }
2587 : }
2588 :
2589 0 : if (!HasPresShell(window)) {
2590 : // We should not make the window editable or setup its editor.
2591 : // It's probably style=display:none.
2592 0 : return NS_OK;
2593 : }
2594 :
2595 0 : bool makeWindowEditable = mEditingState == eOff;
2596 0 : bool updateState = false;
2597 0 : bool spellRecheckAll = false;
2598 0 : nsCOMPtr<nsIEditor> editor;
2599 :
2600 : {
2601 0 : EditingState oldState = mEditingState;
2602 0 : nsAutoEditingState push(this, eSettingUp);
2603 :
2604 0 : if (makeWindowEditable) {
2605 : // Editing is being turned on (through designMode or contentEditable)
2606 : // Turn on editor.
2607 : // XXX This can cause flushing which can change the editing state, so make
2608 : // sure to avoid recursing.
2609 0 : rv = editSession->MakeWindowEditable(window, "html", false, false,
2610 0 : true);
2611 0 : NS_ENSURE_SUCCESS(rv, rv);
2612 : }
2613 :
2614 : // XXX Need to call TearDownEditorOnWindow for all failures.
2615 : nsCOMPtr<nsIEditorDocShell> editorDocShell =
2616 0 : do_QueryInterface(docshell, &rv);
2617 0 : NS_ENSURE_SUCCESS(rv, rv);
2618 :
2619 0 : editorDocShell->GetEditor(getter_AddRefs(editor));
2620 0 : if (!editor)
2621 0 : return NS_ERROR_FAILURE;
2622 :
2623 0 : nsCOMPtr<nsIPresShell> presShell = GetShell();
2624 0 : NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
2625 :
2626 : // If we're entering the design mode, put the selection at the beginning of
2627 : // the document for compatibility reasons.
2628 0 : if (designMode && oldState == eOff) {
2629 0 : editor->BeginningOfDocument();
2630 : }
2631 :
2632 0 : nsCOMArray<nsIStyleSheet> agentSheets;
2633 0 : rv = presShell->GetAgentStyleSheets(agentSheets);
2634 0 : NS_ENSURE_SUCCESS(rv, rv);
2635 :
2636 0 : nsCOMPtr<nsIURI> uri;
2637 0 : rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
2638 0 : NS_ENSURE_SUCCESS(rv, rv);
2639 :
2640 0 : nsRefPtr<nsCSSStyleSheet> sheet;
2641 0 : rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
2642 0 : NS_ENSURE_TRUE(sheet, rv);
2643 :
2644 0 : rv = agentSheets.AppendObject(sheet);
2645 0 : NS_ENSURE_SUCCESS(rv, rv);
2646 :
2647 : // Should we update the editable state of all the nodes in the document? We
2648 : // need to do this when the designMode value changes, as that overrides
2649 : // specific states on the elements.
2650 0 : if (designMode) {
2651 : // designMode is being turned on (overrides contentEditable).
2652 0 : rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("resource://gre/res/designmode.css"));
2653 0 : NS_ENSURE_SUCCESS(rv, rv);
2654 :
2655 0 : rv = LoadChromeSheetSync(uri, true, getter_AddRefs(sheet));
2656 0 : NS_ENSURE_TRUE(sheet, rv);
2657 :
2658 0 : rv = agentSheets.AppendObject(sheet);
2659 0 : NS_ENSURE_SUCCESS(rv, rv);
2660 :
2661 : // Disable scripting and plugins.
2662 0 : rv = editSession->DisableJSAndPlugins(window);
2663 0 : NS_ENSURE_SUCCESS(rv, rv);
2664 :
2665 0 : updateState = true;
2666 0 : spellRecheckAll = oldState == eContentEditable;
2667 : }
2668 0 : else if (oldState == eDesignMode) {
2669 : // designMode is being turned off (contentEditable is still on).
2670 0 : RemoveFromAgentSheets(agentSheets, NS_LITERAL_STRING("resource://gre/res/designmode.css"));
2671 :
2672 0 : rv = editSession->RestoreJSAndPlugins(window);
2673 0 : NS_ENSURE_SUCCESS(rv, rv);
2674 :
2675 0 : updateState = true;
2676 : }
2677 :
2678 0 : rv = presShell->SetAgentStyleSheets(agentSheets);
2679 0 : NS_ENSURE_SUCCESS(rv, rv);
2680 :
2681 0 : presShell->ReconstructStyleData();
2682 : }
2683 :
2684 0 : mEditingState = newState;
2685 :
2686 0 : if (makeWindowEditable) {
2687 : // Set the editor to not insert br's on return when in p
2688 : // elements by default.
2689 : // XXX Do we only want to do this for designMode?
2690 : bool unused;
2691 0 : rv = ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), false,
2692 0 : NS_LITERAL_STRING("false"), &unused);
2693 :
2694 0 : if (NS_FAILED(rv)) {
2695 : // Editor setup failed. Editing is not on after all.
2696 : // XXX Should we reset the editable flag on nodes?
2697 0 : editSession->TearDownEditorOnWindow(window);
2698 0 : mEditingState = eOff;
2699 :
2700 0 : return rv;
2701 : }
2702 : }
2703 :
2704 0 : if (updateState) {
2705 0 : nsAutoScriptBlocker scriptBlocker;
2706 0 : NotifyEditableStateChange(this, this);
2707 : }
2708 :
2709 : // Resync the editor's spellcheck state.
2710 0 : if (spellRecheckAll) {
2711 0 : nsCOMPtr<nsISelectionController> selcon;
2712 0 : nsresult rv = editor->GetSelectionController(getter_AddRefs(selcon));
2713 0 : NS_ENSURE_SUCCESS(rv, rv);
2714 :
2715 0 : nsCOMPtr<nsISelection> spellCheckSelection;
2716 0 : rv = selcon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
2717 0 : getter_AddRefs(spellCheckSelection));
2718 0 : if (NS_SUCCEEDED(rv)) {
2719 0 : spellCheckSelection->RemoveAllRanges();
2720 : }
2721 : }
2722 0 : editor->SyncRealTimeSpell();
2723 :
2724 0 : return NS_OK;
2725 : }
2726 :
2727 : NS_IMETHODIMP
2728 0 : nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
2729 : {
2730 0 : nsresult rv = NS_OK;
2731 :
2732 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
2733 0 : nsCOMPtr<nsIPrincipal> subject;
2734 0 : nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
2735 0 : rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
2736 0 : NS_ENSURE_SUCCESS(rv, rv);
2737 0 : if (subject) {
2738 : bool subsumes;
2739 0 : rv = subject->Subsumes(NodePrincipal(), &subsumes);
2740 0 : NS_ENSURE_SUCCESS(rv, rv);
2741 :
2742 0 : NS_ENSURE_TRUE(subsumes, NS_ERROR_DOM_PROP_ACCESS_DENIED);
2743 : }
2744 : }
2745 :
2746 0 : bool editableMode = HasFlag(NODE_IS_EDITABLE);
2747 0 : if (aDesignMode.LowerCaseEqualsASCII(editableMode ? "off" : "on")) {
2748 0 : SetEditableFlag(!editableMode);
2749 :
2750 0 : return EditingStateChanged();
2751 : }
2752 :
2753 0 : return NS_OK;
2754 : }
2755 :
2756 : nsresult
2757 0 : nsHTMLDocument::GetMidasCommandManager(nsICommandManager** aCmdMgr)
2758 : {
2759 : // initialize return value
2760 0 : NS_ENSURE_ARG_POINTER(aCmdMgr);
2761 :
2762 : // check if we have it cached
2763 0 : if (mMidasCommandManager) {
2764 0 : NS_ADDREF(*aCmdMgr = mMidasCommandManager);
2765 0 : return NS_OK;
2766 : }
2767 :
2768 0 : *aCmdMgr = nsnull;
2769 :
2770 0 : nsPIDOMWindow *window = GetWindow();
2771 0 : if (!window)
2772 0 : return NS_ERROR_FAILURE;
2773 :
2774 0 : nsIDocShell *docshell = window->GetDocShell();
2775 0 : if (!docshell)
2776 0 : return NS_ERROR_FAILURE;
2777 :
2778 0 : mMidasCommandManager = do_GetInterface(docshell);
2779 0 : if (!mMidasCommandManager)
2780 0 : return NS_ERROR_FAILURE;
2781 :
2782 0 : NS_ADDREF(*aCmdMgr = mMidasCommandManager);
2783 :
2784 0 : return NS_OK;
2785 : }
2786 :
2787 :
2788 : struct MidasCommand {
2789 : const char* incomingCommandString;
2790 : const char* internalCommandString;
2791 : const char* internalParamString;
2792 : bool useNewParam;
2793 : bool convertToBoolean;
2794 : };
2795 :
2796 : static const struct MidasCommand gMidasCommandTable[] = {
2797 : { "bold", "cmd_bold", "", true, false },
2798 : { "italic", "cmd_italic", "", true, false },
2799 : { "underline", "cmd_underline", "", true, false },
2800 : { "strikethrough", "cmd_strikethrough", "", true, false },
2801 : { "subscript", "cmd_subscript", "", true, false },
2802 : { "superscript", "cmd_superscript", "", true, false },
2803 : { "cut", "cmd_cut", "", true, false },
2804 : { "copy", "cmd_copy", "", true, false },
2805 : { "paste", "cmd_paste", "", true, false },
2806 : { "delete", "cmd_delete", "", true, false },
2807 : { "selectall", "cmd_selectAll", "", true, false },
2808 : { "undo", "cmd_undo", "", true, false },
2809 : { "redo", "cmd_redo", "", true, false },
2810 : { "indent", "cmd_indent", "", true, false },
2811 : { "outdent", "cmd_outdent", "", true, false },
2812 : { "backcolor", "cmd_backgroundColor", "", false, false },
2813 : { "forecolor", "cmd_fontColor", "", false, false },
2814 : { "hilitecolor", "cmd_highlight", "", false, false },
2815 : { "fontname", "cmd_fontFace", "", false, false },
2816 : { "fontsize", "cmd_fontSize", "", false, false },
2817 : { "increasefontsize", "cmd_increaseFont", "", false, false },
2818 : { "decreasefontsize", "cmd_decreaseFont", "", false, false },
2819 : { "inserthorizontalrule", "cmd_insertHR", "", true, false },
2820 : { "createlink", "cmd_insertLinkNoUI", "", false, false },
2821 : { "insertimage", "cmd_insertImageNoUI", "", false, false },
2822 : { "inserthtml", "cmd_insertHTML", "", false, false },
2823 : { "gethtml", "cmd_getContents", "", false, false },
2824 : { "justifyleft", "cmd_align", "left", true, false },
2825 : { "justifyright", "cmd_align", "right", true, false },
2826 : { "justifycenter", "cmd_align", "center", true, false },
2827 : { "justifyfull", "cmd_align", "justify", true, false },
2828 : { "removeformat", "cmd_removeStyles", "", true, false },
2829 : { "unlink", "cmd_removeLinks", "", true, false },
2830 : { "insertorderedlist", "cmd_ol", "", true, false },
2831 : { "insertunorderedlist", "cmd_ul", "", true, false },
2832 : { "insertparagraph", "cmd_paragraphState", "p", true, false },
2833 : { "formatblock", "cmd_paragraphState", "", false, false },
2834 : { "heading", "cmd_paragraphState", "", false, false },
2835 : { "styleWithCSS", "cmd_setDocumentUseCSS", "", false, true },
2836 : { "contentReadOnly", "cmd_setDocumentReadOnly", "", false, true },
2837 : { "insertBrOnReturn", "cmd_insertBrOnReturn", "", false, true },
2838 : { "enableObjectResizing", "cmd_enableObjectResizing", "", false, true },
2839 : { "enableInlineTableEditing", "cmd_enableInlineTableEditing", "", false, true },
2840 : #if 0
2841 : // no editor support to remove alignments right now
2842 : { "justifynone", "cmd_align", "", true, false },
2843 :
2844 : // the following will need special review before being turned on
2845 : { "saveas", "cmd_saveAs", "", true, false },
2846 : { "print", "cmd_print", "", true, false },
2847 : #endif
2848 : { NULL, NULL, NULL, false, false }
2849 : };
2850 :
2851 : #define MidasCommandCount ((sizeof(gMidasCommandTable) / sizeof(struct MidasCommand)) - 1)
2852 :
2853 : static const char* const gBlocks[] = {
2854 : "ADDRESS",
2855 : "BLOCKQUOTE",
2856 : "DD",
2857 : "DIV",
2858 : "DL",
2859 : "DT",
2860 : "H1",
2861 : "H2",
2862 : "H3",
2863 : "H4",
2864 : "H5",
2865 : "H6",
2866 : "P",
2867 : "PRE"
2868 : };
2869 :
2870 : static bool
2871 0 : ConvertToMidasInternalCommandInner(const nsAString & inCommandID,
2872 : const nsAString & inParam,
2873 : nsACString& outCommandID,
2874 : nsACString& outParam,
2875 : bool& outIsBoolean,
2876 : bool& outBooleanValue,
2877 : bool aIgnoreParams)
2878 : {
2879 0 : NS_ConvertUTF16toUTF8 convertedCommandID(inCommandID);
2880 :
2881 : // Hack to support old boolean commands that were backwards (see bug 301490).
2882 0 : bool invertBool = false;
2883 0 : if (convertedCommandID.LowerCaseEqualsLiteral("usecss")) {
2884 0 : convertedCommandID.Assign("styleWithCSS");
2885 0 : invertBool = true;
2886 : }
2887 0 : else if (convertedCommandID.LowerCaseEqualsLiteral("readonly")) {
2888 0 : convertedCommandID.Assign("contentReadOnly");
2889 0 : invertBool = true;
2890 : }
2891 :
2892 : PRUint32 i;
2893 0 : bool found = false;
2894 0 : for (i = 0; i < MidasCommandCount; ++i) {
2895 0 : if (convertedCommandID.Equals(gMidasCommandTable[i].incomingCommandString,
2896 0 : nsCaseInsensitiveCStringComparator())) {
2897 0 : found = true;
2898 0 : break;
2899 : }
2900 : }
2901 :
2902 0 : if (found) {
2903 : // set outCommandID (what we use internally)
2904 0 : outCommandID.Assign(gMidasCommandTable[i].internalCommandString);
2905 :
2906 : // set outParam & outIsBoolean based on flags from the table
2907 0 : outIsBoolean = gMidasCommandTable[i].convertToBoolean;
2908 :
2909 0 : if (!aIgnoreParams) {
2910 0 : if (gMidasCommandTable[i].useNewParam) {
2911 0 : outParam.Assign(gMidasCommandTable[i].internalParamString);
2912 : }
2913 : else {
2914 : // handle checking of param passed in
2915 0 : if (outIsBoolean) {
2916 : // if this is a boolean value and it's not explicitly false
2917 : // (e.g. no value) we default to "true". For old backwards commands
2918 : // we invert the check (see bug 301490).
2919 0 : if (invertBool) {
2920 0 : outBooleanValue = inParam.LowerCaseEqualsLiteral("false");
2921 : }
2922 : else {
2923 0 : outBooleanValue = !inParam.LowerCaseEqualsLiteral("false");
2924 : }
2925 0 : outParam.Truncate();
2926 : }
2927 : else {
2928 : // check to see if we need to convert the parameter
2929 0 : if (outCommandID.EqualsLiteral("cmd_paragraphState")) {
2930 0 : const PRUnichar *start = inParam.BeginReading();
2931 0 : const PRUnichar *end = inParam.EndReading();
2932 0 : if (start != end && *start == '<' && *(end - 1) == '>') {
2933 0 : ++start;
2934 0 : --end;
2935 : }
2936 :
2937 0 : NS_ConvertUTF16toUTF8 convertedParam(Substring(start, end));
2938 : PRUint32 j;
2939 0 : for (j = 0; j < ArrayLength(gBlocks); ++j) {
2940 0 : if (convertedParam.Equals(gBlocks[j],
2941 0 : nsCaseInsensitiveCStringComparator())) {
2942 0 : outParam.Assign(gBlocks[j]);
2943 0 : break;
2944 : }
2945 : }
2946 :
2947 0 : return j != ArrayLength(gBlocks);
2948 : }
2949 : else {
2950 0 : CopyUTF16toUTF8(inParam, outParam);
2951 : }
2952 : }
2953 : }
2954 : }
2955 : } // end else for useNewParam (do convert existing param)
2956 : else {
2957 : // reset results if the command is not found in our table
2958 0 : outCommandID.SetLength(0);
2959 0 : outParam.SetLength(0);
2960 0 : outIsBoolean = false;
2961 : }
2962 :
2963 0 : return found;
2964 : }
2965 :
2966 : static bool
2967 0 : ConvertToMidasInternalCommand(const nsAString & inCommandID,
2968 : const nsAString & inParam,
2969 : nsACString& outCommandID,
2970 : nsACString& outParam,
2971 : bool& outIsBoolean,
2972 : bool& outBooleanValue)
2973 : {
2974 : return ConvertToMidasInternalCommandInner(inCommandID, inParam, outCommandID,
2975 : outParam, outIsBoolean,
2976 0 : outBooleanValue, false);
2977 : }
2978 :
2979 : static bool
2980 0 : ConvertToMidasInternalCommand(const nsAString & inCommandID,
2981 : nsACString& outCommandID)
2982 : {
2983 0 : nsCAutoString dummyCString;
2984 0 : nsAutoString dummyString;
2985 : bool dummyBool;
2986 : return ConvertToMidasInternalCommandInner(inCommandID, dummyString,
2987 : outCommandID, dummyCString,
2988 0 : dummyBool, dummyBool, true);
2989 : }
2990 :
2991 : jsid
2992 1464 : nsHTMLDocument::sCutCopyInternal_id = JSID_VOID;
2993 : jsid
2994 1464 : nsHTMLDocument::sPasteInternal_id = JSID_VOID;
2995 :
2996 : /* Helper function to check security of clipboard commands. If aPaste is */
2997 : /* true, we check paste, else we check cutcopy */
2998 : nsresult
2999 0 : nsHTMLDocument::DoClipboardSecurityCheck(bool aPaste)
3000 : {
3001 0 : nsresult rv = NS_ERROR_FAILURE;
3002 :
3003 : nsCOMPtr<nsIJSContextStack> stack =
3004 0 : do_GetService("@mozilla.org/js/xpc/ContextStack;1");
3005 :
3006 0 : if (stack) {
3007 0 : JSContext *cx = nsnull;
3008 0 : stack->Peek(&cx);
3009 0 : if (!cx) {
3010 0 : return NS_OK;
3011 : }
3012 :
3013 0 : JSAutoRequest ar(cx);
3014 :
3015 0 : NS_NAMED_LITERAL_CSTRING(classNameStr, "Clipboard");
3016 :
3017 0 : nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
3018 :
3019 0 : if (aPaste) {
3020 0 : if (nsHTMLDocument::sPasteInternal_id == JSID_VOID) {
3021 : nsHTMLDocument::sPasteInternal_id =
3022 0 : INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "paste"));
3023 : }
3024 : rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(),
3025 : nsHTMLDocument::sPasteInternal_id,
3026 0 : nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
3027 : } else {
3028 0 : if (nsHTMLDocument::sCutCopyInternal_id == JSID_VOID) {
3029 : nsHTMLDocument::sCutCopyInternal_id =
3030 0 : INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "cutcopy"));
3031 : }
3032 : rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(),
3033 : nsHTMLDocument::sCutCopyInternal_id,
3034 0 : nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
3035 : }
3036 : }
3037 0 : return rv;
3038 : }
3039 :
3040 : /* TODO: don't let this call do anything if the page is not done loading */
3041 : /* boolean execCommand(in DOMString commandID, in boolean doShowUI,
3042 : in DOMString value); */
3043 : NS_IMETHODIMP
3044 0 : nsHTMLDocument::ExecCommand(const nsAString & commandID,
3045 : bool doShowUI,
3046 : const nsAString & value,
3047 : bool *_retval)
3048 : {
3049 0 : NS_ENSURE_ARG_POINTER(_retval);
3050 :
3051 : // for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go()
3052 : // this might add some ugly JS dependencies?
3053 :
3054 0 : *_retval = false;
3055 :
3056 : // if editing is not on, bail
3057 0 : if (!IsEditingOnAfterFlush())
3058 0 : return NS_ERROR_FAILURE;
3059 :
3060 : // if they are requesting UI from us, let's fail since we have no UI
3061 0 : if (doShowUI)
3062 0 : return NS_OK;
3063 :
3064 0 : nsresult rv = NS_OK;
3065 :
3066 0 : if (commandID.LowerCaseEqualsLiteral("gethtml"))
3067 0 : return NS_ERROR_FAILURE;
3068 :
3069 0 : if (commandID.LowerCaseEqualsLiteral("cut") ||
3070 0 : (commandID.LowerCaseEqualsLiteral("copy"))) {
3071 0 : rv = DoClipboardSecurityCheck(false);
3072 0 : } else if (commandID.LowerCaseEqualsLiteral("paste")) {
3073 0 : rv = DoClipboardSecurityCheck(true);
3074 : }
3075 :
3076 0 : if (NS_FAILED(rv))
3077 0 : return rv;
3078 :
3079 : // get command manager and dispatch command to our window if it's acceptable
3080 0 : nsCOMPtr<nsICommandManager> cmdMgr;
3081 0 : GetMidasCommandManager(getter_AddRefs(cmdMgr));
3082 0 : if (!cmdMgr)
3083 0 : return NS_ERROR_FAILURE;
3084 :
3085 0 : nsIDOMWindow *window = GetWindow();
3086 0 : if (!window)
3087 0 : return NS_ERROR_FAILURE;
3088 :
3089 0 : nsCAutoString cmdToDispatch, paramStr;
3090 : bool isBool, boolVal;
3091 0 : if (!ConvertToMidasInternalCommand(commandID, value,
3092 0 : cmdToDispatch, paramStr, isBool, boolVal))
3093 0 : return NS_OK;
3094 :
3095 0 : if (!isBool && paramStr.IsEmpty()) {
3096 0 : rv = cmdMgr->DoCommand(cmdToDispatch.get(), nsnull, window);
3097 : } else {
3098 : // we have a command that requires a parameter, create params
3099 : nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
3100 0 : NS_COMMAND_PARAMS_CONTRACTID, &rv);
3101 0 : if (!cmdParams)
3102 0 : return NS_ERROR_OUT_OF_MEMORY;
3103 :
3104 0 : if (isBool)
3105 0 : rv = cmdParams->SetBooleanValue("state_attribute", boolVal);
3106 0 : else if (cmdToDispatch.Equals("cmd_fontFace"))
3107 0 : rv = cmdParams->SetStringValue("state_attribute", value);
3108 0 : else if (cmdToDispatch.Equals("cmd_insertHTML"))
3109 0 : rv = cmdParams->SetStringValue("state_data", value);
3110 : else
3111 0 : rv = cmdParams->SetCStringValue("state_attribute", paramStr.get());
3112 0 : if (NS_FAILED(rv))
3113 0 : return rv;
3114 0 : rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window);
3115 : }
3116 :
3117 0 : *_retval = NS_SUCCEEDED(rv);
3118 :
3119 0 : return rv;
3120 : }
3121 :
3122 : /* TODO: don't let this call do anything if the page is not done loading */
3123 : /* boolean execCommandShowHelp(in DOMString commandID); */
3124 : NS_IMETHODIMP
3125 0 : nsHTMLDocument::ExecCommandShowHelp(const nsAString & commandID,
3126 : bool *_retval)
3127 : {
3128 0 : NS_ENSURE_ARG_POINTER(_retval);
3129 0 : *_retval = false;
3130 :
3131 : // if editing is not on, bail
3132 0 : if (!IsEditingOnAfterFlush())
3133 0 : return NS_ERROR_FAILURE;
3134 :
3135 0 : return NS_ERROR_NOT_IMPLEMENTED;
3136 : }
3137 :
3138 : /* boolean queryCommandEnabled(in DOMString commandID); */
3139 : NS_IMETHODIMP
3140 0 : nsHTMLDocument::QueryCommandEnabled(const nsAString & commandID,
3141 : bool *_retval)
3142 : {
3143 0 : NS_ENSURE_ARG_POINTER(_retval);
3144 0 : *_retval = false;
3145 :
3146 : // if editing is not on, bail
3147 0 : if (!IsEditingOnAfterFlush())
3148 0 : return NS_ERROR_FAILURE;
3149 :
3150 : // get command manager and dispatch command to our window if it's acceptable
3151 0 : nsCOMPtr<nsICommandManager> cmdMgr;
3152 0 : GetMidasCommandManager(getter_AddRefs(cmdMgr));
3153 0 : if (!cmdMgr)
3154 0 : return NS_ERROR_FAILURE;
3155 :
3156 0 : nsIDOMWindow *window = GetWindow();
3157 0 : if (!window)
3158 0 : return NS_ERROR_FAILURE;
3159 :
3160 0 : nsCAutoString cmdToDispatch;
3161 0 : if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch))
3162 0 : return NS_OK; // queryCommandEnabled returns false on unsupported commands
3163 :
3164 0 : return cmdMgr->IsCommandEnabled(cmdToDispatch.get(), window, _retval);
3165 : }
3166 :
3167 : /* boolean queryCommandIndeterm (in DOMString commandID); */
3168 : NS_IMETHODIMP
3169 0 : nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID,
3170 : bool *_retval)
3171 : {
3172 0 : NS_ENSURE_ARG_POINTER(_retval);
3173 0 : *_retval = false;
3174 :
3175 : // if editing is not on, bail
3176 0 : if (!IsEditingOnAfterFlush())
3177 0 : return NS_ERROR_FAILURE;
3178 :
3179 : // get command manager and dispatch command to our window if it's acceptable
3180 0 : nsCOMPtr<nsICommandManager> cmdMgr;
3181 0 : GetMidasCommandManager(getter_AddRefs(cmdMgr));
3182 0 : if (!cmdMgr)
3183 0 : return NS_ERROR_FAILURE;
3184 :
3185 0 : nsIDOMWindow *window = GetWindow();
3186 0 : if (!window)
3187 0 : return NS_ERROR_FAILURE;
3188 :
3189 0 : nsCAutoString cmdToDispatch, paramToCheck;
3190 : bool dummy;
3191 0 : if (!ConvertToMidasInternalCommand(commandID, commandID,
3192 0 : cmdToDispatch, paramToCheck, dummy, dummy))
3193 0 : return NS_ERROR_NOT_IMPLEMENTED;
3194 :
3195 : nsresult rv;
3196 : nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
3197 0 : NS_COMMAND_PARAMS_CONTRACTID, &rv);
3198 0 : NS_ENSURE_SUCCESS(rv, rv);
3199 :
3200 0 : rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams);
3201 0 : if (NS_FAILED(rv))
3202 0 : return rv;
3203 :
3204 : // if command does not have a state_mixed value, this call fails, so we fail too,
3205 : // which is what is expected
3206 0 : rv = cmdParams->GetBooleanValue("state_mixed", _retval);
3207 0 : return rv;
3208 : }
3209 :
3210 : /* boolean queryCommandState(in DOMString commandID); */
3211 : NS_IMETHODIMP
3212 0 : nsHTMLDocument::QueryCommandState(const nsAString & commandID, bool *_retval)
3213 : {
3214 0 : NS_ENSURE_ARG_POINTER(_retval);
3215 0 : *_retval = false;
3216 :
3217 : // if editing is not on, bail
3218 0 : if (!IsEditingOnAfterFlush())
3219 0 : return NS_ERROR_FAILURE;
3220 :
3221 : // get command manager and dispatch command to our window if it's acceptable
3222 0 : nsCOMPtr<nsICommandManager> cmdMgr;
3223 0 : GetMidasCommandManager(getter_AddRefs(cmdMgr));
3224 0 : if (!cmdMgr)
3225 0 : return NS_ERROR_FAILURE;
3226 :
3227 0 : nsIDOMWindow *window = GetWindow();
3228 0 : if (!window)
3229 0 : return NS_ERROR_FAILURE;
3230 :
3231 0 : nsCAutoString cmdToDispatch, paramToCheck;
3232 : bool dummy, dummy2;
3233 0 : if (!ConvertToMidasInternalCommand(commandID, commandID,
3234 0 : cmdToDispatch, paramToCheck, dummy, dummy2))
3235 0 : return NS_ERROR_NOT_IMPLEMENTED;
3236 :
3237 : nsresult rv;
3238 : nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
3239 0 : NS_COMMAND_PARAMS_CONTRACTID, &rv);
3240 0 : if (!cmdParams)
3241 0 : return NS_ERROR_OUT_OF_MEMORY;
3242 :
3243 0 : rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams);
3244 0 : if (NS_FAILED(rv))
3245 0 : return rv;
3246 :
3247 : // handle alignment as a special case (possibly other commands too?)
3248 : // Alignment is special because the external api is individual
3249 : // commands but internally we use cmd_align with different
3250 : // parameters. When getting the state of this command, we need to
3251 : // return the boolean for this particular alignment rather than the
3252 : // string of 'which alignment is this?'
3253 0 : if (cmdToDispatch.Equals("cmd_align")) {
3254 0 : char * actualAlignmentType = nsnull;
3255 0 : rv = cmdParams->GetCStringValue("state_attribute", &actualAlignmentType);
3256 0 : if (NS_SUCCEEDED(rv) && actualAlignmentType && actualAlignmentType[0]) {
3257 0 : *_retval = paramToCheck.Equals(actualAlignmentType);
3258 : }
3259 0 : if (actualAlignmentType)
3260 0 : nsMemory::Free(actualAlignmentType);
3261 : }
3262 : else {
3263 0 : rv = cmdParams->GetBooleanValue("state_all", _retval);
3264 0 : if (NS_FAILED(rv))
3265 0 : *_retval = false;
3266 : }
3267 :
3268 0 : return rv;
3269 : }
3270 :
3271 : /* boolean queryCommandSupported(in DOMString commandID); */
3272 : NS_IMETHODIMP
3273 0 : nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
3274 : bool *_retval)
3275 : {
3276 0 : NS_ENSURE_ARG_POINTER(_retval);
3277 0 : *_retval = false;
3278 :
3279 : // if editing is not on, bail
3280 0 : if (!IsEditingOnAfterFlush())
3281 0 : return NS_ERROR_FAILURE;
3282 :
3283 : // get command manager
3284 0 : nsCOMPtr<nsICommandManager> cmdMgr;
3285 0 : GetMidasCommandManager(getter_AddRefs(cmdMgr));
3286 0 : if (!cmdMgr)
3287 0 : return NS_ERROR_FAILURE;
3288 :
3289 : // commandID is supported if it can be converted to a Midas command
3290 0 : nsCAutoString cmdToDispatch;
3291 0 : if (ConvertToMidasInternalCommand(commandID, cmdToDispatch))
3292 0 : *_retval = true;
3293 :
3294 0 : return NS_OK;
3295 : }
3296 :
3297 : /* DOMString queryCommandText(in DOMString commandID); */
3298 : NS_IMETHODIMP
3299 0 : nsHTMLDocument::QueryCommandText(const nsAString & commandID,
3300 : nsAString & _retval)
3301 : {
3302 0 : _retval.SetLength(0);
3303 :
3304 : // if editing is not on, bail
3305 0 : if (!IsEditingOnAfterFlush())
3306 0 : return NS_ERROR_FAILURE;
3307 :
3308 0 : return NS_ERROR_NOT_IMPLEMENTED;
3309 : }
3310 :
3311 : /* DOMString queryCommandValue(in DOMString commandID); */
3312 : NS_IMETHODIMP
3313 0 : nsHTMLDocument::QueryCommandValue(const nsAString & commandID,
3314 : nsAString &_retval)
3315 : {
3316 0 : _retval.SetLength(0);
3317 :
3318 : // if editing is not on, bail
3319 0 : if (!IsEditingOnAfterFlush())
3320 0 : return NS_ERROR_FAILURE;
3321 :
3322 : // get command manager and dispatch command to our window if it's acceptable
3323 0 : nsCOMPtr<nsICommandManager> cmdMgr;
3324 0 : GetMidasCommandManager(getter_AddRefs(cmdMgr));
3325 0 : if (!cmdMgr)
3326 0 : return NS_ERROR_FAILURE;
3327 :
3328 0 : nsIDOMWindow *window = GetWindow();
3329 0 : if (!window)
3330 0 : return NS_ERROR_FAILURE;
3331 :
3332 0 : nsCAutoString cmdToDispatch, paramStr;
3333 0 : if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch))
3334 0 : return NS_ERROR_NOT_IMPLEMENTED;
3335 :
3336 : // create params
3337 : nsresult rv;
3338 : nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
3339 0 : NS_COMMAND_PARAMS_CONTRACTID, &rv);
3340 0 : if (!cmdParams)
3341 0 : return NS_ERROR_OUT_OF_MEMORY;
3342 :
3343 : // this is a special command since we are calling "DoCommand rather than
3344 : // GetCommandState like the other commands
3345 0 : if (cmdToDispatch.Equals("cmd_getContents"))
3346 : {
3347 0 : rv = cmdParams->SetBooleanValue("selection_only", true);
3348 0 : if (NS_FAILED(rv)) return rv;
3349 0 : rv = cmdParams->SetCStringValue("format", "text/html");
3350 0 : if (NS_FAILED(rv)) return rv;
3351 0 : rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window);
3352 0 : if (NS_FAILED(rv)) return rv;
3353 0 : return cmdParams->GetStringValue("result", _retval);
3354 : }
3355 :
3356 0 : rv = cmdParams->SetCStringValue("state_attribute", paramStr.get());
3357 0 : if (NS_FAILED(rv))
3358 0 : return rv;
3359 :
3360 0 : rv = cmdMgr->GetCommandState(cmdToDispatch.get(), window, cmdParams);
3361 0 : if (NS_FAILED(rv))
3362 0 : return rv;
3363 :
3364 0 : nsXPIDLCString cStringResult;
3365 0 : rv = cmdParams->GetCStringValue("state_attribute",
3366 0 : getter_Copies(cStringResult));
3367 0 : CopyUTF8toUTF16(cStringResult, _retval);
3368 :
3369 0 : return rv;
3370 : }
3371 :
3372 : nsresult
3373 0 : nsHTMLDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
3374 : {
3375 0 : NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
3376 : "Can't import this document into another document!");
3377 :
3378 0 : nsRefPtr<nsHTMLDocument> clone = new nsHTMLDocument();
3379 0 : NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
3380 0 : nsresult rv = CloneDocHelper(clone.get());
3381 0 : NS_ENSURE_SUCCESS(rv, rv);
3382 :
3383 : // State from nsHTMLDocument
3384 0 : clone->mLoadFlags = mLoadFlags;
3385 :
3386 0 : return CallQueryInterface(clone.get(), aResult);
3387 : }
3388 :
3389 : bool
3390 0 : nsHTMLDocument::IsEditingOnAfterFlush()
3391 : {
3392 0 : nsIDocument* doc = GetParentDocument();
3393 0 : if (doc) {
3394 : // Make sure frames are up to date, since that can affect whether
3395 : // we're editable.
3396 0 : doc->FlushPendingNotifications(Flush_Frames);
3397 : }
3398 :
3399 0 : return IsEditingOn();
3400 : }
3401 :
3402 : void
3403 0 : nsHTMLDocument::RemovedFromDocShell()
3404 : {
3405 0 : mEditingState = eOff;
3406 0 : nsDocument::RemovedFromDocShell();
3407 0 : }
3408 :
3409 : /* virtual */ void
3410 0 : nsHTMLDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
3411 : {
3412 0 : nsDocument::DocSizeOfExcludingThis(aWindowSizes);
3413 :
3414 : // Measurement of the following members may be added later if DMD finds it is
3415 : // worthwhile:
3416 : // - mImages
3417 : // - mApplets
3418 : // - mEmbeds
3419 : // - mLinks
3420 : // - mAnchors
3421 : // - mScripts
3422 : // - mForms
3423 : // - mFormControls
3424 : // - mWyciwygChannel
3425 : // - mMidasCommandManager
3426 4392 : }
|