LCOV - code coverage report
Current view: directory - editor/libeditor/html - nsHTMLEditor.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2671 2 0.1 %
Date: 2012-06-02 Functions: 155 2 1.3 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      24                 :  *   Daniel Glazman <glazman@netscape.com>
      25                 :  *   Ms2ger <ms2ger@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : #include "nsCRT.h"
      41                 : 
      42                 : #include "nsUnicharUtils.h"
      43                 : 
      44                 : #include "nsHTMLEditor.h"
      45                 : #include "nsHTMLEditRules.h"
      46                 : #include "nsTextEditUtils.h"
      47                 : #include "nsHTMLEditUtils.h"
      48                 : 
      49                 : #include "nsHTMLEditorEventListener.h"
      50                 : #include "TypeInState.h"
      51                 : 
      52                 : #include "nsHTMLURIRefObject.h"
      53                 : 
      54                 : #include "nsIDOMText.h"
      55                 : #include "nsIDOMNodeList.h"
      56                 : #include "nsIDOMDocument.h"
      57                 : #include "nsIDOMAttr.h"
      58                 : #include "nsIDocument.h"
      59                 : #include "nsIDOMEventTarget.h" 
      60                 : #include "nsIDOMKeyEvent.h"
      61                 : #include "nsISelectionPrivate.h"
      62                 : #include "nsIDOMHTMLAnchorElement.h"
      63                 : #include "nsISelectionController.h"
      64                 : #include "nsIDOMHTMLDocument.h"
      65                 : #include "nsILinkHandler.h"
      66                 : 
      67                 : #include "mozilla/css/Loader.h"
      68                 : #include "nsCSSStyleSheet.h"
      69                 : #include "nsIDOMStyleSheet.h"
      70                 : 
      71                 : #include "nsIEnumerator.h"
      72                 : #include "nsIContent.h"
      73                 : #include "nsIContentIterator.h"
      74                 : #include "nsIDOMRange.h"
      75                 : #include "nsISupportsArray.h"
      76                 : #include "nsContentUtils.h"
      77                 : #include "nsIDocumentEncoder.h"
      78                 : #include "nsIDOMDocumentFragment.h"
      79                 : #include "nsIPresShell.h"
      80                 : #include "nsPresContext.h"
      81                 : #include "SetDocTitleTxn.h"
      82                 : #include "nsFocusManager.h"
      83                 : #include "nsPIDOMWindow.h"
      84                 : 
      85                 : // netwerk
      86                 : #include "nsIURI.h"
      87                 : #include "nsNetUtil.h"
      88                 : 
      89                 : // Transactionas
      90                 : #include "nsStyleSheetTxns.h"
      91                 : 
      92                 : // Misc
      93                 : #include "TextEditorTest.h"
      94                 : #include "nsEditorUtils.h"
      95                 : #include "nsWSRunObject.h"
      96                 : #include "nsGkAtoms.h"
      97                 : #include "nsIWidget.h"
      98                 : 
      99                 : #include "nsIFrame.h"
     100                 : #include "nsIParserService.h"
     101                 : #include "mozilla/dom/Element.h"
     102                 : 
     103                 : using namespace mozilla;
     104                 : using namespace mozilla::widget;
     105                 : 
     106                 : // Some utilities to handle annoying overloading of "A" tag for link and named anchor
     107                 : static char hrefText[] = "href";
     108                 : static char anchorTxt[] = "anchor";
     109                 : static char namedanchorText[] = "namedanchor";
     110                 : 
     111                 : #define IsLinkTag(s) (s.EqualsIgnoreCase(hrefText))
     112                 : #define IsNamedAnchorTag(s) (s.EqualsIgnoreCase(anchorTxt) || s.EqualsIgnoreCase(namedanchorText))
     113                 : 
     114               0 : nsHTMLEditor::nsHTMLEditor()
     115                 : : nsPlaintextEditor()
     116                 : , mCRInParagraphCreatesParagraph(false)
     117                 : , mSelectedCellIndex(0)
     118                 : , mIsObjectResizingEnabled(true)
     119                 : , mIsResizing(false)
     120                 : , mIsAbsolutelyPositioningEnabled(true)
     121                 : , mResizedObjectIsAbsolutelyPositioned(false)
     122                 : , mGrabberClicked(false)
     123                 : , mIsMoving(false)
     124                 : , mSnapToGridEnabled(false)
     125                 : , mIsInlineTableEditingEnabled(true)
     126                 : , mInfoXIncrement(20)
     127                 : , mInfoYIncrement(20)
     128               0 : , mGridSize(0)
     129                 : {
     130               0 : } 
     131                 : 
     132               0 : nsHTMLEditor::~nsHTMLEditor()
     133                 : {
     134                 :   // remove the rules as an action listener.  Else we get a bad
     135                 :   // ownership loop later on.  it's ok if the rules aren't a listener;
     136                 :   // we ignore the error.
     137               0 :   nsCOMPtr<nsIEditActionListener> mListener = do_QueryInterface(mRules);
     138               0 :   RemoveEditActionListener(mListener);
     139                 : 
     140                 :   //the autopointers will clear themselves up. 
     141                 :   //but we need to also remove the listeners or we have a leak
     142               0 :   nsCOMPtr<nsISelection>selection;
     143               0 :   nsresult result = GetSelection(getter_AddRefs(selection));
     144                 :   // if we don't get the selection, just skip this
     145               0 :   if (NS_SUCCEEDED(result) && selection) 
     146                 :   {
     147               0 :     nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     148               0 :     nsCOMPtr<nsISelectionListener>listener;
     149               0 :     listener = do_QueryInterface(mTypeInState);
     150               0 :     if (listener)
     151                 :     {
     152               0 :       selPriv->RemoveSelectionListener(listener); 
     153                 :     }
     154               0 :     listener = do_QueryInterface(mSelectionListenerP);
     155               0 :     if (listener)
     156                 :     {
     157               0 :       selPriv->RemoveSelectionListener(listener); 
     158                 :     }
     159                 :   }
     160                 : 
     161               0 :   mTypeInState = nsnull;
     162               0 :   mSelectionListenerP = nsnull;
     163                 : 
     164                 :   // free any default style propItems
     165               0 :   RemoveAllDefaultProperties();
     166                 : 
     167               0 :   if (mLinkHandler && mDocWeak)
     168                 :   {
     169               0 :     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     170                 : 
     171               0 :     if (ps && ps->GetPresContext())
     172                 :     {
     173               0 :       ps->GetPresContext()->SetLinkHandler(mLinkHandler);
     174                 :     }
     175                 :   }
     176                 : 
     177               0 :   RemoveEventListeners();
     178               0 : }
     179                 : 
     180                 : void
     181               0 : nsHTMLEditor::HideAnonymousEditingUIs()
     182                 : {
     183               0 :   if (mAbsolutelyPositionedObject)
     184               0 :     HideGrabber();
     185               0 :   if (mInlineEditedCell)
     186               0 :     HideInlineTableEditingUI();
     187               0 :   if (mResizedObject)
     188               0 :     HideResizers();
     189               0 : }
     190                 : 
     191            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLEditor)
     192                 : 
     193               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLEditor, nsPlaintextEditor)
     194               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTypeInState)
     195               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTextServices)
     196                 : 
     197               0 :   tmp->HideAnonymousEditingUIs();
     198               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     199                 : 
     200               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLEditor, nsPlaintextEditor)
     201               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTypeInState)
     202               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTextServices)
     203                 : 
     204               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTopLeftHandle)
     205               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTopHandle)
     206               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTopRightHandle)
     207               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLeftHandle)
     208               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRightHandle)
     209               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBottomLeftHandle)
     210               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBottomHandle)
     211               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBottomRightHandle)
     212               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mActivatedHandle)
     213               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResizingShadow)
     214               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResizingInfo)
     215               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResizedObject)
     216               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMouseMotionListenerP)
     217               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSelectionListenerP)
     218               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResizeEventListenerP)
     219               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(objectResizeEventListeners)
     220                 : 
     221               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAbsolutelyPositionedObject)
     222               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGrabber)
     223               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPositioningShadow)
     224                 : 
     225               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mInlineEditedCell)
     226               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAddColumnBeforeButton)
     227               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRemoveColumnButton)
     228               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAddColumnAfterButton)
     229               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAddRowBeforeButton)
     230               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRemoveRowButton)
     231               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAddRowAfterButton)
     232               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     233                 : 
     234               0 : NS_IMPL_ADDREF_INHERITED(nsHTMLEditor, nsEditor)
     235               0 : NS_IMPL_RELEASE_INHERITED(nsHTMLEditor, nsEditor)
     236                 : 
     237               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsHTMLEditor)
     238               0 :   NS_INTERFACE_MAP_ENTRY(nsIHTMLEditor)
     239               0 :   NS_INTERFACE_MAP_ENTRY(nsIHTMLObjectResizer)
     240               0 :   NS_INTERFACE_MAP_ENTRY(nsIHTMLAbsPosEditor)
     241               0 :   NS_INTERFACE_MAP_ENTRY(nsIHTMLInlineTableEditor)
     242               0 :   NS_INTERFACE_MAP_ENTRY(nsITableEditor)
     243               0 :   NS_INTERFACE_MAP_ENTRY(nsIEditorStyleSheets)
     244               0 :   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
     245               0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     246               0 : NS_INTERFACE_MAP_END_INHERITING(nsPlaintextEditor)
     247                 : 
     248                 : 
     249                 : NS_IMETHODIMP
     250               0 : nsHTMLEditor::Init(nsIDOMDocument *aDoc,
     251                 :                    nsIContent *aRoot,
     252                 :                    nsISelectionController *aSelCon,
     253                 :                    PRUint32 aFlags)
     254                 : {
     255               0 :   NS_PRECONDITION(aDoc && !aSelCon, "bad arg");
     256               0 :   NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER);
     257                 : 
     258               0 :   nsresult result = NS_OK, rulesRes = NS_OK;
     259                 :    
     260                 :   if (1)
     261                 :   {
     262                 :     // block to scope nsAutoEditInitRulesTrigger
     263               0 :     nsAutoEditInitRulesTrigger rulesTrigger(static_cast<nsPlaintextEditor*>(this), rulesRes);
     264                 : 
     265                 :     // Init the plaintext editor
     266               0 :     result = nsPlaintextEditor::Init(aDoc, aRoot, nsnull, aFlags);
     267               0 :     if (NS_FAILED(result)) { return result; }
     268                 : 
     269                 :     // Init mutation observer
     270               0 :     nsCOMPtr<nsINode> document = do_QueryInterface(aDoc);
     271               0 :     document->AddMutationObserverUnlessExists(this);
     272                 : 
     273                 :     // disable Composer-only features
     274               0 :     if (IsMailEditor())
     275                 :     {
     276               0 :       SetAbsolutePositioningEnabled(false);
     277               0 :       SetSnapToGridEnabled(false);
     278                 :     }
     279                 : 
     280                 :     // Init the HTML-CSS utils
     281               0 :     mHTMLCSSUtils = new nsHTMLCSSUtils(this);
     282                 : 
     283                 :     // disable links
     284               0 :     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     285               0 :     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
     286               0 :     nsPresContext *context = presShell->GetPresContext();
     287               0 :     NS_ENSURE_TRUE(context, NS_ERROR_NULL_POINTER);
     288               0 :     if (!IsPlaintextEditor() && !IsInteractionAllowed()) {
     289               0 :       mLinkHandler = context->GetLinkHandler();
     290                 : 
     291               0 :       context->SetLinkHandler(nsnull);
     292                 :     }
     293                 : 
     294                 :     // init the type-in state
     295               0 :     mTypeInState = new TypeInState();
     296                 : 
     297                 :     // init the selection listener for image resizing
     298               0 :     mSelectionListenerP = new ResizerSelectionListener(this);
     299                 : 
     300               0 :     if (!IsInteractionAllowed()) {
     301                 :       // ignore any errors from this in case the file is missing
     302               0 :       AddOverrideStyleSheet(NS_LITERAL_STRING("resource://gre/res/EditorOverride.css"));
     303                 :     }
     304                 : 
     305               0 :     nsCOMPtr<nsISelection>selection;
     306               0 :     result = GetSelection(getter_AddRefs(selection));
     307               0 :     if (NS_FAILED(result)) { return result; }
     308               0 :     if (selection) 
     309                 :     {
     310               0 :       nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     311               0 :       nsCOMPtr<nsISelectionListener>listener;
     312               0 :       listener = do_QueryInterface(mTypeInState);
     313               0 :       if (listener) {
     314               0 :         selPriv->AddSelectionListener(listener); 
     315                 :       }
     316               0 :       listener = do_QueryInterface(mSelectionListenerP);
     317               0 :       if (listener) {
     318               0 :         selPriv->AddSelectionListener(listener); 
     319                 :       }
     320                 :     }
     321                 :   }
     322                 : 
     323               0 :   NS_ENSURE_SUCCESS(rulesRes, rulesRes);
     324               0 :   return result;
     325                 : }
     326                 : 
     327                 : NS_IMETHODIMP
     328               0 : nsHTMLEditor::PreDestroy(bool aDestroyingFrames)
     329                 : {
     330               0 :   if (mDidPreDestroy) {
     331               0 :     return NS_OK;
     332                 :   }
     333                 : 
     334               0 :   nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak);
     335               0 :   if (document) {
     336               0 :     document->RemoveMutationObserver(this);
     337                 :   }
     338                 : 
     339               0 :   while (mStyleSheetURLs.Length())
     340                 :   {
     341               0 :     RemoveOverrideStyleSheet(mStyleSheetURLs[0]);
     342                 :   }
     343                 : 
     344                 :   // Clean up after our anonymous content -- we don't want these nodes to
     345                 :   // stay around (which they would, since the frames have an owning reference).
     346               0 :   HideAnonymousEditingUIs();
     347                 : 
     348               0 :   return nsPlaintextEditor::PreDestroy(aDestroyingFrames);
     349                 : }
     350                 : 
     351                 : NS_IMETHODIMP
     352               0 : nsHTMLEditor::GetRootElement(nsIDOMElement **aRootElement)
     353                 : {
     354               0 :   NS_ENSURE_ARG_POINTER(aRootElement);
     355                 : 
     356               0 :   if (mRootElement) {
     357               0 :     return nsEditor::GetRootElement(aRootElement);
     358                 :   }
     359                 : 
     360               0 :   *aRootElement = nsnull;
     361                 : 
     362                 :   // Use the HTML documents body element as the editor root if we didn't
     363                 :   // get a root element during initialization.
     364                 : 
     365               0 :   nsCOMPtr<nsIDOMElement> rootElement; 
     366               0 :   nsCOMPtr<nsIDOMHTMLElement> bodyElement; 
     367               0 :   nsresult rv = GetBodyElement(getter_AddRefs(bodyElement));
     368               0 :   NS_ENSURE_SUCCESS(rv, rv);
     369                 : 
     370               0 :   if (bodyElement) {
     371               0 :     rootElement = bodyElement;
     372                 :   } else {
     373                 :     // If there is no HTML body element,
     374                 :     // we should use the document root element instead.
     375               0 :     nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
     376               0 :     NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
     377                 : 
     378               0 :     rv = doc->GetDocumentElement(getter_AddRefs(rootElement));
     379               0 :     NS_ENSURE_SUCCESS(rv, rv);
     380                 :     // Document can have no elements
     381               0 :     if (!rootElement) {
     382               0 :       return NS_ERROR_NOT_AVAILABLE;
     383                 :     }
     384                 :   }
     385                 : 
     386               0 :   mRootElement = do_QueryInterface(rootElement);
     387               0 :   rootElement.forget(aRootElement);
     388                 : 
     389               0 :   return NS_OK;
     390                 : }
     391                 : 
     392                 : already_AddRefed<nsIContent>
     393               0 : nsHTMLEditor::FindSelectionRoot(nsINode *aNode)
     394                 : {
     395               0 :   NS_PRECONDITION(aNode->IsNodeOfType(nsINode::eDOCUMENT) ||
     396                 :                   aNode->IsNodeOfType(nsINode::eCONTENT),
     397                 :                   "aNode must be content or document node");
     398                 : 
     399               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
     400               0 :   nsCOMPtr<nsIDocument> doc = aNode->GetCurrentDoc();
     401               0 :   if (!doc) {
     402               0 :     return nsnull;
     403                 :   }
     404                 : 
     405               0 :   if (doc->HasFlag(NODE_IS_EDITABLE) || !content) {
     406               0 :     content = doc->GetRootElement();
     407               0 :     return content.forget();
     408                 :   }
     409                 : 
     410                 :   // XXX If we have readonly flag, shouldn't return the element which has
     411                 :   // contenteditable="true"?  However, such case isn't there without chrome
     412                 :   // permission script.
     413               0 :   if (IsReadonly()) {
     414                 :     // We still want to allow selection in a readonly editor.
     415               0 :     content = do_QueryInterface(GetRoot());
     416               0 :     return content.forget();
     417                 :   }
     418                 : 
     419               0 :   if (!content->HasFlag(NODE_IS_EDITABLE)) {
     420               0 :     return nsnull;
     421                 :   }
     422                 : 
     423                 :   // For non-readonly editors we want to find the root of the editable subtree
     424                 :   // containing aContent.
     425               0 :   content = content->GetEditingHost();
     426               0 :   return content.forget();
     427                 : }
     428                 : 
     429                 : /* virtual */
     430                 : void
     431               0 : nsHTMLEditor::CreateEventListeners()
     432                 : {
     433                 :   // Don't create the handler twice
     434               0 :   if (!mEventListener) {
     435               0 :     mEventListener = new nsHTMLEditorEventListener();
     436                 :   }
     437               0 : }
     438                 : 
     439                 : nsresult
     440               0 : nsHTMLEditor::InstallEventListeners()
     441                 : {
     442               0 :   NS_ENSURE_TRUE(mDocWeak && mEventListener,
     443                 :                  NS_ERROR_NOT_INITIALIZED);
     444                 : 
     445                 :   // NOTE: nsHTMLEditor doesn't need to initialize mEventTarget here because
     446                 :   // the target must be document node and it must be referenced as weak pointer.
     447                 : 
     448                 :   nsHTMLEditorEventListener* listener =
     449               0 :     reinterpret_cast<nsHTMLEditorEventListener*>(mEventListener.get());
     450               0 :   return listener->Connect(this);
     451                 : }
     452                 : 
     453                 : void
     454               0 : nsHTMLEditor::RemoveEventListeners()
     455                 : {
     456               0 :   if (!mDocWeak)
     457                 :   {
     458               0 :     return;
     459                 :   }
     460                 : 
     461               0 :   nsCOMPtr<nsIDOMEventTarget> target = GetDOMEventTarget();
     462                 : 
     463               0 :   if (target)
     464                 :   {
     465                 :     // Both mMouseMotionListenerP and mResizeEventListenerP can be
     466                 :     // registerd with other targets than the DOM event receiver that
     467                 :     // we can reach from here. But nonetheless, unregister the event
     468                 :     // listeners with the DOM event reveiver (if it's registerd with
     469                 :     // other targets, it'll get unregisterd once the target goes
     470                 :     // away).
     471                 : 
     472               0 :     if (mMouseMotionListenerP)
     473                 :     {
     474                 :       // mMouseMotionListenerP might be registerd either as bubbling or
     475                 :       // capturing, unregister by both.
     476               0 :       target->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
     477               0 :                                   mMouseMotionListenerP, false);
     478               0 :       target->RemoveEventListener(NS_LITERAL_STRING("mousemove"),
     479               0 :                                   mMouseMotionListenerP, true);
     480                 :     }
     481                 : 
     482               0 :     if (mResizeEventListenerP)
     483                 :     {
     484               0 :       target->RemoveEventListener(NS_LITERAL_STRING("resize"),
     485               0 :                                   mResizeEventListenerP, false);
     486                 :     }
     487                 :   }
     488                 : 
     489               0 :   mMouseMotionListenerP = nsnull;
     490               0 :   mResizeEventListenerP = nsnull;
     491                 : 
     492               0 :   nsPlaintextEditor::RemoveEventListeners();
     493                 : }
     494                 : 
     495                 : NS_IMETHODIMP 
     496               0 : nsHTMLEditor::SetFlags(PRUint32 aFlags)
     497                 : {
     498               0 :   nsresult rv = nsPlaintextEditor::SetFlags(aFlags);
     499               0 :   NS_ENSURE_SUCCESS(rv, rv);
     500                 : 
     501                 :   // Sets mCSSAware to correspond to aFlags. This toggles whether CSS is
     502                 :   // used to style elements in the editor. Note that the editor is only CSS
     503                 :   // aware by default in Composer and in the mail editor.
     504               0 :   mCSSAware = !NoCSS() && !IsMailEditor();
     505                 : 
     506               0 :   return NS_OK;
     507                 : }
     508                 : 
     509                 : NS_IMETHODIMP
     510               0 : nsHTMLEditor::InitRules()
     511                 : {
     512                 :   // instantiate the rules for the html editor
     513               0 :   mRules = new nsHTMLEditRules();
     514               0 :   return mRules->Init(static_cast<nsPlaintextEditor*>(this));
     515                 : }
     516                 : 
     517                 : NS_IMETHODIMP
     518               0 : nsHTMLEditor::BeginningOfDocument()
     519                 : {
     520               0 :   if (!mDocWeak) { return NS_ERROR_NOT_INITIALIZED; }
     521                 : 
     522                 :   // get the selection
     523               0 :   nsCOMPtr<nsISelection> selection;
     524               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
     525               0 :   NS_ENSURE_SUCCESS(res, res);
     526               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
     527                 : 
     528                 :   // Get the root element.
     529               0 :   nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
     530               0 :   if (!rootElement) {
     531               0 :     NS_WARNING("GetRoot() returned a null pointer (mRootElement is null)");
     532               0 :     return NS_OK;
     533                 :   }
     534                 : 
     535                 :   // find first editable thingy
     536               0 :   bool done = false;
     537               0 :   nsCOMPtr<nsIDOMNode> curNode(rootElement), selNode;
     538               0 :   PRInt32 curOffset = 0, selOffset;
     539               0 :   while (!done)
     540                 :   {
     541               0 :     nsWSRunObject wsObj(this, curNode, curOffset);
     542               0 :     nsCOMPtr<nsIDOMNode> visNode;
     543               0 :     PRInt32 visOffset=0;
     544               0 :     PRInt16 visType=0;
     545               0 :     wsObj.NextVisibleNode(curNode, curOffset, address_of(visNode), &visOffset, &visType);
     546               0 :     if ((visType==nsWSRunObject::eNormalWS) || 
     547                 :         (visType==nsWSRunObject::eText))
     548                 :     {
     549               0 :       selNode = visNode;
     550               0 :       selOffset = visOffset;
     551               0 :       done = true;
     552                 :     }
     553               0 :     else if ((visType==nsWSRunObject::eBreak)    ||
     554                 :              (visType==nsWSRunObject::eSpecial))
     555                 :     {
     556               0 :       res = GetNodeLocation(visNode, address_of(selNode), &selOffset);
     557               0 :       NS_ENSURE_SUCCESS(res, res); 
     558               0 :       done = true;
     559                 :     }
     560               0 :     else if (visType==nsWSRunObject::eOtherBlock)
     561                 :     {
     562                 :       // By definition of nsWSRunObject, a block element terminates 
     563                 :       // a whitespace run. That is, although we are calling a method 
     564                 :       // that is named "NextVisibleNode", the node returned
     565                 :       // might not be visible/editable!
     566                 :       // If the given block does not contain any visible/editable items,
     567                 :       // we want to skip it and continue our search.
     568                 : 
     569               0 :       if (!IsContainer(visNode))
     570                 :       {
     571                 :         // However, we were given a block that is not a container.
     572                 :         // Since the block can not contain anything that's visible,
     573                 :         // such a block only makes sense if it is visible by itself,
     574                 :         // like a <hr>
     575                 :         // We want to place the caret in front of that block.
     576                 : 
     577               0 :         res = GetNodeLocation(visNode, address_of(selNode), &selOffset);
     578               0 :         NS_ENSURE_SUCCESS(res, res); 
     579               0 :         done = true;
     580                 :       }
     581                 :       else
     582                 :       {
     583                 :         bool isEmptyBlock;
     584               0 :         if (NS_SUCCEEDED(IsEmptyNode(visNode, &isEmptyBlock)) &&
     585                 :             isEmptyBlock)
     586                 :         {
     587                 :           // skip the empty block
     588               0 :           res = GetNodeLocation(visNode, address_of(curNode), &curOffset);
     589               0 :           NS_ENSURE_SUCCESS(res, res); 
     590               0 :           ++curOffset;
     591                 :         }
     592                 :         else
     593                 :         {
     594               0 :           curNode = visNode;
     595               0 :           curOffset = 0;
     596                 :         }
     597                 :         // keep looping
     598                 :       }
     599                 :     }
     600                 :     else
     601                 :     {
     602                 :       // else we found nothing useful
     603               0 :       selNode = curNode;
     604               0 :       selOffset = curOffset;
     605               0 :       done = true;
     606                 :     }
     607                 :   }
     608               0 :   return selection->Collapse(selNode, selOffset);
     609                 : }
     610                 : 
     611                 : nsresult
     612               0 : nsHTMLEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
     613                 : {
     614                 :   // NOTE: When you change this method, you should also change:
     615                 :   //   * editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
     616                 : 
     617               0 :   if (IsReadonly() || IsDisabled()) {
     618                 :     // When we're not editable, the events are handled on nsEditor, so, we can
     619                 :     // bypass nsPlaintextEditor.
     620               0 :     return nsEditor::HandleKeyPressEvent(aKeyEvent);
     621                 :   }
     622                 : 
     623               0 :   nsKeyEvent* nativeKeyEvent = GetNativeKeyEvent(aKeyEvent);
     624               0 :   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
     625               0 :   NS_ASSERTION(nativeKeyEvent->message == NS_KEY_PRESS,
     626                 :                "HandleKeyPressEvent gets non-keypress event");
     627                 : 
     628               0 :   switch (nativeKeyEvent->keyCode) {
     629                 :     case nsIDOMKeyEvent::DOM_VK_META:
     630                 :     case nsIDOMKeyEvent::DOM_VK_SHIFT:
     631                 :     case nsIDOMKeyEvent::DOM_VK_CONTROL:
     632                 :     case nsIDOMKeyEvent::DOM_VK_ALT:
     633                 :     case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
     634                 :     case nsIDOMKeyEvent::DOM_VK_DELETE:
     635                 :       // These keys are handled on nsEditor, so, we can bypass
     636                 :       // nsPlaintextEditor.
     637               0 :       return nsEditor::HandleKeyPressEvent(aKeyEvent);
     638                 :     case nsIDOMKeyEvent::DOM_VK_TAB: {
     639               0 :       if (IsPlaintextEditor()) {
     640                 :         // If this works as plain text editor, e.g., mail editor for plain
     641                 :         // text, should be handled on nsPlaintextEditor.
     642               0 :         return nsPlaintextEditor::HandleKeyPressEvent(aKeyEvent);
     643                 :       }
     644                 : 
     645               0 :       if (IsTabbable()) {
     646               0 :         return NS_OK; // let it be used for focus switching
     647                 :       }
     648                 : 
     649               0 :       if (nativeKeyEvent->isControl || nativeKeyEvent->isAlt ||
     650                 :           nativeKeyEvent->isMeta) {
     651               0 :         return NS_OK;
     652                 :       }
     653                 : 
     654               0 :       nsCOMPtr<nsISelection> selection;
     655               0 :       nsresult rv = GetSelection(getter_AddRefs(selection));
     656               0 :       NS_ENSURE_SUCCESS(rv, rv);
     657                 :       PRInt32 offset;
     658               0 :       nsCOMPtr<nsIDOMNode> node, blockParent;
     659               0 :       rv = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
     660               0 :       NS_ENSURE_SUCCESS(rv, rv);
     661               0 :       NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
     662                 : 
     663               0 :       bool isBlock = false;
     664               0 :       NodeIsBlock(node, &isBlock);
     665               0 :       if (isBlock) {
     666               0 :         blockParent = node;
     667                 :       } else {
     668               0 :         blockParent = GetBlockNodeParent(node);
     669                 :       }
     670                 : 
     671               0 :       if (!blockParent) {
     672                 :         break;
     673                 :       }
     674                 : 
     675               0 :       bool handled = false;
     676               0 :       if (nsHTMLEditUtils::IsTableElement(blockParent)) {
     677               0 :         rv = TabInTable(nativeKeyEvent->isShift, &handled);
     678               0 :         if (handled) {
     679               0 :           ScrollSelectionIntoView(false);
     680                 :         }
     681               0 :       } else if (nsHTMLEditUtils::IsListItem(blockParent)) {
     682                 :         rv = Indent(nativeKeyEvent->isShift ?
     683               0 :                       NS_LITERAL_STRING("outdent") :
     684               0 :                       NS_LITERAL_STRING("indent"));
     685               0 :         handled = true;
     686                 :       }
     687               0 :       NS_ENSURE_SUCCESS(rv, rv);
     688               0 :       if (handled) {
     689               0 :         return aKeyEvent->PreventDefault(); // consumed
     690                 :       }
     691               0 :       if (nativeKeyEvent->isShift) {
     692               0 :         return NS_OK; // don't type text for shift tabs
     693                 :       }
     694               0 :       aKeyEvent->PreventDefault();
     695               0 :       return TypedText(NS_LITERAL_STRING("\t"), eTypedText);
     696                 :     }
     697                 :     case nsIDOMKeyEvent::DOM_VK_RETURN:
     698                 :     case nsIDOMKeyEvent::DOM_VK_ENTER:
     699               0 :       if (nativeKeyEvent->isControl || nativeKeyEvent->isAlt ||
     700                 :           nativeKeyEvent->isMeta) {
     701               0 :         return NS_OK;
     702                 :       }
     703               0 :       aKeyEvent->PreventDefault(); // consumed
     704               0 :       if (nativeKeyEvent->isShift && !IsPlaintextEditor()) {
     705                 :         // only inserts a br node
     706               0 :         return TypedText(EmptyString(), eTypedBR);
     707                 :       }
     708                 :       // uses rules to figure out what to insert
     709               0 :       return TypedText(EmptyString(), eTypedBreak);
     710                 :   }
     711                 : 
     712                 :   // NOTE: On some keyboard layout, some characters are inputted with Control
     713                 :   // key or Alt key, but at that time, widget sets FALSE to these keys.
     714               0 :   if (nativeKeyEvent->charCode == 0 || nativeKeyEvent->isControl ||
     715                 :       nativeKeyEvent->isAlt || nativeKeyEvent->isMeta) {
     716                 :     // we don't PreventDefault() here or keybindings like control-x won't work
     717               0 :     return NS_OK;
     718                 :   }
     719               0 :   aKeyEvent->PreventDefault();
     720               0 :   nsAutoString str(nativeKeyEvent->charCode);
     721               0 :   return TypedText(str, eTypedText);
     722                 : }
     723                 : 
     724                 : /**
     725                 :  * Returns true if the id represents an element of block type.
     726                 :  * Can be used to determine if a new paragraph should be started.
     727                 :  */
     728                 : nsresult
     729               0 : nsHTMLEditor::NodeIsBlockStatic(nsIDOMNode *aNode, bool *aIsBlock)
     730                 : {
     731               0 :   if (!aNode || !aIsBlock) { return NS_ERROR_NULL_POINTER; }
     732                 : 
     733               0 :   *aIsBlock = false;
     734                 : 
     735                 : #define USE_PARSER_FOR_BLOCKNESS 1
     736                 : #ifdef USE_PARSER_FOR_BLOCKNESS
     737                 :   nsresult rv;
     738                 : 
     739               0 :   nsCOMPtr<nsIDOMElement>element = do_QueryInterface(aNode);
     740               0 :   if (!element)
     741                 :   {
     742                 :     // We don't have an element -- probably a text node
     743               0 :     return NS_OK;
     744                 :   }
     745                 : 
     746               0 :   nsIAtom *tagAtom = GetTag(aNode);
     747               0 :   NS_ENSURE_TRUE(tagAtom, NS_ERROR_NULL_POINTER);
     748                 : 
     749                 :   // Nodes we know we want to treat as block
     750                 :   // even though the parser says they're not:
     751               0 :   if (tagAtom==nsEditProperty::body       ||
     752                 :       tagAtom==nsEditProperty::head       ||
     753                 :       tagAtom==nsEditProperty::tbody      ||
     754                 :       tagAtom==nsEditProperty::thead      ||
     755                 :       tagAtom==nsEditProperty::tfoot      ||
     756                 :       tagAtom==nsEditProperty::tr         ||
     757                 :       tagAtom==nsEditProperty::th         ||
     758                 :       tagAtom==nsEditProperty::td         ||
     759                 :       tagAtom==nsEditProperty::li         ||
     760                 :       tagAtom==nsEditProperty::dt         ||
     761                 :       tagAtom==nsEditProperty::dd         ||
     762                 :       tagAtom==nsEditProperty::pre)
     763                 :   {
     764               0 :     *aIsBlock = true;
     765               0 :     return NS_OK;
     766                 :   }
     767                 : 
     768               0 :   rv = nsContentUtils::GetParserService()->
     769               0 :     IsBlock(nsContentUtils::GetParserService()->HTMLAtomTagToId(tagAtom),
     770               0 :             *aIsBlock);
     771                 : 
     772                 : #ifdef DEBUG
     773                 :   // Check this against what we would have said with the old code:
     774               0 :   if (tagAtom==nsEditProperty::p          ||
     775                 :       tagAtom==nsEditProperty::div        ||
     776                 :       tagAtom==nsEditProperty::blockquote ||
     777                 :       tagAtom==nsEditProperty::h1         ||
     778                 :       tagAtom==nsEditProperty::h2         ||
     779                 :       tagAtom==nsEditProperty::h3         ||
     780                 :       tagAtom==nsEditProperty::h4         ||
     781                 :       tagAtom==nsEditProperty::h5         ||
     782                 :       tagAtom==nsEditProperty::h6         ||
     783                 :       tagAtom==nsEditProperty::ul         ||
     784                 :       tagAtom==nsEditProperty::ol         ||
     785                 :       tagAtom==nsEditProperty::dl         ||
     786                 :       tagAtom==nsEditProperty::noscript   ||
     787                 :       tagAtom==nsEditProperty::form       ||
     788                 :       tagAtom==nsEditProperty::hr         ||
     789                 :       tagAtom==nsEditProperty::table      ||
     790                 :       tagAtom==nsEditProperty::fieldset   ||
     791                 :       tagAtom==nsEditProperty::address    ||
     792                 :       tagAtom==nsEditProperty::caption    ||
     793                 :       tagAtom==nsEditProperty::col        ||
     794                 :       tagAtom==nsEditProperty::colgroup   ||
     795                 :       tagAtom==nsEditProperty::li         ||
     796                 :       tagAtom==nsEditProperty::dt         ||
     797                 :       tagAtom==nsEditProperty::dd         ||
     798                 :       tagAtom==nsEditProperty::legend     )
     799                 :   {
     800               0 :     if (!(*aIsBlock))
     801                 :     {
     802               0 :       nsAutoString assertmsg (NS_LITERAL_STRING("Parser and editor disagree on blockness: "));
     803                 : 
     804               0 :       nsAutoString tagName;
     805               0 :       rv = element->GetTagName(tagName);
     806               0 :       NS_ENSURE_SUCCESS(rv, rv);
     807                 : 
     808               0 :       assertmsg.Append(tagName);
     809               0 :       char* assertstr = ToNewCString(assertmsg);
     810               0 :       NS_ASSERTION(*aIsBlock, assertstr);
     811               0 :       NS_Free(assertstr);
     812                 :     }
     813                 :   }
     814                 : #endif /* DEBUG */
     815                 : 
     816               0 :   return rv;
     817                 : #else /* USE_PARSER_FOR_BLOCKNESS */
     818                 :   nsresult result = NS_ERROR_FAILURE;
     819                 :   *aIsBlock = false;
     820                 :   nsCOMPtr<nsIDOMElement>element;
     821                 :   element = do_QueryInterface(aNode);
     822                 :   if (element)
     823                 :   {
     824                 :     nsAutoString tagName;
     825                 :     result = element->GetTagName(tagName);
     826                 :     if (NS_SUCCEEDED(result))
     827                 :     {
     828                 :       ToLowerCase(tagName);
     829                 :       nsCOMPtr<nsIAtom> tagAtom = do_GetAtom(tagName);
     830                 :       if (!tagAtom) { return NS_ERROR_NULL_POINTER; }
     831                 : 
     832                 :       if (tagAtom==nsEditProperty::p          ||
     833                 :           tagAtom==nsEditProperty::div        ||
     834                 :           tagAtom==nsEditProperty::blockquote ||
     835                 :           tagAtom==nsEditProperty::h1         ||
     836                 :           tagAtom==nsEditProperty::h2         ||
     837                 :           tagAtom==nsEditProperty::h3         ||
     838                 :           tagAtom==nsEditProperty::h4         ||
     839                 :           tagAtom==nsEditProperty::h5         ||
     840                 :           tagAtom==nsEditProperty::h6         ||
     841                 :           tagAtom==nsEditProperty::ul         ||
     842                 :           tagAtom==nsEditProperty::ol         ||
     843                 :           tagAtom==nsEditProperty::dl         ||
     844                 :           tagAtom==nsEditProperty::pre        ||
     845                 :           tagAtom==nsEditProperty::noscript   ||
     846                 :           tagAtom==nsEditProperty::form       ||
     847                 :           tagAtom==nsEditProperty::hr         ||
     848                 :           tagAtom==nsEditProperty::fieldset   ||
     849                 :           tagAtom==nsEditProperty::address    ||
     850                 :           tagAtom==nsEditProperty::body       ||
     851                 :           tagAtom==nsEditProperty::caption    ||
     852                 :           tagAtom==nsEditProperty::table      ||
     853                 :           tagAtom==nsEditProperty::tbody      ||
     854                 :           tagAtom==nsEditProperty::thead      ||
     855                 :           tagAtom==nsEditProperty::tfoot      ||
     856                 :           tagAtom==nsEditProperty::tr         ||
     857                 :           tagAtom==nsEditProperty::td         ||
     858                 :           tagAtom==nsEditProperty::th         ||
     859                 :           tagAtom==nsEditProperty::col        ||
     860                 :           tagAtom==nsEditProperty::colgroup   ||
     861                 :           tagAtom==nsEditProperty::li         ||
     862                 :           tagAtom==nsEditProperty::dt         ||
     863                 :           tagAtom==nsEditProperty::dd         ||
     864                 :           tagAtom==nsEditProperty::legend     )
     865                 :       {
     866                 :         *aIsBlock = true;
     867                 :       }
     868                 :       result = NS_OK;
     869                 :     }
     870                 :   } else {
     871                 :     // We don't have an element -- probably a text node
     872                 :     nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(aNode);
     873                 :     if (nodeAsText)
     874                 :     {
     875                 :       *aIsBlock = false;
     876                 :       result = NS_OK;
     877                 :     }
     878                 :   }
     879                 :   return result;
     880                 : 
     881                 : #endif /* USE_PARSER_FOR_BLOCKNESS */
     882                 : }
     883                 : 
     884                 : NS_IMETHODIMP
     885               0 : nsHTMLEditor::NodeIsBlock(nsIDOMNode *aNode, bool *aIsBlock)
     886                 : {
     887               0 :   return NodeIsBlockStatic(aNode, aIsBlock);
     888                 : }
     889                 : 
     890                 : bool
     891               0 : nsHTMLEditor::IsBlockNode(nsIDOMNode *aNode)
     892                 : {
     893                 :   bool isBlock;
     894               0 :   NodeIsBlockStatic(aNode, &isBlock);
     895               0 :   return isBlock;
     896                 : }
     897                 : 
     898                 : bool
     899               0 : nsHTMLEditor::IsBlockNode(nsINode *aNode)
     900                 : {
     901                 :   bool isBlock;
     902               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
     903               0 :   NodeIsBlockStatic(node, &isBlock);
     904               0 :   return isBlock;
     905                 : }
     906                 : 
     907                 : // Non-static version for the nsIEditor interface and JavaScript
     908                 : NS_IMETHODIMP 
     909               0 : nsHTMLEditor::SetDocumentTitle(const nsAString &aTitle)
     910                 : {
     911               0 :   nsRefPtr<SetDocTitleTxn> txn = new SetDocTitleTxn();
     912               0 :   NS_ENSURE_TRUE(txn, NS_ERROR_OUT_OF_MEMORY);
     913                 : 
     914               0 :   nsresult result = txn->Init(this, &aTitle);
     915               0 :   NS_ENSURE_SUCCESS(result, result);
     916                 : 
     917                 :   //Don't let Rules System change the selection
     918               0 :   nsAutoTxnsConserveSelection dontChangeSelection(this);
     919               0 :   return nsEditor::DoTransaction(txn);  
     920                 : }
     921                 : 
     922                 : /* ------------ Block methods moved from nsEditor -------------- */
     923                 : ///////////////////////////////////////////////////////////////////////////
     924                 : // GetBlockNodeParent: returns enclosing block level ancestor, if any
     925                 : //
     926                 : already_AddRefed<nsIDOMNode>
     927               0 : nsHTMLEditor::GetBlockNodeParent(nsIDOMNode *aNode)
     928                 : {
     929               0 :   if (!aNode)
     930                 :   {
     931               0 :     NS_NOTREACHED("null node passed to GetBlockNodeParent()");
     932               0 :     return nsnull;
     933                 :   }
     934                 : 
     935               0 :   nsCOMPtr<nsIDOMNode> p;
     936               0 :   if (NS_FAILED(aNode->GetParentNode(getter_AddRefs(p))))  // no parent, ran off top of tree
     937               0 :     return nsnull;
     938                 : 
     939               0 :   nsCOMPtr<nsIDOMNode> tmp;
     940               0 :   while (p)
     941                 :   {
     942                 :     bool isBlock;
     943               0 :     if (NS_FAILED(NodeIsBlockStatic(p, &isBlock)) || isBlock)
     944               0 :       break;
     945               0 :     if (NS_FAILED(p->GetParentNode(getter_AddRefs(tmp))) || !tmp) // no parent, ran off top of tree
     946               0 :       break;
     947                 : 
     948               0 :     p = tmp;
     949                 :   }
     950               0 :   return p.forget();
     951                 : }
     952                 : 
     953                 : ///////////////////////////////////////////////////////////////////////////
     954                 : // NextNodeInBlock: gets the next/prev node in the block, if any.  Next node
     955                 : //                  must be an element or text node, others are ignored
     956                 : already_AddRefed<nsIDOMNode>
     957               0 : nsHTMLEditor::NextNodeInBlock(nsIDOMNode *aNode, IterDirection aDir)
     958                 : {
     959               0 :   NS_ENSURE_TRUE(aNode, nsnull);
     960                 : 
     961                 :   nsresult rv;
     962                 :   nsCOMPtr<nsIContentIterator> iter =
     963               0 :        do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
     964               0 :   NS_ENSURE_SUCCESS(rv, nsnull);
     965                 : 
     966                 :   // much gnashing of teeth as we twit back and forth between content and domnode types
     967               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
     968               0 :   nsCOMPtr<nsIDOMNode> blockParent;
     969                 :   bool isBlock;
     970               0 :   if (NS_SUCCEEDED(NodeIsBlockStatic(aNode, &isBlock)) && isBlock) {
     971               0 :     blockParent = aNode;
     972                 :   } else {
     973               0 :     blockParent = GetBlockNodeParent(aNode);
     974                 :   }
     975               0 :   NS_ENSURE_TRUE(blockParent, nsnull);
     976               0 :   nsCOMPtr<nsIContent> blockContent = do_QueryInterface(blockParent);
     977               0 :   NS_ENSURE_TRUE(blockContent, nsnull);
     978                 :   
     979               0 :   if (NS_FAILED(iter->Init(blockContent))) {
     980               0 :     return nsnull;
     981                 :   }
     982               0 :   if (NS_FAILED(iter->PositionAt(content))) {
     983               0 :     return nsnull;
     984                 :   }
     985                 :   
     986               0 :   while (!iter->IsDone()) {
     987                 :     // ignore nodes that aren't elements or text, or that are the
     988                 :     // block parent
     989               0 :     nsCOMPtr<nsIDOMNode> node = do_QueryInterface(iter->GetCurrentNode());
     990               0 :     if (node && IsTextOrElementNode(node) && node != blockParent &&
     991               0 :         node != aNode)
     992               0 :       return node.forget();
     993                 : 
     994               0 :     if (aDir == kIterForward)
     995               0 :       iter->Next();
     996                 :     else
     997               0 :       iter->Prev();
     998                 :   }
     999                 :   
    1000               0 :   return nsnull;
    1001                 : }
    1002                 : 
    1003                 : static const PRUnichar nbsp = 160;
    1004                 : 
    1005                 : ///////////////////////////////////////////////////////////////////////////
    1006                 : // IsNextCharWhitespace: checks the adjacent content in the same block
    1007                 : //                       to see if following selection is whitespace or nbsp
    1008                 : nsresult 
    1009               0 : nsHTMLEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode, 
    1010                 :                                    PRInt32 aOffset,
    1011                 :                                    bool *outIsSpace,
    1012                 :                                    bool *outIsNBSP,
    1013                 :                                    nsCOMPtr<nsIDOMNode> *outNode,
    1014                 :                                    PRInt32 *outOffset)
    1015                 : {
    1016               0 :   NS_ENSURE_TRUE(outIsSpace && outIsNBSP, NS_ERROR_NULL_POINTER);
    1017               0 :   *outIsSpace = false;
    1018               0 :   *outIsNBSP = false;
    1019               0 :   if (outNode) *outNode = nsnull;
    1020               0 :   if (outOffset) *outOffset = -1;
    1021                 :   
    1022               0 :   nsAutoString tempString;
    1023                 :   PRUint32 strLength;
    1024               0 :   nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode);
    1025               0 :   if (textNode)
    1026                 :   {
    1027               0 :     textNode->GetLength(&strLength);
    1028               0 :     if ((PRUint32)aOffset < strLength)
    1029                 :     {
    1030                 :       // easy case: next char is in same node
    1031               0 :       textNode->SubstringData(aOffset,aOffset+1,tempString);
    1032               0 :       *outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
    1033               0 :       *outIsNBSP = (tempString.First() == nbsp);
    1034               0 :       if (outNode) *outNode = do_QueryInterface(aParentNode);
    1035               0 :       if (outOffset) *outOffset = aOffset+1;  // yes, this is _past_ the character; 
    1036               0 :       return NS_OK;
    1037                 :     }
    1038                 :   }
    1039                 :   
    1040                 :   // harder case: next char in next node.
    1041               0 :   nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterForward);
    1042               0 :   nsCOMPtr<nsIDOMNode> tmp;
    1043               0 :   while (node) 
    1044                 :   {
    1045               0 :     bool isBlock (false);
    1046               0 :     NodeIsBlock(node, &isBlock);
    1047               0 :     if (isBlock)  // skip over bold, italic, link, ect nodes
    1048                 :     {
    1049               0 :       if (IsTextNode(node) && IsEditable(node))
    1050                 :       {
    1051               0 :         textNode = do_QueryInterface(node);
    1052               0 :         textNode->GetLength(&strLength);
    1053               0 :         if (strLength)
    1054                 :         {
    1055               0 :           textNode->SubstringData(0,1,tempString);
    1056               0 :           *outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
    1057               0 :           *outIsNBSP = (tempString.First() == nbsp);
    1058               0 :           if (outNode) *outNode = do_QueryInterface(node);
    1059               0 :           if (outOffset) *outOffset = 1;  // yes, this is _past_ the character; 
    1060               0 :           return NS_OK;
    1061                 :         }
    1062                 :         // else it's an empty text node, or not editable; skip it.
    1063                 :       }
    1064                 :       else  // node is an image or some other thingy that doesn't count as whitespace
    1065                 :       {
    1066               0 :         break;
    1067                 :       }
    1068                 :     }
    1069               0 :     tmp = node;
    1070               0 :     node = NextNodeInBlock(tmp, kIterForward);
    1071                 :   }
    1072                 :   
    1073               0 :   return NS_OK;
    1074                 : }
    1075                 : 
    1076                 : 
    1077                 : ///////////////////////////////////////////////////////////////////////////
    1078                 : // IsPrevCharWhitespace: checks the adjacent content in the same block
    1079                 : //                       to see if following selection is whitespace
    1080                 : nsresult 
    1081               0 : nsHTMLEditor::IsPrevCharWhitespace(nsIDOMNode *aParentNode, 
    1082                 :                                    PRInt32 aOffset,
    1083                 :                                    bool *outIsSpace,
    1084                 :                                    bool *outIsNBSP,
    1085                 :                                    nsCOMPtr<nsIDOMNode> *outNode,
    1086                 :                                    PRInt32 *outOffset)
    1087                 : {
    1088               0 :   NS_ENSURE_TRUE(outIsSpace && outIsNBSP, NS_ERROR_NULL_POINTER);
    1089               0 :   *outIsSpace = false;
    1090               0 :   *outIsNBSP = false;
    1091               0 :   if (outNode) *outNode = nsnull;
    1092               0 :   if (outOffset) *outOffset = -1;
    1093                 :   
    1094               0 :   nsAutoString tempString;
    1095                 :   PRUint32 strLength;
    1096               0 :   nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aParentNode);
    1097               0 :   if (textNode)
    1098                 :   {
    1099               0 :     if (aOffset > 0)
    1100                 :     {
    1101                 :       // easy case: prev char is in same node
    1102               0 :       textNode->SubstringData(aOffset-1,aOffset,tempString);
    1103               0 :       *outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
    1104               0 :       *outIsNBSP = (tempString.First() == nbsp);
    1105               0 :       if (outNode) *outNode = do_QueryInterface(aParentNode);
    1106               0 :       if (outOffset) *outOffset = aOffset-1;  
    1107               0 :       return NS_OK;
    1108                 :     }
    1109                 :   }
    1110                 :   
    1111                 :   // harder case: prev char in next node
    1112               0 :   nsCOMPtr<nsIDOMNode> node = NextNodeInBlock(aParentNode, kIterBackward);
    1113               0 :   nsCOMPtr<nsIDOMNode> tmp;
    1114               0 :   while (node) 
    1115                 :   {
    1116               0 :     bool isBlock (false);
    1117               0 :     NodeIsBlock(node, &isBlock);
    1118               0 :     if (isBlock)  // skip over bold, italic, link, ect nodes
    1119                 :     {
    1120               0 :       if (IsTextNode(node) && IsEditable(node))
    1121                 :       {
    1122               0 :         textNode = do_QueryInterface(node);
    1123               0 :         textNode->GetLength(&strLength);
    1124               0 :         if (strLength)
    1125                 :         {
    1126                 :           // you could use nsIContent::TextIsOnlyWhitespace here
    1127               0 :           textNode->SubstringData(strLength-1,strLength,tempString);
    1128               0 :           *outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
    1129               0 :           *outIsNBSP = (tempString.First() == nbsp);
    1130               0 :           if (outNode) *outNode = do_QueryInterface(aParentNode);
    1131               0 :           if (outOffset) *outOffset = strLength-1;  
    1132               0 :           return NS_OK;
    1133                 :         }
    1134                 :         // else it's an empty text node, or not editable; skip it.
    1135                 :       }
    1136                 :       else  // node is an image or some other thingy that doesn't count as whitespace
    1137                 :       {
    1138               0 :         break;
    1139                 :       }
    1140                 :     }
    1141                 :     // otherwise we found a node we want to skip, keep going
    1142               0 :     tmp = node;
    1143               0 :     node = NextNodeInBlock(tmp, kIterBackward);
    1144                 :   }
    1145                 :   
    1146               0 :   return NS_OK;
    1147                 :   
    1148                 : }
    1149                 : 
    1150                 : 
    1151                 : 
    1152                 : /* ------------ End Block methods -------------- */
    1153                 : 
    1154                 : 
    1155               0 : bool nsHTMLEditor::IsVisBreak(nsIDOMNode *aNode)
    1156                 : {
    1157               0 :   NS_ENSURE_TRUE(aNode, false);
    1158               0 :   if (!nsTextEditUtils::IsBreak(aNode)) 
    1159               0 :     return false;
    1160                 :   // check if there is a later node in block after br
    1161               0 :   nsCOMPtr<nsIDOMNode> priorNode, nextNode;
    1162               0 :   GetPriorHTMLNode(aNode, address_of(priorNode), true); 
    1163               0 :   GetNextHTMLNode(aNode, address_of(nextNode), true); 
    1164                 :   // if we are next to another break, we are visible
    1165               0 :   if (priorNode && nsTextEditUtils::IsBreak(priorNode))
    1166               0 :     return true;
    1167               0 :   if (nextNode && nsTextEditUtils::IsBreak(nextNode))
    1168               0 :     return true;
    1169                 :   
    1170                 :   // if we are right before block boundary, then br not visible
    1171               0 :   NS_ENSURE_TRUE(nextNode, false);  // this break is trailer in block, it's not visible
    1172               0 :   if (IsBlockNode(nextNode))
    1173               0 :     return false; // break is right before a block, it's not visible
    1174                 :     
    1175                 :   // sigh.  We have to use expensive whitespace calculation code to 
    1176                 :   // determine what is going on
    1177               0 :   nsCOMPtr<nsIDOMNode> selNode, tmp;
    1178                 :   PRInt32 selOffset;
    1179               0 :   GetNodeLocation(aNode, address_of(selNode), &selOffset);
    1180               0 :   selOffset++; // lets look after the break
    1181               0 :   nsWSRunObject wsObj(this, selNode, selOffset);
    1182               0 :   nsCOMPtr<nsIDOMNode> visNode;
    1183               0 :   PRInt32 visOffset=0;
    1184               0 :   PRInt16 visType=0;
    1185               0 :   wsObj.NextVisibleNode(selNode, selOffset, address_of(visNode), &visOffset, &visType);
    1186               0 :   if (visType & nsWSRunObject::eBlock)
    1187               0 :     return false;
    1188                 :   
    1189               0 :   return true;
    1190                 : }
    1191                 : 
    1192                 : NS_IMETHODIMP
    1193               0 : nsHTMLEditor::BreakIsVisible(nsIDOMNode *aNode, bool *aIsVisible)
    1194                 : {
    1195               0 :   NS_ENSURE_ARG_POINTER(aNode && aIsVisible);
    1196                 : 
    1197               0 :   *aIsVisible = IsVisBreak(aNode);
    1198                 : 
    1199               0 :   return NS_OK;
    1200                 : }
    1201                 : 
    1202                 : 
    1203                 : NS_IMETHODIMP
    1204               0 : nsHTMLEditor::GetIsDocumentEditable(bool *aIsDocumentEditable)
    1205                 : {
    1206               0 :   NS_ENSURE_ARG_POINTER(aIsDocumentEditable);
    1207                 : 
    1208               0 :   nsCOMPtr<nsIDOMDocument> doc;
    1209               0 :   GetDocument(getter_AddRefs(doc));
    1210               0 :   *aIsDocumentEditable = doc ? IsModifiable() : false;
    1211                 : 
    1212               0 :   return NS_OK;
    1213                 : }
    1214                 : 
    1215               0 : bool nsHTMLEditor::IsModifiable()
    1216                 : {
    1217               0 :   return !IsReadonly();
    1218                 : }
    1219                 : 
    1220                 : NS_IMETHODIMP
    1221               0 : nsHTMLEditor::UpdateBaseURL()
    1222                 : {
    1223               0 :   nsCOMPtr<nsIDOMDocument> domDoc;
    1224               0 :   GetDocument(getter_AddRefs(domDoc));
    1225               0 :   NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
    1226                 : 
    1227                 :   // Look for an HTML <base> tag
    1228               0 :   nsCOMPtr<nsIDOMNodeList> nodeList;
    1229               0 :   nsresult rv = domDoc->GetElementsByTagName(NS_LITERAL_STRING("base"), getter_AddRefs(nodeList));
    1230               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1231                 : 
    1232               0 :   nsCOMPtr<nsIDOMNode> baseNode;
    1233               0 :   if (nodeList)
    1234                 :   {
    1235                 :     PRUint32 count;
    1236               0 :     nodeList->GetLength(&count);
    1237               0 :     if (count >= 1)
    1238                 :     {
    1239               0 :       rv = nodeList->Item(0, getter_AddRefs(baseNode));
    1240               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1241                 :     }
    1242                 :   }
    1243                 :   // If no base tag, then set baseURL to the document's URL
    1244                 :   // This is very important, else relative URLs for links and images are wrong
    1245               0 :   if (!baseNode)
    1246                 :   {
    1247               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
    1248               0 :     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    1249                 : 
    1250               0 :     return doc->SetBaseURI(doc->GetDocumentURI());
    1251                 :   }
    1252               0 :   return NS_OK;
    1253                 : }
    1254                 : 
    1255                 : /* This routine is needed to provide a bottleneck for typing for logging
    1256                 :    purposes.  Can't use HandleKeyPress() (above) for that since it takes
    1257                 :    a nsIDOMKeyEvent* parameter.  So instead we pass enough info through
    1258                 :    to TypedText() to determine what action to take, but without passing
    1259                 :    an event.
    1260                 :    */
    1261               0 : NS_IMETHODIMP nsHTMLEditor::TypedText(const nsAString& aString,
    1262                 :                                       PRInt32 aAction)
    1263                 : {
    1264               0 :   nsAutoPlaceHolderBatch batch(this, nsGkAtoms::TypingTxnName);
    1265                 : 
    1266               0 :   switch (aAction)
    1267                 :   {
    1268                 :     case eTypedText:
    1269                 :     case eTypedBreak:
    1270                 :       {
    1271               0 :         return nsPlaintextEditor::TypedText(aString, aAction);
    1272                 :       }
    1273                 :     case eTypedBR:
    1274                 :       {
    1275               0 :         nsCOMPtr<nsIDOMNode> brNode;
    1276               0 :         return InsertBR(address_of(brNode));  // only inserts a br node
    1277                 :       }
    1278                 :   } 
    1279               0 :   return NS_ERROR_FAILURE; 
    1280                 : }
    1281                 : 
    1282               0 : NS_IMETHODIMP nsHTMLEditor::TabInTable(bool inIsShift, bool *outHandled)
    1283                 : {
    1284               0 :   NS_ENSURE_TRUE(outHandled, NS_ERROR_NULL_POINTER);
    1285               0 :   *outHandled = false;
    1286                 : 
    1287                 :   // Find enclosing table cell from the selection (cell may be the selected element)
    1288               0 :   nsCOMPtr<nsIDOMElement> cellElement;
    1289                 :     // can't use |NS_LITERAL_STRING| here until |GetElementOrParentByTagName| is fixed to accept readables
    1290               0 :   nsresult res = GetElementOrParentByTagName(NS_LITERAL_STRING("td"), nsnull, getter_AddRefs(cellElement));
    1291               0 :   NS_ENSURE_SUCCESS(res, res);
    1292                 :   // Do nothing -- we didn't find a table cell
    1293               0 :   NS_ENSURE_TRUE(cellElement, NS_OK);
    1294                 : 
    1295                 :   // find enclosing table
    1296               0 :   nsCOMPtr<nsIDOMNode> tbl = GetEnclosingTable(cellElement);
    1297               0 :   NS_ENSURE_TRUE(tbl, res);
    1298                 : 
    1299                 :   // advance to next cell
    1300                 :   // first create an iterator over the table
    1301                 :   nsCOMPtr<nsIContentIterator> iter =
    1302               0 :       do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res);
    1303               0 :   NS_ENSURE_SUCCESS(res, res);
    1304               0 :   NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
    1305               0 :   nsCOMPtr<nsIContent> cTbl = do_QueryInterface(tbl);
    1306               0 :   nsCOMPtr<nsIContent> cBlock = do_QueryInterface(cellElement);
    1307               0 :   res = iter->Init(cTbl);
    1308               0 :   NS_ENSURE_SUCCESS(res, res);
    1309                 :   // position iter at block
    1310               0 :   res = iter->PositionAt(cBlock);
    1311               0 :   NS_ENSURE_SUCCESS(res, res);
    1312                 : 
    1313               0 :   nsCOMPtr<nsIDOMNode> node;
    1314               0 :   do
    1315                 :   {
    1316               0 :     if (inIsShift)
    1317               0 :       iter->Prev();
    1318                 :     else
    1319               0 :       iter->Next();
    1320                 : 
    1321               0 :     node = do_QueryInterface(iter->GetCurrentNode());
    1322                 : 
    1323               0 :     if (node && nsHTMLEditUtils::IsTableCell(node) &&
    1324               0 :         GetEnclosingTable(node) == tbl)
    1325                 :     {
    1326               0 :       res = CollapseSelectionToDeepestNonTableFirstChild(nsnull, node);
    1327               0 :       NS_ENSURE_SUCCESS(res, res);
    1328               0 :       *outHandled = true;
    1329               0 :       return NS_OK;
    1330                 :     }
    1331               0 :   } while (!iter->IsDone());
    1332                 :   
    1333               0 :   if (!(*outHandled) && !inIsShift)
    1334                 :   {
    1335                 :     // if we havent handled it yet then we must have run off the end of
    1336                 :     // the table.  Insert a new row.
    1337               0 :     res = InsertTableRow(1, true);
    1338               0 :     NS_ENSURE_SUCCESS(res, res);
    1339               0 :     *outHandled = true;
    1340                 :     // put selection in right place
    1341                 :     // Use table code to get selection and index to new row...
    1342               0 :     nsCOMPtr<nsISelection>selection;
    1343               0 :     nsCOMPtr<nsIDOMElement> tblElement;
    1344               0 :     nsCOMPtr<nsIDOMElement> cell;
    1345                 :     PRInt32 row;
    1346               0 :     res = GetCellContext(getter_AddRefs(selection), 
    1347               0 :                          getter_AddRefs(tblElement),
    1348               0 :                          getter_AddRefs(cell), 
    1349                 :                          nsnull, nsnull,
    1350               0 :                          &row, nsnull);
    1351               0 :     NS_ENSURE_SUCCESS(res, res);
    1352                 :     // ...so that we can ask for first cell in that row...
    1353               0 :     res = GetCellAt(tblElement, row, 0, getter_AddRefs(cell));
    1354               0 :     NS_ENSURE_SUCCESS(res, res);
    1355                 :     // ...and then set selection there.
    1356                 :     // (Note that normally you should use CollapseSelectionToDeepestNonTableFirstChild(),
    1357                 :     //  but we know cell is an empty new cell, so this works fine)
    1358               0 :     node = do_QueryInterface(cell);
    1359               0 :     if (node) selection->Collapse(node,0);
    1360               0 :     return NS_OK;
    1361                 :   }
    1362                 :   
    1363               0 :   return res;
    1364                 : }
    1365                 : 
    1366               0 : NS_IMETHODIMP nsHTMLEditor::CreateBR(nsIDOMNode *aNode, PRInt32 aOffset, nsCOMPtr<nsIDOMNode> *outBRNode, EDirection aSelect)
    1367                 : {
    1368               0 :   nsCOMPtr<nsIDOMNode> parent = aNode;
    1369               0 :   PRInt32 offset = aOffset;
    1370               0 :   return CreateBRImpl(address_of(parent), &offset, outBRNode, aSelect);
    1371                 : }
    1372                 : 
    1373                 : nsresult 
    1374               0 : nsHTMLEditor::CollapseSelectionToDeepestNonTableFirstChild(nsISelection *aSelection, nsIDOMNode *aNode)
    1375                 : {
    1376               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    1377                 :   nsresult res;
    1378                 : 
    1379               0 :   nsCOMPtr<nsISelection> selection;
    1380               0 :   if (aSelection)
    1381                 :   {
    1382               0 :     selection = aSelection;
    1383                 :   } else {
    1384               0 :     res = GetSelection(getter_AddRefs(selection));
    1385               0 :     NS_ENSURE_SUCCESS(res, res);
    1386               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    1387                 :   }
    1388               0 :   nsCOMPtr<nsIDOMNode> node = aNode;
    1389               0 :   nsCOMPtr<nsIDOMNode> child;
    1390                 :   
    1391               0 :   do {
    1392               0 :     node->GetFirstChild(getter_AddRefs(child));
    1393                 :     
    1394               0 :     if (child)
    1395                 :     {
    1396                 :       // Stop if we find a table
    1397                 :       // don't want to go into nested tables
    1398               0 :       if (nsHTMLEditUtils::IsTable(child)) break;
    1399                 :       // hey, it'g gotta be a container too!
    1400               0 :       if (!IsContainer(child)) break;
    1401               0 :       node = child;
    1402                 :     }
    1403                 :   }
    1404               0 :   while (child);
    1405                 : 
    1406               0 :   selection->Collapse(node,0);
    1407               0 :   return NS_OK;
    1408                 : }
    1409                 : 
    1410                 : 
    1411                 : // This is mostly like InsertHTMLWithCharsetAndContext, 
    1412                 : //  but we can't use that because it is selection-based and 
    1413                 : //  the rules code won't let us edit under the <head> node
    1414                 : NS_IMETHODIMP
    1415               0 : nsHTMLEditor::ReplaceHeadContentsWithHTML(const nsAString& aSourceToInsert)
    1416                 : {
    1417               0 :   nsAutoRules beginRulesSniffing(this, kOpIgnore, nsIEditor::eNone); // don't do any post processing, rules get confused
    1418               0 :   nsCOMPtr<nsISelection> selection;
    1419               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    1420               0 :   NS_ENSURE_SUCCESS(res, res);
    1421               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1422                 : 
    1423               0 :   ForceCompositionEnd();
    1424                 : 
    1425                 :   // Do not use nsAutoRules -- rules code won't let us insert in <head>
    1426                 :   // Use the head node as a parent and delete/insert directly
    1427               0 :   nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
    1428               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
    1429                 : 
    1430               0 :   nsCOMPtr<nsIDOMNodeList>nodeList; 
    1431               0 :   res = doc->GetElementsByTagName(NS_LITERAL_STRING("head"), getter_AddRefs(nodeList));
    1432               0 :   NS_ENSURE_SUCCESS(res, res);
    1433               0 :   NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER);
    1434                 : 
    1435                 :   PRUint32 count; 
    1436               0 :   nodeList->GetLength(&count);
    1437               0 :   if (count < 1) return NS_ERROR_FAILURE;
    1438                 : 
    1439               0 :   nsCOMPtr<nsIDOMNode> headNode;
    1440               0 :   res = nodeList->Item(0, getter_AddRefs(headNode)); 
    1441               0 :   NS_ENSURE_SUCCESS(res, res);
    1442               0 :   NS_ENSURE_TRUE(headNode, NS_ERROR_NULL_POINTER);
    1443                 : 
    1444                 :   // First, make sure there are no return chars in the source.
    1445                 :   // Bad things happen if you insert returns (instead of dom newlines, \n)
    1446                 :   // into an editor document.
    1447               0 :   nsAutoString inputString (aSourceToInsert);  // hope this does copy-on-write
    1448                 :  
    1449                 :   // Windows linebreaks: Map CRLF to LF:
    1450               0 :   inputString.ReplaceSubstring(NS_LITERAL_STRING("\r\n").get(),
    1451               0 :                                NS_LITERAL_STRING("\n").get());
    1452                 :  
    1453                 :   // Mac linebreaks: Map any remaining CR to LF:
    1454               0 :   inputString.ReplaceSubstring(NS_LITERAL_STRING("\r").get(),
    1455               0 :                                NS_LITERAL_STRING("\n").get());
    1456                 : 
    1457               0 :   nsAutoEditBatch beginBatching(this);
    1458                 : 
    1459               0 :   res = GetSelection(getter_AddRefs(selection));
    1460               0 :   NS_ENSURE_SUCCESS(res, res);
    1461               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1462                 : 
    1463                 :   // Get the first range in the selection, for context:
    1464               0 :   nsCOMPtr<nsIDOMRange> range;
    1465               0 :   res = selection->GetRangeAt(0, getter_AddRefs(range));
    1466               0 :   NS_ENSURE_SUCCESS(res, res);
    1467                 : 
    1468               0 :   nsCOMPtr<nsIDOMDocumentFragment> docfrag;
    1469               0 :   res = range->CreateContextualFragment(inputString,
    1470               0 :                                         getter_AddRefs(docfrag));
    1471                 : 
    1472                 :   //XXXX BUG 50965: This is not returning the text between <title> ... </title>
    1473                 :   // Special code is needed in JS to handle title anyway, so it really doesn't matter!
    1474                 : 
    1475               0 :   if (NS_FAILED(res))
    1476                 :   {
    1477                 : #ifdef DEBUG
    1478               0 :     printf("Couldn't create contextual fragment: error was %d\n", res);
    1479                 : #endif
    1480               0 :     return res;
    1481                 :   }
    1482               0 :   NS_ENSURE_TRUE(docfrag, NS_ERROR_NULL_POINTER);
    1483                 : 
    1484               0 :   nsCOMPtr<nsIDOMNode> child;
    1485                 : 
    1486                 :   // First delete all children in head
    1487               0 :   do {
    1488               0 :     res = headNode->GetFirstChild(getter_AddRefs(child));
    1489               0 :     NS_ENSURE_SUCCESS(res, res);
    1490               0 :     if (child)
    1491                 :     {
    1492               0 :       res = DeleteNode(child);
    1493               0 :       NS_ENSURE_SUCCESS(res, res);
    1494                 :     }
    1495               0 :   } while (child);
    1496                 : 
    1497                 :   // Now insert the new nodes
    1498               0 :   PRInt32 offsetOfNewNode = 0;
    1499               0 :   nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
    1500                 : 
    1501                 :   // Loop over the contents of the fragment and move into the document
    1502               0 :   do {
    1503               0 :     res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
    1504               0 :     NS_ENSURE_SUCCESS(res, res);
    1505               0 :     if (child)
    1506                 :     {
    1507               0 :       res = InsertNode(child, headNode, offsetOfNewNode++);
    1508               0 :       NS_ENSURE_SUCCESS(res, res);
    1509                 :     }
    1510               0 :   } while (child);
    1511                 : 
    1512               0 :   return res;
    1513                 : }
    1514                 : 
    1515                 : NS_IMETHODIMP
    1516               0 : nsHTMLEditor::RebuildDocumentFromSource(const nsAString& aSourceString)
    1517                 : {
    1518               0 :   ForceCompositionEnd();
    1519                 : 
    1520               0 :   nsCOMPtr<nsISelection>selection;
    1521               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    1522               0 :   NS_ENSURE_SUCCESS(res, res);
    1523                 : 
    1524               0 :   nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
    1525               0 :   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
    1526                 : 
    1527                 :   // Find where the <body> tag starts.
    1528               0 :   nsReadingIterator<PRUnichar> beginbody;
    1529               0 :   nsReadingIterator<PRUnichar> endbody;
    1530               0 :   aSourceString.BeginReading(beginbody);
    1531               0 :   aSourceString.EndReading(endbody);
    1532               0 :   bool foundbody = CaseInsensitiveFindInReadable(NS_LITERAL_STRING("<body"),
    1533               0 :                                                    beginbody, endbody);
    1534                 : 
    1535               0 :   nsReadingIterator<PRUnichar> beginhead;
    1536               0 :   nsReadingIterator<PRUnichar> endhead;
    1537               0 :   aSourceString.BeginReading(beginhead);
    1538               0 :   aSourceString.EndReading(endhead);
    1539               0 :   bool foundhead = CaseInsensitiveFindInReadable(NS_LITERAL_STRING("<head"),
    1540               0 :                                                    beginhead, endhead);
    1541                 : 
    1542               0 :   nsReadingIterator<PRUnichar> beginclosehead;
    1543               0 :   nsReadingIterator<PRUnichar> endclosehead;
    1544               0 :   aSourceString.BeginReading(beginclosehead);
    1545               0 :   aSourceString.EndReading(endclosehead);
    1546                 : 
    1547                 :   // Find the index after "<head>"
    1548                 :   bool foundclosehead = CaseInsensitiveFindInReadable(
    1549               0 :            NS_LITERAL_STRING("</head>"), beginclosehead, endclosehead);
    1550                 :   
    1551                 :   // Time to change the document
    1552               0 :   nsAutoEditBatch beginBatching(this);
    1553                 : 
    1554               0 :   nsReadingIterator<PRUnichar> endtotal;
    1555               0 :   aSourceString.EndReading(endtotal);
    1556                 : 
    1557               0 :   if (foundhead) {
    1558               0 :     if (foundclosehead)
    1559               0 :       res = ReplaceHeadContentsWithHTML(Substring(beginhead, beginclosehead));
    1560               0 :     else if (foundbody)
    1561               0 :       res = ReplaceHeadContentsWithHTML(Substring(beginhead, beginbody));
    1562                 :     else
    1563                 :       // XXX Without recourse to some parser/content sink/docshell hackery
    1564                 :       // we don't really know where the head ends and the body begins
    1565                 :       // so we assume that there is no body
    1566               0 :       res = ReplaceHeadContentsWithHTML(Substring(beginhead, endtotal));
    1567                 :   } else {
    1568               0 :     nsReadingIterator<PRUnichar> begintotal;
    1569               0 :     aSourceString.BeginReading(begintotal);
    1570               0 :     NS_NAMED_LITERAL_STRING(head, "<head>");
    1571               0 :     if (foundclosehead)
    1572               0 :       res = ReplaceHeadContentsWithHTML(head + Substring(begintotal, beginclosehead));
    1573               0 :     else if (foundbody)
    1574               0 :       res = ReplaceHeadContentsWithHTML(head + Substring(begintotal, beginbody));
    1575                 :     else
    1576                 :       // XXX Without recourse to some parser/content sink/docshell hackery
    1577                 :       // we don't really know where the head ends and the body begins
    1578                 :       // so we assume that there is no head
    1579               0 :       res = ReplaceHeadContentsWithHTML(head);
    1580                 :   }
    1581               0 :   NS_ENSURE_SUCCESS(res, res);
    1582                 : 
    1583               0 :   res = SelectAll();
    1584               0 :   NS_ENSURE_SUCCESS(res, res);
    1585                 : 
    1586               0 :   if (!foundbody) {
    1587               0 :     NS_NAMED_LITERAL_STRING(body, "<body>");
    1588                 :     // XXX Without recourse to some parser/content sink/docshell hackery
    1589                 :     // we don't really know where the head ends and the body begins
    1590               0 :     if (foundclosehead) // assume body starts after the head ends
    1591               0 :       res = LoadHTML(body + Substring(endclosehead, endtotal));
    1592               0 :     else if (foundhead) // assume there is no body
    1593               0 :       res = LoadHTML(body);
    1594                 :     else // assume there is no head, the entire source is body
    1595               0 :       res = LoadHTML(body + aSourceString);
    1596               0 :     NS_ENSURE_SUCCESS(res, res);
    1597                 : 
    1598               0 :     nsCOMPtr<nsIDOMElement> divElement;
    1599               0 :     res = CreateElementWithDefaults(NS_LITERAL_STRING("div"), getter_AddRefs(divElement));
    1600               0 :     NS_ENSURE_SUCCESS(res, res);
    1601                 : 
    1602               0 :     res = CloneAttributes(bodyElement, divElement);
    1603               0 :     NS_ENSURE_SUCCESS(res, res);
    1604                 : 
    1605               0 :     return BeginningOfDocument();
    1606                 :   }
    1607                 : 
    1608               0 :   res = LoadHTML(Substring(beginbody, endtotal));
    1609               0 :   NS_ENSURE_SUCCESS(res, res);
    1610                 : 
    1611                 :   // Now we must copy attributes user might have edited on the <body> tag
    1612                 :   //  because InsertHTML (actually, CreateContextualFragment()) 
    1613                 :   //  will never return a body node in the DOM fragment
    1614                 :   
    1615                 :   // We already know where "<body" begins
    1616               0 :   nsReadingIterator<PRUnichar> beginclosebody = beginbody;
    1617               0 :   nsReadingIterator<PRUnichar> endclosebody;
    1618               0 :   aSourceString.EndReading(endclosebody);
    1619               0 :   if (!FindInReadable(NS_LITERAL_STRING(">"),beginclosebody,endclosebody))
    1620               0 :     return NS_ERROR_FAILURE;
    1621                 : 
    1622                 :   // Truncate at the end of the body tag
    1623                 :   // Kludge of the year: fool the parser by replacing "body" with "div" so we get a node
    1624               0 :   nsAutoString bodyTag;
    1625               0 :   bodyTag.AssignLiteral("<div ");
    1626               0 :   bodyTag.Append(Substring(endbody, endclosebody));
    1627                 : 
    1628               0 :   nsCOMPtr<nsIDOMRange> range;
    1629               0 :   res = selection->GetRangeAt(0, getter_AddRefs(range));
    1630               0 :   NS_ENSURE_SUCCESS(res, res);
    1631                 : 
    1632               0 :   nsCOMPtr<nsIDOMDocumentFragment> docfrag;
    1633               0 :   res = range->CreateContextualFragment(bodyTag, getter_AddRefs(docfrag));
    1634               0 :   NS_ENSURE_SUCCESS(res, res);
    1635                 : 
    1636               0 :   nsCOMPtr<nsIDOMNode> fragmentAsNode (do_QueryInterface(docfrag));
    1637               0 :   NS_ENSURE_TRUE(fragmentAsNode, NS_ERROR_NULL_POINTER);
    1638                 :   
    1639               0 :   nsCOMPtr<nsIDOMNode> child;
    1640               0 :   res = fragmentAsNode->GetFirstChild(getter_AddRefs(child));
    1641               0 :   NS_ENSURE_SUCCESS(res, res);
    1642               0 :   NS_ENSURE_TRUE(child, NS_ERROR_NULL_POINTER);
    1643                 :   
    1644                 :   // Copy all attributes from the div child to current body element
    1645               0 :   res = CloneAttributes(bodyElement, child);
    1646               0 :   NS_ENSURE_SUCCESS(res, res);
    1647                 :   
    1648                 :   // place selection at first editable content
    1649               0 :   return BeginningOfDocument();
    1650                 : }
    1651                 : 
    1652                 : void
    1653               0 : nsHTMLEditor::NormalizeEOLInsertPosition(nsIDOMNode *firstNodeToInsert,
    1654                 :                                      nsCOMPtr<nsIDOMNode> *insertParentNode,
    1655                 :                                      PRInt32 *insertOffset)
    1656                 : {
    1657                 :   /*
    1658                 :     This function will either correct the position passed in,
    1659                 :     or leave the position unchanged.
    1660                 : 
    1661                 :     When the (first) item to insert is a block level element, 
    1662                 :     and our insertion position is after the last visible item in a line, 
    1663                 :     i.e. the insertion position is just before a visible line break <br>, 
    1664                 :     we want to skip to the position just after the line break (see bug 68767)
    1665                 : 
    1666                 :     However, our logic to detect whether we should skip or not
    1667                 :     needs to be more clever.
    1668                 :     We must not skip when the caret appears to be positioned at the beginning
    1669                 :     of a block, in that case skipping the <br> would not insert the <br>
    1670                 :     at the caret position, but after the current empty line.
    1671                 :      
    1672                 :     So we have several cases to test:
    1673                 :      
    1674                 :     1) We only ever want to skip, if the next visible thing after the current position is a break
    1675                 :      
    1676                 :     2) We do not want to skip if there is no previous visible thing at all
    1677                 :        That is detected if the call to PriorVisibleNode gives us an offset of zero.
    1678                 :        Because PriorVisibleNode always positions after the prior node, we would
    1679                 :        see an offset > 0, if there were a prior node.
    1680                 :      
    1681                 :     3) We do not want to skip, if both the next and the previous visible things are breaks.
    1682                 :     
    1683                 :     4) We do not want to skip if the previous visible thing is in a different block
    1684                 :        than the insertion position.
    1685                 :   */
    1686                 : 
    1687               0 :   if (!IsBlockNode(firstNodeToInsert))
    1688               0 :     return;
    1689                 : 
    1690               0 :   nsWSRunObject wsObj(this, *insertParentNode, *insertOffset);
    1691               0 :   nsCOMPtr<nsIDOMNode> nextVisNode;
    1692               0 :   nsCOMPtr<nsIDOMNode> prevVisNode;
    1693               0 :   PRInt32 nextVisOffset=0;
    1694               0 :   PRInt16 nextVisType=0;
    1695               0 :   PRInt32 prevVisOffset=0;
    1696               0 :   PRInt16 prevVisType=0;
    1697                 : 
    1698               0 :   wsObj.NextVisibleNode(*insertParentNode, *insertOffset, address_of(nextVisNode), &nextVisOffset, &nextVisType);
    1699               0 :   if (!nextVisNode)
    1700                 :     return;
    1701                 : 
    1702               0 :   if (! (nextVisType & nsWSRunObject::eBreak))
    1703                 :     return;
    1704                 : 
    1705               0 :   wsObj.PriorVisibleNode(*insertParentNode, *insertOffset, address_of(prevVisNode), &prevVisOffset, &prevVisType);
    1706               0 :   if (!prevVisNode)
    1707                 :     return;
    1708                 : 
    1709               0 :   if (prevVisType & nsWSRunObject::eBreak)
    1710                 :     return;
    1711                 : 
    1712               0 :   if (prevVisType & nsWSRunObject::eThisBlock)
    1713                 :     return;
    1714                 : 
    1715               0 :   nsCOMPtr<nsIDOMNode> brNode;
    1716               0 :   PRInt32 brOffset=0;
    1717                 : 
    1718               0 :   GetNodeLocation(nextVisNode, address_of(brNode), &brOffset);
    1719                 : 
    1720               0 :   *insertParentNode = brNode;
    1721               0 :   *insertOffset = brOffset + 1;
    1722                 : }
    1723                 : 
    1724                 : NS_IMETHODIMP
    1725               0 : nsHTMLEditor::InsertElementAtSelection(nsIDOMElement* aElement, bool aDeleteSelection)
    1726                 : {
    1727                 :   // Protect the edit rules object from dying
    1728               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    1729                 : 
    1730               0 :   nsresult res = NS_ERROR_NOT_INITIALIZED;
    1731                 :   
    1732               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    1733                 :   
    1734               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
    1735                 :   
    1736               0 :   ForceCompositionEnd();
    1737               0 :   nsAutoEditBatch beginBatching(this);
    1738               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
    1739                 : 
    1740               0 :   nsCOMPtr<nsISelection>selection;
    1741               0 :   res = GetSelection(getter_AddRefs(selection));
    1742               0 :   if (NS_FAILED(res) || !selection)
    1743               0 :     return NS_ERROR_FAILURE;
    1744                 : 
    1745                 :   // hand off to the rules system, see if it has anything to say about this
    1746                 :   bool cancel, handled;
    1747               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertElement);
    1748               0 :   ruleInfo.insertElement = aElement;
    1749               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1750               0 :   if (cancel || (NS_FAILED(res))) return res;
    1751                 : 
    1752               0 :   if (!handled)
    1753                 :   {
    1754               0 :     if (aDeleteSelection)
    1755                 :     {
    1756               0 :       nsCOMPtr<nsIDOMNode> tempNode;
    1757                 :       PRInt32 tempOffset;
    1758               0 :       nsresult result = DeleteSelectionAndPrepareToCreateNode(tempNode,tempOffset);
    1759               0 :       NS_ENSURE_SUCCESS(result, result);
    1760                 :     }
    1761                 : 
    1762                 :     // If deleting, selection will be collapsed.
    1763                 :     // so if not, we collapse it
    1764               0 :     if (!aDeleteSelection)
    1765                 :     {
    1766                 :       // Named Anchor is a special case,
    1767                 :       // We collapse to insert element BEFORE the selection
    1768                 :       // For all other tags, we insert AFTER the selection
    1769               0 :       if (nsHTMLEditUtils::IsNamedAnchor(node))
    1770                 :       {
    1771               0 :         selection->CollapseToStart();
    1772                 :       } else {
    1773               0 :         selection->CollapseToEnd();
    1774                 :       }
    1775                 :     }
    1776                 : 
    1777               0 :     nsCOMPtr<nsIDOMNode> parentSelectedNode;
    1778                 :     PRInt32 offsetForInsert;
    1779               0 :     res = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
    1780                 :     // XXX: ERROR_HANDLING bad XPCOM usage
    1781               0 :     if (NS_SUCCEEDED(res) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetForInsert)) && parentSelectedNode)
    1782                 :     {
    1783                 : #ifdef DEBUG_cmanske
    1784                 :       {
    1785                 :       nsAutoString name;
    1786                 :       parentSelectedNode->GetNodeName(name);
    1787                 :       printf("InsertElement: Anchor node of selection: ");
    1788                 :       wprintf(name.get());
    1789                 :       printf(" Offset: %d\n", offsetForInsert);
    1790                 :       }
    1791                 : #endif
    1792                 : 
    1793                 :       // Adjust position based on the node we are going to insert.
    1794               0 :       NormalizeEOLInsertPosition(node, address_of(parentSelectedNode), &offsetForInsert);
    1795                 : 
    1796               0 :       res = InsertNodeAtPoint(node, address_of(parentSelectedNode), &offsetForInsert, false);
    1797               0 :       NS_ENSURE_SUCCESS(res, res);
    1798                 :       // Set caret after element, but check for special case 
    1799                 :       //  of inserting table-related elements: set in first cell instead
    1800               0 :       if (!SetCaretInTableCell(aElement))
    1801                 :       {
    1802               0 :         res = SetCaretAfterElement(aElement);
    1803               0 :         NS_ENSURE_SUCCESS(res, res);
    1804                 :       }
    1805                 :       // check for inserting a whole table at the end of a block. If so insert a br after it.
    1806               0 :       if (nsHTMLEditUtils::IsTable(node))
    1807                 :       {
    1808                 :         bool isLast;
    1809               0 :         res = IsLastEditableChild(node, &isLast);
    1810               0 :         NS_ENSURE_SUCCESS(res, res);
    1811               0 :         if (isLast)
    1812                 :         {
    1813               0 :           nsCOMPtr<nsIDOMNode> brNode;
    1814               0 :           res = CreateBR(parentSelectedNode, offsetForInsert+1, address_of(brNode));
    1815               0 :           NS_ENSURE_SUCCESS(res, res);
    1816               0 :           selection->Collapse(parentSelectedNode, offsetForInsert+1);
    1817                 :         }
    1818                 :       }
    1819                 :     }
    1820                 :   }
    1821               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    1822               0 :   return res;
    1823                 : }
    1824                 : 
    1825                 : 
    1826                 : /* 
    1827                 :   InsertNodeAtPoint: attempts to insert aNode into the document, at a point specified by 
    1828                 :       {*ioParent,*ioOffset}.  Checks with strict dtd to see if containment is allowed.  If not
    1829                 :       allowed, will attempt to find a parent in the parent hierarchy of *ioParent that will
    1830                 :       accept aNode as a child.  If such a parent is found, will split the document tree from
    1831                 :       {*ioParent,*ioOffset} up to parent, and then insert aNode.  ioParent & ioOffset are then
    1832                 :       adjusted to point to the actual location that aNode was inserted at.  aNoEmptyNodes
    1833                 :       specifies if the splitting process is allowed to reslt in empty nodes.
    1834                 :               nsIDOMNode            *aNode           node to insert
    1835                 :               nsCOMPtr<nsIDOMNode>  *ioParent        insertion parent
    1836                 :               PRInt32               *ioOffset        insertion offset
    1837                 :               bool                  aNoEmptyNodes    splitting can result in empty nodes?
    1838                 : */
    1839                 : nsresult
    1840               0 : nsHTMLEditor::InsertNodeAtPoint(nsIDOMNode *aNode, 
    1841                 :                                 nsCOMPtr<nsIDOMNode> *ioParent, 
    1842                 :                                 PRInt32 *ioOffset, 
    1843                 :                                 bool aNoEmptyNodes)
    1844                 : {
    1845               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    1846               0 :   NS_ENSURE_TRUE(ioParent, NS_ERROR_NULL_POINTER);
    1847               0 :   NS_ENSURE_TRUE(*ioParent, NS_ERROR_NULL_POINTER);
    1848               0 :   NS_ENSURE_TRUE(ioOffset, NS_ERROR_NULL_POINTER);
    1849                 :   
    1850               0 :   nsresult res = NS_OK;
    1851               0 :   nsAutoString tagName;
    1852               0 :   aNode->GetNodeName(tagName);
    1853               0 :   ToLowerCase(tagName);
    1854               0 :   nsCOMPtr<nsIDOMNode> parent = *ioParent;
    1855               0 :   nsCOMPtr<nsIDOMNode> topChild = *ioParent;
    1856               0 :   nsCOMPtr<nsIDOMNode> tmp;
    1857               0 :   PRInt32 offsetOfInsert = *ioOffset;
    1858                 :    
    1859                 :   // Search up the parent chain to find a suitable container      
    1860               0 :   while (!CanContainTag(parent, tagName))
    1861                 :   {
    1862                 :     // If the current parent is a root (body or table element)
    1863                 :     // then go no further - we can't insert
    1864               0 :     if (nsTextEditUtils::IsBody(parent) || nsHTMLEditUtils::IsTableElement(parent))
    1865               0 :       return NS_ERROR_FAILURE;
    1866                 :     // Get the next parent
    1867               0 :     parent->GetParentNode(getter_AddRefs(tmp));
    1868               0 :     NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    1869               0 :     topChild = parent;
    1870               0 :     parent = tmp;
    1871                 :   }
    1872               0 :   if (parent != topChild)
    1873                 :   {
    1874                 :     // we need to split some levels above the original selection parent
    1875               0 :     res = SplitNodeDeep(topChild, *ioParent, *ioOffset, &offsetOfInsert, aNoEmptyNodes);
    1876               0 :     NS_ENSURE_SUCCESS(res, res);
    1877               0 :     *ioParent = parent;
    1878               0 :     *ioOffset = offsetOfInsert;
    1879                 :   }
    1880                 :   // Now we can insert the new node
    1881               0 :   res = InsertNode(aNode, parent, offsetOfInsert);
    1882               0 :   return res;
    1883                 : }
    1884                 : 
    1885                 : NS_IMETHODIMP
    1886               0 : nsHTMLEditor::SelectElement(nsIDOMElement* aElement)
    1887                 : {
    1888               0 :   nsresult res = NS_ERROR_NULL_POINTER;
    1889                 : 
    1890                 :   // Must be sure that element is contained in the document body
    1891               0 :   if (IsNodeInActiveEditor(aElement)) {
    1892               0 :     nsCOMPtr<nsISelection> selection;
    1893               0 :     res = GetSelection(getter_AddRefs(selection));
    1894               0 :     NS_ENSURE_SUCCESS(res, res);
    1895               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1896               0 :     nsCOMPtr<nsIDOMNode>parent;
    1897               0 :     res = aElement->GetParentNode(getter_AddRefs(parent));
    1898               0 :     if (NS_SUCCEEDED(res) && parent)
    1899                 :     {
    1900                 :       PRInt32 offsetInParent;
    1901               0 :       res = GetChildOffset(aElement, parent, offsetInParent);
    1902                 : 
    1903               0 :       if (NS_SUCCEEDED(res))
    1904                 :       {
    1905                 :         // Collapse selection to just before desired element,
    1906               0 :         res = selection->Collapse(parent, offsetInParent);
    1907               0 :         if (NS_SUCCEEDED(res)) {
    1908                 :           //  then extend it to just after
    1909               0 :           res = selection->Extend(parent, offsetInParent+1);
    1910                 :         }
    1911                 :       }
    1912                 :     }
    1913                 :   }
    1914               0 :   return res;
    1915                 : }
    1916                 : 
    1917                 : NS_IMETHODIMP
    1918               0 : nsHTMLEditor::SetCaretAfterElement(nsIDOMElement* aElement)
    1919                 : {
    1920               0 :   nsresult res = NS_ERROR_NULL_POINTER;
    1921                 : 
    1922                 :   // Be sure the element is contained in the document body
    1923               0 :   if (aElement && IsNodeInActiveEditor(aElement)) {
    1924               0 :     nsCOMPtr<nsISelection> selection;
    1925               0 :     res = GetSelection(getter_AddRefs(selection));
    1926               0 :     NS_ENSURE_SUCCESS(res, res);
    1927               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1928               0 :     nsCOMPtr<nsIDOMNode>parent;
    1929               0 :     res = aElement->GetParentNode(getter_AddRefs(parent));
    1930               0 :     NS_ENSURE_SUCCESS(res, res);
    1931               0 :     NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
    1932                 :     PRInt32 offsetInParent;
    1933               0 :     res = GetChildOffset(aElement, parent, offsetInParent);
    1934               0 :     if (NS_SUCCEEDED(res))
    1935                 :     {
    1936                 :       // Collapse selection to just after desired element,
    1937               0 :       res = selection->Collapse(parent, offsetInParent+1);
    1938                 : #if 0 //def DEBUG_cmanske
    1939                 :       {
    1940                 :       nsAutoString name;
    1941                 :       parent->GetNodeName(name);
    1942                 :       printf("SetCaretAfterElement: Parent node: ");
    1943                 :       wprintf(name.get());
    1944                 :       printf(" Offset: %d\n\nHTML:\n", offsetInParent+1);
    1945                 :       nsAutoString Format("text/html");
    1946                 :       nsAutoString ContentsAs;
    1947                 :       OutputToString(Format, 2, ContentsAs);
    1948                 :       wprintf(ContentsAs.get());
    1949                 :       }
    1950                 : #endif
    1951                 :     }
    1952                 :   }
    1953               0 :   return res;
    1954                 : }
    1955                 : 
    1956                 : NS_IMETHODIMP 
    1957               0 : nsHTMLEditor::SetParagraphFormat(const nsAString& aParagraphFormat)
    1958                 : {
    1959               0 :   nsAutoString tag; tag.Assign(aParagraphFormat);
    1960               0 :   ToLowerCase(tag);
    1961               0 :   if (tag.EqualsLiteral("dd") || tag.EqualsLiteral("dt"))
    1962               0 :     return MakeDefinitionItem(tag);
    1963                 :   else
    1964               0 :     return InsertBasicBlock(tag);
    1965                 : }
    1966                 : 
    1967                 : NS_IMETHODIMP 
    1968               0 : nsHTMLEditor::GetParagraphState(bool *aMixed, nsAString &outFormat)
    1969                 : {
    1970               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    1971               0 :   NS_ENSURE_TRUE(aMixed, NS_ERROR_NULL_POINTER);
    1972               0 :   nsHTMLEditRules* htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
    1973               0 :   NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
    1974                 :   
    1975               0 :   return htmlRules->GetParagraphState(aMixed, outFormat);
    1976                 : }
    1977                 : 
    1978                 : NS_IMETHODIMP
    1979               0 : nsHTMLEditor::GetBackgroundColorState(bool *aMixed, nsAString &aOutColor)
    1980                 : {
    1981                 :   nsresult res;
    1982               0 :   if (IsCSSEnabled()) {
    1983                 :     // if we are in CSS mode, we have to check if the containing block defines
    1984                 :     // a background color
    1985               0 :     res = GetCSSBackgroundColorState(aMixed, aOutColor, true);
    1986                 :   }
    1987                 :   else {
    1988                 :     // in HTML mode, we look only at page's background
    1989               0 :     res = GetHTMLBackgroundColorState(aMixed, aOutColor);
    1990                 :   }
    1991               0 :   return res;
    1992                 : }
    1993                 : 
    1994                 : NS_IMETHODIMP
    1995               0 : nsHTMLEditor::GetHighlightColorState(bool *aMixed, nsAString &aOutColor)
    1996                 : {
    1997               0 :   nsresult res = NS_OK;
    1998               0 :   *aMixed = false;
    1999               0 :   aOutColor.AssignLiteral("transparent");
    2000               0 :   if (IsCSSEnabled()) {
    2001                 :     // in CSS mode, text background can be added by the Text Highlight button
    2002                 :     // we need to query the background of the selection without looking for
    2003                 :     // the block container of the ranges in the selection
    2004               0 :     res = GetCSSBackgroundColorState(aMixed, aOutColor, false);
    2005                 :   }
    2006               0 :   return res;
    2007                 : }
    2008                 : 
    2009                 : nsresult
    2010               0 : nsHTMLEditor::GetCSSBackgroundColorState(bool *aMixed, nsAString &aOutColor, bool aBlockLevel)
    2011                 : {
    2012               0 :   NS_ENSURE_TRUE(aMixed, NS_ERROR_NULL_POINTER);
    2013               0 :   *aMixed = false;
    2014                 :   // the default background color is transparent
    2015               0 :   aOutColor.AssignLiteral("transparent");
    2016                 :   
    2017                 :   // get selection
    2018               0 :   nsCOMPtr<nsISelection>selection;
    2019               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    2020               0 :   NS_ENSURE_SUCCESS(res, res);
    2021                 : 
    2022                 :   // get selection location
    2023               0 :   nsCOMPtr<nsIDOMNode> parent;
    2024                 :   PRInt32 offset;
    2025               0 :   res = GetStartNodeAndOffset(selection, getter_AddRefs(parent), &offset);
    2026               0 :   NS_ENSURE_SUCCESS(res, res);
    2027               0 :   NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
    2028                 : 
    2029                 :   // is the selection collapsed?
    2030                 :   bool bCollapsed;
    2031               0 :   res = selection->GetIsCollapsed(&bCollapsed);
    2032               0 :   NS_ENSURE_SUCCESS(res, res);
    2033               0 :   nsCOMPtr<nsIDOMNode> nodeToExamine;
    2034               0 :   if (bCollapsed || IsTextNode(parent))
    2035                 :   {
    2036                 :     // we want to look at the parent and ancestors
    2037               0 :     nodeToExamine = parent;
    2038                 :   }
    2039                 :   else
    2040                 :   {
    2041                 :     // otherwise we want to look at the first editable node after
    2042                 :     // {parent,offset} and its ancestors for divs with alignment on them
    2043               0 :     nodeToExamine = GetChildAt(parent, offset);
    2044                 :     //GetNextNode(parent, offset, true, address_of(nodeToExamine));
    2045                 :   }
    2046                 :   
    2047               0 :   NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER);
    2048                 : 
    2049                 :   // is the node to examine a block ?
    2050                 :   bool isBlock;
    2051               0 :   res = NodeIsBlockStatic(nodeToExamine, &isBlock);
    2052               0 :   NS_ENSURE_SUCCESS(res, res);
    2053                 : 
    2054               0 :   nsCOMPtr<nsIDOMNode> tmp;
    2055                 : 
    2056               0 :   if (aBlockLevel) {
    2057                 :     // we are querying the block background (and not the text background), let's
    2058                 :     // climb to the block container
    2059               0 :     nsCOMPtr<nsIDOMNode> blockParent = nodeToExamine;
    2060               0 :     if (!isBlock) {
    2061               0 :       blockParent = GetBlockNodeParent(nodeToExamine);
    2062               0 :       NS_ENSURE_TRUE(blockParent, NS_OK);
    2063                 :     }
    2064                 : 
    2065                 :     // Make sure to not walk off onto the Document node
    2066               0 :     nsCOMPtr<nsIDOMElement> element;
    2067               0 :     do {
    2068                 :       // retrieve the computed style of background-color for blockParent
    2069                 :       mHTMLCSSUtils->GetComputedProperty(blockParent,
    2070                 :                                          nsEditProperty::cssBackgroundColor,
    2071               0 :                                          aOutColor);
    2072               0 :       tmp.swap(blockParent);
    2073               0 :       res = tmp->GetParentNode(getter_AddRefs(blockParent));
    2074               0 :       element = do_QueryInterface(blockParent);
    2075                 :       // look at parent if the queried color is transparent and if the node to
    2076                 :       // examine is not the root of the document
    2077               0 :     } while (aOutColor.EqualsLiteral("transparent") && element);
    2078               0 :     if (aOutColor.EqualsLiteral("transparent")) {
    2079                 :       // we have hit the root of the document and the color is still transparent !
    2080                 :       // Grumble... Let's look at the default background color because that's the
    2081                 :       // color we are looking for
    2082               0 :       mHTMLCSSUtils->GetDefaultBackgroundColor(aOutColor);
    2083                 :     }
    2084                 :   }
    2085                 :   else {
    2086                 :     // no, we are querying the text background for the Text Highlight button
    2087               0 :     if (IsTextNode(nodeToExamine)) {
    2088                 :       // if the node of interest is a text node, let's climb a level
    2089               0 :       res = nodeToExamine->GetParentNode(getter_AddRefs(parent));
    2090               0 :       NS_ENSURE_SUCCESS(res, res);
    2091               0 :       nodeToExamine = parent;
    2092                 :     }
    2093               0 :     do {
    2094                 :       // is the node to examine a block ?
    2095               0 :       res = NodeIsBlockStatic(nodeToExamine, &isBlock);
    2096               0 :       NS_ENSURE_SUCCESS(res, res);
    2097               0 :       if (isBlock) {
    2098                 :         // yes it is a block; in that case, the text background color is transparent
    2099               0 :         aOutColor.AssignLiteral("transparent");
    2100               0 :         break;
    2101                 :       }
    2102                 :       else {
    2103                 :         // no, it's not; let's retrieve the computed style of background-color for the
    2104                 :         // node to examine
    2105                 :         mHTMLCSSUtils->GetComputedProperty(nodeToExamine, nsEditProperty::cssBackgroundColor,
    2106               0 :                             aOutColor);
    2107               0 :         if (!aOutColor.EqualsLiteral("transparent")) {
    2108               0 :           break;
    2109                 :         }
    2110                 :       }
    2111               0 :       tmp.swap(nodeToExamine);
    2112               0 :       res = tmp->GetParentNode(getter_AddRefs(nodeToExamine));
    2113               0 :       NS_ENSURE_SUCCESS(res, res);
    2114               0 :     } while ( aOutColor.EqualsLiteral("transparent") && nodeToExamine );
    2115                 :   }
    2116               0 :   return NS_OK;
    2117                 : }
    2118                 : 
    2119                 : NS_IMETHODIMP 
    2120               0 : nsHTMLEditor::GetHTMLBackgroundColorState(bool *aMixed, nsAString &aOutColor)
    2121                 : {
    2122                 :   //TODO: We don't handle "mixed" correctly!
    2123               0 :   NS_ENSURE_TRUE(aMixed, NS_ERROR_NULL_POINTER);
    2124               0 :   *aMixed = false;
    2125               0 :   aOutColor.Truncate();
    2126                 :   
    2127               0 :   nsCOMPtr<nsIDOMElement> domElement;
    2128                 :   PRInt32 selectedCount;
    2129               0 :   nsAutoString tagName;
    2130                 :   nsresult res = GetSelectedOrParentTableElement(tagName,
    2131                 :                                                  &selectedCount,
    2132               0 :                                                  getter_AddRefs(domElement));
    2133               0 :   NS_ENSURE_SUCCESS(res, res);
    2134                 : 
    2135               0 :   nsCOMPtr<nsINode> element = do_QueryInterface(domElement);
    2136                 : 
    2137               0 :   while (element) {
    2138                 :     // We are in a cell or selected table
    2139               0 :     element->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::bgcolor, aOutColor);
    2140                 : 
    2141                 :     // Done if we have a color explicitly set
    2142               0 :     if (!aOutColor.IsEmpty()) {
    2143               0 :       return NS_OK;
    2144                 :     }
    2145                 : 
    2146                 :     // Once we hit the body, we're done
    2147               0 :     if (element->AsElement()->IsHTML(nsGkAtoms::body)) {
    2148               0 :       return NS_OK;
    2149                 :     }
    2150                 : 
    2151                 :     // No color is set, but we need to report visible color inherited 
    2152                 :     // from nested cells/tables, so search up parent chain
    2153               0 :     element = element->GetElementParent();
    2154                 :   }
    2155                 : 
    2156                 :   // If no table or cell found, get page body
    2157               0 :   dom::Element* bodyElement = GetRoot();
    2158               0 :   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
    2159                 : 
    2160               0 :   bodyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::bgcolor, aOutColor);
    2161               0 :   return NS_OK;
    2162                 : }
    2163                 : 
    2164                 : NS_IMETHODIMP 
    2165               0 : nsHTMLEditor::GetListState(bool *aMixed, bool *aOL, bool *aUL, bool *aDL)
    2166                 : {
    2167               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2168               0 :   NS_ENSURE_TRUE(aMixed && aOL && aUL && aDL, NS_ERROR_NULL_POINTER);
    2169               0 :   nsHTMLEditRules* htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
    2170               0 :   NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
    2171                 :   
    2172               0 :   return htmlRules->GetListState(aMixed, aOL, aUL, aDL);
    2173                 : }
    2174                 : 
    2175                 : NS_IMETHODIMP 
    2176               0 : nsHTMLEditor::GetListItemState(bool *aMixed, bool *aLI, bool *aDT, bool *aDD)
    2177                 : {
    2178               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2179               0 :   NS_ENSURE_TRUE(aMixed && aLI && aDT && aDD, NS_ERROR_NULL_POINTER);
    2180                 : 
    2181               0 :   nsHTMLEditRules* htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
    2182               0 :   NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
    2183                 :   
    2184               0 :   return htmlRules->GetListItemState(aMixed, aLI, aDT, aDD);
    2185                 : }
    2186                 : 
    2187                 : NS_IMETHODIMP
    2188               0 : nsHTMLEditor::GetAlignment(bool *aMixed, nsIHTMLEditor::EAlignment *aAlign)
    2189                 : {
    2190               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2191               0 :   NS_ENSURE_TRUE(aMixed && aAlign, NS_ERROR_NULL_POINTER);
    2192               0 :   nsHTMLEditRules* htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
    2193               0 :   NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
    2194                 :   
    2195               0 :   return htmlRules->GetAlignment(aMixed, aAlign);
    2196                 : }
    2197                 : 
    2198                 : 
    2199                 : NS_IMETHODIMP 
    2200               0 : nsHTMLEditor::GetIndentState(bool *aCanIndent, bool *aCanOutdent)
    2201                 : {
    2202               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2203               0 :   NS_ENSURE_TRUE(aCanIndent && aCanOutdent, NS_ERROR_NULL_POINTER);
    2204                 : 
    2205               0 :   nsHTMLEditRules* htmlRules = static_cast<nsHTMLEditRules*>(mRules.get());
    2206               0 :   NS_ENSURE_TRUE(htmlRules, NS_ERROR_FAILURE);
    2207                 :   
    2208               0 :   return htmlRules->GetIndentState(aCanIndent, aCanOutdent);
    2209                 : }
    2210                 : 
    2211                 : NS_IMETHODIMP
    2212               0 : nsHTMLEditor::MakeOrChangeList(const nsAString& aListType, bool entireList, const nsAString& aBulletType)
    2213                 : {
    2214                 :   nsresult res;
    2215               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2216                 : 
    2217                 :   // Protect the edit rules object from dying
    2218               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    2219                 : 
    2220               0 :   nsCOMPtr<nsISelection> selection;
    2221                 :   bool cancel, handled;
    2222                 : 
    2223               0 :   nsAutoEditBatch beginBatching(this);
    2224               0 :   nsAutoRules beginRulesSniffing(this, kOpMakeList, nsIEditor::eNext);
    2225                 :   
    2226                 :   // pre-process
    2227               0 :   res = GetSelection(getter_AddRefs(selection));
    2228               0 :   NS_ENSURE_SUCCESS(res, res);
    2229               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2230                 : 
    2231               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeList);
    2232               0 :   ruleInfo.blockType = &aListType;
    2233               0 :   ruleInfo.entireList = entireList;
    2234               0 :   ruleInfo.bulletType = &aBulletType;
    2235               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2236               0 :   if (cancel || (NS_FAILED(res))) return res;
    2237                 : 
    2238               0 :   if (!handled)
    2239                 :   {
    2240                 :     // Find out if the selection is collapsed:
    2241                 :     bool isCollapsed;
    2242               0 :     res = selection->GetIsCollapsed(&isCollapsed);
    2243               0 :     NS_ENSURE_SUCCESS(res, res);
    2244                 : 
    2245               0 :     nsCOMPtr<nsIDOMNode> node;
    2246                 :     PRInt32 offset;
    2247                 :   
    2248               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
    2249               0 :     if (!node) res = NS_ERROR_FAILURE;
    2250               0 :     NS_ENSURE_SUCCESS(res, res);
    2251                 :   
    2252               0 :     if (isCollapsed)
    2253                 :     {
    2254                 :       // have to find a place to put the list
    2255               0 :       nsCOMPtr<nsIDOMNode> parent = node;
    2256               0 :       nsCOMPtr<nsIDOMNode> topChild = node;
    2257               0 :       nsCOMPtr<nsIDOMNode> tmp;
    2258                 :     
    2259               0 :       while ( !CanContainTag(parent, aListType))
    2260                 :       {
    2261               0 :         parent->GetParentNode(getter_AddRefs(tmp));
    2262               0 :         NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    2263               0 :         topChild = parent;
    2264               0 :         parent = tmp;
    2265                 :       }
    2266                 :     
    2267               0 :       if (parent != node)
    2268                 :       {
    2269                 :         // we need to split up to the child of parent
    2270               0 :         res = SplitNodeDeep(topChild, node, offset, &offset);
    2271               0 :         NS_ENSURE_SUCCESS(res, res);
    2272                 :       }
    2273                 : 
    2274                 :       // make a list
    2275               0 :       nsCOMPtr<nsIDOMNode> newList;
    2276               0 :       res = CreateNode(aListType, parent, offset, getter_AddRefs(newList));
    2277               0 :       NS_ENSURE_SUCCESS(res, res);
    2278                 :       // make a list item
    2279               0 :       nsCOMPtr<nsIDOMNode> newItem;
    2280               0 :       res = CreateNode(NS_LITERAL_STRING("li"), newList, 0, getter_AddRefs(newItem));
    2281               0 :       NS_ENSURE_SUCCESS(res, res);
    2282               0 :       res = selection->Collapse(newItem,0);
    2283               0 :       NS_ENSURE_SUCCESS(res, res);
    2284                 :     }
    2285                 :   }
    2286                 :   
    2287               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    2288               0 :   return res;
    2289                 : }
    2290                 : 
    2291                 : 
    2292                 : NS_IMETHODIMP
    2293               0 : nsHTMLEditor::RemoveList(const nsAString& aListType)
    2294                 : {
    2295                 :   nsresult res;
    2296               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2297                 : 
    2298                 :   // Protect the edit rules object from dying
    2299               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    2300                 : 
    2301               0 :   nsCOMPtr<nsISelection> selection;
    2302                 :   bool cancel, handled;
    2303                 : 
    2304               0 :   nsAutoEditBatch beginBatching(this);
    2305               0 :   nsAutoRules beginRulesSniffing(this, kOpRemoveList, nsIEditor::eNext);
    2306                 :   
    2307                 :   // pre-process
    2308               0 :   res = GetSelection(getter_AddRefs(selection));
    2309               0 :   NS_ENSURE_SUCCESS(res, res);
    2310               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2311                 : 
    2312               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kRemoveList);
    2313               0 :   if (aListType.LowerCaseEqualsLiteral("ol"))
    2314               0 :     ruleInfo.bOrdered = true;
    2315               0 :   else  ruleInfo.bOrdered = false;
    2316               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2317               0 :   if (cancel || (NS_FAILED(res))) return res;
    2318                 : 
    2319                 :   // no default behavior for this yet.  what would it mean?
    2320                 : 
    2321               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    2322               0 :   return res;
    2323                 : }
    2324                 : 
    2325                 : nsresult
    2326               0 : nsHTMLEditor::MakeDefinitionItem(const nsAString& aItemType)
    2327                 : {
    2328                 :   nsresult res;
    2329               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2330                 : 
    2331                 :   // Protect the edit rules object from dying
    2332               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    2333                 : 
    2334               0 :   nsCOMPtr<nsISelection> selection;
    2335                 :   bool cancel, handled;
    2336                 : 
    2337               0 :   nsAutoEditBatch beginBatching(this);
    2338               0 :   nsAutoRules beginRulesSniffing(this, kOpMakeDefListItem, nsIEditor::eNext);
    2339                 :   
    2340                 :   // pre-process
    2341               0 :   res = GetSelection(getter_AddRefs(selection));
    2342               0 :   NS_ENSURE_SUCCESS(res, res);
    2343               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2344               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeDefListItem);
    2345               0 :   ruleInfo.blockType = &aItemType;
    2346               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2347               0 :   if (cancel || (NS_FAILED(res))) return res;
    2348                 : 
    2349               0 :   if (!handled)
    2350                 :   {
    2351                 :     // todo: no default for now.  we count on rules to handle it.
    2352                 :   }
    2353                 : 
    2354               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    2355               0 :   return res;
    2356                 : }
    2357                 : 
    2358                 : nsresult
    2359               0 : nsHTMLEditor::InsertBasicBlock(const nsAString& aBlockType)
    2360                 : {
    2361                 :   nsresult res;
    2362               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2363                 : 
    2364                 :   // Protect the edit rules object from dying
    2365               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    2366                 : 
    2367               0 :   nsCOMPtr<nsISelection> selection;
    2368                 :   bool cancel, handled;
    2369                 : 
    2370               0 :   nsAutoEditBatch beginBatching(this);
    2371               0 :   nsAutoRules beginRulesSniffing(this, kOpMakeBasicBlock, nsIEditor::eNext);
    2372                 :   
    2373                 :   // pre-process
    2374               0 :   res = GetSelection(getter_AddRefs(selection));
    2375               0 :   NS_ENSURE_SUCCESS(res, res);
    2376               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2377               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeBasicBlock);
    2378               0 :   ruleInfo.blockType = &aBlockType;
    2379               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2380               0 :   if (cancel || (NS_FAILED(res))) return res;
    2381                 : 
    2382               0 :   if (!handled)
    2383                 :   {
    2384                 :     // Find out if the selection is collapsed:
    2385                 :     bool isCollapsed;
    2386               0 :     res = selection->GetIsCollapsed(&isCollapsed);
    2387               0 :     NS_ENSURE_SUCCESS(res, res);
    2388                 : 
    2389               0 :     nsCOMPtr<nsIDOMNode> node;
    2390                 :     PRInt32 offset;
    2391                 :   
    2392               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
    2393               0 :     if (!node) res = NS_ERROR_FAILURE;
    2394               0 :     NS_ENSURE_SUCCESS(res, res);
    2395                 :   
    2396               0 :     if (isCollapsed)
    2397                 :     {
    2398                 :       // have to find a place to put the block
    2399               0 :       nsCOMPtr<nsIDOMNode> parent = node;
    2400               0 :       nsCOMPtr<nsIDOMNode> topChild = node;
    2401               0 :       nsCOMPtr<nsIDOMNode> tmp;
    2402                 :     
    2403               0 :       while ( !CanContainTag(parent, aBlockType))
    2404                 :       {
    2405               0 :         parent->GetParentNode(getter_AddRefs(tmp));
    2406               0 :         NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    2407               0 :         topChild = parent;
    2408               0 :         parent = tmp;
    2409                 :       }
    2410                 :     
    2411               0 :       if (parent != node)
    2412                 :       {
    2413                 :         // we need to split up to the child of parent
    2414               0 :         res = SplitNodeDeep(topChild, node, offset, &offset);
    2415               0 :         NS_ENSURE_SUCCESS(res, res);
    2416                 :       }
    2417                 : 
    2418                 :       // make a block
    2419               0 :       nsCOMPtr<nsIDOMNode> newBlock;
    2420               0 :       res = CreateNode(aBlockType, parent, offset, getter_AddRefs(newBlock));
    2421               0 :       NS_ENSURE_SUCCESS(res, res);
    2422                 :     
    2423                 :       // reposition selection to inside the block
    2424               0 :       res = selection->Collapse(newBlock,0);
    2425               0 :       NS_ENSURE_SUCCESS(res, res);  
    2426                 :     }
    2427                 :   }
    2428                 : 
    2429               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    2430               0 :   return res;
    2431                 : }
    2432                 : 
    2433                 : NS_IMETHODIMP
    2434               0 : nsHTMLEditor::Indent(const nsAString& aIndent)
    2435                 : {
    2436                 :   nsresult res;
    2437               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    2438                 : 
    2439                 :   // Protect the edit rules object from dying
    2440               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    2441                 : 
    2442                 :   bool cancel, handled;
    2443               0 :   PRInt32 theAction = nsTextEditRules::kIndent;
    2444               0 :   PRInt32 opID = kOpIndent;
    2445               0 :   if (aIndent.LowerCaseEqualsLiteral("outdent"))
    2446                 :   {
    2447               0 :     theAction = nsTextEditRules::kOutdent;
    2448               0 :     opID = kOpOutdent;
    2449                 :   }
    2450               0 :   nsAutoEditBatch beginBatching(this);
    2451               0 :   nsAutoRules beginRulesSniffing(this, opID, nsIEditor::eNext);
    2452                 :   
    2453                 :   // pre-process
    2454               0 :   nsCOMPtr<nsISelection> selection;
    2455               0 :   res = GetSelection(getter_AddRefs(selection));
    2456               0 :   NS_ENSURE_SUCCESS(res, res);
    2457               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2458                 : 
    2459               0 :   nsTextRulesInfo ruleInfo(theAction);
    2460               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2461               0 :   if (cancel || (NS_FAILED(res))) return res;
    2462                 :   
    2463               0 :   if (!handled)
    2464                 :   {
    2465                 :     // Do default - insert a blockquote node if selection collapsed
    2466               0 :     nsCOMPtr<nsIDOMNode> node;
    2467                 :     PRInt32 offset;
    2468                 :     bool isCollapsed;
    2469               0 :     res = selection->GetIsCollapsed(&isCollapsed);
    2470               0 :     NS_ENSURE_SUCCESS(res, res);
    2471                 : 
    2472               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
    2473               0 :     if (!node) res = NS_ERROR_FAILURE;
    2474               0 :     NS_ENSURE_SUCCESS(res, res);
    2475                 :   
    2476               0 :     if (aIndent.EqualsLiteral("indent"))
    2477                 :     {
    2478               0 :       if (isCollapsed)
    2479                 :       {
    2480                 :         // have to find a place to put the blockquote
    2481               0 :         nsCOMPtr<nsIDOMNode> parent = node;
    2482               0 :         nsCOMPtr<nsIDOMNode> topChild = node;
    2483               0 :         nsCOMPtr<nsIDOMNode> tmp;
    2484               0 :         NS_NAMED_LITERAL_STRING(bq, "blockquote");
    2485               0 :         while ( !CanContainTag(parent, bq))
    2486                 :         {
    2487               0 :           parent->GetParentNode(getter_AddRefs(tmp));
    2488               0 :           NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    2489               0 :           topChild = parent;
    2490               0 :           parent = tmp;
    2491                 :         }
    2492                 :     
    2493               0 :         if (parent != node)
    2494                 :         {
    2495                 :           // we need to split up to the child of parent
    2496               0 :           res = SplitNodeDeep(topChild, node, offset, &offset);
    2497               0 :           NS_ENSURE_SUCCESS(res, res);
    2498                 :         }
    2499                 : 
    2500                 :         // make a blockquote
    2501               0 :         nsCOMPtr<nsIDOMNode> newBQ;
    2502               0 :         res = CreateNode(bq, parent, offset, getter_AddRefs(newBQ));
    2503               0 :         NS_ENSURE_SUCCESS(res, res);
    2504                 :         // put a space in it so layout will draw the list item
    2505               0 :         res = selection->Collapse(newBQ,0);
    2506               0 :         NS_ENSURE_SUCCESS(res, res);
    2507               0 :         res = InsertText(NS_LITERAL_STRING(" "));
    2508               0 :         NS_ENSURE_SUCCESS(res, res);
    2509                 :         // reposition selection to before the space character
    2510               0 :         res = GetStartNodeAndOffset(selection, getter_AddRefs(node), &offset);
    2511               0 :         NS_ENSURE_SUCCESS(res, res);
    2512               0 :         res = selection->Collapse(node,0);
    2513               0 :         NS_ENSURE_SUCCESS(res, res);
    2514                 :       }
    2515                 :     }
    2516                 :   }
    2517               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    2518               0 :   return res;
    2519                 : }
    2520                 : 
    2521                 : //TODO: IMPLEMENT ALIGNMENT!
    2522                 : 
    2523                 : NS_IMETHODIMP
    2524               0 : nsHTMLEditor::Align(const nsAString& aAlignType)
    2525                 : {
    2526                 :   // Protect the edit rules object from dying
    2527               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    2528                 : 
    2529               0 :   nsAutoEditBatch beginBatching(this);
    2530               0 :   nsAutoRules beginRulesSniffing(this, kOpAlign, nsIEditor::eNext);
    2531                 : 
    2532               0 :   nsCOMPtr<nsIDOMNode> node;
    2533                 :   bool cancel, handled;
    2534                 :   
    2535                 :   // Find out if the selection is collapsed:
    2536               0 :   nsCOMPtr<nsISelection> selection;
    2537               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    2538               0 :   NS_ENSURE_SUCCESS(res, res);
    2539               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2540               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kAlign);
    2541               0 :   ruleInfo.alignType = &aAlignType;
    2542               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    2543               0 :   if (cancel || NS_FAILED(res))
    2544               0 :     return res;
    2545                 :   
    2546               0 :   res = mRules->DidDoAction(selection, &ruleInfo, res);
    2547               0 :   return res;
    2548                 : }
    2549                 : 
    2550                 : NS_IMETHODIMP
    2551               0 : nsHTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn)
    2552                 : {
    2553               0 :   if (aTagName.IsEmpty() || !aReturn )
    2554               0 :     return NS_ERROR_NULL_POINTER;
    2555                 :   
    2556               0 :   nsresult res = NS_OK;
    2557               0 :   nsCOMPtr<nsIDOMNode> currentNode;
    2558                 : 
    2559               0 :   if (aNode)
    2560               0 :     currentNode = aNode;
    2561                 :   else
    2562                 :   {
    2563                 :     // If no node supplied, get it from anchor node of current selection
    2564               0 :     nsCOMPtr<nsISelection>selection;
    2565               0 :     res = GetSelection(getter_AddRefs(selection));
    2566               0 :     NS_ENSURE_SUCCESS(res, res);
    2567               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2568                 : 
    2569               0 :     nsCOMPtr<nsIDOMNode> anchorNode;
    2570               0 :     res = selection->GetAnchorNode(getter_AddRefs(anchorNode));
    2571               0 :     if(NS_FAILED(res)) return res;
    2572               0 :     NS_ENSURE_TRUE(anchorNode, NS_ERROR_FAILURE);
    2573                 : 
    2574                 :     // Try to get the actual selected node
    2575               0 :     bool hasChildren = false;
    2576               0 :     anchorNode->HasChildNodes(&hasChildren);
    2577               0 :     if (hasChildren)
    2578                 :     {
    2579                 :       PRInt32 offset;
    2580               0 :       res = selection->GetAnchorOffset(&offset);
    2581               0 :       if(NS_FAILED(res)) return res;
    2582               0 :       currentNode = nsEditor::GetChildAt(anchorNode, offset);
    2583                 :     }
    2584                 :     // anchor node is probably a text node - just use that
    2585               0 :     if (!currentNode)
    2586               0 :       currentNode = anchorNode;
    2587                 :   }
    2588                 :    
    2589               0 :   nsAutoString TagName(aTagName);
    2590               0 :   ToLowerCase(TagName);
    2591               0 :   bool getLink = IsLinkTag(TagName);
    2592               0 :   bool getNamedAnchor = IsNamedAnchorTag(TagName);
    2593               0 :   if ( getLink || getNamedAnchor)
    2594                 :   {
    2595               0 :     TagName.AssignLiteral("a");  
    2596                 :   }
    2597               0 :   bool findTableCell = TagName.EqualsLiteral("td");
    2598               0 :   bool findList = TagName.EqualsLiteral("list");
    2599                 : 
    2600                 :   // default is null - no element found
    2601               0 :   *aReturn = nsnull;
    2602                 :   
    2603               0 :   nsCOMPtr<nsIDOMNode> parent;
    2604               0 :   bool bNodeFound = false;
    2605                 : 
    2606               0 :   while (true)
    2607                 :   {
    2608               0 :     nsAutoString currentTagName; 
    2609                 :     // Test if we have a link (an anchor with href set)
    2610               0 :     if ( (getLink && nsHTMLEditUtils::IsLink(currentNode)) ||
    2611               0 :          (getNamedAnchor && nsHTMLEditUtils::IsNamedAnchor(currentNode)) )
    2612                 :     {
    2613               0 :       bNodeFound = true;
    2614                 :       break;
    2615                 :     } else {
    2616               0 :       if (findList)
    2617                 :       {
    2618                 :         // Match "ol", "ul", or "dl" for lists
    2619               0 :         if (nsHTMLEditUtils::IsList(currentNode))
    2620               0 :           goto NODE_FOUND;
    2621                 : 
    2622               0 :       } else if (findTableCell)
    2623                 :       {
    2624                 :         // Table cells are another special case:
    2625                 :         // Match either "td" or "th" for them
    2626               0 :         if (nsHTMLEditUtils::IsTableCell(currentNode))
    2627               0 :           goto NODE_FOUND;
    2628                 : 
    2629                 :       } else {
    2630               0 :         currentNode->GetNodeName(currentTagName);
    2631               0 :         if (currentTagName.Equals(TagName, nsCaseInsensitiveStringComparator()))
    2632                 :         {
    2633                 : NODE_FOUND:
    2634               0 :           bNodeFound = true;
    2635                 :           break;
    2636                 :         } 
    2637                 :       }
    2638                 :     }
    2639                 :     // Search up the parent chain
    2640                 :     // We should never fail because of root test below, but lets be safe
    2641                 :     // XXX: ERROR_HANDLING error return code lost
    2642               0 :     if (NS_FAILED(currentNode->GetParentNode(getter_AddRefs(parent))) || !parent)
    2643                 :       break;
    2644                 : 
    2645                 :     // Stop searching if parent is a body tag
    2646               0 :     nsAutoString parentTagName;
    2647               0 :     parent->GetNodeName(parentTagName);
    2648                 :     // Note: Originally used IsRoot to stop at table cells,
    2649                 :     //  but that's too messy when you are trying to find the parent table
    2650               0 :     if(parentTagName.LowerCaseEqualsLiteral("body"))
    2651                 :       break;
    2652                 : 
    2653               0 :     currentNode = parent;
    2654                 :   }
    2655               0 :   if (bNodeFound)
    2656                 :   {
    2657               0 :     nsCOMPtr<nsIDOMElement> currentElement = do_QueryInterface(currentNode);
    2658               0 :     if (currentElement)
    2659                 :     {
    2660               0 :       *aReturn = currentElement;
    2661                 :       // Getters must addref
    2662               0 :       NS_ADDREF(*aReturn);
    2663                 :     }
    2664                 :   }
    2665               0 :   else res = NS_EDITOR_ELEMENT_NOT_FOUND;
    2666                 : 
    2667               0 :   return res;
    2668                 : }
    2669                 : 
    2670                 : NS_IMETHODIMP
    2671               0 : nsHTMLEditor::GetSelectedElement(const nsAString& aTagName, nsIDOMElement** aReturn)
    2672                 : {
    2673               0 :   NS_ENSURE_TRUE(aReturn , NS_ERROR_NULL_POINTER);
    2674                 :   
    2675                 :   // default is null - no element found
    2676               0 :   *aReturn = nsnull;
    2677                 :   
    2678                 :   // First look for a single element in selection
    2679               0 :   nsCOMPtr<nsISelection>selection;
    2680               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    2681               0 :   NS_ENSURE_SUCCESS(res, res);
    2682               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2683               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    2684                 : 
    2685               0 :   bool bNodeFound = false;
    2686               0 :   res=NS_ERROR_NOT_INITIALIZED;
    2687                 :   bool isCollapsed;
    2688               0 :   selection->GetIsCollapsed(&isCollapsed);
    2689                 : 
    2690               0 :   nsAutoString domTagName;
    2691               0 :   nsAutoString TagName(aTagName);
    2692               0 :   ToLowerCase(TagName);
    2693                 :   // Empty string indicates we should match any element tag
    2694               0 :   bool anyTag = (TagName.IsEmpty());
    2695               0 :   bool isLinkTag = IsLinkTag(TagName);
    2696               0 :   bool isNamedAnchorTag = IsNamedAnchorTag(TagName);
    2697                 :   
    2698               0 :   nsCOMPtr<nsIDOMElement> selectedElement;
    2699               0 :   nsCOMPtr<nsIDOMRange> range;
    2700               0 :   res = selection->GetRangeAt(0, getter_AddRefs(range));
    2701               0 :   NS_ENSURE_SUCCESS(res, res);
    2702                 : 
    2703               0 :   nsCOMPtr<nsIDOMNode> startParent;
    2704                 :   PRInt32 startOffset, endOffset;
    2705               0 :   res = range->GetStartContainer(getter_AddRefs(startParent));
    2706               0 :   NS_ENSURE_SUCCESS(res, res);
    2707               0 :   res = range->GetStartOffset(&startOffset);
    2708               0 :   NS_ENSURE_SUCCESS(res, res);
    2709                 : 
    2710               0 :   nsCOMPtr<nsIDOMNode> endParent;
    2711               0 :   res = range->GetEndContainer(getter_AddRefs(endParent));
    2712               0 :   NS_ENSURE_SUCCESS(res, res);
    2713               0 :   res = range->GetEndOffset(&endOffset);
    2714               0 :   NS_ENSURE_SUCCESS(res, res);
    2715                 : 
    2716                 :   // Optimization for a single selected element
    2717               0 :   if (startParent && startParent == endParent && (endOffset-startOffset) == 1)
    2718                 :   {
    2719               0 :     nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startParent, startOffset);
    2720               0 :     NS_ENSURE_SUCCESS(res, NS_OK);
    2721               0 :     if (selectedNode)
    2722                 :     {
    2723               0 :       selectedNode->GetNodeName(domTagName);
    2724               0 :       ToLowerCase(domTagName);
    2725                 : 
    2726                 :       // Test for appropriate node type requested
    2727               0 :       if (anyTag || (TagName == domTagName) ||
    2728               0 :           (isLinkTag && nsHTMLEditUtils::IsLink(selectedNode)) ||
    2729               0 :           (isNamedAnchorTag && nsHTMLEditUtils::IsNamedAnchor(selectedNode)))
    2730                 :       {
    2731               0 :         bNodeFound = true;
    2732               0 :         selectedElement = do_QueryInterface(selectedNode);
    2733                 :       }
    2734                 :     }
    2735                 :   }
    2736                 : 
    2737               0 :   if (!bNodeFound)
    2738                 :   {
    2739               0 :     if (isLinkTag)
    2740                 :     {
    2741                 :       // Link tag is a special case - we return the anchor node
    2742                 :       //  found for any selection that is totally within a link,
    2743                 :       //  included a collapsed selection (just a caret in a link)
    2744               0 :       nsCOMPtr<nsIDOMNode> anchorNode;
    2745               0 :       res = selection->GetAnchorNode(getter_AddRefs(anchorNode));
    2746               0 :       NS_ENSURE_SUCCESS(res, res);
    2747               0 :       PRInt32 anchorOffset = -1;
    2748               0 :       if (anchorNode)
    2749               0 :         selection->GetAnchorOffset(&anchorOffset);
    2750                 :     
    2751               0 :       nsCOMPtr<nsIDOMNode> focusNode;
    2752               0 :       res = selection->GetFocusNode(getter_AddRefs(focusNode));
    2753               0 :       NS_ENSURE_SUCCESS(res, res);
    2754               0 :       PRInt32 focusOffset = -1;
    2755               0 :       if (focusNode)
    2756               0 :         selection->GetFocusOffset(&focusOffset);
    2757                 : 
    2758                 :       // Link node must be the same for both ends of selection
    2759               0 :       if (NS_SUCCEEDED(res) && anchorNode)
    2760                 :       {
    2761                 :   #ifdef DEBUG_cmanske
    2762                 :         {
    2763                 :         nsAutoString name;
    2764                 :         anchorNode->GetNodeName(name);
    2765                 :         printf("GetSelectedElement: Anchor node of selection: ");
    2766                 :         wprintf(name.get());
    2767                 :         printf(" Offset: %d\n", anchorOffset);
    2768                 :         focusNode->GetNodeName(name);
    2769                 :         printf("Focus node of selection: ");
    2770                 :         wprintf(name.get());
    2771                 :         printf(" Offset: %d\n", focusOffset);
    2772                 :         }
    2773                 :   #endif
    2774               0 :         nsCOMPtr<nsIDOMElement> parentLinkOfAnchor;
    2775               0 :         res = GetElementOrParentByTagName(NS_LITERAL_STRING("href"), anchorNode, getter_AddRefs(parentLinkOfAnchor));
    2776                 :         // XXX: ERROR_HANDLING  can parentLinkOfAnchor be null?
    2777               0 :         if (NS_SUCCEEDED(res) && parentLinkOfAnchor)
    2778                 :         {
    2779               0 :           if (isCollapsed)
    2780                 :           {
    2781                 :             // We have just a caret in the link
    2782               0 :             bNodeFound = true;
    2783               0 :           } else if(focusNode) 
    2784                 :           {  // Link node must be the same for both ends of selection
    2785               0 :             nsCOMPtr<nsIDOMElement> parentLinkOfFocus;
    2786               0 :             res = GetElementOrParentByTagName(NS_LITERAL_STRING("href"), focusNode, getter_AddRefs(parentLinkOfFocus));
    2787               0 :             if (NS_SUCCEEDED(res) && parentLinkOfFocus == parentLinkOfAnchor)
    2788               0 :               bNodeFound = true;
    2789                 :           }
    2790                 :       
    2791                 :           // We found a link node parent
    2792               0 :           if (bNodeFound) {
    2793                 :             // GetElementOrParentByTagName addref'd this, so we don't need to do it here
    2794               0 :             *aReturn = parentLinkOfAnchor;
    2795               0 :             NS_IF_ADDREF(*aReturn);
    2796               0 :             return NS_OK;
    2797                 :           }
    2798                 :         }
    2799               0 :         else if (anchorOffset >= 0)  // Check if link node is the only thing selected
    2800                 :         {
    2801               0 :           nsCOMPtr<nsIDOMNode> anchorChild;
    2802               0 :           anchorChild = GetChildAt(anchorNode,anchorOffset);
    2803               0 :           if (anchorChild && nsHTMLEditUtils::IsLink(anchorChild) && 
    2804               0 :               (anchorNode == focusNode) && focusOffset == (anchorOffset+1))
    2805                 :           {
    2806               0 :             selectedElement = do_QueryInterface(anchorChild);
    2807               0 :             bNodeFound = true;
    2808                 :           }
    2809                 :         }
    2810                 :       }
    2811                 :     } 
    2812                 : 
    2813               0 :     if (!isCollapsed)   // Don't bother to examine selection if it is collapsed
    2814                 :     {
    2815               0 :       nsCOMPtr<nsIEnumerator> enumerator;
    2816               0 :       res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    2817               0 :       if (NS_SUCCEEDED(res))
    2818                 :       {
    2819               0 :         if(!enumerator)
    2820               0 :           return NS_ERROR_NULL_POINTER;
    2821                 : 
    2822               0 :         enumerator->First(); 
    2823               0 :         nsCOMPtr<nsISupports> currentItem;
    2824               0 :         res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    2825               0 :         if ((NS_SUCCEEDED(res)) && currentItem)
    2826                 :         {
    2827               0 :           nsCOMPtr<nsIDOMRange> currange( do_QueryInterface(currentItem) );
    2828                 :           nsCOMPtr<nsIContentIterator> iter =
    2829               0 :             do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res);
    2830               0 :           NS_ENSURE_SUCCESS(res, res);
    2831                 : 
    2832               0 :           iter->Init(currange);
    2833                 :           // loop through the content iterator for each content node
    2834               0 :           while (!iter->IsDone())
    2835                 :           {
    2836                 :             // Query interface to cast nsIContent to nsIDOMNode
    2837                 :             //  then get tagType to compare to  aTagName
    2838                 :             // Clone node of each desired type and append it to the aDomFrag
    2839               0 :             selectedElement = do_QueryInterface(iter->GetCurrentNode());
    2840               0 :             if (selectedElement)
    2841                 :             {
    2842                 :               // If we already found a node, then we have another element,
    2843                 :               //  thus there's not just one element selected
    2844               0 :               if (bNodeFound)
    2845                 :               {
    2846               0 :                 bNodeFound = false;
    2847               0 :                 break;
    2848                 :               }
    2849                 : 
    2850               0 :               selectedElement->GetNodeName(domTagName);
    2851               0 :               ToLowerCase(domTagName);
    2852                 : 
    2853               0 :               if (anyTag)
    2854                 :               {
    2855                 :                 // Get name of first selected element
    2856               0 :                 selectedElement->GetTagName(TagName);
    2857               0 :                 ToLowerCase(TagName);
    2858               0 :                 anyTag = false;
    2859                 :               }
    2860                 : 
    2861                 :               // The "A" tag is a pain,
    2862                 :               //  used for both link(href is set) and "Named Anchor"
    2863               0 :               nsCOMPtr<nsIDOMNode> selectedNode = do_QueryInterface(selectedElement);
    2864               0 :               if ( (isLinkTag && nsHTMLEditUtils::IsLink(selectedNode)) ||
    2865               0 :                    (isNamedAnchorTag && nsHTMLEditUtils::IsNamedAnchor(selectedNode)) )
    2866                 :               {
    2867               0 :                 bNodeFound = true;
    2868               0 :               } else if (TagName == domTagName) { // All other tag names are handled here
    2869               0 :                 bNodeFound = true;
    2870                 :               }
    2871               0 :               if (!bNodeFound)
    2872                 :               {
    2873                 :                 // Check if node we have is really part of the selection???
    2874                 :                 break;
    2875                 :               }
    2876                 :             }
    2877               0 :             iter->Next();
    2878                 :           }
    2879                 :         } else {
    2880                 :           // Should never get here?
    2881               0 :           isCollapsed = true;
    2882               0 :           printf("isCollapsed was FALSE, but no elements found in selection\n");
    2883                 :         }
    2884                 :       } else {
    2885               0 :         printf("Could not create enumerator for GetSelectionProperties\n");
    2886                 :       }
    2887                 :     }
    2888                 :   }
    2889               0 :   if (bNodeFound)
    2890                 :   {
    2891                 :     
    2892               0 :     *aReturn = selectedElement;
    2893               0 :     if (selectedElement)
    2894                 :     {  
    2895                 :       // Getters must addref
    2896               0 :       NS_ADDREF(*aReturn);
    2897                 :     }
    2898                 :   } 
    2899               0 :   else res = NS_EDITOR_ELEMENT_NOT_FOUND;
    2900                 : 
    2901               0 :   return res;
    2902                 : }
    2903                 : 
    2904                 : NS_IMETHODIMP
    2905               0 : nsHTMLEditor::CreateElementWithDefaults(const nsAString& aTagName, nsIDOMElement** aReturn)
    2906                 : {
    2907               0 :   nsresult res=NS_ERROR_NOT_INITIALIZED;
    2908               0 :   if (aReturn)
    2909               0 :     *aReturn = nsnull;
    2910                 : 
    2911                 : //  NS_ENSURE_TRUE(aTagName && aReturn, NS_ERROR_NULL_POINTER);
    2912               0 :   NS_ENSURE_TRUE(!aTagName.IsEmpty() && aReturn, NS_ERROR_NULL_POINTER);
    2913                 :     
    2914               0 :   nsAutoString TagName(aTagName);
    2915               0 :   ToLowerCase(TagName);
    2916               0 :   nsAutoString realTagName;
    2917                 : 
    2918               0 :   if (IsLinkTag(TagName) || IsNamedAnchorTag(TagName))
    2919                 :   {
    2920               0 :     realTagName.AssignLiteral("a");
    2921                 :   } else {
    2922               0 :     realTagName = TagName;
    2923                 :   }
    2924                 :   //We don't use editor's CreateElement because we don't want to 
    2925                 :   //  go through the transaction system
    2926                 : 
    2927               0 :   nsCOMPtr<nsIDOMElement>newElement;
    2928               0 :   nsCOMPtr<nsIContent> newContent;
    2929               0 :   nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(mDocWeak);
    2930               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
    2931                 : 
    2932                 :   //new call to use instead to get proper HTML element, bug# 39919
    2933               0 :   res = CreateHTMLContent(realTagName, getter_AddRefs(newContent));
    2934               0 :   newElement = do_QueryInterface(newContent);
    2935               0 :   if (NS_FAILED(res) || !newElement)
    2936               0 :     return NS_ERROR_FAILURE;
    2937                 : 
    2938                 :   // Mark the new element dirty, so it will be formatted
    2939               0 :   newElement->SetAttribute(NS_LITERAL_STRING("_moz_dirty"), EmptyString());
    2940                 : 
    2941                 :   // Set default values for new elements
    2942               0 :   if (TagName.EqualsLiteral("hr"))
    2943                 :   {
    2944                 :     // Note that we read the user's attributes for these from prefs (in InsertHLine JS)
    2945               0 :     res = SetAttributeOrEquivalent(newElement, NS_LITERAL_STRING("width"),
    2946               0 :                                    NS_LITERAL_STRING("100%"), true);
    2947               0 :     NS_ENSURE_SUCCESS(res, res);
    2948               0 :     res = SetAttributeOrEquivalent(newElement, NS_LITERAL_STRING("size"),
    2949               0 :                                    NS_LITERAL_STRING("2"), true);
    2950               0 :   } else if (TagName.EqualsLiteral("table"))
    2951                 :   {
    2952               0 :     res = newElement->SetAttribute(NS_LITERAL_STRING("cellpadding"),NS_LITERAL_STRING("2"));
    2953               0 :     NS_ENSURE_SUCCESS(res, res);
    2954               0 :     res = newElement->SetAttribute(NS_LITERAL_STRING("cellspacing"),NS_LITERAL_STRING("2"));
    2955               0 :     NS_ENSURE_SUCCESS(res, res);
    2956               0 :     res = newElement->SetAttribute(NS_LITERAL_STRING("border"),NS_LITERAL_STRING("1"));
    2957               0 :   } else if (TagName.EqualsLiteral("td"))
    2958                 :   {
    2959               0 :     res = SetAttributeOrEquivalent(newElement, NS_LITERAL_STRING("valign"),
    2960               0 :                                    NS_LITERAL_STRING("top"), true);
    2961                 :   }
    2962                 :   // ADD OTHER TAGS HERE
    2963                 : 
    2964               0 :   if (NS_SUCCEEDED(res))
    2965                 :   {
    2966               0 :     *aReturn = newElement;
    2967                 :     // Getters must addref
    2968               0 :     NS_ADDREF(*aReturn);
    2969                 :   }
    2970                 : 
    2971               0 :   return res;
    2972                 : }
    2973                 : 
    2974                 : NS_IMETHODIMP
    2975               0 : nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
    2976                 : {
    2977               0 :   nsresult res=NS_ERROR_NULL_POINTER;
    2978               0 :   nsCOMPtr<nsISelection> selection;
    2979                 : 
    2980               0 :   NS_ENSURE_TRUE(aAnchorElement, NS_ERROR_NULL_POINTER); 
    2981                 : 
    2982                 : 
    2983                 :   // We must have a real selection
    2984               0 :   res = GetSelection(getter_AddRefs(selection));
    2985               0 :   if (!selection)
    2986                 :   {
    2987               0 :     res = NS_ERROR_NULL_POINTER;
    2988                 :   }
    2989               0 :   NS_ENSURE_SUCCESS(res, res);
    2990               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    2991                 : 
    2992                 :   bool isCollapsed;
    2993               0 :   res = selection->GetIsCollapsed(&isCollapsed);
    2994               0 :   if (NS_FAILED(res))
    2995               0 :     isCollapsed = true;
    2996                 :   
    2997               0 :   if (isCollapsed)
    2998                 :   {
    2999               0 :     printf("InsertLinkAroundSelection called but there is no selection!!!\n");     
    3000               0 :     res = NS_OK;
    3001                 :   } else {
    3002                 :     // Be sure we were given an anchor element
    3003               0 :     nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aAnchorElement);
    3004               0 :     if (anchor)
    3005                 :     {
    3006               0 :       nsAutoString href;
    3007               0 :       res = anchor->GetHref(href);
    3008               0 :       NS_ENSURE_SUCCESS(res, res);
    3009               0 :       if (!href.IsEmpty())      
    3010                 :       {
    3011               0 :         nsAutoEditBatch beginBatching(this);
    3012                 : 
    3013                 :         // Set all attributes found on the supplied anchor element
    3014               0 :         nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
    3015               0 :         aAnchorElement->GetAttributes(getter_AddRefs(attrMap));
    3016               0 :         NS_ENSURE_TRUE(attrMap, NS_ERROR_FAILURE);
    3017                 : 
    3018                 :         PRUint32 count, i;
    3019               0 :         attrMap->GetLength(&count);
    3020               0 :         nsAutoString name, value;
    3021                 : 
    3022               0 :         for (i = 0; i < count; i++)
    3023                 :         {
    3024               0 :           nsCOMPtr<nsIDOMNode> attrNode;
    3025               0 :           res = attrMap->Item(i, getter_AddRefs(attrNode));
    3026               0 :           NS_ENSURE_SUCCESS(res, res);
    3027                 : 
    3028               0 :           if (attrNode)
    3029                 :           {
    3030               0 :             nsCOMPtr<nsIDOMAttr> attribute = do_QueryInterface(attrNode);
    3031               0 :             if (attribute)
    3032                 :             {
    3033                 :               // We must clear the string buffers
    3034                 :               //   because GetName, GetValue appends to previous string!
    3035               0 :               name.Truncate();
    3036               0 :               value.Truncate();
    3037                 : 
    3038               0 :               res = attribute->GetName(name);
    3039               0 :               NS_ENSURE_SUCCESS(res, res);
    3040                 : 
    3041               0 :               res = attribute->GetValue(value);
    3042               0 :               NS_ENSURE_SUCCESS(res, res);
    3043                 : 
    3044               0 :               res = SetInlineProperty(nsEditProperty::a, name, value);
    3045               0 :               NS_ENSURE_SUCCESS(res, res);
    3046                 :             }
    3047                 :           }
    3048                 :         }
    3049                 :       }
    3050                 :     }
    3051                 :   }
    3052               0 :   return res;
    3053                 : }
    3054                 : 
    3055                 : NS_IMETHODIMP
    3056               0 : nsHTMLEditor::SetHTMLBackgroundColor(const nsAString& aColor)
    3057                 : {
    3058               0 :   NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document");
    3059                 :   
    3060                 :   // Find a selected or enclosing table element to set background on
    3061               0 :   nsCOMPtr<nsIDOMElement> element;
    3062                 :   PRInt32 selectedCount;
    3063               0 :   nsAutoString tagName;
    3064                 :   nsresult res = GetSelectedOrParentTableElement(tagName, &selectedCount,
    3065               0 :                                                  getter_AddRefs(element));
    3066               0 :   NS_ENSURE_SUCCESS(res, res);
    3067                 : 
    3068               0 :   bool setColor = !aColor.IsEmpty();
    3069                 : 
    3070               0 :   NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor");
    3071               0 :   if (element)
    3072                 :   {
    3073               0 :     if (selectedCount > 0)
    3074                 :     {
    3075                 :       // Traverse all selected cells
    3076               0 :       nsCOMPtr<nsIDOMElement> cell;
    3077               0 :       res = GetFirstSelectedCell(nsnull, getter_AddRefs(cell));
    3078               0 :       if (NS_SUCCEEDED(res) && cell)
    3079                 :       {
    3080               0 :         while(cell)
    3081                 :         {
    3082               0 :           if (setColor)
    3083               0 :             res = SetAttribute(cell, bgcolor, aColor);
    3084                 :           else
    3085               0 :             res = RemoveAttribute(cell, bgcolor);
    3086               0 :           if (NS_FAILED(res)) break;
    3087                 : 
    3088               0 :           GetNextSelectedCell(nsnull, getter_AddRefs(cell));
    3089                 :         };
    3090               0 :         return res;
    3091                 :       }
    3092                 :     }
    3093                 :     // If we failed to find a cell, fall through to use originally-found element
    3094                 :   } else {
    3095                 :     // No table element -- set the background color on the body tag
    3096               0 :     element = do_QueryInterface(GetRoot());
    3097               0 :     NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
    3098                 :   }
    3099                 :   // Use the editor method that goes through the transaction system
    3100               0 :   if (setColor)
    3101               0 :     res = SetAttribute(element, bgcolor, aColor);
    3102                 :   else
    3103               0 :     res = RemoveAttribute(element, bgcolor);
    3104                 : 
    3105               0 :   return res;
    3106                 : }
    3107                 : 
    3108               0 : NS_IMETHODIMP nsHTMLEditor::SetBodyAttribute(const nsAString& aAttribute, const nsAString& aValue)
    3109                 : {
    3110                 :   // TODO: Check selection for Cell, Row, Column or table and do color on appropriate level
    3111                 : 
    3112               0 :   NS_ASSERTION(mDocWeak, "Missing Editor DOM Document");
    3113                 :   
    3114                 :   // Set the background color attribute on the body tag
    3115               0 :   nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
    3116               0 :   NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
    3117                 : 
    3118                 :   // Use the editor method that goes through the transaction system
    3119               0 :   return SetAttribute(bodyElement, aAttribute, aValue);
    3120                 : }
    3121                 : 
    3122                 : NS_IMETHODIMP
    3123               0 : nsHTMLEditor::GetLinkedObjects(nsISupportsArray** aNodeList)
    3124                 : {
    3125               0 :   NS_ENSURE_TRUE(aNodeList, NS_ERROR_NULL_POINTER);
    3126                 : 
    3127                 :   nsresult res;
    3128                 : 
    3129               0 :   res = NS_NewISupportsArray(aNodeList);
    3130               0 :   NS_ENSURE_SUCCESS(res, res);
    3131               0 :   NS_ENSURE_TRUE(*aNodeList, NS_ERROR_NULL_POINTER);
    3132                 : 
    3133                 :   nsCOMPtr<nsIContentIterator> iter =
    3134               0 :        do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res);
    3135               0 :   NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
    3136               0 :   if ((NS_SUCCEEDED(res)))
    3137                 :   {
    3138               0 :     nsCOMPtr<nsIDOMDocument> domdoc;
    3139               0 :     nsEditor::GetDocument(getter_AddRefs(domdoc));
    3140               0 :     NS_ENSURE_TRUE(domdoc, NS_ERROR_UNEXPECTED);
    3141                 : 
    3142               0 :     nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc));
    3143               0 :     NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
    3144                 : 
    3145               0 :     iter->Init(doc->GetRootElement());
    3146                 : 
    3147                 :     // loop through the content iterator for each content node
    3148               0 :     while (!iter->IsDone())
    3149                 :     {
    3150               0 :       nsCOMPtr<nsIDOMNode> node (do_QueryInterface(iter->GetCurrentNode()));
    3151               0 :       if (node)
    3152                 :       {
    3153                 :         // Let nsURIRefObject make the hard decisions:
    3154               0 :         nsCOMPtr<nsIURIRefObject> refObject;
    3155               0 :         res = NS_NewHTMLURIRefObject(getter_AddRefs(refObject), node);
    3156               0 :         if (NS_SUCCEEDED(res))
    3157                 :         {
    3158               0 :           nsCOMPtr<nsISupports> isupp (do_QueryInterface(refObject));
    3159                 : 
    3160               0 :           (*aNodeList)->AppendElement(isupp);
    3161                 :         }
    3162                 :       }
    3163               0 :       iter->Next();
    3164                 :     }
    3165                 :   }
    3166                 : 
    3167               0 :   return NS_OK;
    3168                 : }
    3169                 : 
    3170                 : 
    3171                 : NS_IMETHODIMP
    3172               0 : nsHTMLEditor::AddStyleSheet(const nsAString &aURL)
    3173                 : {
    3174                 :   // Enable existing sheet if already loaded.
    3175               0 :   if (EnableExistingStyleSheet(aURL))
    3176               0 :     return NS_OK;
    3177                 : 
    3178                 :   // Lose the previously-loaded sheet so there's nothing to replace
    3179                 :   // This pattern is different from Override methods because
    3180                 :   //  we must wait to remove mLastStyleSheetURL and add new sheet
    3181                 :   //  at the same time (in StyleSheetLoaded callback) so they are undoable together
    3182               0 :   mLastStyleSheetURL.Truncate();
    3183               0 :   return ReplaceStyleSheet(aURL);
    3184                 : }
    3185                 : 
    3186                 : NS_IMETHODIMP
    3187               0 : nsHTMLEditor::ReplaceStyleSheet(const nsAString& aURL)
    3188                 : {
    3189                 :   // Enable existing sheet if already loaded.
    3190               0 :   if (EnableExistingStyleSheet(aURL))
    3191                 :   {
    3192                 :     // Disable last sheet if not the same as new one
    3193               0 :     if (!mLastStyleSheetURL.IsEmpty() && !mLastStyleSheetURL.Equals(aURL))
    3194               0 :       return EnableStyleSheet(mLastStyleSheetURL, false);
    3195                 : 
    3196               0 :     return NS_OK;
    3197                 :   }
    3198                 : 
    3199                 :   // Make sure the pres shell doesn't disappear during the load.
    3200               0 :   NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
    3201               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    3202               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
    3203                 : 
    3204               0 :   nsCOMPtr<nsIURI> uaURI;
    3205               0 :   nsresult rv = NS_NewURI(getter_AddRefs(uaURI), aURL);
    3206               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3207                 : 
    3208                 :   return ps->GetDocument()->CSSLoader()->
    3209               0 :     LoadSheet(uaURI, nsnull, EmptyCString(), this);
    3210                 : }
    3211                 : 
    3212                 : NS_IMETHODIMP
    3213               0 : nsHTMLEditor::RemoveStyleSheet(const nsAString &aURL)
    3214                 : {
    3215               0 :   nsRefPtr<nsCSSStyleSheet> sheet;
    3216               0 :   nsresult rv = GetStyleSheetForURL(aURL, getter_AddRefs(sheet));
    3217               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3218               0 :   NS_ENSURE_TRUE(sheet, NS_ERROR_UNEXPECTED);
    3219                 : 
    3220               0 :   nsRefPtr<RemoveStyleSheetTxn> txn;
    3221               0 :   rv = CreateTxnForRemoveStyleSheet(sheet, getter_AddRefs(txn));
    3222               0 :   if (!txn) rv = NS_ERROR_NULL_POINTER;
    3223               0 :   if (NS_SUCCEEDED(rv))
    3224                 :   {
    3225               0 :     rv = DoTransaction(txn);
    3226               0 :     if (NS_SUCCEEDED(rv))
    3227               0 :       mLastStyleSheetURL.Truncate();        // forget it
    3228                 : 
    3229                 :     // Remove it from our internal list
    3230               0 :     rv = RemoveStyleSheetFromList(aURL);
    3231                 :   }
    3232                 :   
    3233               0 :   return rv;
    3234                 : }
    3235                 : 
    3236                 : 
    3237                 : NS_IMETHODIMP
    3238               0 : nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL)
    3239                 : {
    3240                 :   // Enable existing sheet if already loaded.
    3241               0 :   if (EnableExistingStyleSheet(aURL))
    3242               0 :     return NS_OK;
    3243                 : 
    3244                 :   // Make sure the pres shell doesn't disappear during the load.
    3245               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    3246               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
    3247                 : 
    3248               0 :   nsCOMPtr<nsIURI> uaURI;
    3249               0 :   nsresult rv = NS_NewURI(getter_AddRefs(uaURI), aURL);
    3250               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3251                 : 
    3252                 :   // We MUST ONLY load synchronous local files (no @import)
    3253                 :   // XXXbz Except this will actually try to load remote files
    3254                 :   // synchronously, of course..
    3255               0 :   nsRefPtr<nsCSSStyleSheet> sheet;
    3256                 :   // Editor override style sheets may want to style Gecko anonymous boxes
    3257                 :   rv = ps->GetDocument()->CSSLoader()->
    3258               0 :     LoadSheetSync(uaURI, true, true, getter_AddRefs(sheet));
    3259                 : 
    3260                 :   // Synchronous loads should ALWAYS return completed
    3261               0 :   NS_ENSURE_TRUE(sheet, NS_ERROR_NULL_POINTER);
    3262                 : 
    3263                 :   // Add the override style sheet
    3264                 :   // (This checks if already exists)
    3265               0 :   ps->AddOverrideStyleSheet(sheet);
    3266                 : 
    3267               0 :   ps->ReconstructStyleData();
    3268                 : 
    3269                 :   // Save as the last-loaded sheet
    3270               0 :   mLastOverrideStyleSheetURL = aURL;
    3271                 : 
    3272                 :   //Add URL and style sheet to our lists
    3273               0 :   return AddNewStyleSheetToList(aURL, sheet);
    3274                 : }
    3275                 : 
    3276                 : NS_IMETHODIMP
    3277               0 : nsHTMLEditor::ReplaceOverrideStyleSheet(const nsAString& aURL)
    3278                 : {
    3279                 :   // Enable existing sheet if already loaded.
    3280               0 :   if (EnableExistingStyleSheet(aURL))
    3281                 :   {
    3282                 :     // Disable last sheet if not the same as new one
    3283               0 :     if (!mLastOverrideStyleSheetURL.IsEmpty() && !mLastOverrideStyleSheetURL.Equals(aURL))
    3284               0 :       return EnableStyleSheet(mLastOverrideStyleSheetURL, false);
    3285                 : 
    3286               0 :     return NS_OK;
    3287                 :   }
    3288                 :   // Remove the previous sheet
    3289               0 :   if (!mLastOverrideStyleSheetURL.IsEmpty())
    3290               0 :     RemoveOverrideStyleSheet(mLastOverrideStyleSheetURL);
    3291                 : 
    3292               0 :   return AddOverrideStyleSheet(aURL);
    3293                 : }
    3294                 : 
    3295                 : // Do NOT use transaction system for override style sheets
    3296                 : NS_IMETHODIMP
    3297               0 : nsHTMLEditor::RemoveOverrideStyleSheet(const nsAString &aURL)
    3298                 : {
    3299               0 :   nsRefPtr<nsCSSStyleSheet> sheet;
    3300               0 :   GetStyleSheetForURL(aURL, getter_AddRefs(sheet));
    3301                 : 
    3302                 :   // Make sure we remove the stylesheet from our internal list in all
    3303                 :   // cases.
    3304               0 :   nsresult rv = RemoveStyleSheetFromList(aURL);
    3305                 : 
    3306               0 :   NS_ENSURE_TRUE(sheet, NS_OK); /// Don't fail if sheet not found
    3307                 : 
    3308               0 :   NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
    3309               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    3310               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
    3311                 : 
    3312               0 :   ps->RemoveOverrideStyleSheet(sheet);
    3313               0 :   ps->ReconstructStyleData();
    3314                 : 
    3315                 :   // Remove it from our internal list
    3316               0 :   return rv;
    3317                 : }
    3318                 : 
    3319                 : NS_IMETHODIMP
    3320               0 : nsHTMLEditor::EnableStyleSheet(const nsAString &aURL, bool aEnable)
    3321                 : {
    3322               0 :   nsRefPtr<nsCSSStyleSheet> sheet;
    3323               0 :   nsresult rv = GetStyleSheetForURL(aURL, getter_AddRefs(sheet));
    3324               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3325               0 :   NS_ENSURE_TRUE(sheet, NS_OK); // Don't fail if sheet not found
    3326                 : 
    3327                 :   // Ensure the style sheet is owned by our document.
    3328               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    3329               0 :   sheet->SetOwningDocument(doc);
    3330                 : 
    3331               0 :   return sheet->SetDisabled(!aEnable);
    3332                 : }
    3333                 : 
    3334                 : bool
    3335               0 : nsHTMLEditor::EnableExistingStyleSheet(const nsAString &aURL)
    3336                 : {
    3337               0 :   nsRefPtr<nsCSSStyleSheet> sheet;
    3338               0 :   nsresult rv = GetStyleSheetForURL(aURL, getter_AddRefs(sheet));
    3339               0 :   NS_ENSURE_SUCCESS(rv, false);
    3340                 : 
    3341                 :   // Enable sheet if already loaded.
    3342               0 :   if (sheet)
    3343                 :   {
    3344                 :     // Ensure the style sheet is owned by our document.
    3345               0 :     nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    3346               0 :     sheet->SetOwningDocument(doc);
    3347                 : 
    3348               0 :     sheet->SetDisabled(false);
    3349               0 :     return true;
    3350                 :   }
    3351               0 :   return false;
    3352                 : }
    3353                 : 
    3354                 : nsresult
    3355               0 : nsHTMLEditor::AddNewStyleSheetToList(const nsAString &aURL,
    3356                 :                                      nsCSSStyleSheet *aStyleSheet)
    3357                 : {
    3358               0 :   PRUint32 countSS = mStyleSheets.Length();
    3359               0 :   PRUint32 countU = mStyleSheetURLs.Length();
    3360                 : 
    3361               0 :   if (countSS != countU)
    3362               0 :     return NS_ERROR_UNEXPECTED;
    3363                 : 
    3364               0 :   if (!mStyleSheetURLs.AppendElement(aURL))
    3365               0 :     return NS_ERROR_UNEXPECTED;
    3366                 : 
    3367               0 :   return mStyleSheets.AppendElement(aStyleSheet) ? NS_OK : NS_ERROR_UNEXPECTED;
    3368                 : }
    3369                 : 
    3370                 : nsresult
    3371               0 : nsHTMLEditor::RemoveStyleSheetFromList(const nsAString &aURL)
    3372                 : {
    3373                 :   // is it already in the list?
    3374                 :   PRUint32 foundIndex;
    3375               0 :   foundIndex = mStyleSheetURLs.IndexOf(aURL);
    3376               0 :   if (foundIndex == mStyleSheetURLs.NoIndex)
    3377               0 :     return NS_ERROR_FAILURE;
    3378                 : 
    3379                 :   // Attempt both removals; if one fails there's not much we can do.
    3380               0 :   mStyleSheets.RemoveElementAt(foundIndex);
    3381               0 :   mStyleSheetURLs.RemoveElementAt(foundIndex);
    3382                 : 
    3383               0 :   return NS_OK;
    3384                 : }
    3385                 : 
    3386                 : NS_IMETHODIMP
    3387               0 : nsHTMLEditor::GetStyleSheetForURL(const nsAString &aURL,
    3388                 :                                   nsCSSStyleSheet **aStyleSheet)
    3389                 : {
    3390               0 :   NS_ENSURE_ARG_POINTER(aStyleSheet);
    3391               0 :   *aStyleSheet = 0;
    3392                 : 
    3393                 :   // is it already in the list?
    3394                 :   PRUint32 foundIndex;
    3395               0 :   foundIndex = mStyleSheetURLs.IndexOf(aURL);
    3396               0 :   if (foundIndex == mStyleSheetURLs.NoIndex)
    3397               0 :     return NS_OK; //No sheet -- don't fail!
    3398                 : 
    3399               0 :   *aStyleSheet = mStyleSheets[foundIndex];
    3400               0 :   NS_ENSURE_TRUE(*aStyleSheet, NS_ERROR_FAILURE);
    3401                 : 
    3402               0 :   NS_ADDREF(*aStyleSheet);
    3403                 : 
    3404               0 :   return NS_OK;
    3405                 : }
    3406                 : 
    3407                 : NS_IMETHODIMP
    3408               0 : nsHTMLEditor::GetURLForStyleSheet(nsCSSStyleSheet *aStyleSheet,
    3409                 :                                   nsAString &aURL)
    3410                 : {
    3411                 :   // is it already in the list?
    3412               0 :   PRInt32 foundIndex = mStyleSheets.IndexOf(aStyleSheet);
    3413                 : 
    3414                 :   // Don't fail if we don't find it in our list
    3415                 :   // Note: mStyleSheets is nsCOMArray, so its IndexOf() method
    3416                 :   // returns -1 on failure.
    3417               0 :   if (foundIndex == -1)
    3418               0 :     return NS_OK;
    3419                 : 
    3420                 :   // Found it in the list!
    3421               0 :   aURL = mStyleSheetURLs[foundIndex];
    3422               0 :   return NS_OK;
    3423                 : }
    3424                 : 
    3425                 : /*
    3426                 :  * nsIEditorMailSupport methods
    3427                 :  */
    3428                 : 
    3429                 : NS_IMETHODIMP
    3430               0 : nsHTMLEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList)
    3431                 : {
    3432               0 :   NS_ENSURE_TRUE(aNodeList, NS_ERROR_NULL_POINTER);
    3433                 : 
    3434               0 :   nsresult rv = NS_NewISupportsArray(aNodeList);
    3435               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3436               0 :   NS_ENSURE_TRUE(*aNodeList, NS_ERROR_NULL_POINTER);
    3437                 : 
    3438                 :   nsCOMPtr<nsIContentIterator> iter =
    3439               0 :       do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &rv);
    3440               0 :   NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
    3441               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3442                 : 
    3443               0 :   nsCOMPtr<nsIDOMDocument> domdoc;
    3444               0 :   nsEditor::GetDocument(getter_AddRefs(domdoc));
    3445               0 :   NS_ENSURE_TRUE(domdoc, NS_ERROR_UNEXPECTED);
    3446                 : 
    3447               0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
    3448               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
    3449                 : 
    3450               0 :   iter->Init(doc->GetRootElement());
    3451                 : 
    3452                 :   // Loop through the content iterator for each content node.
    3453               0 :   while (!iter->IsDone()) {
    3454               0 :     nsINode* node = iter->GetCurrentNode();
    3455               0 :     if (node->IsElement()) {
    3456               0 :       dom::Element* element = node->AsElement();
    3457                 : 
    3458                 :       // See if it's an image or an embed and also include all links.
    3459                 :       // Let mail decide which link to send or not
    3460               0 :       if (element->IsHTML(nsGkAtoms::img) ||
    3461               0 :           element->IsHTML(nsGkAtoms::embed) ||
    3462               0 :           element->IsHTML(nsGkAtoms::a) ||
    3463               0 :           (element->IsHTML(nsGkAtoms::body) &&
    3464               0 :            element->HasAttr(kNameSpaceID_None, nsGkAtoms::background))) {
    3465               0 :         nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(node);
    3466               0 :         (*aNodeList)->AppendElement(domNode);
    3467                 :       }
    3468                 :     }
    3469               0 :     iter->Next();
    3470                 :   }
    3471                 : 
    3472               0 :   return rv;
    3473                 : }
    3474                 : 
    3475                 : 
    3476                 : NS_IMETHODIMP
    3477               0 : nsHTMLEditor::DeleteNode(nsIDOMNode* aNode)
    3478                 : {
    3479                 :   // do nothing if the node is read-only
    3480               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
    3481               0 :   if (!IsModifiableNode(aNode) && !IsMozEditorBogusNode(content)) {
    3482               0 :     return NS_ERROR_FAILURE;
    3483                 :   }
    3484                 : 
    3485               0 :   nsCOMPtr<nsIDOMNode> selectAllNode = FindUserSelectAllNode(aNode);
    3486                 :   
    3487               0 :   if (selectAllNode)
    3488                 :   {
    3489               0 :     return nsEditor::DeleteNode(selectAllNode);
    3490                 :   }
    3491               0 :   return nsEditor::DeleteNode(aNode);
    3492                 : }
    3493                 : 
    3494               0 : NS_IMETHODIMP nsHTMLEditor::DeleteText(nsIDOMCharacterData *aTextNode,
    3495                 :                                        PRUint32             aOffset,
    3496                 :                                        PRUint32             aLength)
    3497                 : {
    3498                 :   // do nothing if the node is read-only
    3499               0 :   if (!IsModifiableNode(aTextNode)) {
    3500               0 :     return NS_ERROR_FAILURE;
    3501                 :   }
    3502                 : 
    3503               0 :   nsCOMPtr<nsIDOMNode> selectAllNode = FindUserSelectAllNode(aTextNode);
    3504                 :   
    3505               0 :   if (selectAllNode)
    3506                 :   {
    3507               0 :     return nsEditor::DeleteNode(selectAllNode);
    3508                 :   }
    3509               0 :   return nsEditor::DeleteText(aTextNode, aOffset, aLength);
    3510                 : }
    3511                 : 
    3512               0 : NS_IMETHODIMP nsHTMLEditor::InsertTextImpl(const nsAString& aStringToInsert, 
    3513                 :                                            nsCOMPtr<nsIDOMNode> *aInOutNode, 
    3514                 :                                            PRInt32 *aInOutOffset,
    3515                 :                                            nsIDOMDocument *aDoc)
    3516                 : {
    3517                 :   // do nothing if the node is read-only
    3518               0 :   if (!IsModifiableNode(*aInOutNode)) {
    3519               0 :     return NS_ERROR_FAILURE;
    3520                 :   }
    3521                 : 
    3522               0 :   return nsEditor::InsertTextImpl(aStringToInsert, aInOutNode, aInOutOffset, aDoc);
    3523                 : }
    3524                 : 
    3525                 : void
    3526               0 : nsHTMLEditor::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer,
    3527                 :                               nsIContent* aFirstNewContent,
    3528                 :                               PRInt32 aIndexInContainer)
    3529                 : {
    3530               0 :   ContentInserted(aDocument, aContainer, aFirstNewContent, aIndexInContainer);
    3531               0 : }
    3532                 : 
    3533                 : void
    3534               0 : nsHTMLEditor::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
    3535                 :                               nsIContent* aChild, PRInt32 aIndexInContainer)
    3536                 : {
    3537               0 :   if (!aChild) {
    3538               0 :     return;
    3539                 :   }
    3540                 : 
    3541               0 :   nsCOMPtr<nsIHTMLEditor> kungFuDeathGrip(this);
    3542                 : 
    3543               0 :   if (ShouldReplaceRootElement()) {
    3544               0 :     ResetRootElementAndEventTarget();
    3545                 :   }
    3546                 :   // We don't need to handle our own modifications
    3547               0 :   else if (!mAction && (aContainer ? aContainer->IsEditable() : aDocument->IsEditable())) {
    3548               0 :     if (IsMozEditorBogusNode(aChild)) {
    3549                 :       // Ignore insertion of the bogus node
    3550                 :       return;
    3551                 :     }
    3552               0 :     mRules->DocumentModified();
    3553                 : 
    3554                 :     // Update spellcheck for only the newly-inserted node (bug 743819)
    3555               0 :     if (mInlineSpellChecker) {
    3556               0 :       nsRefPtr<nsRange> range = new nsRange();
    3557                 :       nsresult res = range->Set(aContainer, aIndexInContainer,
    3558               0 :                                 aContainer, aIndexInContainer + 1);
    3559               0 :       if (NS_SUCCEEDED(res)) {
    3560               0 :         mInlineSpellChecker->SpellCheckRange(range);
    3561                 :       }
    3562                 :     }
    3563                 :   }
    3564                 : }
    3565                 : 
    3566                 : void
    3567               0 : nsHTMLEditor::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
    3568                 :                              nsIContent* aChild, PRInt32 aIndexInContainer,
    3569                 :                              nsIContent* aPreviousSibling)
    3570                 : {
    3571               0 :   nsCOMPtr<nsIHTMLEditor> kungFuDeathGrip(this);
    3572                 : 
    3573               0 :   if (SameCOMIdentity(aChild, mRootElement)) {
    3574               0 :     ResetRootElementAndEventTarget();
    3575                 :   }
    3576                 :   // We don't need to handle our own modifications
    3577               0 :   else if (!mAction && (aContainer ? aContainer->IsEditable() : aDocument->IsEditable())) {
    3578               0 :     if (aChild && IsMozEditorBogusNode(aChild)) {
    3579                 :       // Ignore removal of the bogus node
    3580                 :       return;
    3581                 :     }
    3582               0 :     mRules->DocumentModified();
    3583                 :   }
    3584                 : }
    3585                 : 
    3586                 : 
    3587                 : /* This routine examines aNode and its ancestors looking for any node which has the
    3588                 :    -moz-user-select: all style lit.  Return the highest such ancestor.  */
    3589                 : already_AddRefed<nsIDOMNode>
    3590               0 : nsHTMLEditor::FindUserSelectAllNode(nsIDOMNode* aNode)
    3591                 : {
    3592               0 :   nsCOMPtr<nsIDOMNode> node = aNode;
    3593               0 :   nsCOMPtr<nsIDOMElement> root = do_QueryInterface(GetRoot());
    3594               0 :   if (!nsEditorUtils::IsDescendantOf(aNode, root))
    3595               0 :     return nsnull;
    3596                 : 
    3597               0 :   nsCOMPtr<nsIDOMNode> resultNode;  // starts out empty
    3598               0 :   nsAutoString mozUserSelectValue;
    3599               0 :   while (node)
    3600                 :   {
    3601                 :     // retrieve the computed style of -moz-user-select for node
    3602               0 :     mHTMLCSSUtils->GetComputedProperty(node, nsEditProperty::cssMozUserSelect, mozUserSelectValue);
    3603               0 :     if (mozUserSelectValue.EqualsLiteral("all"))
    3604                 :     {
    3605               0 :       resultNode = node;
    3606                 :     }
    3607               0 :     if (node != root)
    3608                 :     {
    3609               0 :       nsCOMPtr<nsIDOMNode> tmp;
    3610               0 :       node->GetParentNode(getter_AddRefs(tmp));
    3611               0 :       node = tmp;
    3612                 :     }
    3613                 :     else
    3614                 :     {
    3615               0 :       node = nsnull;
    3616                 :     }
    3617                 :   } 
    3618                 : 
    3619               0 :   return resultNode.forget();
    3620                 : }
    3621                 : 
    3622                 : NS_IMETHODIMP_(bool)
    3623               0 : nsHTMLEditor::IsModifiableNode(nsIDOMNode *aNode)
    3624                 : {
    3625               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    3626               0 :   return IsModifiableNode(node);
    3627                 : }
    3628                 : 
    3629                 : bool
    3630               0 : nsHTMLEditor::IsModifiableNode(nsINode *aNode)
    3631                 : {
    3632               0 :   return !aNode || aNode->IsEditable();
    3633                 : }
    3634                 : 
    3635               0 : static nsresult SetSelectionAroundHeadChildren(nsCOMPtr<nsISelection> aSelection, nsWeakPtr aDocWeak)
    3636                 : {
    3637               0 :   nsresult res = NS_OK;
    3638                 :   // Set selection around <head> node
    3639               0 :   nsCOMPtr<nsIDOMDocument> doc = do_QueryReferent(aDocWeak);
    3640               0 :   NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
    3641                 : 
    3642               0 :   nsCOMPtr<nsIDOMNodeList>nodeList; 
    3643               0 :   res = doc->GetElementsByTagName(NS_LITERAL_STRING("head"), getter_AddRefs(nodeList));
    3644               0 :   NS_ENSURE_SUCCESS(res, res);
    3645               0 :   NS_ENSURE_TRUE(nodeList, NS_ERROR_NULL_POINTER);
    3646                 : 
    3647                 :   PRUint32 count; 
    3648               0 :   nodeList->GetLength(&count);
    3649               0 :   if (count < 1) return NS_ERROR_FAILURE;
    3650                 : 
    3651               0 :   nsCOMPtr<nsIDOMNode> headNode;
    3652               0 :   res = nodeList->Item(0, getter_AddRefs(headNode)); 
    3653               0 :   NS_ENSURE_SUCCESS(res, res);
    3654               0 :   NS_ENSURE_TRUE(headNode, NS_ERROR_NULL_POINTER);
    3655                 : 
    3656                 :   // Collapse selection to before first child of the head,
    3657               0 :   res = aSelection->Collapse(headNode, 0);
    3658               0 :   NS_ENSURE_SUCCESS(res, res);
    3659                 : 
    3660                 :   //  then extend it to just after
    3661               0 :   nsCOMPtr<nsIDOMNodeList> childNodes;
    3662               0 :   res = headNode->GetChildNodes(getter_AddRefs(childNodes));
    3663               0 :   NS_ENSURE_SUCCESS(res, res);
    3664               0 :   NS_ENSURE_TRUE(childNodes, NS_ERROR_NULL_POINTER);
    3665                 :   PRUint32 childCount;
    3666               0 :   childNodes->GetLength(&childCount);
    3667                 : 
    3668               0 :   return aSelection->Extend(headNode, childCount+1);
    3669                 : }
    3670                 : 
    3671                 : NS_IMETHODIMP
    3672               0 : nsHTMLEditor::GetHeadContentsAsHTML(nsAString& aOutputString)
    3673                 : {
    3674               0 :   nsCOMPtr<nsISelection> selection;
    3675               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    3676               0 :   NS_ENSURE_SUCCESS(res, res);
    3677               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    3678                 : 
    3679                 :   // Save current selection
    3680               0 :   nsAutoSelectionReset selectionResetter(selection, this);
    3681                 : 
    3682               0 :   res = SetSelectionAroundHeadChildren(selection, mDocWeak);
    3683               0 :   NS_ENSURE_SUCCESS(res, res);
    3684                 : 
    3685               0 :   res = OutputToString(NS_LITERAL_STRING("text/html"),
    3686                 :                        nsIDocumentEncoder::OutputSelectionOnly,
    3687               0 :                        aOutputString);
    3688               0 :   if (NS_SUCCEEDED(res))
    3689                 :   {
    3690                 :     // Selection always includes <body></body>,
    3691                 :     //  so terminate there
    3692               0 :     nsReadingIterator<PRUnichar> findIter,endFindIter;
    3693               0 :     aOutputString.BeginReading(findIter);
    3694               0 :     aOutputString.EndReading(endFindIter);
    3695                 :     //counting on our parser to always lower case!!!
    3696               0 :     if (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("<body"),
    3697               0 :                                       findIter, endFindIter))
    3698                 :     {
    3699               0 :       nsReadingIterator<PRUnichar> beginIter;
    3700               0 :       aOutputString.BeginReading(beginIter);
    3701               0 :       PRInt32 offset = Distance(beginIter, findIter);//get the distance
    3702                 : 
    3703               0 :       nsWritingIterator<PRUnichar> writeIter;
    3704               0 :       aOutputString.BeginWriting(writeIter);
    3705                 :       // Ensure the string ends in a newline
    3706               0 :       PRUnichar newline ('\n');
    3707               0 :       findIter.advance(-1);
    3708               0 :       if (offset ==0 || (offset >0 &&  (*findIter) != newline)) //check for 0
    3709                 :       {
    3710               0 :         writeIter.advance(offset);
    3711               0 :         *writeIter = newline;
    3712               0 :         aOutputString.Truncate(offset+1);
    3713                 :       }
    3714                 :     }
    3715                 :   }
    3716               0 :   return res;
    3717                 : }
    3718                 : 
    3719                 : NS_IMETHODIMP
    3720               0 : nsHTMLEditor::DebugUnitTests(PRInt32 *outNumTests, PRInt32 *outNumTestsFailed)
    3721                 : {
    3722                 : #ifdef DEBUG
    3723               0 :   NS_ENSURE_TRUE(outNumTests && outNumTestsFailed, NS_ERROR_NULL_POINTER);
    3724                 : 
    3725               0 :   TextEditorTest *tester = new TextEditorTest();
    3726               0 :   NS_ENSURE_TRUE(tester, NS_ERROR_OUT_OF_MEMORY);
    3727                 :    
    3728               0 :   tester->Run(this, outNumTests, outNumTestsFailed);
    3729               0 :   delete tester;
    3730               0 :   return NS_OK;
    3731                 : #else
    3732                 :   return NS_ERROR_NOT_IMPLEMENTED;
    3733                 : #endif
    3734                 : }
    3735                 : 
    3736                 : 
    3737                 : NS_IMETHODIMP 
    3738               0 : nsHTMLEditor::StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate,
    3739                 :                                nsresult aStatus)
    3740                 : {
    3741               0 :   nsresult rv = NS_OK;
    3742               0 :   nsAutoEditBatch batchIt(this);
    3743                 : 
    3744               0 :   if (!mLastStyleSheetURL.IsEmpty())
    3745               0 :     RemoveStyleSheet(mLastStyleSheetURL);
    3746                 : 
    3747               0 :   nsRefPtr<AddStyleSheetTxn> txn;
    3748               0 :   rv = CreateTxnForAddStyleSheet(aSheet, getter_AddRefs(txn));
    3749               0 :   if (!txn) rv = NS_ERROR_NULL_POINTER;
    3750               0 :   if (NS_SUCCEEDED(rv))
    3751                 :   {
    3752               0 :     rv = DoTransaction(txn);
    3753               0 :     if (NS_SUCCEEDED(rv))
    3754                 :     {
    3755                 :       // Get the URI, then url spec from the sheet
    3756               0 :       nsCAutoString spec;
    3757               0 :       rv = aSheet->GetSheetURI()->GetSpec(spec);
    3758                 : 
    3759               0 :       if (NS_SUCCEEDED(rv))
    3760                 :       {
    3761                 :         // Save it so we can remove before applying the next one
    3762               0 :         mLastStyleSheetURL.AssignWithConversion(spec.get());
    3763                 : 
    3764                 :         // Also save in our arrays of urls and sheets
    3765               0 :         AddNewStyleSheetToList(mLastStyleSheetURL, aSheet);
    3766                 :       }
    3767                 :     }
    3768                 :   }
    3769                 : 
    3770               0 :   return NS_OK;
    3771                 : }
    3772                 : 
    3773                 : 
    3774                 : /** All editor operations which alter the doc should be prefaced
    3775                 :  *  with a call to StartOperation, naming the action and direction */
    3776                 : NS_IMETHODIMP
    3777               0 : nsHTMLEditor::StartOperation(PRInt32 opID, nsIEditor::EDirection aDirection)
    3778                 : {
    3779                 :   // Protect the edit rules object from dying
    3780               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    3781                 : 
    3782               0 :   nsEditor::StartOperation(opID, aDirection);  // will set mAction, mDirection
    3783               0 :   if (mRules) return mRules->BeforeEdit(mAction, mDirection);
    3784               0 :   return NS_OK;
    3785                 : }
    3786                 : 
    3787                 : 
    3788                 : /** All editor operations which alter the doc should be followed
    3789                 :  *  with a call to EndOperation */
    3790                 : NS_IMETHODIMP
    3791               0 : nsHTMLEditor::EndOperation()
    3792                 : {
    3793                 :   // Protect the edit rules object from dying
    3794               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    3795                 : 
    3796                 :   // post processing
    3797               0 :   nsresult res = NS_OK;
    3798               0 :   if (mRules) res = mRules->AfterEdit(mAction, mDirection);
    3799               0 :   nsEditor::EndOperation();  // will clear mAction, mDirection
    3800               0 :   return res;
    3801                 : }  
    3802                 : 
    3803                 : bool 
    3804               0 : nsHTMLEditor::TagCanContainTag(const nsAString& aParentTag, const nsAString& aChildTag)  
    3805                 : {
    3806               0 :   nsIParserService* parserService = nsContentUtils::GetParserService();
    3807                 : 
    3808                 :   PRInt32 childTagEnum;
    3809                 :   // XXX Should this handle #cdata-section too?
    3810               0 :   if (aChildTag.EqualsLiteral("#text")) {
    3811               0 :     childTagEnum = eHTMLTag_text;
    3812                 :   }
    3813                 :   else {
    3814               0 :     childTagEnum = parserService->HTMLStringTagToId(aChildTag);
    3815                 :   }
    3816                 : 
    3817               0 :   PRInt32 parentTagEnum = parserService->HTMLStringTagToId(aParentTag);
    3818               0 :   NS_ASSERTION(parentTagEnum < NS_HTML_TAG_MAX,
    3819                 :                "Fix the caller, this type of node can never contain children.");
    3820                 : 
    3821               0 :   return nsHTMLEditUtils::CanContain(parentTagEnum, childTagEnum);
    3822                 : }
    3823                 : 
    3824                 : bool
    3825               0 : nsHTMLEditor::IsContainer(nsINode* aNode)
    3826                 : {
    3827               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
    3828               0 :   return IsContainer(node);
    3829                 : }
    3830                 : 
    3831                 : bool
    3832               0 : nsHTMLEditor::IsContainer(nsIDOMNode *aNode)
    3833                 : {
    3834               0 :   if (!aNode) {
    3835               0 :     return false;
    3836                 :   }
    3837                 : 
    3838               0 :   nsAutoString stringTag;
    3839                 : 
    3840               0 :   nsresult rv = aNode->GetNodeName(stringTag);
    3841               0 :   NS_ENSURE_SUCCESS(rv, false);
    3842                 : 
    3843                 :   PRInt32 tagEnum;
    3844                 :   // XXX Should this handle #cdata-section too?
    3845               0 :   if (stringTag.EqualsLiteral("#text")) {
    3846               0 :     tagEnum = eHTMLTag_text;
    3847                 :   }
    3848                 :   else {
    3849               0 :     tagEnum = nsContentUtils::GetParserService()->HTMLStringTagToId(stringTag);
    3850                 :   }
    3851                 : 
    3852               0 :   return nsHTMLEditUtils::IsContainer(tagEnum);
    3853                 : }
    3854                 : 
    3855                 : 
    3856                 : NS_IMETHODIMP 
    3857               0 : nsHTMLEditor::SelectEntireDocument(nsISelection *aSelection)
    3858                 : {
    3859               0 :   if (!aSelection || !mRules) { return NS_ERROR_NULL_POINTER; }
    3860                 :   
    3861                 :   // Protect the edit rules object from dying
    3862               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    3863                 : 
    3864                 :   // get editor root node
    3865               0 :   nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
    3866                 :   
    3867                 :   // is doc empty?
    3868                 :   bool bDocIsEmpty;
    3869               0 :   nsresult res = mRules->DocumentIsEmpty(&bDocIsEmpty);
    3870               0 :   NS_ENSURE_SUCCESS(res, res);
    3871                 :     
    3872               0 :   if (bDocIsEmpty)
    3873                 :   {
    3874                 :     // if its empty dont select entire doc - that would select the bogus node
    3875               0 :     return aSelection->Collapse(rootElement, 0);
    3876                 :   }
    3877                 : 
    3878               0 :   return nsEditor::SelectEntireDocument(aSelection);
    3879                 : }
    3880                 : 
    3881                 : NS_IMETHODIMP
    3882               0 : nsHTMLEditor::SelectAll()
    3883                 : {
    3884               0 :   ForceCompositionEnd();
    3885                 : 
    3886                 :   nsresult rv;
    3887               0 :   nsCOMPtr<nsISelectionController> selCon;
    3888               0 :   rv = GetSelectionController(getter_AddRefs(selCon));
    3889               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3890                 : 
    3891               0 :   nsCOMPtr<nsISelection> selection;
    3892               0 :   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    3893               0 :                             getter_AddRefs(selection));
    3894               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3895                 : 
    3896               0 :   nsCOMPtr<nsIDOMNode> anchorNode;
    3897               0 :   rv = selection->GetAnchorNode(getter_AddRefs(anchorNode));
    3898               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3899                 : 
    3900               0 :   nsCOMPtr<nsIContent> anchorContent = do_QueryInterface(anchorNode, &rv);
    3901               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3902                 :   
    3903                 :   // If the anchor content has independent selection, we never need to explicitly
    3904                 :   // select its children.
    3905               0 :   if (anchorContent->HasIndependentSelection()) {
    3906               0 :     nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
    3907               0 :     NS_ENSURE_TRUE(selPriv, NS_ERROR_UNEXPECTED);
    3908               0 :     rv = selPriv->SetAncestorLimiter(nsnull);
    3909               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3910               0 :     nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(mRootElement, &rv);
    3911               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3912               0 :     return selection->SelectAllChildren(rootElement);
    3913                 :   }
    3914                 : 
    3915               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    3916               0 :   nsIContent *rootContent = anchorContent->GetSelectionRootContent(ps);
    3917               0 :   NS_ENSURE_TRUE(rootContent, NS_ERROR_UNEXPECTED);
    3918                 : 
    3919               0 :   nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent, &rv);
    3920               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3921                 : 
    3922               0 :   return selection->SelectAllChildren(rootElement);
    3923                 : }
    3924                 : 
    3925                 : 
    3926                 : // this will NOT find aAttribute unless aAttribute has a non-null value
    3927                 : // so singleton attributes like <Table border> will not be matched!
    3928               0 : void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode        *aNode,
    3929                 :                                               nsIAtom           *aProperty, 
    3930                 :                                               const nsAString   *aAttribute, 
    3931                 :                                               const nsAString   *aValue, 
    3932                 :                                               bool              &aIsSet,
    3933                 :                                               nsIDOMNode       **aStyleNode,
    3934                 :                                               nsAString *outValue)
    3935                 : {
    3936                 :   nsresult result;
    3937               0 :   aIsSet = false;  // must be initialized to false for code below to work
    3938               0 :   nsAutoString propName;
    3939               0 :   aProperty->ToString(propName);
    3940               0 :   nsCOMPtr<nsIDOMNode>node = aNode;
    3941                 : 
    3942               0 :   while (node)
    3943                 :   {
    3944               0 :     nsCOMPtr<nsIDOMElement>element;
    3945               0 :     element = do_QueryInterface(node);
    3946               0 :     if (element)
    3947                 :     {
    3948               0 :       nsAutoString tag, value;
    3949               0 :       element->GetTagName(tag);
    3950               0 :       if (propName.Equals(tag, nsCaseInsensitiveStringComparator()))
    3951                 :       {
    3952               0 :         bool found = false;
    3953               0 :         if (aAttribute && 0!=aAttribute->Length())
    3954                 :         {
    3955               0 :           element->GetAttribute(*aAttribute, value);
    3956               0 :           if (outValue) *outValue = value;
    3957               0 :           if (!value.IsEmpty())
    3958                 :           {
    3959               0 :             if (!aValue) {
    3960               0 :               found = true;
    3961                 :             }
    3962                 :             else
    3963                 :             {
    3964               0 :               nsString tString(*aValue);
    3965               0 :               if (tString.Equals(value, nsCaseInsensitiveStringComparator())) {
    3966               0 :                 found = true;
    3967                 :               }
    3968                 :               else {  // we found the prop with the attribute, but the value doesn't match
    3969                 :                 break;
    3970                 :               }
    3971                 :             }
    3972                 :           }
    3973                 :         }
    3974                 :         else { 
    3975               0 :           found = true;
    3976                 :         }
    3977               0 :         if (found)
    3978                 :         {
    3979               0 :           aIsSet = true;
    3980                 :           break;
    3981                 :         }
    3982                 :       }
    3983                 :     }
    3984               0 :     nsCOMPtr<nsIDOMNode>temp;
    3985               0 :     result = node->GetParentNode(getter_AddRefs(temp));
    3986               0 :     if (NS_SUCCEEDED(result) && temp) {
    3987               0 :       node = temp;
    3988                 :     }
    3989                 :     else {
    3990               0 :       node = nsnull;
    3991                 :     }
    3992                 :   }
    3993               0 : }
    3994                 : 
    3995                 : 
    3996                 : //================================================================
    3997                 : // HTML Editor methods
    3998                 : //
    3999                 : // Note: Table Editing methods are implemented in nsTableEditor.cpp
    4000                 : //
    4001                 : 
    4002                 : 
    4003                 : bool
    4004               0 : nsHTMLEditor::IsNodeInActiveEditor(nsIDOMNode* aNode)
    4005                 : {
    4006               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    4007               0 :   return node && IsNodeInActiveEditor(node);
    4008                 : }
    4009                 : 
    4010                 : bool
    4011               0 : nsHTMLEditor::IsNodeInActiveEditor(nsINode* aNode)
    4012                 : {
    4013               0 :   nsIContent* activeEditingHost = GetActiveEditingHost();
    4014               0 :   if (!activeEditingHost) {
    4015               0 :     return false;
    4016                 :   }
    4017               0 :   return nsContentUtils::ContentIsDescendantOf(aNode, activeEditingHost);
    4018                 : }
    4019                 : 
    4020                 : bool
    4021               0 : nsHTMLEditor::SetCaretInTableCell(nsIDOMElement* aElement)
    4022                 : {
    4023               0 :   nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
    4024               0 :   if (!element || !element->IsHTML() ||
    4025               0 :       !nsHTMLEditUtils::IsTableElement(element) ||
    4026               0 :       !IsNodeInActiveEditor(element)) {
    4027               0 :     return false;
    4028                 :   }
    4029                 : 
    4030               0 :   nsIContent* node = element;
    4031               0 :   while (node->HasChildren()) {
    4032               0 :     node = node->GetFirstChild();
    4033                 :   }
    4034                 : 
    4035                 :   // Set selection at beginning of the found node
    4036               0 :   nsCOMPtr<nsISelection> selection;
    4037               0 :   nsresult rv = GetSelection(getter_AddRefs(selection));
    4038               0 :   NS_ENSURE_SUCCESS(rv, false);
    4039               0 :   NS_ENSURE_TRUE(selection, false);
    4040                 : 
    4041               0 :   return NS_SUCCEEDED(selection->CollapseNative(node, 0));
    4042                 : }            
    4043                 : 
    4044                 : ///////////////////////////////////////////////////////////////////////////
    4045                 : // GetEnclosingTable: find ancestor who is a table, if any
    4046                 : //                  
    4047                 : nsCOMPtr<nsIDOMNode> 
    4048               0 : nsHTMLEditor::GetEnclosingTable(nsIDOMNode *aNode)
    4049                 : {
    4050               0 :   NS_PRECONDITION(aNode, "null node passed to nsHTMLEditor::GetEnclosingTable");
    4051               0 :   nsCOMPtr<nsIDOMNode> tbl, tmp, node = aNode;
    4052                 : 
    4053               0 :   while (!tbl)
    4054                 :   {
    4055               0 :     tmp = GetBlockNodeParent(node);
    4056               0 :     if (!tmp) break;
    4057               0 :     if (nsHTMLEditUtils::IsTable(tmp)) tbl = tmp;
    4058               0 :     node = tmp;
    4059                 :   }
    4060                 :   return tbl;
    4061                 : }
    4062                 : 
    4063                 : 
    4064                 : #ifdef PRE_NODE_IN_BODY
    4065                 : nsCOMPtr<nsIDOMElement> nsHTMLEditor::FindPreElement()
    4066                 : {
    4067                 :   nsCOMPtr<nsIDOMDocument> domdoc;
    4068                 :   nsEditor::GetDocument(getter_AddRefs(domdoc));
    4069                 :   NS_ENSURE_TRUE(domdoc, 0);
    4070                 : 
    4071                 :   nsCOMPtr<nsIDocument> doc (do_QueryInterface(domdoc));
    4072                 :   NS_ENSURE_TRUE(doc, 0);
    4073                 : 
    4074                 :   nsCOMPtr<nsIContent> rootContent = doc->GetRootElement();
    4075                 :   NS_ENSURE_TRUE(rootContent, 0);
    4076                 : 
    4077                 :   nsCOMPtr<nsIDOMNode> rootNode (do_QueryInterface(rootContent));
    4078                 :   NS_ENSURE_TRUE(rootNode, 0);
    4079                 : 
    4080                 :   nsString prestr ("PRE");  // GetFirstNodeOfType requires capitals
    4081                 :   nsCOMPtr<nsIDOMNode> preNode;
    4082                 :   if (NS_FAILED(nsEditor::GetFirstNodeOfType(rootNode, prestr,
    4083                 :                                              getter_AddRefs(preNode))))
    4084                 :     return 0;
    4085                 : 
    4086                 :   return do_QueryInterface(preNode);
    4087                 : }
    4088                 : #endif /* PRE_NODE_IN_BODY */
    4089                 : 
    4090                 : /* this method scans the selection for adjacent text nodes
    4091                 :  * and collapses them into a single text node.
    4092                 :  * "adjacent" means literally adjacent siblings of the same parent.
    4093                 :  * Uses nsEditor::JoinNodes so action is undoable. 
    4094                 :  * Should be called within the context of a batch transaction.
    4095                 :  */
    4096                 : NS_IMETHODIMP
    4097               0 : nsHTMLEditor::CollapseAdjacentTextNodes(nsIDOMRange *aInRange)
    4098                 : {
    4099               0 :   NS_ENSURE_TRUE(aInRange, NS_ERROR_NULL_POINTER);
    4100               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(this);
    4101               0 :   nsTArray<nsIDOMNode*> textNodes;
    4102                 :   // we can't actually do anything during iteration, so store the text nodes in an array
    4103                 :   // don't bother ref counting them because we know we can hold them for the 
    4104                 :   // lifetime of this method
    4105                 : 
    4106                 : 
    4107                 :   // build a list of editable text nodes
    4108                 :   nsresult result;
    4109                 :   nsCOMPtr<nsIContentIterator> iter =
    4110               0 :     do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &result);
    4111               0 :   NS_ENSURE_SUCCESS(result, result);
    4112                 : 
    4113               0 :   iter->Init(aInRange);
    4114                 : 
    4115               0 :   while (!iter->IsDone())
    4116                 :   {
    4117               0 :     nsINode* node = iter->GetCurrentNode();
    4118               0 :     if (node->NodeType() == nsIDOMNode::TEXT_NODE &&
    4119               0 :         IsEditable(static_cast<nsIContent*>(node))) {
    4120               0 :       nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(node);
    4121               0 :       textNodes.AppendElement(domNode);
    4122                 :     }
    4123                 : 
    4124               0 :     iter->Next();
    4125                 :   }
    4126                 : 
    4127                 :   // now that I have a list of text nodes, collapse adjacent text nodes
    4128                 :   // NOTE: assumption that JoinNodes keeps the righthand node
    4129               0 :   while (textNodes.Length() > 1)
    4130                 :   {
    4131                 :     // we assume a textNodes entry can't be nsnull
    4132               0 :     nsIDOMNode *leftTextNode = textNodes[0];
    4133               0 :     nsIDOMNode *rightTextNode = textNodes[1];
    4134               0 :     NS_ASSERTION(leftTextNode && rightTextNode,"left or rightTextNode null in CollapseAdjacentTextNodes");
    4135                 : 
    4136                 :     // get the prev sibling of the right node, and see if its leftTextNode
    4137               0 :     nsCOMPtr<nsIDOMNode> prevSibOfRightNode;
    4138                 :     result =
    4139               0 :       rightTextNode->GetPreviousSibling(getter_AddRefs(prevSibOfRightNode));
    4140               0 :     NS_ENSURE_SUCCESS(result, result);
    4141               0 :     if (prevSibOfRightNode && (prevSibOfRightNode == leftTextNode))
    4142                 :     {
    4143               0 :       nsCOMPtr<nsIDOMNode> parent;
    4144               0 :       result = rightTextNode->GetParentNode(getter_AddRefs(parent));
    4145               0 :       NS_ENSURE_SUCCESS(result, result);
    4146               0 :       NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
    4147               0 :       result = JoinNodes(leftTextNode, rightTextNode, parent);
    4148               0 :       NS_ENSURE_SUCCESS(result, result);
    4149                 :     }
    4150                 : 
    4151               0 :     textNodes.RemoveElementAt(0); // remove the leftmost text node from the list
    4152                 :   }
    4153                 : 
    4154               0 :   return result;
    4155                 : }
    4156                 : 
    4157                 : NS_IMETHODIMP 
    4158               0 : nsHTMLEditor::SetSelectionAtDocumentStart(nsISelection *aSelection)
    4159                 : {
    4160               0 :   dom::Element* rootElement = GetRoot();
    4161               0 :   NS_ENSURE_TRUE(rootElement, NS_ERROR_NULL_POINTER);
    4162                 : 
    4163               0 :   return aSelection->CollapseNative(rootElement, 0);
    4164                 : }
    4165                 : 
    4166                 : 
    4167                 : ///////////////////////////////////////////////////////////////////////////
    4168                 : // RemoveBlockContainer: remove inNode, reparenting its children into their
    4169                 : //                  the parent of inNode.  In addition, INSERT ANY BR's NEEDED
    4170                 : //                  TO PRESERVE IDENTITY OF REMOVED BLOCK.
    4171                 : //
    4172                 : nsresult
    4173               0 : nsHTMLEditor::RemoveBlockContainer(nsIDOMNode *inNode)
    4174                 : {
    4175               0 :   NS_ENSURE_TRUE(inNode, NS_ERROR_NULL_POINTER);
    4176                 :   nsresult res;
    4177               0 :   nsCOMPtr<nsIDOMNode> sibling, child, unused;
    4178                 :   
    4179                 :   // Two possibilities: the container cold be empty of editable content.
    4180                 :   // If that is the case, we need to compare what is before and after inNode
    4181                 :   // to determine if we need a br.
    4182                 :   // Or it could not be empty, in which case we have to compare previous
    4183                 :   // sibling and first child to determine if we need a leading br,
    4184                 :   // and compare following sibling and last child to determine if we need a
    4185                 :   // trailing br.
    4186                 :   
    4187               0 :   res = GetFirstEditableChild(inNode, address_of(child));
    4188               0 :   NS_ENSURE_SUCCESS(res, res);
    4189                 :   
    4190               0 :   if (child)  // the case of inNode not being empty
    4191                 :   {
    4192                 :     // we need a br at start unless:
    4193                 :     // 1) previous sibling of inNode is a block, OR
    4194                 :     // 2) previous sibling of inNode is a br, OR
    4195                 :     // 3) first child of inNode is a block OR
    4196                 :     // 4) either is null
    4197                 :     
    4198               0 :     res = GetPriorHTMLSibling(inNode, address_of(sibling));
    4199               0 :     NS_ENSURE_SUCCESS(res, res);
    4200               0 :     if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
    4201                 :     {
    4202               0 :       res = GetFirstEditableChild(inNode, address_of(child));
    4203               0 :       NS_ENSURE_SUCCESS(res, res);
    4204               0 :       if (child && !IsBlockNode(child))
    4205                 :       {
    4206                 :         // insert br node
    4207               0 :         res = CreateBR(inNode, 0, address_of(unused));
    4208               0 :         NS_ENSURE_SUCCESS(res, res);
    4209                 :       }
    4210                 :     }
    4211                 :     
    4212                 :     // we need a br at end unless:
    4213                 :     // 1) following sibling of inNode is a block, OR
    4214                 :     // 2) last child of inNode is a block, OR
    4215                 :     // 3) last child of inNode is a block OR
    4216                 :     // 4) either is null
    4217                 : 
    4218               0 :     res = GetNextHTMLSibling(inNode, address_of(sibling));
    4219               0 :     NS_ENSURE_SUCCESS(res, res);
    4220               0 :     if (sibling && !IsBlockNode(sibling))
    4221                 :     {
    4222               0 :       res = GetLastEditableChild(inNode, address_of(child));
    4223               0 :       NS_ENSURE_SUCCESS(res, res);
    4224               0 :       if (child && !IsBlockNode(child) && !nsTextEditUtils::IsBreak(child))
    4225                 :       {
    4226                 :         // insert br node
    4227                 :         PRUint32 len;
    4228               0 :         res = GetLengthOfDOMNode(inNode, len);
    4229               0 :         NS_ENSURE_SUCCESS(res, res);
    4230               0 :         res = CreateBR(inNode, (PRInt32)len, address_of(unused));
    4231               0 :         NS_ENSURE_SUCCESS(res, res);
    4232                 :       }
    4233                 :     }
    4234                 :   }
    4235                 :   else  // the case of inNode being empty
    4236                 :   {
    4237                 :     // we need a br at start unless:
    4238                 :     // 1) previous sibling of inNode is a block, OR
    4239                 :     // 2) previous sibling of inNode is a br, OR
    4240                 :     // 3) following sibling of inNode is a block, OR
    4241                 :     // 4) following sibling of inNode is a br OR
    4242                 :     // 5) either is null
    4243               0 :     res = GetPriorHTMLSibling(inNode, address_of(sibling));
    4244               0 :     NS_ENSURE_SUCCESS(res, res);
    4245               0 :     if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
    4246                 :     {
    4247               0 :       res = GetNextHTMLSibling(inNode, address_of(sibling));
    4248               0 :       NS_ENSURE_SUCCESS(res, res);
    4249               0 :       if (sibling && !IsBlockNode(sibling) && !nsTextEditUtils::IsBreak(sibling))
    4250                 :       {
    4251                 :         // insert br node
    4252               0 :         res = CreateBR(inNode, 0, address_of(unused));
    4253               0 :         NS_ENSURE_SUCCESS(res, res);
    4254                 :       }
    4255                 :     }
    4256                 :   }
    4257                 :     
    4258                 :   // now remove container
    4259               0 :   return RemoveContainer(inNode);
    4260                 : }
    4261                 : 
    4262                 : 
    4263                 : ///////////////////////////////////////////////////////////////////////////
    4264                 : // GetPriorHTMLSibling: returns the previous editable sibling, if there is
    4265                 : //                   one within the parent
    4266                 : //                       
    4267                 : nsresult
    4268               0 : nsHTMLEditor::GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
    4269                 : {
    4270               0 :   NS_ENSURE_TRUE(outNode && inNode, NS_ERROR_NULL_POINTER);
    4271               0 :   nsresult res = NS_OK;
    4272               0 :   *outNode = nsnull;
    4273               0 :   nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
    4274                 :   
    4275               0 :   while (1)
    4276                 :   {
    4277               0 :     res = node->GetPreviousSibling(getter_AddRefs(temp));
    4278               0 :     NS_ENSURE_SUCCESS(res, res);
    4279               0 :     if (!temp) {
    4280                 :       // return null sibling
    4281               0 :       return NS_OK;
    4282                 :     }
    4283                 :     // if it's editable, we're done
    4284               0 :     if (IsEditable(temp)) break;
    4285                 :     // otherwise try again
    4286               0 :     node = temp;
    4287                 :   }
    4288               0 :   *outNode = temp;
    4289               0 :   return res;
    4290                 : }
    4291                 : 
    4292                 : 
    4293                 : 
    4294                 : ///////////////////////////////////////////////////////////////////////////
    4295                 : // GetPriorHTMLSibling: returns the previous editable sibling, if there is
    4296                 : //                   one within the parent.  just like above routine but
    4297                 : //                   takes a parent/offset instead of a node.
    4298                 : //                       
    4299                 : nsresult
    4300               0 : nsHTMLEditor::GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
    4301                 : {
    4302               0 :   NS_ENSURE_TRUE(outNode && inParent, NS_ERROR_NULL_POINTER);
    4303               0 :   nsresult res = NS_OK;
    4304               0 :   *outNode = nsnull;
    4305               0 :   if (inOffset <= 0) {
    4306                 :     // return null sibling if at offset zero
    4307               0 :     return NS_OK;
    4308                 :   }
    4309               0 :   nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset-1);
    4310               0 :   if (node && IsEditable(node)) {
    4311               0 :     *outNode = node;
    4312               0 :     return res;
    4313                 :   }
    4314                 :   // else
    4315               0 :   return GetPriorHTMLSibling(node, outNode);
    4316                 : }
    4317                 : 
    4318                 : 
    4319                 : 
    4320                 : ///////////////////////////////////////////////////////////////////////////
    4321                 : // GetNextHTMLSibling: returns the next editable sibling, if there is
    4322                 : //                   one within the parent
    4323                 : //                       
    4324                 : nsresult
    4325               0 : nsHTMLEditor::GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode)
    4326                 : {
    4327               0 :   NS_ENSURE_TRUE(outNode, NS_ERROR_NULL_POINTER);
    4328               0 :   nsresult res = NS_OK;
    4329               0 :   *outNode = nsnull;
    4330               0 :   nsCOMPtr<nsIDOMNode> temp, node = do_QueryInterface(inNode);
    4331                 :   
    4332               0 :   while (1)
    4333                 :   {
    4334               0 :     res = node->GetNextSibling(getter_AddRefs(temp));
    4335               0 :     NS_ENSURE_SUCCESS(res, res);
    4336               0 :     if (!temp) {
    4337                 :       // return null sibling
    4338               0 :       return NS_OK;
    4339                 :     }
    4340                 :     // if it's editable, we're done
    4341               0 :     if (IsEditable(temp)) break;
    4342                 :     // otherwise try again
    4343               0 :     node = temp;
    4344                 :   }
    4345               0 :   *outNode = temp;
    4346               0 :   return res;
    4347                 : }
    4348                 : 
    4349                 : 
    4350                 : 
    4351                 : ///////////////////////////////////////////////////////////////////////////
    4352                 : // GetNextHTMLSibling: returns the next editable sibling, if there is
    4353                 : //                   one within the parent.  just like above routine but
    4354                 : //                   takes a parent/offset instead of a node.
    4355                 : //                       
    4356                 : nsresult
    4357               0 : nsHTMLEditor::GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode)
    4358                 : {
    4359               0 :   NS_ENSURE_TRUE(outNode && inParent, NS_ERROR_NULL_POINTER);
    4360               0 :   nsresult res = NS_OK;
    4361               0 :   *outNode = nsnull;
    4362               0 :   nsCOMPtr<nsIDOMNode> node = nsEditor::GetChildAt(inParent,inOffset);
    4363               0 :   if (!node) {
    4364                 :     // return null sibling if no sibling
    4365               0 :     return NS_OK;
    4366                 :   }
    4367               0 :   if (node && IsEditable(node)) {
    4368               0 :     *outNode = node;
    4369               0 :     return res;
    4370                 :   }
    4371                 :   // else
    4372               0 :   return GetPriorHTMLSibling(node, outNode);
    4373                 : }
    4374                 : 
    4375                 : 
    4376                 : 
    4377                 : ///////////////////////////////////////////////////////////////////////////
    4378                 : // GetPriorHTMLNode: returns the previous editable leaf node, if there is
    4379                 : //                   one within the <body>
    4380                 : //
    4381                 : nsresult
    4382               0 : nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing)
    4383                 : {
    4384               0 :   NS_ENSURE_TRUE(outNode, NS_ERROR_NULL_POINTER);
    4385                 : 
    4386               0 :   nsIContent* activeEditingHost = GetActiveEditingHost();
    4387               0 :   if (!activeEditingHost) {
    4388               0 :     *outNode = nsnull;
    4389               0 :     return NS_OK;
    4390                 :   }
    4391                 : 
    4392               0 :   nsresult res = GetPriorNode(inNode, true, address_of(*outNode), bNoBlockCrossing, activeEditingHost);
    4393               0 :   NS_ENSURE_SUCCESS(res, res);
    4394                 :   
    4395               0 :   NS_ASSERTION(!*outNode || IsNodeInActiveEditor(*outNode),
    4396                 :                "GetPriorNode screwed up");
    4397               0 :   return res;
    4398                 : }
    4399                 : 
    4400                 : 
    4401                 : ///////////////////////////////////////////////////////////////////////////
    4402                 : // GetPriorHTMLNode: same as above but takes {parent,offset} instead of node
    4403                 : //                       
    4404                 : nsresult
    4405               0 : nsHTMLEditor::GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing)
    4406                 : {
    4407               0 :   NS_ENSURE_TRUE(outNode, NS_ERROR_NULL_POINTER);
    4408                 : 
    4409               0 :   nsIContent* activeEditingHost = GetActiveEditingHost();
    4410               0 :   if (!activeEditingHost) {
    4411               0 :     *outNode = nsnull;
    4412               0 :     return NS_OK;
    4413                 :   }
    4414                 : 
    4415               0 :   nsresult res = GetPriorNode(inParent, inOffset, true, address_of(*outNode), bNoBlockCrossing, activeEditingHost);
    4416               0 :   NS_ENSURE_SUCCESS(res, res);
    4417                 :   
    4418               0 :   NS_ASSERTION(!*outNode || IsNodeInActiveEditor(*outNode),
    4419                 :                "GetPriorNode screwed up");
    4420               0 :   return res;
    4421                 : }
    4422                 : 
    4423                 : 
    4424                 : ///////////////////////////////////////////////////////////////////////////
    4425                 : // GetNextHTMLNode: returns the next editable leaf node, if there is
    4426                 : //                   one within the <body>
    4427                 : //                       
    4428                 : nsresult
    4429               0 : nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing)
    4430                 : {
    4431               0 :   NS_ENSURE_TRUE(outNode, NS_ERROR_NULL_POINTER);
    4432               0 :   nsresult res = GetNextNode(inNode, true, address_of(*outNode), bNoBlockCrossing);
    4433               0 :   NS_ENSURE_SUCCESS(res, res);
    4434                 :   
    4435                 :   // if it's not in the body, then zero it out
    4436               0 :   if (*outNode && !IsNodeInActiveEditor(*outNode)) {
    4437               0 :     *outNode = nsnull;
    4438                 :   }
    4439               0 :   return res;
    4440                 : }
    4441                 : 
    4442                 : 
    4443                 : ///////////////////////////////////////////////////////////////////////////
    4444                 : // GetNHTMLextNode: same as above but takes {parent,offset} instead of node
    4445                 : //                       
    4446                 : nsresult
    4447               0 : nsHTMLEditor::GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode, bool bNoBlockCrossing)
    4448                 : {
    4449               0 :   NS_ENSURE_TRUE(outNode, NS_ERROR_NULL_POINTER);
    4450               0 :   nsresult res = GetNextNode(inParent, inOffset, true, address_of(*outNode), bNoBlockCrossing);
    4451               0 :   NS_ENSURE_SUCCESS(res, res);
    4452                 :   
    4453                 :   // if it's not in the body, then zero it out
    4454               0 :   if (*outNode && !IsNodeInActiveEditor(*outNode)) {
    4455               0 :     *outNode = nsnull;
    4456                 :   }
    4457               0 :   return res;
    4458                 : }
    4459                 : 
    4460                 : 
    4461                 : nsresult 
    4462               0 : nsHTMLEditor::IsFirstEditableChild( nsIDOMNode *aNode, bool *aOutIsFirst)
    4463                 : {
    4464                 :   // check parms
    4465               0 :   NS_ENSURE_TRUE(aOutIsFirst && aNode, NS_ERROR_NULL_POINTER);
    4466                 :   
    4467                 :   // init out parms
    4468               0 :   *aOutIsFirst = false;
    4469                 :   
    4470                 :   // find first editable child and compare it to aNode
    4471               0 :   nsCOMPtr<nsIDOMNode> parent, firstChild;
    4472               0 :   nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
    4473               0 :   NS_ENSURE_SUCCESS(res, res);
    4474               0 :   NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
    4475               0 :   res = GetFirstEditableChild(parent, address_of(firstChild));
    4476               0 :   NS_ENSURE_SUCCESS(res, res);
    4477                 :   
    4478               0 :   *aOutIsFirst = (firstChild.get() == aNode);
    4479               0 :   return res;
    4480                 : }
    4481                 : 
    4482                 : 
    4483                 : nsresult 
    4484               0 : nsHTMLEditor::IsLastEditableChild( nsIDOMNode *aNode, bool *aOutIsLast)
    4485                 : {
    4486                 :   // check parms
    4487               0 :   NS_ENSURE_TRUE(aOutIsLast && aNode, NS_ERROR_NULL_POINTER);
    4488                 :   
    4489                 :   // init out parms
    4490               0 :   *aOutIsLast = false;
    4491                 :   
    4492                 :   // find last editable child and compare it to aNode
    4493               0 :   nsCOMPtr<nsIDOMNode> parent, lastChild;
    4494               0 :   nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
    4495               0 :   NS_ENSURE_SUCCESS(res, res);
    4496               0 :   NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
    4497               0 :   res = GetLastEditableChild(parent, address_of(lastChild));
    4498               0 :   NS_ENSURE_SUCCESS(res, res);
    4499                 :   
    4500               0 :   *aOutIsLast = (lastChild.get() == aNode);
    4501               0 :   return res;
    4502                 : }
    4503                 : 
    4504                 : 
    4505                 : nsresult 
    4506               0 : nsHTMLEditor::GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild)
    4507                 : {
    4508                 :   // check parms
    4509               0 :   NS_ENSURE_TRUE(aOutFirstChild && aNode, NS_ERROR_NULL_POINTER);
    4510                 :   
    4511                 :   // init out parms
    4512               0 :   *aOutFirstChild = nsnull;
    4513                 :   
    4514                 :   // find first editable child
    4515               0 :   nsCOMPtr<nsIDOMNode> child;
    4516               0 :   nsresult res = aNode->GetFirstChild(getter_AddRefs(child));
    4517               0 :   NS_ENSURE_SUCCESS(res, res);
    4518                 :   
    4519               0 :   while (child && !IsEditable(child))
    4520                 :   {
    4521               0 :     nsCOMPtr<nsIDOMNode> tmp;
    4522               0 :     res = child->GetNextSibling(getter_AddRefs(tmp));
    4523               0 :     NS_ENSURE_SUCCESS(res, res);
    4524               0 :     NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    4525               0 :     child = tmp;
    4526                 :   }
    4527                 :   
    4528               0 :   *aOutFirstChild = child;
    4529               0 :   return res;
    4530                 : }
    4531                 : 
    4532                 : 
    4533                 : nsresult 
    4534               0 : nsHTMLEditor::GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild)
    4535                 : {
    4536                 :   // check parms
    4537               0 :   NS_ENSURE_TRUE(aOutLastChild && aNode, NS_ERROR_NULL_POINTER);
    4538                 :   
    4539                 :   // init out parms
    4540               0 :   *aOutLastChild = aNode;
    4541                 :   
    4542                 :   // find last editable child
    4543               0 :   nsCOMPtr<nsIDOMNode> child;
    4544               0 :   nsresult res = aNode->GetLastChild(getter_AddRefs(child));
    4545               0 :   NS_ENSURE_SUCCESS(res, res);
    4546                 :   
    4547               0 :   while (child && !IsEditable(child))
    4548                 :   {
    4549               0 :     nsCOMPtr<nsIDOMNode> tmp;
    4550               0 :     res = child->GetPreviousSibling(getter_AddRefs(tmp));
    4551               0 :     NS_ENSURE_SUCCESS(res, res);
    4552               0 :     NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    4553               0 :     child = tmp;
    4554                 :   }
    4555                 :   
    4556               0 :   *aOutLastChild = child;
    4557               0 :   return res;
    4558                 : }
    4559                 : 
    4560                 : nsresult 
    4561               0 : nsHTMLEditor::GetFirstEditableLeaf( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstLeaf)
    4562                 : {
    4563                 :   // check parms
    4564               0 :   NS_ENSURE_TRUE(aOutFirstLeaf && aNode, NS_ERROR_NULL_POINTER);
    4565                 :   
    4566                 :   // init out parms
    4567               0 :   *aOutFirstLeaf = aNode;
    4568                 :   
    4569                 :   // find leftmost leaf
    4570               0 :   nsCOMPtr<nsIDOMNode> child;
    4571               0 :   nsresult res = NS_OK;
    4572               0 :   child = GetLeftmostChild(aNode);  
    4573               0 :   while (child && (!IsEditable(child) || !nsEditorUtils::IsLeafNode(child)))
    4574                 :   {
    4575               0 :     nsCOMPtr<nsIDOMNode> tmp;
    4576               0 :     res = GetNextHTMLNode(child, address_of(tmp));
    4577               0 :     NS_ENSURE_SUCCESS(res, res);
    4578               0 :     NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    4579                 :     
    4580                 :     // only accept nodes that are descendants of aNode
    4581               0 :     if (nsEditorUtils::IsDescendantOf(tmp, aNode))
    4582               0 :       child = tmp;
    4583                 :     else
    4584                 :     {
    4585               0 :       child = nsnull;  // this will abort the loop
    4586                 :     }
    4587                 :   }
    4588                 :   
    4589               0 :   *aOutFirstLeaf = child;
    4590               0 :   return res;
    4591                 : }
    4592                 : 
    4593                 : 
    4594                 : nsresult 
    4595               0 : nsHTMLEditor::GetLastEditableLeaf(nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastLeaf)
    4596                 : {
    4597                 :   // check parms
    4598               0 :   NS_ENSURE_TRUE(aOutLastLeaf && aNode, NS_ERROR_NULL_POINTER);
    4599                 :   
    4600                 :   // init out parms
    4601               0 :   *aOutLastLeaf = nsnull;
    4602                 :   
    4603                 :   // find rightmost leaf
    4604               0 :   nsCOMPtr<nsIDOMNode> child = GetRightmostChild(aNode, false);
    4605               0 :   nsresult res = NS_OK;
    4606               0 :   while (child && (!IsEditable(child) || !nsEditorUtils::IsLeafNode(child)))
    4607                 :   {
    4608               0 :     nsCOMPtr<nsIDOMNode> tmp;
    4609               0 :     res = GetPriorHTMLNode(child, address_of(tmp));
    4610               0 :     NS_ENSURE_SUCCESS(res, res);
    4611               0 :     NS_ENSURE_TRUE(tmp, NS_ERROR_FAILURE);
    4612                 :     
    4613                 :     // only accept nodes that are descendants of aNode
    4614               0 :     if (nsEditorUtils::IsDescendantOf(tmp, aNode))
    4615               0 :       child = tmp;
    4616                 :     else
    4617                 :     {
    4618               0 :       child = nsnull;
    4619                 :     }
    4620                 :   }
    4621                 :   
    4622               0 :   *aOutLastLeaf = child;
    4623               0 :   return res;
    4624                 : }
    4625                 : 
    4626                 : bool
    4627               0 : nsHTMLEditor::IsTextInDirtyFrameVisible(nsIContent *aNode)
    4628                 : {
    4629                 :   bool isEmptyTextNode;
    4630               0 :   nsresult rv = IsVisTextNode(aNode, &isEmptyTextNode, false);
    4631               0 :   if (NS_FAILED(rv)) {
    4632                 :     // We are following the historical decision:
    4633                 :     //   if we don't know, we say it's visible...
    4634               0 :     return true;
    4635                 :   }
    4636                 : 
    4637               0 :   return !isEmptyTextNode;
    4638                 : }
    4639                 : 
    4640                 : 
    4641                 : ///////////////////////////////////////////////////////////////////////////
    4642                 : // IsVisTextNode: figure out if textnode aTextNode has any visible content.
    4643                 : //                  
    4644                 : nsresult
    4645               0 : nsHTMLEditor::IsVisTextNode(nsIContent* aNode,
    4646                 :                             bool* outIsEmptyNode,
    4647                 :                             bool aSafeToAskFrames)
    4648                 : {
    4649               0 :   NS_ENSURE_TRUE(aNode && outIsEmptyNode, NS_ERROR_NULL_POINTER);
    4650               0 :   *outIsEmptyNode = true;
    4651                 : 
    4652                 :   // callers job to only call us with text nodes
    4653               0 :   if (!aNode->IsNodeOfType(nsINode::eTEXT)) {
    4654               0 :     return NS_ERROR_NULL_POINTER;
    4655                 :   }
    4656                 : 
    4657               0 :   PRUint32 length = aNode->TextLength();
    4658               0 :   if (aSafeToAskFrames)
    4659                 :   {
    4660               0 :     nsCOMPtr<nsISelectionController> selCon;
    4661               0 :     nsresult res = GetSelectionController(getter_AddRefs(selCon));
    4662               0 :     NS_ENSURE_SUCCESS(res, res);
    4663               0 :     NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
    4664               0 :     bool isVisible = false;
    4665                 :     // ask the selection controller for information about whether any
    4666                 :     // of the data in the node is really rendered.  This is really
    4667                 :     // something that frames know about, but we aren't supposed to talk to frames.
    4668                 :     // So we put a call in the selection controller interface, since it's already
    4669                 :     // in bed with frames anyway.  (this is a fix for bug 22227, and a
    4670                 :     // partial fix for bug 46209)
    4671               0 :     res = selCon->CheckVisibilityContent(aNode, 0, length, &isVisible);
    4672               0 :     NS_ENSURE_SUCCESS(res, res);
    4673               0 :     if (isVisible) 
    4674                 :     {
    4675               0 :       *outIsEmptyNode = false;
    4676                 :     }
    4677                 :   }
    4678               0 :   else if (length)
    4679                 :   {
    4680               0 :     if (aNode->TextIsOnlyWhitespace())
    4681                 :     {
    4682               0 :       nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
    4683               0 :       nsWSRunObject wsRunObj(this, node, 0);
    4684               0 :       nsCOMPtr<nsIDOMNode> visNode;
    4685               0 :       PRInt32 outVisOffset=0;
    4686               0 :       PRInt16 visType=0;
    4687                 :       nsresult res = wsRunObj.NextVisibleNode(node, 0, address_of(visNode),
    4688               0 :                                               &outVisOffset, &visType);
    4689               0 :       NS_ENSURE_SUCCESS(res, res);
    4690               0 :       if ( (visType == nsWSRunObject::eNormalWS) ||
    4691                 :            (visType == nsWSRunObject::eText) )
    4692                 :       {
    4693               0 :         *outIsEmptyNode = (node != visNode);
    4694                 :       }
    4695                 :     }
    4696                 :     else
    4697                 :     {
    4698               0 :       *outIsEmptyNode = false;
    4699                 :     }
    4700                 :   }
    4701               0 :   return NS_OK;  
    4702                 : }
    4703                 :   
    4704                 : 
    4705                 : ///////////////////////////////////////////////////////////////////////////
    4706                 : // IsEmptyNode: figure out if aNode is an empty node.
    4707                 : //               A block can have children and still be considered empty,
    4708                 : //               if the children are empty or non-editable.
    4709                 : //                  
    4710                 : nsresult
    4711               0 : nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, 
    4712                 :                            bool *outIsEmptyNode, 
    4713                 :                            bool aSingleBRDoesntCount,
    4714                 :                            bool aListOrCellNotEmpty,
    4715                 :                            bool aSafeToAskFrames)
    4716                 : {
    4717               0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    4718                 :   return IsEmptyNode(node, outIsEmptyNode, aSingleBRDoesntCount,
    4719               0 :                      aListOrCellNotEmpty, aSafeToAskFrames);
    4720                 : }
    4721                 : 
    4722                 : nsresult
    4723               0 : nsHTMLEditor::IsEmptyNode(nsINode* aNode,
    4724                 :                           bool* outIsEmptyNode,
    4725                 :                           bool aSingleBRDoesntCount,
    4726                 :                           bool aListOrCellNotEmpty,
    4727                 :                           bool aSafeToAskFrames)
    4728                 : {
    4729               0 :   NS_ENSURE_TRUE(aNode && outIsEmptyNode, NS_ERROR_NULL_POINTER);
    4730               0 :   *outIsEmptyNode = true;
    4731               0 :   bool seenBR = false;
    4732                 :   return IsEmptyNodeImpl(aNode, outIsEmptyNode, aSingleBRDoesntCount,
    4733               0 :                          aListOrCellNotEmpty, aSafeToAskFrames, &seenBR);
    4734                 : }
    4735                 : 
    4736                 : ///////////////////////////////////////////////////////////////////////////
    4737                 : // IsEmptyNodeImpl: workhorse for IsEmptyNode.
    4738                 : //                  
    4739                 : nsresult
    4740               0 : nsHTMLEditor::IsEmptyNodeImpl(nsINode* aNode,
    4741                 :                               bool *outIsEmptyNode,
    4742                 :                               bool aSingleBRDoesntCount,
    4743                 :                               bool aListOrCellNotEmpty,
    4744                 :                               bool aSafeToAskFrames,
    4745                 :                               bool *aSeenBR)
    4746                 : {
    4747               0 :   NS_ENSURE_TRUE(aNode && outIsEmptyNode && aSeenBR, NS_ERROR_NULL_POINTER);
    4748                 : 
    4749               0 :   if (aNode->NodeType() == nsIDOMNode::TEXT_NODE) {
    4750               0 :     return IsVisTextNode(static_cast<nsIContent*>(aNode), outIsEmptyNode, aSafeToAskFrames);
    4751                 :   }
    4752                 : 
    4753                 :   // if it's not a text node (handled above) and it's not a container,
    4754                 :   // then we don't call it empty (it's an <hr>, or <br>, etc).
    4755                 :   // Also, if it's an anchor then don't treat it as empty - even though
    4756                 :   // anchors are containers, named anchors are "empty" but we don't
    4757                 :   // want to treat them as such.  Also, don't call ListItems or table
    4758                 :   // cells empty if caller desires.  Form Widgets not empty.
    4759               0 :   if (!IsContainer(aNode)                                   ||
    4760               0 :       (aNode->IsElement() &&
    4761               0 :        (nsHTMLEditUtils::IsNamedAnchor(aNode->AsElement())  ||
    4762               0 :         nsHTMLEditUtils::IsFormWidget(aNode->AsElement())   ||
    4763                 :         (aListOrCellNotEmpty &&
    4764               0 :          (nsHTMLEditUtils::IsListItem(aNode->AsElement())   ||
    4765               0 :           nsHTMLEditUtils::IsTableCell(aNode->AsElement()))))))  {
    4766               0 :     *outIsEmptyNode = false;
    4767               0 :     return NS_OK;
    4768                 :   }
    4769                 :     
    4770                 :   // need this for later
    4771               0 :   bool isListItemOrCell = aNode->IsElement() &&
    4772               0 :        (nsHTMLEditUtils::IsListItem(aNode->AsElement()) ||
    4773               0 :         nsHTMLEditUtils::IsTableCell(aNode->AsElement()));
    4774                 :        
    4775                 :   // loop over children of node. if no children, or all children are either 
    4776                 :   // empty text nodes or non-editable, then node qualifies as empty
    4777               0 :   for (nsCOMPtr<nsIContent> child = aNode->GetFirstChild();
    4778               0 :        child;
    4779               0 :        child = child->GetNextSibling()) {
    4780                 :     // Is the child editable and non-empty?  if so, return false
    4781               0 :     if (nsEditor::IsEditable(child)) {
    4782               0 :       if (child->NodeType() == nsIDOMNode::TEXT_NODE) {
    4783               0 :         nsresult rv = IsVisTextNode(child, outIsEmptyNode, aSafeToAskFrames);
    4784               0 :         NS_ENSURE_SUCCESS(rv, rv);
    4785                 :         // break out if we find we aren't emtpy
    4786               0 :         if (!*outIsEmptyNode) {
    4787               0 :           return NS_OK;
    4788                 :         }
    4789                 :       } else {
    4790                 :         // An editable, non-text node. We need to check its content.
    4791                 :         // Is it the node we are iterating over?
    4792               0 :         if (child == aNode) {
    4793               0 :           break;
    4794                 :         }
    4795                 : 
    4796               0 :         if (aSingleBRDoesntCount && !*aSeenBR && child->IsHTML(nsGkAtoms::br)) {
    4797                 :           // the first br in a block doesn't count if the caller so indicated
    4798               0 :           *aSeenBR = true;
    4799                 :         } else {
    4800                 :           // is it an empty node of some sort?
    4801                 :           // note: list items or table cells are not considered empty
    4802                 :           // if they contain other lists or tables
    4803               0 :           if (child->IsElement()) {
    4804               0 :             if (isListItemOrCell) {
    4805               0 :               if (nsHTMLEditUtils::IsList(child->AsElement()) || child->IsHTML(nsGkAtoms::table)) {
    4806                 :                 // break out if we find we aren't empty
    4807               0 :                 *outIsEmptyNode = false;
    4808               0 :                 return NS_OK;
    4809                 :               }
    4810               0 :             } else if (nsHTMLEditUtils::IsFormWidget(child->AsElement())) {
    4811                 :               // is it a form widget?
    4812                 :               // break out if we find we aren't empty
    4813               0 :               *outIsEmptyNode = false;
    4814               0 :               return NS_OK;
    4815                 :             }
    4816                 :           }
    4817                 : 
    4818               0 :           bool isEmptyNode = true;
    4819                 :           nsresult rv = IsEmptyNodeImpl(child, &isEmptyNode,
    4820                 :                                         aSingleBRDoesntCount,
    4821                 :                                         aListOrCellNotEmpty, aSafeToAskFrames,
    4822               0 :                                         aSeenBR);
    4823               0 :           NS_ENSURE_SUCCESS(rv, rv);
    4824               0 :           if (!isEmptyNode) {
    4825                 :             // otherwise it ain't empty
    4826               0 :             *outIsEmptyNode = false;
    4827               0 :             return NS_OK;
    4828                 :           }
    4829                 :         }
    4830                 :       }
    4831                 :     }
    4832                 :   }
    4833                 :   
    4834               0 :   return NS_OK;
    4835                 : }
    4836                 : 
    4837                 : // add to aElement the CSS inline styles corresponding to the HTML attribute
    4838                 : // aAttribute with its value aValue
    4839                 : nsresult
    4840               0 : nsHTMLEditor::SetAttributeOrEquivalent(nsIDOMElement * aElement,
    4841                 :                                        const nsAString & aAttribute,
    4842                 :                                        const nsAString & aValue,
    4843                 :                                        bool aSuppressTransaction)
    4844                 : {
    4845               0 :   nsresult res = NS_OK;
    4846               0 :   if (IsCSSEnabled() && mHTMLCSSUtils) {
    4847                 :     PRInt32 count;
    4848                 :     res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(aElement, nsnull, &aAttribute, &aValue, &count,
    4849               0 :                                                      aSuppressTransaction);
    4850               0 :     NS_ENSURE_SUCCESS(res, res);
    4851               0 :     if (count) {
    4852                 :       // we found an equivalence ; let's remove the HTML attribute itself if it is set
    4853               0 :       nsAutoString existingValue;
    4854               0 :       bool wasSet = false;
    4855               0 :       res = GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
    4856               0 :       NS_ENSURE_SUCCESS(res, res);
    4857               0 :       if (wasSet) {
    4858               0 :         if (aSuppressTransaction)
    4859               0 :           res = aElement->RemoveAttribute(aAttribute);
    4860                 :         else
    4861               0 :           res = RemoveAttribute(aElement, aAttribute);
    4862                 :       }
    4863                 :     }
    4864                 :     else {
    4865                 :       // count is an integer that represents the number of CSS declarations applied to the
    4866                 :       // element. If it is zero, we found no equivalence in this implementation for the
    4867                 :       // attribute
    4868               0 :       if (aAttribute.EqualsLiteral("style")) {
    4869                 :         // if it is the style attribute, just add the new value to the existing style
    4870                 :         // attribute's value
    4871               0 :         nsAutoString existingValue;
    4872               0 :         bool wasSet = false;
    4873               0 :         res = GetAttributeValue(aElement, NS_LITERAL_STRING("style"), existingValue, &wasSet);
    4874               0 :         NS_ENSURE_SUCCESS(res, res);
    4875               0 :         existingValue.AppendLiteral(" ");
    4876               0 :         existingValue.Append(aValue);
    4877               0 :         if (aSuppressTransaction)
    4878               0 :           res = aElement->SetAttribute(aAttribute, existingValue);
    4879                 :         else
    4880               0 :           res = SetAttribute(aElement, aAttribute, existingValue);
    4881                 :       }
    4882                 :       else {
    4883                 :         // we have no CSS equivalence for this attribute and it is not the style
    4884                 :         // attribute; let's set it the good'n'old HTML way
    4885               0 :         if (aSuppressTransaction)
    4886               0 :           res = aElement->SetAttribute(aAttribute, aValue);
    4887                 :         else
    4888               0 :           res = SetAttribute(aElement, aAttribute, aValue);
    4889                 :       }
    4890                 :     }
    4891                 :   }
    4892                 :   else {
    4893                 :     // we are not in an HTML+CSS editor; let's set the attribute the HTML way
    4894               0 :     if (aSuppressTransaction)
    4895               0 :       res = aElement->SetAttribute(aAttribute, aValue);
    4896                 :     else
    4897               0 :       res = SetAttribute(aElement, aAttribute, aValue);
    4898                 :   }  
    4899               0 :   return res;
    4900                 : }
    4901                 : 
    4902                 : nsresult
    4903               0 : nsHTMLEditor::RemoveAttributeOrEquivalent(nsIDOMElement * aElement,
    4904                 :                                           const nsAString & aAttribute,
    4905                 :                                           bool aSuppressTransaction)
    4906                 : {
    4907               0 :   nsresult res = NS_OK;
    4908               0 :   if (IsCSSEnabled() && mHTMLCSSUtils) {
    4909                 :     res = mHTMLCSSUtils->RemoveCSSEquivalentToHTMLStyle(aElement, nsnull, &aAttribute, nsnull,
    4910               0 :                                                         aSuppressTransaction);
    4911               0 :     NS_ENSURE_SUCCESS(res, res);
    4912                 :   }
    4913                 : 
    4914               0 :   nsAutoString existingValue;
    4915               0 :   bool wasSet = false;
    4916               0 :   res = GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
    4917               0 :   NS_ENSURE_SUCCESS(res, res);
    4918               0 :   if (wasSet) {
    4919               0 :     if (aSuppressTransaction)
    4920               0 :       res = aElement->RemoveAttribute(aAttribute);
    4921                 :     else
    4922               0 :       res = RemoveAttribute(aElement, aAttribute);
    4923                 :   }
    4924               0 :   return res;
    4925                 : }
    4926                 : 
    4927                 : nsresult
    4928               0 : nsHTMLEditor::SetIsCSSEnabled(bool aIsCSSPrefChecked)
    4929                 : {
    4930               0 :   if (!mHTMLCSSUtils) {
    4931               0 :     return NS_ERROR_NOT_INITIALIZED;
    4932                 :   }
    4933                 : 
    4934               0 :   nsresult rv = mHTMLCSSUtils->SetCSSEnabled(aIsCSSPrefChecked);
    4935               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4936                 : 
    4937                 :   // Disable the eEditorNoCSSMask flag if we're enabling StyleWithCSS.
    4938               0 :   PRUint32 flags = mFlags;
    4939               0 :   if (aIsCSSPrefChecked) {
    4940                 :     // Turn off NoCSS as we're enabling CSS
    4941               0 :     flags &= ~eEditorNoCSSMask;
    4942                 :   } else {
    4943                 :     // Turn on NoCSS, as we're disabling CSS.
    4944               0 :     flags |= eEditorNoCSSMask;
    4945                 :   }
    4946                 : 
    4947               0 :   return SetFlags(flags);
    4948                 : }
    4949                 : 
    4950                 : // Set the block background color
    4951                 : NS_IMETHODIMP
    4952               0 : nsHTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
    4953                 : {
    4954               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
    4955               0 :   ForceCompositionEnd();
    4956                 : 
    4957                 :   // Protect the edit rules object from dying
    4958               0 :   nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
    4959                 : 
    4960                 :   nsresult res;
    4961               0 :   nsCOMPtr<nsISelection>selection;
    4962               0 :   res = GetSelection(getter_AddRefs(selection));
    4963               0 :   NS_ENSURE_SUCCESS(res, res);
    4964               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    4965               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    4966                 : 
    4967                 :   bool isCollapsed;
    4968               0 :   selection->GetIsCollapsed(&isCollapsed);
    4969                 : 
    4970               0 :   nsAutoEditBatch batchIt(this);
    4971               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
    4972               0 :   nsAutoSelectionReset selectionResetter(selection, this);
    4973               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(this);
    4974                 :   
    4975                 :   bool cancel, handled;
    4976               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kSetTextProperty);
    4977               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    4978               0 :   NS_ENSURE_SUCCESS(res, res);
    4979               0 :   if (!cancel && !handled)
    4980                 :   {
    4981                 :     // get selection range enumerator
    4982               0 :     nsCOMPtr<nsIEnumerator> enumerator;
    4983               0 :     res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    4984               0 :     NS_ENSURE_SUCCESS(res, res);
    4985               0 :     NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
    4986                 : 
    4987                 :     // loop thru the ranges in the selection
    4988               0 :     enumerator->First(); 
    4989               0 :     nsCOMPtr<nsISupports> currentItem;
    4990               0 :     nsAutoString bgcolor; bgcolor.AssignLiteral("bgcolor");
    4991               0 :     nsCOMPtr<nsIDOMNode> cachedBlockParent = nsnull;
    4992               0 :     while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
    4993                 :     {
    4994               0 :       res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    4995               0 :       NS_ENSURE_SUCCESS(res, res);
    4996               0 :       NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
    4997                 :       
    4998               0 :       nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    4999                 :       
    5000                 :       // check for easy case: both range endpoints in same text node
    5001               0 :       nsCOMPtr<nsIDOMNode> startNode, endNode;
    5002                 :       PRInt32 startOffset, endOffset;
    5003               0 :       res = range->GetStartContainer(getter_AddRefs(startNode));
    5004               0 :       NS_ENSURE_SUCCESS(res, res);
    5005               0 :       res = range->GetEndContainer(getter_AddRefs(endNode));
    5006               0 :       NS_ENSURE_SUCCESS(res, res);
    5007               0 :       res = range->GetStartOffset(&startOffset);
    5008               0 :       NS_ENSURE_SUCCESS(res, res);
    5009               0 :       res = range->GetEndOffset(&endOffset);
    5010               0 :       NS_ENSURE_SUCCESS(res, res);
    5011               0 :       if ((startNode == endNode) && IsTextNode(startNode))
    5012                 :       {
    5013                 :         // let's find the block container of the text node
    5014               0 :         nsCOMPtr<nsIDOMNode> blockParent;
    5015               0 :         blockParent = GetBlockNodeParent(startNode);
    5016                 :         // and apply the background color to that block container
    5017               0 :         if (cachedBlockParent != blockParent)
    5018                 :         {
    5019               0 :           cachedBlockParent = blockParent;
    5020               0 :           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
    5021                 :           PRInt32 count;
    5022               0 :           res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count, false);
    5023               0 :           NS_ENSURE_SUCCESS(res, res);
    5024                 :         }
    5025                 :       }
    5026               0 :       else if ((startNode == endNode) && nsTextEditUtils::IsBody(startNode) && isCollapsed)
    5027                 :       {
    5028                 :         // we have no block in the document, let's apply the background to the body 
    5029               0 :         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(startNode);
    5030                 :         PRInt32 count;
    5031               0 :         res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count, false);
    5032               0 :         NS_ENSURE_SUCCESS(res, res);
    5033                 :       }
    5034               0 :       else if ((startNode == endNode) && (((endOffset-startOffset) == 1) || (!startOffset && !endOffset)))
    5035                 :       {
    5036                 :         // a unique node is selected, let's also apply the background color
    5037                 :         // to the containing block, possibly the node itself
    5038               0 :         nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startNode, startOffset);
    5039               0 :         bool isBlock =false;
    5040               0 :         res = NodeIsBlockStatic(selectedNode, &isBlock);
    5041               0 :         NS_ENSURE_SUCCESS(res, res);
    5042               0 :         nsCOMPtr<nsIDOMNode> blockParent = selectedNode;
    5043               0 :         if (!isBlock) {
    5044               0 :           blockParent = GetBlockNodeParent(selectedNode);
    5045                 :         }
    5046               0 :         if (cachedBlockParent != blockParent)
    5047                 :         {
    5048               0 :           cachedBlockParent = blockParent;
    5049               0 :           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
    5050                 :           PRInt32 count;
    5051               0 :           res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count, false);
    5052               0 :           NS_ENSURE_SUCCESS(res, res);
    5053                 :         }
    5054                 :       }
    5055                 :       else
    5056                 :       {
    5057                 :         // not the easy case.  range not contained in single text node. 
    5058                 :         // there are up to three phases here.  There are all the nodes
    5059                 :         // reported by the subtree iterator to be processed.  And there
    5060                 :         // are potentially a starting textnode and an ending textnode
    5061                 :         // which are only partially contained by the range.
    5062                 :         
    5063                 :         // lets handle the nodes reported by the iterator.  These nodes
    5064                 :         // are entirely contained in the selection range.  We build up
    5065                 :         // a list of them (since doing operations on the document during
    5066                 :         // iteration would perturb the iterator).
    5067                 : 
    5068                 :         nsCOMPtr<nsIContentIterator> iter =
    5069               0 :           do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
    5070               0 :         NS_ENSURE_SUCCESS(res, res);
    5071               0 :         NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
    5072                 : 
    5073               0 :         nsCOMArray<nsIDOMNode> arrayOfNodes;
    5074               0 :         nsCOMPtr<nsIDOMNode> node;
    5075                 :                 
    5076                 :         // iterate range and build up array
    5077               0 :         res = iter->Init(range);
    5078                 :         // init returns an error if no nodes in range.
    5079                 :         // this can easily happen with the subtree 
    5080                 :         // iterator if the selection doesn't contain
    5081                 :         // any *whole* nodes.
    5082               0 :         if (NS_SUCCEEDED(res))
    5083                 :         {
    5084               0 :           while (!iter->IsDone())
    5085                 :           {
    5086               0 :             node = do_QueryInterface(iter->GetCurrentNode());
    5087               0 :             NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    5088                 : 
    5089               0 :             if (IsEditable(node))
    5090                 :             {
    5091               0 :               arrayOfNodes.AppendObject(node);
    5092                 :             }
    5093                 : 
    5094               0 :             iter->Next();
    5095                 :           }
    5096                 :         }
    5097                 :         // first check the start parent of the range to see if it needs to 
    5098                 :         // be separately handled (it does if it's a text node, due to how the
    5099                 :         // subtree iterator works - it will not have reported it).
    5100               0 :         if (IsTextNode(startNode) && IsEditable(startNode))
    5101                 :         {
    5102               0 :           nsCOMPtr<nsIDOMNode> blockParent;
    5103               0 :           blockParent = GetBlockNodeParent(startNode);
    5104               0 :           if (cachedBlockParent != blockParent)
    5105                 :           {
    5106               0 :             cachedBlockParent = blockParent;
    5107               0 :             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
    5108                 :             PRInt32 count;
    5109               0 :             res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count, false);
    5110               0 :             NS_ENSURE_SUCCESS(res, res);
    5111                 :           }
    5112                 :         }
    5113                 :         
    5114                 :         // then loop through the list, set the property on each node
    5115               0 :         PRInt32 listCount = arrayOfNodes.Count();
    5116                 :         PRInt32 j;
    5117               0 :         for (j = 0; j < listCount; j++)
    5118                 :         {
    5119               0 :           node = arrayOfNodes[j];
    5120                 :           // do we have a block here ?
    5121               0 :           bool isBlock =false;
    5122               0 :           res = NodeIsBlockStatic(node, &isBlock);
    5123               0 :           NS_ENSURE_SUCCESS(res, res);
    5124               0 :           nsCOMPtr<nsIDOMNode> blockParent = node;
    5125               0 :           if (!isBlock) {
    5126                 :             // no we don't, let's find the block ancestor
    5127               0 :             blockParent = GetBlockNodeParent(node);
    5128                 :           }
    5129               0 :           if (cachedBlockParent != blockParent)
    5130                 :           {
    5131               0 :             cachedBlockParent = blockParent;
    5132               0 :             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
    5133                 :             PRInt32 count;
    5134                 :             // and set the property on it
    5135               0 :             res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count, false);
    5136               0 :             NS_ENSURE_SUCCESS(res, res);
    5137                 :           }
    5138                 :         }
    5139               0 :         arrayOfNodes.Clear();
    5140                 :         
    5141                 :         // last check the end parent of the range to see if it needs to 
    5142                 :         // be separately handled (it does if it's a text node, due to how the
    5143                 :         // subtree iterator works - it will not have reported it).
    5144               0 :         if (IsTextNode(endNode) && IsEditable(endNode))
    5145                 :         {
    5146               0 :           nsCOMPtr<nsIDOMNode> blockParent;
    5147               0 :           blockParent = GetBlockNodeParent(endNode);
    5148               0 :           if (cachedBlockParent != blockParent)
    5149                 :           {
    5150               0 :             cachedBlockParent = blockParent;
    5151               0 :             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
    5152                 :             PRInt32 count;
    5153               0 :             res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count, false);
    5154               0 :             NS_ENSURE_SUCCESS(res, res);
    5155                 :           }
    5156                 :         }
    5157                 :       }
    5158               0 :       enumerator->Next();
    5159                 :     }
    5160                 :   }
    5161               0 :   if (!cancel)
    5162                 :   {
    5163                 :     // post-process
    5164               0 :     res = mRules->DidDoAction(selection, &ruleInfo, res);
    5165                 :   }
    5166               0 :   return res;
    5167                 : }
    5168                 : 
    5169                 : NS_IMETHODIMP
    5170               0 : nsHTMLEditor::SetBackgroundColor(const nsAString& aColor)
    5171                 : {
    5172                 :   nsresult res;
    5173               0 :   if (IsCSSEnabled()) {
    5174                 :     // if we are in CSS mode, we have to apply the background color to the
    5175                 :     // containing block (or the body if we have no block-level element in
    5176                 :     // the document)
    5177               0 :     res = SetCSSBackgroundColor(aColor);
    5178                 :   }
    5179                 :   else {
    5180                 :     // but in HTML mode, we can only set the document's background color
    5181               0 :     res = SetHTMLBackgroundColor(aColor);
    5182                 :   }
    5183               0 :   return res;
    5184                 : }
    5185                 : 
    5186                 : ///////////////////////////////////////////////////////////////////////////
    5187                 : // NodesSameType: do these nodes have the same tag?
    5188                 : //                    
    5189                 : bool 
    5190               0 : nsHTMLEditor::NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
    5191                 : {
    5192               0 :   if (!aNode1 || !aNode2) 
    5193                 :   {
    5194               0 :     NS_NOTREACHED("null node passed to nsEditor::NodesSameType()");
    5195               0 :     return false;
    5196                 :   }
    5197                 : 
    5198               0 :   nsIAtom *tag1 = GetTag(aNode1);
    5199                 : 
    5200               0 :   if (tag1 == GetTag(aNode2)) {
    5201               0 :     if (IsCSSEnabled() && tag1 == nsEditProperty::span) {
    5202               0 :       if (mHTMLCSSUtils->ElementsSameStyle(aNode1, aNode2)) {
    5203               0 :         return true;
    5204                 :       }
    5205                 :     }
    5206                 :     else {
    5207               0 :       return true;
    5208                 :     }
    5209                 :   }
    5210               0 :   return false;
    5211                 : }
    5212                 : 
    5213                 : NS_IMETHODIMP
    5214               0 : nsHTMLEditor::CopyLastEditableChildStyles(nsIDOMNode * aPreviousBlock, nsIDOMNode * aNewBlock,
    5215                 :                                           nsIDOMNode **aOutBrNode)
    5216                 : {
    5217               0 :   *aOutBrNode = nsnull;
    5218               0 :   nsCOMPtr<nsIDOMNode> child, tmp;
    5219                 :   nsresult res;
    5220                 :   // first, clear out aNewBlock.  Contract is that we want only the styles from previousBlock.
    5221               0 :   res = aNewBlock->GetFirstChild(getter_AddRefs(child));
    5222               0 :   while (NS_SUCCEEDED(res) && child)
    5223                 :   {
    5224               0 :     res = DeleteNode(child);
    5225               0 :     NS_ENSURE_SUCCESS(res, res);
    5226               0 :     res = aNewBlock->GetFirstChild(getter_AddRefs(child));
    5227                 :   }
    5228                 :   // now find and clone the styles
    5229               0 :   child = aPreviousBlock;
    5230               0 :   tmp = aPreviousBlock;
    5231               0 :   while (tmp) {
    5232               0 :     child = tmp;
    5233               0 :     res = GetLastEditableChild(child, address_of(tmp));
    5234               0 :     NS_ENSURE_SUCCESS(res, res);
    5235                 :   }
    5236               0 :   while (child && nsTextEditUtils::IsBreak(child)) {
    5237               0 :     nsCOMPtr<nsIDOMNode> priorNode;
    5238               0 :     res = GetPriorHTMLNode(child, address_of(priorNode));
    5239               0 :     NS_ENSURE_SUCCESS(res, res);
    5240               0 :     child = priorNode;
    5241                 :   }
    5242               0 :   nsCOMPtr<nsIDOMNode> newStyles = nsnull, deepestStyle = nsnull;
    5243               0 :   while (child && (child != aPreviousBlock)) {
    5244               0 :     if (nsHTMLEditUtils::IsInlineStyle(child) ||
    5245               0 :         nsEditor::NodeIsType(child, nsEditProperty::span)) {
    5246               0 :       nsAutoString domTagName;
    5247               0 :       child->GetNodeName(domTagName);
    5248               0 :       ToLowerCase(domTagName);
    5249               0 :       if (newStyles) {
    5250               0 :         nsCOMPtr<nsIDOMNode> newContainer;
    5251               0 :         res = InsertContainerAbove(newStyles, address_of(newContainer), domTagName);
    5252               0 :         NS_ENSURE_SUCCESS(res, res);
    5253               0 :         newStyles = newContainer;
    5254                 :       }
    5255                 :       else {
    5256               0 :         res = CreateNode(domTagName, aNewBlock, 0, getter_AddRefs(newStyles));
    5257               0 :         NS_ENSURE_SUCCESS(res, res);
    5258               0 :         deepestStyle = newStyles;
    5259                 :       }
    5260               0 :       res = CloneAttributes(newStyles, child);
    5261               0 :       NS_ENSURE_SUCCESS(res, res);
    5262                 :     }
    5263               0 :     nsCOMPtr<nsIDOMNode> tmp;
    5264               0 :     res = child->GetParentNode(getter_AddRefs(tmp));
    5265               0 :     NS_ENSURE_SUCCESS(res, res);
    5266               0 :     child = tmp;
    5267                 :   }
    5268               0 :   if (deepestStyle) {
    5269               0 :     nsCOMPtr<nsIDOMNode> outBRNode;
    5270               0 :     res = CreateBR(deepestStyle, 0, address_of(outBRNode));
    5271               0 :     NS_ENSURE_SUCCESS(res, res);
    5272                 :     // Getters must addref
    5273               0 :     outBRNode.forget(aOutBrNode);
    5274                 :   }
    5275               0 :   return NS_OK;
    5276                 : }
    5277                 : 
    5278                 : nsresult
    5279               0 : nsHTMLEditor::GetElementOrigin(nsIDOMElement * aElement, PRInt32 & aX, PRInt32 & aY)
    5280                 : {
    5281               0 :   aX = 0;
    5282               0 :   aY = 0;
    5283                 : 
    5284               0 :   NS_ENSURE_TRUE(mDocWeak, NS_ERROR_NOT_INITIALIZED);
    5285               0 :   nsCOMPtr<nsIPresShell> ps = GetPresShell();
    5286               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
    5287                 : 
    5288               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
    5289               0 :   nsIFrame *frame = content->GetPrimaryFrame();
    5290               0 :   NS_ENSURE_TRUE(frame, NS_OK);
    5291                 : 
    5292               0 :   nsIFrame *container = ps->GetAbsoluteContainingBlock(frame);
    5293               0 :   NS_ENSURE_TRUE(container, NS_OK);
    5294               0 :   nsPoint off = frame->GetOffsetTo(container);
    5295               0 :   aX = nsPresContext::AppUnitsToIntCSSPixels(off.x);
    5296               0 :   aY = nsPresContext::AppUnitsToIntCSSPixels(off.y);
    5297                 : 
    5298               0 :   return NS_OK;
    5299                 : }
    5300                 : 
    5301                 : nsresult
    5302               0 : nsHTMLEditor::EndUpdateViewBatch()
    5303                 : {
    5304               0 :   nsresult res = nsEditor::EndUpdateViewBatch();
    5305               0 :   NS_ENSURE_SUCCESS(res, res);
    5306                 : 
    5307                 :   // We may need to show resizing handles or update existing ones after
    5308                 :   // all transactions are done. This way of doing is preferred to DOM
    5309                 :   // mutation events listeners because all the changes the user can apply
    5310                 :   // to a document may result in multiple events, some of them quite hard
    5311                 :   // to listen too (in particular when an ancestor of the selection is
    5312                 :   // changed but the selection itself is not changed).
    5313               0 :   if (mUpdateCount == 0) {
    5314               0 :     nsCOMPtr<nsISelection> selection;
    5315               0 :     res = GetSelection(getter_AddRefs(selection));
    5316               0 :     NS_ENSURE_SUCCESS(res, res);
    5317               0 :     NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
    5318               0 :     res = CheckSelectionStateForAnonymousButtons(selection);
    5319                 :   }
    5320               0 :   return res;
    5321                 : }
    5322                 : 
    5323                 : NS_IMETHODIMP
    5324               0 : nsHTMLEditor::GetSelectionContainer(nsIDOMElement ** aReturn)
    5325                 : {
    5326               0 :   nsCOMPtr<nsISelection>selection;
    5327               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    5328                 :   // if we don't get the selection, just skip this
    5329               0 :   if (NS_FAILED(res) || !selection) return res;
    5330                 : 
    5331                 :   bool bCollapsed;
    5332               0 :   res = selection->GetIsCollapsed(&bCollapsed);
    5333               0 :   NS_ENSURE_SUCCESS(res, res);
    5334                 : 
    5335               0 :   nsCOMPtr<nsIDOMNode> focusNode;
    5336                 : 
    5337               0 :   if (bCollapsed) {
    5338               0 :     res = selection->GetFocusNode(getter_AddRefs(focusNode));
    5339               0 :     NS_ENSURE_SUCCESS(res, res);
    5340                 :   }
    5341                 :   else {
    5342                 : 
    5343                 :     PRInt32 rangeCount;
    5344               0 :     res = selection->GetRangeCount(&rangeCount);
    5345               0 :     NS_ENSURE_SUCCESS(res, res);
    5346                 : 
    5347               0 :     if (rangeCount == 1) {
    5348                 : 
    5349               0 :       nsCOMPtr<nsIDOMRange> range;
    5350               0 :       res = selection->GetRangeAt(0, getter_AddRefs(range));
    5351               0 :       NS_ENSURE_SUCCESS(res, res);
    5352               0 :       NS_ENSURE_TRUE(range, NS_ERROR_NULL_POINTER);
    5353                 : 
    5354               0 :       nsCOMPtr<nsIDOMNode> startContainer, endContainer;
    5355               0 :       res = range->GetStartContainer(getter_AddRefs(startContainer));
    5356               0 :       NS_ENSURE_SUCCESS(res, res);
    5357               0 :       res = range->GetEndContainer(getter_AddRefs(endContainer));
    5358               0 :       NS_ENSURE_SUCCESS(res, res);
    5359                 :       PRInt32 startOffset, endOffset;
    5360               0 :       res = range->GetStartOffset(&startOffset);
    5361               0 :       NS_ENSURE_SUCCESS(res, res);
    5362               0 :       res = range->GetEndOffset(&endOffset);
    5363               0 :       NS_ENSURE_SUCCESS(res, res);
    5364                 : 
    5365               0 :       nsCOMPtr<nsIDOMElement> focusElement;
    5366               0 :       if (startContainer == endContainer && startOffset + 1 == endOffset) {
    5367               0 :         res = GetSelectedElement(EmptyString(), getter_AddRefs(focusElement));
    5368               0 :         NS_ENSURE_SUCCESS(res, res);
    5369               0 :         if (focusElement)
    5370               0 :           focusNode = do_QueryInterface(focusElement);
    5371                 :       }
    5372               0 :       if (!focusNode) {
    5373               0 :         res = range->GetCommonAncestorContainer(getter_AddRefs(focusNode));
    5374               0 :         NS_ENSURE_SUCCESS(res, res);
    5375                 :       }
    5376                 :     }
    5377                 :     else {
    5378                 :       PRInt32 i;
    5379               0 :       nsCOMPtr<nsIDOMRange> range;
    5380               0 :       for (i = 0; i < rangeCount; i++)
    5381                 :       {
    5382               0 :         res = selection->GetRangeAt(i, getter_AddRefs(range));
    5383               0 :         NS_ENSURE_SUCCESS(res, res);
    5384               0 :         nsCOMPtr<nsIDOMNode> startContainer;
    5385               0 :         res = range->GetStartContainer(getter_AddRefs(startContainer));
    5386               0 :         if (NS_FAILED(res)) continue;
    5387               0 :         if (!focusNode)
    5388               0 :           focusNode = startContainer;
    5389               0 :         else if (focusNode != startContainer) {
    5390               0 :           res = startContainer->GetParentNode(getter_AddRefs(focusNode));
    5391               0 :           NS_ENSURE_SUCCESS(res, res);
    5392                 :           break;
    5393                 :         }
    5394                 :       }
    5395                 :     }
    5396                 :   }
    5397                 : 
    5398               0 :   if (focusNode) {
    5399                 :     PRUint16 nodeType;
    5400               0 :     focusNode->GetNodeType(&nodeType);
    5401               0 :     if (nsIDOMNode::TEXT_NODE == nodeType) {
    5402               0 :       nsCOMPtr<nsIDOMNode> parent;
    5403               0 :       res = focusNode->GetParentNode(getter_AddRefs(parent));
    5404               0 :       NS_ENSURE_SUCCESS(res, res);
    5405               0 :       focusNode = parent;
    5406                 :     }
    5407                 :   }
    5408                 : 
    5409               0 :   nsCOMPtr<nsIDOMElement> focusElement = do_QueryInterface(focusNode);
    5410               0 :   focusElement.forget(aReturn);
    5411               0 :   return NS_OK;
    5412                 : }
    5413                 : 
    5414                 : NS_IMETHODIMP
    5415               0 : nsHTMLEditor::IsAnonymousElement(nsIDOMElement * aElement, bool * aReturn)
    5416                 : {
    5417               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
    5418               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
    5419               0 :   *aReturn = content->IsRootOfNativeAnonymousSubtree();
    5420               0 :   return NS_OK;
    5421                 : }
    5422                 : 
    5423                 : nsresult
    5424               0 : nsHTMLEditor::SetReturnInParagraphCreatesNewParagraph(bool aCreatesNewParagraph)
    5425                 : {
    5426               0 :   mCRInParagraphCreatesParagraph = aCreatesNewParagraph;
    5427               0 :   return NS_OK;
    5428                 : }
    5429                 : 
    5430                 : nsresult
    5431               0 : nsHTMLEditor::GetReturnInParagraphCreatesNewParagraph(bool *aCreatesNewParagraph)
    5432                 : {
    5433               0 :   *aCreatesNewParagraph = mCRInParagraphCreatesParagraph;
    5434               0 :   return NS_OK;
    5435                 : }
    5436                 : 
    5437                 : already_AddRefed<nsIContent>
    5438               0 : nsHTMLEditor::GetFocusedContent()
    5439                 : {
    5440               0 :   NS_ENSURE_TRUE(mDocWeak, nsnull);
    5441                 : 
    5442               0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5443               0 :   NS_ENSURE_TRUE(fm, nsnull);
    5444                 : 
    5445               0 :   nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
    5446                 : 
    5447               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    5448               0 :   bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE);
    5449               0 :   if (!focusedContent) {
    5450                 :     // in designMode, nobody gets focus in most cases.
    5451               0 :     if (inDesignMode && OurWindowHasFocus()) {
    5452               0 :       nsCOMPtr<nsIContent> docRoot = doc->GetRootElement();
    5453               0 :       return docRoot.forget();
    5454                 :     }
    5455               0 :     return nsnull;
    5456                 :   }
    5457                 : 
    5458               0 :   if (inDesignMode) {
    5459               0 :     return OurWindowHasFocus() &&
    5460               0 :       nsContentUtils::ContentIsDescendantOf(focusedContent, doc) ?
    5461               0 :       focusedContent.forget() : nsnull;
    5462                 :   }
    5463                 : 
    5464                 :   // We're HTML editor for contenteditable
    5465                 : 
    5466                 :   // If the focused content isn't editable, or it has independent selection,
    5467                 :   // we don't have focus.
    5468               0 :   if (!focusedContent->HasFlag(NODE_IS_EDITABLE) ||
    5469               0 :       focusedContent->HasIndependentSelection()) {
    5470               0 :     return nsnull;
    5471                 :   }
    5472                 :   // If our window is focused, we're focused.
    5473               0 :   return OurWindowHasFocus() ? focusedContent.forget() : nsnull;
    5474                 : }
    5475                 : 
    5476                 : bool
    5477               0 : nsHTMLEditor::IsActiveInDOMWindow()
    5478                 : {
    5479               0 :   NS_ENSURE_TRUE(mDocWeak, false);
    5480                 : 
    5481               0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5482               0 :   NS_ENSURE_TRUE(fm, false);
    5483                 : 
    5484               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    5485               0 :   bool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE);
    5486                 : 
    5487                 :   // If we're in designMode, we're always active in the DOM window.
    5488               0 :   if (inDesignMode) {
    5489               0 :     return true;
    5490                 :   }
    5491                 : 
    5492               0 :   nsPIDOMWindow* ourWindow = doc->GetWindow();
    5493               0 :   nsCOMPtr<nsPIDOMWindow> win;
    5494                 :   nsIContent* content =
    5495                 :     nsFocusManager::GetFocusedDescendant(ourWindow, false,
    5496               0 :                                          getter_AddRefs(win));
    5497               0 :   if (!content) {
    5498               0 :     return false;
    5499                 :   }
    5500                 : 
    5501                 :   // We're HTML editor for contenteditable
    5502                 : 
    5503                 :   // If the active content isn't editable, or it has independent selection,
    5504                 :   // we're not active).
    5505               0 :   if (!content->HasFlag(NODE_IS_EDITABLE) ||
    5506               0 :       content->HasIndependentSelection()) {
    5507               0 :     return false;
    5508                 :   }
    5509               0 :   return true;
    5510                 : }
    5511                 : 
    5512                 : nsIContent*
    5513               0 : nsHTMLEditor::GetActiveEditingHost()
    5514                 : {
    5515               0 :   NS_ENSURE_TRUE(mDocWeak, nsnull);
    5516                 : 
    5517               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    5518               0 :   NS_ENSURE_TRUE(doc, nsnull);
    5519               0 :   if (doc->HasFlag(NODE_IS_EDITABLE)) {
    5520               0 :     return doc->GetBodyElement();
    5521                 :   }
    5522                 : 
    5523                 :   // We're HTML editor for contenteditable
    5524               0 :   nsCOMPtr<nsISelection> selection;
    5525               0 :   nsresult rv = GetSelection(getter_AddRefs(selection));
    5526               0 :   NS_ENSURE_SUCCESS(rv, nsnull);
    5527               0 :   nsCOMPtr<nsIDOMNode> focusNode;
    5528               0 :   rv = selection->GetFocusNode(getter_AddRefs(focusNode));
    5529               0 :   NS_ENSURE_SUCCESS(rv, nsnull);
    5530               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(focusNode);
    5531               0 :   if (!content) {
    5532               0 :     return nsnull;
    5533                 :   }
    5534                 : 
    5535                 :   // If the active content isn't editable, or it has independent selection,
    5536                 :   // we're not active.
    5537               0 :   if (!content->HasFlag(NODE_IS_EDITABLE) ||
    5538               0 :       content->HasIndependentSelection()) {
    5539               0 :     return nsnull;
    5540                 :   }
    5541               0 :   return content->GetEditingHost();
    5542                 : }
    5543                 : 
    5544                 : already_AddRefed<nsIDOMEventTarget>
    5545               0 : nsHTMLEditor::GetDOMEventTarget()
    5546                 : {
    5547                 :   // Don't use getDocument here, because we have no way of knowing
    5548                 :   // whether Init() was ever called.  So we need to get the document
    5549                 :   // ourselves, if it exists.
    5550               0 :   NS_PRECONDITION(mDocWeak, "This editor has not been initialized yet");
    5551               0 :   nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mDocWeak.get());
    5552               0 :   return target.forget();
    5553                 : }
    5554                 : 
    5555                 : bool
    5556               0 : nsHTMLEditor::ShouldReplaceRootElement()
    5557                 : {
    5558               0 :   if (!mRootElement) {
    5559                 :     // If we don't know what is our root element, we should find our root.
    5560               0 :     return true;
    5561                 :   }
    5562                 : 
    5563                 :   // If we temporary set document root element to mRootElement, but there is
    5564                 :   // body element now, we should replace the root element by the body element.
    5565               0 :   nsCOMPtr<nsIDOMHTMLElement> docBody;
    5566               0 :   GetBodyElement(getter_AddRefs(docBody));
    5567               0 :   return !SameCOMIdentity(docBody, mRootElement);
    5568                 : }
    5569                 : 
    5570                 : void
    5571               0 : nsHTMLEditor::ResetRootElementAndEventTarget()
    5572                 : {
    5573               0 :   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    5574                 : 
    5575                 :   // Need to remove the event listeners first because BeginningOfDocument
    5576                 :   // could set a new root (and event target is set by InstallEventListeners())
    5577                 :   // and we won't be able to remove them from the old event target then.
    5578               0 :   RemoveEventListeners();
    5579               0 :   mRootElement = nsnull;
    5580               0 :   nsresult rv = InstallEventListeners();
    5581               0 :   if (NS_FAILED(rv)) {
    5582                 :     return;
    5583                 :   }
    5584                 : 
    5585                 :   // We must have mRootElement now.
    5586               0 :   nsCOMPtr<nsIDOMElement> root;
    5587               0 :   rv = GetRootElement(getter_AddRefs(root));
    5588               0 :   if (NS_FAILED(rv) || !mRootElement) {
    5589                 :     return;
    5590                 :   }
    5591                 : 
    5592               0 :   rv = BeginningOfDocument();
    5593               0 :   if (NS_FAILED(rv)) {
    5594                 :     return;
    5595                 :   }
    5596                 : 
    5597                 :   // When this editor has focus, we need to reset the selection limiter to
    5598                 :   // new root.  Otherwise, that is going to be done when this gets focus.
    5599               0 :   nsCOMPtr<nsINode> node = GetFocusedNode();
    5600               0 :   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(node);
    5601               0 :   if (target) {
    5602               0 :     InitializeSelection(target);
    5603                 :   }
    5604                 : 
    5605               0 :   SyncRealTimeSpell();
    5606                 : }
    5607                 : 
    5608                 : nsresult
    5609               0 : nsHTMLEditor::GetBodyElement(nsIDOMHTMLElement** aBody)
    5610                 : {
    5611               0 :   NS_PRECONDITION(mDocWeak, "bad state, null mDocWeak");
    5612               0 :   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryReferent(mDocWeak);
    5613               0 :   if (!htmlDoc) {
    5614               0 :     return NS_ERROR_NOT_INITIALIZED;
    5615                 :   }
    5616               0 :   return htmlDoc->GetBody(aBody);
    5617                 : }
    5618                 : 
    5619                 : already_AddRefed<nsINode>
    5620               0 : nsHTMLEditor::GetFocusedNode()
    5621                 : {
    5622               0 :   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
    5623               0 :   if (!focusedContent) {
    5624               0 :     return nsnull;
    5625                 :   }
    5626                 : 
    5627               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    5628               0 :   NS_ASSERTION(fm, "Focus manager is null");
    5629               0 :   nsCOMPtr<nsIDOMElement> focusedElement;
    5630               0 :   fm->GetFocusedElement(getter_AddRefs(focusedElement));
    5631               0 :   if (focusedElement) {
    5632               0 :     nsCOMPtr<nsINode> node = do_QueryInterface(focusedElement);
    5633               0 :     return node.forget();
    5634                 :   }
    5635                 : 
    5636               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    5637               0 :   return doc.forget();
    5638                 : }
    5639                 : 
    5640                 : bool
    5641               0 : nsHTMLEditor::OurWindowHasFocus()
    5642                 : {
    5643               0 :   NS_ENSURE_TRUE(mDocWeak, false);
    5644               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    5645               0 :   NS_ENSURE_TRUE(fm, false);
    5646               0 :   nsCOMPtr<nsIDOMWindow> focusedWindow;
    5647               0 :   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
    5648               0 :   if (!focusedWindow) {
    5649               0 :     return false;
    5650                 :   }
    5651               0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
    5652               0 :   nsCOMPtr<nsIDOMWindow> ourWindow = do_QueryInterface(doc->GetWindow());
    5653               0 :   return ourWindow == focusedWindow;
    5654                 : }
    5655                 : 
    5656                 : bool
    5657               0 : nsHTMLEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
    5658                 : {
    5659               0 :   if (!nsEditor::IsAcceptableInputEvent(aEvent)) {
    5660               0 :     return false;
    5661                 :   }
    5662                 : 
    5663               0 :   NS_ENSURE_TRUE(mDocWeak, false);
    5664                 : 
    5665               0 :   nsCOMPtr<nsIDOMEventTarget> target;
    5666               0 :   aEvent->GetTarget(getter_AddRefs(target));
    5667               0 :   NS_ENSURE_TRUE(target, false);
    5668                 : 
    5669               0 :   nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocWeak);
    5670               0 :   if (document->HasFlag(NODE_IS_EDITABLE)) {
    5671                 :     // If this editor is in designMode and the event target is the document,
    5672                 :     // the event is for this editor.
    5673               0 :     nsCOMPtr<nsIDocument> targetDocument = do_QueryInterface(target);
    5674               0 :     if (targetDocument) {
    5675               0 :       return targetDocument == document;
    5676                 :     }
    5677                 :     // Otherwise, check whether the event target is in this document or not.
    5678               0 :     nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
    5679               0 :     NS_ENSURE_TRUE(targetContent, false);
    5680               0 :     return document == targetContent->GetCurrentDoc();
    5681                 :   }
    5682                 : 
    5683                 :   // This HTML editor is for contenteditable.  We need to check the validity of
    5684                 :   // the target.
    5685               0 :   nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
    5686               0 :   NS_ENSURE_TRUE(targetContent, false);
    5687                 : 
    5688                 :   // If the event is a mouse event, we need to check if the target content is
    5689                 :   // the focused editing host or its descendant.
    5690               0 :   nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
    5691               0 :   if (mouseEvent) {
    5692               0 :     nsIContent* editingHost = GetActiveEditingHost();
    5693                 :     // If there is no active editing host, we cannot handle the mouse event
    5694                 :     // correctly.
    5695               0 :     if (!editingHost) {
    5696               0 :       return false;
    5697                 :     }
    5698                 :     // If clicked on non-editable root element but the body element is the
    5699                 :     // active editing host, we should assume that the click event is targetted.
    5700               0 :     if (targetContent == document->GetRootElement() &&
    5701               0 :         !targetContent->HasFlag(NODE_IS_EDITABLE) &&
    5702               0 :         editingHost == document->GetBodyElement()) {
    5703               0 :       targetContent = editingHost;
    5704                 :     }
    5705                 :     // If the target element is neither the active editing host nor a descendant
    5706                 :     // of it, we may not be able to handle the event.
    5707               0 :     if (!nsContentUtils::ContentIsDescendantOf(targetContent, editingHost)) {
    5708               0 :       return false;
    5709                 :     }
    5710                 :     // If the clicked element has an independent selection, we shouldn't
    5711                 :     // handle this click event.
    5712               0 :     if (targetContent->HasIndependentSelection()) {
    5713               0 :       return false;
    5714                 :     }
    5715                 :     // If the target content is editable, we should handle this event.
    5716               0 :     return targetContent->HasFlag(NODE_IS_EDITABLE);
    5717                 :   }
    5718                 : 
    5719                 :   // If the target of the other events which target focused element isn't
    5720                 :   // editable or has an independent selection, this editor shouldn't handle the
    5721                 :   // event.
    5722               0 :   if (!targetContent->HasFlag(NODE_IS_EDITABLE) ||
    5723               0 :       targetContent->HasIndependentSelection()) {
    5724               0 :     return false;
    5725                 :   }
    5726                 : 
    5727                 :   // Finally, check whether we're actually focused or not.  When we're not
    5728                 :   // focused, we should ignore the dispatched event by script (or something)
    5729                 :   // because content editable element needs selection in itself for editing.
    5730                 :   // However, when we're not focused, it's not guaranteed.
    5731               0 :   return IsActiveInDOMWindow();
    5732                 : }
    5733                 : 
    5734                 : NS_IMETHODIMP
    5735               0 : nsHTMLEditor::GetPreferredIMEState(IMEState *aState)
    5736                 : {
    5737                 :   // HTML editor don't prefer the CSS ime-mode because IE didn't do so too.
    5738               0 :   aState->mOpen = IMEState::DONT_CHANGE_OPEN_STATE;
    5739               0 :   if (IsReadonly() || IsDisabled()) {
    5740               0 :     aState->mEnabled = IMEState::DISABLED;
    5741                 :   } else {
    5742               0 :     aState->mEnabled = IMEState::ENABLED;
    5743                 :   }
    5744               0 :   return NS_OK;
    5745            4392 : }

Generated by: LCOV version 1.7