Back to index

lightning-sunbird  0.9+nobinonly
nsRange.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * nsRange.cpp: Implementation of the nsIDOMRange object.
00040  */
00041 
00042 #include "nscore.h"
00043 #include "nsRange.h"
00044 
00045 #include "nsString.h"
00046 #include "nsReadableUtils.h"
00047 #include "nsIDOMNode.h"
00048 #include "nsIDOMDocument.h"
00049 #include "nsIDOMNSDocument.h"
00050 #include "nsIDOMDocumentFragment.h"
00051 #include "nsIContent.h"
00052 #include "nsIDocument.h"
00053 #include "nsVoidArray.h"
00054 #include "nsIDOMText.h"
00055 #include "nsDOMError.h"
00056 #include "nsIContentIterator.h"
00057 #include "nsIDOMNodeList.h"
00058 #include "nsIParser.h"
00059 #include "nsIComponentManager.h"
00060 #include "nsParserCIID.h"
00061 #include "nsIFragmentContentSink.h"
00062 #include "nsIContentSink.h"
00063 #include "nsIEnumerator.h"
00064 #include "nsIScriptSecurityManager.h"
00065 #include "nsIScriptGlobalObject.h"
00066 #include "nsIScriptContext.h"
00067 #include "nsIHTMLDocument.h"
00068 #include "nsCRT.h"
00069 
00070 #include "nsIJSContextStack.h"
00071 // XXX Temporary inclusion to deal with fragment parsing
00072 #include "nsHTMLParts.h"
00073 
00074 #include "nsContentUtils.h"
00075 
00076 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
00077 
00078 nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
00079 nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
00080 
00081 
00082 
00083 #ifdef XP_MAC
00084 #pragma mark -
00085 #pragma mark  utility functions (some exposed through nsRangeUtils, below
00086 #pragma mark -
00087 #endif
00088 
00089 
00090 /******************************************************
00091  * stack based utilty class for managing monitor
00092  ******************************************************/
00093 
00094 // NS_ERROR_DOM_NOT_OBJECT_ERR is not the correct one to throw, but spec doesn't say
00095 // what is
00096 #define VALIDATE_ACCESS(node_)                                                     \
00097   PR_BEGIN_MACRO                                                                   \
00098     if (!node_) {                                                                  \
00099       return NS_ERROR_DOM_NOT_OBJECT_ERR;                                          \
00100     }                                                                              \
00101     if (!nsContentUtils::CanCallerAccess(node_)) {                                 \
00102       return NS_ERROR_DOM_SECURITY_ERR;                                            \
00103     }                                                                              \
00104     if (IsDetached()) {                                                            \
00105       return NS_ERROR_DOM_INVALID_STATE_ERR;                                       \
00106     }                                                                              \
00107   PR_END_MACRO
00108 
00109 
00110 
00111 /* static */
00112 PRInt32
00113 nsRange::ComparePoints(nsIDOMNode* aParent1, PRInt32 aOffset1,
00114                        nsIDOMNode* aParent2, PRInt32 aOffset2)
00115 {
00116   if (aParent1 == aParent2) {
00117     return (aOffset1 < aOffset2) ? -1 :
00118       ((aOffset1 > aOffset2) ? 1 : 0);
00119   }
00120 
00121   return IsIncreasing(aParent1, aOffset1, aParent2, aOffset2) ? -1 : 1;
00122 }
00123 
00124 // Utility routine to detect if a content node intersects a range
00125 /* static */
00126 PRBool
00127 nsRange::IsNodeIntersectsRange(nsIContent* aNode, nsIDOMRange* aRange)
00128 {
00129   // create a pair of dom points that expresses location of node:
00130   //     NODE(start), NODE(end)
00131   // Let incoming range be:
00132   //    {RANGE(start), RANGE(end)}
00133   // if (RANGE(start) < NODE(end))  and (RANGE(end) > NODE(start))
00134   // then the Node intersect the Range.
00135   
00136   if (!aNode) return PR_FALSE;
00137   nsCOMPtr<nsIDOMNode> parent, rangeStartParent, rangeEndParent;
00138   PRInt32 nodeStart, nodeEnd, rangeStartOffset, rangeEndOffset; 
00139   
00140   // gather up the dom point info
00141   if (!GetNodeBracketPoints(aNode, address_of(parent), &nodeStart, &nodeEnd))
00142     return PR_FALSE;
00143   
00144   if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(rangeStartParent))))
00145     return PR_FALSE;
00146 
00147   if (NS_FAILED(aRange->GetStartOffset(&rangeStartOffset)))
00148     return PR_FALSE;
00149 
00150   if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(rangeEndParent))))
00151     return PR_FALSE;
00152 
00153   if (NS_FAILED(aRange->GetEndOffset(&rangeEndOffset)))
00154     return PR_FALSE;
00155 
00156   // is RANGE(start) < NODE(end) ?
00157   PRInt32 comp = ComparePoints(rangeStartParent, rangeStartOffset, parent, nodeEnd);
00158   if (comp >= 0)
00159     return PR_FALSE; // range start is after node end
00160     
00161   // is RANGE(end) > NODE(start) ?
00162   comp = ComparePoints(rangeEndParent, rangeEndOffset, parent, nodeStart);
00163   if (comp <= 0)
00164     return PR_FALSE; // range end is before node start
00165     
00166   // if we got here then the node intersects the range
00167   return PR_TRUE;
00168 }
00169 
00170 
00171 // Utility routine to detect if a content node is completely contained in a range
00172 // If outNodeBefore is returned true, then the node starts before the range does.
00173 // If outNodeAfter is returned true, then the node ends after the range does.
00174 // Note that both of the above might be true.
00175 // If neither are true, the node is contained inside of the range.
00176 // XXX - callers responsibility to ensure node in same doc as range! 
00177 
00178 // static
00179 nsresult
00180 nsRange::CompareNodeToRange(nsIContent* aNode, nsIDOMRange* aRange,
00181                             PRBool *outNodeBefore, PRBool *outNodeAfter)
00182 {
00183   // create a pair of dom points that expresses location of node:
00184   //     NODE(start), NODE(end)
00185   // Let incoming range be:
00186   //    {RANGE(start), RANGE(end)}
00187   // if (RANGE(start) <= NODE(start))  and (RANGE(end) => NODE(end))
00188   // then the Node is contained (completely) by the Range.
00189   
00190   if (!aNode) 
00191     return NS_ERROR_NULL_POINTER;
00192   if (!aRange) 
00193     return NS_ERROR_NULL_POINTER;
00194   if (!outNodeBefore) 
00195     return NS_ERROR_NULL_POINTER;
00196   if (!outNodeAfter) 
00197     return NS_ERROR_NULL_POINTER;
00198   
00199   PRBool isPositioned;
00200   nsresult err = ((nsRange*)aRange)->GetIsPositioned(&isPositioned);
00201   // Why do I have to cast above?  Because GetIsPositioned() is
00202   // mysteriously missing from the nsIDOMRange interface.  dunno why.
00203 
00204   if (NS_FAILED(err))
00205     return err;
00206     
00207   if (!isPositioned) 
00208     return NS_ERROR_UNEXPECTED; 
00209   
00210   nsCOMPtr<nsIDOMNode> parent, rangeStartParent, rangeEndParent;
00211   PRInt32 nodeStart, nodeEnd, rangeStartOffset, rangeEndOffset; 
00212   
00213   // gather up the dom point info
00214   if (!GetNodeBracketPoints(aNode, address_of(parent), &nodeStart, &nodeEnd))
00215     return NS_ERROR_FAILURE;
00216   
00217   if (NS_FAILED(aRange->GetStartContainer(getter_AddRefs(rangeStartParent))))
00218     return NS_ERROR_FAILURE;
00219 
00220   if (NS_FAILED(aRange->GetStartOffset(&rangeStartOffset)))
00221     return NS_ERROR_FAILURE;
00222 
00223   if (NS_FAILED(aRange->GetEndContainer(getter_AddRefs(rangeEndParent))))
00224     return NS_ERROR_FAILURE;
00225 
00226   if (NS_FAILED(aRange->GetEndOffset(&rangeEndOffset)))
00227     return NS_ERROR_FAILURE;
00228 
00229   *outNodeBefore = PR_FALSE;
00230   *outNodeAfter = PR_FALSE;
00231   
00232   // is RANGE(start) <= NODE(start) ?
00233   PRInt32 comp = ComparePoints(rangeStartParent, rangeStartOffset, parent, nodeStart);
00234   if (comp > 0)
00235     *outNodeBefore = PR_TRUE; // range start is after node start
00236     
00237   // is RANGE(end) >= NODE(end) ?
00238   comp = ComparePoints(rangeEndParent, rangeEndOffset, parent, nodeEnd);
00239   if (comp < 0)
00240     *outNodeAfter = PR_TRUE; // range end is before node end
00241     
00242   return NS_OK;
00243 }
00244 
00245 
00246 // Utility routine to create a pair of dom points to represent 
00247 // the start and end locations of a single node.  Return false
00248 // if we dont' succeed.
00249 PRBool GetNodeBracketPoints(nsIContent* aNode, 
00250                             nsCOMPtr<nsIDOMNode>* outParent,
00251                             PRInt32* outStartOffset,
00252                             PRInt32* outEndOffset)
00253 {
00254   if (!aNode) 
00255     return PR_FALSE;
00256   if (!outParent) 
00257     return PR_FALSE;
00258   if (!outStartOffset)
00259     return PR_FALSE;
00260   if (!outEndOffset)
00261     return PR_FALSE;
00262     
00263   nsIContent* parent = aNode->GetParent();
00264 
00265   if (!parent) // special case for root node
00266   {
00267     // can't make a parent/offset pair to represent start or 
00268     // end of the root node, becasue it has no parent.
00269     // so instead represent it by (node,0) and (node,numChildren)
00270     *outParent = do_QueryInterface(aNode);
00271     PRUint32 indx = aNode->GetChildCount();
00272     if (!indx)
00273       return PR_FALSE;
00274     *outStartOffset = 0;
00275     *outEndOffset = indx;
00276   }
00277   else
00278   {
00279     *outParent = do_QueryInterface(parent);
00280     *outStartOffset = parent->IndexOf(aNode);
00281     *outEndOffset = *outStartOffset+1;
00282   }
00283   return PR_TRUE;
00284 }
00285 
00286 
00287 
00288 #ifdef XP_MAC
00289 #pragma mark -
00290 #pragma mark  class nsRangeUtils
00291 #pragma mark -
00292 #endif
00293 
00294 
00295 /******************************************************
00296  * non members
00297  ******************************************************/
00298 
00299 nsresult
00300 NS_NewRangeUtils(nsIRangeUtils** aResult)
00301 {
00302   NS_ENSURE_ARG_POINTER(aResult);
00303 
00304   nsRangeUtils* rangeUtil = new nsRangeUtils();
00305   if (!rangeUtil) {
00306     return NS_ERROR_OUT_OF_MEMORY;
00307   }
00308 
00309   return CallQueryInterface(rangeUtil, aResult);
00310 }
00311 
00312 /******************************************************
00313  * constructor/destructor
00314  ******************************************************/
00315 
00316 nsRangeUtils::nsRangeUtils()
00317 {
00318 } 
00319 
00320 nsRangeUtils::~nsRangeUtils() 
00321 {
00322 } 
00323 
00324 /******************************************************
00325  * nsISupports
00326  ******************************************************/
00327 NS_IMPL_ISUPPORTS1(nsRangeUtils, nsIRangeUtils)
00328 
00329 /******************************************************
00330  * nsIRangeUtils methods
00331  ******************************************************/
00332  
00333 NS_IMETHODIMP_(PRInt32) 
00334 nsRangeUtils::ComparePoints(nsIDOMNode* aParent1, PRInt32 aOffset1,
00335                             nsIDOMNode* aParent2, PRInt32 aOffset2)
00336 {
00337   return nsRange::ComparePoints(aParent1, aOffset1, aParent2, aOffset2);
00338 }
00339 
00340 NS_IMETHODIMP_(PRBool) 
00341 nsRangeUtils::IsNodeIntersectsRange(nsIContent* aNode, nsIDOMRange* aRange)
00342 {
00343   return nsRange::IsNodeIntersectsRange( aNode,  aRange);
00344 }
00345 
00346 NS_IMETHODIMP
00347 nsRangeUtils::CompareNodeToRange(nsIContent* aNode, nsIDOMRange* aRange,
00348                                  PRBool *outNodeBefore, PRBool *outNodeAfter)
00349 {
00350   return nsRange::CompareNodeToRange(aNode, aRange, outNodeBefore,
00351                                      outNodeAfter);
00352 }
00353 
00354 #ifdef XP_MAC
00355 #pragma mark -
00356 #pragma mark  class nsRange
00357 #pragma mark -
00358 #endif
00359 
00360 
00361 /******************************************************
00362  * non members
00363  ******************************************************/
00364 
00365 nsresult
00366 NS_NewRange(nsIDOMRange** aResult)
00367 {
00368   NS_ENSURE_ARG_POINTER(aResult);
00369 
00370   nsRange * range = new nsRange();
00371   if (!range) {
00372     return NS_ERROR_OUT_OF_MEMORY;
00373   }
00374 
00375   return CallQueryInterface(range, aResult);
00376 }
00377 
00378 /******************************************************
00379  * constructor/destructor
00380  ******************************************************/
00381 
00382 nsRange::nsRange() :
00383   mIsPositioned(PR_FALSE),
00384   mIsDetached(PR_FALSE),
00385   mStartOffset(0),
00386   mEndOffset(0),
00387   mStartParent(),
00388   mEndParent()
00389 {
00390 } 
00391 
00392 nsRange::~nsRange() 
00393 {
00394   DoSetRange(nsCOMPtr<nsIDOMNode>(),0,nsCOMPtr<nsIDOMNode>(),0); 
00395   // we want the side effects (releases and list removals)
00396   // note that "nsCOMPtr<nsIDOMmNode>()" is the moral equivalent of null
00397 } 
00398 
00399 /******************************************************
00400  * nsISupports
00401  ******************************************************/
00402 
00403 
00404 // QueryInterface implementation for nsRange
00405 NS_INTERFACE_MAP_BEGIN(nsRange)
00406   NS_INTERFACE_MAP_ENTRY(nsIDOMRange)
00407   NS_INTERFACE_MAP_ENTRY(nsIDOMNSRange)
00408   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMRange)
00409   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(Range)
00410 NS_INTERFACE_MAP_END
00411 
00412 
00413 NS_IMPL_ADDREF(nsRange)
00414 NS_IMPL_RELEASE(nsRange)
00415 
00416 
00417 /********************************************************
00418  * Utilities for comparing points: API from nsIDOMNSRange
00419  ********************************************************/
00420 NS_IMETHODIMP
00421 nsRange::IsPointInRange(nsIDOMNode* aParent, PRInt32 aOffset, PRBool* aResult)
00422 {
00423   PRInt16 compareResult = 0;
00424   nsresult res;
00425   res = ComparePoint(aParent, aOffset, &compareResult);
00426   if (compareResult) 
00427     *aResult = PR_FALSE;
00428   else 
00429     *aResult = PR_TRUE;
00430   return res;
00431 }
00432   
00433 // returns -1 if point is before range, 0 if point is in range,
00434 // 1 if point is after range.
00435 NS_IMETHODIMP
00436 nsRange::ComparePoint(nsIDOMNode* aParent, PRInt32 aOffset, PRInt16* aResult)
00437 {
00438   // check arguments
00439   if (!aResult) 
00440     return NS_ERROR_NULL_POINTER;
00441   
00442   // no trivial cases please
00443   if (!aParent) 
00444     return NS_ERROR_NULL_POINTER;
00445   
00446   // our range is in a good state?
00447   if (!mIsPositioned) 
00448     return NS_ERROR_NOT_INITIALIZED;
00449   
00450   // check common case first
00451   if ((aParent == mStartParent.get()) && (aParent == mEndParent.get()))
00452   {
00453     if (aOffset<mStartOffset)
00454     {
00455       *aResult = -1;
00456       return NS_OK;
00457     }
00458     if (aOffset>mEndOffset)
00459     {
00460       *aResult = 1;
00461       return NS_OK;
00462     }
00463     *aResult = 0;
00464     return NS_OK;
00465   }
00466   
00467   // more common cases
00468   if ((aParent == mStartParent.get()) && (aOffset == mStartOffset)) 
00469   {
00470     *aResult = 0;
00471     return NS_OK;
00472   }
00473   if ((aParent == mEndParent.get()) && (aOffset == mEndOffset)) 
00474   {
00475     *aResult = 0;
00476     return NS_OK;
00477   }
00478   
00479   // ok, do it the hard way
00480   if (IsIncreasing(aParent,aOffset,mStartParent,mStartOffset)) 
00481     *aResult = -1;
00482   else if (IsIncreasing(mEndParent,mEndOffset,aParent,aOffset)) 
00483     *aResult = 1;
00484   else 
00485     *aResult = 0;
00486   
00487   return NS_OK;
00488 }
00489   
00490 NS_IMETHODIMP
00491 nsRange::IntersectsNode(nsIDOMNode* aNode, PRBool* aReturn)
00492 {
00493   if (!aReturn)
00494     return NS_ERROR_NULL_POINTER;
00495   nsCOMPtr<nsIContent> content (do_QueryInterface(aNode));
00496   if (!content)
00497   {
00498     *aReturn = 0;
00499     return NS_ERROR_UNEXPECTED;
00500   }
00501   *aReturn = IsNodeIntersectsRange(content, this);
00502   return NS_OK;
00503 }
00504 
00505 // HOW does the node intersect the range?
00506 NS_IMETHODIMP
00507 nsRange::CompareNode(nsIDOMNode* aNode, PRUint16* aReturn)
00508 {
00509   if (!aReturn)
00510     return NS_ERROR_NULL_POINTER;
00511   *aReturn = 0;
00512   PRBool nodeBefore, nodeAfter;
00513   nsCOMPtr<nsIContent> content (do_QueryInterface(aNode));
00514   if (!content)
00515     return NS_ERROR_UNEXPECTED;
00516 
00517   nsresult res = CompareNodeToRange(content, this, &nodeBefore, &nodeAfter);
00518   if (NS_FAILED(res))
00519     return res;
00520 
00521   // nodeBefore -> range start after node start, i.e. node starts before range.
00522   // nodeAfter -> range end before node end, i.e. node ends after range.
00523   // But I know that I get nodeBefore && !nodeAfter when the node is
00524   // entirely inside the selection!  This doesn't make sense.
00525   if (nodeBefore && !nodeAfter)
00526     *aReturn = nsIDOMNSRange::NODE_BEFORE;  // May or may not intersect
00527   else if (!nodeBefore && nodeAfter)
00528     *aReturn = nsIDOMNSRange::NODE_AFTER;   // May or may not intersect
00529   else if (nodeBefore && nodeAfter)
00530     *aReturn = nsIDOMNSRange::NODE_BEFORE_AND_AFTER;  // definitely intersects
00531   else
00532     *aReturn = nsIDOMNSRange::NODE_INSIDE;            // definitely intersects
00533 
00534   return NS_OK;
00535 }
00536 
00537 
00538 
00539 nsresult
00540 nsRange::NSDetach()
00541 {
00542   return DoSetRange(nsnull,0,nsnull,0);
00543 }
00544 
00545 
00546 
00547 /******************************************************
00548  * Private helper routines
00549  ******************************************************/
00550 
00551 nsresult nsRange::AddToListOf(nsIDOMNode* aNode)
00552 {
00553   if (!aNode) 
00554     return NS_ERROR_NULL_POINTER;
00555 
00556   nsresult res;
00557   nsCOMPtr<nsIContent> cN = do_QueryInterface(aNode, &res);
00558   if (NS_FAILED(res)) 
00559     return res;
00560 
00561   res = cN->RangeAdd(NS_STATIC_CAST(nsIDOMRange*,this));
00562   return res;
00563 }
00564   
00565 
00566 void nsRange::RemoveFromListOf(nsIDOMNode* aNode)
00567 {
00568   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
00569 
00570   if (content) 
00571     content->RangeRemove(NS_STATIC_CAST(nsIDOMRange *, this));
00572 }
00573 
00574 
00575 // Get the length of aNode
00576 PRInt32 nsRange::GetNodeLength(nsIDOMNode *aNode)
00577 {
00578   if (!aNode)
00579     return 0;
00580 
00581   PRUint16 nodeType;
00582   PRInt32 len = -1;
00583 
00584   aNode->GetNodeType(&nodeType);
00585   if( (nodeType == nsIDOMNode::CDATA_SECTION_NODE) ||
00586       (nodeType == nsIDOMNode::TEXT_NODE) )
00587   {
00588     nsCOMPtr<nsIDOMText> textText = do_QueryInterface(aNode);
00589     if (textText)
00590       textText->GetLength((PRUint32 *)&len);
00591   }
00592   else
00593   {
00594     nsCOMPtr<nsIDOMNodeList> childList;
00595     nsresult res = aNode->GetChildNodes(getter_AddRefs(childList));
00596     if (NS_SUCCEEDED(res) && childList)
00597       childList->GetLength((PRUint32 *)&len);
00598   }
00599   
00600   return len;
00601 }
00602 
00603 // It's important that all setting of the range start/end points 
00604 // go through this function, which will do all the right voodoo
00605 // for content notification of range ownership.  
00606 // Calling DoSetRange with either parent argument null will collapse
00607 // the range to have both endpoints point to the other node
00608 nsresult nsRange::DoSetRange(nsIDOMNode* aStartN, PRInt32 aStartOffset,
00609                              nsIDOMNode* aEndN, PRInt32 aEndOffset)
00610 {
00611   //if only one endpoint is null, set it to the other one
00612   if (aStartN && !aEndN) 
00613   {
00614     aEndN = aStartN;
00615     aEndOffset = aStartOffset;
00616   }
00617   if (aEndN && !aStartN)
00618   {
00619     aStartN = aEndN;
00620     aStartOffset = aEndOffset;
00621   }
00622   
00623   if (mStartParent && (mStartParent.get() != aStartN) && (mStartParent.get() != aEndN))
00624   {
00625     // if old start parent no longer involved, remove range from that
00626     // node's range list.
00627     RemoveFromListOf(mStartParent);
00628   }
00629   if (mEndParent && (mEndParent.get() != aStartN) && (mEndParent.get() != aEndN))
00630   {
00631     // if old end parent no longer involved, remove range from that
00632     // node's range list.
00633     RemoveFromListOf(mEndParent);
00634   }
00635  
00636  
00637   if (mStartParent.get() != aStartN)
00638   {
00639     mStartParent = do_QueryInterface(aStartN);
00640     if (mStartParent) // if it has a new start node, put it on it's list
00641     {
00642       AddToListOf(mStartParent);  // AddToList() detects duplication for us
00643     }
00644   }
00645   mStartOffset = aStartOffset;
00646 
00647   if (mEndParent.get() != aEndN)
00648   {
00649     mEndParent = do_QueryInterface(aEndN);
00650     if (mEndParent) // if it has a new end node, put it on it's list
00651     {
00652       AddToListOf(mEndParent);  // AddToList() detects duplication for us
00653     }
00654   }
00655   mEndOffset = aEndOffset;
00656 
00657   if (mStartParent) 
00658     mIsPositioned = PR_TRUE;
00659   else
00660     mIsPositioned = PR_FALSE;
00661 
00662   // FIX ME need to handle error cases 
00663   // (range lists return error, or setting only one endpoint to null)
00664   return NS_OK;
00665 }
00666 
00667 
00668 PRBool nsRange::IsIncreasing(nsIDOMNode* aStartN, PRInt32 aStartOffset,
00669                              nsIDOMNode* aEndN, PRInt32 aEndOffset)
00670 {
00671   // no trivial cases please
00672   if (!aStartN || !aEndN) 
00673     return PR_FALSE;
00674   
00675   // check common case first
00676   if (aStartN == aEndN)
00677   {
00678     return aStartOffset <= aEndOffset;
00679   }
00680 
00681   nsCOMPtr<nsIContent> startCont = do_QueryInterface(aStartN);
00682   nsCOMPtr<nsIContent> endCont = do_QueryInterface(aEndN);
00683 
00684   nsAutoVoidArray startAncestors, endAncestors;
00685   nsIContent* node = startCont;
00686   while (node) {
00687     startAncestors.AppendElement(node);
00688     node = node->GetParent();
00689   }
00690   node = endCont;
00691   while (node) {
00692     endAncestors.AppendElement(node);
00693     node = node->GetParent();
00694   }
00695   
00696   // Get the number of ancestors, adjusting for zero-based counting.
00697   PRInt32 startIdx = startAncestors.Count() - 1;
00698   PRInt32 endIdx = endAncestors.Count() - 1;
00699 
00700   // Ensure that we actually have ancestors to iterate through
00701   if (startIdx < 0) {
00702     if (startIdx < endIdx) {
00703       return PR_TRUE;
00704     }
00705     return PR_FALSE;
00706   }
00707   if (endIdx < 0) {
00708     return PR_FALSE;
00709   }
00710 
00711   // back through the ancestors, starting from the root, until first non-matching ancestor found
00712   do
00713   {
00714     --startIdx;
00715     --endIdx;
00716     // numStartAncestors will only be <0 if one endpoint's node is the
00717     // common ancestor of the other
00718   } while (startIdx >= 0 && endIdx >= 0 &&
00719            startAncestors.FastElementAt(startIdx) ==
00720            endAncestors.FastElementAt(endIdx));
00721   // now back up one and that's the last common ancestor from the root,
00722   // or the first common ancestor from the leaf perspective
00723   ++startIdx;
00724   ++endIdx;
00725   // both indexes are now >= 0
00726   
00727   
00728   PRInt32 commonNodeStartOffset = startIdx == 0 ? aStartOffset :
00729     NS_STATIC_CAST(nsIContent*, startAncestors.FastElementAt(startIdx))->IndexOf(
00730       NS_STATIC_CAST(nsIContent*, startAncestors.FastElementAt(startIdx - 1)));
00731 
00732   PRInt32 commonNodeEndOffset = endIdx == 0 ? aEndOffset :
00733     NS_STATIC_CAST(nsIContent*, endAncestors.FastElementAt(endIdx))->IndexOf(
00734       NS_STATIC_CAST(nsIContent*, endAncestors.FastElementAt(endIdx - 1)));
00735 
00736   if (commonNodeStartOffset > commonNodeEndOffset) {
00737     return PR_FALSE;
00738   }
00739 
00740   if (commonNodeStartOffset < commonNodeEndOffset) {
00741     return PR_TRUE;
00742   }
00743 
00744   // The offsets are equal.  This can happen when one endpoint parent is the common parent
00745   // of both endpoints.  In this case, we compare the depth of the ancestor tree to determine
00746   // the ordering.
00747 
00748   NS_ASSERTION(startIdx != endIdx, "whoa nelly. this shouldn't happen");
00749 
00750   return startIdx < endIdx;
00751 }
00752 
00753 PRInt32 nsRange::IndexOf(nsIDOMNode* aChildNode)
00754 {
00755   // convert node to nsIContent, so that we can find the child index
00756 
00757   nsCOMPtr<nsIContent> contentChild = do_QueryInterface(aChildNode);
00758   if (!contentChild) 
00759     return 0;
00760 
00761   nsIContent *parent = contentChild->GetParent();
00762 
00763   if (!parent)
00764     return 0;
00765 
00766   // finally we get the index
00767   return parent->IndexOf(contentChild); 
00768 }
00769 
00770 nsresult nsRange::PopRanges(nsIDOMNode* aDestNode, PRInt32 aOffset, nsIContent* aSourceNode)
00771 {
00772   // utility routine to pop all the range endpoints inside the content subtree defined by 
00773   // aSourceNode, into the node/offset represented by aDestNode/aOffset.
00774   
00775   nsCOMPtr<nsIContentIterator> iter;
00776   nsresult res = NS_NewContentIterator(getter_AddRefs(iter));
00777   iter->Init(aSourceNode);
00778 
00779   const nsVoidArray* theRangeList;
00780 
00781   while (!iter->IsDone())
00782   {
00783     nsIContent *cN = iter->GetCurrentNode();
00784 
00785     theRangeList = cN->GetRangeList();
00786     if (theRangeList)
00787     {
00788        nsRange* theRange;
00789        PRInt32  theCount = theRangeList->Count();
00790        while (theCount)
00791        {
00792           theRange = NS_STATIC_CAST(nsRange*, (theRangeList->ElementAt(0)));
00793           if (theRange)
00794           {
00795             nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(cN));
00796             NS_POSTCONDITION(domNode, "error updating range list");
00797             // sanity check - do range and content agree over ownership?
00798             res = theRange->ContentOwnsUs(domNode);
00799             NS_POSTCONDITION(NS_SUCCEEDED(res), "range and content disagree over range ownership");
00800 
00801             if (theRange->mStartParent == domNode)
00802             {
00803               // promote start point up to replacement point
00804               res = theRange->SetStart(aDestNode, aOffset);
00805               NS_POSTCONDITION(NS_SUCCEEDED(res), "nsRange::PopRanges() got error from SetStart()");
00806               if (NS_FAILED(res)) return res;
00807             }
00808             if (theRange->mEndParent == domNode)
00809             {
00810               // promote end point up to replacement point
00811               res = theRange->SetEnd(aDestNode, aOffset);
00812               NS_POSTCONDITION(NS_SUCCEEDED(res), "nsRange::PopRanges() got error from SetEnd()");
00813               if (NS_FAILED(res)) return res;
00814             }          
00815           }
00816           // must refresh theRangeList - it might have gone away!
00817           theRangeList = cN->GetRangeList();
00818           if (theRangeList)
00819             theCount = theRangeList->Count();
00820           else
00821             theCount = 0;
00822        } 
00823     }
00824 
00825     iter->Next();
00826   }
00827   
00828   return NS_OK;
00829 }
00830 
00831 // sanity check routine for content helpers.  confirms that given 
00832 // node owns one or both range endpoints.
00833 nsresult nsRange::ContentOwnsUs(nsIDOMNode* domNode)
00834 {
00835   NS_PRECONDITION(domNode, "null pointer");
00836   if ((mStartParent.get() != domNode) && (mEndParent.get() != domNode))
00837   {
00838     NS_NOTREACHED("nsRange::ContentOwnsUs");
00839     return NS_ERROR_UNEXPECTED;
00840   }
00841   return NS_OK;
00842 }
00843 
00844 /******************************************************
00845  * public functionality
00846  ******************************************************/
00847 
00848 nsresult nsRange::GetIsPositioned(PRBool* aIsPositioned)
00849 {
00850   *aIsPositioned = mIsPositioned;
00851   return NS_OK;
00852 }
00853 
00854 nsresult nsRange::GetStartContainer(nsIDOMNode** aStartParent)
00855 {
00856   if (!mIsPositioned)
00857     return NS_ERROR_NOT_INITIALIZED;
00858   if (!aStartParent)
00859     return NS_ERROR_NULL_POINTER;
00860 
00861   *aStartParent = mStartParent;
00862   NS_IF_ADDREF(*aStartParent);
00863   return NS_OK;
00864 }
00865 
00866 nsresult nsRange::GetStartOffset(PRInt32* aStartOffset)
00867 {
00868   if (!mIsPositioned)
00869     return NS_ERROR_NOT_INITIALIZED;
00870   if (!aStartOffset)
00871     return NS_ERROR_NULL_POINTER;
00872   *aStartOffset = mStartOffset;
00873   return NS_OK;
00874 }
00875 
00876 nsresult nsRange::GetEndContainer(nsIDOMNode** aEndParent)
00877 {
00878   if (!mIsPositioned)
00879     return NS_ERROR_NOT_INITIALIZED;
00880   if (!aEndParent)
00881     return NS_ERROR_NULL_POINTER;
00882   //NS_IF_RELEASE(*aEndParent); don't think we should be doing this
00883   *aEndParent = mEndParent;
00884   NS_IF_ADDREF(*aEndParent);
00885   return NS_OK;
00886 }
00887 
00888 nsresult nsRange::GetEndOffset(PRInt32* aEndOffset)
00889 {
00890   if (!mIsPositioned)
00891     return NS_ERROR_NOT_INITIALIZED;
00892   if (!aEndOffset)
00893     return NS_ERROR_NULL_POINTER;
00894   *aEndOffset = mEndOffset;
00895   return NS_OK;
00896 }
00897 
00898 nsresult nsRange::GetCollapsed(PRBool* aIsCollapsed)
00899 {
00900   if(IsDetached())
00901     return NS_ERROR_DOM_INVALID_STATE_ERR;
00902   if (!mIsPositioned)
00903     return NS_ERROR_NOT_INITIALIZED;
00904 
00905   if (mEndParent == 0 ||
00906       (mStartParent == mEndParent && mStartOffset == mEndOffset))
00907     *aIsCollapsed = PR_TRUE;
00908   else
00909     *aIsCollapsed = PR_FALSE;
00910   return NS_OK;
00911 }
00912 
00913 nsresult nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
00914 { 
00915   if(IsDetached())
00916     return NS_ERROR_DOM_INVALID_STATE_ERR;
00917 
00918   return nsContentUtils::GetCommonAncestor(mStartParent, mEndParent, aCommonParent);
00919 }
00920 
00921 nsresult nsRange::SetStart(nsIDOMNode* aParent, PRInt32 aOffset)
00922 {
00923   VALIDATE_ACCESS(aParent);
00924   
00925   PRInt32 len = GetNodeLength(aParent);
00926   if ( (aOffset < 0) || (len < 0) || (aOffset > len) )
00927     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00928     
00929   if (mIsPositioned) {
00930     // if not in the same document as the endpoint,
00931     // collapse the endpoint to the new start.
00932     if (!nsContentUtils::InSameDoc(aParent, mEndParent)) {
00933       return DoSetRange(aParent, aOffset, aParent, aOffset);
00934     }
00935 
00936     // the start must be before the end
00937     if (!IsIncreasing(aParent, aOffset, mEndParent, mEndOffset)) {
00938       return NS_ERROR_ILLEGAL_VALUE;
00939     }
00940   }
00941 
00942   // if it's in an attribute node, end must be in or descended from same node
00943   // XXX write me!
00944 
00945   return DoSetRange(aParent, aOffset, mEndParent, mEndOffset);
00946 }
00947 
00948 nsresult nsRange::SetStartBefore(nsIDOMNode* aSibling)
00949 {
00950   VALIDATE_ACCESS(aSibling);
00951   
00952   nsCOMPtr<nsIDOMNode> nParent;
00953   nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent));
00954   if (NS_FAILED(res) || !nParent) return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
00955   PRInt32 indx = IndexOf(aSibling);
00956   return SetStart(nParent,indx);
00957 }
00958 
00959 nsresult nsRange::SetStartAfter(nsIDOMNode* aSibling)
00960 {
00961   VALIDATE_ACCESS(aSibling);
00962 
00963   nsCOMPtr<nsIDOMNode> nParent;
00964   nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent));
00965   if (NS_FAILED(res) || !nParent) return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
00966   PRInt32 indx = IndexOf(aSibling) + 1;
00967   return SetStart(nParent,indx);
00968 }
00969 
00970 nsresult nsRange::SetEnd(nsIDOMNode* aParent, PRInt32 aOffset)
00971 {
00972   VALIDATE_ACCESS(aParent);
00973   
00974   PRInt32 len = GetNodeLength(aParent);
00975   if ( (aOffset < 0) || (len < 0) || (aOffset > len) )
00976     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00977     
00978   nsresult res;
00979   
00980   nsCOMPtr<nsIDOMNode>theParent( do_QueryInterface(aParent) );
00981   
00982   // must be in same document as startpoint, else 
00983   // endpoint is collapsed to new end.
00984   if (mIsPositioned && !nsContentUtils::InSameDoc(theParent,mStartParent))
00985   {
00986     res = DoSetRange(theParent,aOffset,theParent,aOffset);
00987     return res;
00988   }
00989   // start must be before end
00990   if (mIsPositioned && !IsIncreasing(mStartParent,mStartOffset,theParent,aOffset))
00991     return NS_ERROR_ILLEGAL_VALUE;
00992   // if it's in an attribute node, start must be in or descended from same node
00993   // (haven't done this one yet)
00994   
00995   res = DoSetRange(mStartParent,mStartOffset,theParent,aOffset);
00996   return res;
00997 }
00998 
00999 nsresult nsRange::SetEndBefore(nsIDOMNode* aSibling)
01000 {
01001   VALIDATE_ACCESS(aSibling);
01002   
01003   nsCOMPtr<nsIDOMNode> nParent;
01004   nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent));
01005   if (NS_FAILED(res) || !nParent) return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
01006   PRInt32 indx = IndexOf(aSibling);
01007   return SetEnd(nParent,indx);
01008 }
01009 
01010 nsresult nsRange::SetEndAfter(nsIDOMNode* aSibling)
01011 {
01012   VALIDATE_ACCESS(aSibling);
01013   
01014   nsCOMPtr<nsIDOMNode> nParent;
01015   nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent));
01016   if (NS_FAILED(res) || !nParent) return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
01017   PRInt32 indx = IndexOf(aSibling) + 1;
01018   return SetEnd(nParent,indx);
01019 }
01020 
01021 nsresult nsRange::Collapse(PRBool aToStart)
01022 {
01023   if(IsDetached())
01024     return NS_ERROR_DOM_INVALID_STATE_ERR;
01025   if (!mIsPositioned)
01026     return NS_ERROR_NOT_INITIALIZED;
01027 
01028   if (aToStart)
01029     return DoSetRange(mStartParent,mStartOffset,mStartParent,mStartOffset);
01030   else
01031     return DoSetRange(mEndParent,mEndOffset,mEndParent,mEndOffset);
01032 }
01033 
01034 nsresult nsRange::SelectNode(nsIDOMNode* aN)
01035 {
01036   VALIDATE_ACCESS(aN);
01037   
01038   nsCOMPtr<nsIDOMNode> parent;
01039   PRInt32 start, end;
01040 
01041   PRUint16 type = 0;
01042   aN->GetNodeType(&type);
01043 
01044   switch (type) {
01045     case nsIDOMNode::ATTRIBUTE_NODE :
01046     case nsIDOMNode::ENTITY_NODE :
01047     case nsIDOMNode::DOCUMENT_NODE :
01048     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE :
01049     case nsIDOMNode::NOTATION_NODE :
01050       return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
01051   }
01052 
01053   nsresult res;
01054   res = aN->GetParentNode(getter_AddRefs(parent));
01055   if(NS_SUCCEEDED(res) && parent)
01056   {
01057     nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(parent));
01058     if(doc)
01059     {
01060       nsCOMPtr<nsIContent>content(do_QueryInterface(aN));
01061       if(!content)
01062         return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
01063       parent = aN;//parent is now equal to the node you passed in
01064       // which is the root.  start is zero, end is the number of children
01065       start = 0;
01066       end = content->GetChildCount();
01067     }
01068     else
01069     {
01070       start = IndexOf(aN);
01071       end = start + 1;
01072     }
01073     return DoSetRange(parent,start,parent,end);
01074   }
01075   return NS_ERROR_DOM_RANGE_INVALID_NODE_TYPE_ERR;
01076 }
01077 
01078 nsresult nsRange::SelectNodeContents(nsIDOMNode* aN)
01079 {
01080   VALIDATE_ACCESS(aN);
01081   
01082   nsCOMPtr<nsIDOMNode> theNode( do_QueryInterface(aN) );
01083   nsCOMPtr<nsIDOMNodeList> aChildNodes;
01084   
01085   nsresult res = aN->GetChildNodes(getter_AddRefs(aChildNodes));
01086   if (NS_FAILED(res))
01087     return res;
01088   if (!aChildNodes)
01089     return NS_ERROR_UNEXPECTED;
01090   PRUint32 indx;
01091   res = aChildNodes->GetLength(&indx);
01092   if (NS_FAILED(res))
01093     return res;
01094   return DoSetRange(theNode,0,theNode,indx);
01095 }
01096 
01097 #ifdef XP_MAC
01098 #pragma mark -
01099 #pragma mark  class RangeSubtreeIterator
01100 #pragma mark -
01101 #endif
01102 
01103 // The Subtree Content Iterator only returns subtrees that are
01104 // completely within a given range. It doesn't return a CharacterData
01105 // node that contains either the start or end point of the range.
01106 // We need an iterator that will also include these start/end points
01107 // so that our methods/algorithms aren't cluttered with special
01108 // case code that tries to include these points while iterating.
01109 //
01110 // The RangeSubtreeIterator class mimics the nsIContentIterator
01111 // methods we need, so should the Content Iterator support the
01112 // start/end points in the future, we can switchover relatively
01113 // easy.
01114 
01115 class RangeSubtreeIterator
01116 {
01117 private:
01118 
01119   enum RangeSubtreeIterState { eDone=0,
01120                                eUseStartCData,
01121                                eUseIterator,
01122                                eUseEndCData };
01123 
01124   nsCOMPtr<nsIContentIterator>  mIter;
01125   RangeSubtreeIterState         mIterState;
01126 
01127   nsCOMPtr<nsIDOMCharacterData> mStartCData;
01128   nsCOMPtr<nsIDOMCharacterData> mEndCData;
01129 
01130 public:
01131 
01132   RangeSubtreeIterator()
01133     : mIterState(eDone)
01134   {
01135   }
01136   ~RangeSubtreeIterator()
01137   {
01138   }
01139 
01140   nsresult Init(nsIDOMRange *aRange);
01141   already_AddRefed<nsIDOMNode> GetCurrentNode();
01142   void First();
01143   void Last();
01144   void Next();
01145   void Prev();
01146 
01147   PRBool IsDone()
01148   {
01149     return mIterState == eDone;
01150   }
01151 };
01152 
01153 nsresult
01154 RangeSubtreeIterator::Init(nsIDOMRange *aRange)
01155 {
01156   mIterState = eDone;
01157 
01158   nsCOMPtr<nsIDOMNode> node;
01159 
01160   // Grab the start point of the range and QI it to
01161   // a CharacterData pointer. If it is CharacterData store
01162   // a pointer to the node.
01163 
01164   nsresult res = aRange->GetStartContainer(getter_AddRefs(node));
01165   if (!node) return NS_ERROR_FAILURE;
01166 
01167   mStartCData = do_QueryInterface(node);
01168 
01169   // Grab the end point of the range and QI it to
01170   // a CharacterData pointer. If it is CharacterData store
01171   // a pointer to the node.
01172 
01173   res = aRange->GetEndContainer(getter_AddRefs(node));
01174   if (!node) return NS_ERROR_FAILURE;
01175 
01176   mEndCData = do_QueryInterface(node);
01177 
01178   if (mStartCData && mStartCData == mEndCData)
01179   {
01180     // The range starts and stops in the same CharacterData
01181     // node. Null out the end pointer so we only visit the
01182     // node once!
01183 
01184     mEndCData = nsnull;
01185   }
01186   else
01187   {
01188     // Now create a Content Subtree Iterator to be used
01189     // for the subtrees between the end points!
01190 
01191     res = NS_NewContentSubtreeIterator(getter_AddRefs(mIter));
01192     if (NS_FAILED(res)) return res;
01193 
01194     res = mIter->Init(aRange);
01195     if (NS_FAILED(res)) return res;
01196 
01197     if (mIter->IsDone())
01198     {
01199       // The subtree iterator thinks there's nothing
01200       // to iterate over, so just free it up so we
01201       // don't accidentally call into it.
01202 
01203       mIter = nsnull;
01204     }
01205   }
01206 
01207   // Initialize the iterator by calling First().
01208   // Note that we are ignoring the return value on purpose!
01209 
01210   First();
01211 
01212   return NS_OK;
01213 }
01214 
01215 already_AddRefed<nsIDOMNode>
01216 RangeSubtreeIterator::GetCurrentNode()
01217 {
01218   nsIDOMNode *node = nsnull;
01219 
01220   if (mIterState == eUseStartCData && mStartCData) {
01221     NS_ADDREF(node = mStartCData);
01222   } else if (mIterState == eUseEndCData && mEndCData)
01223     NS_ADDREF(node = mEndCData);
01224   else if (mIterState == eUseIterator && mIter)
01225   {
01226     nsIContent *content = mIter->GetCurrentNode();
01227 
01228     if (content) {
01229       CallQueryInterface(content, &node);
01230     }
01231   }
01232 
01233   return node;
01234 }
01235 
01236 void
01237 RangeSubtreeIterator::First()
01238 {
01239   if (mStartCData)
01240     mIterState = eUseStartCData;
01241   else if (mIter)
01242   {
01243     mIter->First();
01244 
01245     mIterState = eUseIterator;
01246   }
01247   else if (mEndCData)
01248     mIterState = eUseEndCData;
01249   else
01250     mIterState = eDone;
01251 }
01252 
01253 void
01254 RangeSubtreeIterator::Last()
01255 {
01256   if (mEndCData)
01257     mIterState = eUseEndCData;
01258   else if (mIter)
01259   {
01260     mIter->Last();
01261 
01262     mIterState = eUseIterator;
01263   }
01264   else if (mStartCData)
01265     mIterState = eUseStartCData;
01266   else
01267     mIterState = eDone;
01268 }
01269 
01270 void
01271 RangeSubtreeIterator::Next()
01272 {
01273   if (mIterState == eUseStartCData)
01274   {
01275     if (mIter)
01276     {
01277       mIter->First();
01278 
01279       mIterState = eUseIterator;
01280     }
01281     else if (mEndCData)
01282       mIterState = eUseEndCData;
01283     else
01284       mIterState = eDone;
01285   }
01286   else if (mIterState == eUseIterator)
01287   {
01288     mIter->Next();
01289 
01290     if (mIter->IsDone())
01291     {
01292       if (mEndCData)
01293         mIterState = eUseEndCData;
01294       else
01295         mIterState = eDone;
01296     }
01297   }
01298   else
01299     mIterState = eDone;
01300 }
01301 
01302 void
01303 RangeSubtreeIterator::Prev()
01304 {
01305   if (mIterState == eUseEndCData)
01306   {
01307     if (mIter)
01308     {
01309       mIter->Last();
01310 
01311       mIterState = eUseIterator;
01312     }
01313     else if (mStartCData)
01314       mIterState = eUseStartCData;
01315     else
01316       mIterState = eDone;
01317   }
01318   else if (mIterState == eUseIterator)
01319   {
01320     mIter->Prev();
01321 
01322     if (mIter->IsDone())
01323     {
01324       if (mStartCData)
01325         mIterState = eUseStartCData;
01326       else
01327         mIterState = eDone;
01328     }
01329   }
01330   else
01331     mIterState = eDone;
01332 }
01333 
01334 
01335 // CollapseRangeAfterDelete() is a utiltiy method that is used by
01336 // DeleteContents() and ExtractContents() to collapse the range
01337 // in the correct place, under the range's root container (the
01338 // range end points common container) as outlined by the Range spec:
01339 //
01340 // http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/ranges.html
01341 // The assumption made by this method is that the delete or extract
01342 // has been done already, and left the range in a state where there is
01343 // no content between the 2 end points.
01344 
01345 nsresult nsRange::CollapseRangeAfterDelete(nsIDOMRange *aRange)
01346 {
01347   NS_ENSURE_ARG_POINTER(aRange);
01348 
01349   // Check if range gravity took care of collapsing the range for us!
01350 
01351   PRBool isCollapsed = PR_FALSE;
01352   nsresult res = aRange->GetCollapsed(&isCollapsed);
01353   if (NS_FAILED(res)) return res;
01354 
01355   if (isCollapsed)
01356   {
01357     // aRange is collapsed so there's nothing for us to do.
01358     //
01359     // There are 2 possible scenarios here:
01360     //
01361     // 1. aRange could've been collapsed prior to the delete/extract,
01362     //    which would've resulted in nothing being removed, so aRange
01363     //    is already where it should be.
01364     //
01365     // 2. Prior to the delete/extract, aRange's start and end were in
01366     //    the same container which would mean everything between them
01367     //    was removed, causing range gravity to collapse the range.
01368 
01369     return NS_OK;
01370   }
01371 
01372   // aRange isn't collapsed so figure out the appropriate place to collapse!
01373   // First get both end points and their common ancestor.
01374 
01375   nsCOMPtr<nsIDOMNode> commonAncestor;
01376   res = aRange->GetCommonAncestorContainer(getter_AddRefs(commonAncestor));
01377   if(NS_FAILED(res)) return res;
01378 
01379   nsCOMPtr<nsIDOMNode> startContainer, endContainer;
01380 
01381   res = aRange->GetStartContainer(getter_AddRefs(startContainer));
01382   if (NS_FAILED(res)) return res;
01383 
01384   res = aRange->GetEndContainer(getter_AddRefs(endContainer));
01385   if (NS_FAILED(res)) return res;
01386 
01387   // Collapse to one of the end points if they are already in the
01388   // commonAncestor. This should work ok since this method is called
01389   // immediately after a delete or extract that leaves no content
01390   // between the 2 end points!
01391 
01392   if (startContainer == commonAncestor)
01393     return aRange->Collapse(PR_TRUE);
01394   if (endContainer == commonAncestor)
01395     return aRange->Collapse(PR_FALSE);
01396 
01397   // End points are at differing levels. We want to collapse to the
01398   // point that is between the 2 subtrees that contain each point,
01399   // under the common ancestor.
01400 
01401   nsCOMPtr<nsIDOMNode> nodeToSelect(startContainer), parent;
01402 
01403   while (nodeToSelect)
01404   {
01405     nsresult res = nodeToSelect->GetParentNode(getter_AddRefs(parent));
01406     if (NS_FAILED(res)) return res;
01407 
01408     if (parent == commonAncestor)
01409       break; // We found the nodeToSelect!
01410 
01411     nodeToSelect = parent;
01412   }
01413 
01414   if (!nodeToSelect)
01415     return NS_ERROR_FAILURE; // This should never happen!
01416 
01417   res = aRange->SelectNode(nodeToSelect);
01418   if (NS_FAILED(res)) return res;
01419 
01420   return aRange->Collapse(PR_FALSE);
01421 }
01422 
01423 nsresult nsRange::DeleteContents()
01424 { 
01425   if(IsDetached())
01426     return NS_ERROR_DOM_INVALID_STATE_ERR;
01427 
01428   // Save the range end points locally to avoid interference
01429   // of Range gravity during our edits!
01430 
01431   nsCOMPtr<nsIDOMNode> startContainer(mStartParent);
01432   PRInt32              startOffset = mStartOffset;
01433   nsCOMPtr<nsIDOMNode> endContainer(mEndParent);
01434   PRInt32              endOffset = mEndOffset;
01435 
01436   // Create and initialize a subtree iterator that will give
01437   // us all the subtrees within the range.
01438 
01439   RangeSubtreeIterator iter;
01440 
01441   nsresult res = iter.Init(this);
01442   if (NS_FAILED(res)) return res;
01443 
01444   if (iter.IsDone())
01445   {
01446     // There's nothing for us to delete.
01447     return CollapseRangeAfterDelete(this);
01448   }
01449 
01450   // We delete backwards to avoid iterator problems!
01451 
01452   iter.Last();
01453 
01454   PRBool handled = PR_FALSE;
01455 
01456   // With the exception of text nodes that contain one of the range
01457   // end points, the subtree iterator should only give us back subtrees
01458   // that are completely contained between the range's end points.
01459 
01460   while (!iter.IsDone())
01461   {
01462     nsCOMPtr<nsIDOMNode> node(iter.GetCurrentNode());
01463 
01464     // Before we delete anything, advance the iterator to the
01465     // next subtree.
01466 
01467     iter.Prev();
01468 
01469     handled = PR_FALSE;
01470 
01471     // If it's CharacterData, make sure we might need to delete
01472     // part of the data, instead of removing the whole node.
01473     //
01474     // XXX_kin: We need to also handle ProcessingInstruction
01475     // XXX_kin: according to the spec.
01476 
01477     nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(node));
01478 
01479     if (charData)
01480     {
01481       PRUint32 dataLength = 0;
01482 
01483       if (node == startContainer)
01484       {
01485         if (node == endContainer)
01486         {
01487           // This range is completely contained within a single text node.
01488           // Delete the data between startOffset and endOffset.
01489 
01490           if (endOffset > startOffset)
01491           {
01492             res = charData->DeleteData(startOffset, endOffset - startOffset);
01493             if (NS_FAILED(res)) return res;
01494           }
01495 
01496           handled = PR_TRUE;
01497         }
01498         else
01499         {
01500           // Delete everything after startOffset.
01501 
01502           res = charData->GetLength(&dataLength);
01503           if (NS_FAILED(res)) return res;
01504 
01505           if (dataLength > (PRUint32)startOffset)
01506           {
01507             res = charData->DeleteData(startOffset, dataLength - startOffset);
01508             if (NS_FAILED(res)) return res;
01509           }
01510 
01511           handled = PR_TRUE;
01512         }
01513       }
01514       else if (node == endContainer)
01515       {
01516         // Delete the data between 0 and endOffset.
01517 
01518         if (endOffset > 0)
01519         {
01520           res = charData->DeleteData(0, endOffset);
01521           if (NS_FAILED(res)) return res;
01522         }
01523 
01524         handled = PR_TRUE;
01525       }       
01526     }
01527 
01528     if (!handled)
01529     {
01530       // node was not handled above, so it must be completely contained
01531       // within the range. Just remove it from the tree!
01532 
01533       nsCOMPtr<nsIDOMNode> parent, tmpNode;
01534 
01535       node->GetParentNode(getter_AddRefs(parent));
01536 
01537       if (parent) {
01538         res = parent->RemoveChild(node, getter_AddRefs(tmpNode));
01539         if (NS_FAILED(res)) return res;
01540       }
01541     }
01542   }
01543 
01544   // XXX_kin: At this point we should be checking for the case
01545   // XXX_kin: where we have 2 adjacent text nodes left, each
01546   // XXX_kin: containing one of the range end points. The spec
01547   // XXX_kin: says the 2 nodes should be merged in that case,
01548   // XXX_kin: and to use Normalize() to do the merging, but
01549   // XXX_kin: calling Normalize() on the common parent to accomplish
01550   // XXX_kin: this might also normalize nodes that are outside the
01551   // XXX_kin: range but under the common parent. Need to verify
01552   // XXX_kin: with the range commitee members that this was the
01553   // XXX_kin: desired behavior. For now we don't merge anything!
01554 
01555   return CollapseRangeAfterDelete(this);
01556 }
01557 
01558 NS_IMETHODIMP
01559 nsRange::CompareBoundaryPoints(PRUint16 how, nsIDOMRange* srcRange,
01560                                PRInt16* aCmpRet)
01561 {
01562   if(IsDetached())
01563     return NS_ERROR_DOM_INVALID_STATE_ERR;
01564 
01565   nsresult res;
01566   if (aCmpRet == 0)
01567     return NS_ERROR_NULL_POINTER;
01568   if (srcRange == 0)
01569     return NS_ERROR_INVALID_ARG;
01570 
01571   nsCOMPtr<nsIDOMNode> boundaryNode;  // the Invoking range
01572   nsCOMPtr<nsIDOMNode> sourceNode;    // the sourceRange
01573   PRInt32 boundaryOffset, sourceOffset;
01574 
01575   switch (how)
01576   {
01577   case nsIDOMRange::START_TO_START: // where is the start point of boundary range
01578     boundaryNode = mStartParent;    // relative to the start point of the source range?
01579     boundaryOffset = mStartOffset;
01580     res = srcRange->GetStartContainer(getter_AddRefs(sourceNode));
01581     if (NS_SUCCEEDED(res))
01582       res = srcRange->GetStartOffset(&sourceOffset);
01583     break;
01584   case nsIDOMRange::START_TO_END: // where is the end point of the boundary range
01585     boundaryNode = mEndParent;  // relative to the start point of source range?
01586     boundaryOffset = mEndOffset;
01587     res = srcRange->GetStartContainer(getter_AddRefs(sourceNode));
01588     if (NS_SUCCEEDED(res))
01589       res = srcRange->GetStartOffset(&sourceOffset);
01590     break;
01591   case nsIDOMRange::END_TO_START: // where is the the start point of the boundary range
01592     boundaryNode = mStartParent;    // relative to end point of source range?
01593     boundaryOffset = mStartOffset;
01594     res = srcRange->GetEndContainer(getter_AddRefs(sourceNode));
01595     if (NS_SUCCEEDED(res))
01596       res = srcRange->GetEndOffset(&sourceOffset);
01597     break;
01598   case nsIDOMRange::END_TO_END: // where is the end point of boundary range
01599     boundaryNode = mEndParent;  // relative to the end point of the source range?
01600     boundaryOffset = mEndOffset;
01601     res = srcRange->GetEndContainer(getter_AddRefs(sourceNode));
01602     if (NS_SUCCEEDED(res))
01603       res = srcRange->GetEndOffset(&sourceOffset);
01604     break;
01605 
01606   default:  // shouldn't get here
01607     return NS_ERROR_ILLEGAL_VALUE;
01608   }
01609 
01610   if (NS_FAILED(res))
01611     return res;
01612 
01613   if ((boundaryNode == sourceNode) && (boundaryOffset == sourceOffset))
01614     *aCmpRet = 0;//then the points are equal
01615   else if (IsIncreasing(boundaryNode, boundaryOffset, sourceNode, sourceOffset))
01616       *aCmpRet = -1;//then boundary point is before source point
01617   else
01618       *aCmpRet = 1;//then boundary point is after source point
01619 
01620   return NS_OK;
01621 }
01622 
01623 nsresult nsRange::ExtractContents(nsIDOMDocumentFragment** aReturn)
01624 { 
01625   if(IsDetached())
01626     return NS_ERROR_DOM_INVALID_STATE_ERR;
01627 
01628   // XXX_kin: The spec says that nodes that are completely in the
01629   // XXX_kin: range should be moved into the document fragment, not
01630   // XXX_kin: copied. This method will have to be rewritten using
01631   // XXX_kin: DeleteContents() as a template, with the charData cloning
01632   // XXX_kin: code from CloneContents() merged in.
01633 
01634   nsresult res = CloneContents(aReturn);
01635   if (NS_FAILED(res))
01636     return res;
01637   res = DeleteContents();
01638   return res; 
01639 }
01640 
01641 nsresult nsRange::CloneParentsBetween(nsIDOMNode *aAncestor,
01642                              nsIDOMNode *aNode,
01643                              nsIDOMNode **aClosestAncestor,
01644                              nsIDOMNode **aFarthestAncestor)
01645 {
01646   NS_ENSURE_ARG_POINTER((aAncestor && aNode && aClosestAncestor && aFarthestAncestor));
01647 
01648   *aClosestAncestor  = nsnull;
01649   *aFarthestAncestor = nsnull;
01650 
01651   if (aAncestor == aNode)
01652     return NS_OK;
01653 
01654   nsCOMPtr<nsIDOMNode> parent, firstParent, lastParent;
01655 
01656   nsresult res = aNode->GetParentNode(getter_AddRefs(parent));
01657 
01658   while(parent && parent != aAncestor)
01659   {
01660     nsCOMPtr<nsIDOMNode> clone, tmpNode;
01661 
01662     res = parent->CloneNode(PR_FALSE, getter_AddRefs(clone));
01663 
01664     if (NS_FAILED(res)) return res;
01665     if (!clone)         return NS_ERROR_FAILURE;
01666 
01667     if (! firstParent)
01668       firstParent = lastParent = clone;
01669     else
01670     {
01671       res = clone->AppendChild(lastParent, getter_AddRefs(tmpNode));
01672 
01673       if (NS_FAILED(res)) return res;
01674 
01675       lastParent = clone;
01676     }
01677 
01678     tmpNode = parent;
01679     res = tmpNode->GetParentNode(getter_AddRefs(parent));
01680   }
01681 
01682   *aClosestAncestor  = firstParent;
01683   NS_IF_ADDREF(*aClosestAncestor);
01684 
01685   *aFarthestAncestor = lastParent;
01686   NS_IF_ADDREF(*aFarthestAncestor);
01687 
01688   return NS_OK;
01689 }
01690 
01691 nsresult nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
01692 {
01693   if (IsDetached())
01694     return NS_ERROR_DOM_INVALID_STATE_ERR;
01695 
01696   nsresult res;
01697   nsCOMPtr<nsIDOMNode> commonAncestor;
01698   res = GetCommonAncestorContainer(getter_AddRefs(commonAncestor));
01699   if (NS_FAILED(res)) return res;
01700 
01701   nsCOMPtr<nsIDOMDocument> document;
01702   res = mStartParent->GetOwnerDocument(getter_AddRefs(document));
01703   if (NS_FAILED(res)) return res;
01704 
01705   if (!document) {
01706     document = do_QueryInterface(mStartParent);
01707   }
01708 
01709   NS_ASSERTION(document, "CloneContents needs a document to continue.");
01710   if (!document) return NS_ERROR_FAILURE;
01711 
01712   // Create a new document fragment in the context of this document,
01713   // which might be null
01714 
01715   nsCOMPtr<nsIDOMDocumentFragment> clonedFrag;
01716 
01717   nsCOMPtr<nsIDocument> doc(do_QueryInterface(document));
01718 
01719   res = NS_NewDocumentFragment(getter_AddRefs(clonedFrag),
01720                                doc->NodeInfoManager());
01721   if (NS_FAILED(res)) return res;
01722 
01723   nsCOMPtr<nsIDOMNode> commonCloneAncestor(do_QueryInterface(clonedFrag));
01724   if (!commonCloneAncestor) return NS_ERROR_FAILURE;
01725 
01726   // Create and initialize a subtree iterator that will give
01727   // us all the subtrees within the range.
01728 
01729   RangeSubtreeIterator iter;
01730 
01731   res = iter.Init(this);
01732   if (NS_FAILED(res)) return res;
01733 
01734   if (iter.IsDone())
01735   {
01736     // There's nothing to add to the doc frag, we must be done!
01737 
01738     *aReturn = clonedFrag;
01739     NS_IF_ADDREF(*aReturn);
01740     return NS_OK;
01741   }
01742 
01743   iter.First();
01744 
01745   // With the exception of text nodes that contain one of the range
01746   // end points, the subtree iterator should only give us back subtrees
01747   // that are completely contained between the range's end points.
01748   //
01749   // Unfortunately these subtrees don't contain the parent hierarchy/context
01750   // that the Range spec requires us to return. This loop clones the
01751   // parent hierarchy, adds a cloned version of the subtree, to it, then
01752   // correctly places this new subtree into the doc fragment.
01753 
01754   while (!iter.IsDone())
01755   {
01756     nsCOMPtr<nsIDOMNode> node(iter.GetCurrentNode());
01757     // Clone the current subtree!
01758 
01759     nsCOMPtr<nsIDOMNode> clone;
01760     res = node->CloneNode(PR_TRUE, getter_AddRefs(clone));
01761     if (NS_FAILED(res)) return res;
01762 
01763     // If it's CharacterData, make sure we only clone what
01764     // is in the range.
01765     //
01766     // XXX_kin: We need to also handle ProcessingInstruction
01767     // XXX_kin: according to the spec.
01768 
01769     nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(clone));
01770 
01771     if (charData)
01772     {
01773       if (node == mEndParent)
01774       {
01775         // We only need the data before mEndOffset, so get rid of any
01776         // data after it.
01777 
01778         PRUint32 dataLength = 0;
01779         res = charData->GetLength(&dataLength);
01780         if (NS_FAILED(res)) return res;
01781 
01782         if (dataLength > (PRUint32)mEndOffset)
01783         {
01784           res = charData->DeleteData(mEndOffset, dataLength - mEndOffset);
01785           if (NS_FAILED(res)) return res;
01786         }
01787       }       
01788 
01789       if (node == mStartParent)
01790       {
01791         // We don't need any data before mStartOffset, so just
01792         // delete it!
01793 
01794         if (mStartOffset > 0)
01795         {
01796           res = charData->DeleteData(0, mStartOffset);
01797           if (NS_FAILED(res)) return res;
01798         }
01799       }
01800     }
01801 
01802     // Clone the parent hierarchy between commonAncestor and node.
01803 
01804     nsCOMPtr<nsIDOMNode> closestAncestor, farthestAncestor;
01805 
01806     res = CloneParentsBetween(commonAncestor, node,
01807                               getter_AddRefs(closestAncestor),
01808                               getter_AddRefs(farthestAncestor));
01809 
01810     if (NS_FAILED(res)) return res;
01811 
01812     // Hook the parent hierarchy/context of the subtree into the clone tree.
01813 
01814     nsCOMPtr<nsIDOMNode> tmpNode;
01815 
01816     if (farthestAncestor)
01817     {
01818       res = commonCloneAncestor->AppendChild(farthestAncestor,
01819                                              getter_AddRefs(tmpNode));
01820 
01821       if (NS_FAILED(res)) return res;
01822     }
01823 
01824     // Place the cloned subtree into the cloned doc frag tree!
01825 
01826     if (closestAncestor)
01827     {
01828       // Append the subtree under closestAncestor since it is the
01829       // immediate parent of the subtree.
01830 
01831       res = closestAncestor->AppendChild(clone, getter_AddRefs(tmpNode));
01832     }
01833     else
01834     {
01835       // If we get here, there is no missing parent hierarchy between 
01836       // commonAncestor and node, so just append clone to commonCloneAncestor.
01837 
01838       res = commonCloneAncestor->AppendChild(clone, getter_AddRefs(tmpNode));
01839     }
01840     if (NS_FAILED(res)) return res;
01841 
01842     // Get the next subtree to be processed. The idea here is to setup
01843     // the parameters for the next iteration of the loop.
01844 
01845     iter.Next();
01846 
01847     if (iter.IsDone())
01848       break; // We must be done!
01849 
01850     nsCOMPtr<nsIDOMNode> nextNode(iter.GetCurrentNode());
01851     if (!nextNode) return NS_ERROR_FAILURE;
01852 
01853     // Get node and nextNode's common parent.
01854     nsContentUtils::GetCommonAncestor(node, nextNode, getter_AddRefs(commonAncestor));
01855 
01856     if (!commonAncestor)
01857       return NS_ERROR_FAILURE;
01858 
01859     // Find the equivalent of commonAncestor in the cloned tree!
01860 
01861     while (node && node != commonAncestor)
01862     {
01863       tmpNode = node;
01864       res = tmpNode->GetParentNode(getter_AddRefs(node));
01865       if (NS_FAILED(res)) return res;
01866       if (!node) return NS_ERROR_FAILURE;
01867 
01868       tmpNode = clone;
01869       res = tmpNode->GetParentNode(getter_AddRefs(clone));
01870       if (NS_FAILED(res)) return res;
01871       if (!node) return NS_ERROR_FAILURE;
01872     }
01873 
01874     commonCloneAncestor = clone;
01875   }
01876 
01877   *aReturn = clonedFrag;
01878   NS_IF_ADDREF(*aReturn);
01879 
01880   return NS_OK;
01881 }
01882 
01883 nsresult nsRange::CloneRange(nsIDOMRange** aReturn)
01884 {
01885   if(IsDetached())
01886     return NS_ERROR_DOM_INVALID_STATE_ERR;
01887 
01888   if (aReturn == 0)
01889     return NS_ERROR_NULL_POINTER;
01890 
01891   nsresult res = NS_NewRange(aReturn);
01892   if (NS_FAILED(res))
01893     return res;
01894 
01895   res = (*aReturn)->SetStart(mStartParent, mStartOffset);
01896   if (NS_FAILED(res))
01897     return res;
01898   
01899   res = (*aReturn)->SetEnd(mEndParent, mEndOffset);
01900   return res;
01901 }
01902 
01903 nsresult nsRange::InsertNode(nsIDOMNode* aN)
01904 {
01905   VALIDATE_ACCESS(aN);
01906   
01907   nsresult res;
01908   PRInt32 tStartOffset;
01909   this->GetStartOffset(&tStartOffset);
01910 
01911   nsCOMPtr<nsIDOMNode> tStartContainer;
01912   res = this->GetStartContainer(getter_AddRefs(tStartContainer));
01913   if(NS_FAILED(res)) return res;
01914 
01915   nsCOMPtr<nsIContent> startContent = do_QueryInterface(tStartContainer);
01916   NS_ENSURE_TRUE(!nsContentUtils::IsNativeAnonymous(startContent) ||
01917                  nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead"),
01918                  NS_ERROR_DOM_SECURITY_ERR);
01919 
01920   nsCOMPtr<nsIDOMText> startTextNode(do_QueryInterface(tStartContainer));
01921   if (startTextNode)
01922   {
01923     nsCOMPtr<nsIDOMNode> tSCParentNode;
01924     res = tStartContainer->GetParentNode(getter_AddRefs(tSCParentNode));
01925     if(NS_FAILED(res)) return res;
01926 
01927     nsCOMPtr<nsIDOMText> secondPart;
01928     res = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart));
01929     if (NS_FAILED(res)) return res;
01930     
01931     nsCOMPtr<nsIDOMNode> tResultNode;
01932     return tSCParentNode->InsertBefore(aN, secondPart, getter_AddRefs(tResultNode));
01933   }  
01934 
01935   nsCOMPtr<nsIDOMNodeList>tChildList;
01936   res = tStartContainer->GetChildNodes(getter_AddRefs(tChildList));
01937   if(NS_FAILED(res)) return res;
01938   PRUint32 tChildListLength;
01939   res = tChildList->GetLength(&tChildListLength);
01940   if(NS_FAILED(res)) return res;
01941 
01942   // find the insertion point in the DOM and insert the Node
01943   nsCOMPtr<nsIDOMNode>tChildNode;
01944   res = tChildList->Item(tStartOffset, getter_AddRefs(tChildNode));
01945   if(NS_FAILED(res)) return res;
01946   
01947   nsCOMPtr<nsIDOMNode> tResultNode;
01948   return tStartContainer->InsertBefore(aN, tChildNode, getter_AddRefs(tResultNode));
01949 }
01950 
01951 nsresult nsRange::SurroundContents(nsIDOMNode* aNewParent)
01952 {
01953   VALIDATE_ACCESS(aNewParent);
01954   
01955   // Extract the contents within the range.
01956 
01957   nsCOMPtr<nsIDOMDocumentFragment> docFrag;
01958 
01959   nsresult res = ExtractContents(getter_AddRefs(docFrag));
01960 
01961   if (NS_FAILED(res)) return res;
01962   if (!docFrag) return NS_ERROR_FAILURE;
01963 
01964   // Spec says we need to remove all of aNewParent's
01965   // children prior to insertion.
01966 
01967   nsCOMPtr<nsIDOMNodeList> children;
01968   res = aNewParent->GetChildNodes(getter_AddRefs(children));
01969 
01970   if (NS_FAILED(res)) return res;
01971   if (!children) return NS_ERROR_FAILURE;
01972 
01973   PRUint32 numChildren = 0;
01974   res = children->GetLength(&numChildren);
01975   if (NS_FAILED(res)) return res;
01976 
01977   nsCOMPtr<nsIDOMNode> tmpNode;
01978 
01979   while (numChildren)
01980   {
01981     nsCOMPtr<nsIDOMNode> child;
01982     res = children->Item(--numChildren, getter_AddRefs(child));
01983 
01984     if (NS_FAILED(res)) return res;
01985     if (!child) return NS_ERROR_FAILURE;
01986 
01987     res = aNewParent->RemoveChild(child, getter_AddRefs(tmpNode));
01988     if (NS_FAILED(res)) return res;
01989   }
01990 
01991   // Insert aNewParent at the range's start point.
01992 
01993   res = InsertNode(aNewParent);
01994   if (NS_FAILED(res)) return res;
01995 
01996   // Append the content we extracted under aNewParent.
01997 
01998   res = aNewParent->AppendChild(docFrag, getter_AddRefs(tmpNode));
01999   if (NS_FAILED(res)) return res;
02000 
02001   // Select aNewParent, and its contents.
02002 
02003   return SelectNode(aNewParent);
02004 }
02005 
02006 nsresult nsRange::ToString(nsAString& aReturn)
02007 { 
02008   if(IsDetached())
02009     return NS_ERROR_DOM_INVALID_STATE_ERR;
02010 
02011   nsCOMPtr<nsIContent> cStart( do_QueryInterface(mStartParent) );
02012   nsCOMPtr<nsIContent> cEnd( do_QueryInterface(mEndParent) );
02013   
02014   // clear the string
02015   aReturn.Truncate();
02016   
02017   // If we're unpositioned, return the empty string
02018   if (!cStart || !cEnd) {
02019     return NS_OK;
02020   }
02021 
02022 #ifdef DEBUG_range
02023       printf("Range dump: -----------------------\n");
02024 #endif /* DEBUG */
02025     
02026   // effeciency hack for simple case
02027   if (cStart == cEnd)
02028   {
02029     nsCOMPtr<nsIDOMText> textNode( do_QueryInterface(mStartParent) );
02030     
02031     if (textNode)
02032     {
02033 #ifdef DEBUG_range
02034       // If debug, dump it:
02035       nsCOMPtr<nsIContent> cN (do_QueryInterface(mStartParent));
02036       if (cN) cN->List(stdout);
02037       printf("End Range dump: -----------------------\n");
02038 #endif /* DEBUG */
02039 
02040       // grab the text
02041       if (NS_FAILED(textNode->SubstringData(mStartOffset,mEndOffset-mStartOffset,aReturn)))
02042         return NS_ERROR_UNEXPECTED;
02043       return NS_OK;
02044     }
02045   } 
02046   
02047   /* complex case: cStart != cEnd, or cStart not a text node
02048      revisit - there are potential optimizations here and also tradeoffs.
02049   */
02050 
02051   nsCOMPtr<nsIContentIterator> iter;
02052   NS_NewContentIterator(getter_AddRefs(iter));
02053   iter->Init(this);
02054   
02055   nsString tempString;
02056  
02057   // loop through the content iterator, which returns nodes in the range in 
02058   // close tag order, and grab the text from any text node
02059   while (!iter->IsDone())
02060   {
02061     nsIContent *cN = iter->GetCurrentNode();
02062 
02063 #ifdef DEBUG_range
02064     // If debug, dump it:
02065     cN->List(stdout);
02066 #endif /* DEBUG */
02067     nsCOMPtr<nsIDOMText> textNode( do_QueryInterface(cN) );
02068     if (textNode) // if it's a text node, get the text
02069     {
02070       if (cN == cStart) // only include text past start offset
02071       {
02072         PRUint32 strLength;
02073         textNode->GetLength(&strLength);
02074         textNode->SubstringData(mStartOffset,strLength-mStartOffset,tempString);
02075         aReturn += tempString;
02076       }
02077       else if (cN == cEnd)  // only include text before end offset
02078       {
02079         textNode->SubstringData(0,mEndOffset,tempString);
02080         aReturn += tempString;
02081       }
02082       else  // grab the whole kit-n-kaboodle
02083       {
02084         textNode->GetData(tempString);
02085         aReturn += tempString;
02086       }
02087     }
02088 
02089     iter->Next();
02090   }
02091 
02092 #ifdef DEBUG_range
02093   printf("End Range dump: -----------------------\n");
02094 #endif /* DEBUG */
02095   return NS_OK;
02096 }
02097 
02098 
02099 
02100 nsresult
02101 nsRange::Detach()
02102 {
02103   if(IsDetached())
02104     return NS_ERROR_DOM_INVALID_STATE_ERR;
02105   mIsDetached = PR_TRUE;
02106   return DoSetRange(nsnull,0,nsnull,0);
02107 }
02108 
02109 
02110 
02111 nsresult nsRange::OwnerGone(nsIContent* aDyingNode)
02112 {
02113   // nothing for now - should be impossible to getter here
02114   // No node should be deleted if it holds a range endpoint,
02115   // since the range endpoint addrefs the node.
02116   NS_ASSERTION(PR_FALSE,"Deleted content holds a range endpoint");  
02117   return NS_OK;
02118 }
02119   
02120 
02121 nsresult nsRange::OwnerChildInserted(nsIContent* aParentNode, PRInt32 aOffset)
02122 {
02123   // sanity check - null nodes shouldn't have enclosed ranges
02124   if (!aParentNode) return NS_ERROR_UNEXPECTED;
02125 
02126   nsCOMPtr<nsIContent> parent( do_QueryInterface(aParentNode) );
02127   // quick return if no range list
02128   const nsVoidArray *theRangeList = parent->GetRangeList();
02129   if (!theRangeList) return NS_OK;
02130 
02131   nsresult res;
02132 
02133   nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(parent));
02134   if (!domNode) return NS_ERROR_UNEXPECTED;
02135 
02136 
02137   PRInt32   count = theRangeList->Count();
02138   for (PRInt32 loop = 0; loop < count; loop++)
02139   {
02140     nsRange* theRange = NS_STATIC_CAST(nsRange*, (theRangeList->ElementAt(loop))); 
02141     NS_ASSERTION(theRange, "oops, no range");
02142 
02143     // sanity check - do range and content agree over ownership?
02144     res = theRange->ContentOwnsUs(domNode);
02145     NS_PRECONDITION(NS_SUCCEEDED(res), "range and content disagree over range ownership");
02146     if (NS_SUCCEEDED(res))
02147     {
02148       if (theRange->mStartParent == domNode)
02149       {
02150         // if child inserted before start, move start offset right one
02151         if (aOffset < theRange->mStartOffset) theRange->mStartOffset++;
02152       }
02153       if (theRange->mEndParent == domNode)
02154       {
02155         // if child inserted before end, move end offset right one
02156         if (aOffset < theRange->mEndOffset) theRange->mEndOffset++;
02157       }
02158       NS_PRECONDITION(NS_SUCCEEDED(res), "error updating range list");
02159     }
02160   }
02161   return NS_OK;
02162 }
02163   
02164 
02165 nsresult nsRange::OwnerChildRemoved(nsIContent* aParentNode, PRInt32 aOffset, nsIContent* aRemovedNode)
02166 {
02167   // sanity check - null nodes shouldn't have enclosed ranges
02168   if (!aParentNode) return NS_ERROR_UNEXPECTED;
02169 
02170   nsCOMPtr<nsIContent> parent( do_QueryInterface(aParentNode) );
02171   nsCOMPtr<nsIContent> removed( do_QueryInterface(aRemovedNode) );
02172 
02173   // any ranges in the content subtree rooted by aRemovedNode need to
02174   // have the enclosed endpoints promoted up to the parentNode/offset
02175   nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(parent));
02176   if (!domNode) return NS_ERROR_UNEXPECTED;
02177   nsresult res = PopRanges(domNode, aOffset, removed);
02178 
02179   // quick return if no range list
02180   const nsVoidArray *theRangeList = parent->GetRangeList();
02181   if (!theRangeList) return NS_OK;
02182   
02183   PRInt32   count = theRangeList->Count();
02184   for (PRInt32 loop = 0; loop < count; loop++)
02185   {
02186     nsRange* theRange = NS_STATIC_CAST(nsRange*, (theRangeList->ElementAt(loop))); 
02187     NS_ASSERTION(theRange, "oops, no range");
02188 
02189     // sanity check - do range and content agree over ownership?
02190     res = theRange->ContentOwnsUs(domNode);
02191     NS_PRECONDITION(NS_SUCCEEDED(res), "range and content disagree over range ownership");
02192     if (NS_SUCCEEDED(res))
02193     {
02194       if (theRange->mStartParent == domNode)
02195       {
02196         // if child deleted before start, move start offset left one
02197         if (aOffset < theRange->mStartOffset) theRange->mStartOffset--;
02198       }
02199       if (theRange->mEndParent == domNode)
02200       {
02201         // if child deleted before end, move end offset left one
02202         if (aOffset < theRange->mEndOffset) 
02203         {
02204           if (theRange->mEndOffset>0) theRange->mEndOffset--;
02205         }
02206       }
02207     }
02208   }
02209   
02210   return NS_OK;
02211 }
02212   
02213 
02214 nsresult nsRange::OwnerChildReplaced(nsIContent* aParentNode, PRInt32 aOffset, nsIContent* aReplacedNode)
02215 {
02216   // sanity check - null nodes shouldn't have enclosed ranges
02217   if (!aParentNode) return NS_ERROR_UNEXPECTED;
02218 
02219   // don't need to adjust ranges whose endpoints are in this parent,
02220   // but we do need to pop out any range endpoints inside the subtree
02221   // rooted by aReplacedNode.
02222   
02223   nsCOMPtr<nsIContent> parent( do_QueryInterface(aParentNode) );
02224   nsCOMPtr<nsIContent> replaced( do_QueryInterface(aReplacedNode) );
02225   nsCOMPtr<nsIDOMNode> parentDomNode( do_QueryInterface(parent) ); 
02226 
02227   if (!parentDomNode) return NS_ERROR_UNEXPECTED;
02228 
02229   return PopRanges(parentDomNode, aOffset, replaced);
02230 }
02231   
02232 
02233 nsresult
02234 nsRange::TextOwnerChanged(nsIContent* aTextNode, nsVoidArray *aRangeList,
02235                           PRInt32 aStartChanged, PRInt32 aEndChanged,
02236                           PRInt32 aReplaceLength)
02237 {
02238   NS_ASSERTION(aRangeList,
02239                "Don't call TextOwnerChanged if aTextNode is not in a range!");
02240   NS_ASSERTION(aTextNode, "Null nodes don't have enclosed ranges!");
02241 
02242   nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(aTextNode));
02243   if (!domNode) return NS_ERROR_UNEXPECTED;
02244 
02245   PRInt32   count = aRangeList->Count();
02246   for (PRInt32 loop = 0; loop < count; loop++)
02247   {
02248     nsRange* theRange = NS_STATIC_CAST(nsRange*, (aRangeList->ElementAt(loop))); 
02249     NS_ASSERTION(theRange, "oops, no range");
02250 
02251     // sanity check - do range and content agree over ownership?
02252     nsresult res = theRange->ContentOwnsUs(domNode);
02253     NS_PRECONDITION(NS_SUCCEEDED(res), "range and content disagree over range ownership");
02254     if (NS_SUCCEEDED(res))
02255     { 
02256       PRBool bStartPointInChangedText = PR_FALSE;
02257       
02258       if (theRange->mStartParent == domNode)
02259       {
02260         // if range start is inside changed text, position it after change
02261         if ((aStartChanged <= theRange->mStartOffset) && (aEndChanged >= theRange->mStartOffset))
02262         { 
02263           theRange->mStartOffset = aStartChanged+aReplaceLength;
02264           bStartPointInChangedText = PR_TRUE;
02265         }
02266         // else if text changed before start, adjust start offset
02267         else if (aEndChanged <= theRange->mStartOffset) 
02268           theRange->mStartOffset += aStartChanged + aReplaceLength - aEndChanged;
02269       }
02270       if (theRange->mEndParent == domNode)
02271       {
02272         // if range end is inside changed text, position it before change
02273         if ((aStartChanged <= theRange->mEndOffset) && (aEndChanged >= theRange->mEndOffset)) 
02274         {
02275           theRange->mEndOffset = aStartChanged;
02276           // hack: if BOTH range endpoints were inside the change, then they
02277           // both get collapsed to the beginning of the change.  
02278           if (bStartPointInChangedText) theRange->mStartOffset = aStartChanged;
02279         }
02280         // else if text changed before end, adjust end offset
02281         else if (aEndChanged <= theRange->mEndOffset) 
02282           theRange->mEndOffset += aStartChanged + aReplaceLength - aEndChanged;
02283       }
02284     }
02285   }
02286   
02287   return NS_OK;
02288 }
02289 
02290 
02291 // nsIDOMNSRange interface
02292 NS_IMETHODIMP    
02293 nsRange::CreateContextualFragment(const nsAString& aFragment, 
02294                                   nsIDOMDocumentFragment** aReturn)
02295 {
02296   if (!mIsPositioned) {
02297     return NS_ERROR_FAILURE;
02298   }
02299 
02300   // Create a new parser for this entire operation
02301   nsresult result;
02302   nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &result);
02303   NS_ENSURE_SUCCESS(result, result);
02304 
02305   nsCOMPtr<nsIDocument> document;
02306   nsCOMPtr<nsIDOMDocument> domDocument;
02307 
02308   result = mStartParent->GetOwnerDocument(getter_AddRefs(domDocument));
02309   if (domDocument && NS_SUCCEEDED(result)) {
02310     document = do_QueryInterface(domDocument, &result);
02311   }
02312 
02313   nsVoidArray tagStack;
02314   nsCOMPtr<nsIDOMNode> parent = mStartParent;
02315   while (parent && 
02316          (parent != domDocument) && 
02317          NS_SUCCEEDED(result)) {
02318     PRUint16 nodeType;
02319     
02320     parent->GetNodeType(&nodeType);
02321     if (nsIDOMNode::ELEMENT_NODE == nodeType) {
02322       PRInt32 namespaceID;
02323       nsAutoString tagName, uriStr;
02324       parent->GetNodeName(tagName);
02325 
02326       // see if we need to add xmlns declarations
02327       nsCOMPtr<nsIContent> content( do_QueryInterface(parent) );
02328       PRUint32 count = content->GetAttrCount();
02329       PRBool setDefaultNamespace = PR_FALSE;
02330       if (count > 0) {
02331         PRUint32 index;
02332         nsAutoString nameStr, prefixStr, valueStr;
02333         nsCOMPtr<nsIAtom> attrName, attrPrefix;
02334 
02335         for (index = 0; index < count; index++) {
02336     
02337           content->GetAttrNameAt(index,
02338                                 &namespaceID,
02339                                 getter_AddRefs(attrName),
02340                                 getter_AddRefs(attrPrefix));
02341     
02342           if (namespaceID == kNameSpaceID_XMLNS) {
02343             content->GetAttr(namespaceID, attrName, uriStr);
02344 
02345             // really want something like nsXMLContentSerializer::SerializeAttr()
02346             tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important
02347             if (attrPrefix) {
02348               tagName.Append(PRUnichar(':'));
02349               attrName->ToString(nameStr);
02350               tagName.Append(nameStr);
02351             }
02352             else {
02353               setDefaultNamespace = PR_TRUE;
02354             }
02355             tagName.Append(NS_LITERAL_STRING("=\"") + uriStr + NS_LITERAL_STRING("\""));
02356           }
02357         }
02358       }
02359       if (!setDefaultNamespace) {
02360         nsINodeInfo* info = content->GetNodeInfo();
02361         if (info && !info->GetPrefixAtom() &&
02362             info->NamespaceID() != kNameSpaceID_None) {
02363           // We have no namespace prefix, but have a namespace ID.  Push
02364           // default namespace attr in, so that our kids will be in our
02365           // namespace.
02366           nsAutoString uri;
02367           info->GetNamespaceURI(uri);
02368           tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uri +
02369                          NS_LITERAL_STRING("\""));
02370         }
02371       }
02372 
02373       // XXX Wish we didn't have to allocate here
02374       PRUnichar* name = ToNewUnicode(tagName);
02375       if (name) {
02376         tagStack.AppendElement(name);
02377         nsCOMPtr<nsIDOMNode> temp = parent;
02378         result = temp->GetParentNode(getter_AddRefs(parent));
02379       }
02380       else {
02381         result = NS_ERROR_OUT_OF_MEMORY;
02382       }
02383     }
02384     else {
02385       nsCOMPtr<nsIDOMNode> temp = parent;
02386       result = temp->GetParentNode(getter_AddRefs(parent));
02387     }
02388   }
02389 
02390   if (NS_SUCCEEDED(result)) {
02391     nsCAutoString contentType;
02392     PRBool bCaseSensitive = PR_TRUE;
02393     if (document) {
02394       nsAutoString buf;
02395       document->GetContentType(buf);
02396       CopyUCS2toASCII(buf, contentType);
02397       bCaseSensitive = document->IsCaseSensitive();
02398     }
02399     else {
02400       contentType.AssignLiteral("text/xml");
02401     }
02402 
02403     nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(domDocument));
02404     PRBool bHTML = htmlDoc && !bCaseSensitive;
02405     nsCOMPtr<nsIFragmentContentSink> sink;
02406     if (bHTML) {
02407       result = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink));
02408     } else {
02409       result = NS_NewXMLFragmentContentSink(getter_AddRefs(sink));
02410     }
02411     if (NS_SUCCEEDED(result)) {
02412       sink->SetTargetDocument(document);
02413       nsCOMPtr<nsIContentSink> contentsink( do_QueryInterface(sink) );
02414       parser->SetContentSink(contentsink);
02415 
02416       // If there's no JS or system JS running,
02417       // push the current document's context on the JS context stack
02418       // so that event handlers in the fragment do not get 
02419       // compiled with the system principal.
02420       nsCOMPtr<nsIJSContextStack> ContextStack;
02421       if (document) {
02422         nsCOMPtr<nsIPrincipal> sysPrin;
02423         nsCOMPtr<nsIPrincipal> subjectPrin;
02424 
02425         nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
02426 
02427         // Just to compare, not to use!
02428         result = secMan->GetSystemPrincipal(getter_AddRefs(sysPrin));
02429         if (NS_SUCCEEDED(result))
02430             result = secMan->GetSubjectPrincipal(getter_AddRefs(subjectPrin));
02431         // If there's no subject principal, there's no JS running, so we're in system code.
02432         // (just in case...null subject principal will probably never happen)
02433         if (NS_SUCCEEDED(result) &&
02434            (!subjectPrin || sysPrin.get() == subjectPrin.get())) {
02435           nsIScriptGlobalObject *globalObj = document->GetScriptGlobalObject();
02436           JSContext* cx = nsnull;
02437 
02438           if (globalObj) {
02439             nsIScriptContext *scriptContext = globalObj->GetContext();
02440 
02441             if (scriptContext) {
02442               cx = (JSContext*)scriptContext->GetNativeContext();
02443             }
02444           }
02445 
02446           if (cx) {
02447             ContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
02448             if (ContextStack) {
02449               result = ContextStack->Push(cx);
02450             }
02451           }
02452         }
02453       }
02454 
02455       nsDTDMode mode = eDTDMode_autodetect;
02456       nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(domDocument));
02457       if (bHTML) {
02458         switch (htmlDoc->GetCompatibilityMode()) {
02459           case eCompatibility_NavQuirks:
02460             mode = eDTDMode_quirks;
02461             break;
02462           case eCompatibility_AlmostStandards:
02463             mode = eDTDMode_almost_standards;
02464             break;
02465           case eCompatibility_FullStandards:
02466             mode = eDTDMode_full_standards;
02467             break;
02468           default:
02469             NS_NOTREACHED("unknown mode");
02470             break;
02471         }
02472       } else {
02473         mode = eDTDMode_full_standards;
02474       }
02475       result = parser->ParseFragment(aFragment, (void*)0,
02476                                      tagStack,
02477                                      !bHTML, contentType, mode);
02478 
02479       if (ContextStack) {
02480         JSContext *notused;
02481         ContextStack->Pop(&notused);
02482       }
02483 
02484       if (NS_SUCCEEDED(result)) {
02485         result = sink->GetFragment(aReturn);
02486       }
02487     }
02488   }
02489 
02490   // XXX Ick! Delete strings we allocated above.
02491   PRInt32 count = tagStack.Count();
02492   for (PRInt32 i = 0; i < count; i++) {
02493     PRUnichar* str = (PRUnichar*)tagStack.ElementAt(i);
02494     if (str) {
02495       NS_Free(str);
02496     }
02497   }
02498 
02499   return result;
02500 }
02501 
02502 NS_IMETHODIMP
02503 nsRange::GetHasGeneratedBefore(PRBool *aBool)
02504 {
02505   NS_ENSURE_ARG_POINTER(aBool);
02506   *aBool = mBeforeGenContent;
02507   return NS_OK;
02508 }
02509 
02510 NS_IMETHODIMP    
02511 nsRange::GetHasGeneratedAfter(PRBool *aBool)
02512 {
02513   NS_ENSURE_ARG_POINTER(aBool);
02514   *aBool = mAfterGenContent;
02515   return NS_OK;
02516 }
02517 
02518 NS_IMETHODIMP    
02519 nsRange::SetHasGeneratedBefore(PRBool aBool)
02520 {
02521   mBeforeGenContent = aBool;
02522   return NS_OK;
02523 }
02524 
02525 NS_IMETHODIMP    
02526 nsRange::SetHasGeneratedAfter(PRBool aBool)
02527 {
02528   mAfterGenContent = aBool;
02529   return NS_OK;
02530 }
02531 
02532 NS_IMETHODIMP    
02533 nsRange::SetBeforeAndAfter(PRBool aBefore, PRBool aAfter)
02534 {
02535   mBeforeGenContent = aBefore;
02536   mBeforeGenContent = aAfter;
02537   return NS_OK;
02538 }