LCOV - code coverage report
Current view: directory - editor/libeditor/html - nsHTMLEditorStyle.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 940 0 0.0 %
Date: 2012-06-02 Functions: 37 0 0.0 %

       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                 :  *   Daniel Glazman <glazman@netscape.com>
      24                 :  *   Mats Palmgren <matspal@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : #include "nsUnicharUtils.h"
      40                 : 
      41                 : #include "nsHTMLEditor.h"
      42                 : #include "nsHTMLEditRules.h"
      43                 : #include "nsTextEditUtils.h"
      44                 : #include "nsHTMLEditUtils.h"
      45                 : #include "nsIDOMNodeList.h"
      46                 : #include "nsIDOMAttr.h"
      47                 : #include "nsIDOMMouseEvent.h"
      48                 : #include "nsISelection.h"
      49                 : #include "nsISelectionPrivate.h"
      50                 : #include "nsIDOMHTMLImageElement.h"
      51                 : #include "nsISelectionController.h"
      52                 : #include "nsIDocumentObserver.h"
      53                 : #include "TypeInState.h"
      54                 : 
      55                 : #include "nsIEnumerator.h"
      56                 : #include "nsIContent.h"
      57                 : #include "nsIContentIterator.h"
      58                 : #include "nsAttrName.h"
      59                 : 
      60                 : #include "mozilla/dom/Element.h"
      61                 : 
      62                 : using namespace mozilla;
      63                 : 
      64               0 : NS_IMETHODIMP nsHTMLEditor::AddDefaultProperty(nsIAtom *aProperty, 
      65                 :                                             const nsAString & aAttribute, 
      66                 :                                             const nsAString & aValue)
      67                 : {
      68               0 :   nsString outValue;
      69                 :   PRInt32 index;
      70               0 :   nsString attr(aAttribute);
      71               0 :   if (TypeInState::FindPropInList(aProperty, attr, &outValue, mDefaultStyles, index))
      72                 :   {
      73               0 :     PropItem *item = mDefaultStyles[index];
      74               0 :     item->value = aValue;
      75                 :   }
      76                 :   else
      77                 :   {
      78               0 :     nsString value(aValue);
      79               0 :     PropItem *propItem = new PropItem(aProperty, attr, value);
      80               0 :     mDefaultStyles.AppendElement(propItem);
      81                 :   }
      82               0 :   return NS_OK;
      83                 : }
      84                 : 
      85               0 : NS_IMETHODIMP nsHTMLEditor::RemoveDefaultProperty(nsIAtom *aProperty, 
      86                 :                                    const nsAString & aAttribute, 
      87                 :                                    const nsAString & aValue)
      88                 : {
      89               0 :   nsString outValue;
      90                 :   PRInt32 index;
      91               0 :   nsString attr(aAttribute);
      92               0 :   if (TypeInState::FindPropInList(aProperty, attr, &outValue, mDefaultStyles, index))
      93                 :   {
      94               0 :     delete mDefaultStyles[index];
      95               0 :     mDefaultStyles.RemoveElementAt(index);
      96                 :   }
      97               0 :   return NS_OK;
      98                 : }
      99                 : 
     100               0 : NS_IMETHODIMP nsHTMLEditor::RemoveAllDefaultProperties()
     101                 : {
     102               0 :   PRUint32 j, defcon = mDefaultStyles.Length();
     103               0 :   for (j=0; j<defcon; j++)
     104                 :   {
     105               0 :     delete mDefaultStyles[j];
     106                 :   }
     107               0 :   mDefaultStyles.Clear();
     108               0 :   return NS_OK;
     109                 : }
     110                 : 
     111                 : 
     112                 : // Add the CSS style corresponding to the HTML inline style defined
     113                 : // by aProperty aAttribute and aValue to the selection
     114               0 : NS_IMETHODIMP nsHTMLEditor::SetCSSInlineProperty(nsIAtom *aProperty, 
     115                 :                             const nsAString & aAttribute, 
     116                 :                             const nsAString & aValue)
     117                 : {
     118               0 :   if (IsCSSEnabled()) {
     119               0 :     return SetInlineProperty(aProperty, aAttribute, aValue);
     120                 :   }
     121               0 :   return NS_OK;
     122                 : }
     123                 : 
     124               0 : NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty, 
     125                 :                             const nsAString & aAttribute, 
     126                 :                             const nsAString & aValue)
     127                 : {
     128               0 :   if (!aProperty) { return NS_ERROR_NULL_POINTER; }
     129               0 :   if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
     130               0 :   ForceCompositionEnd();
     131                 : 
     132               0 :   nsCOMPtr<nsISelection>selection;
     133               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
     134               0 :   NS_ENSURE_SUCCESS(res, res);
     135               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     136               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
     137                 : 
     138                 :   bool isCollapsed;
     139               0 :   selection->GetIsCollapsed(&isCollapsed);
     140               0 :   if (isCollapsed)
     141                 :   {
     142                 :     // manipulating text attributes on a collapsed selection only sets state for the next text insertion
     143               0 :     nsString tAttr(aAttribute);//MJUDGE SCC NEED HELP
     144               0 :     nsString tVal(aValue);//MJUDGE SCC NEED HELP
     145               0 :     return mTypeInState->SetProp(aProperty, tAttr, tVal);
     146                 :   }
     147                 :   
     148               0 :   nsAutoEditBatch batchIt(this);
     149               0 :   nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
     150               0 :   nsAutoSelectionReset selectionResetter(selection, this);
     151               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(this);
     152                 :   
     153                 :   bool cancel, handled;
     154               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kSetTextProperty);
     155               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
     156               0 :   NS_ENSURE_SUCCESS(res, res);
     157               0 :   if (!cancel && !handled)
     158                 :   {
     159                 :     // get selection range enumerator
     160               0 :     nsCOMPtr<nsIEnumerator> enumerator;
     161               0 :     res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
     162               0 :     NS_ENSURE_SUCCESS(res, res);
     163               0 :     NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
     164                 : 
     165                 :     // loop thru the ranges in the selection
     166               0 :     enumerator->First(); 
     167               0 :     nsCOMPtr<nsISupports> currentItem;
     168               0 :     while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
     169                 :     {
     170               0 :       res = enumerator->CurrentItem(getter_AddRefs(currentItem));
     171               0 :       NS_ENSURE_SUCCESS(res, res);
     172               0 :       NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
     173                 :       
     174               0 :       nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
     175                 : 
     176                 :       // adjust range to include any ancestors who's children are entirely selected
     177               0 :       res = PromoteInlineRange(range);
     178               0 :       NS_ENSURE_SUCCESS(res, res);
     179                 :       
     180                 :       // check for easy case: both range endpoints in same text node
     181               0 :       nsCOMPtr<nsIDOMNode> startNode, endNode;
     182               0 :       res = range->GetStartContainer(getter_AddRefs(startNode));
     183               0 :       NS_ENSURE_SUCCESS(res, res);
     184               0 :       res = range->GetEndContainer(getter_AddRefs(endNode));
     185               0 :       NS_ENSURE_SUCCESS(res, res);
     186               0 :       if ((startNode == endNode) && IsTextNode(startNode))
     187                 :       {
     188                 :         PRInt32 startOffset, endOffset;
     189               0 :         range->GetStartOffset(&startOffset);
     190               0 :         range->GetEndOffset(&endOffset);
     191               0 :         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
     192               0 :         res = SetInlinePropertyOnTextNode(nodeAsText, startOffset, endOffset, aProperty, &aAttribute, &aValue);
     193               0 :         NS_ENSURE_SUCCESS(res, res);
     194                 :       }
     195                 :       else
     196                 :       {
     197                 :         // not the easy case.  range not contained in single text node. 
     198                 :         // there are up to three phases here.  There are all the nodes
     199                 :         // reported by the subtree iterator to be processed.  And there
     200                 :         // are potentially a starting textnode and an ending textnode
     201                 :         // which are only partially contained by the range.
     202                 :         
     203                 :         // lets handle the nodes reported by the iterator.  These nodes
     204                 :         // are entirely contained in the selection range.  We build up
     205                 :         // a list of them (since doing operations on the document during
     206                 :         // iteration would perturb the iterator).
     207                 : 
     208                 :         nsCOMPtr<nsIContentIterator> iter =
     209               0 :           do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
     210               0 :         NS_ENSURE_SUCCESS(res, res);
     211               0 :         NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
     212                 : 
     213               0 :         nsCOMArray<nsIDOMNode> arrayOfNodes;
     214               0 :         nsCOMPtr<nsIDOMNode> node;
     215                 :         
     216                 :         // iterate range and build up array
     217               0 :         res = iter->Init(range);
     218                 :         // init returns an error if no nodes in range.
     219                 :         // this can easily happen with the subtree 
     220                 :         // iterator if the selection doesn't contain
     221                 :         // any *whole* nodes.
     222               0 :         if (NS_SUCCEEDED(res))
     223                 :         {
     224               0 :           while (!iter->IsDone())
     225                 :           {
     226               0 :             node = do_QueryInterface(iter->GetCurrentNode());
     227               0 :             NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
     228                 : 
     229               0 :             if (IsEditable(node))
     230                 :             { 
     231               0 :               arrayOfNodes.AppendObject(node);
     232                 :             }
     233                 : 
     234               0 :             iter->Next();
     235                 :           }
     236                 :         }
     237                 :         // first check the start parent of the range to see if it needs to 
     238                 :         // be separately handled (it does if it's a text node, due to how the
     239                 :         // subtree iterator works - it will not have reported it).
     240               0 :         if (IsTextNode(startNode) && IsEditable(startNode))
     241                 :         {
     242               0 :           nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
     243                 :           PRInt32 startOffset;
     244                 :           PRUint32 textLen;
     245               0 :           range->GetStartOffset(&startOffset);
     246               0 :           nodeAsText->GetLength(&textLen);
     247               0 :           res = SetInlinePropertyOnTextNode(nodeAsText, startOffset, textLen, aProperty, &aAttribute, &aValue);
     248               0 :           NS_ENSURE_SUCCESS(res, res);
     249                 :         }
     250                 :         
     251                 :         // then loop through the list, set the property on each node
     252               0 :         PRInt32 listCount = arrayOfNodes.Count();
     253                 :         PRInt32 j;
     254               0 :         for (j = 0; j < listCount; j++)
     255                 :         {
     256               0 :           node = arrayOfNodes[j];
     257               0 :           res = SetInlinePropertyOnNode(node, aProperty, &aAttribute, &aValue);
     258               0 :           NS_ENSURE_SUCCESS(res, res);
     259                 :         }
     260               0 :         arrayOfNodes.Clear();
     261                 :         
     262                 :         // last check the end parent of the range to see if it needs to 
     263                 :         // be separately handled (it does if it's a text node, due to how the
     264                 :         // subtree iterator works - it will not have reported it).
     265               0 :         if (IsTextNode(endNode) && IsEditable(endNode))
     266                 :         {
     267               0 :           nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(endNode);
     268                 :           PRInt32 endOffset;
     269               0 :           range->GetEndOffset(&endOffset);
     270               0 :           res = SetInlinePropertyOnTextNode(nodeAsText, 0, endOffset, aProperty, &aAttribute, &aValue);
     271               0 :           NS_ENSURE_SUCCESS(res, res);
     272                 :         }
     273                 :       }
     274               0 :       enumerator->Next();
     275                 :     }
     276                 :   }
     277               0 :   if (!cancel)
     278                 :   {
     279                 :     // post-process
     280               0 :     res = mRules->DidDoAction(selection, &ruleInfo, res);
     281                 :   }
     282               0 :   return res;
     283                 : }
     284                 : 
     285                 : 
     286                 : 
     287                 : nsresult
     288               0 : nsHTMLEditor::SetInlinePropertyOnTextNode( nsIDOMCharacterData *aTextNode, 
     289                 :                                             PRInt32 aStartOffset,
     290                 :                                             PRInt32 aEndOffset,
     291                 :                                             nsIAtom *aProperty, 
     292                 :                                             const nsAString *aAttribute,
     293                 :                                             const nsAString *aValue)
     294                 : {
     295               0 :   NS_ENSURE_TRUE(aTextNode, NS_ERROR_NULL_POINTER);
     296               0 :   nsCOMPtr<nsIDOMNode> parent;
     297               0 :   nsresult res = aTextNode->GetParentNode(getter_AddRefs(parent));
     298               0 :   NS_ENSURE_SUCCESS(res, res);
     299                 : 
     300               0 :   nsAutoString tagString;
     301               0 :   aProperty->ToString(tagString);
     302               0 :   if (!CanContainTag(parent, tagString)) return NS_OK;
     303                 :   
     304                 :   // don't need to do anything if no characters actually selected
     305               0 :   if (aStartOffset == aEndOffset) return NS_OK;
     306                 :   
     307               0 :   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aTextNode);
     308                 :   
     309                 :   // don't need to do anything if property already set on node
     310                 :   bool bHasProp;
     311               0 :   if (IsCSSEnabled() &&
     312               0 :       mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
     313                 :     // the HTML styles defined by aProperty/aAttribute has a CSS equivalence
     314                 :     // in this implementation for node; let's check if it carries those css styles
     315               0 :     nsAutoString value;
     316               0 :     if (aValue) value.Assign(*aValue);
     317                 :     mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, aAttribute,
     318                 :                                                        bHasProp, value,
     319               0 :                                                        COMPUTED_STYLE_TYPE);
     320                 :   }
     321                 :   else
     322                 :   {
     323               0 :     nsCOMPtr<nsIDOMNode> styleNode;
     324               0 :     IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, bHasProp, getter_AddRefs(styleNode));
     325                 :   }
     326                 : 
     327               0 :   if (bHasProp) return NS_OK;
     328                 :   
     329                 :   // do we need to split the text node?
     330                 :   PRUint32 textLen;
     331               0 :   aTextNode->GetLength(&textLen);
     332                 :   
     333               0 :   nsCOMPtr<nsIDOMNode> tmp;
     334               0 :   if ( (PRUint32)aEndOffset != textLen )
     335                 :   {
     336                 :     // we need to split off back of text node
     337               0 :     res = SplitNode(node, aEndOffset, getter_AddRefs(tmp));
     338               0 :     NS_ENSURE_SUCCESS(res, res);
     339               0 :     node = tmp;  // remember left node
     340                 :   }
     341               0 :   if ( aStartOffset )
     342                 :   {
     343                 :     // we need to split off front of text node
     344               0 :     res = SplitNode(node, aStartOffset, getter_AddRefs(tmp));
     345               0 :     NS_ENSURE_SUCCESS(res, res);
     346                 :   }
     347                 :   
     348                 :   // look for siblings that are correct type of node
     349               0 :   nsCOMPtr<nsIDOMNode> sibling;
     350               0 :   GetPriorHTMLSibling(node, address_of(sibling));
     351               0 :   if (sibling && NodeIsType(sibling, aProperty) &&         
     352               0 :       HasAttrVal(sibling, aAttribute, aValue) &&
     353               0 :       IsOnlyAttribute(sibling, aAttribute) )
     354                 :   {
     355                 :     // previous sib is already right kind of inline node; slide this over into it
     356               0 :     res = MoveNode(node, sibling, -1);
     357               0 :     return res;
     358                 :   }
     359               0 :   sibling = nsnull;
     360               0 :   GetNextHTMLSibling(node, address_of(sibling));
     361               0 :   if (sibling && NodeIsType(sibling, aProperty) &&         
     362               0 :       HasAttrVal(sibling, aAttribute, aValue) &&
     363               0 :       IsOnlyAttribute(sibling, aAttribute) )
     364                 :   {
     365                 :     // following sib is already right kind of inline node; slide this over into it
     366               0 :     res = MoveNode(node, sibling, 0);
     367               0 :     return res;
     368                 :   }
     369                 :   
     370                 :   // reparent the node inside inline node with appropriate {attribute,value}
     371               0 :   return SetInlinePropertyOnNode(node, aProperty, aAttribute, aValue);
     372                 : }
     373                 : 
     374                 : 
     375                 : nsresult
     376               0 : nsHTMLEditor::SetInlinePropertyOnNode( nsIDOMNode *aNode,
     377                 :                                        nsIAtom *aProperty, 
     378                 :                                        const nsAString *aAttribute,
     379                 :                                        const nsAString *aValue)
     380                 : {
     381               0 :   NS_ENSURE_TRUE(aNode && aProperty, NS_ERROR_NULL_POINTER);
     382                 : 
     383               0 :   nsresult res = NS_OK;
     384               0 :   nsCOMPtr<nsIDOMNode> tmp;
     385               0 :   nsAutoString tag;
     386               0 :   aProperty->ToString(tag);
     387               0 :   ToLowerCase(tag);
     388                 :   
     389               0 :   if (IsCSSEnabled())
     390                 :   {
     391                 :     // we are in CSS mode
     392               0 :     if (mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute))
     393                 :     {
     394                 :       // the HTML style defined by aProperty/aAttribute has a CSS equivalence
     395                 :       // in this implementation for the node aNode
     396               0 :       nsCOMPtr<nsIDOMNode> tmp = aNode;
     397               0 :       if (IsTextNode(tmp))
     398                 :       {
     399                 :         // we are working on a text node and need to create a span container
     400                 :         // that will carry the styles
     401                 :         InsertContainerAbove( aNode, 
     402                 :                               address_of(tmp), 
     403               0 :                               NS_LITERAL_STRING("span"),
     404                 :                               nsnull,
     405               0 :                               nsnull);
     406                 :       }
     407               0 :       nsCOMPtr<nsIDOMElement>element;
     408               0 :       element = do_QueryInterface(tmp);
     409                 :       // first we have to remove occurences of the same style hint in the
     410                 :       // children of the aNode
     411               0 :       res = RemoveStyleInside(tmp, aProperty, aAttribute, true);
     412               0 :       NS_ENSURE_SUCCESS(res, res);
     413                 :       PRInt32 count;
     414                 :       // then we add the css styles corresponding to the HTML style request
     415               0 :       res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, aProperty, aAttribute, aValue, &count, false);
     416               0 :       NS_ENSURE_SUCCESS(res, res);
     417                 : 
     418               0 :       nsCOMPtr<nsIDOMNode> nextSibling, previousSibling;
     419               0 :       GetNextHTMLSibling(tmp, address_of(nextSibling));
     420               0 :       GetPriorHTMLSibling(tmp, address_of(previousSibling));
     421               0 :       if (nextSibling || previousSibling)
     422                 :       {
     423               0 :         nsCOMPtr<nsIDOMNode> mergeParent;
     424               0 :         res = tmp->GetParentNode(getter_AddRefs(mergeParent));
     425               0 :         NS_ENSURE_SUCCESS(res, res);
     426               0 :         if (previousSibling &&
     427               0 :             nsEditor::NodeIsType(previousSibling, nsEditProperty::span) &&
     428               0 :             NodesSameType(tmp, previousSibling))
     429                 :         {
     430               0 :           res = JoinNodes(previousSibling, tmp, mergeParent);
     431               0 :           NS_ENSURE_SUCCESS(res, res);
     432                 :         }
     433               0 :         if (nextSibling &&
     434               0 :             nsEditor::NodeIsType(nextSibling, nsEditProperty::span) &&
     435               0 :             NodesSameType(tmp, nextSibling))
     436                 :         {
     437               0 :           res = JoinNodes(tmp, nextSibling, mergeParent);
     438                 :         }
     439                 :       }
     440               0 :       return res;
     441                 :     }
     442                 :   }
     443                 :   
     444                 :   // don't need to do anything if property already set on node
     445                 :   bool bHasProp;
     446               0 :   nsCOMPtr<nsIDOMNode> styleNode;
     447               0 :   IsTextPropertySetByContent(aNode, aProperty, aAttribute, aValue, bHasProp, getter_AddRefs(styleNode));
     448               0 :   if (bHasProp) return NS_OK;
     449                 : 
     450                 :   // is it already the right kind of node, but with wrong attribute?
     451               0 :   if (NodeIsType(aNode, aProperty))
     452                 :   {
     453                 :     // just set the attribute on it.
     454                 :     // but first remove any contrary style in it's children.
     455               0 :     res = RemoveStyleInside(aNode, aProperty, aAttribute, true);
     456               0 :     NS_ENSURE_SUCCESS(res, res);
     457               0 :     nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
     458               0 :     return SetAttribute(elem, *aAttribute, *aValue);
     459                 :   }
     460                 :   
     461                 :   // can it be put inside inline node?
     462               0 :   if (TagCanContain(tag, aNode))
     463                 :   {
     464               0 :     nsCOMPtr<nsIDOMNode> priorNode, nextNode;
     465                 :     // is either of it's neighbors the right kind of node?
     466               0 :     GetPriorHTMLSibling(aNode, address_of(priorNode));
     467               0 :     GetNextHTMLSibling(aNode, address_of(nextNode));
     468               0 :     if (priorNode && NodeIsType(priorNode, aProperty) && 
     469               0 :         HasAttrVal(priorNode, aAttribute, aValue)     &&
     470               0 :         IsOnlyAttribute(priorNode, aAttribute) )
     471                 :     {
     472                 :       // previous sib is already right kind of inline node; slide this over into it
     473               0 :       res = MoveNode(aNode, priorNode, -1);
     474                 :     }
     475               0 :     else if (nextNode && NodeIsType(nextNode, aProperty) && 
     476               0 :              HasAttrVal(nextNode, aAttribute, aValue)    &&
     477               0 :              IsOnlyAttribute(priorNode, aAttribute) )
     478                 :     {
     479                 :       // following sib is already right kind of inline node; slide this over into it
     480               0 :       res = MoveNode(aNode, nextNode, 0);
     481                 :     }
     482                 :     else
     483                 :     {
     484                 :       // ok, chuck it in its very own container
     485               0 :       res = InsertContainerAbove(aNode, address_of(tmp), tag, aAttribute, aValue);
     486                 :     }
     487               0 :     NS_ENSURE_SUCCESS(res, res);
     488               0 :     return RemoveStyleInside(aNode, aProperty, aAttribute);
     489                 :   }
     490                 :   // none of the above?  then cycle through the children.
     491               0 :   nsCOMPtr<nsIDOMNodeList> childNodes;
     492               0 :   res = aNode->GetChildNodes(getter_AddRefs(childNodes));
     493               0 :   NS_ENSURE_SUCCESS(res, res);
     494               0 :   if (childNodes)
     495                 :   {
     496                 :     PRInt32 j;
     497                 :     PRUint32 childCount;
     498               0 :     childNodes->GetLength(&childCount);
     499               0 :     if (childCount)
     500                 :     {
     501               0 :       nsCOMArray<nsIDOMNode> arrayOfNodes;
     502               0 :       nsCOMPtr<nsIDOMNode> node;
     503                 :       
     504                 :       // populate the list
     505               0 :       for (j=0 ; j < (PRInt32)childCount; j++)
     506                 :       {
     507               0 :         nsCOMPtr<nsIDOMNode> childNode;
     508               0 :         res = childNodes->Item(j, getter_AddRefs(childNode));
     509               0 :         if ((NS_SUCCEEDED(res)) && (childNode) && IsEditable(childNode))
     510                 :         {
     511               0 :           arrayOfNodes.AppendObject(childNode);
     512                 :         }
     513                 :       }
     514                 :       
     515                 :       // then loop through the list, set the property on each node
     516               0 :       PRInt32 listCount = arrayOfNodes.Count();
     517               0 :       for (j = 0; j < listCount; j++)
     518                 :       {
     519               0 :         node = arrayOfNodes[j];
     520               0 :         res = SetInlinePropertyOnNode(node, aProperty, aAttribute, aValue);
     521               0 :         NS_ENSURE_SUCCESS(res, res);
     522                 :       }
     523               0 :       arrayOfNodes.Clear();
     524                 :     }
     525                 :   }
     526               0 :   return res;
     527                 : }
     528                 : 
     529                 : 
     530               0 : nsresult nsHTMLEditor::SplitStyleAboveRange(nsIDOMRange *inRange, 
     531                 :                                             nsIAtom *aProperty, 
     532                 :                                             const nsAString *aAttribute)
     533                 : {
     534               0 :   NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
     535                 :   nsresult res;
     536               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode, origStartNode;
     537                 :   PRInt32 startOffset, endOffset;
     538                 : 
     539               0 :   res = inRange->GetStartContainer(getter_AddRefs(startNode));
     540               0 :   NS_ENSURE_SUCCESS(res, res);
     541               0 :   res = inRange->GetStartOffset(&startOffset);
     542               0 :   NS_ENSURE_SUCCESS(res, res);
     543               0 :   res = inRange->GetEndContainer(getter_AddRefs(endNode));
     544               0 :   NS_ENSURE_SUCCESS(res, res);
     545               0 :   res = inRange->GetEndOffset(&endOffset);
     546               0 :   NS_ENSURE_SUCCESS(res, res);
     547                 : 
     548               0 :   origStartNode = startNode;
     549                 : 
     550                 :   // split any matching style nodes above the start of range
     551                 :   {
     552               0 :     nsAutoTrackDOMPoint tracker(mRangeUpdater, address_of(endNode), &endOffset);
     553               0 :     res = SplitStyleAbovePoint(address_of(startNode), &startOffset, aProperty, aAttribute);
     554               0 :     NS_ENSURE_SUCCESS(res, res);
     555                 :   }
     556                 : 
     557                 :   // second verse, same as the first...
     558               0 :   res = SplitStyleAbovePoint(address_of(endNode), &endOffset, aProperty, aAttribute);
     559               0 :   NS_ENSURE_SUCCESS(res, res);
     560                 : 
     561                 :   // reset the range
     562               0 :   res = inRange->SetStart(startNode, startOffset);
     563               0 :   NS_ENSURE_SUCCESS(res, res);
     564               0 :   res = inRange->SetEnd(endNode, endOffset);
     565               0 :   return res;
     566                 : }
     567                 : 
     568               0 : nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
     569                 :                                            PRInt32 *aOffset,
     570                 :                                            nsIAtom *aProperty,          // null here means we split all properties
     571                 :                                            const nsAString *aAttribute,
     572                 :                                            nsCOMPtr<nsIDOMNode> *outLeftNode,
     573                 :                                            nsCOMPtr<nsIDOMNode> *outRightNode)
     574                 : {
     575               0 :   NS_ENSURE_TRUE(aNode && *aNode && aOffset, NS_ERROR_NULL_POINTER);
     576               0 :   if (outLeftNode)  *outLeftNode  = nsnull;
     577               0 :   if (outRightNode) *outRightNode = nsnull;
     578                 :   // split any matching style nodes above the node/offset
     579               0 :   nsCOMPtr<nsIDOMNode> parent, tmp = *aNode;
     580                 :   PRInt32 offset;
     581                 : 
     582               0 :   bool useCSS = IsCSSEnabled();
     583                 : 
     584                 :   bool isSet;
     585               0 :   while (tmp && !IsBlockNode(tmp))
     586                 :   {
     587               0 :     isSet = false;
     588               0 :     if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(tmp, aProperty, aAttribute)) {
     589                 :       // the HTML style defined by aProperty/aAttribute has a CSS equivalence
     590                 :       // in this implementation for the node tmp; let's check if it carries those css styles
     591               0 :       nsAutoString firstValue;
     592                 :       mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(tmp, aProperty, aAttribute,
     593                 :                                                          isSet, firstValue,
     594               0 :                                                          SPECIFIED_STYLE_TYPE);
     595                 :     }
     596               0 :     if ( (aProperty && NodeIsType(tmp, aProperty)) ||   // node is the correct inline prop
     597               0 :          (aProperty == nsEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) ||
     598                 :                                                         // node is href - test if really <a href=...
     599               0 :          (!aProperty && NodeIsProperty(tmp)) ||         // or node is any prop, and we asked to split them all
     600                 :          isSet)                                         // or the style is specified in the style attribute
     601                 :     {
     602                 :       // found a style node we need to split
     603                 :       nsresult rv = SplitNodeDeep(tmp, *aNode, *aOffset, &offset, false,
     604               0 :                                   outLeftNode, outRightNode);
     605               0 :       NS_ENSURE_SUCCESS(rv, rv);
     606                 :       // reset startNode/startOffset
     607               0 :       tmp->GetParentNode(getter_AddRefs(*aNode));
     608               0 :       *aOffset = offset;
     609                 :     }
     610               0 :     tmp->GetParentNode(getter_AddRefs(parent));
     611               0 :     tmp = parent;
     612                 :   }
     613               0 :   return NS_OK;
     614                 : }
     615                 : 
     616               0 : bool nsHTMLEditor::NodeIsProperty(nsIDOMNode *aNode)
     617                 : {
     618               0 :   NS_ENSURE_TRUE(aNode, false);
     619               0 :   if (!IsContainer(aNode))  return false;
     620               0 :   if (!IsEditable(aNode))   return false;
     621               0 :   if (IsBlockNode(aNode))   return false;
     622               0 :   if (NodeIsType(aNode, nsEditProperty::a)) return false;
     623               0 :   return true;
     624                 : }
     625                 : 
     626               0 : nsresult nsHTMLEditor::ApplyDefaultProperties()
     627                 : {
     628               0 :   nsresult res = NS_OK;
     629               0 :   PRUint32 j, defcon = mDefaultStyles.Length();
     630               0 :   for (j=0; j<defcon; j++)
     631                 :   {
     632               0 :     PropItem *propItem = mDefaultStyles[j];
     633               0 :     NS_ENSURE_TRUE(propItem, NS_ERROR_NULL_POINTER);
     634               0 :     res = SetInlineProperty(propItem->tag, propItem->attr, propItem->value);
     635               0 :     NS_ENSURE_SUCCESS(res, res);
     636                 :   }
     637               0 :   return res;
     638                 : }
     639                 : 
     640               0 : nsresult nsHTMLEditor::RemoveStyleInside(nsIDOMNode *aNode, 
     641                 :                                          nsIAtom *aProperty,   // null here means remove all properties
     642                 :                                          const nsAString *aAttribute,
     643                 :                                          bool aChildrenOnly)
     644                 : {
     645               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
     646               0 :   if (IsTextNode(aNode)) return NS_OK;
     647               0 :   nsresult res = NS_OK;
     648                 : 
     649                 :   // first process the children
     650               0 :   nsCOMPtr<nsIDOMNode> child, tmp;
     651               0 :   aNode->GetFirstChild(getter_AddRefs(child));
     652               0 :   while (child)
     653                 :   {
     654                 :     // cache next sibling since we might remove child
     655               0 :     child->GetNextSibling(getter_AddRefs(tmp));
     656               0 :     res = RemoveStyleInside(child, aProperty, aAttribute);
     657               0 :     NS_ENSURE_SUCCESS(res, res);
     658               0 :     child = tmp;
     659                 :   }
     660                 : 
     661                 :   // then process the node itself
     662               0 :   if ((!aChildrenOnly &&
     663               0 :         ((aProperty && NodeIsType(aNode, aProperty)) || // node is prop we asked for
     664               0 :         (aProperty == nsEditProperty::href && nsHTMLEditUtils::IsLink(aNode)) || // but check for link (<a href=...)
     665               0 :         (aProperty == nsEditProperty::name && nsHTMLEditUtils::IsNamedAnchor(aNode)))) || // and for named anchors
     666               0 :         (!aProperty && NodeIsProperty(aNode)))  // or node is any prop and we asked for that
     667                 :   {
     668                 :     // if we weren't passed an attribute, then we want to 
     669                 :     // remove any matching inlinestyles entirely
     670               0 :     if (!aAttribute || aAttribute->IsEmpty())
     671                 :     {
     672               0 :       NS_NAMED_LITERAL_STRING(styleAttr, "style");
     673               0 :       NS_NAMED_LITERAL_STRING(classAttr, "class");
     674               0 :       bool hasStyleAttr = HasAttr(aNode, &styleAttr);
     675               0 :       bool hasClassAtrr = HasAttr(aNode, &classAttr);
     676               0 :       if (aProperty &&
     677                 :           (hasStyleAttr || hasClassAtrr)) {
     678                 :         // aNode carries inline styles or a class attribute so we can't
     679                 :         // just remove the element... We need to create above the element
     680                 :         // a span that will carry those styles or class, then we can delete
     681                 :         // the node.
     682               0 :         nsCOMPtr<nsIDOMNode> spanNode;
     683                 :         res = InsertContainerAbove(aNode, address_of(spanNode),
     684               0 :                                    NS_LITERAL_STRING("span"));
     685               0 :         NS_ENSURE_SUCCESS(res, res);
     686               0 :         res = CloneAttribute(styleAttr, spanNode, aNode);
     687               0 :         NS_ENSURE_SUCCESS(res, res);
     688               0 :         res = CloneAttribute(classAttr, spanNode, aNode);
     689               0 :         NS_ENSURE_SUCCESS(res, res);
     690               0 :         if (hasStyleAttr)
     691                 :         {
     692                 :           // we need to remove the styles property corresponding to
     693                 :           // aProperty (bug 215406)
     694               0 :           nsAutoString propertyValue;
     695                 :           mHTMLCSSUtils->RemoveCSSEquivalentToHTMLStyle(spanNode,
     696                 :                                                         aProperty,
     697                 :                                                         aAttribute,
     698                 :                                                         &propertyValue,
     699               0 :                                                         false);
     700                 :           // remove the span if it's useless
     701               0 :           RemoveElementIfNoStyleOrIdOrClass(spanNode);
     702                 :         }
     703                 :       }
     704               0 :       res = RemoveContainer(aNode);
     705                 :     }
     706                 :     // otherwise we just want to eliminate the attribute
     707                 :     else
     708                 :     {
     709               0 :       if (HasAttr(aNode, aAttribute))
     710                 :       {
     711                 :         // if this matching attribute is the ONLY one on the node,
     712                 :         // then remove the whole node.  Otherwise just nix the attribute.
     713               0 :         if (IsOnlyAttribute(aNode, aAttribute))
     714                 :         {
     715               0 :           res = RemoveContainer(aNode);
     716                 :         }
     717                 :         else
     718                 :         {
     719               0 :           nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
     720               0 :           NS_ENSURE_TRUE(elem, NS_ERROR_NULL_POINTER);
     721               0 :           res = RemoveAttribute(elem, *aAttribute);
     722                 :         }
     723                 :       }
     724                 :     }
     725                 :   }
     726                 :   else {
     727               0 :     if (!aChildrenOnly && IsCSSEnabled() &&
     728               0 :         mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute)) {
     729                 :       // the HTML style defined by aProperty/aAttribute has a CSS equivalence
     730                 :       // in this implementation for the node aNode; let's check if it carries those css styles
     731               0 :       nsAutoString propertyValue;
     732                 :       bool isSet;
     733                 :       mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(aNode, aProperty, aAttribute,
     734                 :                                                          isSet, propertyValue,
     735               0 :                                                          SPECIFIED_STYLE_TYPE);
     736               0 :       if (isSet) {
     737                 :         // yes, tmp has the corresponding css declarations in its style attribute
     738                 :         // let's remove them
     739                 :         mHTMLCSSUtils->RemoveCSSEquivalentToHTMLStyle(aNode,
     740                 :                                                       aProperty,
     741                 :                                                       aAttribute,
     742                 :                                                       &propertyValue,
     743               0 :                                                       false);
     744                 :         // remove the node if it is a span, if its style attribute is empty or absent,
     745                 :         // and if it does not have a class nor an id
     746               0 :         RemoveElementIfNoStyleOrIdOrClass(aNode);
     747               0 :         res = NS_OK;
     748                 :       }
     749                 :     }
     750                 :   }  
     751               0 :   if ( aProperty == nsEditProperty::font &&    // or node is big or small and we are setting font size
     752               0 :        (nsHTMLEditUtils::IsBig(aNode) || nsHTMLEditUtils::IsSmall(aNode)) &&
     753               0 :        aAttribute && aAttribute->LowerCaseEqualsLiteral("size"))       
     754                 :   {
     755               0 :     res = RemoveContainer(aNode);  // if we are setting font size, remove any nested bigs and smalls
     756                 :   }
     757               0 :   return res;
     758                 : }
     759                 : 
     760               0 : bool nsHTMLEditor::IsOnlyAttribute(nsIDOMNode *aNode, 
     761                 :                                      const nsAString *aAttribute)
     762                 : {
     763               0 :   NS_ENSURE_TRUE(aNode && aAttribute, false);  // ooops
     764               0 :   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
     765               0 :   NS_ENSURE_TRUE(content, false);  // ooops
     766                 :   
     767               0 :   PRUint32 i, attrCount = content->GetAttrCount();
     768               0 :   for (i = 0; i < attrCount; ++i) {
     769               0 :     nsAutoString attrString;
     770               0 :     const nsAttrName* name = content->GetAttrNameAt(i);
     771               0 :     if (!name->NamespaceEquals(kNameSpaceID_None)) {
     772               0 :       return false;
     773                 :     }
     774               0 :     name->LocalName()->ToString(attrString);
     775                 :     // if it's the attribute we know about, or a special _moz attribute,
     776                 :     // keep looking
     777               0 :     if (!attrString.Equals(*aAttribute, nsCaseInsensitiveStringComparator()) &&
     778               0 :         !StringBeginsWith(attrString, NS_LITERAL_STRING("_moz"))) {
     779               0 :       return false;
     780                 :     }
     781                 :   }
     782                 :   // if we made it through all of them without finding a real attribute
     783                 :   // other than aAttribute, then return true
     784               0 :   return true;
     785                 : }
     786                 : 
     787               0 : bool nsHTMLEditor::HasAttr(nsIDOMNode* aNode,
     788                 :                            const nsAString* aAttribute)
     789                 : {
     790               0 :   NS_ENSURE_TRUE(aNode, false);
     791               0 :   if (!aAttribute || aAttribute->IsEmpty()) {
     792                 :     // everybody has the 'null' attribute
     793               0 :     return true;
     794                 :   }
     795                 : 
     796                 :   // get element
     797               0 :   nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
     798               0 :   NS_ENSURE_TRUE(element, false);
     799                 : 
     800               0 :   nsCOMPtr<nsIAtom> atom = do_GetAtom(*aAttribute);
     801               0 :   NS_ENSURE_TRUE(atom, false);
     802                 : 
     803               0 :   return element->HasAttr(kNameSpaceID_None, atom);
     804                 : }
     805                 : 
     806                 : 
     807               0 : bool nsHTMLEditor::HasAttrVal(nsIDOMNode* aNode,
     808                 :                               const nsAString* aAttribute,
     809                 :                               const nsAString* aValue)
     810                 : {
     811               0 :   NS_ENSURE_TRUE(aNode, false);
     812               0 :   if (!aAttribute || aAttribute->IsEmpty()) {
     813                 :     // everybody has the 'null' attribute
     814               0 :     return true;
     815                 :   }
     816                 : 
     817                 :   // get element
     818               0 :   nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
     819               0 :   NS_ENSURE_TRUE(element, false);
     820                 : 
     821               0 :   nsCOMPtr<nsIAtom> atom = do_GetAtom(*aAttribute);
     822               0 :   NS_ENSURE_TRUE(atom, false);
     823                 : 
     824               0 :   return element->AttrValueIs(kNameSpaceID_None, atom, *aValue, eIgnoreCase);
     825                 : }
     826                 : 
     827               0 : nsresult nsHTMLEditor::PromoteRangeIfStartsOrEndsInNamedAnchor(nsIDOMRange *inRange)
     828                 : {
     829               0 :   NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
     830                 :   nsresult res;
     831               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode, parent, tmp;
     832                 :   PRInt32 startOffset, endOffset, tmpOffset;
     833                 :   
     834               0 :   res = inRange->GetStartContainer(getter_AddRefs(startNode));
     835               0 :   NS_ENSURE_SUCCESS(res, res);
     836               0 :   res = inRange->GetStartOffset(&startOffset);
     837               0 :   NS_ENSURE_SUCCESS(res, res);
     838               0 :   res = inRange->GetEndContainer(getter_AddRefs(endNode));
     839               0 :   NS_ENSURE_SUCCESS(res, res);
     840               0 :   res = inRange->GetEndOffset(&endOffset);
     841               0 :   NS_ENSURE_SUCCESS(res, res);
     842                 : 
     843               0 :   tmp = startNode;
     844               0 :   while ( tmp && 
     845               0 :           !nsTextEditUtils::IsBody(tmp) &&
     846               0 :           !nsHTMLEditUtils::IsNamedAnchor(tmp))
     847                 :   {
     848               0 :     res = GetNodeLocation(tmp, address_of(parent), &tmpOffset);
     849               0 :     NS_ENSURE_SUCCESS(res, res);
     850               0 :     tmp = parent;
     851                 :   }
     852               0 :   NS_ENSURE_TRUE(tmp, NS_ERROR_NULL_POINTER);
     853               0 :   if (nsHTMLEditUtils::IsNamedAnchor(tmp))
     854                 :   {
     855               0 :     res = GetNodeLocation(tmp, address_of(parent), &tmpOffset);
     856               0 :     NS_ENSURE_SUCCESS(res, res);
     857               0 :     startNode = parent;
     858               0 :     startOffset = tmpOffset;
     859                 :   }
     860                 : 
     861               0 :   tmp = endNode;
     862               0 :   while ( tmp && 
     863               0 :           !nsTextEditUtils::IsBody(tmp) &&
     864               0 :           !nsHTMLEditUtils::IsNamedAnchor(tmp))
     865                 :   {
     866               0 :     res = GetNodeLocation(tmp, address_of(parent), &tmpOffset);
     867               0 :     NS_ENSURE_SUCCESS(res, res);
     868               0 :     tmp = parent;
     869                 :   }
     870               0 :   NS_ENSURE_TRUE(tmp, NS_ERROR_NULL_POINTER);
     871               0 :   if (nsHTMLEditUtils::IsNamedAnchor(tmp))
     872                 :   {
     873               0 :     res = GetNodeLocation(tmp, address_of(parent), &tmpOffset);
     874               0 :     NS_ENSURE_SUCCESS(res, res);
     875               0 :     endNode = parent;
     876               0 :     endOffset = tmpOffset + 1;
     877                 :   }
     878                 : 
     879               0 :   res = inRange->SetStart(startNode, startOffset);
     880               0 :   NS_ENSURE_SUCCESS(res, res);
     881               0 :   res = inRange->SetEnd(endNode, endOffset);
     882               0 :   return res;
     883                 : }
     884                 : 
     885               0 : nsresult nsHTMLEditor::PromoteInlineRange(nsIDOMRange *inRange)
     886                 : {
     887               0 :   NS_ENSURE_TRUE(inRange, NS_ERROR_NULL_POINTER);
     888                 :   nsresult res;
     889               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode, parent;
     890                 :   PRInt32 startOffset, endOffset;
     891                 :   
     892               0 :   res = inRange->GetStartContainer(getter_AddRefs(startNode));
     893               0 :   NS_ENSURE_SUCCESS(res, res);
     894               0 :   res = inRange->GetStartOffset(&startOffset);
     895               0 :   NS_ENSURE_SUCCESS(res, res);
     896               0 :   res = inRange->GetEndContainer(getter_AddRefs(endNode));
     897               0 :   NS_ENSURE_SUCCESS(res, res);
     898               0 :   res = inRange->GetEndOffset(&endOffset);
     899               0 :   NS_ENSURE_SUCCESS(res, res);
     900                 :   
     901               0 :   while ( startNode && 
     902               0 :           !nsTextEditUtils::IsBody(startNode) && 
     903               0 :           IsEditable(startNode) &&
     904               0 :           IsAtFrontOfNode(startNode, startOffset) )
     905                 :   {
     906               0 :     res = GetNodeLocation(startNode, address_of(parent), &startOffset);
     907               0 :     NS_ENSURE_SUCCESS(res, res);
     908               0 :     startNode = parent;
     909                 :   }
     910               0 :   NS_ENSURE_TRUE(startNode, NS_ERROR_NULL_POINTER);
     911                 :   
     912               0 :   while ( endNode && 
     913               0 :           !nsTextEditUtils::IsBody(endNode) && 
     914               0 :           IsEditable(endNode) &&
     915               0 :           IsAtEndOfNode(endNode, endOffset) )
     916                 :   {
     917               0 :     res = GetNodeLocation(endNode, address_of(parent), &endOffset);
     918               0 :     NS_ENSURE_SUCCESS(res, res);
     919               0 :     endNode = parent;
     920               0 :     endOffset++;  // we are AFTER this node
     921                 :   }
     922               0 :   NS_ENSURE_TRUE(endNode, NS_ERROR_NULL_POINTER);
     923                 :   
     924               0 :   res = inRange->SetStart(startNode, startOffset);
     925               0 :   NS_ENSURE_SUCCESS(res, res);
     926               0 :   res = inRange->SetEnd(endNode, endOffset);
     927               0 :   return res;
     928                 : }
     929                 : 
     930               0 : bool nsHTMLEditor::IsAtFrontOfNode(nsIDOMNode *aNode, PRInt32 aOffset)
     931                 : {
     932               0 :   NS_ENSURE_TRUE(aNode, false);  // oops
     933               0 :   if (!aOffset) {
     934               0 :     return true;
     935                 :   }
     936                 : 
     937               0 :   if (IsTextNode(aNode))
     938                 :   {
     939               0 :     return false;
     940                 :   }
     941                 :   else
     942                 :   {
     943               0 :     nsCOMPtr<nsIDOMNode> firstNode;
     944               0 :     GetFirstEditableChild(aNode, address_of(firstNode));
     945               0 :     NS_ENSURE_TRUE(firstNode, true); 
     946                 :     PRInt32 offset;
     947               0 :     nsEditor::GetChildOffset(firstNode, aNode, offset);
     948               0 :     if (offset < aOffset) return false;
     949               0 :     return true;
     950                 :   }
     951                 : }
     952                 : 
     953               0 : bool nsHTMLEditor::IsAtEndOfNode(nsIDOMNode *aNode, PRInt32 aOffset)
     954                 : {
     955               0 :   NS_ENSURE_TRUE(aNode, false);  // oops
     956                 :   PRUint32 len;
     957               0 :   GetLengthOfDOMNode(aNode, len);
     958               0 :   if (aOffset == (PRInt32)len) return true;
     959                 :   
     960               0 :   if (IsTextNode(aNode))
     961                 :   {
     962               0 :     return false;
     963                 :   }
     964                 :   else
     965                 :   {
     966               0 :     nsCOMPtr<nsIDOMNode> lastNode;
     967               0 :     GetLastEditableChild(aNode, address_of(lastNode));
     968               0 :     NS_ENSURE_TRUE(lastNode, true); 
     969                 :     PRInt32 offset;
     970               0 :     nsEditor::GetChildOffset(lastNode, aNode, offset);
     971               0 :     if (offset < aOffset) return true;
     972               0 :     return false;
     973                 :   }
     974                 : }
     975                 : 
     976                 : 
     977                 : nsresult
     978               0 : nsHTMLEditor::GetInlinePropertyBase(nsIAtom *aProperty, 
     979                 :                              const nsAString *aAttribute,
     980                 :                              const nsAString *aValue,
     981                 :                              bool *aFirst, 
     982                 :                              bool *aAny, 
     983                 :                              bool *aAll,
     984                 :                              nsAString *outValue,
     985                 :                              bool aCheckDefaults)
     986                 : {
     987               0 :   NS_ENSURE_TRUE(aProperty, NS_ERROR_NULL_POINTER);
     988                 : 
     989                 :   nsresult result;
     990               0 :   *aAny=false;
     991               0 :   *aAll=true;
     992               0 :   *aFirst=false;
     993               0 :   bool first=true;
     994                 : 
     995               0 :   bool useCSS = IsCSSEnabled();
     996                 : 
     997               0 :   nsCOMPtr<nsISelection>selection;
     998               0 :   result = GetSelection(getter_AddRefs(selection));
     999               0 :   NS_ENSURE_SUCCESS(result, result);
    1000               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1001               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    1002                 : 
    1003                 :   bool isCollapsed;
    1004               0 :   selection->GetIsCollapsed(&isCollapsed);
    1005               0 :   nsCOMPtr<nsIDOMNode> collapsedNode;
    1006               0 :   nsCOMPtr<nsIEnumerator> enumerator;
    1007               0 :   result = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    1008               0 :   NS_ENSURE_SUCCESS(result, result);
    1009               0 :   NS_ENSURE_TRUE(enumerator, NS_ERROR_NULL_POINTER);
    1010                 : 
    1011               0 :   enumerator->First(); 
    1012               0 :   nsCOMPtr<nsISupports> currentItem;
    1013               0 :   result = enumerator->CurrentItem(getter_AddRefs(currentItem));
    1014                 :   // XXX: should be a while loop, to get each separate range
    1015                 :   // XXX: ERROR_HANDLING can currentItem be null?
    1016               0 :   if ((NS_SUCCEEDED(result)) && currentItem)
    1017                 :   {
    1018               0 :     bool firstNodeInRange = true; // for each range, set a flag 
    1019               0 :     nsCOMPtr<nsIDOMRange> range(do_QueryInterface(currentItem));
    1020                 : 
    1021               0 :     if (isCollapsed)
    1022                 :     {
    1023               0 :       range->GetStartContainer(getter_AddRefs(collapsedNode));
    1024               0 :       NS_ENSURE_TRUE(collapsedNode, NS_ERROR_FAILURE);
    1025                 :       bool isSet, theSetting;
    1026               0 :       if (aAttribute)
    1027                 :       {
    1028               0 :         nsString tString(*aAttribute); //MJUDGE SCC NEED HELP
    1029               0 :         nsString tOutString;//MJUDGE SCC NEED HELP
    1030               0 :         mTypeInState->GetTypingState(isSet, theSetting, aProperty, tString, &tOutString);
    1031               0 :         if (outValue)
    1032               0 :           outValue->Assign(tOutString);
    1033                 :       }
    1034                 :       else
    1035               0 :         mTypeInState->GetTypingState(isSet, theSetting, aProperty);
    1036               0 :       if (isSet)
    1037                 :       {
    1038               0 :         *aFirst = *aAny = *aAll = theSetting;
    1039               0 :         return NS_OK;
    1040                 :       }
    1041               0 :       if (!useCSS) {
    1042               0 :         nsCOMPtr<nsIDOMNode> resultNode;
    1043                 :         IsTextPropertySetByContent(collapsedNode, aProperty, aAttribute, aValue,
    1044               0 :                                    isSet, getter_AddRefs(resultNode), outValue);
    1045               0 :         *aFirst = *aAny = *aAll = isSet;
    1046                 : 
    1047               0 :         if (!isSet && aCheckDefaults) 
    1048                 :         {
    1049                 :           // style not set, but if it is a default then it will appear if 
    1050                 :           // content is inserted, so we should report it as set (analogous to TypeInState).
    1051                 :           PRInt32 index;
    1052               0 :           if (aAttribute &&
    1053               0 :               TypeInState::FindPropInList(aProperty, *aAttribute, outValue, mDefaultStyles, index))
    1054                 :           {
    1055               0 :             *aFirst = *aAny = *aAll = true;
    1056               0 :             if (outValue)
    1057               0 :               outValue->Assign(mDefaultStyles[index]->value);
    1058                 :           }
    1059                 :         }
    1060               0 :         return NS_OK;
    1061                 :       }
    1062                 :     }
    1063                 : 
    1064                 :     // non-collapsed selection
    1065                 :     nsCOMPtr<nsIContentIterator> iter =
    1066               0 :             do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
    1067               0 :     NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER);
    1068                 : 
    1069               0 :     iter->Init(range);
    1070               0 :     nsAutoString firstValue, theValue;
    1071                 : 
    1072               0 :     nsCOMPtr<nsIDOMNode> endNode;
    1073                 :     PRInt32 endOffset;
    1074               0 :     result = range->GetEndContainer(getter_AddRefs(endNode));
    1075               0 :     NS_ENSURE_SUCCESS(result, result);
    1076               0 :     result = range->GetEndOffset(&endOffset);
    1077               0 :     NS_ENSURE_SUCCESS(result, result);
    1078               0 :     while (!iter->IsDone())
    1079                 :     {
    1080               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(iter->GetCurrentNode());
    1081                 : 
    1082               0 :       nsCOMPtr<nsIDOMNode> node = do_QueryInterface(content);
    1083                 : 
    1084               0 :       if (node && nsTextEditUtils::IsBody(node))
    1085                 :         break;
    1086                 : 
    1087               0 :       nsCOMPtr<nsIDOMCharacterData>text;
    1088               0 :       text = do_QueryInterface(content);
    1089                 :       
    1090               0 :       bool skipNode = false;
    1091                 :       
    1092                 :       // just ignore any non-editable nodes
    1093               0 :       if (text && !IsEditable(text))
    1094                 :       {
    1095               0 :         skipNode = true;
    1096                 :       }
    1097               0 :       else if (text)
    1098                 :       {
    1099               0 :         if (!isCollapsed && first && firstNodeInRange)
    1100                 :         {
    1101               0 :           firstNodeInRange = false;
    1102                 :           PRInt32 startOffset;
    1103               0 :           range->GetStartOffset(&startOffset);
    1104                 :           PRUint32 count;
    1105               0 :           text->GetLength(&count);
    1106               0 :           if (startOffset==(PRInt32)count) 
    1107                 :           {
    1108               0 :             skipNode = true;
    1109               0 :           }
    1110                 :         }
    1111               0 :         else if (node == endNode && !endOffset)
    1112                 :         {
    1113               0 :           skipNode = true;
    1114                 :         }
    1115                 :       }
    1116               0 :       else if (content->IsElement())
    1117                 :       { // handle non-text leaf nodes here
    1118               0 :         skipNode = true;
    1119                 :       }
    1120               0 :       if (!skipNode)
    1121                 :       {
    1122               0 :         if (node)
    1123                 :         {
    1124               0 :           bool isSet = false;
    1125               0 :           nsCOMPtr<nsIDOMNode>resultNode;
    1126               0 :           if (first)
    1127                 :           {
    1128               0 :             if (useCSS &&
    1129               0 :                 mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
    1130                 :               // the HTML styles defined by aProperty/aAttribute has a CSS equivalence
    1131                 :               // in this implementation for node; let's check if it carries those css styles
    1132               0 :               if (aValue) firstValue.Assign(*aValue);
    1133                 :               mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, aAttribute,
    1134                 :                                                                  isSet, firstValue,
    1135               0 :                                                                  COMPUTED_STYLE_TYPE);
    1136                 :             }
    1137                 :             else {
    1138                 :               IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet,
    1139               0 :                                          getter_AddRefs(resultNode), &firstValue);
    1140                 :             }
    1141               0 :             *aFirst = isSet;
    1142               0 :             first = false;
    1143               0 :             if (outValue) *outValue = firstValue;
    1144                 :           }
    1145                 :           else
    1146                 :           {
    1147               0 :             if (useCSS &&
    1148               0 :                 mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
    1149                 :               // the HTML styles defined by aProperty/aAttribute has a CSS equivalence
    1150                 :               // in this implementation for node; let's check if it carries those css styles
    1151               0 :               if (aValue) theValue.Assign(*aValue);
    1152                 :               mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, aAttribute,
    1153                 :                                                                  isSet, theValue,
    1154               0 :                                                                  COMPUTED_STYLE_TYPE);
    1155                 :             }
    1156                 :             else {
    1157                 :               IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet,
    1158               0 :                                          getter_AddRefs(resultNode), &theValue);
    1159                 :             }
    1160               0 :             if (firstValue != theValue)
    1161               0 :               *aAll = false;
    1162                 :           }
    1163                 :           
    1164               0 :           if (isSet) {
    1165               0 :             *aAny = true;
    1166                 :           }
    1167                 :           else {
    1168               0 :             *aAll = false;
    1169                 :           }
    1170                 :         }
    1171                 :       }
    1172                 : 
    1173               0 :       iter->Next();
    1174                 :     }
    1175                 :   }
    1176               0 :   if (!*aAny) 
    1177                 :   { // make sure that if none of the selection is set, we don't report all is set
    1178               0 :     *aAll = false;
    1179                 :   }
    1180               0 :   return result;
    1181                 : }
    1182                 : 
    1183                 : 
    1184               0 : NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty, 
    1185                 :                                               const nsAString &aAttribute, 
    1186                 :                                               const nsAString &aValue,
    1187                 :                                               bool *aFirst, 
    1188                 :                                               bool *aAny, 
    1189                 :                                               bool *aAll)
    1190                 : {
    1191               0 :   NS_ENSURE_TRUE(aProperty && aFirst && aAny && aAll, NS_ERROR_NULL_POINTER);
    1192               0 :   const nsAString *att = nsnull;
    1193               0 :   if (!aAttribute.IsEmpty())
    1194               0 :     att = &aAttribute;
    1195               0 :   const nsAString *val = nsnull;
    1196               0 :   if (!aValue.IsEmpty())
    1197               0 :     val = &aValue;
    1198               0 :   return GetInlinePropertyBase( aProperty, att, val, aFirst, aAny, aAll, nsnull);
    1199                 : }
    1200                 : 
    1201                 : 
    1202               0 : NS_IMETHODIMP nsHTMLEditor::GetInlinePropertyWithAttrValue(nsIAtom *aProperty, 
    1203                 :                                               const nsAString &aAttribute, 
    1204                 :                                               const nsAString &aValue,
    1205                 :                                               bool *aFirst, 
    1206                 :                                               bool *aAny, 
    1207                 :                                               bool *aAll,
    1208                 :                                               nsAString &outValue)
    1209                 : {
    1210               0 :   NS_ENSURE_TRUE(aProperty && aFirst && aAny && aAll, NS_ERROR_NULL_POINTER);
    1211               0 :   const nsAString *att = nsnull;
    1212               0 :   if (!aAttribute.IsEmpty())
    1213               0 :     att = &aAttribute;
    1214               0 :   const nsAString *val = nsnull;
    1215               0 :   if (!aValue.IsEmpty())
    1216               0 :     val = &aValue;
    1217               0 :   return GetInlinePropertyBase( aProperty, att, val, aFirst, aAny, aAll, &outValue);
    1218                 : }
    1219                 : 
    1220                 : 
    1221               0 : NS_IMETHODIMP nsHTMLEditor::RemoveAllInlineProperties()
    1222                 : {
    1223               0 :   nsAutoEditBatch batchIt(this);
    1224               0 :   nsAutoRules beginRulesSniffing(this, kOpResetTextProperties, nsIEditor::eNext);
    1225                 : 
    1226               0 :   nsresult res = RemoveInlinePropertyImpl(nsnull, nsnull);
    1227               0 :   NS_ENSURE_SUCCESS(res, res);
    1228               0 :   return ApplyDefaultProperties();
    1229                 : }
    1230                 : 
    1231               0 : NS_IMETHODIMP nsHTMLEditor::RemoveInlineProperty(nsIAtom *aProperty, const nsAString &aAttribute)
    1232                 : {
    1233               0 :   return RemoveInlinePropertyImpl(aProperty, &aAttribute);
    1234                 : }
    1235                 : 
    1236               0 : nsresult nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom *aProperty, const nsAString *aAttribute)
    1237                 : {
    1238               0 :   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
    1239               0 :   ForceCompositionEnd();
    1240                 : 
    1241                 :   nsresult res;
    1242               0 :   nsCOMPtr<nsISelection>selection;
    1243               0 :   res = GetSelection(getter_AddRefs(selection));
    1244               0 :   NS_ENSURE_SUCCESS(res, res);
    1245               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
    1246               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
    1247                 : 
    1248                 :   bool isCollapsed;
    1249               0 :   selection->GetIsCollapsed(&isCollapsed);
    1250                 : 
    1251               0 :   bool useCSS = IsCSSEnabled();
    1252               0 :   if (isCollapsed)
    1253                 :   {
    1254                 :     // manipulating text attributes on a collapsed selection only sets state for the next text insertion
    1255                 : 
    1256                 :     // For links, aProperty uses "href", use "a" instead
    1257               0 :     if (aProperty == nsEditProperty::href ||
    1258                 :         aProperty == nsEditProperty::name)
    1259               0 :       aProperty = nsEditProperty::a;
    1260                 : 
    1261               0 :     if (aProperty) return mTypeInState->ClearProp(aProperty, nsAutoString(*aAttribute));
    1262               0 :     else return mTypeInState->ClearAllProps();
    1263                 :   }
    1264               0 :   nsAutoEditBatch batchIt(this);
    1265               0 :   nsAutoRules beginRulesSniffing(this, kOpRemoveTextProperty, nsIEditor::eNext);
    1266               0 :   nsAutoSelectionReset selectionResetter(selection, this);
    1267               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(this);
    1268                 :   
    1269                 :   bool cancel, handled;
    1270               0 :   nsTextRulesInfo ruleInfo(nsTextEditRules::kRemoveTextProperty);
    1271               0 :   res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
    1272               0 :   NS_ENSURE_SUCCESS(res, res);
    1273               0 :   if (!cancel && !handled)
    1274                 :   {
    1275                 :     // get selection range enumerator
    1276               0 :     nsCOMPtr<nsIEnumerator> enumerator;
    1277               0 :     res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    1278               0 :     NS_ENSURE_SUCCESS(res, res);
    1279               0 :     NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
    1280                 : 
    1281                 :     // loop thru the ranges in the selection
    1282               0 :     enumerator->First(); 
    1283               0 :     nsCOMPtr<nsISupports> currentItem;
    1284               0 :     while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
    1285                 :     {
    1286               0 :       res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    1287               0 :       NS_ENSURE_SUCCESS(res, res);
    1288               0 :       NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
    1289                 :       
    1290               0 :       nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    1291                 : 
    1292               0 :       if (aProperty == nsEditProperty::name)
    1293                 :       {
    1294                 :         // promote range if it starts or end in a named anchor and we
    1295                 :         // want to remove named anchors
    1296               0 :         res = PromoteRangeIfStartsOrEndsInNamedAnchor(range);
    1297                 :       }
    1298                 :       else {
    1299                 :         // adjust range to include any ancestors who's children are entirely selected
    1300               0 :         res = PromoteInlineRange(range);
    1301                 :       }
    1302               0 :       NS_ENSURE_SUCCESS(res, res);
    1303                 : 
    1304                 :       // remove this style from ancestors of our range endpoints, 
    1305                 :       // splitting them as appropriate
    1306               0 :       res = SplitStyleAboveRange(range, aProperty, aAttribute);
    1307               0 :       NS_ENSURE_SUCCESS(res, res);
    1308                 : 
    1309                 :       // check for easy case: both range endpoints in same text node
    1310               0 :       nsCOMPtr<nsIDOMNode> startNode, endNode;
    1311               0 :       res = range->GetStartContainer(getter_AddRefs(startNode));
    1312               0 :       NS_ENSURE_SUCCESS(res, res);
    1313               0 :       res = range->GetEndContainer(getter_AddRefs(endNode));
    1314               0 :       NS_ENSURE_SUCCESS(res, res);
    1315               0 :       if ((startNode == endNode) && IsTextNode(startNode))
    1316                 :       {
    1317                 :         // we're done with this range!
    1318               0 :         if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(startNode, aProperty, aAttribute)) {
    1319                 :           // the HTML style defined by aProperty/aAttribute has a CSS equivalence
    1320                 :           // in this implementation for startNode
    1321               0 :           nsAutoString cssValue;
    1322               0 :           bool isSet = false;
    1323                 :           mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(startNode,
    1324                 :                                                     aProperty,
    1325                 :                                                     aAttribute,
    1326                 :                                                     isSet ,
    1327                 :                                                     cssValue,
    1328               0 :                                                     COMPUTED_STYLE_TYPE);
    1329               0 :           if (isSet) {
    1330                 :             // startNode's computed style indicates the CSS equivalence to the HTML style to
    1331                 :             // remove is applied; but we found no element in the ancestors of startNode
    1332                 :             // carrying specified styles; assume it comes from a rule and let's try to
    1333                 :             // insert a span "inverting" the style
    1334               0 :             nsAutoString value; value.AssignLiteral("-moz-editor-invert-value");
    1335                 :             PRInt32 startOffset, endOffset;
    1336               0 :             range->GetStartOffset(&startOffset);
    1337               0 :             range->GetEndOffset(&endOffset);
    1338               0 :             nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
    1339               0 :             if (mHTMLCSSUtils->IsCSSInvertable(aProperty, aAttribute)) {
    1340               0 :               SetInlinePropertyOnTextNode(nodeAsText, startOffset, endOffset, aProperty, aAttribute, &value);
    1341                 :             }
    1342                 :           }
    1343                 :         }
    1344                 :       }
    1345                 :       else
    1346                 :       {
    1347                 :         // not the easy case.  range not contained in single text node. 
    1348                 :         nsCOMPtr<nsIContentIterator> iter =
    1349               0 :           do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
    1350               0 :         NS_ENSURE_SUCCESS(res, res);
    1351               0 :         NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
    1352                 : 
    1353               0 :         nsCOMArray<nsIDOMNode> arrayOfNodes;
    1354               0 :         nsCOMPtr<nsIDOMNode> node;
    1355                 :         
    1356                 :         // iterate range and build up array
    1357               0 :         iter->Init(range);
    1358               0 :         while (!iter->IsDone())
    1359                 :         {
    1360               0 :           node = do_QueryInterface(iter->GetCurrentNode());
    1361               0 :           NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    1362                 : 
    1363               0 :           if (IsEditable(node))
    1364                 :           { 
    1365               0 :             arrayOfNodes.AppendObject(node);
    1366                 :           }
    1367                 : 
    1368               0 :           iter->Next();
    1369                 :         }
    1370                 :         
    1371                 :         // loop through the list, remove the property on each node
    1372               0 :         PRInt32 listCount = arrayOfNodes.Count();
    1373                 :         PRInt32 j;
    1374               0 :         for (j = 0; j < listCount; j++)
    1375                 :         {
    1376               0 :           node = arrayOfNodes[j];
    1377               0 :           res = RemoveStyleInside(node, aProperty, aAttribute);
    1378               0 :           NS_ENSURE_SUCCESS(res, res);
    1379               0 :           if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
    1380                 :             // the HTML style defined by aProperty/aAttribute has a CSS equivalence
    1381                 :             // in this implementation for node
    1382               0 :             nsAutoString cssValue;
    1383               0 :             bool isSet = false;
    1384                 :             mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node,
    1385                 :                                                                aProperty,
    1386                 :                                                                aAttribute,
    1387                 :                                                                isSet ,
    1388                 :                                                                cssValue,
    1389               0 :                                                                COMPUTED_STYLE_TYPE);
    1390               0 :             if (isSet) {
    1391                 :               // startNode's computed style indicates the CSS equivalence to the HTML style to
    1392                 :               // remove is applied; but we found no element in the ancestors of startNode
    1393                 :               // carrying specified styles; assume it comes from a rule and let's try to
    1394                 :               // insert a span "inverting" the style
    1395               0 :               if (mHTMLCSSUtils->IsCSSInvertable(aProperty, aAttribute)) {
    1396               0 :                 nsAutoString value; value.AssignLiteral("-moz-editor-invert-value");
    1397               0 :                 SetInlinePropertyOnNode(node, aProperty, aAttribute, &value);
    1398                 :               }
    1399                 :             }
    1400                 :           }
    1401                 :         }
    1402               0 :         arrayOfNodes.Clear();
    1403                 :       }
    1404               0 :       enumerator->Next();
    1405                 :     }
    1406                 :   }
    1407               0 :   if (!cancel)
    1408                 :   {
    1409                 :     // post-process 
    1410               0 :     res = mRules->DidDoAction(selection, &ruleInfo, res);
    1411                 :   }
    1412               0 :   return res;
    1413                 : }
    1414                 : 
    1415               0 : NS_IMETHODIMP nsHTMLEditor::IncreaseFontSize()
    1416                 : {
    1417               0 :   return RelativeFontChange(1);
    1418                 : }
    1419                 : 
    1420               0 : NS_IMETHODIMP nsHTMLEditor::DecreaseFontSize()
    1421                 : {
    1422               0 :   return RelativeFontChange(-1);
    1423                 : }
    1424                 : 
    1425                 : nsresult
    1426               0 : nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange)
    1427                 : {
    1428                 :   // Can only change font size by + or - 1
    1429               0 :   if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
    1430               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1431                 :   
    1432               0 :   ForceCompositionEnd();
    1433                 : 
    1434                 :   // Get the selection 
    1435               0 :   nsCOMPtr<nsISelection>selection;
    1436               0 :   nsresult res = GetSelection(getter_AddRefs(selection));
    1437               0 :   NS_ENSURE_SUCCESS(res, res);
    1438               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
    1439               0 :   nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));  
    1440                 :   // Is the selection collapsed?
    1441                 :   bool bCollapsed;
    1442               0 :   res = selection->GetIsCollapsed(&bCollapsed);
    1443               0 :   NS_ENSURE_SUCCESS(res, res);
    1444                 :   
    1445                 :   // if it's collapsed set typing state
    1446               0 :   if (bCollapsed)
    1447                 :   {
    1448               0 :     nsCOMPtr<nsIAtom> atom;
    1449               0 :     if (aSizeChange==1) atom = nsEditProperty::big;
    1450               0 :     else                atom = nsEditProperty::small;
    1451                 : 
    1452                 :     // Let's see in what kind of element the selection is
    1453                 :     PRInt32 offset;
    1454               0 :     nsCOMPtr<nsIDOMNode> selectedNode;
    1455               0 :     res = GetStartNodeAndOffset(selection, getter_AddRefs(selectedNode), &offset);
    1456               0 :     if (IsTextNode(selectedNode)) {
    1457               0 :       nsCOMPtr<nsIDOMNode> parent;
    1458               0 :       res = selectedNode->GetParentNode(getter_AddRefs(parent));
    1459               0 :       NS_ENSURE_SUCCESS(res, res);
    1460               0 :       selectedNode = parent;
    1461                 :     }
    1462               0 :     nsAutoString tag;
    1463               0 :     atom->ToString(tag);
    1464               0 :     if (!CanContainTag(selectedNode, tag)) return NS_OK;
    1465                 : 
    1466                 :     // manipulating text attributes on a collapsed selection only sets state for the next text insertion
    1467               0 :     return mTypeInState->SetProp(atom, EmptyString(), EmptyString());
    1468                 :   }
    1469                 :   
    1470                 :   // wrap with txn batching, rules sniffing, and selection preservation code
    1471               0 :   nsAutoEditBatch batchIt(this);
    1472               0 :   nsAutoRules beginRulesSniffing(this, kOpSetTextProperty, nsIEditor::eNext);
    1473               0 :   nsAutoSelectionReset selectionResetter(selection, this);
    1474               0 :   nsAutoTxnsConserveSelection dontSpazMySelection(this);
    1475                 : 
    1476                 :   // get selection range enumerator
    1477               0 :   nsCOMPtr<nsIEnumerator> enumerator;
    1478               0 :   res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
    1479               0 :   NS_ENSURE_SUCCESS(res, res);
    1480               0 :   NS_ENSURE_TRUE(enumerator, NS_ERROR_FAILURE);
    1481                 : 
    1482                 :   // loop thru the ranges in the selection
    1483               0 :   enumerator->First(); 
    1484               0 :   nsCOMPtr<nsISupports> currentItem;
    1485               0 :   while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
    1486                 :   {
    1487               0 :     res = enumerator->CurrentItem(getter_AddRefs(currentItem));
    1488               0 :     NS_ENSURE_SUCCESS(res, res);
    1489               0 :     NS_ENSURE_TRUE(currentItem, NS_ERROR_FAILURE);
    1490                 :     
    1491               0 :     nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
    1492                 : 
    1493                 :     // adjust range to include any ancestors who's children are entirely selected
    1494               0 :     res = PromoteInlineRange(range);
    1495               0 :     NS_ENSURE_SUCCESS(res, res);
    1496                 :     
    1497                 :     // check for easy case: both range endpoints in same text node
    1498               0 :     nsCOMPtr<nsIDOMNode> startNode, endNode;
    1499               0 :     res = range->GetStartContainer(getter_AddRefs(startNode));
    1500               0 :     NS_ENSURE_SUCCESS(res, res);
    1501               0 :     res = range->GetEndContainer(getter_AddRefs(endNode));
    1502               0 :     NS_ENSURE_SUCCESS(res, res);
    1503               0 :     if ((startNode == endNode) && IsTextNode(startNode))
    1504                 :     {
    1505                 :       PRInt32 startOffset, endOffset;
    1506               0 :       range->GetStartOffset(&startOffset);
    1507               0 :       range->GetEndOffset(&endOffset);
    1508               0 :       nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
    1509               0 :       res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, endOffset);
    1510               0 :       NS_ENSURE_SUCCESS(res, res);
    1511                 :     }
    1512                 :     else
    1513                 :     {
    1514                 :       // not the easy case.  range not contained in single text node. 
    1515                 :       // there are up to three phases here.  There are all the nodes
    1516                 :       // reported by the subtree iterator to be processed.  And there
    1517                 :       // are potentially a starting textnode and an ending textnode
    1518                 :       // which are only partially contained by the range.
    1519                 :       
    1520                 :       // lets handle the nodes reported by the iterator.  These nodes
    1521                 :       // are entirely contained in the selection range.  We build up
    1522                 :       // a list of them (since doing operations on the document during
    1523                 :       // iteration would perturb the iterator).
    1524                 : 
    1525                 :       nsCOMPtr<nsIContentIterator> iter =
    1526               0 :         do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res);
    1527               0 :       NS_ENSURE_SUCCESS(res, res);
    1528               0 :       NS_ENSURE_TRUE(iter, NS_ERROR_FAILURE);
    1529                 : 
    1530               0 :       nsCOMArray<nsIDOMNode> arrayOfNodes;
    1531               0 :       nsCOMPtr<nsIDOMNode> node;
    1532                 :       
    1533                 :       // iterate range and build up array
    1534               0 :       res = iter->Init(range);
    1535               0 :       if (NS_SUCCEEDED(res))
    1536                 :       {
    1537               0 :         while (!iter->IsDone())
    1538                 :         {
    1539               0 :           node = do_QueryInterface(iter->GetCurrentNode());
    1540               0 :           NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
    1541                 : 
    1542               0 :           if (IsEditable(node))
    1543                 :           { 
    1544               0 :             arrayOfNodes.AppendObject(node);
    1545                 :           }
    1546                 : 
    1547               0 :           iter->Next();
    1548                 :         }
    1549                 :         
    1550                 :         // now that we have the list, do the font size change on each node
    1551               0 :         PRInt32 listCount = arrayOfNodes.Count();
    1552                 :         PRInt32 j;
    1553               0 :         for (j = 0; j < listCount; j++)
    1554                 :         {
    1555               0 :           node = arrayOfNodes[j];
    1556               0 :           res = RelativeFontChangeOnNode(aSizeChange, node);
    1557               0 :           NS_ENSURE_SUCCESS(res, res);
    1558                 :         }
    1559               0 :         arrayOfNodes.Clear();
    1560                 :       }
    1561                 :       // now check the start and end parents of the range to see if they need to 
    1562                 :       // be separately handled (they do if they are text nodes, due to how the
    1563                 :       // subtree iterator works - it will not have reported them).
    1564               0 :       if (IsTextNode(startNode) && IsEditable(startNode))
    1565                 :       {
    1566               0 :         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
    1567                 :         PRInt32 startOffset;
    1568                 :         PRUint32 textLen;
    1569               0 :         range->GetStartOffset(&startOffset);
    1570               0 :         nodeAsText->GetLength(&textLen);
    1571               0 :         res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, startOffset, textLen);
    1572               0 :         NS_ENSURE_SUCCESS(res, res);
    1573                 :       }
    1574               0 :       if (IsTextNode(endNode) && IsEditable(endNode))
    1575                 :       {
    1576               0 :         nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(endNode);
    1577                 :         PRInt32 endOffset;
    1578               0 :         range->GetEndOffset(&endOffset);
    1579               0 :         res = RelativeFontChangeOnTextNode(aSizeChange, nodeAsText, 0, endOffset);
    1580               0 :         NS_ENSURE_SUCCESS(res, res);
    1581                 :       }
    1582                 :     }
    1583               0 :     enumerator->Next();
    1584                 :   }
    1585                 :   
    1586               0 :   return res;  
    1587                 : }
    1588                 : 
    1589                 : nsresult
    1590               0 : nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange, 
    1591                 :                                             nsIDOMCharacterData *aTextNode, 
    1592                 :                                             PRInt32 aStartOffset,
    1593                 :                                             PRInt32 aEndOffset)
    1594                 : {
    1595                 :   // Can only change font size by + or - 1
    1596               0 :   if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
    1597               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1598               0 :   NS_ENSURE_TRUE(aTextNode, NS_ERROR_NULL_POINTER);
    1599                 :   
    1600                 :   // don't need to do anything if no characters actually selected
    1601               0 :   if (aStartOffset == aEndOffset) return NS_OK;
    1602                 :   
    1603               0 :   nsresult res = NS_OK;
    1604               0 :   nsCOMPtr<nsIDOMNode> parent;
    1605               0 :   res = aTextNode->GetParentNode(getter_AddRefs(parent));
    1606               0 :   NS_ENSURE_SUCCESS(res, res);
    1607               0 :   if (!CanContainTag(parent, NS_LITERAL_STRING("big"))) return NS_OK;
    1608                 : 
    1609               0 :   nsCOMPtr<nsIDOMNode> tmp, node = do_QueryInterface(aTextNode);
    1610                 : 
    1611                 :   // do we need to split the text node?
    1612                 :   PRUint32 textLen;
    1613               0 :   aTextNode->GetLength(&textLen);
    1614                 :   
    1615                 :   // -1 is a magic value meaning to the end of node
    1616               0 :   if (aEndOffset == -1) aEndOffset = textLen;
    1617                 :   
    1618               0 :   if ( (PRUint32)aEndOffset != textLen )
    1619                 :   {
    1620                 :     // we need to split off back of text node
    1621               0 :     res = SplitNode(node, aEndOffset, getter_AddRefs(tmp));
    1622               0 :     NS_ENSURE_SUCCESS(res, res);
    1623               0 :     node = tmp;  // remember left node
    1624                 :   }
    1625               0 :   if ( aStartOffset )
    1626                 :   {
    1627                 :     // we need to split off front of text node
    1628               0 :     res = SplitNode(node, aStartOffset, getter_AddRefs(tmp));
    1629               0 :     NS_ENSURE_SUCCESS(res, res);
    1630                 :   }
    1631                 : 
    1632               0 :   NS_NAMED_LITERAL_STRING(bigSize, "big");
    1633               0 :   NS_NAMED_LITERAL_STRING(smallSize, "small");
    1634               0 :   const nsAString& nodeType = (aSizeChange==1) ? static_cast<const nsAString&>(bigSize) : static_cast<const nsAString&>(smallSize);
    1635                 :   // look for siblings that are correct type of node
    1636               0 :   nsCOMPtr<nsIDOMNode> sibling;
    1637               0 :   GetPriorHTMLSibling(node, address_of(sibling));
    1638               0 :   if (sibling && NodeIsType(sibling, (aSizeChange==1) ? nsEditProperty::big : nsEditProperty::small))
    1639                 :   {
    1640                 :     // previous sib is already right kind of inline node; slide this over into it
    1641               0 :     res = MoveNode(node, sibling, -1);
    1642               0 :     return res;
    1643                 :   }
    1644               0 :   sibling = nsnull;
    1645               0 :   GetNextHTMLSibling(node, address_of(sibling));
    1646               0 :   if (sibling && NodeIsType(sibling, (aSizeChange==1) ? nsEditProperty::big : nsEditProperty::small))
    1647                 :   {
    1648                 :     // following sib is already right kind of inline node; slide this over into it
    1649               0 :     res = MoveNode(node, sibling, 0);
    1650               0 :     return res;
    1651                 :   }
    1652                 :   
    1653                 :   // else reparent the node inside font node with appropriate relative size
    1654               0 :   res = InsertContainerAbove(node, address_of(tmp), nodeType);
    1655               0 :   return res;
    1656                 : }
    1657                 : 
    1658                 : 
    1659                 : nsresult
    1660               0 : nsHTMLEditor::RelativeFontChangeHelper( PRInt32 aSizeChange, 
    1661                 :                                         nsIDOMNode *aNode)
    1662                 : {
    1663                 :   /*  This routine looks for all the font nodes in the tree rooted by aNode,
    1664                 :       including aNode itself, looking for font nodes that have the size attr
    1665                 :       set.  Any such nodes need to have big or small put inside them, since
    1666                 :       they override any big/small that are above them.
    1667                 :   */
    1668                 :   
    1669                 :   // Can only change font size by + or - 1
    1670               0 :   if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
    1671               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1672               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    1673                 : 
    1674               0 :   nsresult res = NS_OK;
    1675               0 :   nsAutoString tag;
    1676               0 :   if (aSizeChange == 1) tag.AssignLiteral("big");
    1677               0 :   else tag.AssignLiteral("small");
    1678               0 :   nsCOMPtr<nsIDOMNodeList> childNodes;
    1679                 :   PRInt32 j;
    1680                 :   PRUint32 childCount;
    1681               0 :   nsCOMPtr<nsIDOMNode> childNode;
    1682                 :   
    1683                 :   // if this is a font node with size, put big/small inside it
    1684               0 :   NS_NAMED_LITERAL_STRING(attr, "size");
    1685               0 :   if (NodeIsType(aNode, nsEditProperty::font) && HasAttr(aNode, &attr))
    1686                 :   {
    1687                 :     // cycle through children and adjust relative font size
    1688               0 :     res = aNode->GetChildNodes(getter_AddRefs(childNodes));
    1689               0 :     NS_ENSURE_SUCCESS(res, res);
    1690               0 :     if (childNodes)
    1691                 :     {
    1692               0 :       childNodes->GetLength(&childCount);
    1693               0 :       for (j=childCount-1; j>=0; j--)
    1694                 :       {
    1695               0 :         res = childNodes->Item(j, getter_AddRefs(childNode));
    1696               0 :         if ((NS_SUCCEEDED(res)) && (childNode))
    1697                 :         {
    1698               0 :           res = RelativeFontChangeOnNode(aSizeChange, childNode);
    1699               0 :           NS_ENSURE_SUCCESS(res, res);
    1700                 :         }
    1701                 :       }
    1702                 :     }
    1703                 :   }
    1704                 : 
    1705               0 :   childNodes = nsnull;
    1706                 :   // now cycle through the children.
    1707               0 :   res = aNode->GetChildNodes(getter_AddRefs(childNodes));
    1708               0 :   NS_ENSURE_SUCCESS(res, res);
    1709               0 :   if (childNodes)
    1710                 :   {
    1711               0 :     childNodes->GetLength(&childCount);
    1712               0 :     for (j=childCount-1; j>=0; j--)
    1713                 :     {
    1714               0 :       res = childNodes->Item(j, getter_AddRefs(childNode));
    1715               0 :       if ((NS_SUCCEEDED(res)) && (childNode))
    1716                 :       {
    1717               0 :         res = RelativeFontChangeHelper(aSizeChange, childNode);
    1718               0 :         NS_ENSURE_SUCCESS(res, res);
    1719                 :       }
    1720                 :     }
    1721                 :   }
    1722                 : 
    1723               0 :   return res;
    1724                 : }
    1725                 : 
    1726                 : 
    1727                 : nsresult
    1728               0 : nsHTMLEditor::RelativeFontChangeOnNode( PRInt32 aSizeChange, 
    1729                 :                                         nsIDOMNode *aNode)
    1730                 : {
    1731                 :   // Can only change font size by + or - 1
    1732               0 :   if ( !( (aSizeChange==1) || (aSizeChange==-1) ) )
    1733               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1734               0 :   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
    1735                 : 
    1736               0 :   nsresult res = NS_OK;
    1737               0 :   nsCOMPtr<nsIDOMNode> tmp;
    1738               0 :   nsAutoString tag;
    1739               0 :   if (aSizeChange == 1) tag.AssignLiteral("big");
    1740               0 :   else tag.AssignLiteral("small");
    1741                 :   
    1742                 :   // is it the opposite of what we want?  
    1743               0 :   if ( ((aSizeChange == 1) && nsHTMLEditUtils::IsSmall(aNode)) || 
    1744               0 :        ((aSizeChange == -1) &&  nsHTMLEditUtils::IsBig(aNode)) )
    1745                 :   {
    1746                 :     // first populate any nested font tags that have the size attr set
    1747               0 :     res = RelativeFontChangeHelper(aSizeChange, aNode);
    1748               0 :     NS_ENSURE_SUCCESS(res, res);
    1749                 :     // in that case, just remove this node and pull up the children
    1750               0 :     res = RemoveContainer(aNode);
    1751               0 :     return res;
    1752                 :   }
    1753                 :   // can it be put inside a "big" or "small"?
    1754               0 :   if (TagCanContain(tag, aNode))
    1755                 :   {
    1756                 :     // first populate any nested font tags that have the size attr set
    1757               0 :     res = RelativeFontChangeHelper(aSizeChange, aNode);
    1758               0 :     NS_ENSURE_SUCCESS(res, res);
    1759                 :     // ok, chuck it in.
    1760                 :     // first look at siblings of aNode for matching bigs or smalls.
    1761                 :     // if we find one, move aNode into it.
    1762               0 :     nsCOMPtr<nsIDOMNode> sibling;
    1763               0 :     GetPriorHTMLSibling(aNode, address_of(sibling));
    1764               0 :     if (sibling && nsEditor::NodeIsType(sibling, (aSizeChange==1 ? nsEditProperty::big : nsEditProperty::small)))
    1765                 :     {
    1766                 :       // previous sib is already right kind of inline node; slide this over into it
    1767               0 :       res = MoveNode(aNode, sibling, -1);
    1768               0 :       return res;
    1769                 :     }
    1770               0 :     sibling = nsnull;
    1771               0 :     GetNextHTMLSibling(aNode, address_of(sibling));
    1772               0 :     if (sibling && nsEditor::NodeIsType(sibling, (aSizeChange==1 ? nsEditProperty::big : nsEditProperty::small)))
    1773                 :     {
    1774                 :       // following sib is already right kind of inline node; slide this over into it
    1775               0 :       res = MoveNode(aNode, sibling, 0);
    1776               0 :       return res;
    1777                 :     }
    1778                 :     // else insert it above aNode
    1779               0 :     res = InsertContainerAbove(aNode, address_of(tmp), tag);
    1780               0 :     return res;
    1781                 :   }
    1782                 :   // none of the above?  then cycle through the children.
    1783                 :   // MOOSE: we should group the children together if possible
    1784                 :   // into a single "big" or "small".  For the moment they are
    1785                 :   // each getting their own.  
    1786               0 :   nsCOMPtr<nsIDOMNodeList> childNodes;
    1787               0 :   res = aNode->GetChildNodes(getter_AddRefs(childNodes));
    1788               0 :   NS_ENSURE_SUCCESS(res, res);
    1789               0 :   if (childNodes)
    1790                 :   {
    1791                 :     PRInt32 j;
    1792                 :     PRUint32 childCount;
    1793               0 :     childNodes->GetLength(&childCount);
    1794               0 :     for (j=childCount-1; j>=0; j--)
    1795                 :     {
    1796               0 :       nsCOMPtr<nsIDOMNode> childNode;
    1797               0 :       res = childNodes->Item(j, getter_AddRefs(childNode));
    1798               0 :       if ((NS_SUCCEEDED(res)) && (childNode))
    1799                 :       {
    1800               0 :         res = RelativeFontChangeOnNode(aSizeChange, childNode);
    1801               0 :         NS_ENSURE_SUCCESS(res, res);
    1802                 :       }
    1803                 :     }
    1804                 :   }
    1805               0 :   return res;
    1806                 : }
    1807                 : 
    1808                 : NS_IMETHODIMP 
    1809               0 : nsHTMLEditor::GetFontFaceState(bool *aMixed, nsAString &outFace)
    1810                 : {
    1811               0 :   NS_ENSURE_TRUE(aMixed, NS_ERROR_FAILURE);
    1812               0 :   *aMixed = true;
    1813               0 :   outFace.Truncate();
    1814                 : 
    1815                 :   nsresult res;
    1816                 :   bool first, any, all;
    1817                 :   
    1818               0 :   NS_NAMED_LITERAL_STRING(attr, "face");
    1819               0 :   res = GetInlinePropertyBase(nsEditProperty::font, &attr, nsnull, &first, &any, &all, &outFace);
    1820               0 :   NS_ENSURE_SUCCESS(res, res);
    1821               0 :   if (any && !all) return res; // mixed
    1822               0 :   if (all)
    1823                 :   {
    1824               0 :     *aMixed = false;
    1825               0 :     return res;
    1826                 :   }
    1827                 :   
    1828                 :   // if there is no font face, check for tt
    1829               0 :   res = GetInlinePropertyBase(nsEditProperty::tt, nsnull, nsnull, &first, &any, &all,nsnull);
    1830               0 :   NS_ENSURE_SUCCESS(res, res);
    1831               0 :   if (any && !all) return res; // mixed
    1832               0 :   if (all)
    1833                 :   {
    1834               0 :     *aMixed = false;
    1835               0 :     nsEditProperty::tt->ToString(outFace);
    1836                 :   }
    1837                 :   
    1838               0 :   if (!any)
    1839                 :   {
    1840                 :     // there was no font face attrs of any kind.  We are in normal font.
    1841               0 :     outFace.Truncate();
    1842               0 :     *aMixed = false;
    1843                 :   }
    1844               0 :   return res;
    1845                 : }
    1846                 : 
    1847                 : NS_IMETHODIMP 
    1848               0 : nsHTMLEditor::GetFontColorState(bool *aMixed, nsAString &aOutColor)
    1849                 : {
    1850               0 :   NS_ENSURE_TRUE(aMixed, NS_ERROR_NULL_POINTER);
    1851               0 :   *aMixed = true;
    1852               0 :   aOutColor.Truncate();
    1853                 :   
    1854                 :   nsresult res;
    1855               0 :   NS_NAMED_LITERAL_STRING(colorStr, "color");
    1856                 :   bool first, any, all;
    1857                 :   
    1858               0 :   res = GetInlinePropertyBase(nsEditProperty::font, &colorStr, nsnull, &first, &any, &all, &aOutColor);
    1859               0 :   NS_ENSURE_SUCCESS(res, res);
    1860               0 :   if (any && !all) return res; // mixed
    1861               0 :   if (all)
    1862                 :   {
    1863               0 :     *aMixed = false;
    1864               0 :     return res;
    1865                 :   }
    1866                 :   
    1867               0 :   if (!any)
    1868                 :   {
    1869                 :     // there was no font color attrs of any kind..
    1870               0 :     aOutColor.Truncate();
    1871               0 :     *aMixed = false;
    1872                 :   }
    1873               0 :   return res;
    1874                 : }
    1875                 : 
    1876                 : // the return value is true only if the instance of the HTML editor we created
    1877                 : // can handle CSS styles (for instance, Composer can, Messenger can't) and if
    1878                 : // the CSS preference is checked
    1879                 : nsresult
    1880               0 : nsHTMLEditor::GetIsCSSEnabled(bool *aIsCSSEnabled)
    1881                 : {
    1882               0 :   *aIsCSSEnabled = IsCSSEnabled();
    1883               0 :   return NS_OK;
    1884                 : }
    1885                 : 
    1886                 : static bool
    1887               0 : HasNonEmptyAttribute(dom::Element* aElement, nsIAtom* aName)
    1888                 : {
    1889               0 :   MOZ_ASSERT(aElement);
    1890                 : 
    1891               0 :   nsAutoString value;
    1892               0 :   return aElement->GetAttr(kNameSpaceID_None, aName, value) && !value.IsEmpty();
    1893                 : }
    1894                 : 
    1895                 : bool
    1896               0 : nsHTMLEditor::HasStyleOrIdOrClass(dom::Element* aElement)
    1897                 : {
    1898               0 :   MOZ_ASSERT(aElement);
    1899                 : 
    1900                 :   // remove the node if its style attribute is empty or absent,
    1901                 :   // and if it does not have a class nor an id
    1902               0 :   return HasNonEmptyAttribute(aElement, nsGkAtoms::style) ||
    1903               0 :          HasNonEmptyAttribute(aElement, nsGkAtoms::_class) ||
    1904               0 :          HasNonEmptyAttribute(aElement, nsGkAtoms::id);
    1905                 : }
    1906                 : 
    1907                 : nsresult
    1908               0 : nsHTMLEditor::RemoveElementIfNoStyleOrIdOrClass(nsIDOMNode* aElement)
    1909                 : {
    1910               0 :   nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
    1911               0 :   NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
    1912                 : 
    1913                 :   // early way out if node is not the right kind of element
    1914               0 :   if (!element->IsHTML(nsGkAtoms::span) || HasStyleOrIdOrClass(element)) {
    1915               0 :     return NS_OK;
    1916                 :   }
    1917                 : 
    1918               0 :   return RemoveContainer(element);
    1919                 : }

Generated by: LCOV version 1.7