Back to index

lightning-sunbird  0.9+nobinonly
nsGenericHTMLElement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Mats Palmgren <mats.palmgren@bredband.net>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nscore.h"
00040 #include "nsGenericHTMLElement.h"
00041 #include "nsCOMPtr.h"
00042 #include "nsIAtom.h"
00043 #include "nsINodeInfo.h"
00044 #include "nsIContentViewer.h"
00045 #include "nsICSSParser.h"
00046 #include "nsICSSLoader.h"
00047 #include "nsICSSStyleRule.h"
00048 #include "nsCSSStruct.h"
00049 #include "nsCSSDeclaration.h"
00050 #include "nsIDocument.h"
00051 #include "nsIDocumentEncoder.h"
00052 #include "nsIDOMHTMLBodyElement.h"
00053 #include "nsIDOMHTMLDocument.h"
00054 #include "nsIDOMAttr.h"
00055 #include "nsIDOMEventReceiver.h"
00056 #include "nsIDOMNamedNodeMap.h"
00057 #include "nsIDOMNodeList.h"
00058 #include "nsIDOMDocumentFragment.h"
00059 #include "nsIDOMNSHTMLDocument.h"
00060 #include "nsIDOMNSHTMLElement.h"
00061 #include "nsIDOMElementCSSInlineStyle.h"
00062 #include "nsIDOMWindow.h"
00063 #include "nsIDOMDocument.h"
00064 #include "nsIEventListenerManager.h"
00065 #include "nsIFocusController.h"
00066 #include "nsMappedAttributes.h"
00067 #include "nsHTMLStyleSheet.h"
00068 #include "nsIHTMLDocument.h"
00069 #include "nsILink.h"
00070 #include "nsILinkHandler.h"
00071 #include "nsPIDOMWindow.h"
00072 #include "nsIStyleRule.h"
00073 #include "nsISupportsArray.h"
00074 #include "nsIURL.h"
00075 #include "nsNetUtil.h"
00076 #include "nsEscape.h"
00077 #include "nsStyleConsts.h"
00078 #include "nsIFrame.h"
00079 #include "nsIScrollableFrame.h"
00080 #include "nsIScrollableView.h"
00081 #include "nsIScrollableViewProvider.h"
00082 #include "nsRange.h"
00083 #include "nsIPresShell.h"
00084 #include "nsPresContext.h"
00085 #include "nsIDocShell.h"
00086 #include "nsIView.h"
00087 #include "nsIViewManager.h"
00088 #include "nsINameSpaceManager.h"
00089 #include "nsDOMError.h"
00090 #include "nsIScriptGlobalObject.h"
00091 #include "nsIScriptLoader.h"
00092 #include "nsRuleData.h"
00093 
00094 #include "nsPresState.h"
00095 #include "nsILayoutHistoryState.h"
00096 
00097 #include "nsHTMLParts.h"
00098 #include "nsContentUtils.h"
00099 #include "nsString.h"
00100 #include "nsReadableUtils.h"
00101 #include "nsUnicharUtils.h"
00102 #include "nsLayoutAtoms.h"
00103 #include "nsHTMLAtoms.h"
00104 #include "nsIEventStateManager.h"
00105 #include "nsIDOMEvent.h"
00106 #include "nsIDOMNSEvent.h"
00107 #include "nsIPrivateDOMEvent.h"
00108 #include "nsDOMCID.h"
00109 #include "nsIServiceManager.h"
00110 #include "nsDOMCSSDeclaration.h"
00111 #include "nsICSSOMFactory.h"
00112 #include "prprf.h"
00113 #include "prmem.h"
00114 #include "nsITextControlFrame.h"
00115 #include "nsIForm.h"
00116 #include "nsIFormControl.h"
00117 #include "nsIDOMHTMLFormElement.h"
00118 #include "nsILanguageAtomService.h"
00119 
00120 #include "nsIDOMMutationEvent.h"
00121 #include "nsMutationEvent.h"
00122 
00123 #include "nsIBindingManager.h"
00124 #include "nsXBLBinding.h"
00125 
00126 #include "nsRuleWalker.h"
00127 
00128 #include "nsIObjectFrame.h"
00129 #include "nsLayoutAtoms.h"
00130 #include "xptinfo.h"
00131 #include "nsIInterfaceInfoManager.h"
00132 #include "nsIServiceManager.h"
00133 
00134 #include "nsIParser.h"
00135 #include "nsParserCIID.h"
00136 #include "nsIHTMLContentSink.h"
00137 #include "nsLayoutCID.h"
00138 #include "nsContentCID.h"
00139 
00140 #include "nsIDOMText.h"
00141 #include "nsITextContent.h"
00142 #include "nsCOMArray.h"
00143 #include "nsNodeInfoManager.h"
00144 
00145 #include "nsIEditor.h"
00146 
00147 // XXX todo: add in missing out-of-memory checks
00148 
00149 //----------------------------------------------------------------------
00150 
00151 #ifdef GATHER_ELEMENT_USEAGE_STATISTICS
00152 
00153 // static objects that have constructors are kinda bad, but we don't
00154 // care here, this is only debugging code!
00155 
00156 static nsHashtable sGEUS_ElementCounts;
00157 
00158 void GEUS_ElementCreated(nsINodeInfo *aNodeInfo)
00159 {
00160   nsAutoString name;
00161   aNodeInfo->GetLocalName(name);
00162 
00163   nsStringKey key(name);
00164 
00165   PRInt32 count = (PRInt32)sGEUS_ElementCounts.Get(&key);
00166 
00167   count++;
00168 
00169   sGEUS_ElementCounts.Put(&key, (void *)count);
00170 }
00171 
00172 PRBool GEUS_enum_func(nsHashKey *aKey, void *aData, void *aClosure)
00173 {
00174   const PRUnichar *name_chars = ((nsStringKey *)aKey)->GetString();
00175   NS_ConvertUCS2toUTF8 name(name_chars);
00176 
00177   printf ("%s %d\n", name.get(), aData);
00178 
00179   return PR_TRUE;
00180 }
00181 
00182 void GEUS_DumpElementCounts()
00183 {
00184   printf ("Element count statistics:\n");
00185 
00186   sGEUS_ElementCounts.Enumerate(GEUS_enum_func, nsnull);
00187 
00188   printf ("End of element count statistics:\n");
00189 }
00190 
00191 nsresult
00192 nsGenericHTMLElement::Init(nsINodeInfo *aNodeInfo)
00193 {
00194   GEUS_ElementCreated(aNodeInfo);
00195 
00196   return nsGenericElement::Init(aNodeInfo);
00197 }
00198 
00199 #endif
00200 
00201 
00202 class nsGenericHTMLElementTearoff : public nsIDOMNSHTMLElement_MOZILLA_1_8_BRANCH,
00203                                     public nsIDOMElementCSSInlineStyle
00204 {
00205   NS_DECL_ISUPPORTS
00206 
00207   nsGenericHTMLElementTearoff(nsGenericHTMLElement *aElement)
00208     : mElement(aElement)
00209   {
00210     NS_ADDREF(mElement);
00211   }
00212 
00213   virtual ~nsGenericHTMLElementTearoff()
00214   {
00215     NS_RELEASE(mElement);
00216   }
00217 
00218   NS_FORWARD_NSIDOMNSHTMLELEMENT(mElement->)
00219   NS_FORWARD_NSIDOMNSHTMLELEMENT_MOZILLA_1_8_BRANCH(mElement->)
00220   NS_FORWARD_NSIDOMELEMENTCSSINLINESTYLE(mElement->)
00221 
00222 private:
00223   nsGenericHTMLElement *mElement;
00224 };
00225 
00226 
00227 NS_IMPL_ADDREF(nsGenericHTMLElementTearoff)
00228 NS_IMPL_RELEASE(nsGenericHTMLElementTearoff)
00229 
00230 NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElementTearoff)
00231   NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLElement)
00232   NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLElement_MOZILLA_1_8_BRANCH)
00233   NS_INTERFACE_MAP_ENTRY(nsIDOMElementCSSInlineStyle)
00234 NS_INTERFACE_MAP_END_AGGREGATED(mElement)
00235 
00236 
00237 static nsICSSOMFactory* gCSSOMFactory = nsnull;
00238 static NS_DEFINE_CID(kCSSOMFactoryCID, NS_CSSOMFACTORY_CID);
00239 
00240 NS_IMPL_INT_ATTR(nsGenericHTMLElement, TabIndex, tabindex)
00241 
00242 nsresult
00243 nsGenericHTMLElement::DOMQueryInterface(nsIDOMHTMLElement *aElement,
00244                                         REFNSIID aIID, void **aInstancePtr)
00245 {
00246   nsISupports *inst = nsnull;
00247 
00248   if (aIID.Equals(NS_GET_IID(nsIDOMNode))) {
00249     inst = NS_STATIC_CAST(nsIDOMNode *, aElement);
00250   } else if (aIID.Equals(NS_GET_IID(nsIDOMElement))) {
00251     inst = NS_STATIC_CAST(nsIDOMElement *, aElement);
00252   } else if (aIID.Equals(NS_GET_IID(nsIDOMHTMLElement))) {
00253     inst = NS_STATIC_CAST(nsIDOMHTMLElement *, aElement);
00254   } else if (aIID.Equals(NS_GET_IID(nsIDOMNSHTMLElement))) {
00255     inst = NS_STATIC_CAST(nsIDOMNSHTMLElement *,
00256                           new nsGenericHTMLElementTearoff(this));
00257     NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
00258   } else if (aIID.Equals(NS_GET_IID(nsIDOMNSHTMLElement_MOZILLA_1_8_BRANCH))) {
00259     inst = NS_STATIC_CAST(nsIDOMNSHTMLElement_MOZILLA_1_8_BRANCH *,
00260                           new nsGenericHTMLElementTearoff(this));
00261     NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
00262   } else if (aIID.Equals(NS_GET_IID(nsIDOMElementCSSInlineStyle))) {
00263     inst = NS_STATIC_CAST(nsIDOMElementCSSInlineStyle *,
00264                           new nsGenericHTMLElementTearoff(this));
00265     NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
00266   } else {
00267     return NS_NOINTERFACE;
00268   }
00269 
00270   NS_ADDREF(inst);
00271 
00272   *aInstancePtr = inst;
00273 
00274   return NS_OK;
00275 }
00276 
00277 /* static */ void
00278 nsGenericHTMLElement::Shutdown()
00279 {
00280   NS_IF_RELEASE(gCSSOMFactory);
00281 }
00282 
00283 nsresult
00284 nsGenericHTMLElement::CopyInnerTo(nsGenericElement* aDst, PRBool aDeep)
00285 {
00286   nsresult rv = NS_OK;
00287   PRInt32 i, count = GetAttrCount();
00288   nsCOMPtr<nsIAtom> name, prefix;
00289   PRInt32 namespace_id;
00290   nsAutoString value;
00291 
00292   for (i = 0; i < count; ++i) {
00293     rv = GetAttrNameAt(i, &namespace_id, getter_AddRefs(name),
00294                        getter_AddRefs(prefix));
00295     NS_ENSURE_SUCCESS(rv, rv);
00296 
00297     if (name == nsHTMLAtoms::style && namespace_id == kNameSpaceID_None) {
00298       // We can't just set this as a string, because that will fail
00299       // to reparse the string into style data until the node is
00300       // inserted into the document.  Clone the HTMLValue instead.
00301       const nsAttrValue* styleVal =
00302         mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
00303       if (styleVal && styleVal->Type() == nsAttrValue::eCSSStyleRule) {
00304         nsCOMPtr<nsICSSRule> ruleClone;
00305         rv = styleVal->GetCSSStyleRuleValue()->
00306           Clone(*getter_AddRefs(ruleClone));
00307         NS_ENSURE_SUCCESS(rv, rv);
00308 
00309         nsCOMPtr<nsICSSStyleRule> styleRule = do_QueryInterface(ruleClone);
00310         NS_ENSURE_TRUE(styleRule, NS_ERROR_UNEXPECTED);
00311 
00312         rv = aDst->SetInlineStyleRule(styleRule, PR_FALSE);
00313         NS_ENSURE_SUCCESS(rv, rv);
00314 
00315         continue;
00316       }
00317     }
00318 
00319     rv = GetAttr(namespace_id, name, value);
00320     NS_ENSURE_SUCCESS(rv, rv);
00321 
00322     rv = aDst->SetAttr(namespace_id, name, prefix, value, PR_FALSE);
00323     NS_ENSURE_SUCCESS(rv, rv);
00324   }
00325 
00326   nsIDocument *doc = nsContentUtils::GetDocument(mNodeInfo);
00327 
00328   PRInt32 id;
00329   if (doc) {
00330     id = doc->GetAndIncrementContentID();
00331   } else {
00332     id = PR_INT32_MAX;
00333   }
00334 
00335   aDst->SetContentID(id);
00336 
00337   if (aDeep) {
00338     PRInt32 i;
00339     PRInt32 count = mAttrsAndChildren.ChildCount();
00340     for (i = 0; i < count; ++i) {
00341       nsCOMPtr<nsIDOMNode> node = 
00342           do_QueryInterface(mAttrsAndChildren.ChildAt(i));
00343       NS_ASSERTION(node, "child doesn't implement nsIDOMNode");
00344 
00345       nsCOMPtr<nsIDOMNode> newNode;
00346       rv = node->CloneNode(aDeep, getter_AddRefs(newNode));
00347       NS_ENSURE_SUCCESS(rv, rv);
00348 
00349       nsCOMPtr<nsIContent> newContent(do_QueryInterface(newNode));
00350       NS_ASSERTION(newContent, "clone doesn't implement nsIContent");
00351       rv = aDst->AppendChildTo(newContent, PR_FALSE);
00352       NS_ENSURE_SUCCESS(rv, rv);
00353     }
00354   }
00355 
00356   return NS_OK;
00357 }
00358 
00359 nsresult
00360 nsGenericHTMLElement::GetTagName(nsAString& aTagName)
00361 {
00362   return GetNodeName(aTagName);
00363 }
00364 
00365 NS_IMETHODIMP
00366 nsGenericHTMLElement::SetAttribute(const nsAString& aName,
00367                                    const nsAString& aValue)
00368 {
00369   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
00370 
00371   if (!name) {
00372     nsresult rv = nsContentUtils::CheckQName(aName, PR_FALSE);
00373     NS_ENSURE_SUCCESS(rv, rv);
00374 
00375     nsCOMPtr<nsIAtom> nameAtom;
00376     if (mNodeInfo->NamespaceEquals(kNameSpaceID_None)) {
00377       nsAutoString lower;
00378       ToLowerCase(aName, lower);
00379       nameAtom = do_GetAtom(lower);
00380     }
00381     else {
00382       nameAtom = do_GetAtom(aName);
00383     }
00384     NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
00385 
00386     return SetAttr(kNameSpaceID_None, nameAtom, aValue, PR_TRUE);
00387   }
00388 
00389   return SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
00390                  aValue, PR_TRUE);
00391 }
00392 
00393 nsresult
00394 nsGenericHTMLElement::GetNodeName(nsAString& aNodeName)
00395 {
00396   mNodeInfo->GetQualifiedName(aNodeName);
00397 
00398   if (mNodeInfo->NamespaceEquals(kNameSpaceID_None))
00399     ToUpperCase(aNodeName);
00400 
00401   return NS_OK;
00402 }
00403 
00404 nsresult
00405 nsGenericHTMLElement::GetLocalName(nsAString& aLocalName)
00406 {
00407   mNodeInfo->GetLocalName(aLocalName);
00408 
00409   if (mNodeInfo->NamespaceEquals(kNameSpaceID_None)) {
00410     // No namespace, this means we're dealing with a good ol' HTML
00411     // element, so uppercase the local name.
00412 
00413     ToUpperCase(aLocalName);
00414   }
00415 
00416   return NS_OK;
00417 }
00418 
00419 nsresult
00420 nsGenericHTMLElement::GetElementsByTagName(const nsAString& aTagname,
00421                                            nsIDOMNodeList** aReturn)
00422 {
00423   nsAutoString tagName(aTagname);
00424 
00425   // Only lowercase the name if this element has no namespace (i.e.
00426   // it's a HTML element, not an XHTML element).
00427   if (mNodeInfo && mNodeInfo->NamespaceEquals(kNameSpaceID_None))
00428     ToLowerCase(tagName);
00429 
00430   return nsGenericElement::GetElementsByTagName(tagName, aReturn);
00431 }
00432 
00433 nsresult
00434 nsGenericHTMLElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
00435                                              const nsAString& aLocalName,
00436                                              nsIDOMNodeList** aReturn)
00437 {
00438   nsAutoString localName(aLocalName);
00439 
00440   // Only lowercase the name if this element has no namespace (i.e.
00441   // it's a HTML element, not an XHTML element).
00442   if (mNodeInfo && mNodeInfo->NamespaceEquals(kNameSpaceID_None))
00443     ToLowerCase(localName);
00444 
00445   return nsGenericElement::GetElementsByTagNameNS(aNamespaceURI, localName,
00446                                                   aReturn);
00447 }
00448 
00449 // Implementation for nsIDOMHTMLElement
00450 nsresult
00451 nsGenericHTMLElement::GetId(nsAString& aId)
00452 {
00453   GetAttr(kNameSpaceID_None, nsHTMLAtoms::id, aId);
00454   return NS_OK;
00455 }
00456 
00457 nsresult
00458 nsGenericHTMLElement::SetId(const nsAString& aId)
00459 {
00460   SetAttr(kNameSpaceID_None, nsHTMLAtoms::id, aId, PR_TRUE);
00461   return NS_OK;
00462 }
00463 
00464 nsresult
00465 nsGenericHTMLElement::GetTitle(nsAString& aTitle)
00466 {
00467   GetAttr(kNameSpaceID_None, nsHTMLAtoms::title, aTitle);
00468   return NS_OK;
00469 }
00470 
00471 nsresult
00472 nsGenericHTMLElement::SetTitle(const nsAString& aTitle)
00473 {
00474   SetAttr(kNameSpaceID_None, nsHTMLAtoms::title, aTitle, PR_TRUE);
00475   return NS_OK;
00476 }
00477 
00478 nsresult
00479 nsGenericHTMLElement::GetLang(nsAString& aLang)
00480 {
00481   GetAttr(kNameSpaceID_None, nsHTMLAtoms::lang, aLang);
00482   return NS_OK;
00483 }
00484 
00485 nsresult
00486 nsGenericHTMLElement::SetLang(const nsAString& aLang)
00487 {
00488   SetAttr(kNameSpaceID_None, nsHTMLAtoms::lang, aLang, PR_TRUE);
00489   return NS_OK;
00490 }
00491 
00492 static const nsAttrValue::EnumTable kDirTable[] = {
00493   { "ltr", NS_STYLE_DIRECTION_LTR },
00494   { "rtl", NS_STYLE_DIRECTION_RTL },
00495   { 0 }
00496 };
00497 
00498 nsresult
00499 nsGenericHTMLElement::GetDir(nsAString& aDir)
00500 {
00501   const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsHTMLAtoms::dir);
00502 
00503   if (attr && attr->Type() == nsAttrValue::eEnum) {
00504     attr->ToString(aDir);
00505   }
00506   else {
00507     aDir.Truncate();
00508   }
00509 
00510   return NS_OK;
00511 }
00512 
00513 nsresult
00514 nsGenericHTMLElement::SetDir(const nsAString& aDir)
00515 {
00516   SetAttr(kNameSpaceID_None, nsHTMLAtoms::dir, aDir, PR_TRUE);
00517   return NS_OK;
00518 }
00519 
00520 nsresult
00521 nsGenericHTMLElement::GetClassName(nsAString& aClassName)
00522 {
00523   GetAttr(kNameSpaceID_None, nsHTMLAtoms::kClass, aClassName);
00524   return NS_OK;
00525 }
00526 
00527 nsresult
00528 nsGenericHTMLElement::SetClassName(const nsAString& aClassName)
00529 {
00530   SetAttr(kNameSpaceID_None, nsHTMLAtoms::kClass, aClassName, PR_TRUE);
00531   return NS_OK;
00532 }
00533 
00534 nsresult
00535 nsGenericHTMLElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
00536 {
00537   nsDOMSlots *slots = GetDOMSlots();
00538 
00539   if (!slots->mStyle) {
00540     // Just in case...
00541     ReparseStyleAttribute();
00542 
00543     nsresult rv;
00544     if (!gCSSOMFactory) {
00545       rv = CallGetService(kCSSOMFactoryCID, &gCSSOMFactory);
00546       if (NS_FAILED(rv)) {
00547         return rv;
00548       }
00549     }
00550 
00551     rv = gCSSOMFactory->CreateDOMCSSAttributeDeclaration(this,
00552                                                          getter_AddRefs(slots->mStyle));
00553     if (NS_FAILED(rv)) {
00554       return rv;
00555     }
00556   }
00557 
00558   // Why bother with QI?
00559   NS_IF_ADDREF(*aStyle = slots->mStyle);
00560   return NS_OK;
00561 }
00562 
00563 void
00564 nsGenericHTMLElement::RecreateFrames()
00565 {
00566   nsIDocument* document = GetCurrentDoc();
00567   
00568   if (!document) {
00569     return;
00570   }
00571 
00572   PRInt32 numShells = document->GetNumberOfShells();
00573   for (PRInt32 i = 0; i < numShells; ++i) {
00574     nsIPresShell *shell = document->GetShellAt(i);
00575     if (shell) {
00576       nsIFrame* frame = nsnull;
00577       shell->GetPrimaryFrameFor(this, &frame);
00578       if (frame) {
00579         shell->RecreateFramesFor(this);
00580       }
00581     }
00582   }
00583 }
00584 
00585 static PRBool
00586 IsBody(nsIContent *aContent)
00587 {
00588   nsINodeInfo *ni = aContent->GetNodeInfo();
00589 
00590   return (ni && ni->Equals(nsHTMLAtoms::body) &&
00591           aContent->IsContentOfType(nsIContent::eHTML));
00592 }
00593 
00594 static PRBool
00595 IsOffsetParent(nsIContent *aContent)
00596 {
00597   nsINodeInfo *ni = aContent->GetNodeInfo();
00598 
00599   return (ni && (ni->Equals(nsHTMLAtoms::td) ||
00600                  ni->Equals(nsHTMLAtoms::table) ||
00601                  ni->Equals(nsHTMLAtoms::th)) &&
00602           aContent->IsContentOfType(nsIContent::eHTML));
00603 }
00604 
00605 void
00606 nsGenericHTMLElement::GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent)
00607 {
00608   *aOffsetParent = nsnull;
00609 
00610   aRect.x = aRect.y = 0;
00611   aRect.Empty();
00612 
00613   nsIDocument *document = GetCurrentDoc();
00614   if (!document) {
00615     return;
00616   }
00617 
00618   // Flush all pending notifications so that our frames are up to date.  Make
00619   // sure to do this first thing, since it may end up destroying our document's
00620   // presshell.
00621   document->FlushPendingNotifications(Flush_Layout);
00622 
00623   // Get Presentation shell 0
00624   nsIPresShell *presShell = document->GetShellAt(0);
00625 
00626   if (!presShell) {
00627     return;
00628   }
00629 
00630   // Get the Presentation Context from the Shell
00631   nsPresContext *context = presShell->GetPresContext();
00632   if (!context) {
00633     return;
00634   }
00635 
00636   // Get the Frame for our content
00637   nsIFrame* frame = nsnull;
00638   presShell->GetPrimaryFrameFor(this, &frame);
00639 
00640   if (!frame) {
00641     return;
00642   }
00643 
00644   // Get the union of all rectangles in this and continuation frames
00645   nsRect rcFrame;
00646   nsIFrame* next = frame;
00647 
00648   do {
00649     rcFrame.UnionRect(rcFrame, next->GetRect());
00650     next = next->GetNextInFlow();
00651   } while (next);
00652 
00653   if (rcFrame.IsEmpty()) {
00654     // It could happen that all the rects are empty (eg zero-width or
00655     // zero-height).  In that case, use the first rect for the frame.
00656     rcFrame = frame->GetRect();
00657   }
00658 
00659   nsIContent *docElement = document->GetRootContent();
00660 
00661   // Find the frame parent whose content's tagName either matches
00662   // the tagName passed in or is the document element.
00663   nsIFrame* parent = nsnull;
00664   PRBool done = PR_FALSE;
00665 
00666   nsIContent* content = frame->GetContent();
00667 
00668   if (content) {
00669     if (IsBody(content) || content == docElement) {
00670       done = PR_TRUE;
00671 
00672       parent = frame;
00673     }
00674   }
00675 
00676   nsPoint origin(0, 0);
00677 
00678   if (!done) {
00679     PRBool is_absolutely_positioned = PR_FALSE;
00680     PRBool is_positioned = PR_FALSE;
00681 
00682     origin = frame->GetPosition();
00683 
00684     const nsStyleDisplay* display = frame->GetStyleDisplay();
00685 
00686     if (display->IsPositioned()) {
00687       if (display->IsAbsolutelyPositioned()) {
00688         // If the primary frame or a parent is absolutely positioned
00689         // (fixed or absolute) we stop walking up the frame parent
00690         // chain
00691 
00692         is_absolutely_positioned = PR_TRUE;
00693       }
00694 
00695       // We need to know if the primary frame is positioned later on.
00696       is_positioned = PR_TRUE;
00697     }
00698 
00699     parent = frame->GetParent();
00700 
00701     while (parent) {
00702       display = parent->GetStyleDisplay();
00703 
00704       if (display->IsPositioned()) {
00705         // Stop at the first *parent* that is positioned (fixed,
00706         // absolute, or relatiive)
00707 
00708         *aOffsetParent = parent->GetContent();
00709         NS_IF_ADDREF(*aOffsetParent);
00710 
00711         break;
00712       }
00713 
00714       // Add the parent's origin to our own to get to the
00715       // right coordinate system
00716 
00717       if (!is_absolutely_positioned) {
00718         origin += parent->GetPosition();
00719       }
00720 
00721       content = parent->GetContent();
00722 
00723       if (content) {
00724         // If we've hit the document element, break here
00725         if (content == docElement) {
00726           break;
00727         }
00728 
00729         // If the tag of this frame is a offset parent tag and this
00730         // element is *not* positioned, break here. Also break if we
00731         // hit the body element.
00732         if ((!is_positioned && IsOffsetParent(content)) || IsBody(content)) {
00733           *aOffsetParent = content;
00734           NS_ADDREF(*aOffsetParent);
00735 
00736           break;
00737         }
00738       }
00739 
00740       parent = parent->GetParent();
00741     }
00742 
00743     if (is_absolutely_positioned && !*aOffsetParent) {
00744       // If this element is absolutely positioned, but we don't have
00745       // an offset parent it means this element is an absolutely
00746       // positioned child that's not nested inside another positioned
00747       // element, in this case the element's frame's parent is the
00748       // frame for the HTML element so we fail to find the body in the
00749       // parent chain. We want the offset parent in this case to be
00750       // the body, so we just get the body element from the document.
00751 
00752       nsCOMPtr<nsIDOMHTMLDocument> html_doc(do_QueryInterface(document));
00753 
00754       if (html_doc) {
00755         nsCOMPtr<nsIDOMHTMLElement> html_element;
00756 
00757         html_doc->GetBody(getter_AddRefs(html_element));
00758 
00759         if (html_element) {
00760           CallQueryInterface(html_element, aOffsetParent);
00761         }
00762       }
00763     }
00764   }
00765 
00766   // For the origin, add in the border for the frame
00767 
00768 #if 0
00769   // We used to do this to include the border of the frame in the
00770   // calculations, but I think that's wrong. My tests show that we
00771   // work more like IE if we don't do this, so lets try this and see
00772   // if people agree.
00773   const nsStyleBorder* border = frame->GetStyleBorder();
00774   origin.x += border->GetBorderWidth(NS_SIDE_LEFT);
00775   origin.y += border->GetBorderWidth(NS_SIDE_TOP);
00776 #endif
00777 
00778   // And subtract out the border for the parent
00779   if (parent) {
00780     PRBool includeBorder = PR_TRUE;  // set to false if border-box sizing is used
00781     const nsStylePosition* position = parent->GetStylePosition();
00782     if (position->mBoxSizing == NS_STYLE_BOX_SIZING_BORDER) {
00783       includeBorder = PR_FALSE;
00784     }
00785     
00786     if (includeBorder) {
00787       const nsStyleBorder* border = parent->GetStyleBorder();
00788       origin.x -= border->GetBorderWidth(NS_SIDE_LEFT);
00789       origin.y -= border->GetBorderWidth(NS_SIDE_TOP);
00790     }
00791   }
00792 
00793   // XXX We should really consider subtracting out padding for
00794   // content-box sizing, but we should see what IE does....
00795   
00796   // Get the scale from that Presentation Context
00797   float scale;
00798   scale = context->TwipsToPixels();
00799 
00800   // Convert to pixels using that scale
00801   aRect.x = NSTwipsToIntPixels(origin.x, scale);
00802   aRect.y = NSTwipsToIntPixels(origin.y, scale);
00803   aRect.width = NSTwipsToIntPixels(rcFrame.width, scale);
00804   aRect.height = NSTwipsToIntPixels(rcFrame.height, scale);
00805 }
00806 
00807 nsresult
00808 nsGenericHTMLElement::GetOffsetTop(PRInt32* aOffsetTop)
00809 {
00810   nsRect rcFrame;
00811   nsCOMPtr<nsIContent> parent;
00812   GetOffsetRect(rcFrame, getter_AddRefs(parent));
00813 
00814   *aOffsetTop = rcFrame.y;
00815 
00816   return NS_OK;
00817 }
00818 
00819 nsresult
00820 nsGenericHTMLElement::GetOffsetLeft(PRInt32* aOffsetLeft)
00821 {
00822   nsRect rcFrame;
00823   nsCOMPtr<nsIContent> parent;
00824   GetOffsetRect(rcFrame, getter_AddRefs(parent));
00825 
00826   *aOffsetLeft = rcFrame.x;
00827 
00828   return NS_OK;
00829 }
00830 
00831 nsresult
00832 nsGenericHTMLElement::GetOffsetWidth(PRInt32* aOffsetWidth)
00833 {
00834   nsRect rcFrame;
00835   nsCOMPtr<nsIContent> parent;
00836   GetOffsetRect(rcFrame, getter_AddRefs(parent));
00837 
00838   *aOffsetWidth = rcFrame.width;
00839 
00840   return NS_OK;
00841 }
00842 
00843 nsresult
00844 nsGenericHTMLElement::GetOffsetHeight(PRInt32* aOffsetHeight)
00845 {
00846   nsRect rcFrame;
00847   nsCOMPtr<nsIContent> parent;
00848   GetOffsetRect(rcFrame, getter_AddRefs(parent));
00849 
00850   *aOffsetHeight = rcFrame.height;
00851 
00852   return NS_OK;
00853 }
00854 
00855 nsresult
00856 nsGenericHTMLElement::GetOffsetParent(nsIDOMElement** aOffsetParent)
00857 {
00858   nsRect rcFrame;
00859   nsCOMPtr<nsIContent> parent;
00860   GetOffsetRect(rcFrame, getter_AddRefs(parent));
00861 
00862   if (parent) {
00863     CallQueryInterface(parent, aOffsetParent);
00864   } else {
00865     *aOffsetParent = nsnull;
00866   }
00867 
00868   return NS_OK;
00869 }
00870 
00871 nsresult
00872 nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML)
00873 {
00874   aInnerHTML.Truncate();
00875 
00876   nsCOMPtr<nsIDocument> doc = GetOwnerDoc();
00877   if (!doc) {
00878     return NS_OK; // We rely on the document for doing HTML conversion
00879   }
00880 
00881   nsCOMPtr<nsIDOMNode> thisNode(do_QueryInterface(NS_STATIC_CAST(nsIContent *,
00882                                                                  this)));
00883   nsresult rv = NS_OK;
00884 
00885   nsAutoString contentType;
00886   if (!doc->IsCaseSensitive()) {
00887     // All case-insensitive documents are HTML as far as we're concerned
00888     contentType.AssignLiteral("text/html");
00889   } else {
00890     doc->GetContentType(contentType);
00891   }
00892   
00893   nsCOMPtr<nsIDocumentEncoder> docEncoder;
00894   docEncoder =
00895     do_CreateInstance(PromiseFlatCString(
00896         nsDependentCString(NS_DOC_ENCODER_CONTRACTID_BASE) +
00897         NS_ConvertUTF16toUTF8(contentType)
00898       ).get());
00899   if (!docEncoder && doc->IsCaseSensitive()) {
00900     // This could be some type for which we create a synthetic document.  Try
00901     // again as XML
00902     contentType.AssignLiteral("application/xml");
00903     docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xml");
00904   }
00905 
00906   NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
00907 
00908   docEncoder->Init(doc, contentType,
00909                    nsIDocumentEncoder::OutputEncodeBasicEntities |
00910                    // Output DOM-standard newlines
00911                    nsIDocumentEncoder::OutputLFLineBreak |
00912                    // Don't do linebreaking that's not present in the source
00913                    nsIDocumentEncoder::OutputRaw);
00914 
00915   nsCOMPtr<nsIDOMRange> range(new nsRange);
00916   NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
00917 
00918   rv = range->SelectNodeContents(thisNode);
00919   NS_ENSURE_SUCCESS(rv, rv);
00920 
00921   docEncoder->SetRange(range);
00922 
00923   docEncoder->EncodeToString(aInnerHTML);
00924 
00925   return rv;
00926 }
00927 
00928 nsresult
00929 nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
00930 {
00931   // This BeginUpdate/EndUpdate pair is important to make us reenable the
00932   // scriptloader before the last EndUpdate call.
00933   mozAutoDocUpdate updateBatch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, PR_TRUE);
00934 
00935   nsresult rv = NS_OK;
00936 
00937   nsCOMPtr<nsIDOMRange> range = new nsRange;
00938   NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY);
00939 
00940   nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range, &rv));
00941   NS_ENSURE_SUCCESS(rv, rv);
00942 
00943   nsCOMPtr<nsIDOMNode> thisNode(do_QueryInterface(NS_STATIC_CAST(nsIContent *,
00944                                                                  this)));
00945   rv = range->SelectNodeContents(thisNode);
00946   NS_ENSURE_SUCCESS(rv, rv);
00947 
00948   rv = range->DeleteContents();
00949   NS_ENSURE_SUCCESS(rv, rv);
00950 
00951   nsCOMPtr<nsIDOMDocumentFragment> df;
00952 
00953   nsCOMPtr<nsIDocument> doc = GetOwnerDoc();
00954 
00955   // Strong ref since appendChild can fire events
00956   nsCOMPtr<nsIScriptLoader> loader;
00957   PRBool scripts_enabled = PR_FALSE;
00958 
00959   if (doc) {
00960     loader = doc->GetScriptLoader();
00961     if (loader) {
00962       loader->GetEnabled(&scripts_enabled);
00963     }
00964   }
00965 
00966   if (scripts_enabled) {
00967     // Don't let scripts execute while setting .innerHTML.
00968 
00969     loader->SetEnabled(PR_FALSE);
00970   }
00971 
00972   rv = nsrange->CreateContextualFragment(aInnerHTML, getter_AddRefs(df));
00973 
00974   if (NS_SUCCEEDED(rv)) {
00975     nsCOMPtr<nsIDOMNode> tmpNode;
00976     rv = thisNode->AppendChild(df, getter_AddRefs(tmpNode));
00977   }
00978 
00979   if (scripts_enabled) {
00980     // If we disabled scripts, re-enable them now that we're
00981     // done. Don't fire JS timeouts when enabling the context here.
00982 
00983     loader->SetEnabled(PR_TRUE);
00984   }
00985 
00986   return rv;
00987 }
00988 
00989 void
00990 nsGenericHTMLElement::GetScrollInfo(nsIScrollableView **aScrollableView,
00991                                     float *aP2T, float *aT2P,
00992                                     nsIFrame **aFrame)
00993 {
00994   *aScrollableView = nsnull;
00995   *aP2T = 0.0f;
00996   *aT2P = 0.0f;
00997 
00998   nsIDocument *document = GetCurrentDoc();
00999   if (!document) {
01000     return;
01001   }
01002 
01003   // Flush all pending notifications so that our frames are up to date.  Make
01004   // sure to do this first thing, since it may end up destroying our document's
01005   // presshell.
01006   document->FlushPendingNotifications(Flush_Layout);
01007 
01008   // Get the presentation shell
01009   nsIPresShell *presShell = document->GetShellAt(0);
01010   if (!presShell) {
01011     return;
01012   }
01013 
01014   // Get the presentation context
01015   nsPresContext *presContext = presShell->GetPresContext();
01016   if (!presContext) {
01017     return;
01018   }
01019 
01020   // Get the primary frame for this element
01021   nsIFrame *frame = nsnull;
01022   presShell->GetPrimaryFrameFor(this, &frame);
01023   if (!frame) {
01024     return;
01025   }
01026 
01027   if (aFrame) {
01028     *aFrame = frame;
01029   }
01030 
01031   *aP2T = presContext->PixelsToTwips();
01032   *aT2P = presContext->TwipsToPixels();
01033 
01034   // Get the scrollable frame
01035   nsIScrollableFrame *scrollFrame = nsnull;
01036   CallQueryInterface(frame, &scrollFrame);
01037 
01038   if (!scrollFrame) {
01039     nsIScrollableViewProvider *scrollProvider = nsnull;
01040     CallQueryInterface(frame, &scrollProvider);
01041     if (scrollProvider) {
01042       *aScrollableView = scrollProvider->GetScrollableView();
01043       if (*aScrollableView) {
01044         return;
01045       }
01046     }
01047 
01048     PRBool quirksMode = InNavQuirksMode(document);
01049     if ((quirksMode && mNodeInfo->Equals(nsHTMLAtoms::body)) ||
01050         (!quirksMode && mNodeInfo->Equals(nsHTMLAtoms::html))) {
01051       // In quirks mode, the scroll info for the body element should map to the
01052       // scroll info for the nearest scrollable frame above the body element
01053       // (i.e. the root scrollable frame).  This is what IE6 does in quirks
01054       // mode.  In strict mode the root scrollable frame corresponds to the
01055       // html element in IE6, so we map the scroll info for the html element to
01056       // the root scrollable frame.
01057 
01058       do {
01059         frame = frame->GetParent();
01060 
01061         if (!frame) {
01062           break;
01063         }
01064 
01065         CallQueryInterface(frame, &scrollFrame);
01066       } while (!scrollFrame);
01067     }
01068 
01069     if (!scrollFrame) {
01070       return;
01071     }
01072   }
01073 
01074   // Get the scrollable view
01075   *aScrollableView = scrollFrame->GetScrollableView();
01076 
01077   return;
01078 }
01079 
01080 
01081 nsresult
01082 nsGenericHTMLElement::GetScrollTop(PRInt32* aScrollTop)
01083 {
01084   NS_ENSURE_ARG_POINTER(aScrollTop);
01085   *aScrollTop = 0;
01086 
01087   nsIScrollableView *view = nsnull;
01088   nsresult rv = NS_OK;
01089   float p2t, t2p;
01090 
01091   GetScrollInfo(&view, &p2t, &t2p);
01092 
01093   if (view) {
01094     nscoord xPos, yPos;
01095     rv = view->GetScrollPosition(xPos, yPos);
01096 
01097     *aScrollTop = NSTwipsToIntPixels(yPos, t2p);
01098   }
01099 
01100   return rv;
01101 }
01102 
01103 nsresult
01104 nsGenericHTMLElement::SetScrollTop(PRInt32 aScrollTop)
01105 {
01106   nsIScrollableView *view = nsnull;
01107   nsresult rv = NS_OK;
01108   float p2t, t2p;
01109 
01110   GetScrollInfo(&view, &p2t, &t2p);
01111 
01112   if (view) {
01113     nscoord xPos, yPos;
01114 
01115     rv = view->GetScrollPosition(xPos, yPos);
01116 
01117     if (NS_SUCCEEDED(rv)) {
01118       rv = view->ScrollTo(xPos, NSIntPixelsToTwips(aScrollTop, p2t),
01119                           NS_VMREFRESH_IMMEDIATE);
01120     }
01121   }
01122 
01123   return rv;
01124 }
01125 
01126 nsresult
01127 nsGenericHTMLElement::GetScrollLeft(PRInt32* aScrollLeft)
01128 {
01129   NS_ENSURE_ARG_POINTER(aScrollLeft);
01130   *aScrollLeft = 0;
01131 
01132   nsIScrollableView *view = nsnull;
01133   nsresult rv = NS_OK;
01134   float p2t, t2p;
01135 
01136   GetScrollInfo(&view, &p2t, &t2p);
01137 
01138   if (view) {
01139     nscoord xPos, yPos;
01140     rv = view->GetScrollPosition(xPos, yPos);
01141 
01142     *aScrollLeft = NSTwipsToIntPixels(xPos, t2p);
01143   }
01144 
01145   return rv;
01146 }
01147 
01148 nsresult
01149 nsGenericHTMLElement::SetScrollLeft(PRInt32 aScrollLeft)
01150 {
01151   nsIScrollableView *view = nsnull;
01152   nsresult rv = NS_OK;
01153   float p2t, t2p;
01154 
01155   GetScrollInfo(&view, &p2t, &t2p);
01156 
01157   if (view) {
01158     nscoord xPos, yPos;
01159     rv = view->GetScrollPosition(xPos, yPos);
01160 
01161     if (NS_SUCCEEDED(rv)) {
01162       rv = view->ScrollTo(NSIntPixelsToTwips(aScrollLeft, p2t),
01163                           yPos, NS_VMREFRESH_IMMEDIATE);
01164     }
01165   }
01166 
01167   return rv;
01168 }
01169 
01170 nsresult
01171 nsGenericHTMLElement::GetScrollHeight(PRInt32* aScrollHeight)
01172 {
01173   NS_ENSURE_ARG_POINTER(aScrollHeight);
01174   *aScrollHeight = 0;
01175 
01176   nsIScrollableView *scrollView = nsnull;
01177   nsresult rv = NS_OK;
01178   float p2t, t2p;
01179 
01180   GetScrollInfo(&scrollView, &p2t, &t2p);
01181 
01182   if (!scrollView) {
01183     return GetOffsetHeight(aScrollHeight);
01184   }
01185 
01186   // xMax and yMax is the total length of our container
01187   nscoord xMax, yMax;
01188   rv = scrollView->GetContainerSize(&xMax, &yMax);
01189 
01190   *aScrollHeight = NSTwipsToIntPixels(yMax, t2p);
01191 
01192   return rv;
01193 }
01194 
01195 nsresult
01196 nsGenericHTMLElement::GetScrollWidth(PRInt32* aScrollWidth)
01197 {
01198   NS_ENSURE_ARG_POINTER(aScrollWidth);
01199   *aScrollWidth = 0;
01200 
01201   nsIScrollableView *scrollView = nsnull;
01202   nsresult rv = NS_OK;
01203   float p2t, t2p;
01204 
01205   GetScrollInfo(&scrollView, &p2t, &t2p);
01206 
01207   if (!scrollView) {
01208     return GetOffsetWidth(aScrollWidth);
01209   }
01210 
01211   nscoord xMax, yMax;
01212   rv = scrollView->GetContainerSize(&xMax, &yMax);
01213 
01214   *aScrollWidth = NSTwipsToIntPixels(xMax, t2p);
01215 
01216   return rv;
01217 }
01218 
01219 // static
01220 const nsSize
01221 nsGenericHTMLElement::GetClientAreaSize(nsIFrame *aFrame)
01222 {
01223   nsRect rect = aFrame->GetRect();
01224 
01225   const nsStyleBorder* border = aFrame->GetStyleBorder();
01226 
01227   nsMargin border_size;
01228   border->CalcBorderFor(aFrame, border_size);
01229 
01230   rect.Deflate(border_size);
01231 
01232   return nsSize(rect.width, rect.height);
01233 }
01234 
01235 nsresult
01236 nsGenericHTMLElement::GetClientHeight(PRInt32* aClientHeight)
01237 {
01238   NS_ENSURE_ARG_POINTER(aClientHeight);
01239   *aClientHeight = 0;
01240 
01241   nsIScrollableView *scrollView = nsnull;
01242   float p2t, t2p;
01243   nsIFrame *frame = nsnull;
01244 
01245   GetScrollInfo(&scrollView, &p2t, &t2p, &frame);
01246 
01247   if (scrollView) {
01248     nsRect r = scrollView->View()->GetBounds();
01249 
01250     *aClientHeight = NSTwipsToIntPixels(r.height, t2p);
01251   } else if (frame &&
01252              (frame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
01253               (frame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT))) {
01254     // Special case code to make clientHeight work even when there isn't
01255     // a scroll view, see bug 180552 and bug 227567.
01256 
01257     *aClientHeight = NSTwipsToIntPixels(GetClientAreaSize(frame).height, t2p);
01258   }
01259 
01260   return NS_OK;
01261 }
01262 
01263 nsresult
01264 nsGenericHTMLElement::GetClientWidth(PRInt32* aClientWidth)
01265 {
01266   NS_ENSURE_ARG_POINTER(aClientWidth);
01267   *aClientWidth = 0;
01268 
01269   nsIScrollableView *scrollView = nsnull;
01270   float p2t, t2p;
01271   nsIFrame *frame = nsnull;
01272 
01273   GetScrollInfo(&scrollView, &p2t, &t2p, &frame);
01274 
01275   if (scrollView) {
01276     nsRect r = scrollView->View()->GetBounds();
01277 
01278     *aClientWidth = NSTwipsToIntPixels(r.width, t2p);
01279   } else if (frame &&
01280              (frame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE ||
01281               (frame->GetStateBits() & NS_FRAME_REPLACED_ELEMENT))) {
01282     // Special case code to make clientWidth work even when there isn't
01283     // a scroll view, see bug 180552 and bug 227567.
01284 
01285     *aClientWidth = NSTwipsToIntPixels(GetClientAreaSize(frame).width, t2p);
01286   }
01287 
01288   return NS_OK;
01289 }
01290 
01291 nsresult
01292 nsGenericHTMLElement::ScrollIntoView(PRBool aTop)
01293 {
01294   nsIDocument *document = GetCurrentDoc();
01295 
01296   if (!document) {
01297     return NS_OK;
01298   }
01299 
01300   // Flush all pending notifications so that our frames are up to date.  Make
01301   // sure to do this first thing, since it may end up destroying our document's
01302   // presshell.
01303   document->FlushPendingNotifications(Flush_Layout);
01304   
01305   // Get the presentation shell
01306   nsIPresShell *presShell = document->GetShellAt(0);
01307   if (!presShell) {
01308     return NS_OK;
01309   }
01310 
01311   // Get the primary frame for this element
01312   nsIFrame *frame = nsnull;
01313   presShell->GetPrimaryFrameFor(this, &frame);
01314   if (!frame) {
01315     return NS_OK;
01316   }
01317 
01318   PRIntn vpercent = aTop ? NS_PRESSHELL_SCROLL_TOP :
01319     NS_PRESSHELL_SCROLL_ANYWHERE;
01320 
01321   presShell->ScrollFrameIntoView(frame, vpercent,
01322                                  NS_PRESSHELL_SCROLL_ANYWHERE);
01323 
01324   return NS_OK;
01325 }
01326 
01327 NS_IMETHODIMP
01328 nsGenericHTMLElement::GetSpellcheck(PRBool* aSpellcheck)
01329 {
01330   NS_ENSURE_ARG_POINTER(aSpellcheck);
01331   *aSpellcheck = PR_FALSE;              // Default answer is to not spellcheck
01332 
01333   // Has the state has been explicitly set?
01334   nsIContent* content;
01335   for (content = this; content; content = content->GetParent()) {
01336     if (content->IsContentOfType(nsIContent::eHTML)) {
01337       nsAutoString target;
01338       content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::spellcheck, target);
01339       if (target.EqualsLiteral("true")) {
01340         *aSpellcheck = PR_TRUE;
01341         return NS_OK;
01342       }
01343       if (target.EqualsLiteral("false")) {
01344         *aSpellcheck = PR_FALSE;
01345         return NS_OK;
01346       }
01347     }
01348   }
01349 
01350   // Is this a chrome element?
01351   if (nsContentUtils::IsChromeDoc(GetOwnerDoc())) {
01352     return NS_OK;                       // Not spellchecked by default
01353   }
01354 
01355   // Is this the actual body of the current document?
01356   if (IsCurrentBodyElement()) {
01357     // Is designMode on?
01358     nsCOMPtr<nsIDOMNSHTMLDocument> nsHTMLDocument =
01359       do_QueryInterface(GetCurrentDoc());
01360     if (!nsHTMLDocument) {
01361       return PR_FALSE;
01362     }
01363 
01364     nsAutoString designMode;
01365     nsHTMLDocument->GetDesignMode(designMode);
01366     *aSpellcheck = designMode.EqualsLiteral("on");
01367     return NS_OK;
01368   }
01369 
01370   // Is this element editable?
01371   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(this);
01372   if (!formControl) {
01373     return NS_OK;                       // Not spellchecked by default
01374   }
01375 
01376   // Is this a multiline plaintext input?
01377   PRInt32 controlType = formControl->GetType();
01378   if (controlType == NS_FORM_TEXTAREA) {
01379     *aSpellcheck = PR_TRUE;             // Spellchecked by default
01380     return NS_OK;
01381   }
01382 
01383   // Is this anything other than a single-line plaintext input?
01384   if (controlType != NS_FORM_INPUT_TEXT) {
01385     return NS_OK;                       // Not spellchecked by default
01386   }
01387 
01388   // Does the user want single-line inputs spellchecked by default?
01389   // NOTE: Do not reflect a pref value of 0 back to the DOM getter.
01390   // The web page should not know if the user has disabled spellchecking.
01391   // We'll catch this in the editor itself.
01392   PRInt32 spellcheckLevel =
01393     nsContentUtils::GetIntPref("layout.spellcheckDefault", 1);
01394   if (spellcheckLevel == 2) {           // "Spellcheck multi- and single-line"
01395     *aSpellcheck = PR_TRUE;             // Spellchecked by default
01396   }
01397 
01398   return NS_OK;
01399 }
01400 
01401 NS_IMETHODIMP
01402 nsGenericHTMLElement::SetSpellcheck(PRBool aSpellcheck)
01403 {
01404   if (aSpellcheck) {
01405     return SetAttrHelper(nsHTMLAtoms::spellcheck, NS_LITERAL_STRING("true"));
01406   }
01407 
01408   return SetAttrHelper(nsHTMLAtoms::spellcheck, NS_LITERAL_STRING("false"));
01409 }
01410 
01411 PRBool
01412 nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
01413 {
01414   nsCOMPtr<nsIHTMLDocument> doc(do_QueryInterface(aDoc));
01415   if (!doc) {
01416     return PR_FALSE;
01417   }
01418 
01419   return doc->GetCompatibilityMode() == eCompatibility_NavQuirks;
01420 }
01421 
01422 nsresult
01423 nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
01424                                  nsIContent* aBindingParent,
01425                                  PRBool aCompileEventHandlers)
01426 {
01427   nsresult rv = nsGenericElement::BindToTree(aDocument, aParent,
01428                                              aBindingParent,
01429                                              aCompileEventHandlers);
01430   NS_ENSURE_SUCCESS(rv, rv);
01431 
01432   // XXXbz if we already have a style attr parsed, this won't do
01433   // anything... need to fix that.
01434   ReparseStyleAttribute();
01435 
01436   if (aDocument) {
01437     // If we're in a document now, let our mapped attrs know what their new
01438     // sheet is.
01439     nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
01440     if (sheet) {
01441       mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
01442     }
01443   }
01444 
01445   return rv;
01446 }
01447 
01448 already_AddRefed<nsIDOMHTMLFormElement>
01449 nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm)
01450 {
01451   nsIContent* content = this;
01452   while (content) {
01453     // If the current ancestor is a form, return it as our form
01454     if (content->IsContentOfType(nsIContent::eHTML) &&
01455         content->GetNodeInfo()->Equals(nsHTMLAtoms::form)) {
01456       nsIDOMHTMLFormElement* form;
01457       CallQueryInterface(content, &form);
01458 
01459       return form;
01460     }
01461 
01462     nsIContent *prevContent = content;
01463     content = prevContent->GetParent();
01464 
01465     if (!content && aCurrentForm) {
01466       // We got to the root of the subtree we're in, and we're being removed
01467       // from the DOM (the only time we get into this method with a non-null
01468       // aCurrentForm).  Check whether aCurrentForm is in the same subtree.  If
01469       // it is, we want to return aCurrentForm, since this case means that
01470       // we're one of those inputs-in-a-table that have a hacked mForm pointer
01471       // and a subtree containing both us and the form got removed from the
01472       // DOM.
01473       nsCOMPtr<nsIContent> formCOMPtr = do_QueryInterface(aCurrentForm);
01474       NS_ASSERTION(formCOMPtr, "aCurrentForm isn't an nsIContent?");
01475       // Use an nsIContent temporary to reduce addref/releasing as we go up the
01476       // tree
01477       nsIContent* iter = formCOMPtr;
01478       do {
01479         iter = iter->GetParent();
01480         if (iter == prevContent) {
01481           nsIDOMHTMLFormElement* form;
01482           CallQueryInterface(aCurrentForm, &form);
01483           return form;
01484         }
01485       } while (iter);
01486     }
01487     
01488     if (content) {
01489       PRInt32 i = content->IndexOf(prevContent);
01490 
01491       if (i < 0) {
01492         // This means 'prevContent' is anonymous content, form controls in
01493         // anonymous content can't refer to the real form, if they do
01494         // they end up in form.elements n' such, and that's wrong...
01495 
01496         return nsnull;
01497       }
01498     }
01499   }
01500 
01501   return nsnull;
01502 }
01503 
01504 static PRBool
01505 IsArea(nsIContent *aContent)
01506 {
01507   nsINodeInfo *ni = aContent->GetNodeInfo();
01508 
01509   return (ni && ni->Equals(nsHTMLAtoms::area) &&
01510           aContent->IsContentOfType(nsIContent::eHTML));
01511 }
01512 
01513 /* static */
01514 nsresult
01515 nsGenericHTMLElement::DispatchEvent(nsPresContext* aPresContext,
01516                                     nsEvent* aEvent,
01517                                     nsIContent* aTarget,
01518                                     PRBool aFullDispatch,
01519                                     nsEventStatus* aStatus)
01520 {
01521   NS_PRECONDITION(aTarget, "Must have target");
01522   NS_PRECONDITION(aEvent, "Must have source event");
01523   NS_PRECONDITION(aStatus, "Null out param?");
01524 
01525   if (!aPresContext) {
01526     return NS_OK;
01527   }
01528 
01529   nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
01530   if (!shell) {
01531     return NS_OK;
01532   }
01533 
01534   if (aFullDispatch) {
01535     return shell->HandleEventWithTarget(aEvent, nsnull, aTarget,
01536                                         NS_EVENT_FLAG_INIT, aStatus);
01537   }
01538 
01539   return shell->HandleDOMEventWithTarget(aTarget, aEvent, aStatus);
01540 }
01541               
01542 /* static */
01543 nsresult
01544 nsGenericHTMLElement::DispatchClickEvent(nsPresContext* aPresContext,
01545                                          nsInputEvent* aSourceEvent,
01546                                          nsIContent* aTarget,
01547                                          PRBool aFullDispatch,
01548                                          nsEventStatus* aStatus)
01549 {
01550   NS_PRECONDITION(aTarget, "Must have target");
01551   NS_PRECONDITION(aSourceEvent, "Must have source event");
01552   NS_PRECONDITION(aStatus, "Null out param?");
01553 
01554   nsMouseEvent event(NS_IS_TRUSTED_EVENT(aSourceEvent), NS_MOUSE_LEFT_CLICK,
01555                      aSourceEvent->widget, nsMouseEvent::eReal);
01556   event.point = aSourceEvent->point;
01557   event.refPoint = aSourceEvent->refPoint;
01558   PRUint32 clickCount = 1;
01559   if (aSourceEvent->eventStructType == NS_MOUSE_EVENT) {
01560     clickCount = NS_STATIC_CAST(nsMouseEvent*, aSourceEvent)->clickCount;
01561   }
01562   event.clickCount = clickCount;
01563   event.isShift = aSourceEvent->isShift;
01564   event.isControl = aSourceEvent->isControl;
01565   event.isAlt = aSourceEvent->isAlt;
01566   event.isMeta = aSourceEvent->isMeta;
01567 
01568   return DispatchEvent(aPresContext, &event, aTarget, aFullDispatch, aStatus);
01569 }
01570 
01571 nsresult
01572 nsGenericHTMLElement::HandleDOMEventForAnchors(nsPresContext* aPresContext,
01573                                                nsEvent* aEvent,
01574                                                nsIDOMEvent** aDOMEvent,
01575                                                PRUint32 aFlags,
01576                                                nsEventStatus* aEventStatus)
01577 {
01578   NS_ENSURE_ARG_POINTER(aEventStatus);
01579   NS_PRECONDITION(nsCOMPtr<nsILink>(do_QueryInterface(this)),
01580                   "should be called only when |this| implements |nsILink|");
01581 
01582   // Try script event handlers first
01583   nsresult ret = nsGenericHTMLElement::HandleDOMEvent(aPresContext, aEvent,
01584                                                       aDOMEvent, aFlags,
01585                                                       aEventStatus);
01586 
01587   if (!aPresContext) {
01588     // No pres context when event generated by other parts of DOM code,
01589     // as in mutation events
01590     return NS_OK; 
01591   }
01592 
01593   //Need to check if we hit an imagemap area and if so see if we're handling
01594   //the event on that map or on a link farther up the tree.  If we're on a
01595   //link farther up, do nothing.
01596   if (NS_SUCCEEDED(ret)) {
01597     nsCOMPtr<nsIContent> target;
01598 
01599     aPresContext->EventStateManager()->
01600       GetEventTargetContent(aEvent, getter_AddRefs(target));
01601 
01602     if (target && IsArea(target) && !IsArea(this)) {
01603       // We are over an area and our element is not one.  Return without
01604       // running anchor code.
01605       return ret;
01606     }
01607   }
01608 
01609   if (NS_FAILED(ret))
01610     return ret;
01611 
01612   // Ensure that this is a trusted DOM event before going further.
01613   // XXXldb Why can aDOMEvent by null?
01614   if (aDOMEvent && *aDOMEvent) {
01615     nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(*aDOMEvent);
01616     NS_ENSURE_TRUE(nsEvent, NS_OK);
01617     PRBool isTrusted;
01618     ret = nsEvent->GetIsTrusted(&isTrusted);
01619     NS_ENSURE_SUCCESS(ret, NS_OK);
01620     if (!isTrusted)
01621       return NS_OK;
01622   }
01623 
01624   if ((*aEventStatus == nsEventStatus_eIgnore ||
01625        (*aEventStatus != nsEventStatus_eConsumeNoDefault &&
01626         (aEvent->message == NS_MOUSE_ENTER_SYNTH ||
01627          aEvent->message == NS_MOUSE_EXIT_SYNTH))) &&
01628       !(aFlags & NS_EVENT_FLAG_CAPTURE) && !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
01629 
01630     // We'll use the equivalent of |GetHrefUTF8| on the
01631     // nsILink interface to get a canonified URL that has been
01632     // correctly escaped and URL-encoded for the document's charset.
01633 
01634     nsCOMPtr<nsIURI> hrefURI;
01635     GetHrefURIForAnchors(getter_AddRefs(hrefURI));
01636 
01637     // Only bother to handle the mouse event if there was an href
01638     // specified.
01639     if (hrefURI) {
01640       switch (aEvent->message) {
01641       case NS_MOUSE_LEFT_BUTTON_DOWN:
01642         {
01643           // don't make the link grab the focus if there is no link handler
01644           nsILinkHandler *handler = aPresContext->GetLinkHandler();
01645           nsIDocument *document = GetCurrentDoc();
01646           if (handler && document && ShouldFocus(this)) {
01647             // If the window is not active, do not allow the focus to bring the
01648             // window to the front.  We update the focus controller, but do
01649             // nothing else.
01650             nsCOMPtr<nsPIDOMWindow> win =
01651               do_QueryInterface(document->GetScriptGlobalObject());
01652             if (win) {
01653               nsIFocusController *focusController =
01654                 win->GetRootFocusController();
01655               if (focusController) {
01656                 PRBool isActive = PR_FALSE;
01657                 focusController->GetActive(&isActive);
01658                 if (!isActive) {
01659                   nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(this);
01660                   if(domElement)
01661                     focusController->SetFocusedElement(domElement);
01662                   break;
01663                 }
01664               }
01665             }
01666   
01667             aPresContext->EventStateManager()->
01668               SetContentState(this,
01669                               NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS);
01670 
01671           }
01672         }
01673         break;
01674 
01675       case NS_MOUSE_LEFT_CLICK:
01676         if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
01677           nsInputEvent* inputEvent = NS_STATIC_CAST(nsInputEvent*, aEvent);
01678           if (inputEvent->isControl || inputEvent->isMeta ||
01679               inputEvent->isAlt ||inputEvent->isShift) {
01680             break;  // let the click go through so we can handle it in JS/XUL
01681           }
01682 
01683           // The default action is simply to dispatch DOMActivate
01684           nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
01685           if (shell) {
01686             // single-click
01687             nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_UI_ACTIVATE, 1);
01688             nsEventStatus status = nsEventStatus_eIgnore;
01689 
01690             ret = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
01691             *aEventStatus = status;
01692           }
01693 
01694           if (*aEventStatus != nsEventStatus_eConsumeNoDefault)
01695             *aEventStatus = nsEventStatus_eConsumeDoDefault;
01696         }
01697         break;
01698 
01699       case NS_UI_ACTIVATE:
01700         if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
01701           nsAutoString target;
01702           GetAttr(kNameSpaceID_None, nsHTMLAtoms::target, target);
01703           if (target.IsEmpty()) {
01704             GetBaseTarget(target);
01705           }
01706 
01707           ret = TriggerLink(aPresContext, eLinkVerb_Replace, hrefURI,
01708                             target, PR_TRUE, PR_TRUE);
01709         }
01710         break;
01711 
01712       case NS_KEY_PRESS:
01713         if (aEvent->eventStructType == NS_KEY_EVENT) {
01714           nsKeyEvent* keyEvent = NS_STATIC_CAST(nsKeyEvent*, aEvent);
01715           if (keyEvent->keyCode == NS_VK_RETURN) {
01716             nsEventStatus status = nsEventStatus_eIgnore;
01717             ret = DispatchClickEvent(aPresContext, keyEvent, this, PR_FALSE, &status);
01718             if (NS_SUCCEEDED(ret)) {
01719               *aEventStatus = nsEventStatus_eConsumeNoDefault;
01720             }
01721           }
01722         }
01723         break;
01724 
01725       // Set the status bar the same for focus and mouseover
01726       case NS_MOUSE_ENTER_SYNTH:
01727         *aEventStatus = nsEventStatus_eConsumeNoDefault;
01728       case NS_FOCUS_CONTENT:
01729       {
01730         nsAutoString target;
01731         GetAttr(kNameSpaceID_None, nsHTMLAtoms::target, target);
01732         if (target.IsEmpty()) {
01733           GetBaseTarget(target);
01734         }
01735         ret = TriggerLink(aPresContext, eLinkVerb_Replace,
01736                           hrefURI, target, PR_FALSE, PR_TRUE);
01737       }
01738       break;
01739 
01740       case NS_MOUSE_EXIT_SYNTH:
01741       {
01742         *aEventStatus = nsEventStatus_eConsumeNoDefault;
01743         ret = LeaveLink(aPresContext);
01744       }
01745       break;
01746 
01747       default:
01748         break;
01749       }
01750     }
01751   }
01752   return ret;
01753 }
01754 
01755 nsresult
01756 nsGenericHTMLElement::GetHrefURIForAnchors(nsIURI** aURI)
01757 {
01758   // This is used by the three nsILink implementations and
01759   // nsHTMLStyleElement.
01760 
01761   // Get href= attribute (relative URI).
01762 
01763   // We use the nsAttrValue's copy of the URI string to avoid copying.
01764   const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsHTMLAtoms::href);
01765   if (attr) {
01766     // Get base URI.
01767     nsCOMPtr<nsIURI> baseURI = GetBaseURI();
01768 
01769     // Get absolute URI.
01770     nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI,
01771                                                             attr->GetStringValue(),
01772                                                             GetOwnerDoc(),
01773                                                             baseURI);
01774     if (NS_FAILED(rv)) {
01775       *aURI = nsnull;
01776     }
01777   }
01778   else {
01779     // Absolute URI is null to say we have no HREF.
01780     *aURI = nsnull;
01781   }
01782 
01783   return NS_OK;
01784 }
01785 
01786 nsresult
01787 nsGenericHTMLElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aAttribute,
01788                               nsIAtom* aPrefix, const nsAString& aValue,
01789                               PRBool aNotify)
01790 {
01791   NS_ASSERTION(aNamespaceID != kNameSpaceID_XHTML,
01792                "Error, attribute on [X]HTML element set with XHTML namespace, "
01793                "this is wrong, trust me! Lose the prefix on the attribute!");
01794 
01795   nsresult rv;
01796   nsAutoString oldValue;
01797   PRBool hasListeners = PR_FALSE;
01798   PRBool modification = PR_FALSE;
01799 
01800   if (IsInDoc()) {
01801     hasListeners = nsGenericElement::HasMutationListeners(this,
01802       NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
01803 
01804     // If we have no listeners and aNotify is false, we are almost certainly
01805     // coming from the content sink and will almost certainly have no previous
01806     // value.  Even if we do, setting the value is cheap when we have no
01807     // listeners and don't plan to notify.  The check for aNotify here is an
01808     // optimization, the check for haveListeners is a correctness issue.
01809     if (hasListeners || aNotify) {
01810       // don't do any update if old == new.
01811       // It would be nice to not have to call GetAttr here but to rather just
01812       // grab the nsAttrValue from mAttrsAndChildren and compare that to
01813       // aValue. However not all nsAttrValues can currently be converted to
01814       // strings (specifically enums and nsISupports can't) so we have to take
01815       // the detour through GetAttr for now.
01816       rv = GetAttr(aNamespaceID, aAttribute, oldValue);
01817       modification = rv != NS_CONTENT_ATTR_NOT_THERE;
01818       if (modification && aValue.Equals(oldValue)) {
01819         return NS_OK;
01820       }
01821     }
01822   }
01823 
01824   // Parse into a nsAttrValue
01825   nsAttrValue attrValue;
01826   if (aNamespaceID == kNameSpaceID_None) {
01827     if (!ParseAttribute(aAttribute, aValue, attrValue)) {
01828       attrValue.SetTo(aValue);
01829     }
01830 
01831     if (IsEventName(aAttribute)) {
01832       AddScriptEventListener(aAttribute, aValue);
01833     }
01834   }
01835   else {
01836     attrValue.SetTo(aValue);
01837   }
01838 
01839   return SetAttrAndNotify(aNamespaceID, aAttribute, aPrefix, oldValue,
01840                           attrValue, modification, hasListeners, aNotify);
01841 }
01842 
01843 nsresult
01844 nsGenericHTMLElement::SetAttrAndNotify(PRInt32 aNamespaceID,
01845                                        nsIAtom* aAttribute,
01846                                        nsIAtom* aPrefix,
01847                                        const nsAString& aOldValue,
01848                                        nsAttrValue& aParsedValue,
01849                                        PRBool aModification,
01850                                        PRBool aFireMutation,
01851                                        PRBool aNotify)
01852 {
01853   nsresult rv;
01854   PRUint8 modType = aModification ?
01855     NS_STATIC_CAST(PRUint8, nsIDOMMutationEvent::MODIFICATION) :
01856     NS_STATIC_CAST(PRUint8, nsIDOMMutationEvent::ADDITION);
01857 
01858   nsIDocument* document = GetCurrentDoc();
01859   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
01860   if (aNotify && document) {
01861     document->AttributeWillChange(this, aNamespaceID, aAttribute);
01862   }
01863 
01864   if (aNamespaceID == kNameSpaceID_None) {
01865     if (IsAttributeMapped(aAttribute)) {
01866       nsHTMLStyleSheet* sheet = document ?
01867         document->GetAttributeStyleSheet() : nsnull;
01868       rv = mAttrsAndChildren.SetAndTakeMappedAttr(aAttribute, aParsedValue,
01869                                                   this, sheet);
01870     }
01871     else {
01872       rv = mAttrsAndChildren.SetAndTakeAttr(aAttribute, aParsedValue);
01873     }
01874     NS_ENSURE_SUCCESS(rv, rv);
01875   }
01876   else {
01877     nsCOMPtr<nsINodeInfo> ni;
01878     rv = mNodeInfo->NodeInfoManager()->GetNodeInfo(aAttribute, aPrefix,
01879                                                    aNamespaceID,
01880                                                    getter_AddRefs(ni));
01881     NS_ENSURE_SUCCESS(rv, rv);
01882 
01883     rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue);
01884     NS_ENSURE_SUCCESS(rv, rv);
01885   }
01886 
01887   if (document) {
01888     nsXBLBinding *binding = document->BindingManager()->GetBinding(this);
01889     if (binding) {
01890       binding->AttributeChanged(aAttribute, aNamespaceID, PR_FALSE, aNotify);
01891     }
01892 
01893     if (aFireMutation) {
01894       nsCOMPtr<nsIDOMEventTarget> node =
01895         do_QueryInterface(NS_STATIC_CAST(nsIContent *, this));
01896       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED, node);
01897 
01898       nsAutoString attrName;
01899       aAttribute->ToString(attrName);
01900       nsCOMPtr<nsIDOMAttr> attrNode;
01901       GetAttributeNode(attrName, getter_AddRefs(attrNode));
01902       mutation.mRelatedNode = attrNode;
01903 
01904       mutation.mAttrName = aAttribute;
01905       nsAutoString newValue;
01906       GetAttr(aNamespaceID, aAttribute, newValue);
01907       if (!newValue.IsEmpty()) {
01908         mutation.mNewAttrValue = do_GetAtom(newValue);
01909       }
01910       if (!aOldValue.IsEmpty()) {
01911         mutation.mPrevAttrValue = do_GetAtom(aOldValue);
01912       }
01913       mutation.mAttrChange = modType;
01914       nsEventStatus status = nsEventStatus_eIgnore;
01915       HandleDOMEvent(nsnull, &mutation, nsnull,
01916                      NS_EVENT_FLAG_INIT, &status);
01917     }
01918 
01919     if (aNotify) {
01920       document->AttributeChanged(this, aNamespaceID, aAttribute, modType);
01921     }
01922   }
01923   
01924   if (aNotify && aNamespaceID == kNameSpaceID_None &&
01925       aAttribute == nsHTMLAtoms::spellcheck) {
01926     SyncEditorsOnSubtree(this);
01927   } else if (aNamespaceID == kNameSpaceID_XMLEvents && 
01928       aAttribute == nsHTMLAtoms::_event && mNodeInfo->GetDocument()) {
01929     mNodeInfo->GetDocument()->AddXMLEventsContent(this);
01930   }
01931 
01932   return NS_OK;
01933 }
01934 
01935 PRBool nsGenericHTMLElement::IsEventName(nsIAtom* aName)
01936 {
01937   const char* name;
01938   aName->GetUTF8String(&name);
01939 
01940   if (name[0] != 'o' || name[1] != 'n') {
01941     return PR_FALSE;
01942   }
01943 
01944   return (aName == nsLayoutAtoms::onclick                       ||
01945           aName == nsLayoutAtoms::ondblclick                    ||
01946           aName == nsLayoutAtoms::onmousedown                   ||
01947           aName == nsLayoutAtoms::onmouseup                     ||
01948           aName == nsLayoutAtoms::onmouseover                   ||
01949           aName == nsLayoutAtoms::onmouseout                    ||
01950           aName == nsLayoutAtoms::onkeydown                     ||
01951           aName == nsLayoutAtoms::onkeyup                       ||
01952           aName == nsLayoutAtoms::onkeypress                    ||
01953           aName == nsLayoutAtoms::onmousemove                   ||
01954           aName == nsLayoutAtoms::onload                        ||
01955           aName == nsLayoutAtoms::onunload                      ||
01956           aName == nsLayoutAtoms::onbeforeunload                ||
01957           aName == nsLayoutAtoms::onpageshow                    ||
01958           aName == nsLayoutAtoms::onpagehide                    ||
01959           aName == nsLayoutAtoms::onabort                       ||
01960           aName == nsLayoutAtoms::onerror                       ||
01961           aName == nsLayoutAtoms::onfocus                       ||
01962           aName == nsLayoutAtoms::onblur                        ||
01963           aName == nsLayoutAtoms::onsubmit                      ||
01964           aName == nsLayoutAtoms::onreset                       ||
01965           aName == nsLayoutAtoms::onchange                      ||
01966           aName == nsLayoutAtoms::onselect                      || 
01967           aName == nsLayoutAtoms::onpaint                       ||
01968           aName == nsLayoutAtoms::onresize                      ||
01969           aName == nsLayoutAtoms::onscroll                      ||
01970           aName == nsLayoutAtoms::oninput                       ||
01971           aName == nsLayoutAtoms::oncontextmenu                 ||
01972           aName == nsLayoutAtoms::onDOMAttrModified             ||
01973           aName == nsLayoutAtoms::onDOMCharacterDataModified    || 
01974           aName == nsLayoutAtoms::onDOMSubtreeModified          ||
01975           aName == nsLayoutAtoms::onDOMNodeInsertedIntoDocument || 
01976           aName == nsLayoutAtoms::onDOMNodeRemovedFromDocument  ||
01977           aName == nsLayoutAtoms::onDOMNodeInserted             || 
01978           aName == nsLayoutAtoms::onDOMNodeRemoved              ||
01979           aName == nsLayoutAtoms::onDOMActivate                 ||
01980           aName == nsLayoutAtoms::onDOMFocusIn                  ||
01981           aName == nsLayoutAtoms::onDOMFocusOut);
01982 }
01983 
01984 nsresult
01985 nsGenericHTMLElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
01986                                 PRBool aNotify)
01987 {
01988   // Check for event handlers
01989   if (aNameSpaceID == kNameSpaceID_None &&
01990       IsEventName(aAttribute)) {
01991     nsCOMPtr<nsIEventListenerManager> manager;
01992     GetListenerManager(getter_AddRefs(manager));
01993 
01994     if (manager) {
01995       manager->RemoveScriptEventListener(aAttribute);
01996     }
01997   }
01998 
01999   return nsGenericElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
02000 }
02001 
02002 nsresult
02003 nsGenericHTMLElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute,
02004                               nsAString& aResult) const
02005 {
02006   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
02007                "must have a real namespace ID!");
02008 
02009   aResult.Truncate();
02010 
02011   const nsAttrValue* attrValue =
02012     mAttrsAndChildren.GetAttr(aAttribute, aNameSpaceID);
02013   if (!attrValue) {
02014     return NS_CONTENT_ATTR_NOT_THERE;
02015   }
02016 
02017   attrValue->ToString(aResult);
02018 
02019   return NS_CONTENT_ATTR_HAS_VALUE;
02020 }
02021 
02022 const nsAttrValue*
02023 nsGenericHTMLElement::GetClasses() const
02024 {
02025   return mAttrsAndChildren.GetAttr(nsHTMLAtoms::kClass);
02026 }
02027 
02028 nsIAtom *
02029 nsGenericHTMLElement::GetIDAttributeName() const
02030 {
02031   return nsHTMLAtoms::id;
02032 }
02033 
02034 nsIAtom *
02035 nsGenericHTMLElement::GetClassAttributeName() const
02036 {
02037   return nsHTMLAtoms::kClass;
02038 }
02039 
02040 NS_IMETHODIMP_(PRBool)
02041 nsGenericHTMLElement::HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const
02042 {
02043   const nsAttrValue* val = mAttrsAndChildren.GetAttr(nsHTMLAtoms::kClass);
02044   if (val) {
02045     if (val->Type() == nsAttrValue::eAtom) {
02046       if (aCaseSensitive) {
02047         return aClass == val->GetAtomValue();
02048       }
02049 
02050       const char *class1, *class2;
02051       aClass->GetUTF8String(&class1);
02052       val->GetAtomValue()->GetUTF8String(&class2);
02053 
02054       return nsCRT::strcasecmp(class1, class2) == 0;
02055     }
02056     if (val->Type() == nsAttrValue::eAtomArray) {
02057       nsCOMArray<nsIAtom>* array = val->GetAtomArrayValue();
02058       if (aCaseSensitive) {
02059         return array->IndexOf(aClass) >= 0;
02060       }
02061 
02062       const char *class1, *class2;
02063       aClass->GetUTF8String(&class1);
02064 
02065       PRInt32 i, count = array->Count();
02066       for (i = 0; i < count; ++i) {
02067         array->ObjectAt(i)->GetUTF8String(&class2);
02068         if (nsCRT::strcasecmp(class1, class2) == 0) {
02069           return PR_TRUE;
02070         }
02071       }
02072     }
02073   }
02074 
02075   return PR_FALSE;
02076 }
02077 
02078 nsresult
02079 nsGenericHTMLElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
02080 {
02081   mAttrsAndChildren.WalkMappedAttributeStyleRules(aRuleWalker);
02082   return NS_OK;
02083 }
02084 
02085 nsICSSStyleRule*
02086 nsGenericHTMLElement::GetInlineStyleRule()
02087 { 
02088   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
02089   
02090   if (attrVal) {
02091     if (attrVal->Type() != nsAttrValue::eCSSStyleRule) {
02092       ReparseStyleAttribute();
02093       attrVal = mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
02094       // hopefully attrVal->Type() is now nsAttrValue::eCSSStyleRule
02095     }
02096 
02097     if (attrVal->Type() == nsAttrValue::eCSSStyleRule) {
02098       return attrVal->GetCSSStyleRuleValue();
02099     }
02100   }
02101 
02102   return nsnull;
02103 }
02104 
02105 nsresult
02106 nsGenericHTMLElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule,
02107                                          PRBool aNotify)
02108 {
02109   PRBool hasListeners = PR_FALSE;
02110   PRBool modification = PR_FALSE;
02111   nsAutoString oldValueStr;
02112 
02113   if (IsInDoc()) {
02114     hasListeners = nsGenericElement::HasMutationListeners(this,
02115       NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
02116 
02117     // There's no point in comparing the stylerule pointers since we're always
02118     // getting a new stylerule here. And we can't compare the stringvalues of
02119     // the old and the new rules since both will point to the same declaration
02120     // and thus will be the same.
02121     if (hasListeners) {
02122       // save the old attribute so we can set up the mutation event properly
02123       modification = GetAttr(kNameSpaceID_None, nsHTMLAtoms::style,
02124                              oldValueStr) != NS_CONTENT_ATTR_NOT_THERE;
02125     }
02126     else if (aNotify) {
02127       modification = !!mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
02128     }
02129   }
02130 
02131   nsAttrValue attrValue(aStyleRule);
02132 
02133   return SetAttrAndNotify(kNameSpaceID_None, nsHTMLAtoms::style, nsnull, oldValueStr,
02134                           attrValue, modification, hasListeners, aNotify);
02135 }
02136 
02137 already_AddRefed<nsIURI>
02138 nsGenericHTMLElement::GetBaseURI() const
02139 {
02140   nsIDocument* doc = GetOwnerDoc();
02141 
02142   const nsAttrValue* val = mAttrsAndChildren.GetAttr(nsHTMLAtoms::_baseHref);
02143   if (val) {
02144     // We have a _baseHref attribute; that will determine our base URI
02145     nsAutoString str;
02146     val->ToString(str);
02147 
02148     nsIURI* docBaseURL = nsnull;
02149     if (doc) {
02150       docBaseURL = doc->GetBaseURI();
02151     }
02152 
02153     nsIURI* uri = nsnull;
02154     NS_NewURI(&uri, str, nsnull, docBaseURL);
02155 
02156     return uri;
02157   }
02158 
02159   // If we are a plain old HTML element (not XHTML), don't bother asking the
02160   // base class -- our base URI is determined solely by the document base.
02161   if (mNodeInfo->NamespaceEquals(kNameSpaceID_None)) {
02162     if (doc) {
02163       nsIURI *uri = doc->GetBaseURI();
02164       NS_IF_ADDREF(uri);
02165 
02166       return uri;
02167     }
02168 
02169     return nsnull;
02170   }
02171 
02172   return nsGenericElement::GetBaseURI();
02173 }
02174 
02175 void
02176 nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
02177 {
02178   const nsAttrValue* val = mAttrsAndChildren.GetAttr(nsHTMLAtoms::_baseTarget);
02179   if (val) {
02180     val->ToString(aBaseTarget);
02181     return;
02182   }
02183 
02184   nsIDocument* ownerDoc = GetOwnerDoc();
02185   if (ownerDoc) {
02186     ownerDoc->GetBaseTarget(aBaseTarget);
02187   } else {
02188     aBaseTarget.Truncate();
02189   }
02190 }
02191 
02192 #ifdef DEBUG
02193 void
02194 nsGenericHTMLElement::ListAttributes(FILE* out) const
02195 {
02196   PRUint32 index, count = GetAttrCount();
02197 
02198   for (index = 0; index < count; index++) {
02199     // name
02200     nsCOMPtr<nsIAtom> attr;
02201     nsCOMPtr<nsIAtom> prefix;
02202     PRInt32 nameSpaceID;
02203     GetAttrNameAt(index, &nameSpaceID, getter_AddRefs(attr),
02204                   getter_AddRefs(prefix));
02205 
02206     nsAutoString buffer;
02207     attr->ToString(buffer);
02208 
02209     // value
02210     nsAutoString value;
02211     GetAttr(nameSpaceID, attr, value);
02212     buffer.AppendLiteral("=\"");
02213     for (int i = value.Length(); i >= 0; --i) {
02214       if (value[i] == PRUnichar('"'))
02215         value.Insert(PRUnichar('\\'), PRUint32(i));
02216     }
02217     buffer.Append(value);
02218     buffer.AppendLiteral("\"");
02219 
02220     fputs(" ", out);
02221     fputs(NS_LossyConvertUCS2toASCII(buffer).get(), out);
02222   }
02223 }
02224 
02225 void
02226 nsGenericHTMLElement::List(FILE* out, PRInt32 aIndent) const
02227 {
02228   NS_PRECONDITION(IsInDoc(), "bad content");
02229 
02230   PRInt32 index;
02231   for (index = aIndent; --index >= 0; ) fputs("  ", out);
02232 
02233   nsAutoString buf;
02234   mNodeInfo->GetQualifiedName(buf);
02235   fputs(NS_LossyConvertUCS2toASCII(buf).get(), out);
02236 
02237   fprintf(out, "@%p", (void*)this);
02238 
02239   ListAttributes(out);
02240 
02241   fprintf(out, " refcount=%d<", mRefCnt.get());
02242 
02243   fputs("\n", out);
02244   PRInt32 kids = GetChildCount();
02245   for (index = 0; index < kids; index++) {
02246     nsIContent *kid = GetChildAt(index);
02247     kid->List(out, aIndent + 1);
02248   }
02249   for (index = aIndent; --index >= 0; ) fputs("  ", out);
02250 
02251   fputs(">\n", out);
02252 }
02253 
02254 void
02255 nsGenericHTMLElement::DumpContent(FILE* out, PRInt32 aIndent,
02256                                   PRBool aDumpAll) const
02257 {
02258    NS_PRECONDITION(IsInDoc(), "bad content");
02259 
02260   PRInt32 index;
02261   for (index = aIndent; --index >= 0; ) fputs("  ", out);
02262 
02263   nsAutoString buf;
02264   mNodeInfo->GetQualifiedName(buf);
02265   fputs("<",out);
02266   fputs(NS_LossyConvertUCS2toASCII(buf).get(), out);
02267 
02268   if(aDumpAll) ListAttributes(out);
02269 
02270   fputs(">",out);
02271 
02272   if(aIndent) fputs("\n", out);
02273   PRInt32 kids = GetChildCount();
02274   for (index = 0; index < kids; index++) {
02275     nsIContent *kid = GetChildAt(index);
02276     PRInt32 indent = aIndent ? aIndent + 1 : 0;
02277     kid->DumpContent(out, indent, aDumpAll);
02278   }
02279   for (index = aIndent; --index >= 0; ) fputs("  ", out);
02280   fputs("</",out);
02281   fputs(NS_LossyConvertUCS2toASCII(buf).get(), out);
02282   fputs(">",out);
02283 
02284   if(aIndent) fputs("\n", out);
02285 }
02286 #endif
02287 
02288 
02289 PRBool
02290 nsGenericHTMLElement::IsContentOfType(PRUint32 aFlags) const
02291 {
02292   return !(aFlags & ~(eELEMENT | eHTML));
02293 }
02294 
02295 //----------------------------------------------------------------------
02296 
02297 
02298 PRBool
02299 nsGenericHTMLElement::ParseAttribute(nsIAtom* aAttribute,
02300                                      const nsAString& aValue,
02301                                      nsAttrValue& aResult)
02302 {
02303   if (aAttribute == nsHTMLAtoms::dir) {
02304     return aResult.ParseEnumValue(aValue, kDirTable);
02305   }
02306   if (aAttribute == nsHTMLAtoms::style) {
02307     ParseStyleAttribute(this, mNodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
02308                         aValue, aResult);
02309     return PR_TRUE;
02310   }
02311   if (aAttribute == nsHTMLAtoms::id && !aValue.IsEmpty()) {
02312     aResult.ParseAtom(aValue);
02313 
02314     return PR_TRUE;
02315   }
02316   if (aAttribute == nsHTMLAtoms::kClass) {
02317     aResult.ParseAtomArray(aValue);
02318 
02319     return PR_TRUE;
02320   }
02321 
02322   if (aAttribute == nsHTMLAtoms::tabindex) {
02323     return aResult.ParseIntWithBounds(aValue, -32768, 32767);
02324   }
02325 
02326   return PR_FALSE;
02327 }
02328 
02329 PRBool
02330 nsGenericHTMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
02331 {
02332   static const MappedAttributeEntry* const map[] = {
02333     sCommonAttributeMap
02334   };
02335   
02336   return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map));
02337 }
02338 
02339 nsMapRuleToAttributesFunc
02340 nsGenericHTMLElement::GetAttributeMappingFunction() const
02341 {
02342   return &MapCommonAttributesInto;
02343 }
02344 
02345 // static
02346 nsIFrame *
02347 nsGenericHTMLElement::GetPrimaryFrameFor(nsIContent* aContent,
02348                                          nsIDocument* aDocument,
02349                                          PRBool aFlushContent)
02350 {
02351   if (aFlushContent) {
02352     // Cause a flush of content, so we get up-to-date frame
02353     // information
02354     aDocument->FlushPendingNotifications(Flush_Frames);
02355   }
02356 
02357   // Get presentation shell 0
02358   nsIPresShell *presShell = aDocument->GetShellAt(0);
02359 
02360   nsIFrame *frame = nsnull;
02361 
02362   if (presShell) {
02363     presShell->GetPrimaryFrameFor(aContent, &frame);
02364   }
02365 
02366   return frame;
02367 }
02368 
02369 // static
02370 nsIFormControlFrame*
02371 nsGenericHTMLElement::GetFormControlFrameFor(nsIContent* aContent,
02372                                              nsIDocument* aDocument,
02373                                              PRBool aFlushContent)
02374 {
02375   nsIFrame* frame = GetPrimaryFrameFor(aContent, aDocument, aFlushContent);
02376   if (frame) {
02377     nsIFormControlFrame* form_frame = nsnull;
02378     CallQueryInterface(frame, &form_frame);
02379     if (form_frame) {
02380       return form_frame;
02381     }
02382 
02383     // If we have generated content, the primary frame will be a
02384     // wrapper frame..  out real frame will be in its child list.
02385     for (frame = frame->GetFirstChild(nsnull);
02386          frame;
02387          frame = frame->GetNextSibling()) {
02388       CallQueryInterface(frame, &form_frame);
02389       if (form_frame) {
02390         return form_frame;
02391       }
02392     }
02393         
02394     NS_ERROR("Form control has a frame, but it's not a form frame");
02395   }
02396 
02397   return nsnull;
02398 }
02399 
02400 /* static */ nsresult
02401 nsGenericHTMLElement::GetPrimaryPresState(nsGenericHTMLElement* aContent,
02402                                           nsPresState** aPresState)
02403 {
02404   NS_ENSURE_ARG_POINTER(aPresState);
02405   *aPresState = nsnull;
02406 
02407   nsresult result = NS_OK;
02408 
02409   nsCOMPtr<nsILayoutHistoryState> history;
02410   nsCAutoString key;
02411   GetLayoutHistoryAndKey(aContent, getter_AddRefs(history), key);
02412 
02413   if (history) {
02414     // Get the pres state for this key, if it doesn't exist, create one
02415     result = history->GetState(key, aPresState);
02416     if (!*aPresState) {
02417       result = NS_NewPresState(aPresState);
02418       if (NS_SUCCEEDED(result)) {
02419         result = history->AddState(key, *aPresState);
02420       }
02421     }
02422   }
02423 
02424   return result;
02425 }
02426 
02427 
02428 nsresult
02429 nsGenericHTMLElement::GetLayoutHistoryAndKey(nsGenericHTMLElement* aContent,
02430                                              nsILayoutHistoryState** aHistory,
02431                                              nsACString& aKey)
02432 {
02433   //
02434   // Get the pres shell
02435   //
02436   nsCOMPtr<nsIDocument> doc = aContent->GetDocument();
02437   if (!doc) {
02438     return NS_OK;
02439   }
02440 
02441   //
02442   // Get the history (don't bother with the key if the history is not there)
02443   //
02444   *aHistory = doc->GetLayoutHistoryState().get();
02445   if (!*aHistory) {
02446     return NS_OK;
02447   }
02448 
02449   //
02450   // Get the state key
02451   //
02452   nsresult rv = nsContentUtils::GenerateStateKey(aContent, doc,
02453                                                  nsIStatefulFrame::eNoID,
02454                                                  aKey);
02455   if (NS_FAILED(rv)) {
02456     NS_RELEASE(*aHistory);
02457     return rv;
02458   }
02459 
02460   // If the state key is blank, this is anonymous content or for
02461   // whatever reason we are not supposed to save/restore state.
02462   if (aKey.IsEmpty()) {
02463     NS_RELEASE(*aHistory);
02464     return NS_OK;
02465   }
02466 
02467   // Add something unique to content so layout doesn't muck us up
02468   aKey += "-C";
02469 
02470   return rv;
02471 }
02472 
02473 PRBool
02474 nsGenericHTMLElement::RestoreFormControlState(nsGenericHTMLElement* aContent,
02475                                               nsIFormControl* aControl)
02476 {
02477   nsCOMPtr<nsILayoutHistoryState> history;
02478   nsCAutoString key;
02479   nsresult rv = GetLayoutHistoryAndKey(aContent, getter_AddRefs(history), key);
02480   if (!history) {
02481     return PR_FALSE;
02482   }
02483 
02484   nsPresState *state;
02485   // Get the pres state for this key
02486   rv = history->GetState(key, &state);
02487   if (state) {
02488     PRBool result = aControl->RestoreState(state);
02489     history->RemoveState(key);
02490     return result;
02491   }
02492 
02493   return PR_FALSE;
02494 }
02495 
02496 // XXX This creates a dependency between content and frames
02497 nsPresContext*
02498 nsGenericHTMLElement::GetPresContext()
02499 {
02500   // Get the document
02501   nsIDocument* doc = GetDocument();
02502   if (doc) {
02503     // Get presentation shell 0
02504     nsIPresShell *presShell = doc->GetShellAt(0);
02505     if (presShell) {
02506       return presShell->GetPresContext();
02507     }
02508   }
02509 
02510   return nsnull;
02511 }
02512 
02513 static const nsAttrValue::EnumTable kAlignTable[] = {
02514   { "left",      NS_STYLE_TEXT_ALIGN_LEFT },
02515   { "right",     NS_STYLE_TEXT_ALIGN_RIGHT },
02516 
02517   { "top",       NS_STYLE_VERTICAL_ALIGN_TOP },
02518   { "middle",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
02519   { "bottom",    NS_STYLE_VERTICAL_ALIGN_BASELINE },
02520 
02521   { "center",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
02522   { "baseline",  NS_STYLE_VERTICAL_ALIGN_BASELINE },
02523 
02524   { "texttop",   NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
02525   { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
02526   { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
02527   { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
02528   { 0 }
02529 };
02530 
02531 static const nsAttrValue::EnumTable kDivAlignTable[] = {
02532   { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
02533   { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
02534   { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
02535   { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
02536   { "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY },
02537   { 0 }
02538 };
02539 
02540 static const nsAttrValue::EnumTable kFrameborderTable[] = {
02541   { "yes", NS_STYLE_FRAME_YES },
02542   { "no", NS_STYLE_FRAME_NO },
02543   { "1", NS_STYLE_FRAME_1 },
02544   { "0", NS_STYLE_FRAME_0 },
02545   { 0 }
02546 };
02547 
02548 static const nsAttrValue::EnumTable kScrollingTable[] = {
02549   { "yes", NS_STYLE_FRAME_YES },
02550   { "no", NS_STYLE_FRAME_NO },
02551   { "on", NS_STYLE_FRAME_ON },
02552   { "off", NS_STYLE_FRAME_OFF },
02553   { "scroll", NS_STYLE_FRAME_SCROLL },
02554   { "noscroll", NS_STYLE_FRAME_NOSCROLL },
02555   { "auto", NS_STYLE_FRAME_AUTO },
02556   { 0 }
02557 };
02558 
02559 static const nsAttrValue::EnumTable kTableVAlignTable[] = {
02560   { "top",     NS_STYLE_VERTICAL_ALIGN_TOP },
02561   { "middle",  NS_STYLE_VERTICAL_ALIGN_MIDDLE },
02562   { "bottom",  NS_STYLE_VERTICAL_ALIGN_BOTTOM },
02563   { "baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE },
02564   { 0 }
02565 };
02566 
02567 PRBool
02568 nsGenericHTMLElement::ParseAlignValue(const nsAString& aString,
02569                                       nsAttrValue& aResult)
02570 {
02571   return aResult.ParseEnumValue(aString, kAlignTable);
02572 }
02573 
02574 //----------------------------------------
02575 
02576 // Vanilla table as defined by the html4 spec...
02577 static const nsAttrValue::EnumTable kTableHAlignTable[] = {
02578   { "left",   NS_STYLE_TEXT_ALIGN_LEFT },
02579   { "right",  NS_STYLE_TEXT_ALIGN_RIGHT },
02580   { "center", NS_STYLE_TEXT_ALIGN_CENTER },
02581   { "char",   NS_STYLE_TEXT_ALIGN_CHAR },
02582   { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
02583   { 0 }
02584 };
02585 
02586 // This table is used for TABLE when in compatability mode
02587 static const nsAttrValue::EnumTable kCompatTableHAlignTable[] = {
02588   { "left",   NS_STYLE_TEXT_ALIGN_LEFT },
02589   { "right",  NS_STYLE_TEXT_ALIGN_RIGHT },
02590   { "center", NS_STYLE_TEXT_ALIGN_CENTER },
02591   { "char",   NS_STYLE_TEXT_ALIGN_CHAR },
02592   { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
02593   { "abscenter", NS_STYLE_TEXT_ALIGN_CENTER },
02594   { "absmiddle", NS_STYLE_TEXT_ALIGN_CENTER },
02595   { "middle", NS_STYLE_TEXT_ALIGN_CENTER },
02596   { 0 }
02597 };
02598 
02599 PRBool
02600 nsGenericHTMLElement::ParseTableHAlignValue(const nsAString& aString,
02601                                             nsAttrValue& aResult) const
02602 {
02603   if (InNavQuirksMode(GetOwnerDoc())) {
02604     return aResult.ParseEnumValue(aString, kCompatTableHAlignTable);
02605   }
02606   return aResult.ParseEnumValue(aString, kTableHAlignTable);
02607 }
02608 
02609 //----------------------------------------
02610 
02611 // These tables are used for TD,TH,TR, etc (but not TABLE)
02612 static const nsAttrValue::EnumTable kTableCellHAlignTable[] = {
02613   { "left",   NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
02614   { "right",  NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
02615   { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
02616   { "char",   NS_STYLE_TEXT_ALIGN_CHAR },
02617   { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
02618   { 0 }
02619 };
02620 
02621 static const nsAttrValue::EnumTable kCompatTableCellHAlignTable[] = {
02622   { "left",   NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
02623   { "right",  NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
02624   { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
02625   { "char",   NS_STYLE_TEXT_ALIGN_CHAR },
02626   { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
02627 
02628   // The following are non-standard but necessary for Nav4 compatibility
02629   { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
02630   // allow center and absmiddle to map to NS_STYLE_TEXT_ALIGN_CENTER and
02631   // NS_STYLE_TEXT_ALIGN_CENTER to map to center by using the following order
02632   { "center", NS_STYLE_TEXT_ALIGN_CENTER },
02633   { "absmiddle", NS_STYLE_TEXT_ALIGN_CENTER },
02634   { 0 }
02635 };
02636 
02637 PRBool
02638 nsGenericHTMLElement::ParseTableCellHAlignValue(const nsAString& aString,
02639                                                 nsAttrValue& aResult) const
02640 {
02641   if (InNavQuirksMode(GetOwnerDoc())) {
02642     return aResult.ParseEnumValue(aString, kCompatTableCellHAlignTable);
02643   }
02644   return aResult.ParseEnumValue(aString, kTableCellHAlignTable);
02645 }
02646 
02647 //----------------------------------------
02648 
02649 PRBool
02650 nsGenericHTMLElement::ParseTableVAlignValue(const nsAString& aString,
02651                                             nsAttrValue& aResult)
02652 {
02653   return aResult.ParseEnumValue(aString, kTableVAlignTable);
02654 }
02655 
02656 PRBool
02657 nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString,
02658                                          nsAttrValue& aResult) const
02659 {
02660   return aResult.ParseEnumValue(aString, kDivAlignTable);
02661 }
02662 
02663 PRBool
02664 nsGenericHTMLElement::ParseImageAttribute(nsIAtom* aAttribute,
02665                                           const nsAString& aString,
02666                                           nsAttrValue& aResult)
02667 {
02668   if ((aAttribute == nsHTMLAtoms::width) ||
02669       (aAttribute == nsHTMLAtoms::height)) {
02670     return aResult.ParseSpecialIntValue(aString, PR_TRUE, PR_FALSE);
02671   }
02672   else if ((aAttribute == nsHTMLAtoms::hspace) ||
02673            (aAttribute == nsHTMLAtoms::vspace) ||
02674            (aAttribute == nsHTMLAtoms::border)) {
02675     return aResult.ParseIntWithBounds(aString, 0);
02676   }
02677   return PR_FALSE;
02678 }
02679 
02680 PRBool
02681 nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
02682                                             nsAttrValue& aResult)
02683 {
02684   return aResult.ParseEnumValue(aString, kFrameborderTable);
02685 }
02686 
02687 PRBool
02688 nsGenericHTMLElement::ParseScrollingValue(const nsAString& aString,
02689                                           nsAttrValue& aResult)
02690 {
02691   return aResult.ParseEnumValue(aString, kScrollingTable);
02692 }
02693 
02694 nsresult
02695 nsGenericHTMLElement::ReparseStyleAttribute()
02696 {
02697   const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsHTMLAtoms::style);
02698   
02699   if (oldVal && oldVal->Type() != nsAttrValue::eCSSStyleRule) {
02700     nsAttrValue attrValue;
02701     nsAutoString stringValue;
02702     oldVal->ToString(stringValue);
02703     ParseStyleAttribute(this, mNodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
02704                         stringValue, attrValue);
02705     // Don't bother going through SetInlineStyleRule, we don't want to fire off
02706     // mutation events or document notifications anyway
02707     nsresult rv = mAttrsAndChildren.SetAndTakeAttr(nsHTMLAtoms::style, attrValue);
02708     NS_ENSURE_SUCCESS(rv, rv);
02709   }
02710   
02711   return NS_OK;
02712 }
02713 
02714 void
02715 nsGenericHTMLElement::ParseStyleAttribute(nsIContent* aContent,
02716                                           PRBool aCaseSensitive,
02717                                           const nsAString& aValue,
02718                                           nsAttrValue& aResult)
02719 {
02720   nsresult result = NS_OK;
02721   NS_ASSERTION(aContent->GetNodeInfo(), "If we don't have a nodeinfo, we are very screwed");
02722 
02723   nsIDocument* doc = aContent->GetOwnerDoc();
02724 
02725   if (doc) {
02726     PRBool isCSS = PR_TRUE; // assume CSS until proven otherwise
02727 
02728     if (!aContent->IsNativeAnonymous()) {  // native anonymous content
02729                                            // always assumes CSS
02730       nsAutoString styleType;
02731       doc->GetHeaderData(nsHTMLAtoms::headerContentStyleType, styleType);
02732       if (!styleType.IsEmpty()) {
02733         static const char textCssStr[] = "text/css";
02734         isCSS = (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1));
02735       }
02736     }
02737 
02738     if (isCSS) {
02739       nsICSSLoader* cssLoader = doc->CSSLoader();
02740       nsCOMPtr<nsICSSParser> cssParser;
02741       result = cssLoader->GetParserFor(nsnull, getter_AddRefs(cssParser));
02742       if (cssParser) {
02743         nsCOMPtr<nsIURI> baseURI = aContent->GetBaseURI();
02744 
02745         nsCOMPtr<nsICSSStyleRule> rule;
02746         result = cssParser->ParseStyleAttribute(aValue, doc->GetDocumentURI(),
02747                                                 baseURI,
02748                                                 getter_AddRefs(rule));
02749         cssLoader->RecycleParser(cssParser);
02750 
02751         if (rule) {
02752           aResult.SetTo(rule);
02753 
02754           return;
02755         }
02756       }
02757     }
02758   }
02759 
02760   aResult.SetTo(aValue);
02761 }
02762 
02766 void
02767 nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
02768                                               nsRuleData* aData)
02769 {
02770   if (aData->mSID == eStyleStruct_Visibility) {
02771     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::lang);
02772     if (value && value->Type() == nsAttrValue::eString) {
02773       aData->mDisplayData->mLang.SetStringValue(value->GetStringValue(),
02774                                                 eCSSUnit_String);
02775     }
02776   }
02777 }
02778 
02779 
02780 
02781 /* static */ const nsGenericHTMLElement::MappedAttributeEntry
02782 nsGenericHTMLElement::sCommonAttributeMap[] = {
02783   { &nsHTMLAtoms::lang },
02784   { nsnull }
02785 };
02786 
02787 /* static */ const nsGenericElement::MappedAttributeEntry
02788 nsGenericHTMLElement::sImageMarginSizeAttributeMap[] = {
02789   { &nsHTMLAtoms::width },
02790   { &nsHTMLAtoms::height },
02791   { &nsHTMLAtoms::hspace },
02792   { &nsHTMLAtoms::vspace },
02793   { nsnull }
02794 };
02795 
02796 /* static */ const nsGenericElement::MappedAttributeEntry
02797 nsGenericHTMLElement::sImageAlignAttributeMap[] = {
02798   { &nsHTMLAtoms::align },
02799   { nsnull }
02800 };
02801 
02802 /* static */ const nsGenericElement::MappedAttributeEntry
02803 nsGenericHTMLElement::sDivAlignAttributeMap[] = {
02804   { &nsHTMLAtoms::align },
02805   { nsnull }
02806 };
02807 
02808 /* static */ const nsGenericElement::MappedAttributeEntry
02809 nsGenericHTMLElement::sImageBorderAttributeMap[] = {
02810   { &nsHTMLAtoms::border },
02811   { nsnull }
02812 };
02813 
02814 /* static */ const nsGenericElement::MappedAttributeEntry
02815 nsGenericHTMLElement::sBackgroundAttributeMap[] = {
02816   { &nsHTMLAtoms::background },
02817   { &nsHTMLAtoms::bgcolor },
02818   { nsnull }
02819 };
02820 
02821 /* static */ const nsGenericElement::MappedAttributeEntry
02822 nsGenericHTMLElement::sScrollingAttributeMap[] = {
02823   { &nsHTMLAtoms::scrolling },
02824   { nsnull }
02825 };
02826 
02827 void
02828 nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
02829                                                  nsRuleData* aRuleData)
02830 {
02831   if (aRuleData->mSID == eStyleStruct_Display || aRuleData->mSID == eStyleStruct_TextReset) {
02832     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::align);
02833     if (value && value->Type() == nsAttrValue::eEnum) {
02834       PRInt32 align = value->GetEnumValue();
02835       if (aRuleData->mSID == eStyleStruct_Display && aRuleData->mDisplayData->mFloat.GetUnit() == eCSSUnit_Null) {
02836         if (align == NS_STYLE_TEXT_ALIGN_LEFT)
02837           aRuleData->mDisplayData->mFloat.SetIntValue(NS_STYLE_FLOAT_LEFT, eCSSUnit_Enumerated);
02838         else if (align == NS_STYLE_TEXT_ALIGN_RIGHT)
02839           aRuleData->mDisplayData->mFloat.SetIntValue(NS_STYLE_FLOAT_RIGHT, eCSSUnit_Enumerated);
02840       }
02841       else if (aRuleData->mSID == eStyleStruct_TextReset && aRuleData->mTextData->mVerticalAlign.GetUnit() == eCSSUnit_Null) {
02842         switch (align) {
02843         case NS_STYLE_TEXT_ALIGN_LEFT:
02844         case NS_STYLE_TEXT_ALIGN_RIGHT:
02845           break;
02846         default:
02847           aRuleData->mTextData->mVerticalAlign.SetIntValue(align, eCSSUnit_Enumerated);
02848           break;
02849         }
02850       }
02851     }
02852   }
02853 }
02854 
02855 void
02856 nsGenericHTMLElement::MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
02857                                                nsRuleData* aRuleData)
02858 {
02859   if (aRuleData->mSID == eStyleStruct_Text) {
02860     if (aRuleData->mTextData->mTextAlign.GetUnit() == eCSSUnit_Null) {
02861       // align: enum
02862       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::align);
02863       if (value && value->Type() == nsAttrValue::eEnum)
02864         aRuleData->mTextData->mTextAlign.SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
02865     }
02866   }
02867 }
02868 
02869 
02870 void
02871 nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
02872                                                   nsRuleData* aData)
02873 {
02874   if (aData->mSID != eStyleStruct_Margin)
02875     return;
02876 
02877   const nsAttrValue* value;
02878 
02879   // hspace: value
02880   value = aAttributes->GetAttr(nsHTMLAtoms::hspace);
02881   if (value) {
02882     nsCSSValue hval;
02883     if (value->Type() == nsAttrValue::eInteger)
02884       hval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
02885     else if (value->Type() == nsAttrValue::ePercent)
02886       hval.SetPercentValue(value->GetPercentValue());
02887 
02888     if (hval.GetUnit() != eCSSUnit_Null) {
02889       nsCSSRect& margin = aData->mMarginData->mMargin;
02890       if (margin.mLeft.GetUnit() == eCSSUnit_Null)
02891         margin.mLeft = hval;
02892       if (margin.mRight.GetUnit() == eCSSUnit_Null)
02893         margin.mRight = hval;
02894     }
02895   }
02896 
02897   // vspace: value
02898   value = aAttributes->GetAttr(nsHTMLAtoms::vspace);
02899   if (value) {
02900     nsCSSValue vval;
02901     if (value->Type() == nsAttrValue::eInteger)
02902       vval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
02903     else if (value->Type() == nsAttrValue::ePercent)
02904       vval.SetPercentValue(value->GetPercentValue());
02905   
02906     if (vval.GetUnit() != eCSSUnit_Null) {
02907       nsCSSRect& margin = aData->mMarginData->mMargin;
02908       if (margin.mTop.GetUnit() == eCSSUnit_Null)
02909         margin.mTop = vval;
02910       if (margin.mBottom.GetUnit() == eCSSUnit_Null)
02911         margin.mBottom = vval;
02912     }
02913   }
02914 }
02915 
02916 void
02917 nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
02918                                                  nsRuleData* aData)
02919 {
02920   if (aData->mSID != eStyleStruct_Position)
02921     return;
02922 
02923   // width: value
02924   if (aData->mPositionData->mWidth.GetUnit() == eCSSUnit_Null) {
02925     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::width);
02926     if (value && value->Type() == nsAttrValue::eInteger)
02927       aData->mPositionData->mWidth.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
02928     else if (value && value->Type() == nsAttrValue::ePercent)
02929       aData->mPositionData->mWidth.SetPercentValue(value->GetPercentValue());
02930   }
02931 
02932   // height: value
02933   if (aData->mPositionData->mHeight.GetUnit() == eCSSUnit_Null) {
02934     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::height);
02935     if (value && value->Type() == nsAttrValue::eInteger)
02936       aData->mPositionData->mHeight.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel); 
02937     else if (value && value->Type() == nsAttrValue::ePercent)
02938       aData->mPositionData->mHeight.SetPercentValue(value->GetPercentValue());    
02939   }
02940 }
02941 
02942 void
02943 nsGenericHTMLElement::MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
02944                                                   nsRuleData* aData)
02945 {
02946   if (aData->mSID != eStyleStruct_Border)
02947     return;
02948 
02949   // border: pixels
02950   const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::border);
02951   if (!value)
02952     return;
02953   
02954   nscoord val = 0;
02955   if (value->Type() == nsAttrValue::eInteger)
02956     val = value->GetIntegerValue();
02957 
02958   nsCSSRect& borderWidth = aData->mMarginData->mBorderWidth;
02959   if (borderWidth.mLeft.GetUnit() == eCSSUnit_Null)
02960     borderWidth.mLeft.SetFloatValue((float)val, eCSSUnit_Pixel);
02961   if (borderWidth.mTop.GetUnit() == eCSSUnit_Null)
02962     borderWidth.mTop.SetFloatValue((float)val, eCSSUnit_Pixel);
02963   if (borderWidth.mRight.GetUnit() == eCSSUnit_Null)
02964     borderWidth.mRight.SetFloatValue((float)val, eCSSUnit_Pixel);
02965   if (borderWidth.mBottom.GetUnit() == eCSSUnit_Null)
02966     borderWidth.mBottom.SetFloatValue((float)val, eCSSUnit_Pixel);
02967 
02968   nsCSSRect& borderStyle = aData->mMarginData->mBorderStyle;
02969   if (borderStyle.mLeft.GetUnit() == eCSSUnit_Null)
02970     borderStyle.mLeft.SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
02971   if (borderStyle.mTop.GetUnit() == eCSSUnit_Null)
02972     borderStyle.mTop.SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
02973   if (borderStyle.mRight.GetUnit() == eCSSUnit_Null)
02974     borderStyle.mRight.SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
02975   if (borderStyle.mBottom.GetUnit() == eCSSUnit_Null)
02976     borderStyle.mBottom.SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
02977 
02978   nsCSSRect& borderColor = aData->mMarginData->mBorderColor;
02979   if (borderColor.mLeft.GetUnit() == eCSSUnit_Null)
02980     borderColor.mLeft.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
02981   if (borderColor.mTop.GetUnit() == eCSSUnit_Null)
02982     borderColor.mTop.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
02983   if (borderColor.mRight.GetUnit() == eCSSUnit_Null)
02984     borderColor.mRight.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
02985   if (borderColor.mBottom.GetUnit() == eCSSUnit_Null)
02986     borderColor.mBottom.SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
02987 }
02988 
02989 void
02990 nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
02991                                                   nsRuleData* aData)
02992 {
02993   if (aData->mSID != eStyleStruct_Background)
02994     return;
02995 
02996   if (aData->mColorData->mBackImage.GetUnit() == eCSSUnit_Null) {
02997     // background
02998     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::background);
02999     if (value && value->Type() == nsAttrValue::eString) {
03000       nsAutoString spec(value->GetStringValue());
03001       if (!spec.IsEmpty()) {
03002         // Resolve url to an absolute url
03003         // XXX this breaks if the HTML element has an xml:base
03004         // attribute (the xml:base will not be taken into account)
03005         // as well as elements with _baseHref set. We need to be able
03006         // to get to the element somehow, or store the base URI in the
03007         // attributes.
03008         nsIDocument* doc = aData->mPresContext->GetDocument();
03009         nsCOMPtr<nsIURI> uri;
03010         nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
03011             getter_AddRefs(uri), spec, doc, doc->GetBaseURI());
03012         if (NS_SUCCEEDED(rv)) {
03013           nsCSSValue::Image *img =
03014             new nsCSSValue::Image(uri, spec.get(), doc->GetDocumentURI(),
03015                                   doc, PR_TRUE);
03016           if (img) {
03017             if (img->mString) {
03018               aData->mColorData->mBackImage.SetImageValue(img);
03019             }
03020             else
03021               delete img;
03022           }
03023         }
03024       }
03025       else if (aData->mPresContext->CompatibilityMode() ==
03026                eCompatibility_NavQuirks) {
03027         // in NavQuirks mode, allow the empty string to set the
03028         // background to empty
03029         aData->mColorData->mBackImage.SetNoneValue();
03030       }
03031     }
03032   }
03033 
03034   // bgcolor
03035   if (aData->mColorData->mBackColor.GetUnit() == eCSSUnit_Null) {
03036     const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::bgcolor);
03037     nscolor color;
03038     if (value && value->GetColorValue(color)) {
03039       aData->mColorData->mBackColor.SetColorValue(color);
03040     }
03041   }
03042 }
03043 
03044 void
03045 nsGenericHTMLElement::MapScrollingAttributeInto(const nsMappedAttributes* aAttributes,
03046                                                 nsRuleData* aData)
03047 {
03048   if (aData->mSID != eStyleStruct_Display)
03049     return;
03050 
03051   // scrolling
03052   nsCSSValue* overflowValues[2] = {
03053     &aData->mDisplayData->mOverflowX,
03054     &aData->mDisplayData->mOverflowY,
03055   };
03056   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(overflowValues); ++i) {
03057     if (overflowValues[i]->GetUnit() == eCSSUnit_Null) {
03058       const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::scrolling);
03059       if (value && value->Type() == nsAttrValue::eEnum) {
03060         PRInt32 mappedValue;
03061         switch (value->GetEnumValue()) {
03062           case NS_STYLE_FRAME_ON:
03063           case NS_STYLE_FRAME_SCROLL:
03064           case NS_STYLE_FRAME_YES:
03065             mappedValue = NS_STYLE_OVERFLOW_SCROLL;
03066             break;
03067 
03068           case NS_STYLE_FRAME_OFF:
03069           case NS_STYLE_FRAME_NOSCROLL:
03070           case NS_STYLE_FRAME_NO:
03071             mappedValue = NS_STYLE_OVERFLOW_HIDDEN;
03072             break;
03073         
03074           case NS_STYLE_FRAME_AUTO:
03075             mappedValue = NS_STYLE_OVERFLOW_AUTO;
03076             break;
03077 
03078           default:
03079             NS_NOTREACHED("unexpected value");
03080             mappedValue = NS_STYLE_OVERFLOW_AUTO;
03081             break;
03082         }
03083         overflowValues[i]->SetIntValue(mappedValue, eCSSUnit_Enumerated);
03084       }
03085     }
03086   }
03087 }
03088 
03089 //----------------------------------------------------------------------
03090 
03091 nsresult
03092 nsGenericHTMLElement::ReplaceContentsWithText(const nsAString& aText,
03093                                               PRBool aNotify)
03094 {
03095   PRUint32 count = GetChildCount();
03096   nsresult rv = NS_OK;
03097 
03098   nsCOMPtr<nsIDOMText> textChild;
03099 
03100   if (count > 0) {
03101     // if we already have a DOMText child, reuse it.
03102     textChild = do_QueryInterface(GetChildAt(0));
03103 
03104     PRUint32 lastChild = textChild ? 1 : 0;
03105     PRUint32 i = count - 1;
03106     while (i-- > lastChild) {
03107       RemoveChildAt(i, aNotify);
03108     }
03109   }
03110 
03111   if (textChild) {
03112     rv = textChild->SetData(aText);
03113   } else {
03114     nsCOMPtr<nsITextContent> text;
03115     rv = NS_NewTextNode(getter_AddRefs(text), mNodeInfo->NodeInfoManager());
03116     NS_ENSURE_SUCCESS(rv, rv);
03117 
03118     text->SetText(aText, PR_TRUE);
03119 
03120     rv = InsertChildAt(text, 0, aNotify);
03121   }    
03122       
03123   return rv;
03124 }
03125 
03126 nsresult
03127 nsGenericHTMLElement::GetAttrHelper(nsIAtom* aAttr, nsAString& aValue)
03128 {
03129   GetAttr(kNameSpaceID_None, aAttr, aValue);
03130   return NS_OK;
03131 }
03132 
03133 nsresult
03134 nsGenericHTMLElement::SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue)
03135 {
03136   return SetAttr(kNameSpaceID_None, aAttr, aValue, PR_TRUE);
03137 }
03138 
03139 nsresult
03140 nsGenericHTMLElement::GetStringAttrWithDefault(nsIAtom* aAttr,
03141                                                const char* aDefault,
03142                                                nsAString& aResult)
03143 {
03144   nsresult rv = GetAttr(kNameSpaceID_None, aAttr, aResult);
03145   if (rv == NS_CONTENT_ATTR_NOT_THERE) {
03146     CopyASCIItoUTF16(aDefault, aResult);
03147   }
03148   return NS_OK;
03149 }
03150 
03151 nsresult
03152 nsGenericHTMLElement::SetBoolAttr(nsIAtom* aAttr, PRBool aValue)
03153 {
03154   if (aValue) {
03155     return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), PR_TRUE);
03156   }
03157 
03158   return UnsetAttr(kNameSpaceID_None, aAttr, PR_TRUE);
03159 }
03160 
03161 nsresult
03162 nsGenericHTMLElement::GetBoolAttr(nsIAtom* aAttr, PRBool* aValue) const
03163 {
03164   *aValue = HasAttr(kNameSpaceID_None, aAttr);
03165   return NS_OK;
03166 }
03167 
03168 nsresult
03169 nsGenericHTMLElement::GetIntAttr(nsIAtom* aAttr, PRInt32 aDefault, PRInt32* aResult)
03170 {
03171   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
03172   if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
03173     *aResult = attrVal->GetIntegerValue();
03174   }
03175   else {
03176     *aResult = aDefault;
03177   }
03178   return NS_OK;
03179 }
03180 
03181 nsresult
03182 nsGenericHTMLElement::SetIntAttr(nsIAtom* aAttr, PRInt32 aValue)
03183 {
03184   nsAutoString value;
03185   value.AppendInt(aValue);
03186 
03187   return SetAttr(kNameSpaceID_None, aAttr, value, PR_TRUE);
03188 }
03189 
03190 nsresult
03191 nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsAString& aResult)
03192 {
03193   nsAutoString attrValue;
03194   nsresult rv = GetAttr(kNameSpaceID_None, aAttr, attrValue);
03195   if (rv != NS_CONTENT_ATTR_HAS_VALUE) {
03196     aResult.Truncate();
03197 
03198     return NS_OK;
03199   }
03200 
03201   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
03202   nsCOMPtr<nsIURI> attrURI;
03203   rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(attrURI),
03204                                                  attrValue, GetOwnerDoc(),
03205                                                  baseURI);
03206   if (NS_FAILED(rv)) {
03207     // Just use the attr value as the result...
03208     aResult = attrValue;
03209 
03210     return NS_OK;
03211   }
03212 
03213   NS_ASSERTION(attrURI,
03214                "nsContentUtils::NewURIWithDocumentCharset return value lied");
03215 
03216   nsCAutoString spec;
03217   attrURI->GetSpec(spec);
03218   CopyUTF8toUTF16(spec, aResult);
03219   return NS_OK;
03220 }
03221 
03222 //----------------------------------------------------------------------
03223 
03224 NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLFrameElement, TabIndex, tabindex, 0)
03225 
03226 nsGenericHTMLFormElement::nsGenericHTMLFormElement(nsINodeInfo *aNodeInfo)
03227   : nsGenericHTMLElement(aNodeInfo)
03228 {
03229   mForm = nsnull;
03230 }
03231 
03232 nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
03233 {
03234   // Clean up.  Set the form to nsnull so it knows we went away.
03235   SetForm(nsnull);
03236 }
03237 
03238 NS_INTERFACE_MAP_BEGIN(nsGenericHTMLFormElement)
03239   NS_INTERFACE_MAP_ENTRY(nsIFormControl)
03240 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
03241 
03242 
03243 PRBool
03244 nsGenericHTMLFormElement::IsContentOfType(PRUint32 aFlags) const
03245 {
03246   return !(aFlags & ~(eELEMENT | eHTML | eHTML_FORM_CONTROL));
03247 }
03248 
03249 NS_IMETHODIMP
03250 nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm,
03251                                   PRBool aRemoveFromForm)
03252 {
03253   nsAutoString nameVal, idVal;
03254 
03255   if (aForm || (mForm && aRemoveFromForm)) {
03256     GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, nameVal);
03257     GetAttr(kNameSpaceID_None, nsHTMLAtoms::id, idVal);
03258   }
03259 
03260   if (mForm && aRemoveFromForm) {
03261     mForm->RemoveElement(this);
03262 
03263     if (!nameVal.IsEmpty()) {
03264       mForm->RemoveElementFromTable(this, nameVal);
03265     }
03266 
03267     if (!idVal.IsEmpty()) {
03268       mForm->RemoveElementFromTable(this, idVal);
03269     }
03270   }
03271 
03272   if (aForm) {
03273     // keep a *weak* ref to the form here
03274     CallQueryInterface(aForm, &mForm);
03275     mForm->Release();
03276   } else {
03277     mForm = nsnull;
03278   }
03279 
03280   if (mForm) {
03281     mForm->AddElement(this);
03282 
03283     if (!nameVal.IsEmpty()) {
03284       mForm->AddElementToTable(this, nameVal);
03285     }
03286 
03287     if (!idVal.IsEmpty()) {
03288       mForm->AddElementToTable(this, idVal);
03289     }
03290   }
03291 
03292   return NS_OK;
03293 }
03294 
03295 NS_IMETHODIMP
03296 nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
03297 {
03298   NS_ENSURE_ARG_POINTER(aForm);
03299   *aForm = nsnull;
03300 
03301   if (mForm) {
03302     CallQueryInterface(mForm, aForm);
03303   }
03304 
03305   return NS_OK;
03306 }
03307 
03308 PRBool
03309 nsGenericHTMLFrameElement::IsFocusable(PRInt32 *aTabIndex)
03310 {
03311   if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
03312     return PR_FALSE;
03313   }
03314 
03315   // If there is no subdocument, docshell or content viewer, it's not tabbable
03316   PRBool isFocusable = PR_FALSE;
03317   nsIDocument *doc = GetCurrentDoc();
03318   if (doc) {
03319     // XXXbz should this use GetOwnerDoc() for GetSubDocumentFor?
03320     // sXBL/XBL2 issue!
03321     nsIDocument *subDoc = doc->GetSubDocumentFor(this);
03322     if (subDoc) {
03323       nsCOMPtr<nsISupports> container = subDoc->GetContainer();
03324       nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
03325       if (docShell) {
03326         nsCOMPtr<nsIContentViewer> contentViewer;
03327         docShell->GetContentViewer(getter_AddRefs(contentViewer));
03328         if (contentViewer) {
03329           isFocusable = PR_TRUE;
03330           nsCOMPtr<nsIContentViewer> zombieViewer;
03331           contentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
03332           if (zombieViewer) {
03333             // If there are 2 viewers for the current docshell, that 
03334             // means the current document is a zombie document.
03335             // Only navigate into the frame/iframe if it's not a zombie.
03336             isFocusable = PR_FALSE;
03337           }
03338         }
03339       }
03340     }
03341   }
03342 
03343   if (!isFocusable && aTabIndex) {
03344     *aTabIndex = -1;
03345   }
03346 
03347   return isFocusable;
03348 }
03349 
03350 nsresult
03351 nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
03352                                      nsIContent* aParent,
03353                                      nsIContent* aBindingParent,
03354                                      PRBool aCompileEventHandlers)
03355 {
03356   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
03357                                                  aBindingParent,
03358                                                  aCompileEventHandlers);
03359   NS_ENSURE_SUCCESS(rv, rv);
03360 
03361   if (!mForm && aParent) {
03362     // We now have a parent, so we may have picked up an ancestor form.  Search
03363     // for it.  Note that if mForm is already set we don't want to do this,
03364     // because that means someone (probably the content sink) has already set
03365     // it to the right value.  Also note that even if being bound here didn't
03366     // change our parent, we still need to search, since our parent chain
03367     // probably changed _somewhere_.
03368     FindAndSetForm();
03369   }
03370     
03371   return rv;
03372 }
03373 
03374 void
03375 nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
03376 {
03377   // Save state before doing anything
03378   SaveState();
03379 
03380   if (mForm) {
03381     // Might need to unset mForm
03382     if (aNullParent) {
03383       // No more parent means no more form
03384       SetForm(nsnull);
03385     } else {
03386       // Recheck whether we should still have an mForm.
03387       nsCOMPtr<nsIDOMHTMLFormElement> form = FindForm(mForm);
03388       if (!form) {
03389         SetForm(nsnull);
03390       }
03391     }
03392   }
03393 
03394   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
03395 }
03396 
03397 nsresult
03398 nsGenericHTMLFormElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
03399                                   nsIAtom* aPrefix, const nsAString& aValue,
03400                                   PRBool aNotify)
03401 {
03402   nsresult rv = NS_OK;
03403 
03404   if (aNameSpaceID != kNameSpaceID_None) {
03405     rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
03406                                          aNotify);
03407   } else {
03408     nsCOMPtr<nsIFormControl> thisControl;
03409     nsAutoString tmp;
03410 
03411     QueryInterface(NS_GET_IID(nsIFormControl), getter_AddRefs(thisControl));
03412 
03413     // Add & remove the control to and/or from the hash table
03414     if (mForm && (aName == nsHTMLAtoms::name || aName == nsHTMLAtoms::id)) {
03415       GetAttr(kNameSpaceID_None, aName, tmp);
03416 
03417       if (!tmp.IsEmpty()) {
03418         mForm->RemoveElementFromTable(thisControl, tmp);
03419       }
03420     }
03421 
03422     if (mForm && aName == nsHTMLAtoms::type) {
03423       GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, tmp);
03424 
03425       if (!tmp.IsEmpty()) {
03426         mForm->RemoveElementFromTable(thisControl, tmp);
03427       }
03428 
03429       GetAttr(kNameSpaceID_None, nsHTMLAtoms::id, tmp);
03430 
03431       if (!tmp.IsEmpty()) {
03432         mForm->RemoveElementFromTable(thisControl, tmp);
03433       }
03434 
03435       mForm->RemoveElement(thisControl);
03436     }
03437 
03438     rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
03439                                        aNotify);
03440 
03441     if (mForm && (aName == nsHTMLAtoms::name || aName == nsHTMLAtoms::id)) {
03442       GetAttr(kNameSpaceID_None, aName, tmp);
03443 
03444       if (!tmp.IsEmpty()) {
03445         mForm->AddElementToTable(thisControl, tmp);
03446       }
03447     }
03448 
03449     if (mForm && aName == nsHTMLAtoms::type) {
03450       GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, tmp);
03451 
03452       if (!tmp.IsEmpty()) {
03453         mForm->AddElementToTable(thisControl, tmp);
03454       }
03455 
03456       GetAttr(kNameSpaceID_None, nsHTMLAtoms::id, tmp);
03457 
03458       if (!tmp.IsEmpty()) {
03459         mForm->AddElementToTable(thisControl, tmp);
03460       }
03461 
03462       mForm->AddElement(thisControl);
03463     }
03464   }
03465 
03466   AfterSetAttr(aNameSpaceID, aName, &aValue, aNotify);
03467 
03468   return rv;
03469 }
03470 
03471 nsresult
03472 nsGenericHTMLFormElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
03473                                     PRBool aNotify)
03474 {
03475   nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aName, aNotify);
03476 
03477   AfterSetAttr(aNameSpaceID, aName, nsnull, aNotify);
03478 
03479   return rv;
03480 }
03481 
03482 PRBool
03483 nsGenericHTMLFormElement::CanBeDisabled() const
03484 {
03485   PRInt32 type = GetType();
03486   // It's easier to test the types that _cannot_ be disabled
03487   return
03488     type != NS_FORM_LABEL &&
03489     type != NS_FORM_LEGEND &&
03490     type != NS_FORM_FIELDSET &&
03491     type != NS_FORM_OBJECT;
03492 }
03493 
03494 void
03495 nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
03496                                        const nsAString* aValue, PRBool aNotify)
03497 {
03498   if (aNotify && aNameSpaceID == kNameSpaceID_None &&
03499       aName == nsHTMLAtoms::disabled && CanBeDisabled()) {
03500     nsIDocument* document = GetCurrentDoc();
03501     if (document) {
03502       mozAutoDocUpdate(document, UPDATE_CONTENT_STATE, PR_TRUE);
03503       document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_DISABLED |
03504                                      NS_EVENT_STATE_ENABLED);
03505     }
03506   }
03507 }
03508 
03509 void
03510 nsGenericHTMLFormElement::FindAndSetForm()
03511 {
03512   nsCOMPtr<nsIDOMHTMLFormElement> form = FindForm();
03513   if (form) {
03514     SetForm(form);  // always succeeds
03515   }
03516 }
03517 
03518 PRInt32
03519 nsGenericHTMLFormElement::IntrinsicState() const
03520 {
03521   PRInt32 state = nsGenericHTMLElement::IntrinsicState();
03522 
03523   if (CanBeDisabled()) {
03524     // :enabled/:disabled
03525     PRBool disabled;
03526     GetBoolAttr(nsHTMLAtoms::disabled, &disabled);
03527     if (disabled) {
03528       state |= NS_EVENT_STATE_DISABLED;
03529       state &= ~NS_EVENT_STATE_ENABLED;
03530     } else {
03531       state &= ~NS_EVENT_STATE_DISABLED;
03532       state |= NS_EVENT_STATE_ENABLED;
03533     }
03534   }
03535 
03536   return state;
03537 }
03538 
03539 //----------------------------------------------------------------------
03540 
03541 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
03542 {
03543   if (mFrameLoader) {
03544     mFrameLoader->Destroy();
03545   }
03546 }
03547 
03548 NS_INTERFACE_MAP_BEGIN(nsGenericHTMLFrameElement)
03549   NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLFrameElement)
03550   NS_INTERFACE_MAP_ENTRY(nsIChromeEventHandler)
03551   NS_INTERFACE_MAP_ENTRY(nsIFrameLoaderOwner)
03552 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
03553 
03554 nsresult
03555 nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
03556 {
03557   NS_PRECONDITION(aContentDocument, "Null out param");
03558   *aContentDocument = nsnull;
03559 
03560   nsCOMPtr<nsIDOMWindow> win;
03561   GetContentWindow(getter_AddRefs(win));
03562 
03563   if (!win) {
03564     return NS_OK;
03565   }
03566 
03567   return win->GetDocument(aContentDocument);
03568 }
03569 
03570 NS_IMETHODIMP
03571 nsGenericHTMLFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
03572 {
03573   NS_PRECONDITION(aContentWindow, "Null out param");
03574   *aContentWindow = nsnull;
03575 
03576   nsresult rv = EnsureFrameLoader();
03577   NS_ENSURE_SUCCESS(rv, rv);
03578 
03579   if (!mFrameLoader) {
03580     return NS_OK;
03581   }
03582 
03583   PRBool depthTooGreat = PR_FALSE;
03584   mFrameLoader->GetDepthTooGreat(&depthTooGreat);
03585   if (depthTooGreat) {
03586     // Claim to have no contentWindow
03587     return NS_OK;
03588   }
03589   
03590   nsCOMPtr<nsIDocShell> doc_shell;
03591   mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
03592 
03593   nsCOMPtr<nsPIDOMWindow> win(do_GetInterface(doc_shell));
03594 
03595   if (!win) {
03596     return NS_OK;
03597   }
03598 
03599   NS_ASSERTION(win->IsOuterWindow(),
03600                "Uh, this window should always be an outer window!");
03601 
03602   return CallQueryInterface(win, aContentWindow);
03603 }
03604 
03605 nsresult
03606 nsGenericHTMLFrameElement::EnsureFrameLoader()
03607 {
03608   if (!GetParent() || !IsInDoc() || mFrameLoader) {
03609     // If frame loader is there, we just keep it around, cached
03610     return NS_OK;
03611   }
03612 
03613   mFrameLoader = new nsFrameLoader(this);
03614   if (!mFrameLoader)
03615     return NS_ERROR_OUT_OF_MEMORY;
03616 
03617   return NS_OK;
03618 }
03619 
03620 NS_IMETHODIMP
03621 nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
03622 {
03623   NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
03624   return NS_OK;
03625 }
03626 
03627 nsresult
03628 nsGenericHTMLFrameElement::LoadSrc()
03629 {
03630   nsresult rv = EnsureFrameLoader();
03631   NS_ENSURE_SUCCESS(rv, rv);
03632 
03633   if (!mFrameLoader) {
03634     return NS_OK;
03635   }
03636 
03637   rv = mFrameLoader->LoadFrame();
03638 #ifdef DEBUG
03639   if (NS_FAILED(rv)) {
03640     NS_WARNING("failed to load URL");
03641   }
03642 #endif
03643 
03644   return rv;
03645 }
03646 
03647 nsresult
03648 nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
03649                                       nsIContent* aParent,
03650                                       nsIContent* aBindingParent,
03651                                       PRBool aCompileEventHandlers)
03652 {
03653   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
03654                                                  aBindingParent,
03655                                                  aCompileEventHandlers);
03656   NS_ENSURE_SUCCESS(rv, rv);
03657 
03658   if (aDocument) {
03659     // We're in a document now.  Kick off the frame load.
03660     LoadSrc();
03661   }
03662   
03663   return rv;
03664 }
03665 
03666 void
03667 nsGenericHTMLFrameElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
03668 {
03669   if (mFrameLoader) {
03670     // This iframe is being taken out of the document, destroy the
03671     // iframe's frame loader (doing that will tear down the window in
03672     // this iframe).
03673     // XXXbz we really want to only partially destroy the frame
03674     // loader... we don't want to tear down the docshell.  Food for
03675     // later bug.
03676     mFrameLoader->Destroy();
03677     mFrameLoader = nsnull;
03678   }
03679 
03680   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
03681 }
03682 
03683 nsresult
03684 nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
03685                                    nsIAtom* aPrefix, const nsAString& aValue,
03686                                    PRBool aNotify)
03687 {
03688   nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
03689                                               aValue, aNotify);
03690   
03691   if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None &&
03692       aName == nsHTMLAtoms::src) {
03693     return LoadSrc();
03694   }
03695 
03696   return rv;
03697 }
03698 
03699 NS_IMETHODIMP
03700 nsGenericHTMLFrameElement::HandleChromeEvent(nsPresContext* aPresContext,
03701                                              nsEvent* aEvent,
03702                                              nsIDOMEvent** aDOMEvent,
03703                                              PRUint32 aFlags, 
03704                                              nsEventStatus* aEventStatus)
03705 {
03706   return HandleDOMEvent(aPresContext, aEvent, aDOMEvent, aFlags,aEventStatus);
03707 }
03708 
03709 //----------------------------------------------------------------------
03710 
03711 void
03712 nsGenericHTMLElement::SetElementFocus(PRBool aDoFocus)
03713 {
03714   nsCOMPtr<nsPresContext> presContext = GetPresContext();
03715   if (!presContext)
03716     return;
03717 
03718   if (aDoFocus) {
03719     if (IsInDoc()) {
03720       // Make sure that our frames are up to date so we focus the right thing.
03721       GetCurrentDoc()->FlushPendingNotifications(Flush_Frames);
03722     }
03723 
03724     SetFocus(presContext);
03725 
03726     presContext->EventStateManager()->MoveCaretToFocus();
03727     return;
03728   }
03729 
03730   RemoveFocus(presContext);
03731 }
03732 
03733 nsresult
03734 nsGenericHTMLElement::Blur()
03735 {
03736   if (ShouldFocus(this)) {
03737     SetElementFocus(PR_FALSE);
03738   }
03739 
03740   return NS_OK;
03741 }
03742 
03743 nsresult
03744 nsGenericHTMLElement::Focus()
03745 {
03746   // Generic HTML elements are focusable only if tabindex explicitly set.
03747   // SetFocus() will check to see if we're focusable and then
03748   // call into esm to do the work of focusing.
03749   if (ShouldFocus(this)) {
03750     SetElementFocus(PR_TRUE);
03751   }
03752 
03753   return NS_OK;
03754 }
03755 
03756 void
03757 nsGenericHTMLElement::RemoveFocus(nsPresContext *aPresContext)
03758 {
03759   if (!aPresContext) 
03760     return;
03761 
03762   if (IsContentOfType(eHTML_FORM_CONTROL)) {
03763     nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
03764     if (formControlFrame) {
03765       formControlFrame->SetFocus(PR_FALSE, PR_FALSE);
03766     }
03767   }
03768   
03769   if (IsInDoc()) {
03770     aPresContext->EventStateManager()->SetContentState(nsnull,
03771                                                        NS_EVENT_STATE_FOCUS);
03772   }
03773 }
03774 
03775 PRBool
03776 nsGenericHTMLElement::IsFocusable(PRInt32 *aTabIndex)
03777 {
03778   PRInt32 tabIndex = 0;   // Default value for non HTML elements with -moz-user-focus
03779   GetTabIndex(&tabIndex);
03780 
03781   // Just check for disabled attribute on all HTML elements
03782   PRBool disabled = HasAttr(kNameSpaceID_None, nsHTMLAtoms::disabled);
03783   if (disabled) {
03784     tabIndex = -1;
03785   }
03786 
03787   if (aTabIndex) {
03788     *aTabIndex = tabIndex;
03789   }
03790 
03791   // If a tabindex is specified at all, or the default tabindex is 0, we're focusable
03792   return tabIndex >= 0 || (!disabled && HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex));
03793 }
03794 
03795 void
03796 nsGenericHTMLElement::RegUnRegAccessKey(PRBool aDoReg)
03797 {
03798   // first check to see if we have an access key
03799   nsAutoString accessKey;
03800   nsresult rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::accesskey, accessKey);
03801   if (NS_FAILED(rv) || NS_CONTENT_ATTR_NOT_THERE == rv ||
03802       accessKey.IsEmpty()) {
03803     return;
03804   }
03805 
03806   // We have an access key, so get the ESM from the pres context.
03807   nsPresContext *presContext = GetPresContext();
03808 
03809   if (presContext) {
03810     nsIEventStateManager *esm = presContext->EventStateManager();
03811 
03812     // Register or unregister as appropriate.
03813     if (aDoReg) {
03814       esm->RegisterAccessKey(this, (PRUint32)accessKey.First());
03815     } else {
03816       esm->UnregisterAccessKey(this, (PRUint32)accessKey.First());
03817     }
03818   }
03819 }
03820 
03821 // static
03822 nsresult
03823 nsGenericHTMLElement::SetProtocolInHrefString(const nsAString &aHref,
03824                                               const nsAString &aProtocol,
03825                                               nsAString &aResult)
03826 {
03827   aResult.Truncate();
03828   nsCOMPtr<nsIURI> uri;
03829   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03830   if (NS_FAILED(rv))
03831     return rv;
03832 
03833   nsAString::const_iterator start, end;
03834   aProtocol.BeginReading(start);
03835   aProtocol.EndReading(end);
03836   nsAString::const_iterator iter(start);
03837   FindCharInReadable(':', iter, end);
03838   uri->SetScheme(NS_ConvertUCS2toUTF8(Substring(start, iter)));
03839    
03840   nsCAutoString newHref;
03841   uri->GetSpec(newHref);
03842 
03843   CopyUTF8toUTF16(newHref, aResult);
03844 
03845   return NS_OK;
03846 }
03847 
03848 // static
03849 nsresult
03850 nsGenericHTMLElement::SetHostnameInHrefString(const nsAString &aHref,
03851                                               const nsAString &aHostname,
03852                                               nsAString &aResult)
03853 {
03854   aResult.Truncate();
03855   nsCOMPtr<nsIURI> uri;
03856   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03857   if (NS_FAILED(rv))
03858     return rv;
03859 
03860   uri->SetHost(NS_ConvertUCS2toUTF8(aHostname));
03861 
03862   nsCAutoString newHref;
03863   uri->GetSpec(newHref);
03864 
03865   CopyUTF8toUTF16(newHref, aResult);
03866 
03867   return NS_OK;
03868 }
03869 
03870 // static
03871 nsresult
03872 nsGenericHTMLElement::SetPathnameInHrefString(const nsAString &aHref,
03873                                               const nsAString &aPathname,
03874                                               nsAString &aResult)
03875 {
03876   aResult.Truncate();
03877   nsCOMPtr<nsIURI> uri;
03878   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03879   if (NS_FAILED(rv))
03880     return rv;
03881 
03882   nsCOMPtr<nsIURL> url(do_QueryInterface(uri, &rv));
03883   if (NS_FAILED(rv))
03884     return rv;
03885 
03886   url->SetFilePath(NS_ConvertUCS2toUTF8(aPathname));
03887 
03888   nsCAutoString newHref;
03889   uri->GetSpec(newHref);
03890 
03891   CopyUTF8toUTF16(newHref, aResult);
03892 
03893   return NS_OK;
03894 }
03895 
03896 // static
03897 nsresult
03898 nsGenericHTMLElement::SetHostInHrefString(const nsAString &aHref,
03899                                           const nsAString &aHost,
03900                                           nsAString &aResult)
03901 {
03902   // Can't simply call nsURI::SetHost, because that would treat the name as an
03903   // IPv6 address (like http://[server:443]/)
03904 
03905   aResult.Truncate();
03906   nsCOMPtr<nsIURI> uri;
03907   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03908   if (NS_FAILED(rv))
03909     return rv;
03910 
03911   nsCAutoString scheme, userpass, path;
03912   uri->GetScheme(scheme);
03913   uri->GetUserPass(userpass);
03914   uri->GetPath(path);
03915 
03916   CopyASCIItoUTF16(scheme, aResult);
03917   aResult.AppendLiteral("://");
03918   if (!userpass.IsEmpty()) {
03919     AppendUTF8toUTF16(userpass, aResult);
03920     aResult.Append(PRUnichar('@'));
03921   }
03922   aResult.Append(aHost);
03923   AppendUTF8toUTF16(path, aResult);
03924 
03925   return NS_OK;
03926 }
03927 
03928 // static
03929 nsresult
03930 nsGenericHTMLElement::SetSearchInHrefString(const nsAString &aHref,
03931                                             const nsAString &aSearch,
03932                                             nsAString &aResult)
03933 {
03934   aResult.Truncate();
03935   nsCOMPtr<nsIURI> uri;
03936 
03937   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03938   if (NS_FAILED(rv))
03939     return rv;
03940 
03941   nsCOMPtr<nsIURL> url(do_QueryInterface(uri, &rv));
03942   if (NS_FAILED(rv))
03943     return rv;
03944 
03945   url->SetQuery(NS_ConvertUCS2toUTF8(aSearch));
03946 
03947   nsCAutoString newHref;
03948   uri->GetSpec(newHref);
03949 
03950   CopyUTF8toUTF16(newHref, aResult);
03951 
03952   return NS_OK;
03953 }
03954 
03955 // static
03956 nsresult
03957 nsGenericHTMLElement::SetHashInHrefString(const nsAString &aHref,
03958                                           const nsAString &aHash,
03959                                           nsAString &aResult)
03960 {
03961   aResult.Truncate();
03962   nsCOMPtr<nsIURI> uri;
03963 
03964   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03965   if (NS_FAILED(rv))
03966     return rv;
03967 
03968   nsCOMPtr<nsIURL> url(do_QueryInterface(uri, &rv));
03969   if (NS_FAILED(rv))
03970     return rv;
03971 
03972   rv = url->SetRef(NS_ConvertUCS2toUTF8(aHash));
03973 
03974   nsCAutoString newHref;
03975   uri->GetSpec(newHref);
03976 
03977   CopyUTF8toUTF16(newHref, aResult);
03978 
03979   return NS_OK;
03980 }
03981 
03982 // static
03983 nsresult
03984 nsGenericHTMLElement::SetPortInHrefString(const nsAString &aHref,
03985                                           const nsAString &aPort,
03986                                           nsAString &aResult)
03987 {
03988   aResult.Truncate();
03989   nsCOMPtr<nsIURI> uri;
03990   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
03991 
03992   if (NS_FAILED(rv))
03993     return rv;
03994 
03995   PRInt32 port;
03996   port = nsString(aPort).ToInteger((PRInt32*)&rv);
03997   if (NS_FAILED(rv))
03998     return rv;
03999 
04000   uri->SetPort(port);
04001 
04002   nsCAutoString newHref;
04003   uri->GetSpec(newHref);
04004 
04005   CopyUTF8toUTF16(newHref, aResult);
04006 
04007   return NS_OK;
04008 }
04009 
04010 // static
04011 nsresult
04012 nsGenericHTMLElement::GetProtocolFromHrefString(const nsAString& aHref,
04013                                                 nsAString& aProtocol,
04014                                                 nsIDocument *aDocument)
04015 {
04016   aProtocol.Truncate();
04017 
04018   nsIIOService* ioService = nsContentUtils::GetIOServiceWeakRef();
04019   NS_ENSURE_TRUE(ioService, NS_ERROR_FAILURE);
04020 
04021   nsCAutoString protocol;
04022 
04023   nsresult rv =
04024     ioService->ExtractScheme(NS_ConvertUCS2toUTF8(aHref), protocol);
04025 
04026   if (NS_SUCCEEDED(rv)) {
04027     CopyASCIItoUTF16(protocol, aProtocol);
04028   } else {
04029     // set the protocol to the protocol of the base URI.
04030 
04031     if (aDocument) {
04032       nsIURI *uri = aDocument->GetBaseURI();
04033       if (uri) {
04034         uri->GetScheme(protocol);
04035       }
04036     }
04037 
04038     if (protocol.IsEmpty()) {
04039       // set the protocol to http since it is the most likely protocol
04040       // to be used.
04041       aProtocol.AssignLiteral("http");
04042     } else {
04043       CopyASCIItoUTF16(protocol, aProtocol);
04044     }
04045   }
04046   aProtocol.Append(PRUnichar(':'));
04047 
04048   return NS_OK;
04049 }
04050 
04051 // static
04052 nsresult
04053 nsGenericHTMLElement::GetHostFromHrefString(const nsAString& aHref,
04054                                             nsAString& aHost)
04055 {
04056   aHost.Truncate();
04057   nsCOMPtr<nsIURI> uri;
04058   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
04059   if (NS_FAILED(rv))
04060     return rv;
04061 
04062   nsCAutoString hostport;
04063   rv = uri->GetHostPort(hostport);
04064 
04065   // Failure to get the hostport from the URI isn't necessarily an
04066   // error. Some URI's just don't have a hostport.
04067 
04068   if (NS_SUCCEEDED(rv)) {
04069     CopyUTF8toUTF16(hostport, aHost);
04070   }
04071 
04072   return NS_OK;
04073 }
04074 
04075 // static
04076 nsresult
04077 nsGenericHTMLElement::GetHostnameFromHrefString(const nsAString& aHref,
04078                                                 nsAString& aHostname)
04079 {
04080   aHostname.Truncate();
04081   nsCOMPtr<nsIURI> url;
04082   nsresult rv = NS_NewURI(getter_AddRefs(url), aHref);
04083   if (NS_FAILED(rv))
04084     return rv;
04085 
04086   nsCAutoString host;
04087   rv = url->GetHost(host);
04088 
04089   if (NS_SUCCEEDED(rv)) {
04090     // Failure to get the host from the URI isn't necessarily an
04091     // error. Some URI's just don't have a host.
04092 
04093     CopyUTF8toUTF16(host, aHostname);
04094   }
04095 
04096   return NS_OK;
04097 }
04098 
04099 // static
04100 nsresult
04101 nsGenericHTMLElement::GetPathnameFromHrefString(const nsAString& aHref,
04102                                                 nsAString& aPathname)
04103 {
04104   aPathname.Truncate();
04105   nsCOMPtr<nsIURI> uri;
04106 
04107   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
04108   if (NS_FAILED(rv))
04109     return rv;
04110 
04111   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
04112 
04113   if (!url) {
04114     // If this is not a URL, we can't get the pathname from the URI
04115 
04116     return NS_OK;
04117   }
04118 
04119   nsCAutoString file;
04120   rv = url->GetFilePath(file);
04121   if (NS_FAILED(rv))
04122     return rv;
04123 
04124   CopyUTF8toUTF16(file, aPathname);
04125 
04126   return NS_OK;
04127 }
04128 
04129 // static
04130 nsresult
04131 nsGenericHTMLElement::GetSearchFromHrefString(const nsAString& aHref,
04132                                               nsAString& aSearch)
04133 {
04134   aSearch.Truncate();
04135   nsCOMPtr<nsIURI> uri;
04136 
04137   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
04138   if (NS_FAILED(rv))
04139     return rv;
04140 
04141   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
04142 
04143   if (!url) {
04144     // If this is not a URL, we can't get the query from the URI
04145 
04146     return NS_OK;
04147   }
04148 
04149   nsCAutoString search;
04150   rv = url->GetQuery(search);
04151   if (NS_FAILED(rv))
04152     return rv;
04153 
04154   if (!search.IsEmpty()) {
04155     CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
04156   }
04157 
04158   return NS_OK;
04159 }
04160 
04161 // static
04162 nsresult
04163 nsGenericHTMLElement::GetPortFromHrefString(const nsAString& aHref,
04164                                             nsAString& aPort)
04165 {
04166   aPort.Truncate();
04167   nsCOMPtr<nsIURI> uri;
04168   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
04169   if (NS_FAILED(rv))
04170     return rv;
04171 
04172   PRInt32 port;
04173   rv = uri->GetPort(&port);
04174 
04175   if (NS_SUCCEEDED(rv)) {
04176     // Failure to get the port from the URI isn't necessarily an
04177     // error. Some URI's just don't have a port.
04178 
04179     if (port == -1) {
04180       return NS_OK;
04181     }
04182 
04183     nsAutoString portStr;
04184     portStr.AppendInt(port, 10);
04185     aPort.Assign(portStr);
04186   }
04187 
04188   return NS_OK;
04189 }
04190 
04191 // static
04192 nsresult
04193 nsGenericHTMLElement::GetHashFromHrefString(const nsAString& aHref,
04194                                             nsAString& aHash)
04195 {
04196   aHash.Truncate();
04197   nsCOMPtr<nsIURI> uri;
04198 
04199   nsresult rv = NS_NewURI(getter_AddRefs(uri), aHref);
04200   if (NS_FAILED(rv))
04201     return rv;
04202 
04203   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
04204 
04205   if (!url) {
04206     // If this is not a URL, we can't get the hash part from the URI
04207 
04208     return NS_OK;
04209   }
04210 
04211   nsCAutoString ref;
04212   rv = url->GetRef(ref);
04213   if (NS_FAILED(rv))
04214     return rv;
04215   NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
04216 
04217   if (!ref.IsEmpty()) {
04218     aHash.Assign(PRUnichar('#'));
04219     AppendASCIItoUTF16(ref, aHash);
04220   }
04221   return NS_OK;
04222 }
04223 
04224 const nsAttrName*
04225 nsGenericHTMLElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
04226 {
04227   if (mNodeInfo->NamespaceEquals(kNameSpaceID_None)) {
04228     nsAutoString lower;
04229     ToLowerCase(aStr, lower);
04230     return mAttrsAndChildren.GetExistingAttrNameFromQName(
04231       NS_ConvertUTF16toUTF8(lower));
04232   }
04233 
04234   return mAttrsAndChildren.GetExistingAttrNameFromQName(
04235     NS_ConvertUTF16toUTF8(aStr));
04236 }
04237 
04238 nsresult
04239 nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
04240 {
04241   *aEditor = nsnull;
04242 
04243   if (!nsContentUtils::IsCallerChrome())
04244     return NS_ERROR_DOM_SECURITY_ERR;
04245 
04246   return GetEditorInternal(aEditor);
04247 }
04248 
04249 nsresult
04250 nsGenericHTMLElement::GetEditorInternal(nsIEditor** aEditor)
04251 {
04252   *aEditor = nsnull;
04253 
04254   nsIFormControlFrame *fcFrame = GetFormControlFrame(PR_FALSE);
04255   if (fcFrame) {
04256     nsITextControlFrame *textFrame = nsnull;
04257     CallQueryInterface(fcFrame, &textFrame);
04258     if (textFrame) {
04259       return textFrame->GetEditor(aEditor);
04260     }
04261   }
04262 
04263   return NS_OK;
04264 }
04265 
04266 already_AddRefed<nsIEditor>
04267 nsGenericHTMLElement::GetAssociatedEditor()
04268 {
04269   // If contenteditable is ever implemented, it might need to do something different here?
04270 
04271   nsIEditor* editor = nsnull;
04272   GetEditorInternal(&editor);
04273   return editor;
04274 }
04275 
04276 PRBool
04277 nsGenericHTMLElement::IsCurrentBodyElement()
04278 {
04279   nsCOMPtr<nsIDOMHTMLBodyElement> bodyElement = do_QueryInterface(this);
04280   if (!bodyElement) {
04281     return PR_FALSE;
04282   }
04283 
04284   nsCOMPtr<nsIDOMHTMLDocument> htmlDocument =
04285     do_QueryInterface(GetCurrentDoc());
04286   if (!htmlDocument) {
04287     return PR_FALSE;
04288   }
04289 
04290   nsCOMPtr<nsIDOMHTMLElement> htmlElement;
04291   htmlDocument->GetBody(getter_AddRefs(htmlElement));
04292   return htmlElement == bodyElement;
04293 }
04294 
04295 // static
04296 void
04297 nsGenericHTMLElement::SyncEditorsOnSubtree(nsIContent* content)
04298 {
04299   /* Sync this node */
04300   nsGenericHTMLElement* element = FromContent(content);
04301   if (element) {
04302     nsCOMPtr<nsIEditor> editor = element->GetAssociatedEditor();
04303     nsCOMPtr<nsIEditor_MOZILLA_1_8_BRANCH> editor_1_8 =
04304       do_QueryInterface(editor);
04305     if (editor_1_8) {
04306       editor_1_8->SyncRealTimeSpell();
04307     }
04308   }
04309 
04310   /* Sync all children */
04311   PRUint32 childCount = content->GetChildCount();
04312   for (PRUint32 i = 0; i < childCount; ++i) {
04313     nsIContent* childContent = content->GetChildAt(i);
04314     NS_ASSERTION(childContent,
04315                  "DOM mutated unexpectedly while syncing editors!");
04316     if (childContent) {
04317       SyncEditorsOnSubtree(childContent);
04318     }
04319   }
04320 }