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
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/
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
16 * The Original Code is mozilla.org code.
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.
24 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Kathleen Brade <brade@netscape.com>
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.
39 * ***** END LICENSE BLOCK ***** */
40 #include "nsICharsetAlias.h"
43 #include "nsXPIDLString.h"
44 #include "nsPrintfCString.h"
45 #include "nsReadableUtils.h"
46 #include "nsUnicharUtils.h"
47 #include "nsHTMLDocument.h"
48 #include "nsIParserFilter.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 "nsIDOMText.h"
60 #include "nsIDOMComment.h"
61 #include "nsIDOMDOMImplementation.h"
62 #include "nsIDOMDocumentType.h"
63 #include "nsPIDOMWindow.h"
64 #include "nsIDOMHTMLFormElement.h"
65 #include "nsDOMString.h"
66 #include "nsIStreamListener.h"
68 #include "nsIIOService.h"
69 #include "nsNetUtil.h"
70 #include "nsIContentViewerContainer.h"
71 #include "nsIContentViewer.h"
72 #include "nsIMarkupDocumentViewer.h"
73 #include "nsIDocShell.h"
74 #include "nsIDocShellTreeItem.h"
75 #include "nsDocShellLoadTypes.h"
76 #include "nsIWebNavigation.h"
77 #include "nsIBaseWindow.h"
78 #include "nsIWebShellServices.h"
79 #include "nsIScriptContext.h"
80 #include "nsIXPConnect.h"
81 #include "nsContentList.h"
82 #include "nsDOMError.h"
83 #include "nsIPrincipal.h"
84 #include "nsIScriptSecurityManager.h"
85 #include "nsAttrName.h"
86 #include "nsNodeUtils.h"
89 #include "nsIIOService.h"
90 #include "nsICookieService.h"
92 #include "nsIServiceManager.h"
93 #include "nsIConsoleService.h"
94 #include "nsIComponentManager.h"
95 #include "nsParserCIID.h"
96 #include "nsIDOMHTMLElement.h"
97 #include "nsIDOMHTMLMapElement.h"
98 #include "nsIDOMHTMLBodyElement.h"
99 #include "nsINameSpaceManager.h"
100 #include "nsGenericHTMLElement.h"
101 #include "nsGenericDOMNodeList.h"
102 #include "nsICSSLoader.h"
103 #include "nsIHttpChannel.h"
105 #include "nsIEventListenerManager.h"
106 #include "nsISelectElement.h"
107 #include "nsFrameSelection.h"
108 #include "nsISelectionPrivate.h"//for toStringwithformat code
110 #include "nsICharsetDetector.h"
111 #include "nsICharsetDetectionAdaptor.h"
112 #include "nsCharsetDetectionAdaptorCID.h"
113 #include "nsICharsetAlias.h"
114 #include "nsContentUtils.h"
115 #include "nsJSUtils.h"
116 #include "nsIDocumentCharsetInfo.h"
117 #include "nsIDocumentEncoder.h" //for outputting selection
118 #include "nsICharsetResolver.h"
119 #include "nsICachingChannel.h"
120 #include "nsICacheEntryDescriptor.h"
121 #include "nsIJSContextStack.h"
122 #include "nsIDocumentViewer.h"
123 #include "nsIWyciwygChannel.h"
124 #include "nsIScriptElement.h"
125 #include "nsIScriptError.h"
126 #include "nsIMutableArray.h"
127 #include "nsArrayUtils.h"
128 #include "nsIEffectiveTLDService.h"
129 #include "nsIEventStateManager.h"
131 #include "nsIPrompt.h"
133 #include "nsBidiUtils.h"
135 #include "nsIEditingSession.h"
136 #include "nsIEditor.h"
137 #include "nsNodeInfoManager.h"
138 #include "nsIEditor.h"
139 #include "nsIEditorDocShell.h"
140 #include "nsIEditorStyleSheets.h"
141 #include "nsIInlineSpellChecker.h"
143 #include "mozAutoDocUpdate.h"
145 #define NS_MAX_DOCUMENT_WRITE_DEPTH 20
147 #define DETECTOR_CONTRACTID_MAX 127
148 static char g_detector_contractid
[DETECTOR_CONTRACTID_MAX
+ 1];
149 static PRBool gInitDetector
= PR_FALSE
;
150 static PRBool gPlugDetector
= PR_FALSE
;
155 // Find/Search Includes
156 const PRInt32 kForward
= 0;
157 const PRInt32 kBackward
= 1;
159 //#define DEBUG_charset
161 static NS_DEFINE_CID(kCParserCID
, NS_PARSER_CID
);
163 PRUint32
nsHTMLDocument::gWyciwygSessionCnt
= 0;
165 // this function will return false if the command is not recognized
166 // inCommandID will be converted as necessary for internal operations
167 // inParam will be converted as necessary for internal operations
168 // outParam will be Empty if no parameter is needed or if returning a boolean
169 // outIsBoolean will determine whether to send param as a boolean or string
170 // outBooleanParam will not be set unless outIsBoolean
171 static PRBool
ConvertToMidasInternalCommand(const nsAString
& inCommandID
,
172 const nsAString
& inParam
,
173 nsACString
& outCommandID
,
174 nsACString
& outParam
,
178 static PRBool
ConvertToMidasInternalCommand(const nsAString
& inCommandID
,
179 nsACString
& outCommandID
);
180 static int PR_CALLBACK
181 MyPrefChangedCallback(const char*aPrefName
, void* instance_data
)
183 const nsAdoptingString
& detector_name
=
184 nsContentUtils::GetLocalizedStringPref("intl.charset.detector");
186 if (detector_name
.Length() > 0) {
187 PL_strncpy(g_detector_contractid
, NS_CHARSET_DETECTOR_CONTRACTID_BASE
,
188 DETECTOR_CONTRACTID_MAX
);
189 PL_strncat(g_detector_contractid
,
190 NS_ConvertUTF16toUTF8(detector_name
).get(),
191 DETECTOR_CONTRACTID_MAX
);
192 gPlugDetector
= PR_TRUE
;
194 g_detector_contractid
[0]=0;
195 gPlugDetector
= PR_FALSE
;
201 // ==================================================================
203 // ==================================================================
205 NS_NewHTMLDocument(nsIDocument
** aInstancePtrResult
)
207 nsHTMLDocument
* doc
= new nsHTMLDocument();
208 NS_ENSURE_TRUE(doc
, NS_ERROR_OUT_OF_MEMORY
);
211 nsresult rv
= doc
->Init();
217 *aInstancePtrResult
= doc
;
222 // NOTE! nsDocument::operator new() zeroes out all members, so don't
223 // bother initializing members to 0.
225 nsHTMLDocument::nsHTMLDocument()
226 : nsDocument("text/html")
228 // NOTE! nsDocument::operator new() zeroes out all members, so don't
229 // bother initializing members to 0.
231 mIsRegularHTML
= PR_TRUE
;
232 mDefaultElementType
= kNameSpaceID_XHTML
;
233 mCompatMode
= eCompatibility_NavQuirks
;
236 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLDocument
)
238 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument
, nsDocument
)
239 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mImageMaps
)
240 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mImages
)
241 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplets
)
242 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEmbeds
)
243 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLinks
)
244 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAnchors
)
245 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFragmentParser
)
246 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mForms
, nsIDOMNodeList
)
247 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFormControls
,
249 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
251 NS_IMPL_ADDREF_INHERITED(nsHTMLDocument
, nsDocument
)
252 NS_IMPL_RELEASE_INHERITED(nsHTMLDocument
, nsDocument
)
255 // QueryInterface implementation for nsHTMLDocument
256 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLDocument
)
257 NS_INTERFACE_TABLE_INHERITED3(nsHTMLDocument
,
260 nsIDOMNSHTMLDocument
)
261 NS_INTERFACE_TABLE_TO_MAP_SEGUE
262 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLDocument
)
263 NS_INTERFACE_MAP_END_INHERITING(nsDocument
)
267 nsHTMLDocument::Init()
269 nsresult rv
= nsDocument::Init();
270 NS_ENSURE_SUCCESS(rv
, rv
);
272 // Now reset the case-sensitivity of the CSSLoader, since we default
273 // to being HTML, not XHTML. Also, reset the compatibility mode to
274 // match our compat mode.
275 CSSLoader()->SetCaseSensitive(IsXHTML());
276 CSSLoader()->SetCompatibilityMode(mCompatMode
);
278 PrePopulateIdentifierMap();
284 nsHTMLDocument::Reset(nsIChannel
* aChannel
, nsILoadGroup
* aLoadGroup
)
286 nsDocument::Reset(aChannel
, aLoadGroup
);
289 aChannel
->GetLoadFlags(&mLoadFlags
);
294 nsHTMLDocument::ResetToURI(nsIURI
*aURI
, nsILoadGroup
*aLoadGroup
,
295 nsIPrincipal
* aPrincipal
)
297 mLoadFlags
= nsIRequest::LOAD_NORMAL
;
299 nsDocument::ResetToURI(aURI
, aLoadGroup
, aPrincipal
);
301 PrePopulateIdentifierMap();
312 NS_ASSERTION(!mWyciwygChannel
,
313 "nsHTMLDocument::Reset() - Wyciwyg Channel still exists!");
315 mWyciwygChannel
= nsnull
;
317 // Make the content type default to "text/html", we are a HTML
318 // document, after all. Once we start getting data, this may be
320 mContentType
= "text/html";
323 nsStyleSet::sheetType
324 nsHTMLDocument::GetAttrSheetType()
327 return nsDocument::GetAttrSheetType();
330 return nsStyleSet::eHTMLPresHintSheet
;
334 nsHTMLDocument::CreateShell(nsPresContext
* aContext
,
335 nsIViewManager
* aViewManager
,
336 nsStyleSet
* aStyleSet
,
337 nsIPresShell
** aInstancePtrResult
)
339 return doCreateShell(aContext
, aViewManager
, aStyleSet
, mCompatMode
,
343 // The following Try*Charset will return PR_FALSE only if the charset source
344 // should be considered (ie. aCharsetSource < thisCharsetSource) but we failed
345 // to get the charset from this source.
348 nsHTMLDocument::TryHintCharset(nsIMarkupDocumentViewer
* aMarkupDV
,
349 PRInt32
& aCharsetSource
, nsACString
& aCharset
)
352 PRInt32 requestCharsetSource
;
353 nsresult rv
= aMarkupDV
->GetHintCharacterSetSource(&requestCharsetSource
);
355 if(NS_SUCCEEDED(rv
) && kCharsetUninitialized
!= requestCharsetSource
) {
356 nsCAutoString requestCharset
;
357 rv
= aMarkupDV
->GetHintCharacterSet(requestCharset
);
358 aMarkupDV
->SetHintCharacterSetSource((PRInt32
)(kCharsetUninitialized
));
360 if(requestCharsetSource
<= aCharsetSource
)
363 if(NS_SUCCEEDED(rv
)) {
364 aCharsetSource
= requestCharsetSource
;
365 aCharset
= requestCharset
;
376 nsHTMLDocument::TryUserForcedCharset(nsIMarkupDocumentViewer
* aMarkupDV
,
377 nsIDocumentCharsetInfo
* aDocInfo
,
378 PRInt32
& aCharsetSource
,
379 nsACString
& aCharset
)
383 if(kCharsetFromUserForced
<= aCharsetSource
)
386 nsCAutoString forceCharsetFromDocShell
;
388 rv
= aMarkupDV
->GetForceCharacterSet(forceCharsetFromDocShell
);
391 if(NS_SUCCEEDED(rv
) && !forceCharsetFromDocShell
.IsEmpty()) {
392 aCharset
= forceCharsetFromDocShell
;
393 //TODO: we should define appropriate constant for force charset
394 aCharsetSource
= kCharsetFromUserForced
;
395 } else if (aDocInfo
) {
396 nsCOMPtr
<nsIAtom
> csAtom
;
397 aDocInfo
->GetForcedCharset(getter_AddRefs(csAtom
));
399 csAtom
->ToUTF8String(aCharset
);
400 aCharsetSource
= kCharsetFromUserForced
;
401 aDocInfo
->SetForcedCharset(nsnull
);
410 nsHTMLDocument::TryCacheCharset(nsICacheEntryDescriptor
* aCacheDescriptor
,
411 PRInt32
& aCharsetSource
,
412 nsACString
& aCharset
)
416 if (kCharsetFromCache
<= aCharsetSource
) {
420 nsXPIDLCString cachedCharset
;
421 rv
= aCacheDescriptor
->GetMetaDataElement("charset",
422 getter_Copies(cachedCharset
));
423 if (NS_SUCCEEDED(rv
) && !cachedCharset
.IsEmpty())
425 aCharset
= cachedCharset
;
426 aCharsetSource
= kCharsetFromCache
;
435 nsHTMLDocument::TryBookmarkCharset(nsIDocShell
* aDocShell
,
436 nsIChannel
* aChannel
,
437 PRInt32
& aCharsetSource
,
438 nsACString
& aCharset
)
440 if (kCharsetFromBookmarks
<= aCharsetSource
) {
448 nsCOMPtr
<nsICharsetResolver
> bookmarksResolver
=
449 do_GetService("@mozilla.org/embeddor.implemented/bookmark-charset-resolver;1");
451 if (!bookmarksResolver
) {
455 PRBool wantCharset
; // ignored for now
456 nsCAutoString charset
;
457 nsCOMPtr
<nsIWebNavigation
> webNav(do_QueryInterface(aDocShell
));
458 nsCOMPtr
<nsISupports
> closure
;
459 nsresult rv
= bookmarksResolver
->RequestCharset(webNav
,
462 getter_AddRefs(closure
),
465 NS_ASSERTION(!wantCharset
, "resolved charset notification not implemented!");
467 if (NS_SUCCEEDED(rv
) && !charset
.IsEmpty()) {
469 aCharsetSource
= kCharsetFromBookmarks
;
477 CheckSameOrigin(nsINode
* aNode1
, nsINode
* aNode2
)
479 NS_PRECONDITION(aNode1
, "Null node?");
480 NS_PRECONDITION(aNode2
, "Null node?");
484 NS_SUCCEEDED(aNode1
->NodePrincipal()->
485 Equals(aNode2
->NodePrincipal(), &equal
)) &&
490 nsHTMLDocument::TryParentCharset(nsIDocumentCharsetInfo
* aDocInfo
,
491 nsIDocument
* aParentDocument
,
492 PRInt32
& aCharsetSource
,
493 nsACString
& aCharset
)
497 nsCOMPtr
<nsIAtom
> csAtom
;
498 PRInt32 parentSource
;
499 aDocInfo
->GetParentCharsetSource(&parentSource
);
500 if (kCharsetFromParentForced
<= parentSource
)
501 source
= kCharsetFromParentForced
;
502 else if (kCharsetFromHintPrevDoc
== parentSource
) {
503 // Make sure that's OK
504 if (!aParentDocument
|| !CheckSameOrigin(this, aParentDocument
)) {
508 // if parent is posted doc, set this prevent autodections
509 // I'm not sure this makes much sense... but whatever.
510 source
= kCharsetFromHintPrevDoc
;
512 else if (kCharsetFromCache
<= parentSource
) {
513 // Make sure that's OK
514 if (!aParentDocument
|| !CheckSameOrigin(this, aParentDocument
)) {
518 source
= kCharsetFromParentFrame
;
523 if (source
< aCharsetSource
)
526 aDocInfo
->GetParentCharset(getter_AddRefs(csAtom
));
528 csAtom
->ToUTF8String(aCharset
);
529 aCharsetSource
= source
;
537 nsHTMLDocument::UseWeakDocTypeDefault(PRInt32
& aCharsetSource
,
538 nsACString
& aCharset
)
540 if (kCharsetFromWeakDocTypeDefault
<= aCharsetSource
)
542 // fallback value in case docshell return error
543 aCharset
.AssignLiteral("ISO-8859-1");
545 const nsAdoptingString
& defCharset
=
546 nsContentUtils::GetLocalizedStringPref("intl.charset.default");
548 if (!defCharset
.IsEmpty()) {
549 LossyCopyUTF16toASCII(defCharset
, aCharset
);
550 aCharsetSource
= kCharsetFromWeakDocTypeDefault
;
556 nsHTMLDocument::TryDefaultCharset( nsIMarkupDocumentViewer
* aMarkupDV
,
557 PRInt32
& aCharsetSource
,
558 nsACString
& aCharset
)
560 if(kCharsetFromUserDefault
<= aCharsetSource
)
563 nsCAutoString defaultCharsetFromDocShell
;
566 aMarkupDV
->GetDefaultCharacterSet(defaultCharsetFromDocShell
);
567 if(NS_SUCCEEDED(rv
)) {
568 aCharset
= defaultCharsetFromDocShell
;
570 aCharsetSource
= kCharsetFromUserDefault
;
578 nsHTMLDocument::StartAutodetection(nsIDocShell
*aDocShell
, nsACString
& aCharset
,
579 const char* aCommand
)
581 nsCOMPtr
<nsIParserFilter
> cdetflt
;
585 const nsAdoptingString
& detector_name
=
586 nsContentUtils::GetLocalizedStringPref("intl.charset.detector");
588 if(!detector_name
.IsEmpty()) {
589 PL_strncpy(g_detector_contractid
, NS_CHARSET_DETECTOR_CONTRACTID_BASE
,
590 DETECTOR_CONTRACTID_MAX
);
591 PL_strncat(g_detector_contractid
,
592 NS_ConvertUTF16toUTF8(detector_name
).get(),
593 DETECTOR_CONTRACTID_MAX
);
594 gPlugDetector
= PR_TRUE
;
597 nsContentUtils::RegisterPrefCallback("intl.charset.detector",
598 MyPrefChangedCallback
,
601 gInitDetector
= PR_TRUE
;
605 nsCOMPtr
<nsICharsetDetector
> cdet
=
606 do_CreateInstance(g_detector_contractid
, &rv_detect
);
607 if (NS_SUCCEEDED(rv_detect
)) {
608 cdetflt
= do_CreateInstance(NS_CHARSET_DETECTION_ADAPTOR_CONTRACTID
,
611 nsCOMPtr
<nsICharsetDetectionAdaptor
> adp
= do_QueryInterface(cdetflt
);
613 nsCOMPtr
<nsIWebShellServices
> wss
= do_QueryInterface(aDocShell
);
615 rv_detect
= adp
->Init(wss
, cdet
, this, mParser
,
616 PromiseFlatCString(aCharset
).get(), aCommand
);
619 mParser
->SetParserFilter(cdetflt
);
624 // IF we cannot create the detector, don't bother to
625 // create one next time.
626 gPlugDetector
= PR_FALSE
;
632 nsHTMLDocument::SetDocumentCharacterSet(const nsACString
& aCharSetID
)
634 nsDocument::SetDocumentCharacterSet(aCharSetID
);
635 // Make sure to stash this charset on our channel as needed if it's a wyciwyg
637 nsCOMPtr
<nsIWyciwygChannel
> wyciwygChannel
= do_QueryInterface(mChannel
);
638 if (wyciwygChannel
) {
639 wyciwygChannel
->SetCharsetAndSource(GetDocumentCharacterSetSource(),
645 nsHTMLDocument::StartDocumentLoad(const char* aCommand
,
646 nsIChannel
* aChannel
,
647 nsILoadGroup
* aLoadGroup
,
648 nsISupports
* aContainer
,
649 nsIStreamListener
**aDocListener
,
651 nsIContentSink
* aSink
)
653 nsCAutoString contentType
;
654 aChannel
->GetContentType(contentType
);
656 if (contentType
.Equals("application/xhtml+xml") &&
657 (!aCommand
|| nsCRT::strcmp(aCommand
, "view-source") != 0)) {
658 // We're parsing XHTML as XML, remember that.
660 mIsRegularHTML
= PR_FALSE
;
661 mCompatMode
= eCompatibility_FullStandards
;
665 NS_ASSERTION(mIsRegularHTML
,
666 "Hey, someone forgot to reset mIsRegularHTML!!!");
670 CSSLoader()->SetCaseSensitive(IsXHTML());
671 CSSLoader()->SetCompatibilityMode(mCompatMode
);
673 PRBool needsParser
= PR_TRUE
;
676 if (!nsCRT::strcmp(aCommand
, "view delayedContentLoad")) {
677 needsParser
= PR_FALSE
;
681 nsCOMPtr
<nsICacheEntryDescriptor
> cacheDescriptor
;
682 nsresult rv
= nsDocument::StartDocumentLoad(aCommand
,
683 aChannel
, aLoadGroup
,
685 aDocListener
, aReset
);
690 // Store the security info for future use with wyciwyg channels.
691 aChannel
->GetSecurityInfo(getter_AddRefs(mSecurityInfo
));
693 nsCOMPtr
<nsIURI
> uri
;
694 rv
= aChannel
->GetURI(getter_AddRefs(uri
));
699 nsCOMPtr
<nsICachingChannel
> cachingChan
= do_QueryInterface(aChannel
);
701 nsCOMPtr
<nsISupports
> cacheToken
;
702 cachingChan
->GetCacheToken(getter_AddRefs(cacheToken
));
704 cacheDescriptor
= do_QueryInterface(cacheToken
);
708 mParser
= do_CreateInstance(kCParserCID
, &rv
);
709 NS_ENSURE_SUCCESS(rv
, rv
);
712 nsCOMPtr
<nsIDocShell
> docShell(do_QueryInterface(aContainer
));
714 nsCOMPtr
<nsIDocumentCharsetInfo
> dcInfo
;
715 docShell
->GetDocumentCharsetInfo(getter_AddRefs(dcInfo
));
716 PRInt32 textType
= GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
718 // Look for the parent document. Note that at this point we don't have our
719 // content viewer set up yet, and therefore do not have a useful
722 // in this block of code, if we get an error result, we return it
723 // but if we get a null pointer, that's perfectly legal for parent
724 // and parentContentViewer
725 nsCOMPtr
<nsIDocShellTreeItem
> docShellAsItem(do_QueryInterface(docShell
));
726 NS_ENSURE_TRUE(docShellAsItem
, NS_ERROR_FAILURE
);
728 nsCOMPtr
<nsIDocShellTreeItem
> parentAsItem
;
729 docShellAsItem
->GetSameTypeParent(getter_AddRefs(parentAsItem
));
731 nsCOMPtr
<nsIDocShell
> parent(do_QueryInterface(parentAsItem
));
732 nsCOMPtr
<nsIDocument
> parentDocument
;
733 nsCOMPtr
<nsIContentViewer
> parentContentViewer
;
735 rv
= parent
->GetContentViewer(getter_AddRefs(parentContentViewer
));
736 NS_ENSURE_SUCCESS(rv
, rv
);
737 nsCOMPtr
<nsIDocumentViewer
> docViewer
=
738 do_QueryInterface(parentContentViewer
);
740 docViewer
->GetDocument(getter_AddRefs(parentDocument
));
745 // The following logic is mirrored in nsWebShell::Embed!
747 nsCOMPtr
<nsIMarkupDocumentViewer
> muCV
;
748 PRBool muCVIsParent
= PR_FALSE
;
749 nsCOMPtr
<nsIContentViewer
> cv
;
750 docShell
->GetContentViewer(getter_AddRefs(cv
));
752 muCV
= do_QueryInterface(cv
);
754 muCV
= do_QueryInterface(parentContentViewer
);
756 muCVIsParent
= PR_TRUE
;
760 nsCAutoString scheme
;
761 uri
->GetScheme(scheme
);
763 nsCAutoString urlSpec
;
764 uri
->GetSpec(urlSpec
);
766 printf("Determining charset for %s\n", urlSpec
.get());
769 // These are the charset source and charset for our document
770 PRInt32 charsetSource
;
771 nsCAutoString charset
;
773 // These are the charset source and charset for the parser. This can differ
774 // from that for the document if the channel is a wyciwyg channel.
775 PRInt32 parserCharsetSource
;
776 nsCAutoString parserCharset
;
778 nsCOMPtr
<nsIWyciwygChannel
> wyciwygChannel
;
781 charsetSource
= kCharsetFromDocTypeDefault
;
782 charset
.AssignLiteral("UTF-8");
783 TryChannelCharset(aChannel
, charsetSource
, charset
);
784 parserCharsetSource
= charsetSource
;
785 parserCharset
= charset
;
787 charsetSource
= kCharsetUninitialized
;
788 wyciwygChannel
= do_QueryInterface(aChannel
);
790 // The following charset resolving calls has implied knowledge
791 // about charset source priority order. Each try will return true
792 // if the source is higher or equal to the source as its name
793 // describes. Some try call might change charset source to
794 // multiple values, like TryHintCharset and TryParentCharset. It
795 // should be always safe to try more sources.
796 if (!TryUserForcedCharset(muCV
, dcInfo
, charsetSource
, charset
)) {
797 TryHintCharset(muCV
, charsetSource
, charset
);
798 TryParentCharset(dcInfo
, parentDocument
, charsetSource
, charset
);
800 // Don't actually get the charset from the channel if this is a
801 // wyciwyg channel; it'll always be UTF-16
802 if (!wyciwygChannel
&&
803 TryChannelCharset(aChannel
, charsetSource
, charset
)) {
804 // Use the channel's charset (e.g., charset from HTTP
805 // "Content-Type" header).
807 else if (!scheme
.EqualsLiteral("about") && // don't try to access bookmarks for about:blank
808 TryBookmarkCharset(docShell
, aChannel
, charsetSource
, charset
)) {
809 // Use the bookmark's charset.
811 else if (cacheDescriptor
&& !urlSpec
.IsEmpty() &&
812 TryCacheCharset(cacheDescriptor
, charsetSource
, charset
)) {
813 // Use the cache's charset.
815 else if (TryDefaultCharset(muCV
, charsetSource
, charset
)) {
816 // Use the default charset.
817 // previous document charset might be inherited as default charset.
820 // Use the weak doc type default charset
821 UseWeakDocTypeDefault(charsetSource
, charset
);
825 PRBool isPostPage
= PR_FALSE
;
826 // check if current doc is from POST command
827 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(aChannel
));
829 nsCAutoString methodStr
;
830 rv
= httpChannel
->GetRequestMethod(methodStr
);
831 isPostPage
= (NS_SUCCEEDED(rv
) &&
832 methodStr
.EqualsLiteral("POST"));
835 if (isPostPage
&& muCV
&& kCharsetFromHintPrevDoc
> charsetSource
) {
836 nsCAutoString requestCharset
;
837 muCV
->GetPrevDocCharacterSet(requestCharset
);
838 if (!requestCharset
.IsEmpty()) {
839 charsetSource
= kCharsetFromHintPrevDoc
;
840 charset
= requestCharset
;
844 if (wyciwygChannel
) {
845 // We know for sure that the parser needs to be using UTF16.
846 parserCharset
= "UTF-16";
847 parserCharsetSource
= charsetSource
< kCharsetFromChannel
?
848 kCharsetFromChannel
: charsetSource
;
850 nsCAutoString cachedCharset
;
851 PRInt32 cachedSource
;
852 rv
= wyciwygChannel
->GetCharsetAndSource(&cachedSource
, cachedCharset
);
853 if (NS_SUCCEEDED(rv
)) {
854 if (cachedSource
> charsetSource
) {
855 charsetSource
= cachedSource
;
856 charset
= cachedCharset
;
859 // Don't propagate this error.
864 parserCharset
= charset
;
865 parserCharsetSource
= charsetSource
;
868 if(kCharsetFromAutoDetection
> charsetSource
&& !isPostPage
) {
869 StartAutodetection(docShell
, charset
, aCommand
);
873 // Check if 864 but in Implicit mode !
874 // XXXbz why is this happening after StartAutodetection ?
875 if ((textType
== IBMBIDI_TEXTTYPE_LOGICAL
) &&
876 (charset
.LowerCaseEqualsLiteral("ibm864"))) {
877 charset
.AssignLiteral("IBM864i");
881 SetDocumentCharacterSetSource(charsetSource
);
882 SetDocumentCharacterSet(charset
);
884 // set doc charset to muCV for next document.
885 // Don't propagate this back up to the parent document if we have one.
886 if (muCV
&& !muCVIsParent
)
887 muCV
->SetPrevDocCharacterSet(charset
);
889 if(cacheDescriptor
) {
890 NS_ASSERTION(charset
== parserCharset
,
891 "How did those end up different here? wyciwyg channels are "
892 "not nsICachingChannel");
893 rv
= cacheDescriptor
->SetMetaDataElement("charset",
895 NS_ASSERTION(NS_SUCCEEDED(rv
),"cannot SetMetaDataElement");
898 // Set the parser as the stream listener for the document loader...
900 rv
= CallQueryInterface(mParser
, aDocListener
);
906 printf(" charset = %s source %d\n",
907 charset
.get(), charsetSource
);
909 mParser
->SetDocumentCharset(parserCharset
, parserCharsetSource
);
910 mParser
->SetCommand(aCommand
);
912 // create the content sink
913 nsCOMPtr
<nsIContentSink
> sink
;
919 nsCOMPtr
<nsIXMLContentSink
> xmlsink
;
920 rv
= NS_NewXMLContentSink(getter_AddRefs(xmlsink
), this, uri
,
925 nsCOMPtr
<nsIHTMLContentSink
> htmlsink
;
927 rv
= NS_NewHTMLContentSink(getter_AddRefs(htmlsink
), this, uri
,
932 NS_ENSURE_SUCCESS(rv
, rv
);
935 "null sink with successful result from factory method");
938 mParser
->SetContentSink(sink
);
939 // parser the content of the URI
940 mParser
->Parse(uri
, nsnull
, (void *)this);
947 nsHTMLDocument::StopDocumentLoad()
949 // If we're writing (i.e., there's been a document.open call), then
950 // nsDocument::StopDocumentLoad will do the wrong thing and simply terminate
952 if (mWriteState
!= eNotWriting
) {
955 nsDocument::StopDocumentLoad();
961 nsHTMLDocument::DocumentWriteTerminationFunc(nsISupports
*aRef
)
963 nsCOMPtr
<nsIArray
> arr
= do_QueryInterface(aRef
);
964 NS_ASSERTION(arr
, "Must have array!");
966 nsCOMPtr
<nsIDocument
> doc
= do_QueryElementAt(arr
, 0);
967 NS_ASSERTION(doc
, "Must have document!");
969 nsCOMPtr
<nsIParser
> parser
= do_QueryElementAt(arr
, 1);
970 NS_ASSERTION(parser
, "Must have parser!");
972 nsHTMLDocument
*htmldoc
= static_cast<nsHTMLDocument
*>(doc
.get());
974 // Check whether htmldoc still has the same parser. If not, it's
975 // not for us to mess with it.
976 if (htmldoc
->mParser
!= parser
) {
980 // If the document is in the middle of a document.write() call, this
981 // most likely means that script on a page document.write()'d out a
982 // script tag that did location="..." and we're right now finishing
983 // up executing the script that was written with
984 // document.write(). Since there's still script on the stack (the
985 // script that called document.write()) we don't want to release the
986 // parser now, that would cause the next document.write() call to
987 // cancel the load that was initiated by the location="..." in the
988 // script that was written out by document.write().
990 if (!htmldoc
->mWriteLevel
&& htmldoc
->mWriteState
!= eDocumentOpened
) {
991 // Release the document's parser so that the call to EndLoad()
992 // doesn't just return early and set the termination function again.
994 htmldoc
->mParser
= nsnull
;
1001 nsHTMLDocument::EndLoad()
1003 if (mParser
&& mWriteState
!= eDocumentClosed
) {
1004 nsCOMPtr
<nsIJSContextStack
> stack
=
1005 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1008 JSContext
*cx
= nsnull
;
1012 nsIScriptContext
*scx
= nsJSUtils::GetDynamicScriptContext(cx
);
1015 // The load of the document was terminated while we're
1016 // called from within JS and we have a parser (i.e. we're in
1017 // the middle of doing document.write()). In stead of
1018 // releasing the parser and ending the document load
1019 // directly, we'll make that happen once the script is done
1020 // executing. This way subsequent document.write() calls
1021 // won't end up creating a new parser and interrupting other
1022 // loads that were started while the script was
1023 // running. I.e. this makes the following case work as
1026 // document.write("foo");
1027 // location.href = "http://www.mozilla.org";
1028 // document.write("bar");
1032 nsCOMPtr
<nsIMutableArray
> arr
=
1033 do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
1034 if (NS_SUCCEEDED(rv
)) {
1035 rv
= arr
->AppendElement(static_cast<nsIDocument
*>(this),
1037 if (NS_SUCCEEDED(rv
)) {
1038 rv
= arr
->AppendElement(mParser
, PR_FALSE
);
1039 if (NS_SUCCEEDED(rv
)) {
1040 rv
= scx
->SetTerminationFunction(DocumentWriteTerminationFunc
,
1042 // If we fail to set the termination function, just go ahead
1043 // and EndLoad now. The slight bugginess involved is better
1045 if (NS_SUCCEEDED(rv
)) {
1056 // Reset this now, since we're really done "loading" this document.written
1058 NS_ASSERTION(mWriteState
== eNotWriting
|| mWriteState
== ePendingClose
||
1059 mWriteState
== eDocumentClosed
, "EndLoad called early");
1060 mWriteState
= eNotWriting
;
1062 PRBool turnOnEditing
=
1063 mParser
&& (HasFlag(NODE_IS_EDITABLE
) || mContentEditableCount
> 0);
1064 // Note: nsDocument::EndLoad nulls out mParser.
1065 nsDocument::EndLoad();
1066 if (turnOnEditing
) {
1067 EditingStateChanged();
1072 nsHTMLDocument::SetTitle(const nsAString
& aTitle
)
1074 return nsDocument::SetTitle(aTitle
);
1078 nsHTMLDocument::AddImageMap(nsIDOMHTMLMapElement
* aMap
)
1080 // XXX We should order the maps based on their order in the document.
1081 // XXX Otherwise scripts that add/remove maps with duplicate names
1082 // XXX will cause problems
1083 NS_PRECONDITION(nsnull
!= aMap
, "null ptr");
1084 if (nsnull
== aMap
) {
1085 return NS_ERROR_NULL_POINTER
;
1087 if (mImageMaps
.AppendObject(aMap
)) {
1090 return NS_ERROR_OUT_OF_MEMORY
;
1094 nsHTMLDocument::RemoveImageMap(nsIDOMHTMLMapElement
* aMap
)
1096 NS_PRECONDITION(nsnull
!= aMap
, "null ptr");
1097 mImageMaps
.RemoveObject(aMap
);
1100 nsIDOMHTMLMapElement
*
1101 nsHTMLDocument::GetImageMap(const nsAString
& aMapName
)
1104 PRUint32 i
, n
= mImageMaps
.Count();
1105 nsIDOMHTMLMapElement
*firstMatch
= nsnull
;
1107 for (i
= 0; i
< n
; ++i
) {
1108 nsIDOMHTMLMapElement
*map
= mImageMaps
[i
];
1109 NS_ASSERTION(map
, "Null map in map list!");
1115 rv
= map
->GetId(name
);
1117 match
= name
.Equals(aMapName
);
1119 rv
= map
->GetName(name
);
1121 match
= name
.Equals(aMapName
, nsCaseInsensitiveStringComparator());
1124 if (match
&& NS_SUCCEEDED(rv
)) {
1125 // Quirk: if the first matching map is empty, remember it, but keep
1126 // searching for a non-empty one, only use it if none was found (bug 264624).
1127 if (mCompatMode
== eCompatibility_NavQuirks
) {
1128 nsCOMPtr
<nsIDOMHTMLCollection
> mapAreas
;
1129 rv
= map
->GetAreas(getter_AddRefs(mapAreas
));
1130 if (NS_SUCCEEDED(rv
) && mapAreas
) {
1131 PRUint32 length
= 0;
1132 mapAreas
->GetLength(&length
);
1149 nsHTMLDocument::SetCompatibilityMode(nsCompatibility aMode
)
1151 NS_ASSERTION(!IsXHTML() || aMode
== eCompatibility_FullStandards
,
1152 "Bad compat mode for XHTML document!");
1154 mCompatMode
= aMode
;
1155 CSSLoader()->SetCompatibilityMode(mCompatMode
);
1156 nsCOMPtr
<nsIPresShell
> shell
= GetPrimaryShell();
1158 nsPresContext
*pc
= shell
->GetPresContext();
1160 pc
->CompatibilityModeChanged();
1166 nsHTMLDocument::IsCaseSensitive()
1172 // nsIDOMDocument interface implementation
1175 nsHTMLDocument::CreateElement(const nsAString
& aTagName
,
1176 nsIDOMElement
** aReturn
)
1181 nsAutoString
tagName(aTagName
);
1183 // if we are in quirks, allow surrounding '<' '>' for IE compat
1184 if (mCompatMode
== eCompatibility_NavQuirks
&&
1185 tagName
.Length() > 2 &&
1186 tagName
.First() == '<' &&
1187 tagName
.Last() == '>') {
1188 tagName
= Substring(tagName
, 1, tagName
.Length() - 2);
1191 rv
= nsContentUtils::CheckQName(tagName
, PR_FALSE
);
1192 NS_ENSURE_SUCCESS(rv
, rv
);
1195 ToLowerCase(tagName
);
1198 nsCOMPtr
<nsIAtom
> name
= do_GetAtom(tagName
);
1200 nsCOMPtr
<nsIContent
> content
;
1201 rv
= CreateElem(name
, nsnull
, GetDefaultNamespaceID(), PR_TRUE
,
1202 getter_AddRefs(content
));
1203 NS_ENSURE_SUCCESS(rv
, rv
);
1205 return CallQueryInterface(content
, aReturn
);
1209 nsHTMLDocument::CreateElementNS(const nsAString
& aNamespaceURI
,
1210 const nsAString
& aQualifiedName
,
1211 nsIDOMElement
** aReturn
)
1213 return nsDocument::CreateElementNS(aNamespaceURI
, aQualifiedName
, aReturn
);
1217 nsHTMLDocument::CreateProcessingInstruction(const nsAString
& aTarget
,
1218 const nsAString
& aData
,
1219 nsIDOMProcessingInstruction
** aReturn
)
1222 return nsDocument::CreateProcessingInstruction(aTarget
, aData
, aReturn
);
1225 // There are no PIs for HTML
1228 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1232 nsHTMLDocument::CreateCDATASection(const nsAString
& aData
,
1233 nsIDOMCDATASection
** aReturn
)
1236 return nsDocument::CreateCDATASection(aData
, aReturn
);
1239 // There are no CDATASections in HTML
1242 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1246 nsHTMLDocument::CreateEntityReference(const nsAString
& aName
,
1247 nsIDOMEntityReference
** aReturn
)
1250 return nsDocument::CreateEntityReference(aName
, aReturn
);
1253 // There are no EntityReferences in HTML
1256 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1260 nsHTMLDocument::GetDoctype(nsIDOMDocumentType
** aDocumentType
)
1262 return nsDocument::GetDoctype(aDocumentType
);
1266 nsHTMLDocument::GetImplementation(nsIDOMDOMImplementation
** aImplementation
)
1268 return nsDocument::GetImplementation(aImplementation
);
1272 nsHTMLDocument::GetDocumentElement(nsIDOMElement
** aDocumentElement
)
1274 return nsDocument::GetDocumentElement(aDocumentElement
);
1278 nsHTMLDocument::CreateDocumentFragment(nsIDOMDocumentFragment
** aReturn
)
1280 return nsDocument::CreateDocumentFragment(aReturn
);
1284 nsHTMLDocument::CreateComment(const nsAString
& aData
, nsIDOMComment
** aReturn
)
1286 return nsDocument::CreateComment(aData
, aReturn
);
1290 nsHTMLDocument::CreateAttribute(const nsAString
& aName
, nsIDOMAttr
** aReturn
)
1292 return nsDocument::CreateAttribute(aName
, aReturn
);
1296 nsHTMLDocument::CreateTextNode(const nsAString
& aData
, nsIDOMText
** aReturn
)
1298 return nsDocument::CreateTextNode(aData
, aReturn
);
1302 nsHTMLDocument::GetElementsByTagName(const nsAString
& aTagname
,
1303 nsIDOMNodeList
** aReturn
)
1305 nsAutoString
tmp(aTagname
);
1307 ToLowerCase(tmp
); // HTML elements are lower case internally.
1309 return nsDocument::GetElementsByTagName(tmp
, aReturn
);
1313 nsHTMLDocument::GetBaseURI(nsAString
&aURI
)
1316 nsIURI
*uri
= mDocumentBaseURI
; // WEAK
1326 CopyUTF8toUTF16(spec
, aURI
);
1332 // nsIDOM3Document interface implementation
1334 nsHTMLDocument::GetXmlEncoding(nsAString
& aXmlEncoding
)
1337 return nsDocument::GetXmlEncoding(aXmlEncoding
);
1340 SetDOMStringToNull(aXmlEncoding
);
1346 nsHTMLDocument::GetXmlStandalone(PRBool
*aXmlStandalone
)
1349 return nsDocument::GetXmlStandalone(aXmlStandalone
);
1352 *aXmlStandalone
= PR_FALSE
;
1358 nsHTMLDocument::SetXmlStandalone(PRBool aXmlStandalone
)
1361 return nsDocument::SetXmlStandalone(aXmlStandalone
);
1364 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1369 nsHTMLDocument::GetXmlVersion(nsAString
& aXmlVersion
)
1372 return nsDocument::GetXmlVersion(aXmlVersion
);
1375 SetDOMStringToNull(aXmlVersion
);
1381 nsHTMLDocument::SetXmlVersion(const nsAString
& aXmlVersion
)
1384 return nsDocument::SetXmlVersion(aXmlVersion
);
1387 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1391 // nsIDOMHTMLDocument interface implementation
1394 nsHTMLDocument::GetTitle(nsAString
& aTitle
)
1396 return nsDocument::GetTitle(aTitle
);
1400 nsHTMLDocument::GetReferrer(nsAString
& aReferrer
)
1402 return nsDocument::GetReferrer(aReferrer
);
1406 nsHTMLDocument::GetDomainURI(nsIURI
**aURI
)
1408 nsIPrincipal
*principal
= NodePrincipal();
1410 principal
->GetDomain(aURI
);
1412 principal
->GetURI(aURI
);
1418 nsHTMLDocument::GetDomain(nsAString
& aDomain
)
1420 nsCOMPtr
<nsIURI
> uri
;
1421 GetDomainURI(getter_AddRefs(uri
));
1424 return NS_ERROR_FAILURE
;
1427 nsCAutoString hostName
;
1429 if (NS_SUCCEEDED(uri
->GetHost(hostName
))) {
1430 CopyUTF8toUTF16(hostName
, aDomain
);
1432 // If we can't get the host from the URI (e.g. about:, javascript:,
1433 // etc), just return an null string.
1434 SetDOMStringToNull(aDomain
);
1441 nsHTMLDocument::SetDomain(const nsAString
& aDomain
)
1443 if (aDomain
.IsEmpty())
1444 return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN
;
1447 nsCOMPtr
<nsIURI
> uri
;
1448 GetDomainURI(getter_AddRefs(uri
));
1451 return NS_ERROR_FAILURE
;
1454 nsCAutoString newURIString
;
1455 if (NS_FAILED(uri
->GetScheme(newURIString
)))
1456 return NS_ERROR_FAILURE
;
1458 if (NS_FAILED(uri
->GetPath(path
)))
1459 return NS_ERROR_FAILURE
;
1460 newURIString
.AppendLiteral("://");
1461 AppendUTF16toUTF8(aDomain
, newURIString
);
1462 newURIString
.Append(path
);
1464 nsCOMPtr
<nsIURI
> newURI
;
1465 if (NS_FAILED(NS_NewURI(getter_AddRefs(newURI
), newURIString
)))
1466 return NS_ERROR_FAILURE
;
1468 // Check new domain - must be a superdomain of the current host
1469 // For example, a page from foo.bar.com may set domain to bar.com,
1470 // but not to ar.com, baz.com, or fi.foo.bar.com.
1471 nsCAutoString current
, domain
;
1472 if (NS_FAILED(uri
->GetAsciiHost(current
)))
1474 if (NS_FAILED(newURI
->GetAsciiHost(domain
)))
1477 PRBool ok
= current
.Equals(domain
);
1478 if (current
.Length() > domain
.Length() &&
1479 StringEndsWith(current
, domain
) &&
1480 current
.CharAt(current
.Length() - domain
.Length() - 1) == '.') {
1481 // We're golden if the new domain is the current page's base domain or a
1483 nsCOMPtr
<nsIEffectiveTLDService
> tldService
=
1484 do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID
);
1486 return NS_ERROR_NOT_AVAILABLE
;
1488 nsCAutoString currentBaseDomain
;
1489 ok
= NS_SUCCEEDED(tldService
->GetBaseDomain(uri
, 0, currentBaseDomain
));
1490 NS_ASSERTION(StringEndsWith(domain
, currentBaseDomain
) ==
1491 (domain
.Length() >= currentBaseDomain
.Length()),
1492 "uh-oh! slight optimization wasn't valid somehow!");
1493 ok
= ok
&& domain
.Length() >= currentBaseDomain
.Length();
1496 // Error: illegal domain
1497 return NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN
;
1500 return NodePrincipal()->SetDomain(newURI
);
1504 nsHTMLDocument::GetURL(nsAString
& aURL
)
1509 mDocumentURI
->GetSpec(str
);
1512 CopyUTF8toUTF16(str
, aURL
);
1518 nsHTMLDocument::GetBody(nsIDOMHTMLElement
** aBody
)
1522 nsIContent
* body
= GetBodyContent();
1525 // There is a body element, return that as the body.
1526 return CallQueryInterface(body
, aBody
);
1529 // The document is most likely a frameset document so look for the
1530 // outer most frameset element
1531 nsCOMPtr
<nsIDOMNodeList
> nodeList
;
1535 rv
= GetElementsByTagNameNS(NS_LITERAL_STRING("http://www.w3.org/1999/xhtml"),
1536 NS_LITERAL_STRING("frameset"),
1537 getter_AddRefs(nodeList
));
1539 rv
= GetElementsByTagName(NS_LITERAL_STRING("frameset"),
1540 getter_AddRefs(nodeList
));
1542 NS_ENSURE_SUCCESS(rv
, rv
);
1544 nsCOMPtr
<nsIDOMNode
> node
;
1545 nodeList
->Item(0, getter_AddRefs(node
));
1547 return node
? CallQueryInterface(node
, aBody
) : NS_OK
;
1551 nsHTMLDocument::SetBody(nsIDOMHTMLElement
* aBody
)
1553 nsCOMPtr
<nsIContent
> newBody
= do_QueryInterface(aBody
);
1554 nsIContent
* root
= GetRootContent();
1556 // The body element must be either a body tag or a frameset tag. And we must
1557 // have a html root tag, otherwise GetBody will not return the newly set
1559 if (!newBody
|| !(newBody
->Tag() == nsGkAtoms::body
||
1560 newBody
->Tag() == nsGkAtoms::frameset
) ||
1561 !root
|| !root
->IsNodeOfType(nsINode::eHTML
) ||
1562 root
->Tag() != nsGkAtoms::html
) {
1563 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1566 nsCOMPtr
<nsIDOMElement
> rootElem
= do_QueryInterface(root
);
1567 nsCOMPtr
<nsIDOMNode
> tmp
;
1569 // Use DOM methods so that we pass through the appropriate security checks.
1570 nsCOMPtr
<nsIDOMNode
> currentBody
= do_QueryInterface(GetBodyContent());
1572 return rootElem
->ReplaceChild(aBody
, currentBody
, getter_AddRefs(tmp
));
1575 return rootElem
->AppendChild(aBody
, getter_AddRefs(tmp
));
1579 nsHTMLDocument::GetImages(nsIDOMHTMLCollection
** aImages
)
1582 mImages
= new nsContentList(this, nsGkAtoms::img
, GetDefaultNamespaceID());
1584 return NS_ERROR_OUT_OF_MEMORY
;
1589 NS_ADDREF(*aImages
);
1595 nsHTMLDocument::GetApplets(nsIDOMHTMLCollection
** aApplets
)
1598 mApplets
= new nsContentList(this, nsGkAtoms::applet
,
1599 GetDefaultNamespaceID());
1601 return NS_ERROR_OUT_OF_MEMORY
;
1605 *aApplets
= mApplets
;
1606 NS_ADDREF(*aApplets
);
1612 nsHTMLDocument::MatchLinks(nsIContent
*aContent
, PRInt32 aNamespaceID
,
1613 nsIAtom
* aAtom
, void* aData
)
1615 nsIDocument
* doc
= aContent
->GetCurrentDoc();
1618 NS_ASSERTION(aContent
->IsInDoc(),
1619 "This method should never be called on content nodes that "
1620 "are not in a document!");
1623 nsCOMPtr
<nsIHTMLDocument
> htmldoc
=
1624 do_QueryInterface(aContent
->GetCurrentDoc());
1625 NS_ASSERTION(htmldoc
,
1626 "Huh, how did this happen? This should only be used with "
1631 nsINodeInfo
*ni
= aContent
->NodeInfo();
1632 PRInt32 namespaceID
= doc
->GetDefaultNamespaceID();
1634 nsIAtom
*localName
= ni
->NameAtom();
1635 if (ni
->NamespaceID() == namespaceID
&&
1636 (localName
== nsGkAtoms::a
|| localName
== nsGkAtoms::area
)) {
1637 return aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::href
);
1645 nsHTMLDocument::GetLinks(nsIDOMHTMLCollection
** aLinks
)
1648 mLinks
= new nsContentList(this, MatchLinks
, nsnull
, nsnull
);
1650 return NS_ERROR_OUT_OF_MEMORY
;
1661 nsHTMLDocument::MatchAnchors(nsIContent
*aContent
, PRInt32 aNamespaceID
,
1662 nsIAtom
* aAtom
, void* aData
)
1664 NS_ASSERTION(aContent
->IsInDoc(),
1665 "This method should never be called on content nodes that "
1666 "are not in a document!");
1669 nsCOMPtr
<nsIHTMLDocument
> htmldoc
=
1670 do_QueryInterface(aContent
->GetCurrentDoc());
1671 NS_ASSERTION(htmldoc
,
1672 "Huh, how did this happen? This should only be used with "
1677 PRInt32 namespaceID
= aContent
->GetCurrentDoc()->GetDefaultNamespaceID();
1678 if (aContent
->NodeInfo()->Equals(nsGkAtoms::a
, namespaceID
)) {
1679 return aContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::name
);
1686 nsHTMLDocument::GetAnchors(nsIDOMHTMLCollection
** aAnchors
)
1689 mAnchors
= new nsContentList(this, MatchAnchors
, nsnull
, nsnull
);
1691 return NS_ERROR_OUT_OF_MEMORY
;
1695 *aAnchors
= mAnchors
;
1696 NS_ADDREF(*aAnchors
);
1702 nsHTMLDocument::GetCookie(nsAString
& aCookie
)
1704 aCookie
.Truncate(); // clear current cookie in case service fails;
1705 // no cookie isn't an error condition.
1707 // not having a cookie service isn't an error
1708 nsCOMPtr
<nsICookieService
> service
= do_GetService(NS_COOKIESERVICE_CONTRACTID
);
1710 // Get a URI from the document principal. We use the original
1711 // codebase in case the codebase was changed by SetDomain
1712 nsCOMPtr
<nsIURI
> codebaseURI
;
1713 NodePrincipal()->GetURI(getter_AddRefs(codebaseURI
));
1716 // Document's principal is not a codebase (may be system), so
1717 // can't set cookies
1722 nsXPIDLCString cookie
;
1723 service
->GetCookieString(codebaseURI
, mChannel
, getter_Copies(cookie
));
1724 CopyASCIItoUTF16(cookie
, aCookie
);
1731 nsHTMLDocument::SetCookie(const nsAString
& aCookie
)
1733 // not having a cookie service isn't an error
1734 nsCOMPtr
<nsICookieService
> service
= do_GetService(NS_COOKIESERVICE_CONTRACTID
);
1735 if (service
&& mDocumentURI
) {
1736 nsCOMPtr
<nsIPrompt
> prompt
;
1737 nsCOMPtr
<nsPIDOMWindow
> window
= GetWindow();
1739 window
->GetPrompter(getter_AddRefs(prompt
));
1742 nsCOMPtr
<nsIURI
> codebaseURI
;
1743 NodePrincipal()->GetURI(getter_AddRefs(codebaseURI
));
1746 // Document's principal is not a codebase (may be system), so
1747 // can't set cookies
1752 NS_LossyConvertUTF16toASCII
cookie(aCookie
);
1753 service
->SetCookieString(codebaseURI
, prompt
, cookie
.get(), mChannel
);
1759 // XXX TBI: accepting arguments to the open method.
1761 nsHTMLDocument::OpenCommon(const nsACString
& aContentType
, PRBool aReplace
)
1764 // No calling document.open() on XHTML
1766 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1769 nsresult rv
= NS_OK
;
1771 // If we already have a parser we ignore the document.open call.
1777 NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument
*>(this)),
1778 "XOW should have caught this!");
1780 if (!aContentType
.EqualsLiteral("text/html") &&
1781 !aContentType
.EqualsLiteral("text/plain")) {
1782 NS_WARNING("Unsupported type; fix the caller");
1783 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
1786 // check whether we're in the middle of unload. If so, ignore this call.
1787 nsCOMPtr
<nsIDocShell
> shell
= do_QueryReferent(mDocumentContainer
);
1789 // We won't be able to create a parser anyway.
1794 shell
->GetIsInUnload(&inUnload
);
1799 // Note: We want to use GetDocumentFromContext here because this document
1800 // should inherit the security information of the document that's opening us,
1801 // (since if it's secure, then it's presumeably trusted).
1802 nsCOMPtr
<nsIDocument
> callerDoc
=
1803 do_QueryInterface(nsContentUtils::GetDocumentFromContext());
1805 // Grab a reference to the calling documents security info (if any)
1806 // and principal as it may be lost in the call to Reset().
1807 nsCOMPtr
<nsISupports
> securityInfo
;
1809 securityInfo
= callerDoc
->GetSecurityInfo();
1812 nsCOMPtr
<nsIPrincipal
> callerPrincipal
;
1813 nsIScriptSecurityManager
*secMan
= nsContentUtils::GetSecurityManager();
1815 secMan
->GetSubjectPrincipal(getter_AddRefs(callerPrincipal
));
1817 if (!callerPrincipal
) {
1818 // If we're called from C++ we can't do a document.open w/o
1819 // changing the principal of the document to something like
1820 // about:blank (as that's the only sane thing to do when we don't
1821 // know the origin of this call), and since we can't change the
1822 // principals of a document for security reasons we'll have to
1823 // refuse to go ahead with this call.
1825 return NS_ERROR_DOM_SECURITY_ERR
;
1828 // We're called from script. Make sure the script is from the same
1829 // origin, not just that the caller can access the document. This is
1830 // needed to keep document principals from ever changing, which is
1831 // needed because of the way we use our XOW code, and is a sane
1832 // thing to do anyways.
1834 PRBool equals
= PR_FALSE
;
1835 if (NS_FAILED(callerPrincipal
->Equals(NodePrincipal(), &equals
)) ||
1837 return NS_ERROR_DOM_SECURITY_ERR
;
1840 // The URI for the document after this call. Get it from the calling
1841 // principal (if available), or set it to "about:blank" if no
1842 // principal is reachable.
1843 nsCOMPtr
<nsIURI
> uri
;
1844 callerPrincipal
->GetURI(getter_AddRefs(uri
));
1847 rv
= NS_NewURI(getter_AddRefs(uri
),
1848 NS_LITERAL_CSTRING("about:blank"));
1849 NS_ENSURE_SUCCESS(rv
, rv
);
1852 // Stop current loads targeted at the window this document is in.
1853 if (mScriptGlobalObject
) {
1854 nsCOMPtr
<nsIContentViewer
> cv
;
1855 shell
->GetContentViewer(getter_AddRefs(cv
));
1859 rv
= cv
->PermitUnload(&okToUnload
);
1861 if (NS_SUCCEEDED(rv
) && !okToUnload
) {
1862 // We don't want to unload, so stop here, but don't throw an
1868 nsCOMPtr
<nsIWebNavigation
> webnav(do_QueryInterface(shell
));
1869 webnav
->Stop(nsIWebNavigation::STOP_NETWORK
);
1872 // The open occurred after the document finished loading.
1873 // So we reset the document and create a new one.
1874 nsCOMPtr
<nsIChannel
> channel
;
1875 nsCOMPtr
<nsILoadGroup
> group
= do_QueryReferent(mDocumentLoadGroup
);
1877 rv
= NS_NewChannel(getter_AddRefs(channel
), uri
, nsnull
, group
);
1879 if (NS_FAILED(rv
)) {
1883 // Set the caller principal, if any, on the channel so that we'll
1884 // make sure to use it when we reset.
1885 rv
= channel
->SetOwner(callerPrincipal
);
1886 NS_ENSURE_SUCCESS(rv
, rv
);
1888 // Before we reset the doc notify the globalwindow of the change,
1889 // but only if we still have a window (i.e. our window object the
1890 // current inner window in our outer window).
1892 // Hold onto ourselves on the offchance that we're down to one ref
1893 nsCOMPtr
<nsIDOMDocument
> kungFuDeathGrip
=
1894 do_QueryInterface((nsIHTMLDocument
*)this);
1896 nsPIDOMWindow
*window
= GetInnerWindow();
1898 // Remember the old scope in case the call to SetNewDocument changes it.
1899 nsCOMPtr
<nsIScriptGlobalObject
> oldScope(do_QueryReferent(mScopeObject
));
1901 rv
= window
->SetNewDocument(this, nsnull
, PR_FALSE
);
1902 NS_ENSURE_SUCCESS(rv
, rv
);
1904 // Now make sure we're not flagged as the initial document anymore, now
1905 // that we've had stuff done to us. From now on, if anyone tries to
1906 // document.open() us, they get a new inner window.
1907 SetIsInitialDocument(PR_FALSE
);
1909 nsCOMPtr
<nsIScriptGlobalObject
> newScope(do_QueryReferent(mScopeObject
));
1910 if (oldScope
&& newScope
!= oldScope
) {
1911 nsContentUtils::ReparentContentWrappersInScope(oldScope
, newScope
);
1915 // XXX This is a nasty workaround for a scrollbar code bug
1916 // (http://bugzilla.mozilla.org/show_bug.cgi?id=55334).
1918 // Hold on to our root element
1919 nsCOMPtr
<nsIContent
> root
= GetRootContent();
1922 PRInt32 rootIndex
= mChildren
.IndexOfChild(root
);
1923 NS_ASSERTION(rootIndex
>= 0, "Root must be in list!");
1925 PRUint32 count
= root
->GetChildCount();
1927 // Remove all the children from the root.
1928 while (count
-- > 0) {
1929 root
->RemoveChildAt(count
, PR_TRUE
);
1932 count
= root
->GetAttrCount();
1934 // Remove all attributes from the root element
1935 while (count
-- > 0) {
1936 const nsAttrName
* name
= root
->GetAttrNameAt(count
);
1937 // Hold a strong reference here so that the atom doesn't go away during
1939 nsCOMPtr
<nsIAtom
> localName
= name
->LocalName();
1940 root
->UnsetAttr(name
->NamespaceID(), localName
, PR_FALSE
);
1943 // Remove the root from the childlist
1944 mChildren
.RemoveChildAt(rootIndex
);
1945 mCachedRootContent
= nsnull
;
1948 // Call Reset(), this will now do the full reset, except removing
1949 // the root from the document, doing that confuses the scrollbar
1950 // code in mozilla since the document in the root element and all
1951 // the anonymous content (i.e. scrollbar elements) is set to
1954 Reset(channel
, group
);
1957 // Tear down the frames for the root element.
1958 MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL
, PR_TRUE
);
1959 nsNodeUtils::ContentRemoved(this, root
, 0);
1961 // Put the root element back into the document, we don't notify
1962 // the document about this insertion since the sink will do that
1963 // for us and that'll create frames for the root element and the
1964 // scrollbars work as expected (since the document in the root
1965 // element was never set to null)
1967 mChildren
.AppendChild(root
);
1970 if (IsEditingOn()) {
1971 // Reset() blows away all event listeners in the document, and our
1972 // editor relies heavily on those. Midas is turned on, to make it
1973 // work, re-initialize it to give it a chance to add its event
1977 EditingStateChanged();
1980 // Zap the old title -- otherwise it would hang around until document.close()
1981 // (which might never come) if the new document doesn't explicitly set one.
1982 // Void the title to make sure that we actually respect any titles set by the
1984 SetTitle(EmptyString());
1985 mDocumentTitle
.SetIsVoid(PR_TRUE
);
1987 // Store the security info of the caller now that we're done
1988 // resetting the document.
1989 mSecurityInfo
= securityInfo
;
1991 mParser
= do_CreateInstance(kCParserCID
, &rv
);
1993 // This will be propagated to the parser when someone actually calls write()
1994 mContentType
= aContentType
;
1996 mWriteState
= eDocumentOpened
;
1998 if (NS_SUCCEEDED(rv
)) {
1999 nsCOMPtr
<nsIHTMLContentSink
> sink
;
2001 rv
= NS_NewHTMLContentSink(getter_AddRefs(sink
), this, uri
, shell
,
2003 if (NS_FAILED(rv
)) {
2004 // Don't use a parser without a content sink.
2006 mWriteState
= eNotWriting
;
2010 mParser
->SetContentSink(sink
);
2013 // Prepare the docshell and the document viewer for the impending
2014 // out of band document.write()
2015 shell
->PrepareForNewContentModel();
2017 // Now check whether we were opened with a "replace" argument. If
2018 // so, we need to tell the docshell to not create a new history
2019 // entry for this load. Otherwise, make sure that we're doing a normal load,
2020 // not whatever type of load was previously done on this docshell.
2021 shell
->SetLoadType(aReplace
? LOAD_NORMAL_REPLACE
: LOAD_NORMAL
);
2023 nsCOMPtr
<nsIContentViewer
> cv
;
2024 shell
->GetContentViewer(getter_AddRefs(cv
));
2025 nsCOMPtr
<nsIDocumentViewer
> docViewer
= do_QueryInterface(cv
);
2027 docViewer
->LoadStart(static_cast<nsIHTMLDocument
*>(this));
2030 // Add a wyciwyg channel request into the document load group
2031 NS_ASSERTION(!mWyciwygChannel
, "nsHTMLDocument::OpenCommon(): wyciwyg "
2032 "channel already exists!");
2034 // In case the editor is listening and will see the new channel
2035 // being added, make sure mWriteLevel is non-zero so that the editor
2036 // knows that document.open/write/close() is being called on this
2040 CreateAndAddWyciwygChannel();
2048 nsHTMLDocument::Open()
2050 nsCOMPtr
<nsIDOMDocument
> doc
;
2051 return Open(NS_LITERAL_CSTRING("text/html"), PR_FALSE
, getter_AddRefs(doc
));
2055 nsHTMLDocument::Open(const nsACString
& aContentType
, PRBool aReplace
,
2056 nsIDOMDocument
** aReturn
)
2058 nsresult rv
= OpenCommon(aContentType
, aReplace
);
2059 NS_ENSURE_SUCCESS(rv
, rv
);
2061 return CallQueryInterface(this, aReturn
);
2065 nsHTMLDocument::Clear()
2067 // This method has been deprecated
2072 nsHTMLDocument::Close()
2075 // No calling document.close() on XHTML!
2077 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2080 nsresult rv
= NS_OK
;
2082 if (mParser
&& mWriteState
== eDocumentOpened
) {
2083 mPendingScripts
.RemoveElement(GenerateParserKey());
2085 mWriteState
= mPendingScripts
.Count() == 0
2090 rv
= mParser
->Parse(EmptyString(), mParser
->GetRootContextKey(),
2091 mContentType
, PR_TRUE
);
2094 // XXX Make sure that all the document.written content is
2095 // reflowed. We should remove this call once we change
2096 // nsHTMLDocument::OpenCommon() so that it completely destroys the
2097 // earlier document's content and frame hierarchy. Right now, it
2098 // re-uses the earlier document's root content object and
2099 // corresponding frame objects. These re-used frame objects think
2100 // that they have already been reflowed, so they drop initial
2101 // reflows. For certain cases of document.written content, like a
2102 // frameset document, the dropping of the initial reflow means
2103 // that we end up in document.close() without appended any reflow
2104 // commands to the reflow queue and, consequently, without adding
2105 // the dummy layout request to the load group. Since the dummy
2106 // layout request is not added to the load group, the onload
2107 // handler of the frameset fires before the frames get reflowed
2108 // and loaded. That is the long explanation for why we need this
2109 // one line of code here!
2110 // XXXbz as far as I can tell this may not be needed anymore; all
2111 // the testcases in bug 57636 pass without this line... Leaving
2112 // it be for now, though. In any case, there's no reason to do
2113 // this if we have no presshell, since in that case none of the
2114 // above about reusing frames applies.
2115 if (GetPrimaryShell()) {
2116 FlushPendingNotifications(Flush_Layout
);
2119 // Remove the wyciwyg channel request from the document load group
2120 // that we added in OpenCommon(). If all other requests between
2121 // document.open() and document.close() have completed, then this
2122 // method should cause the firing of an onload event.
2123 NS_ASSERTION(mWyciwygChannel
, "nsHTMLDocument::Close(): Trying to remove "
2124 "non-existent wyciwyg channel!");
2125 RemoveWyciwygChannel();
2126 NS_ASSERTION(!mWyciwygChannel
, "nsHTMLDocument::Close(): "
2127 "nsIWyciwygChannel could not be removed!");
2134 nsHTMLDocument::WriteCommon(const nsAString
& aText
,
2135 PRBool aNewlineTerminate
)
2137 mTooDeepWriteRecursion
=
2138 (mWriteLevel
> NS_MAX_DOCUMENT_WRITE_DEPTH
|| mTooDeepWriteRecursion
);
2139 NS_ENSURE_STATE(!mTooDeepWriteRecursion
);
2142 // No calling document.write*() on XHTML!
2144 return NS_ERROR_DOM_NOT_SUPPORTED_ERR
;
2147 nsresult rv
= NS_OK
;
2149 void *key
= GenerateParserKey();
2150 if (mWriteState
== eDocumentClosed
||
2151 (mWriteState
== ePendingClose
&&
2152 mPendingScripts
.IndexOf(key
) == kNotFound
)) {
2153 mWriteState
= eDocumentClosed
;
2154 mParser
->Terminate();
2155 NS_ASSERTION(!mParser
, "mParser should have been null'd out");
2161 // If Open() fails, or if it didn't create a parser (as it won't
2162 // if the user chose to not discard the current document through
2163 // onbeforeunload), don't write anything.
2164 if (NS_FAILED(rv
) || !mParser
) {
2169 static NS_NAMED_LITERAL_STRING(new_line
, "\n");
2171 // Save the data in cache
2172 if (mWyciwygChannel
) {
2173 if (!aText
.IsEmpty()) {
2174 mWyciwygChannel
->WriteToCacheEntry(aText
);
2177 if (aNewlineTerminate
) {
2178 mWyciwygChannel
->WriteToCacheEntry(new_line
);
2184 // This could be done with less code, but for performance reasons it
2185 // makes sense to have the code for two separate Parse() calls here
2186 // since the concatenation of strings costs more than we like. And
2187 // why pay that price when we don't need to?
2188 if (aNewlineTerminate
) {
2189 rv
= mParser
->Parse(aText
+ new_line
,
2191 (mWriteState
== eNotWriting
|| (mWriteLevel
> 1)));
2193 rv
= mParser
->Parse(aText
,
2195 (mWriteState
== eNotWriting
|| (mWriteLevel
> 1)));
2200 mTooDeepWriteRecursion
= (mWriteLevel
!= 0 && mTooDeepWriteRecursion
);
2206 nsHTMLDocument::Write(const nsAString
& aText
)
2208 return WriteCommon(aText
, PR_FALSE
);
2212 nsHTMLDocument::Writeln(const nsAString
& aText
)
2214 return WriteCommon(aText
, PR_TRUE
);
2218 nsHTMLDocument::ScriptWriteCommon(PRBool aNewlineTerminate
)
2220 nsAXPCNativeCallContext
*ncc
= nsnull
;
2222 nsresult rv
= nsContentUtils::XPConnect()->
2223 GetCurrentNativeCallContext(&ncc
);
2224 NS_ENSURE_SUCCESS(rv
, rv
);
2227 // We're called from JS, concatenate the extra arguments into
2231 ncc
->GetArgc(&argc
);
2233 JSContext
*cx
= nsnull
;
2234 rv
= ncc
->GetJSContext(&cx
);
2235 NS_ENSURE_SUCCESS(rv
, rv
);
2237 jsval
*argv
= nsnull
;
2238 ncc
->GetArgvPtr(&argv
);
2239 NS_ENSURE_TRUE(argv
, NS_ERROR_UNEXPECTED
);
2242 JSAutoRequest
ar(cx
);
2244 JSString
*jsstr
= JS_ValueToString(cx
, argv
[0]);
2245 NS_ENSURE_TRUE(jsstr
, NS_ERROR_OUT_OF_MEMORY
);
2247 nsDependentString
str(reinterpret_cast<const PRUnichar
*>
2248 (::JS_GetStringChars(jsstr
)),
2249 ::JS_GetStringLength(jsstr
));
2251 return WriteCommon(str
, aNewlineTerminate
);
2255 nsAutoString string_buffer
;
2257 for (i
= 0; i
< argc
; ++i
) {
2258 JSAutoRequest
ar(cx
);
2260 JSString
*str
= JS_ValueToString(cx
, argv
[i
]);
2261 NS_ENSURE_TRUE(str
, NS_ERROR_OUT_OF_MEMORY
);
2263 string_buffer
.Append(reinterpret_cast<const PRUnichar
*>
2264 (::JS_GetStringChars(str
)),
2265 ::JS_GetStringLength(str
));
2268 return WriteCommon(string_buffer
, aNewlineTerminate
);
2273 return WriteCommon(EmptyString(), aNewlineTerminate
);
2277 nsHTMLDocument::Write()
2279 return ScriptWriteCommon(PR_FALSE
);
2283 nsHTMLDocument::Writeln()
2285 return ScriptWriteCommon(PR_TRUE
);
2289 nsHTMLDocument::ImportNode(nsIDOMNode
* aImportedNode
,
2291 nsIDOMNode
** aReturn
)
2293 return nsDocument::ImportNode(aImportedNode
, aDeep
, aReturn
);
2297 nsHTMLDocument::CreateAttributeNS(const nsAString
& aNamespaceURI
,
2298 const nsAString
& aQualifiedName
,
2299 nsIDOMAttr
** aReturn
)
2301 return nsDocument::CreateAttributeNS(aNamespaceURI
, aQualifiedName
, aReturn
);
2305 nsHTMLDocument::GetElementsByTagNameNS(const nsAString
& aNamespaceURI
,
2306 const nsAString
& aLocalName
,
2307 nsIDOMNodeList
** aReturn
)
2309 nsAutoString
tmp(aLocalName
);
2312 ToLowerCase(tmp
); // HTML elements are lower case internally.
2315 return nsDocument::GetElementsByTagNameNS(aNamespaceURI
, tmp
, aReturn
);
2319 nsHTMLDocument::GetElementById(const nsAString
& aElementId
,
2320 nsIDOMElement
** aReturn
)
2322 return nsDocument::GetElementById(aElementId
, aReturn
);
2326 nsHTMLDocument::MatchNameAttribute(nsIContent
* aContent
, PRInt32 aNamespaceID
,
2327 nsIAtom
* aAtom
, void* aData
)
2329 NS_PRECONDITION(aContent
, "Must have content node to work with!");
2330 nsString
* elementName
= static_cast<nsString
*>(aData
);
2331 return aContent
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::name
,
2332 *elementName
, eCaseMatters
);
2336 nsHTMLDocument::GetElementsByName(const nsAString
& aElementName
,
2337 nsIDOMNodeList
** aReturn
)
2339 void* elementNameData
= new nsString(aElementName
);
2340 NS_ENSURE_TRUE(elementNameData
, NS_ERROR_OUT_OF_MEMORY
);
2341 nsContentList
* elements
=
2342 new nsContentList(this,
2344 nsContentUtils::DestroyMatchString
,
2346 NS_ENSURE_TRUE(elements
, NS_ERROR_OUT_OF_MEMORY
);
2348 *aReturn
= elements
;
2349 NS_ADDREF(*aReturn
);
2355 nsHTMLDocument::ScriptLoading(nsIScriptElement
*aScript
)
2357 if (mWriteState
== eNotWriting
) {
2361 mPendingScripts
.AppendElement(aScript
);
2365 nsHTMLDocument::ScriptExecuted(nsIScriptElement
*aScript
)
2367 if (mWriteState
== eNotWriting
) {
2371 mPendingScripts
.RemoveElement(aScript
);
2372 if (mPendingScripts
.Count() == 0 && mWriteState
== ePendingClose
) {
2373 // The last pending script just finished, terminate our parser now.
2374 mWriteState
= eDocumentClosed
;
2379 nsHTMLDocument::AddedForm()
2385 nsHTMLDocument::RemovedForm()
2391 nsHTMLDocument::GetNumFormsSynchronous()
2397 nsHTMLDocument::GetBodySize(PRInt32
* aWidth
,
2400 *aWidth
= *aHeight
= 0;
2402 FlushPendingNotifications(Flush_Layout
);
2404 nsCOMPtr
<nsIPresShell
> shell
= GetPrimaryShell();
2409 // Find the <body> element: this is what we'll want to use for the
2410 // document's width and height values.
2411 nsIContent
* body
= GetBodyContent();
2416 // Now grab its frame
2417 nsIFrame
* frame
= shell
->GetPrimaryFrameFor(body
);
2421 nsSize size
= frame
->GetSize();
2423 *aWidth
= nsPresContext::AppUnitsToIntCSSPixels(size
.width
);
2424 *aHeight
= nsPresContext::AppUnitsToIntCSSPixels(size
.height
);
2430 nsHTMLDocument::GetWidth(PRInt32
* aWidth
)
2432 NS_ENSURE_ARG_POINTER(aWidth
);
2435 return GetBodySize(aWidth
, &height
);
2439 nsHTMLDocument::GetHeight(PRInt32
* aHeight
)
2441 NS_ENSURE_ARG_POINTER(aHeight
);
2444 return GetBodySize(&width
, aHeight
);
2448 nsHTMLDocument::GetAlinkColor(nsAString
& aAlinkColor
)
2450 aAlinkColor
.Truncate();
2452 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2455 body
->GetALink(aAlinkColor
);
2456 } else if (mAttrStyleSheet
) {
2458 nsresult rv
= mAttrStyleSheet
->GetActiveLinkColor(color
);
2459 if (NS_SUCCEEDED(rv
)) {
2460 NS_RGBToHex(color
, aAlinkColor
);
2468 nsHTMLDocument::SetAlinkColor(const nsAString
& aAlinkColor
)
2470 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2473 body
->SetALink(aAlinkColor
);
2474 } else if (mAttrStyleSheet
) {
2476 if (value
.ParseColor(aAlinkColor
, this)) {
2478 value
.GetColorValue(color
);
2479 mAttrStyleSheet
->SetActiveLinkColor(color
);
2487 nsHTMLDocument::GetLinkColor(nsAString
& aLinkColor
)
2489 aLinkColor
.Truncate();
2491 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2494 body
->GetLink(aLinkColor
);
2495 } else if (mAttrStyleSheet
) {
2497 nsresult rv
= mAttrStyleSheet
->GetLinkColor(color
);
2498 if (NS_SUCCEEDED(rv
)) {
2499 NS_RGBToHex(color
, aLinkColor
);
2507 nsHTMLDocument::SetLinkColor(const nsAString
& aLinkColor
)
2509 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2512 body
->SetLink(aLinkColor
);
2513 } else if (mAttrStyleSheet
) {
2515 if (value
.ParseColor(aLinkColor
, this)) {
2517 value
.GetColorValue(color
);
2518 mAttrStyleSheet
->SetLinkColor(color
);
2526 nsHTMLDocument::GetVlinkColor(nsAString
& aVlinkColor
)
2528 aVlinkColor
.Truncate();
2530 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2533 body
->GetVLink(aVlinkColor
);
2534 } else if (mAttrStyleSheet
) {
2536 nsresult rv
= mAttrStyleSheet
->GetVisitedLinkColor(color
);
2537 if (NS_SUCCEEDED(rv
)) {
2538 NS_RGBToHex(color
, aVlinkColor
);
2546 nsHTMLDocument::SetVlinkColor(const nsAString
& aVlinkColor
)
2548 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2551 body
->SetVLink(aVlinkColor
);
2552 } else if (mAttrStyleSheet
) {
2554 if (value
.ParseColor(aVlinkColor
, this)) {
2556 value
.GetColorValue(color
);
2557 mAttrStyleSheet
->SetVisitedLinkColor(color
);
2565 nsHTMLDocument::GetBgColor(nsAString
& aBgColor
)
2567 aBgColor
.Truncate();
2569 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2572 body
->GetBgColor(aBgColor
);
2579 nsHTMLDocument::SetBgColor(const nsAString
& aBgColor
)
2581 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2584 body
->SetBgColor(aBgColor
);
2586 // XXXldb And otherwise?
2592 nsHTMLDocument::GetFgColor(nsAString
& aFgColor
)
2594 aFgColor
.Truncate();
2596 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2599 body
->GetText(aFgColor
);
2606 nsHTMLDocument::SetFgColor(const nsAString
& aFgColor
)
2608 nsCOMPtr
<nsIDOMHTMLBodyElement
> body
= do_QueryInterface(GetBodyContent());
2611 body
->SetText(aFgColor
);
2613 // XXXldb And otherwise?
2620 nsHTMLDocument::GetEmbeds(nsIDOMHTMLCollection
** aEmbeds
)
2623 mEmbeds
= new nsContentList(this, nsGkAtoms::embed
, GetDefaultNamespaceID());
2625 return NS_ERROR_OUT_OF_MEMORY
;
2630 NS_ADDREF(*aEmbeds
);
2636 nsHTMLDocument::GetSelection(nsAString
& aReturn
)
2640 nsCOMPtr
<nsIConsoleService
> consoleService
2641 (do_GetService("@mozilla.org/consoleservice;1"));
2643 if (consoleService
) {
2644 consoleService
->LogStringMessage(NS_LITERAL_STRING("Deprecated method document.getSelection() called. Please use window.getSelection() instead.").get());
2647 nsIDOMWindow
*window
= GetWindow();
2648 NS_ENSURE_TRUE(window
, NS_OK
);
2650 nsCOMPtr
<nsISelection
> selection
;
2651 nsresult rv
= window
->GetSelection(getter_AddRefs(selection
));
2652 NS_ENSURE_TRUE(selection
&& NS_SUCCEEDED(rv
), rv
);
2656 rv
= selection
->ToString(getter_Copies(str
));
2658 aReturn
.Assign(str
);
2664 ReportUseOfDeprecatedMethod(nsHTMLDocument
* aDoc
, const char* aWarning
)
2666 nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES
,
2669 static_cast<nsIDocument
*>(aDoc
)->
2671 EmptyString(), 0, 0,
2672 nsIScriptError::warningFlag
,
2677 nsHTMLDocument::CaptureEvents(PRInt32 aEventFlags
)
2679 ReportUseOfDeprecatedMethod(this, "UseOfCaptureEventsWarning");
2684 nsHTMLDocument::ReleaseEvents(PRInt32 aEventFlags
)
2686 ReportUseOfDeprecatedMethod(this, "UseOfReleaseEventsWarning");
2691 nsHTMLDocument::RouteEvent(nsIDOMEvent
* aEvt
)
2693 ReportUseOfDeprecatedMethod(this, "UseOfRouteEventWarning");
2697 // readonly attribute DOMString compatMode;
2698 // Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
2699 // in almost standards or full standards mode. See bug 105640. This was
2700 // implemented to match MSIE's compatMode property
2702 nsHTMLDocument::GetCompatMode(nsAString
& aCompatMode
)
2704 NS_ASSERTION(mCompatMode
== eCompatibility_NavQuirks
||
2705 mCompatMode
== eCompatibility_AlmostStandards
||
2706 mCompatMode
== eCompatibility_FullStandards
,
2707 "mCompatMode is neither quirks nor strict for this document");
2709 if (mCompatMode
== eCompatibility_NavQuirks
) {
2710 aCompatMode
.AssignLiteral("BackCompat");
2712 aCompatMode
.AssignLiteral("CSS1Compat");
2718 // Mapped to document.embeds for NS4 compatibility
2720 nsHTMLDocument::GetPlugins(nsIDOMHTMLCollection
** aPlugins
)
2724 return GetEmbeds(aPlugins
);
2728 FindNamedItems(nsIAtom
* aName
, nsIContent
*aContent
,
2729 nsIdentifierMapEntry
* aEntry
)
2731 NS_ASSERTION(aEntry
->HasNameContentList(),
2732 "Entry w/o content list passed to FindNamedItems()!");
2733 NS_ASSERTION(!aEntry
->IsInvalidName(),
2734 "Entry that should never have a list passed to FindNamedItems()!");
2736 if (aContent
->IsNodeOfType(nsINode::eTEXT
)) {
2737 // Text nodes are not named items nor can they have children.
2741 if (aName
== nsContentUtils::IsNamedItem(aContent
)) {
2742 aEntry
->AddNameContent(aContent
);
2745 if (!aEntry
->GetIdContent() &&
2746 // Maybe this node has the right id?
2747 aName
== aContent
->GetID()) {
2748 aEntry
->AddIdContent(aContent
);
2751 PRUint32 i
, count
= aContent
->GetChildCount();
2752 for (i
= 0; i
< count
; ++i
) {
2753 FindNamedItems(aName
, aContent
->GetChildAt(i
), aEntry
);
2758 nsHTMLDocument::ResolveName(const nsAString
& aName
,
2759 nsIDOMHTMLFormElement
*aForm
,
2760 nsISupports
**aResult
)
2764 if (!mIsRegularHTML
) {
2765 // We don't dynamically resolve names on non-HTML documents.
2769 nsCOMPtr
<nsIAtom
> name(do_GetAtom(aName
));
2771 // We have built a table and cache the named items. The table will
2772 // be updated as content is added and removed.
2773 nsIdentifierMapEntry
*entry
= mIdentifierMap
.PutEntry(name
);
2774 NS_ENSURE_TRUE(entry
, NS_ERROR_OUT_OF_MEMORY
);
2776 if (entry
->IsInvalidName()) {
2777 // There won't be any named items by this name -- it's reserved
2781 // Now we know we _might_ have items. Before looking at
2782 // entry->mNameContentList, make sure to flush out content (see
2784 // This is a perf killer while the document is loading!
2786 // Make sure to stash away the current generation so we can check whether the
2787 // table changes when we flush.
2788 PRUint32 generation
= mIdentifierMap
.GetGeneration();
2790 // If we already have an entry->mNameContentList, we need to flush out
2791 // notifications too, so that it will get updated properly.
2792 FlushPendingNotifications(entry
->HasNameContentList() ?
2793 Flush_ContentAndNotify
: Flush_Content
);
2795 if (generation
!= mIdentifierMap
.GetGeneration()) {
2796 // Table changed, so the entry pointer is no longer valid; look up the
2797 // entry again, adding if necessary (the adding may be necessary in case
2798 // the flush actually deleted entries).
2799 entry
= mIdentifierMap
.PutEntry(name
);
2800 NS_ENSURE_TRUE(entry
, NS_ERROR_OUT_OF_MEMORY
);
2803 if (!entry
->HasNameContentList()) {
2806 printf ("nsHTMLDocument name cache miss for name '%s'\n",
2807 NS_ConvertUTF16toUTF8(aName
).get());
2811 nsresult rv
= entry
->CreateNameContentList();
2815 nsIContent
* root
= GetRootContent();
2816 if (root
&& !aName
.IsEmpty()) {
2817 FindNamedItems(name
, root
, entry
);
2821 nsBaseContentList
*list
= entry
->GetNameContentList();
2824 list
->GetLength(&length
);
2828 // Only one element in the list, return the element instead of
2829 // returning the list
2831 nsCOMPtr
<nsIDOMNode
> node
;
2833 list
->Item(0, getter_AddRefs(node
));
2835 nsCOMPtr
<nsIContent
> ourContent(do_QueryInterface(node
));
2836 if (aForm
&& ourContent
&&
2837 !nsContentUtils::BelongsInForm(aForm
, ourContent
)) {
2838 // This is not the content you are looking for
2843 NS_IF_ADDREF(*aResult
);
2848 // The list contains more than one element, return the whole
2852 // ... we're called from a form, in that case we create a
2853 // nsFormNameContentList which will filter out the elements in the
2854 // list that don't belong to aForm
2856 nsFormContentList
*fc_list
= new nsFormContentList(aForm
, *list
);
2857 NS_ENSURE_TRUE(fc_list
, NS_ERROR_OUT_OF_MEMORY
);
2860 fc_list
->GetLength(&len
);
2863 // After the nsFormContentList is done filtering there's either
2864 // nothing or one element in the list. Return that element, or null
2865 // if there's no element in the list.
2867 nsCOMPtr
<nsIDOMNode
> node
;
2869 fc_list
->Item(0, getter_AddRefs(node
));
2871 NS_IF_ADDREF(*aResult
= node
);
2881 return CallQueryInterface(list
, aResult
);
2884 // No named items were found, see if there's one registerd by id for
2885 // aName. If we get this far, FindNamedItems() will have been called
2886 // for aName, so we're guaranteed that if there is an element with
2887 // the id aName, it'll be entry's IdContent.
2889 nsIContent
*e
= entry
->GetIdContent();
2891 if (e
&& e
->IsNodeOfType(nsINode::eHTML
)) {
2892 nsIAtom
*tag
= e
->Tag();
2894 if ((tag
== nsGkAtoms::embed
||
2895 tag
== nsGkAtoms::img
||
2896 tag
== nsGkAtoms::object
||
2897 tag
== nsGkAtoms::applet
) &&
2898 (!aForm
|| nsContentUtils::BelongsInForm(aForm
, e
))) {
2899 NS_ADDREF(*aResult
= e
);
2906 // Pre-fill the name hash with names that are likely to be resolved in
2907 // this document to avoid walking the tree looking for elements with
2911 nsHTMLDocument::PrePopulateIdentifierMap()
2913 static const char names
[][13] = {
2914 "write", "writeln", "open", "close", "forms", "elements",
2915 "characterSet", "nodeType", "parentNode", "cookie"
2918 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(names
); ++i
) {
2919 nsCOMPtr
<nsIAtom
> atom(do_GetAtom(names
[i
]));
2920 NS_ENSURE_TRUE(atom
, NS_ERROR_OUT_OF_MEMORY
);
2922 nsIdentifierMapEntry
* entry
= mIdentifierMap
.PutEntry(atom
);
2923 NS_ENSURE_TRUE(entry
, NS_ERROR_OUT_OF_MEMORY
);
2925 entry
->SetInvalidName();
2931 //----------------------------
2933 /* virtual */ nsIContent
*
2934 nsHTMLDocument::GetBodyContentExternal()
2936 return GetBodyContent();
2940 nsHTMLDocument::GetHtmlContent()
2942 nsIContent
* rootContent
= GetRootContent();
2943 if (rootContent
&& rootContent
->Tag() == nsGkAtoms::html
&&
2944 rootContent
->IsNodeOfType(nsINode::eHTML
))
2950 nsHTMLDocument::GetBodyContent()
2952 nsIContent
* html
= GetHtmlContent();
2956 // Look for body inside html. This needs to run forwards to find
2957 // the first body element.
2958 for (PRUint32 i
= 0; i
< html
->GetChildCount(); ++i
) {
2959 nsIContent
* body
= html
->GetChildAt(i
);
2960 if (body
->Tag() == nsGkAtoms::body
&&
2961 body
->IsNodeOfType(nsINode::eHTML
))
2967 // forms related stuff
2970 nsHTMLDocument::GetForms(nsIDOMHTMLCollection
** aForms
)
2972 nsContentList
*forms
= nsHTMLDocument::GetForms();
2974 return NS_ERROR_OUT_OF_MEMORY
;
2976 NS_ADDREF(*aForms
= forms
);
2981 nsHTMLDocument::GetForms()
2984 mForms
= new nsContentList(this, nsGkAtoms::form
, GetDefaultNamespaceID());
2989 static PRBool
MatchFormControls(nsIContent
* aContent
, PRInt32 aNamespaceID
,
2990 nsIAtom
* aAtom
, void* aData
)
2992 return aContent
->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL
);
2996 nsHTMLDocument::GetFormControls()
2998 if (!mFormControls
) {
2999 mFormControls
= new nsContentList(this, MatchFormControls
, nsnull
, nsnull
);
3002 return mFormControls
;
3006 nsHTMLDocument::CreateAndAddWyciwygChannel(void)
3008 nsresult rv
= NS_OK
;
3009 nsCAutoString url
, originalSpec
;
3011 mDocumentURI
->GetSpec(originalSpec
);
3013 // Generate the wyciwyg url
3014 url
= NS_LITERAL_CSTRING("wyciwyg://")
3015 + nsPrintfCString("%d", gWyciwygSessionCnt
++)
3016 + NS_LITERAL_CSTRING("/")
3019 nsCOMPtr
<nsIURI
> wcwgURI
;
3020 NS_NewURI(getter_AddRefs(wcwgURI
), url
);
3022 // Create the nsIWyciwygChannel to store out-of-band
3023 // document.write() script to cache
3024 nsCOMPtr
<nsIChannel
> channel
;
3025 // Create a wyciwyg Channel
3026 rv
= NS_NewChannel(getter_AddRefs(channel
), wcwgURI
);
3027 NS_ENSURE_SUCCESS(rv
, rv
);
3029 mWyciwygChannel
= do_QueryInterface(channel
);
3031 mWyciwygChannel
->SetSecurityInfo(mSecurityInfo
);
3033 // Note: we want to treat this like a "previous document" hint so that,
3034 // e.g. a <meta> tag in the document.write content can override it.
3035 SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc
);
3036 mWyciwygChannel
->SetCharsetAndSource(kCharsetFromHintPrevDoc
,
3037 GetDocumentCharacterSet());
3039 // Use our new principal
3040 channel
->SetOwner(NodePrincipal());
3042 // Inherit load flags from the original document's channel
3043 channel
->SetLoadFlags(mLoadFlags
);
3045 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
3047 // Use the Parent document's loadgroup to trigger load notifications
3048 if (loadGroup
&& channel
) {
3049 rv
= channel
->SetLoadGroup(loadGroup
);
3050 NS_ENSURE_SUCCESS(rv
, rv
);
3052 nsLoadFlags loadFlags
= 0;
3053 channel
->GetLoadFlags(&loadFlags
);
3054 loadFlags
|= nsIChannel::LOAD_DOCUMENT_URI
;
3055 channel
->SetLoadFlags(loadFlags
);
3057 channel
->SetOriginalURI(wcwgURI
);
3059 rv
= loadGroup
->AddRequest(mWyciwygChannel
, nsnull
);
3060 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to add request to load group.");
3067 nsHTMLDocument::RemoveWyciwygChannel(void)
3069 nsCOMPtr
<nsILoadGroup
> loadGroup
= GetDocumentLoadGroup();
3071 // note there can be a write request without a load group if
3072 // this is a synchronously constructed about:blank document
3073 if (loadGroup
&& mWyciwygChannel
) {
3074 mWyciwygChannel
->CloseCacheEntry(NS_OK
);
3075 loadGroup
->RemoveRequest(mWyciwygChannel
, nsnull
, NS_OK
);
3078 mWyciwygChannel
= nsnull
;
3084 nsHTMLDocument::GenerateParserKey(void)
3086 if (!mScriptLoader
) {
3087 // If we don't have a script loader, then the parser probably isn't parsing
3088 // anything anyway, so just return null.
3092 // The script loader provides us with the currently executing script element,
3093 // which is guaranteed to be unique per script.
3094 return mScriptLoader
->GetCurrentScript();
3097 /* attribute DOMString designMode; */
3099 nsHTMLDocument::GetDesignMode(nsAString
& aDesignMode
)
3101 if (HasFlag(NODE_IS_EDITABLE
)) {
3102 aDesignMode
.AssignLiteral("on");
3105 aDesignMode
.AssignLiteral("off");
3111 nsHTMLDocument::EndUpdate(nsUpdateType aUpdateType
)
3113 nsDocument::EndUpdate(aUpdateType
);
3115 if (mUpdateNestLevel
== 0 && mContentEditableCount
> 0 != IsEditingOn()) {
3116 EditingStateChanged();
3121 nsHTMLDocument::ChangeContentEditableCount(nsIContent
*aElement
,
3124 NS_ASSERTION(mContentEditableCount
+ aChange
>= 0,
3125 "Trying to decrement too much.");
3127 mContentEditableCount
+= aChange
;
3130 (mUpdateNestLevel
> 0 && mContentEditableCount
> 0 != IsEditingOn())) {
3134 EditingState oldState
= mEditingState
;
3136 nsresult rv
= EditingStateChanged();
3137 NS_ENSURE_SUCCESS(rv
, rv
);
3139 if (oldState
== mEditingState
&& mEditingState
== eContentEditable
) {
3140 // We just changed the contentEditable state of a node, we need to reset
3141 // the spellchecking state of that node.
3142 nsCOMPtr
<nsIDOMNode
> node
= do_QueryInterface(aElement
);
3144 nsPIDOMWindow
*window
= GetWindow();
3146 return NS_ERROR_FAILURE
;
3148 nsIDocShell
*docshell
= window
->GetDocShell();
3150 return NS_ERROR_FAILURE
;
3152 nsCOMPtr
<nsIEditorDocShell
> editorDocShell
=
3153 do_QueryInterface(docshell
, &rv
);
3154 NS_ENSURE_SUCCESS(rv
, rv
);
3156 nsCOMPtr
<nsIEditor
> editor
;
3157 editorDocShell
->GetEditor(getter_AddRefs(editor
));
3159 nsCOMPtr
<nsIDOMRange
> range
;
3160 rv
= NS_NewRange(getter_AddRefs(range
));
3161 NS_ENSURE_SUCCESS(rv
, rv
);
3163 rv
= range
->SelectNode(node
);
3164 NS_ENSURE_SUCCESS(rv
, rv
);
3166 nsCOMPtr
<nsIInlineSpellChecker
> spellChecker
;
3167 rv
= editor
->GetInlineSpellChecker(PR_FALSE
,
3168 getter_AddRefs(spellChecker
));
3169 NS_ENSURE_SUCCESS(rv
, rv
);
3172 rv
= spellChecker
->SpellCheckRange(range
);
3173 NS_ENSURE_SUCCESS(rv
, rv
);
3183 DocAllResultMatch(nsIContent
* aContent
, PRInt32 aNamespaceID
, nsIAtom
* aAtom
,
3186 if (aContent
->GetID() == aAtom
) {
3190 nsGenericHTMLElement
* elm
= nsGenericHTMLElement::FromContent(aContent
);
3191 if (!elm
|| aContent
->GetNameSpaceID() != kNameSpaceID_None
) {
3195 nsIAtom
* tag
= elm
->Tag();
3196 if (tag
!= nsGkAtoms::img
&&
3197 tag
!= nsGkAtoms::form
&&
3198 tag
!= nsGkAtoms::applet
&&
3199 tag
!= nsGkAtoms::embed
&&
3200 tag
!= nsGkAtoms::object
&&
3201 tag
!= nsGkAtoms::input
) {
3205 const nsAttrValue
* val
= elm
->GetParsedAttr(nsGkAtoms::name
);
3206 return val
&& val
->Type() == nsAttrValue::eAtom
&&
3207 val
->GetAtomValue() == aAtom
;
3212 nsHTMLDocument::GetDocumentAllResult(const nsAString
& aID
, nsISupports
** aResult
)
3216 nsCOMPtr
<nsIAtom
> id
= do_GetAtom(aID
);
3217 nsIdentifierMapEntry
*entry
;
3218 if (IdTableIsLive()) {
3219 entry
= mIdentifierMap
.GetEntry(id
);
3220 // If we did a lookup and it failed, there are no items with this id
3224 entry
= mIdentifierMap
.PutEntry(id
);
3225 NS_ENSURE_TRUE(entry
, NS_ERROR_OUT_OF_MEMORY
);
3228 nsIContent
* root
= GetRootContent();
3233 nsRefPtr
<nsContentList
> docAllList
= entry
->GetDocAllList();
3235 docAllList
= new nsContentList(root
, DocAllResultMatch
,
3236 nsnull
, nsnull
, PR_TRUE
, id
);
3237 NS_ENSURE_TRUE(docAllList
, NS_ERROR_OUT_OF_MEMORY
);
3238 entry
->SetDocAllList(docAllList
);
3241 // Check if there are more than 1 entries. Do this by getting the second one
3242 // rather than the length since getting the length always requires walking
3243 // the entire document.
3245 nsIContent
* cont
= docAllList
->Item(1, PR_TRUE
);
3247 NS_ADDREF(*aResult
= static_cast<nsIDOMNodeList
*>(docAllList
));
3251 // There's only 0 or 1 items. Return the first one or null.
3252 NS_IF_ADDREF(*aResult
= docAllList
->Item(0, PR_TRUE
));
3258 NotifyEditableStateChange(nsINode
*aNode
, nsIDocument
*aDocument
,
3261 PRUint32 i
, n
= aNode
->GetChildCount();
3262 for (i
= 0; i
< n
; ++i
) {
3263 nsIContent
*child
= aNode
->GetChildAt(i
);
3264 if (child
->HasFlag(NODE_IS_EDITABLE
) != aEditable
) {
3265 aDocument
->ContentStatesChanged(child
, nsnull
,
3266 NS_EVENT_STATE_MOZ_READONLY
|
3267 NS_EVENT_STATE_MOZ_READWRITE
);
3269 NotifyEditableStateChange(child
, aDocument
, aEditable
);
3274 nsHTMLDocument::TearingDownEditor(nsIEditor
*aEditor
)
3276 if (IsEditingOn()) {
3277 mEditingState
= eTearingDown
;
3279 nsCOMPtr
<nsIEditorStyleSheets
> editorss
= do_QueryInterface(aEditor
);
3281 editorss
->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
3282 if (mEditingState
== eDesignMode
)
3283 editorss
->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/designmode.css"));
3289 nsHTMLDocument::TurnEditingOff()
3291 NS_ASSERTION(mEditingState
!= eOff
, "Editing is already off.");
3293 nsPIDOMWindow
*window
= GetWindow();
3295 return NS_ERROR_FAILURE
;
3297 nsIDocShell
*docshell
= window
->GetDocShell();
3299 return NS_ERROR_FAILURE
;
3302 nsCOMPtr
<nsIEditingSession
> editSession
= do_GetInterface(docshell
, &rv
);
3303 NS_ENSURE_SUCCESS(rv
, rv
);
3306 rv
= editSession
->TearDownEditorOnWindow(window
);
3307 NS_ENSURE_SUCCESS(rv
, rv
);
3309 mEditingState
= eOff
;
3314 static PRBool
HasPresShell(nsPIDOMWindow
*aWindow
)
3316 nsIDocShell
*docShell
= aWindow
->GetDocShell();
3319 nsCOMPtr
<nsIPresShell
> presShell
;
3320 docShell
->GetPresShell(getter_AddRefs(presShell
));
3321 return presShell
!= nsnull
;
3325 nsHTMLDocument::SetEditingState(EditingState aState
)
3327 mEditingState
= aState
;
3332 nsHTMLDocument::EditingStateChanged()
3334 if (mRemovedFromDocShell
) {
3338 if (mEditingState
== eSettingUp
|| mEditingState
== eTearingDown
) {
3339 // XXX We shouldn't recurse.
3343 PRBool designMode
= HasFlag(NODE_IS_EDITABLE
);
3344 EditingState newState
= designMode
? eDesignMode
:
3345 (mContentEditableCount
> 0 ? eContentEditable
: eOff
);
3346 if (mEditingState
== newState
) {
3347 // No changes in editing mode.
3351 if (newState
== eOff
) {
3352 // Editing is being turned off.
3353 return TurnEditingOff();
3356 // get editing session
3357 nsPIDOMWindow
*window
= GetWindow();
3359 return NS_ERROR_FAILURE
;
3361 nsIDocShell
*docshell
= window
->GetDocShell();
3363 return NS_ERROR_FAILURE
;
3366 nsCOMPtr
<nsIEditingSession
> editSession
= do_GetInterface(docshell
, &rv
);
3367 NS_ENSURE_SUCCESS(rv
, rv
);
3369 if (!HasPresShell(window
)) {
3370 // We should not make the window editable or setup its editor.
3371 // It's probably style=display:none.
3375 PRBool makeWindowEditable
= mEditingState
== eOff
;
3376 if (makeWindowEditable
) {
3377 // Editing is being turned on (through designMode or contentEditable)
3379 // XXX This can cause flushing which can change the editing state, so make
3380 // sure to avoid recursing.
3381 EditingState oldState
= mEditingState
;
3382 mEditingState
= eSettingUp
;
3384 rv
= editSession
->MakeWindowEditable(window
, "html", PR_FALSE
, PR_FALSE
,
3386 NS_ENSURE_SUCCESS(rv
, rv
);
3388 mEditingState
= oldState
;
3391 // XXX Need to call TearDownEditorOnWindow for all failures.
3392 nsCOMPtr
<nsIEditorDocShell
> editorDocShell
=
3393 do_QueryInterface(docshell
, &rv
);
3394 NS_ENSURE_SUCCESS(rv
, rv
);
3396 nsCOMPtr
<nsIEditor
> editor
;
3397 editorDocShell
->GetEditor(getter_AddRefs(editor
));
3399 return NS_ERROR_FAILURE
;
3401 nsCOMPtr
<nsIEditorStyleSheets
> editorss
= do_QueryInterface(editor
, &rv
);
3402 NS_ENSURE_SUCCESS(rv
, rv
);
3404 editorss
->AddOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/contenteditable.css"));
3406 // Should we update the editable state of all the nodes in the document? We
3407 // need to do this when the designMode value changes, as that overrides
3408 // specific states on the elements.
3411 PRBool spellRecheckAll
= PR_FALSE
;
3413 // designMode is being turned on (overrides contentEditable).
3414 editorss
->AddOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/designmode.css"));
3416 // Disable scripting and plugins.
3417 rv
= editSession
->DisableJSAndPlugins(window
);
3418 NS_ENSURE_SUCCESS(rv
, rv
);
3420 updateState
= PR_TRUE
;
3421 spellRecheckAll
= mEditingState
== eContentEditable
;
3423 else if (mEditingState
== eDesignMode
) {
3424 // designMode is being turned off (contentEditable is still on).
3425 editorss
->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/designmode.css"));
3427 rv
= editSession
->RestoreJSAndPlugins(window
);
3428 NS_ENSURE_SUCCESS(rv
, rv
);
3430 updateState
= PR_TRUE
;
3433 // contentEditable is being turned on (and designMode is off).
3434 updateState
= PR_FALSE
;
3437 mEditingState
= newState
;
3439 if (makeWindowEditable
) {
3440 // Set the editor to not insert br's on return when in p
3441 // elements by default.
3442 // XXX Do we only want to do this for designMode?
3444 rv
= ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), PR_FALSE
,
3445 NS_LITERAL_STRING("false"), &unused
);
3447 if (NS_FAILED(rv
)) {
3448 // Editor setup failed. Editing is not on after all.
3449 // XXX Should we reset the editable flag on nodes?
3450 editSession
->TearDownEditorOnWindow(window
);
3451 mEditingState
= eOff
;
3458 mozAutoDocUpdate
upd(this, UPDATE_CONTENT_STATE
, PR_TRUE
);
3459 NotifyEditableStateChange(this, this, !designMode
);
3462 // Resync the editor's spellcheck state.
3463 if (spellRecheckAll
) {
3464 nsCOMPtr
<nsISelectionController
> selcon
;
3465 nsresult rv
= editor
->GetSelectionController(getter_AddRefs(selcon
));
3466 NS_ENSURE_SUCCESS(rv
, rv
);
3468 nsCOMPtr
<nsISelection
> spellCheckSelection
;
3469 rv
= selcon
->GetSelection(nsISelectionController::SELECTION_SPELLCHECK
,
3470 getter_AddRefs(spellCheckSelection
));
3471 if (NS_SUCCEEDED(rv
)) {
3472 spellCheckSelection
->RemoveAllRanges();
3475 editor
->SyncRealTimeSpell();
3481 nsHTMLDocument::SetDesignMode(const nsAString
& aDesignMode
)
3483 nsresult rv
= NS_OK
;
3485 if (!nsContentUtils::IsCallerTrustedForWrite()) {
3486 nsCOMPtr
<nsIPrincipal
> subject
;
3487 nsIScriptSecurityManager
*secMan
= nsContentUtils::GetSecurityManager();
3488 rv
= secMan
->GetSubjectPrincipal(getter_AddRefs(subject
));
3489 NS_ENSURE_SUCCESS(rv
, rv
);
3492 rv
= subject
->Subsumes(NodePrincipal(), &subsumes
);
3493 NS_ENSURE_SUCCESS(rv
, rv
);
3495 NS_ENSURE_TRUE(subsumes
, NS_ERROR_DOM_PROP_ACCESS_DENIED
);
3499 PRBool editableMode
= HasFlag(NODE_IS_EDITABLE
);
3500 if (aDesignMode
.LowerCaseEqualsASCII(editableMode
? "off" : "on")) {
3501 SetEditableFlag(!editableMode
);
3503 return EditingStateChanged();
3510 nsHTMLDocument::GetMidasCommandManager(nsICommandManager
** aCmdMgr
)
3512 // initialize return value
3513 NS_ENSURE_ARG_POINTER(aCmdMgr
);
3515 // check if we have it cached
3516 if (mMidasCommandManager
) {
3517 NS_ADDREF(*aCmdMgr
= mMidasCommandManager
);
3523 nsPIDOMWindow
*window
= GetWindow();
3525 return NS_ERROR_FAILURE
;
3527 nsIDocShell
*docshell
= window
->GetDocShell();
3529 return NS_ERROR_FAILURE
;
3531 mMidasCommandManager
= do_GetInterface(docshell
);
3532 if (!mMidasCommandManager
)
3533 return NS_ERROR_FAILURE
;
3535 NS_ADDREF(*aCmdMgr
= mMidasCommandManager
);
3541 struct MidasCommand
{
3542 const char* incomingCommandString
;
3543 const char* internalCommandString
;
3544 const char* internalParamString
;
3545 PRPackedBool useNewParam
;
3546 PRPackedBool convertToBoolean
;
3549 static const struct MidasCommand gMidasCommandTable
[] = {
3550 { "bold", "cmd_bold", "", PR_TRUE
, PR_FALSE
},
3551 { "italic", "cmd_italic", "", PR_TRUE
, PR_FALSE
},
3552 { "underline", "cmd_underline", "", PR_TRUE
, PR_FALSE
},
3553 { "strikethrough", "cmd_strikethrough", "", PR_TRUE
, PR_FALSE
},
3554 { "subscript", "cmd_subscript", "", PR_TRUE
, PR_FALSE
},
3555 { "superscript", "cmd_superscript", "", PR_TRUE
, PR_FALSE
},
3556 { "cut", "cmd_cut", "", PR_TRUE
, PR_FALSE
},
3557 { "copy", "cmd_copy", "", PR_TRUE
, PR_FALSE
},
3558 { "paste", "cmd_paste", "", PR_TRUE
, PR_FALSE
},
3559 { "delete", "cmd_delete", "", PR_TRUE
, PR_FALSE
},
3560 { "selectall", "cmd_selectAll", "", PR_TRUE
, PR_FALSE
},
3561 { "undo", "cmd_undo", "", PR_TRUE
, PR_FALSE
},
3562 { "redo", "cmd_redo", "", PR_TRUE
, PR_FALSE
},
3563 { "indent", "cmd_indent", "", PR_TRUE
, PR_FALSE
},
3564 { "outdent", "cmd_outdent", "", PR_TRUE
, PR_FALSE
},
3565 { "backcolor", "cmd_backgroundColor", "", PR_FALSE
, PR_FALSE
},
3566 { "forecolor", "cmd_fontColor", "", PR_FALSE
, PR_FALSE
},
3567 { "hilitecolor", "cmd_highlight", "", PR_FALSE
, PR_FALSE
},
3568 { "fontname", "cmd_fontFace", "", PR_FALSE
, PR_FALSE
},
3569 { "fontsize", "cmd_fontSize", "", PR_FALSE
, PR_FALSE
},
3570 { "increasefontsize", "cmd_increaseFont", "", PR_FALSE
, PR_FALSE
},
3571 { "decreasefontsize", "cmd_decreaseFont", "", PR_FALSE
, PR_FALSE
},
3572 { "inserthorizontalrule", "cmd_insertHR", "", PR_TRUE
, PR_FALSE
},
3573 { "createlink", "cmd_insertLinkNoUI", "", PR_FALSE
, PR_FALSE
},
3574 { "insertimage", "cmd_insertImageNoUI", "", PR_FALSE
, PR_FALSE
},
3575 { "inserthtml", "cmd_insertHTML", "", PR_FALSE
, PR_FALSE
},
3576 { "gethtml", "cmd_getContents", "", PR_FALSE
, PR_FALSE
},
3577 { "justifyleft", "cmd_align", "left", PR_TRUE
, PR_FALSE
},
3578 { "justifyright", "cmd_align", "right", PR_TRUE
, PR_FALSE
},
3579 { "justifycenter", "cmd_align", "center", PR_TRUE
, PR_FALSE
},
3580 { "justifyfull", "cmd_align", "justify", PR_TRUE
, PR_FALSE
},
3581 { "removeformat", "cmd_removeStyles", "", PR_TRUE
, PR_FALSE
},
3582 { "unlink", "cmd_removeLinks", "", PR_TRUE
, PR_FALSE
},
3583 { "insertorderedlist", "cmd_ol", "", PR_TRUE
, PR_FALSE
},
3584 { "insertunorderedlist", "cmd_ul", "", PR_TRUE
, PR_FALSE
},
3585 { "insertparagraph", "cmd_paragraphState", "p", PR_TRUE
, PR_FALSE
},
3586 { "formatblock", "cmd_paragraphState", "", PR_FALSE
, PR_FALSE
},
3587 { "heading", "cmd_paragraphState", "", PR_FALSE
, PR_FALSE
},
3588 { "styleWithCSS", "cmd_setDocumentUseCSS", "", PR_FALSE
, PR_TRUE
},
3589 { "contentReadOnly", "cmd_setDocumentReadOnly", "", PR_FALSE
, PR_TRUE
},
3590 { "insertBrOnReturn", "cmd_insertBrOnReturn", "", PR_FALSE
, PR_TRUE
},
3591 { "enableObjectResizing", "cmd_enableObjectResizing", "", PR_FALSE
, PR_TRUE
},
3592 { "enableInlineTableEditing", "cmd_enableInlineTableEditing", "", PR_FALSE
, PR_TRUE
},
3594 // no editor support to remove alignments right now
3595 { "justifynone", "cmd_align", "", PR_TRUE
, PR_FALSE
},
3597 // the following will need special review before being turned on
3598 { "saveas", "cmd_saveAs", "", PR_TRUE
, PR_FALSE
},
3599 { "print", "cmd_print", "", PR_TRUE
, PR_FALSE
},
3601 { NULL
, NULL
, NULL
, PR_FALSE
, PR_FALSE
}
3604 #define MidasCommandCount ((sizeof(gMidasCommandTable) / sizeof(struct MidasCommand)) - 1)
3606 static const char* const gBlocks
[] = {
3624 ConvertToMidasInternalCommandInner(const nsAString
& inCommandID
,
3625 const nsAString
& inParam
,
3626 nsACString
& outCommandID
,
3627 nsACString
& outParam
,
3628 PRBool
& outIsBoolean
,
3629 PRBool
& outBooleanValue
,
3630 PRBool aIgnoreParams
)
3632 NS_ConvertUTF16toUTF8
convertedCommandID(inCommandID
);
3634 // Hack to support old boolean commands that were backwards (see bug 301490).
3635 PRBool invertBool
= PR_FALSE
;
3636 if (convertedCommandID
.LowerCaseEqualsLiteral("usecss")) {
3637 convertedCommandID
.Assign("styleWithCSS");
3638 invertBool
= PR_TRUE
;
3640 else if (convertedCommandID
.LowerCaseEqualsLiteral("readonly")) {
3641 convertedCommandID
.Assign("contentReadOnly");
3642 invertBool
= PR_TRUE
;
3646 PRBool found
= PR_FALSE
;
3647 for (i
= 0; i
< MidasCommandCount
; ++i
) {
3648 if (convertedCommandID
.Equals(gMidasCommandTable
[i
].incomingCommandString
,
3649 nsCaseInsensitiveCStringComparator())) {
3656 // set outCommandID (what we use internally)
3657 outCommandID
.Assign(gMidasCommandTable
[i
].internalCommandString
);
3659 // set outParam & outIsBoolean based on flags from the table
3660 outIsBoolean
= gMidasCommandTable
[i
].convertToBoolean
;
3662 if (!aIgnoreParams
) {
3663 if (gMidasCommandTable
[i
].useNewParam
) {
3664 outParam
.Assign(gMidasCommandTable
[i
].internalParamString
);
3667 // handle checking of param passed in
3669 // if this is a boolean value and it's not explicitly false
3670 // (e.g. no value) we default to "true". For old backwards commands
3671 // we invert the check (see bug 301490).
3673 outBooleanValue
= inParam
.LowerCaseEqualsLiteral("false");
3676 outBooleanValue
= !inParam
.LowerCaseEqualsLiteral("false");
3678 outParam
.Truncate();
3681 // check to see if we need to convert the parameter
3682 if (outCommandID
.EqualsLiteral("cmd_paragraphState")) {
3683 const PRUnichar
*start
= inParam
.BeginReading();
3684 const PRUnichar
*end
= inParam
.EndReading();
3685 if (start
!= end
&& *start
== '<' && *(end
- 1) == '>') {
3690 NS_ConvertUTF16toUTF8
convertedParam(Substring(start
, end
));
3692 for (j
= 0; j
< NS_ARRAY_LENGTH(gBlocks
); ++j
) {
3693 if (convertedParam
.Equals(gBlocks
[j
],
3694 nsCaseInsensitiveCStringComparator())) {
3695 outParam
.Assign(gBlocks
[j
]);
3700 return j
!= NS_ARRAY_LENGTH(gBlocks
);
3703 CopyUTF16toUTF8(inParam
, outParam
);
3708 } // end else for useNewParam (do convert existing param)
3710 // reset results if the command is not found in our table
3711 outCommandID
.SetLength(0);
3712 outParam
.SetLength(0);
3713 outIsBoolean
= PR_FALSE
;
3720 ConvertToMidasInternalCommand(const nsAString
& inCommandID
,
3721 const nsAString
& inParam
,
3722 nsACString
& outCommandID
,
3723 nsACString
& outParam
,
3724 PRBool
& outIsBoolean
,
3725 PRBool
& outBooleanValue
)
3727 return ConvertToMidasInternalCommandInner(inCommandID
, inParam
, outCommandID
,
3728 outParam
, outIsBoolean
,
3729 outBooleanValue
, PR_FALSE
);
3733 ConvertToMidasInternalCommand(const nsAString
& inCommandID
,
3734 nsACString
& outCommandID
)
3736 nsCAutoString dummyCString
;
3737 nsAutoString dummyString
;
3739 return ConvertToMidasInternalCommandInner(inCommandID
, dummyString
,
3740 outCommandID
, dummyCString
,
3741 dummyBool
, dummyBool
, PR_TRUE
);
3745 nsHTMLDocument::sCutCopyInternal_id
= JSVAL_VOID
;
3747 nsHTMLDocument::sPasteInternal_id
= JSVAL_VOID
;
3749 /* Helper function to check security of clipboard commands. If aPaste is */
3750 /* true, we check paste, else we check cutcopy */
3752 nsHTMLDocument::DoClipboardSecurityCheck(PRBool aPaste
)
3754 nsresult rv
= NS_ERROR_FAILURE
;
3756 nsCOMPtr
<nsIJSContextStack
> stack
=
3757 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
3760 JSContext
*cx
= nsnull
;
3766 JSAutoRequest
ar(cx
);
3768 NS_NAMED_LITERAL_CSTRING(classNameStr
, "Clipboard");
3770 nsIScriptSecurityManager
*secMan
= nsContentUtils::GetSecurityManager();
3773 if (nsHTMLDocument::sPasteInternal_id
== JSVAL_VOID
) {
3774 nsHTMLDocument::sPasteInternal_id
=
3775 STRING_TO_JSVAL(::JS_InternString(cx
, "paste"));
3777 rv
= secMan
->CheckPropertyAccess(cx
, nsnull
, classNameStr
.get(),
3778 nsHTMLDocument::sPasteInternal_id
,
3779 nsIXPCSecurityManager::ACCESS_GET_PROPERTY
);
3781 if (nsHTMLDocument::sCutCopyInternal_id
== JSVAL_VOID
) {
3782 nsHTMLDocument::sCutCopyInternal_id
=
3783 STRING_TO_JSVAL(::JS_InternString(cx
, "cutcopy"));
3785 rv
= secMan
->CheckPropertyAccess(cx
, nsnull
, classNameStr
.get(),
3786 nsHTMLDocument::sCutCopyInternal_id
,
3787 nsIXPCSecurityManager::ACCESS_GET_PROPERTY
);
3793 /* TODO: don't let this call do anything if the page is not done loading */
3794 /* boolean execCommand(in DOMString commandID, in boolean doShowUI,
3795 in DOMString value); */
3797 nsHTMLDocument::ExecCommand(const nsAString
& commandID
,
3799 const nsAString
& value
,
3802 NS_ENSURE_ARG_POINTER(_retval
);
3804 // for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go()
3805 // this might add some ugly JS dependencies?
3807 *_retval
= PR_FALSE
;
3809 // if editing is not on, bail
3811 return NS_ERROR_FAILURE
;
3813 // if they are requesting UI from us, let's fail since we have no UI
3817 nsresult rv
= NS_OK
;
3819 if (commandID
.LowerCaseEqualsLiteral("gethtml"))
3820 return NS_ERROR_FAILURE
;
3822 if (commandID
.LowerCaseEqualsLiteral("cut") ||
3823 (commandID
.LowerCaseEqualsLiteral("copy"))) {
3824 rv
= DoClipboardSecurityCheck(PR_FALSE
);
3825 } else if (commandID
.LowerCaseEqualsLiteral("paste")) {
3826 rv
= DoClipboardSecurityCheck(PR_TRUE
);
3832 // get command manager and dispatch command to our window if it's acceptable
3833 nsCOMPtr
<nsICommandManager
> cmdMgr
;
3834 GetMidasCommandManager(getter_AddRefs(cmdMgr
));
3836 return NS_ERROR_FAILURE
;
3838 nsIDOMWindow
*window
= GetWindow();
3840 return NS_ERROR_FAILURE
;
3842 nsCAutoString cmdToDispatch
, paramStr
;
3843 PRBool isBool
, boolVal
;
3844 if (!ConvertToMidasInternalCommand(commandID
, value
,
3845 cmdToDispatch
, paramStr
, isBool
, boolVal
))
3848 if (!isBool
&& paramStr
.IsEmpty()) {
3849 rv
= cmdMgr
->DoCommand(cmdToDispatch
.get(), nsnull
, window
);
3851 // we have a command that requires a parameter, create params
3852 nsCOMPtr
<nsICommandParams
> cmdParams
= do_CreateInstance(
3853 NS_COMMAND_PARAMS_CONTRACTID
, &rv
);
3855 return NS_ERROR_OUT_OF_MEMORY
;
3858 rv
= cmdParams
->SetBooleanValue("state_attribute", boolVal
);
3859 else if (cmdToDispatch
.Equals("cmd_fontFace"))
3860 rv
= cmdParams
->SetStringValue("state_attribute", value
);
3861 else if (cmdToDispatch
.Equals("cmd_insertHTML"))
3862 rv
= cmdParams
->SetStringValue("state_data", value
);
3864 rv
= cmdParams
->SetCStringValue("state_attribute", paramStr
.get());
3867 rv
= cmdMgr
->DoCommand(cmdToDispatch
.get(), cmdParams
, window
);
3870 *_retval
= NS_SUCCEEDED(rv
);
3875 /* TODO: don't let this call do anything if the page is not done loading */
3876 /* boolean execCommandShowHelp(in DOMString commandID); */
3878 nsHTMLDocument::ExecCommandShowHelp(const nsAString
& commandID
,
3881 NS_ENSURE_ARG_POINTER(_retval
);
3882 *_retval
= PR_FALSE
;
3884 // if editing is not on, bail
3886 return NS_ERROR_FAILURE
;
3888 return NS_ERROR_NOT_IMPLEMENTED
;
3891 /* boolean queryCommandEnabled(in DOMString commandID); */
3893 nsHTMLDocument::QueryCommandEnabled(const nsAString
& commandID
,
3896 NS_ENSURE_ARG_POINTER(_retval
);
3897 *_retval
= PR_FALSE
;
3899 // if editing is not on, bail
3901 return NS_ERROR_FAILURE
;
3903 // get command manager and dispatch command to our window if it's acceptable
3904 nsCOMPtr
<nsICommandManager
> cmdMgr
;
3905 GetMidasCommandManager(getter_AddRefs(cmdMgr
));
3907 return NS_ERROR_FAILURE
;
3909 nsIDOMWindow
*window
= GetWindow();
3911 return NS_ERROR_FAILURE
;
3913 nsCAutoString cmdToDispatch
, paramStr
;
3914 if (!ConvertToMidasInternalCommand(commandID
, cmdToDispatch
))
3915 return NS_ERROR_NOT_IMPLEMENTED
;
3917 return cmdMgr
->IsCommandEnabled(cmdToDispatch
.get(), window
, _retval
);
3920 /* boolean queryCommandIndeterm (in DOMString commandID); */
3922 nsHTMLDocument::QueryCommandIndeterm(const nsAString
& commandID
,
3925 NS_ENSURE_ARG_POINTER(_retval
);
3926 *_retval
= PR_FALSE
;
3928 // if editing is not on, bail
3930 return NS_ERROR_FAILURE
;
3932 // get command manager and dispatch command to our window if it's acceptable
3933 nsCOMPtr
<nsICommandManager
> cmdMgr
;
3934 GetMidasCommandManager(getter_AddRefs(cmdMgr
));
3936 return NS_ERROR_FAILURE
;
3938 nsIDOMWindow
*window
= GetWindow();
3940 return NS_ERROR_FAILURE
;
3942 nsCAutoString cmdToDispatch
, paramToCheck
;
3944 if (!ConvertToMidasInternalCommand(commandID
, commandID
,
3945 cmdToDispatch
, paramToCheck
, dummy
, dummy
))
3946 return NS_ERROR_NOT_IMPLEMENTED
;
3949 nsCOMPtr
<nsICommandParams
> cmdParams
= do_CreateInstance(
3950 NS_COMMAND_PARAMS_CONTRACTID
, &rv
);
3951 NS_ENSURE_SUCCESS(rv
, rv
);
3953 rv
= cmdMgr
->GetCommandState(cmdToDispatch
.get(), window
, cmdParams
);
3957 // if command does not have a state_mixed value, this call fails, so we fail too,
3958 // which is what is expected
3959 rv
= cmdParams
->GetBooleanValue("state_mixed", _retval
);
3963 /* boolean queryCommandState(in DOMString commandID); */
3965 nsHTMLDocument::QueryCommandState(const nsAString
& commandID
, PRBool
*_retval
)
3967 NS_ENSURE_ARG_POINTER(_retval
);
3968 *_retval
= PR_FALSE
;
3970 // if editing is not on, bail
3972 return NS_ERROR_FAILURE
;
3974 // get command manager and dispatch command to our window if it's acceptable
3975 nsCOMPtr
<nsICommandManager
> cmdMgr
;
3976 GetMidasCommandManager(getter_AddRefs(cmdMgr
));
3978 return NS_ERROR_FAILURE
;
3980 nsIDOMWindow
*window
= GetWindow();
3982 return NS_ERROR_FAILURE
;
3984 nsCAutoString cmdToDispatch
, paramToCheck
;
3985 PRBool dummy
, dummy2
;
3986 if (!ConvertToMidasInternalCommand(commandID
, commandID
,
3987 cmdToDispatch
, paramToCheck
, dummy
, dummy2
))
3988 return NS_ERROR_NOT_IMPLEMENTED
;
3991 nsCOMPtr
<nsICommandParams
> cmdParams
= do_CreateInstance(
3992 NS_COMMAND_PARAMS_CONTRACTID
, &rv
);
3994 return NS_ERROR_OUT_OF_MEMORY
;
3996 rv
= cmdMgr
->GetCommandState(cmdToDispatch
.get(), window
, cmdParams
);
4000 // handle alignment as a special case (possibly other commands too?)
4001 // Alignment is special because the external api is individual
4002 // commands but internally we use cmd_align with different
4003 // parameters. When getting the state of this command, we need to
4004 // return the boolean for this particular alignment rather than the
4005 // string of 'which alignment is this?'
4006 if (cmdToDispatch
.Equals("cmd_align")) {
4007 char * actualAlignmentType
= nsnull
;
4008 rv
= cmdParams
->GetCStringValue("state_attribute", &actualAlignmentType
);
4009 if (NS_SUCCEEDED(rv
) && actualAlignmentType
&& actualAlignmentType
[0]) {
4010 *_retval
= paramToCheck
.Equals(actualAlignmentType
);
4012 if (actualAlignmentType
)
4013 nsMemory::Free(actualAlignmentType
);
4016 rv
= cmdParams
->GetBooleanValue("state_all", _retval
);
4018 *_retval
= PR_FALSE
;
4024 /* boolean queryCommandSupported(in DOMString commandID); */
4026 nsHTMLDocument::QueryCommandSupported(const nsAString
& commandID
,
4029 NS_ENSURE_ARG_POINTER(_retval
);
4030 *_retval
= PR_FALSE
;
4032 // if editing is not on, bail
4034 return NS_ERROR_FAILURE
;
4036 return NS_ERROR_NOT_IMPLEMENTED
;
4039 /* DOMString queryCommandText(in DOMString commandID); */
4041 nsHTMLDocument::QueryCommandText(const nsAString
& commandID
,
4042 nsAString
& _retval
)
4044 _retval
.SetLength(0);
4046 // if editing is not on, bail
4048 return NS_ERROR_FAILURE
;
4050 return NS_ERROR_NOT_IMPLEMENTED
;
4053 /* DOMString queryCommandValue(in DOMString commandID); */
4055 nsHTMLDocument::QueryCommandValue(const nsAString
& commandID
,
4058 _retval
.SetLength(0);
4060 // if editing is not on, bail
4062 return NS_ERROR_FAILURE
;
4064 // get command manager and dispatch command to our window if it's acceptable
4065 nsCOMPtr
<nsICommandManager
> cmdMgr
;
4066 GetMidasCommandManager(getter_AddRefs(cmdMgr
));
4068 return NS_ERROR_FAILURE
;
4070 nsIDOMWindow
*window
= GetWindow();
4072 return NS_ERROR_FAILURE
;
4074 nsCAutoString cmdToDispatch
, paramStr
;
4075 if (!ConvertToMidasInternalCommand(commandID
, cmdToDispatch
))
4076 return NS_ERROR_NOT_IMPLEMENTED
;
4080 nsCOMPtr
<nsICommandParams
> cmdParams
= do_CreateInstance(
4081 NS_COMMAND_PARAMS_CONTRACTID
, &rv
);
4083 return NS_ERROR_OUT_OF_MEMORY
;
4085 // this is a special command since we are calling "DoCommand rather than
4086 // GetCommandState like the other commands
4087 if (cmdToDispatch
.Equals("cmd_getContents"))
4089 rv
= cmdParams
->SetBooleanValue("selection_only", PR_TRUE
);
4090 if (NS_FAILED(rv
)) return rv
;
4091 rv
= cmdParams
->SetCStringValue("format", "text/html");
4092 if (NS_FAILED(rv
)) return rv
;
4093 rv
= cmdMgr
->DoCommand(cmdToDispatch
.get(), cmdParams
, window
);
4094 if (NS_FAILED(rv
)) return rv
;
4095 return cmdParams
->GetStringValue("result", _retval
);
4098 rv
= cmdParams
->SetCStringValue("state_attribute", paramStr
.get());
4102 rv
= cmdMgr
->GetCommandState(cmdToDispatch
.get(), window
, cmdParams
);
4106 nsXPIDLCString cStringResult
;
4107 rv
= cmdParams
->GetCStringValue("state_attribute",
4108 getter_Copies(cStringResult
));
4109 CopyUTF8toUTF16(cStringResult
, _retval
);
4116 nsHTMLDocument::CreateElem(nsIAtom
*aName
, nsIAtom
*aPrefix
,
4117 PRInt32 aNamespaceID
, PRBool aDocumentDefaultType
,
4118 nsIContent
** aResult
)
4120 NS_ASSERTION(!aDocumentDefaultType
|| IsXHTML() ||
4121 aNamespaceID
== kNameSpaceID_None
,
4122 "HTML elements in an HTML document should have "
4123 "kNamespaceID_None as their namespace ID.");
4126 (aDocumentDefaultType
|| aNamespaceID
== kNameSpaceID_XHTML
)) {
4127 nsCAutoString name
, lcName
;
4128 aName
->ToUTF8String(name
);
4129 ToLowerCase(name
, lcName
);
4130 NS_ASSERTION(lcName
.Equals(name
),
4131 "aName should be lowercase, fix caller.");
4134 return nsDocument::CreateElem(aName
, aPrefix
, aNamespaceID
,
4135 aDocumentDefaultType
, aResult
);