content/base/src/nsRange.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsRange.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3025 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + * Implementation of the DOM nsIDOMRange object.
    1.11 + */
    1.12 +
    1.13 +#include "nscore.h"
    1.14 +#include "nsRange.h"
    1.15 +
    1.16 +#include "nsString.h"
    1.17 +#include "nsReadableUtils.h"
    1.18 +#include "nsIDOMNode.h"
    1.19 +#include "nsIDOMDocumentFragment.h"
    1.20 +#include "nsIContent.h"
    1.21 +#include "nsIDocument.h"
    1.22 +#include "nsIDOMText.h"
    1.23 +#include "nsError.h"
    1.24 +#include "nsIContentIterator.h"
    1.25 +#include "nsIDOMNodeList.h"
    1.26 +#include "nsGkAtoms.h"
    1.27 +#include "nsContentUtils.h"
    1.28 +#include "nsGenericDOMDataNode.h"
    1.29 +#include "nsLayoutUtils.h"
    1.30 +#include "nsTextFrame.h"
    1.31 +#include "nsFontFaceList.h"
    1.32 +#include "mozilla/dom/DocumentFragment.h"
    1.33 +#include "mozilla/dom/DocumentType.h"
    1.34 +#include "mozilla/dom/RangeBinding.h"
    1.35 +#include "mozilla/dom/DOMRect.h"
    1.36 +#include "mozilla/dom/ShadowRoot.h"
    1.37 +#include "mozilla/Telemetry.h"
    1.38 +#include "mozilla/Likely.h"
    1.39 +#include "nsCSSFrameConstructor.h"
    1.40 +
    1.41 +using namespace mozilla;
    1.42 +using namespace mozilla::dom;
    1.43 +
    1.44 +JSObject*
    1.45 +nsRange::WrapObject(JSContext* aCx)
    1.46 +{
    1.47 +  return RangeBinding::Wrap(aCx, this);
    1.48 +}
    1.49 +
    1.50 +/******************************************************
    1.51 + * stack based utilty class for managing monitor
    1.52 + ******************************************************/
    1.53 +
    1.54 +static void InvalidateAllFrames(nsINode* aNode)
    1.55 +{
    1.56 +  NS_PRECONDITION(aNode, "bad arg");
    1.57 +
    1.58 +  nsIFrame* frame = nullptr;
    1.59 +  switch (aNode->NodeType()) {
    1.60 +    case nsIDOMNode::TEXT_NODE:
    1.61 +    case nsIDOMNode::ELEMENT_NODE:
    1.62 +    {
    1.63 +      nsIContent* content = static_cast<nsIContent*>(aNode);
    1.64 +      frame = content->GetPrimaryFrame();
    1.65 +      break;
    1.66 +    }
    1.67 +    case nsIDOMNode::DOCUMENT_NODE:
    1.68 +    {
    1.69 +      nsIDocument* doc = static_cast<nsIDocument*>(aNode);
    1.70 +      nsIPresShell* shell = doc ? doc->GetShell() : nullptr;
    1.71 +      frame = shell ? shell->GetRootFrame() : nullptr;
    1.72 +      break;
    1.73 +    }
    1.74 +  }
    1.75 +  for (nsIFrame* f = frame; f; f = f->GetNextContinuation()) {
    1.76 +    f->InvalidateFrameSubtree();
    1.77 +  }
    1.78 +}
    1.79 +
    1.80 +// Utility routine to detect if a content node is completely contained in a range
    1.81 +// If outNodeBefore is returned true, then the node starts before the range does.
    1.82 +// If outNodeAfter is returned true, then the node ends after the range does.
    1.83 +// Note that both of the above might be true.
    1.84 +// If neither are true, the node is contained inside of the range.
    1.85 +// XXX - callers responsibility to ensure node in same doc as range! 
    1.86 +
    1.87 +// static
    1.88 +nsresult
    1.89 +nsRange::CompareNodeToRange(nsINode* aNode, nsRange* aRange,
    1.90 +                            bool *outNodeBefore, bool *outNodeAfter)
    1.91 +{
    1.92 +  NS_ENSURE_STATE(aNode);
    1.93 +  // create a pair of dom points that expresses location of node:
    1.94 +  //     NODE(start), NODE(end)
    1.95 +  // Let incoming range be:
    1.96 +  //    {RANGE(start), RANGE(end)}
    1.97 +  // if (RANGE(start) <= NODE(start))  and (RANGE(end) => NODE(end))
    1.98 +  // then the Node is contained (completely) by the Range.
    1.99 +  
   1.100 +  if (!aRange || !aRange->IsPositioned()) 
   1.101 +    return NS_ERROR_UNEXPECTED; 
   1.102 +  
   1.103 +  // gather up the dom point info
   1.104 +  int32_t nodeStart, nodeEnd;
   1.105 +  nsINode* parent = aNode->GetParentNode();
   1.106 +  if (!parent) {
   1.107 +    // can't make a parent/offset pair to represent start or 
   1.108 +    // end of the root node, because it has no parent.
   1.109 +    // so instead represent it by (node,0) and (node,numChildren)
   1.110 +    parent = aNode;
   1.111 +    nodeStart = 0;
   1.112 +    nodeEnd = aNode->GetChildCount();
   1.113 +  }
   1.114 +  else {
   1.115 +    nodeStart = parent->IndexOf(aNode);
   1.116 +    nodeEnd = nodeStart + 1;
   1.117 +  }
   1.118 +
   1.119 +  nsINode* rangeStartParent = aRange->GetStartParent();
   1.120 +  nsINode* rangeEndParent = aRange->GetEndParent();
   1.121 +  int32_t rangeStartOffset = aRange->StartOffset();
   1.122 +  int32_t rangeEndOffset = aRange->EndOffset();
   1.123 +
   1.124 +  // is RANGE(start) <= NODE(start) ?
   1.125 +  bool disconnected = false;
   1.126 +  *outNodeBefore = nsContentUtils::ComparePoints(rangeStartParent,
   1.127 +                                                 rangeStartOffset,
   1.128 +                                                 parent, nodeStart,
   1.129 +                                                 &disconnected) > 0;
   1.130 +  NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
   1.131 +
   1.132 +  // is RANGE(end) >= NODE(end) ?
   1.133 +  *outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
   1.134 +                                                rangeEndOffset,
   1.135 +                                                parent, nodeEnd,
   1.136 +                                                &disconnected) < 0;
   1.137 +  NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
   1.138 +  return NS_OK;
   1.139 +}
   1.140 +
   1.141 +struct FindSelectedRangeData
   1.142 +{
   1.143 +  nsINode*  mNode;
   1.144 +  nsRange* mResult;
   1.145 +  uint32_t  mStartOffset;
   1.146 +  uint32_t  mEndOffset;
   1.147 +};
   1.148 +
   1.149 +static PLDHashOperator
   1.150 +FindSelectedRange(nsPtrHashKey<nsRange>* aEntry, void* userArg)
   1.151 +{
   1.152 +  nsRange* range = aEntry->GetKey();
   1.153 +  if (range->IsInSelection() && !range->Collapsed()) {
   1.154 +    FindSelectedRangeData* data = static_cast<FindSelectedRangeData*>(userArg);
   1.155 +    int32_t cmp = nsContentUtils::ComparePoints(data->mNode, data->mEndOffset,
   1.156 +                                                range->GetStartParent(),
   1.157 +                                                range->StartOffset());
   1.158 +    if (cmp == 1) {
   1.159 +      cmp = nsContentUtils::ComparePoints(data->mNode, data->mStartOffset,
   1.160 +                                          range->GetEndParent(),
   1.161 +                                          range->EndOffset());
   1.162 +      if (cmp == -1) {
   1.163 +        data->mResult = range;
   1.164 +        return PL_DHASH_STOP;
   1.165 +      }
   1.166 +    }
   1.167 +  }
   1.168 +  return PL_DHASH_NEXT;
   1.169 +}
   1.170 +
   1.171 +static nsINode*
   1.172 +GetNextRangeCommonAncestor(nsINode* aNode)
   1.173 +{
   1.174 +  while (aNode && !aNode->IsCommonAncestorForRangeInSelection()) {
   1.175 +    if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.176 +      return nullptr;
   1.177 +    }
   1.178 +    aNode = aNode->GetParentNode();
   1.179 +  }
   1.180 +  return aNode;
   1.181 +}
   1.182 +
   1.183 +/* static */ bool
   1.184 +nsRange::IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
   1.185 +                        uint32_t aEndOffset)
   1.186 +{
   1.187 +  NS_PRECONDITION(aNode, "bad arg");
   1.188 +
   1.189 +  FindSelectedRangeData data = { aNode, nullptr, aStartOffset, aEndOffset };
   1.190 +  nsINode* n = GetNextRangeCommonAncestor(aNode);
   1.191 +  NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
   1.192 +               "orphan selection descendant");
   1.193 +  for (; n; n = GetNextRangeCommonAncestor(n->GetParentNode())) {
   1.194 +    RangeHashTable* ranges =
   1.195 +      static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
   1.196 +    ranges->EnumerateEntries(FindSelectedRange, &data);
   1.197 +    if (data.mResult) {
   1.198 +      return true;
   1.199 +    }
   1.200 +  }
   1.201 +  return false;
   1.202 +}
   1.203 +
   1.204 +/******************************************************
   1.205 + * constructor/destructor
   1.206 + ******************************************************/
   1.207 +
   1.208 +nsRange::~nsRange() 
   1.209 +{
   1.210 +  NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
   1.211 +
   1.212 +  // Maybe we can remove Detach() -- bug 702948.
   1.213 +  Telemetry::Accumulate(Telemetry::DOM_RANGE_DETACHED, mIsDetached);
   1.214 +
   1.215 +  // we want the side effects (releases and list removals)
   1.216 +  DoSetRange(nullptr, 0, nullptr, 0, nullptr);
   1.217 +}
   1.218 +
   1.219 +/* static */
   1.220 +nsresult
   1.221 +nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
   1.222 +                     nsINode* aEndParent, int32_t aEndOffset,
   1.223 +                     nsRange** aRange)
   1.224 +{
   1.225 +  nsCOMPtr<nsIDOMNode> startDomNode = do_QueryInterface(aStartParent);
   1.226 +  nsCOMPtr<nsIDOMNode> endDomNode = do_QueryInterface(aEndParent);
   1.227 +
   1.228 +  nsresult rv = CreateRange(startDomNode, aStartOffset, endDomNode, aEndOffset,
   1.229 +                            aRange);
   1.230 +
   1.231 +  return rv;
   1.232 +
   1.233 +}
   1.234 +
   1.235 +/* static */
   1.236 +nsresult
   1.237 +nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
   1.238 +                     nsIDOMNode* aEndParent, int32_t aEndOffset,
   1.239 +                     nsRange** aRange)
   1.240 +{
   1.241 +  MOZ_ASSERT(aRange);
   1.242 +  *aRange = nullptr;
   1.243 +
   1.244 +  nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
   1.245 +  NS_ENSURE_ARG_POINTER(startParent);
   1.246 +
   1.247 +  nsRefPtr<nsRange> range = new nsRange(startParent);
   1.248 +
   1.249 +  nsresult rv = range->SetStart(startParent, aStartOffset);
   1.250 +  NS_ENSURE_SUCCESS(rv, rv);
   1.251 +
   1.252 +  rv = range->SetEnd(aEndParent, aEndOffset);
   1.253 +  NS_ENSURE_SUCCESS(rv, rv);
   1.254 +
   1.255 +  range.forget(aRange);
   1.256 +  return NS_OK;
   1.257 +}
   1.258 +
   1.259 +/* static */
   1.260 +nsresult
   1.261 +nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
   1.262 +                     nsIDOMNode* aEndParent, int32_t aEndOffset,
   1.263 +                     nsIDOMRange** aRange)
   1.264 +{
   1.265 +  nsRefPtr<nsRange> range;
   1.266 +  nsresult rv = nsRange::CreateRange(aStartParent, aStartOffset, aEndParent,
   1.267 +                                     aEndOffset, getter_AddRefs(range));
   1.268 +  range.forget(aRange);
   1.269 +  return rv;
   1.270 +}
   1.271 +
   1.272 +/******************************************************
   1.273 + * nsISupports
   1.274 + ******************************************************/
   1.275 +
   1.276 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsRange)
   1.277 +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsRange,
   1.278 +                                                   DoSetRange(nullptr, 0, nullptr, 0, nullptr))
   1.279 +
   1.280 +// QueryInterface implementation for nsRange
   1.281 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsRange)
   1.282 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   1.283 +  NS_INTERFACE_MAP_ENTRY(nsIDOMRange)
   1.284 +  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   1.285 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMRange)
   1.286 +NS_INTERFACE_MAP_END
   1.287 +
   1.288 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsRange)
   1.289 +
   1.290 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsRange)
   1.291 +  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   1.292 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
   1.293 +  tmp->Reset();
   1.294 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1.295 +
   1.296 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
   1.297 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   1.298 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStartParent)
   1.299 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndParent)
   1.300 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
   1.301 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   1.302 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.303 +
   1.304 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsRange)
   1.305 +  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   1.306 +NS_IMPL_CYCLE_COLLECTION_TRACE_END
   1.307 +
   1.308 +static void MarkDescendants(nsINode* aNode)
   1.309 +{
   1.310 +  // Set NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
   1.311 +  // descendants unless aNode is already marked as a range common ancestor
   1.312 +  // or a descendant of one, in which case all of our descendants have the
   1.313 +  // bit set already.
   1.314 +  if (!aNode->IsSelectionDescendant()) {
   1.315 +    // don't set the Descendant bit on |aNode| itself
   1.316 +    nsINode* node = aNode->GetNextNode(aNode);
   1.317 +    while (node) {
   1.318 +      node->SetDescendantOfCommonAncestorForRangeInSelection();
   1.319 +      if (!node->IsCommonAncestorForRangeInSelection()) {
   1.320 +        node = node->GetNextNode(aNode);
   1.321 +      } else {
   1.322 +        // optimize: skip this sub-tree since it's marked already.
   1.323 +        node = node->GetNextNonChildNode(aNode);
   1.324 +      }
   1.325 +    }
   1.326 +  }
   1.327 +}
   1.328 +
   1.329 +static void UnmarkDescendants(nsINode* aNode)
   1.330 +{
   1.331 +  // Unset NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
   1.332 +  // descendants unless aNode is a descendant of another range common ancestor.
   1.333 +  // Also, exclude descendants of range common ancestors (but not the common
   1.334 +  // ancestor itself).
   1.335 +  if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.336 +    // we know |aNode| doesn't have any bit set
   1.337 +    nsINode* node = aNode->GetNextNode(aNode);
   1.338 +    while (node) {
   1.339 +      node->ClearDescendantOfCommonAncestorForRangeInSelection();
   1.340 +      if (!node->IsCommonAncestorForRangeInSelection()) {
   1.341 +        node = node->GetNextNode(aNode);
   1.342 +      } else {
   1.343 +        // We found an ancestor of an overlapping range, skip its descendants.
   1.344 +        node = node->GetNextNonChildNode(aNode);
   1.345 +      }
   1.346 +    }
   1.347 +  }
   1.348 +}
   1.349 +
   1.350 +void
   1.351 +nsRange::RegisterCommonAncestor(nsINode* aNode)
   1.352 +{
   1.353 +  NS_PRECONDITION(aNode, "bad arg");
   1.354 +  NS_ASSERTION(IsInSelection(), "registering range not in selection");
   1.355 +
   1.356 +  MarkDescendants(aNode);
   1.357 +
   1.358 +  RangeHashTable* ranges =
   1.359 +    static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
   1.360 +  if (!ranges) {
   1.361 +    ranges = new RangeHashTable;
   1.362 +    aNode->SetProperty(nsGkAtoms::range, ranges,
   1.363 +                       nsINode::DeleteProperty<nsRange::RangeHashTable>, true);
   1.364 +  }
   1.365 +  ranges->PutEntry(this);
   1.366 +  aNode->SetCommonAncestorForRangeInSelection();
   1.367 +}
   1.368 +
   1.369 +void
   1.370 +nsRange::UnregisterCommonAncestor(nsINode* aNode)
   1.371 +{
   1.372 +  NS_PRECONDITION(aNode, "bad arg");
   1.373 +  NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
   1.374 +  RangeHashTable* ranges =
   1.375 +    static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
   1.376 +  NS_ASSERTION(ranges->GetEntry(this), "unknown range");
   1.377 +
   1.378 +  if (ranges->Count() == 1) {
   1.379 +    aNode->ClearCommonAncestorForRangeInSelection();
   1.380 +    aNode->DeleteProperty(nsGkAtoms::range);
   1.381 +    UnmarkDescendants(aNode);
   1.382 +  } else {
   1.383 +    ranges->RemoveEntry(this);
   1.384 +  }
   1.385 +}
   1.386 +
   1.387 +/******************************************************
   1.388 + * nsIMutationObserver implementation
   1.389 + ******************************************************/
   1.390 +
   1.391 +void
   1.392 +nsRange::CharacterDataChanged(nsIDocument* aDocument,
   1.393 +                              nsIContent* aContent,
   1.394 +                              CharacterDataChangeInfo* aInfo)
   1.395 +{
   1.396 +  MOZ_ASSERT(mAssertNextInsertOrAppendIndex == -1,
   1.397 +             "splitText failed to notify insert/append?");
   1.398 +  NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
   1.399 +
   1.400 +  nsINode* newRoot = nullptr;
   1.401 +  nsINode* newStartNode = nullptr;
   1.402 +  nsINode* newEndNode = nullptr;
   1.403 +  uint32_t newStartOffset = 0;
   1.404 +  uint32_t newEndOffset = 0;
   1.405 +
   1.406 +  if (aInfo->mDetails &&
   1.407 +      aInfo->mDetails->mType == CharacterDataChangeInfo::Details::eSplit) {
   1.408 +    // If the splitted text node is immediately before a range boundary point
   1.409 +    // that refers to a child index (i.e. its parent is the boundary container)
   1.410 +    // then we need to increment the corresponding offset to account for the new
   1.411 +    // text node that will be inserted.  If so, we need to prevent the next
   1.412 +    // ContentInserted or ContentAppended for this range from incrementing it
   1.413 +    // again (when the new text node is notified).
   1.414 +    nsINode* parentNode = aContent->GetParentNode();
   1.415 +    int32_t index = -1;
   1.416 +    if (parentNode == mEndParent && mEndOffset > 0 &&
   1.417 +        (index = parentNode->IndexOf(aContent)) + 1 == mEndOffset) {
   1.418 +      ++mEndOffset;
   1.419 +      mEndOffsetWasIncremented = true;
   1.420 +    }
   1.421 +    if (parentNode == mStartParent && mStartOffset > 0 &&
   1.422 +        (index != -1 ? index : parentNode->IndexOf(aContent)) + 1 == mStartOffset) {
   1.423 +      ++mStartOffset;
   1.424 +      mStartOffsetWasIncremented = true;
   1.425 +    }
   1.426 +#ifdef DEBUG
   1.427 +    if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
   1.428 +      mAssertNextInsertOrAppendIndex =
   1.429 +        (mStartOffsetWasIncremented ? mStartOffset : mEndOffset) - 1;
   1.430 +      mAssertNextInsertOrAppendNode = aInfo->mDetails->mNextSibling;
   1.431 +    }
   1.432 +#endif
   1.433 +  }
   1.434 +
   1.435 +  // If the changed node contains our start boundary and the change starts
   1.436 +  // before the boundary we'll need to adjust the offset.
   1.437 +  if (aContent == mStartParent &&
   1.438 +      aInfo->mChangeStart < static_cast<uint32_t>(mStartOffset)) {
   1.439 +    if (aInfo->mDetails) {
   1.440 +      // splitText(), aInfo->mDetails->mNextSibling is the new text node
   1.441 +      NS_ASSERTION(aInfo->mDetails->mType ==
   1.442 +                   CharacterDataChangeInfo::Details::eSplit,
   1.443 +                   "only a split can start before the end");
   1.444 +      NS_ASSERTION(static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd + 1,
   1.445 +                   "mStartOffset is beyond the end of this node");
   1.446 +      newStartOffset = static_cast<uint32_t>(mStartOffset) - aInfo->mChangeStart;
   1.447 +      newStartNode = aInfo->mDetails->mNextSibling;
   1.448 +      if (MOZ_UNLIKELY(aContent == mRoot)) {
   1.449 +        newRoot = IsValidBoundary(newStartNode);
   1.450 +      }
   1.451 +
   1.452 +      bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
   1.453 +      if (isCommonAncestor) {
   1.454 +        UnregisterCommonAncestor(mStartParent);
   1.455 +        RegisterCommonAncestor(newStartNode);
   1.456 +      }
   1.457 +      if (mStartParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.458 +        newStartNode->SetDescendantOfCommonAncestorForRangeInSelection();
   1.459 +      }
   1.460 +    } else {
   1.461 +      // If boundary is inside changed text, position it before change
   1.462 +      // else adjust start offset for the change in length.
   1.463 +      mStartOffset = static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd ?
   1.464 +        aInfo->mChangeStart :
   1.465 +        mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
   1.466 +          aInfo->mReplaceLength;
   1.467 +    }
   1.468 +  }
   1.469 +
   1.470 +  // Do the same thing for the end boundary, except for splitText of a node
   1.471 +  // with no parent then only switch to the new node if the start boundary
   1.472 +  // did so too (otherwise the range would end up with disconnected nodes).
   1.473 +  if (aContent == mEndParent &&
   1.474 +      aInfo->mChangeStart < static_cast<uint32_t>(mEndOffset)) {
   1.475 +    if (aInfo->mDetails && (aContent->GetParentNode() || newStartNode)) {
   1.476 +      // splitText(), aInfo->mDetails->mNextSibling is the new text node
   1.477 +      NS_ASSERTION(aInfo->mDetails->mType ==
   1.478 +                   CharacterDataChangeInfo::Details::eSplit,
   1.479 +                   "only a split can start before the end");
   1.480 +      NS_ASSERTION(static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd + 1,
   1.481 +                   "mEndOffset is beyond the end of this node");
   1.482 +      newEndOffset = static_cast<uint32_t>(mEndOffset) - aInfo->mChangeStart;
   1.483 +      newEndNode = aInfo->mDetails->mNextSibling;
   1.484 +
   1.485 +      bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
   1.486 +      if (isCommonAncestor && !newStartNode) {
   1.487 +        // The split occurs inside the range.
   1.488 +        UnregisterCommonAncestor(mStartParent);
   1.489 +        RegisterCommonAncestor(mStartParent->GetParentNode());
   1.490 +        newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
   1.491 +      } else if (mEndParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.492 +        newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
   1.493 +      }
   1.494 +    } else {
   1.495 +      mEndOffset = static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd ?
   1.496 +        aInfo->mChangeStart :
   1.497 +        mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
   1.498 +          aInfo->mReplaceLength;
   1.499 +    }
   1.500 +  }
   1.501 +
   1.502 +  if (aInfo->mDetails &&
   1.503 +      aInfo->mDetails->mType == CharacterDataChangeInfo::Details::eMerge) {
   1.504 +    // normalize(), aInfo->mDetails->mNextSibling is the merged text node
   1.505 +    // that will be removed
   1.506 +    nsIContent* removed = aInfo->mDetails->mNextSibling;
   1.507 +    if (removed == mStartParent) {
   1.508 +      newStartOffset = static_cast<uint32_t>(mStartOffset) + aInfo->mChangeStart;
   1.509 +      newStartNode = aContent;
   1.510 +      if (MOZ_UNLIKELY(removed == mRoot)) {
   1.511 +        newRoot = IsValidBoundary(newStartNode);
   1.512 +      }
   1.513 +    }
   1.514 +    if (removed == mEndParent) {
   1.515 +      newEndOffset = static_cast<uint32_t>(mEndOffset) + aInfo->mChangeStart;
   1.516 +      newEndNode = aContent;
   1.517 +      if (MOZ_UNLIKELY(removed == mRoot)) {
   1.518 +        newRoot = IsValidBoundary(newEndNode);
   1.519 +      }
   1.520 +    }
   1.521 +    // When the removed text node's parent is one of our boundary nodes we may
   1.522 +    // need to adjust the offset to account for the removed node. However,
   1.523 +    // there will also be a ContentRemoved notification later so the only cases
   1.524 +    // we need to handle here is when the removed node is the text node after
   1.525 +    // the boundary.  (The m*Offset > 0 check is an optimization - a boundary
   1.526 +    // point before the first child is never affected by normalize().)
   1.527 +    nsINode* parentNode = aContent->GetParentNode();
   1.528 +    if (parentNode == mStartParent && mStartOffset > 0 &&
   1.529 +        uint32_t(mStartOffset) < parentNode->GetChildCount() &&
   1.530 +        removed == parentNode->GetChildAt(mStartOffset)) {
   1.531 +      newStartNode = aContent;
   1.532 +      newStartOffset = aInfo->mChangeStart;
   1.533 +    }
   1.534 +    if (parentNode == mEndParent && mEndOffset > 0 &&
   1.535 +        uint32_t(mEndOffset) < parentNode->GetChildCount() &&
   1.536 +        removed == parentNode->GetChildAt(mEndOffset)) {
   1.537 +      newEndNode = aContent;
   1.538 +      newEndOffset = aInfo->mChangeEnd;
   1.539 +    }
   1.540 +  }
   1.541 +
   1.542 +  if (newStartNode || newEndNode) {
   1.543 +    if (!newStartNode) {
   1.544 +      newStartNode = mStartParent;
   1.545 +      newStartOffset = mStartOffset;
   1.546 +    }
   1.547 +    if (!newEndNode) {
   1.548 +      newEndNode = mEndParent;
   1.549 +      newEndOffset = mEndOffset;
   1.550 +    }
   1.551 +    DoSetRange(newStartNode, newStartOffset, newEndNode, newEndOffset,
   1.552 +               newRoot ? newRoot : mRoot.get(),
   1.553 +               !newEndNode->GetParentNode() || !newStartNode->GetParentNode());
   1.554 +  }
   1.555 +}
   1.556 +
   1.557 +void
   1.558 +nsRange::ContentAppended(nsIDocument* aDocument,
   1.559 +                         nsIContent*  aContainer,
   1.560 +                         nsIContent*  aFirstNewContent,
   1.561 +                         int32_t      aNewIndexInContainer)
   1.562 +{
   1.563 +  NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
   1.564 +
   1.565 +  nsINode* container = NODE_FROM(aContainer, aDocument);
   1.566 +  if (container->IsSelectionDescendant() && IsInSelection()) {
   1.567 +    nsINode* child = aFirstNewContent;
   1.568 +    while (child) {
   1.569 +      if (!child->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.570 +        MarkDescendants(child);
   1.571 +        child->SetDescendantOfCommonAncestorForRangeInSelection();
   1.572 +      }
   1.573 +      child = child->GetNextSibling();
   1.574 +    }
   1.575 +  }
   1.576 +
   1.577 +  if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
   1.578 +    MOZ_ASSERT(mAssertNextInsertOrAppendIndex == aNewIndexInContainer);
   1.579 +    MOZ_ASSERT(mAssertNextInsertOrAppendNode == aFirstNewContent);
   1.580 +    MOZ_ASSERT(aFirstNewContent->IsNodeOfType(nsINode::eDATA_NODE));
   1.581 +    mStartOffsetWasIncremented = mEndOffsetWasIncremented = false;
   1.582 +#ifdef DEBUG
   1.583 +    mAssertNextInsertOrAppendIndex = -1;
   1.584 +    mAssertNextInsertOrAppendNode = nullptr;
   1.585 +#endif
   1.586 +  }
   1.587 +}
   1.588 +
   1.589 +void
   1.590 +nsRange::ContentInserted(nsIDocument* aDocument,
   1.591 +                         nsIContent* aContainer,
   1.592 +                         nsIContent* aChild,
   1.593 +                         int32_t aIndexInContainer)
   1.594 +{
   1.595 +  NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
   1.596 +
   1.597 +  nsINode* container = NODE_FROM(aContainer, aDocument);
   1.598 +
   1.599 +  // Adjust position if a sibling was inserted.
   1.600 +  if (container == mStartParent && aIndexInContainer < mStartOffset &&
   1.601 +      !mStartOffsetWasIncremented) {
   1.602 +    ++mStartOffset;
   1.603 +  }
   1.604 +  if (container == mEndParent && aIndexInContainer < mEndOffset &&
   1.605 +      !mEndOffsetWasIncremented) {
   1.606 +    ++mEndOffset;
   1.607 +  }
   1.608 +  if (container->IsSelectionDescendant() &&
   1.609 +      !aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.610 +    MarkDescendants(aChild);
   1.611 +    aChild->SetDescendantOfCommonAncestorForRangeInSelection();
   1.612 +  }
   1.613 +
   1.614 +  if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
   1.615 +    MOZ_ASSERT(mAssertNextInsertOrAppendIndex == aIndexInContainer);
   1.616 +    MOZ_ASSERT(mAssertNextInsertOrAppendNode == aChild);
   1.617 +    MOZ_ASSERT(aChild->IsNodeOfType(nsINode::eDATA_NODE));
   1.618 +    mStartOffsetWasIncremented = mEndOffsetWasIncremented = false;
   1.619 +#ifdef DEBUG
   1.620 +    mAssertNextInsertOrAppendIndex = -1;
   1.621 +    mAssertNextInsertOrAppendNode = nullptr;
   1.622 +#endif
   1.623 +  }
   1.624 +}
   1.625 +
   1.626 +void
   1.627 +nsRange::ContentRemoved(nsIDocument* aDocument,
   1.628 +                        nsIContent* aContainer,
   1.629 +                        nsIContent* aChild,
   1.630 +                        int32_t aIndexInContainer,
   1.631 +                        nsIContent* aPreviousSibling)
   1.632 +{
   1.633 +  NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
   1.634 +  MOZ_ASSERT(!mStartOffsetWasIncremented && !mEndOffsetWasIncremented &&
   1.635 +             mAssertNextInsertOrAppendIndex == -1,
   1.636 +             "splitText failed to notify insert/append?");
   1.637 +
   1.638 +  nsINode* container = NODE_FROM(aContainer, aDocument);
   1.639 +  bool gravitateStart = false;
   1.640 +  bool gravitateEnd = false;
   1.641 +  bool didCheckStartParentDescendant = false;
   1.642 +
   1.643 +  // Adjust position if a sibling was removed...
   1.644 +  if (container == mStartParent) {
   1.645 +    if (aIndexInContainer < mStartOffset) {
   1.646 +      --mStartOffset;
   1.647 +    }
   1.648 +  } else { // ...or gravitate if an ancestor was removed.
   1.649 +    didCheckStartParentDescendant = true;
   1.650 +    gravitateStart = nsContentUtils::ContentIsDescendantOf(mStartParent, aChild);
   1.651 +  }
   1.652 +
   1.653 +  // Do same thing for end boundry.
   1.654 +  if (container == mEndParent) {
   1.655 +    if (aIndexInContainer < mEndOffset) {
   1.656 +      --mEndOffset;
   1.657 +    }
   1.658 +  } else if (didCheckStartParentDescendant && mStartParent == mEndParent) {
   1.659 +    gravitateEnd = gravitateStart;
   1.660 +  } else {
   1.661 +    gravitateEnd = nsContentUtils::ContentIsDescendantOf(mEndParent, aChild);
   1.662 +  }
   1.663 +
   1.664 +  if (!mEnableGravitationOnElementRemoval) {
   1.665 +    // Do not gravitate.
   1.666 +    return;
   1.667 +  }
   1.668 +
   1.669 +  if (gravitateStart || gravitateEnd) {
   1.670 +    DoSetRange(gravitateStart ? container : mStartParent.get(),
   1.671 +               gravitateStart ? aIndexInContainer : mStartOffset,
   1.672 +               gravitateEnd ? container : mEndParent.get(),
   1.673 +               gravitateEnd ? aIndexInContainer : mEndOffset,
   1.674 +               mRoot);
   1.675 +  }
   1.676 +  if (container->IsSelectionDescendant() &&
   1.677 +      aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
   1.678 +    aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
   1.679 +    UnmarkDescendants(aChild);
   1.680 +  }
   1.681 +}
   1.682 +
   1.683 +void
   1.684 +nsRange::ParentChainChanged(nsIContent *aContent)
   1.685 +{
   1.686 +  MOZ_ASSERT(!mStartOffsetWasIncremented && !mEndOffsetWasIncremented &&
   1.687 +             mAssertNextInsertOrAppendIndex == -1,
   1.688 +             "splitText failed to notify insert/append?");
   1.689 +  NS_ASSERTION(mRoot == aContent, "Wrong ParentChainChanged notification?");
   1.690 +  nsINode* newRoot = IsValidBoundary(mStartParent);
   1.691 +  NS_ASSERTION(newRoot, "No valid boundary or root found!");
   1.692 +  if (newRoot != IsValidBoundary(mEndParent)) {
   1.693 +    // Sometimes ordering involved in cycle collection can lead to our
   1.694 +    // start parent and/or end parent being disconnected from our root
   1.695 +    // without our getting a ContentRemoved notification.
   1.696 +    // See bug 846096 for more details.
   1.697 +    NS_ASSERTION(mEndParent->IsInNativeAnonymousSubtree(),
   1.698 +                 "This special case should happen only with "
   1.699 +                 "native-anonymous content");
   1.700 +    // When that happens, bail out and set pointers to null; since we're
   1.701 +    // in cycle collection and unreachable it shouldn't matter.
   1.702 +    Reset();
   1.703 +    return;
   1.704 +  }
   1.705 +  // This is safe without holding a strong ref to self as long as the change
   1.706 +  // of mRoot is the last thing in DoSetRange.
   1.707 +  DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, newRoot);
   1.708 +}
   1.709 +
   1.710 +/******************************************************
   1.711 + * Utilities for comparing points: API from nsIDOMRange
   1.712 + ******************************************************/
   1.713 +NS_IMETHODIMP
   1.714 +nsRange::IsPointInRange(nsIDOMNode* aParent, int32_t aOffset, bool* aResult)
   1.715 +{
   1.716 +  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
   1.717 +  if (!parent) {
   1.718 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
   1.719 +  }
   1.720 +
   1.721 +  ErrorResult rv;
   1.722 +  *aResult = IsPointInRange(*parent, aOffset, rv);
   1.723 +  return rv.ErrorCode();
   1.724 +}
   1.725 +
   1.726 +bool
   1.727 +nsRange::IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
   1.728 +{
   1.729 +  uint16_t compareResult = ComparePoint(aParent, aOffset, aRv);
   1.730 +  // If the node isn't in the range's document, it clearly isn't in the range.
   1.731 +  if (aRv.ErrorCode() == NS_ERROR_DOM_WRONG_DOCUMENT_ERR) {
   1.732 +    aRv = NS_OK;
   1.733 +    return false;
   1.734 +  }
   1.735 +
   1.736 +  return compareResult == 0;
   1.737 +}
   1.738 +
   1.739 +// returns -1 if point is before range, 0 if point is in range,
   1.740 +// 1 if point is after range.
   1.741 +NS_IMETHODIMP
   1.742 +nsRange::ComparePoint(nsIDOMNode* aParent, int32_t aOffset, int16_t* aResult)
   1.743 +{
   1.744 +  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
   1.745 +  NS_ENSURE_TRUE(parent, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
   1.746 +
   1.747 +  ErrorResult rv;
   1.748 +  *aResult = ComparePoint(*parent, aOffset, rv);
   1.749 +  return rv.ErrorCode();
   1.750 +}
   1.751 +
   1.752 +int16_t
   1.753 +nsRange::ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
   1.754 +{
   1.755 +  // our range is in a good state?
   1.756 +  if (!mIsPositioned) {
   1.757 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
   1.758 +    return 0;
   1.759 +  }
   1.760 +
   1.761 +  if (!nsContentUtils::ContentIsDescendantOf(&aParent, mRoot)) {
   1.762 +    aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
   1.763 +    return 0;
   1.764 +  }
   1.765 +
   1.766 +  if (aParent.NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
   1.767 +    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
   1.768 +    return 0;
   1.769 +  }
   1.770 +
   1.771 +  if (aOffset > aParent.Length()) {
   1.772 +    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
   1.773 +    return 0;
   1.774 +  }
   1.775 +
   1.776 +  int32_t cmp;
   1.777 +  if ((cmp = nsContentUtils::ComparePoints(&aParent, aOffset,
   1.778 +                                           mStartParent, mStartOffset)) <= 0) {
   1.779 +
   1.780 +    return cmp;
   1.781 +  }
   1.782 +  if (nsContentUtils::ComparePoints(mEndParent, mEndOffset,
   1.783 +                                    &aParent, aOffset) == -1) {
   1.784 +    return 1;
   1.785 +  }
   1.786 +
   1.787 +  return 0;
   1.788 +}
   1.789 +
   1.790 +NS_IMETHODIMP
   1.791 +nsRange::IntersectsNode(nsIDOMNode* aNode, bool* aResult)
   1.792 +{
   1.793 +  *aResult = false;
   1.794 +
   1.795 +  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
   1.796 +  // TODO: This should throw a TypeError.
   1.797 +  NS_ENSURE_ARG(node);
   1.798 +
   1.799 +  ErrorResult rv;
   1.800 +  *aResult = IntersectsNode(*node, rv);
   1.801 +  return rv.ErrorCode();
   1.802 +}
   1.803 +
   1.804 +bool
   1.805 +nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
   1.806 +{
   1.807 +  if (!mIsPositioned) {
   1.808 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
   1.809 +    return false;
   1.810 +  }
   1.811 +
   1.812 +  // Step 3.
   1.813 +  nsINode* parent = aNode.GetParentNode();
   1.814 +  if (!parent) {
   1.815 +    // Steps 2 and 4. 
   1.816 +    // |parent| is null, so |node|'s root is |node| itself.
   1.817 +    return GetRoot() == &aNode;
   1.818 +  }
   1.819 +
   1.820 +  // Step 5.
   1.821 +  int32_t nodeIndex = parent->IndexOf(&aNode);
   1.822 +
   1.823 +  // Steps 6-7.
   1.824 +  // Note: if disconnected is true, ComparePoints returns 1.
   1.825 +  bool disconnected = false;
   1.826 +  bool result = nsContentUtils::ComparePoints(mStartParent, mStartOffset,
   1.827 +                                             parent, nodeIndex + 1,
   1.828 +                                             &disconnected) < 0 &&
   1.829 +               nsContentUtils::ComparePoints(parent, nodeIndex,
   1.830 +                                             mEndParent, mEndOffset,
   1.831 +                                             &disconnected) < 0;
   1.832 +
   1.833 +  // Step 2.
   1.834 +  if (disconnected) {
   1.835 +    result = false;
   1.836 +  }
   1.837 +  return result;
   1.838 +}
   1.839 +
   1.840 +/******************************************************
   1.841 + * Private helper routines
   1.842 + ******************************************************/
   1.843 +
   1.844 +// It's important that all setting of the range start/end points 
   1.845 +// go through this function, which will do all the right voodoo
   1.846 +// for content notification of range ownership.  
   1.847 +// Calling DoSetRange with either parent argument null will collapse
   1.848 +// the range to have both endpoints point to the other node
   1.849 +void
   1.850 +nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
   1.851 +                    nsINode* aEndN, int32_t aEndOffset,
   1.852 +                    nsINode* aRoot, bool aNotInsertedYet)
   1.853 +{
   1.854 +  NS_PRECONDITION((aStartN && aEndN && aRoot) ||
   1.855 +                  (!aStartN && !aEndN && !aRoot),
   1.856 +                  "Set all or none");
   1.857 +  NS_PRECONDITION(!aRoot || aNotInsertedYet ||
   1.858 +                  (nsContentUtils::ContentIsDescendantOf(aStartN, aRoot) &&
   1.859 +                   nsContentUtils::ContentIsDescendantOf(aEndN, aRoot) &&
   1.860 +                   aRoot == IsValidBoundary(aStartN) &&
   1.861 +                   aRoot == IsValidBoundary(aEndN)),
   1.862 +                  "Wrong root");
   1.863 +  NS_PRECONDITION(!aRoot ||
   1.864 +                  (aStartN->IsNodeOfType(nsINode::eCONTENT) &&
   1.865 +                   aEndN->IsNodeOfType(nsINode::eCONTENT) &&
   1.866 +                   aRoot ==
   1.867 +                    static_cast<nsIContent*>(aStartN)->GetBindingParent() &&
   1.868 +                   aRoot ==
   1.869 +                    static_cast<nsIContent*>(aEndN)->GetBindingParent()) ||
   1.870 +                  (!aRoot->GetParentNode() &&
   1.871 +                   (aRoot->IsNodeOfType(nsINode::eDOCUMENT) ||
   1.872 +                    aRoot->IsNodeOfType(nsINode::eATTRIBUTE) ||
   1.873 +                    aRoot->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
   1.874 +                     /*For backward compatibility*/
   1.875 +                    aRoot->IsNodeOfType(nsINode::eCONTENT))),
   1.876 +                  "Bad root");
   1.877 +
   1.878 +  if (mRoot != aRoot) {
   1.879 +    if (mRoot) {
   1.880 +      mRoot->RemoveMutationObserver(this);
   1.881 +    }
   1.882 +    if (aRoot) {
   1.883 +      aRoot->AddMutationObserver(this);
   1.884 +    }
   1.885 +  }
   1.886 +  bool checkCommonAncestor = (mStartParent != aStartN || mEndParent != aEndN) &&
   1.887 +                             IsInSelection() && !aNotInsertedYet;
   1.888 +  nsINode* oldCommonAncestor = checkCommonAncestor ? GetCommonAncestor() : nullptr;
   1.889 +  mStartParent = aStartN;
   1.890 +  mStartOffset = aStartOffset;
   1.891 +  mEndParent = aEndN;
   1.892 +  mEndOffset = aEndOffset;
   1.893 +  mIsPositioned = !!mStartParent;
   1.894 +  if (checkCommonAncestor) {
   1.895 +    nsINode* newCommonAncestor = GetCommonAncestor();
   1.896 +    if (newCommonAncestor != oldCommonAncestor) {
   1.897 +      if (oldCommonAncestor) {
   1.898 +        UnregisterCommonAncestor(oldCommonAncestor);
   1.899 +      }
   1.900 +      if (newCommonAncestor) {
   1.901 +        RegisterCommonAncestor(newCommonAncestor);
   1.902 +      } else {
   1.903 +        NS_ASSERTION(!mIsPositioned, "unexpected disconnected nodes");
   1.904 +        mInSelection = false;
   1.905 +      }
   1.906 +    }
   1.907 +  }
   1.908 +
   1.909 +  // This needs to be the last thing this function does.  See comment
   1.910 +  // in ParentChainChanged.
   1.911 +  mRoot = aRoot;
   1.912 +}
   1.913 +
   1.914 +static int32_t
   1.915 +IndexOf(nsINode* aChild)
   1.916 +{
   1.917 +  nsINode* parent = aChild->GetParentNode();
   1.918 +
   1.919 +  return parent ? parent->IndexOf(aChild) : -1;
   1.920 +}
   1.921 +
   1.922 +nsINode*
   1.923 +nsRange::GetCommonAncestor() const
   1.924 +{
   1.925 +  return mIsPositioned ?
   1.926 +    nsContentUtils::GetCommonAncestor(mStartParent, mEndParent) :
   1.927 +    nullptr;
   1.928 +}
   1.929 +
   1.930 +void
   1.931 +nsRange::Reset()
   1.932 +{
   1.933 +  DoSetRange(nullptr, 0, nullptr, 0, nullptr);
   1.934 +}
   1.935 +
   1.936 +/******************************************************
   1.937 + * public functionality
   1.938 + ******************************************************/
   1.939 +
   1.940 +NS_IMETHODIMP
   1.941 +nsRange::GetStartContainer(nsIDOMNode** aStartParent)
   1.942 +{
   1.943 +  if (!mIsPositioned)
   1.944 +    return NS_ERROR_NOT_INITIALIZED;
   1.945 +
   1.946 +  return CallQueryInterface(mStartParent, aStartParent);
   1.947 +}
   1.948 +
   1.949 +nsINode*
   1.950 +nsRange::GetStartContainer(ErrorResult& aRv) const
   1.951 +{
   1.952 +  if (!mIsPositioned) {
   1.953 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
   1.954 +    return nullptr;
   1.955 +  }
   1.956 +
   1.957 +  return mStartParent;
   1.958 +}
   1.959 +
   1.960 +NS_IMETHODIMP
   1.961 +nsRange::GetStartOffset(int32_t* aStartOffset)
   1.962 +{
   1.963 +  if (!mIsPositioned)
   1.964 +    return NS_ERROR_NOT_INITIALIZED;
   1.965 +
   1.966 +  *aStartOffset = mStartOffset;
   1.967 +
   1.968 +  return NS_OK;
   1.969 +}
   1.970 +
   1.971 +uint32_t
   1.972 +nsRange::GetStartOffset(ErrorResult& aRv) const
   1.973 +{
   1.974 +  if (!mIsPositioned) {
   1.975 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
   1.976 +    return 0;
   1.977 +  }
   1.978 +
   1.979 +  return mStartOffset;
   1.980 +}
   1.981 +
   1.982 +NS_IMETHODIMP
   1.983 +nsRange::GetEndContainer(nsIDOMNode** aEndParent)
   1.984 +{
   1.985 +  if (!mIsPositioned)
   1.986 +    return NS_ERROR_NOT_INITIALIZED;
   1.987 +
   1.988 +  return CallQueryInterface(mEndParent, aEndParent);
   1.989 +}
   1.990 +
   1.991 +nsINode*
   1.992 +nsRange::GetEndContainer(ErrorResult& aRv) const
   1.993 +{
   1.994 +  if (!mIsPositioned) {
   1.995 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
   1.996 +    return nullptr;
   1.997 +  }
   1.998 +
   1.999 +  return mEndParent;
  1.1000 +}
  1.1001 +
  1.1002 +NS_IMETHODIMP
  1.1003 +nsRange::GetEndOffset(int32_t* aEndOffset)
  1.1004 +{
  1.1005 +  if (!mIsPositioned)
  1.1006 +    return NS_ERROR_NOT_INITIALIZED;
  1.1007 +
  1.1008 +  *aEndOffset = mEndOffset;
  1.1009 +
  1.1010 +  return NS_OK;
  1.1011 +}
  1.1012 +
  1.1013 +uint32_t
  1.1014 +nsRange::GetEndOffset(ErrorResult& aRv) const
  1.1015 +{
  1.1016 +  if (!mIsPositioned) {
  1.1017 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
  1.1018 +    return 0;
  1.1019 +  }
  1.1020 +
  1.1021 +  return mEndOffset;
  1.1022 +}
  1.1023 +
  1.1024 +NS_IMETHODIMP
  1.1025 +nsRange::GetCollapsed(bool* aIsCollapsed)
  1.1026 +{
  1.1027 +  if (!mIsPositioned)
  1.1028 +    return NS_ERROR_NOT_INITIALIZED;
  1.1029 +
  1.1030 +  *aIsCollapsed = Collapsed();
  1.1031 +
  1.1032 +  return NS_OK;
  1.1033 +}
  1.1034 +
  1.1035 +nsINode*
  1.1036 +nsRange::GetCommonAncestorContainer(ErrorResult& aRv) const
  1.1037 +{
  1.1038 +  if (!mIsPositioned) {
  1.1039 +    aRv.Throw(NS_ERROR_NOT_INITIALIZED);
  1.1040 +    return nullptr;
  1.1041 +  }
  1.1042 +
  1.1043 +  return nsContentUtils::GetCommonAncestor(mStartParent, mEndParent);
  1.1044 +}
  1.1045 +
  1.1046 +NS_IMETHODIMP
  1.1047 +nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
  1.1048 +{
  1.1049 +  ErrorResult rv;
  1.1050 +  nsINode* commonAncestor = GetCommonAncestorContainer(rv);
  1.1051 +  if (commonAncestor) {
  1.1052 +    NS_ADDREF(*aCommonParent = commonAncestor->AsDOMNode());
  1.1053 +  } else {
  1.1054 +    *aCommonParent = nullptr;
  1.1055 +  }
  1.1056 +
  1.1057 +  return rv.ErrorCode();
  1.1058 +}
  1.1059 +
  1.1060 +nsINode*
  1.1061 +nsRange::IsValidBoundary(nsINode* aNode)
  1.1062 +{
  1.1063 +  if (!aNode) {
  1.1064 +    return nullptr;
  1.1065 +  }
  1.1066 +
  1.1067 +  if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
  1.1068 +    nsIContent* content = static_cast<nsIContent*>(aNode);
  1.1069 +    if (content->Tag() == nsGkAtoms::documentTypeNodeName) {
  1.1070 +      return nullptr;
  1.1071 +    }
  1.1072 +
  1.1073 +    if (!mMaySpanAnonymousSubtrees) {
  1.1074 +      // If the node is in a shadow tree then the ShadowRoot is the root.
  1.1075 +      ShadowRoot* containingShadow = content->GetContainingShadow();
  1.1076 +      if (containingShadow) {
  1.1077 +        return containingShadow;
  1.1078 +      }
  1.1079 +
  1.1080 +      // If the node has a binding parent, that should be the root.
  1.1081 +      // XXXbz maybe only for native anonymous content?
  1.1082 +      nsINode* root = content->GetBindingParent();
  1.1083 +      if (root) {
  1.1084 +        return root;
  1.1085 +      }
  1.1086 +    }
  1.1087 +  }
  1.1088 +
  1.1089 +  // Elements etc. must be in document or in document fragment,
  1.1090 +  // text nodes in document, in document fragment or in attribute.
  1.1091 +  nsINode* root = aNode->GetCurrentDoc();
  1.1092 +  if (root) {
  1.1093 +    return root;
  1.1094 +  }
  1.1095 +
  1.1096 +  root = aNode->SubtreeRoot();
  1.1097 +
  1.1098 +  NS_ASSERTION(!root->IsNodeOfType(nsINode::eDOCUMENT),
  1.1099 +               "GetCurrentDoc should have returned a doc");
  1.1100 +
  1.1101 +  // We allow this because of backward compatibility.
  1.1102 +  return root;
  1.1103 +}
  1.1104 +
  1.1105 +void
  1.1106 +nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
  1.1107 +{
  1.1108 + if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1109 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1110 +    return;
  1.1111 +  }
  1.1112 +
  1.1113 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1114 +  aRv = SetStart(&aNode, aOffset);
  1.1115 +}
  1.1116 +
  1.1117 +NS_IMETHODIMP
  1.1118 +nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
  1.1119 +{
  1.1120 +  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
  1.1121 +  if (!parent) {
  1.1122 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.1123 +  }
  1.1124 +
  1.1125 +  ErrorResult rv;
  1.1126 +  SetStart(*parent, aOffset, rv);
  1.1127 +  return rv.ErrorCode();
  1.1128 +}
  1.1129 +
  1.1130 +/* virtual */ nsresult
  1.1131 +nsRange::SetStart(nsINode* aParent, int32_t aOffset)
  1.1132 +{
  1.1133 +  nsINode* newRoot = IsValidBoundary(aParent);
  1.1134 +  NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1135 +
  1.1136 +  if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
  1.1137 +    return NS_ERROR_DOM_INDEX_SIZE_ERR;
  1.1138 +  }
  1.1139 +
  1.1140 +  // Collapse if not positioned yet, if positioned in another doc or
  1.1141 +  // if the new start is after end.
  1.1142 +  if (!mIsPositioned || newRoot != mRoot ||
  1.1143 +      nsContentUtils::ComparePoints(aParent, aOffset,
  1.1144 +                                    mEndParent, mEndOffset) == 1) {
  1.1145 +    DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
  1.1146 +
  1.1147 +    return NS_OK;
  1.1148 +  }
  1.1149 +
  1.1150 +  DoSetRange(aParent, aOffset, mEndParent, mEndOffset, mRoot);
  1.1151 +
  1.1152 +  return NS_OK;
  1.1153 +}
  1.1154 +
  1.1155 +void
  1.1156 +nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv)
  1.1157 +{
  1.1158 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1159 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1160 +    return;
  1.1161 +  }
  1.1162 +
  1.1163 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1164 +  aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode));
  1.1165 +}
  1.1166 +
  1.1167 +NS_IMETHODIMP
  1.1168 +nsRange::SetStartBefore(nsIDOMNode* aSibling)
  1.1169 +{
  1.1170 +  nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
  1.1171 +  if (!sibling) {
  1.1172 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.1173 +  }
  1.1174 +
  1.1175 +  ErrorResult rv;
  1.1176 +  SetStartBefore(*sibling, rv);
  1.1177 +  return rv.ErrorCode();
  1.1178 +}
  1.1179 +
  1.1180 +void
  1.1181 +nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv)
  1.1182 +{
  1.1183 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1184 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1185 +    return;
  1.1186 +  }
  1.1187 +
  1.1188 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1189 +  aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1);
  1.1190 +}
  1.1191 +
  1.1192 +NS_IMETHODIMP
  1.1193 +nsRange::SetStartAfter(nsIDOMNode* aSibling)
  1.1194 +{
  1.1195 +  nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
  1.1196 +  if (!sibling) {
  1.1197 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.1198 +  }
  1.1199 +
  1.1200 +  ErrorResult rv;
  1.1201 +  SetStartAfter(*sibling, rv);
  1.1202 +  return rv.ErrorCode();
  1.1203 +}
  1.1204 +
  1.1205 +void
  1.1206 +nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
  1.1207 +{
  1.1208 + if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1209 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1210 +    return;
  1.1211 +  }
  1.1212 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1213 +  aRv = SetEnd(&aNode, aOffset);
  1.1214 +}
  1.1215 +
  1.1216 +NS_IMETHODIMP
  1.1217 +nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
  1.1218 +{
  1.1219 +  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
  1.1220 +  if (!parent) {
  1.1221 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.1222 +  }
  1.1223 +
  1.1224 +  ErrorResult rv;
  1.1225 +  SetEnd(*parent, aOffset, rv);
  1.1226 +  return rv.ErrorCode();
  1.1227 +}
  1.1228 +
  1.1229 +/* virtual */ nsresult
  1.1230 +nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
  1.1231 +{
  1.1232 +  nsINode* newRoot = IsValidBoundary(aParent);
  1.1233 +  NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1234 +
  1.1235 +  if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
  1.1236 +    return NS_ERROR_DOM_INDEX_SIZE_ERR;
  1.1237 +  }
  1.1238 +
  1.1239 +  // Collapse if not positioned yet, if positioned in another doc or
  1.1240 +  // if the new end is before start.
  1.1241 +  if (!mIsPositioned || newRoot != mRoot ||
  1.1242 +      nsContentUtils::ComparePoints(mStartParent, mStartOffset,
  1.1243 +                                    aParent, aOffset) == 1) {
  1.1244 +    DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
  1.1245 +
  1.1246 +    return NS_OK;
  1.1247 +  }
  1.1248 +
  1.1249 +  DoSetRange(mStartParent, mStartOffset, aParent, aOffset, mRoot);
  1.1250 +
  1.1251 +  return NS_OK;
  1.1252 +}
  1.1253 +
  1.1254 +void
  1.1255 +nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
  1.1256 +{
  1.1257 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1258 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1259 +    return;
  1.1260 +  }
  1.1261 +
  1.1262 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1263 +  aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode));
  1.1264 +}
  1.1265 +
  1.1266 +NS_IMETHODIMP
  1.1267 +nsRange::SetEndBefore(nsIDOMNode* aSibling)
  1.1268 +{
  1.1269 +  nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
  1.1270 +  if (!sibling) {
  1.1271 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.1272 +  }
  1.1273 +
  1.1274 +  ErrorResult rv;
  1.1275 +  SetEndBefore(*sibling, rv);
  1.1276 +  return rv.ErrorCode();
  1.1277 +}
  1.1278 +
  1.1279 +void
  1.1280 +nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv)
  1.1281 +{
  1.1282 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1283 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1284 +    return;
  1.1285 +  }
  1.1286 +
  1.1287 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1288 +  aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1);
  1.1289 +}
  1.1290 +
  1.1291 +NS_IMETHODIMP
  1.1292 +nsRange::SetEndAfter(nsIDOMNode* aSibling)
  1.1293 +{
  1.1294 +  nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling);
  1.1295 +  if (!sibling) {
  1.1296 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.1297 +  }
  1.1298 +
  1.1299 +  ErrorResult rv;
  1.1300 +  SetEndAfter(*sibling, rv);
  1.1301 +  return rv.ErrorCode();
  1.1302 +}
  1.1303 +
  1.1304 +NS_IMETHODIMP
  1.1305 +nsRange::Collapse(bool aToStart)
  1.1306 +{
  1.1307 +  if (!mIsPositioned)
  1.1308 +    return NS_ERROR_NOT_INITIALIZED;
  1.1309 +
  1.1310 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1311 +  if (aToStart)
  1.1312 +    DoSetRange(mStartParent, mStartOffset, mStartParent, mStartOffset, mRoot);
  1.1313 +  else
  1.1314 +    DoSetRange(mEndParent, mEndOffset, mEndParent, mEndOffset, mRoot);
  1.1315 +
  1.1316 +  return NS_OK;
  1.1317 +}
  1.1318 +
  1.1319 +NS_IMETHODIMP
  1.1320 +nsRange::SelectNode(nsIDOMNode* aN)
  1.1321 +{
  1.1322 +  nsCOMPtr<nsINode> node = do_QueryInterface(aN);
  1.1323 +  NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1324 +
  1.1325 +  ErrorResult rv;
  1.1326 +  SelectNode(*node, rv);
  1.1327 +  return rv.ErrorCode();
  1.1328 +}
  1.1329 +
  1.1330 +void
  1.1331 +nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
  1.1332 +{
  1.1333 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1334 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1335 +    return;
  1.1336 +  }
  1.1337 +
  1.1338 +  nsINode* parent = aNode.GetParentNode();
  1.1339 +  nsINode* newRoot = IsValidBoundary(parent);
  1.1340 +  if (!newRoot) {
  1.1341 +    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1342 +    return;
  1.1343 +  }
  1.1344 +
  1.1345 +  int32_t index = parent->IndexOf(&aNode);
  1.1346 +  if (index < 0) {
  1.1347 +    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1348 +    return;
  1.1349 +  }
  1.1350 +
  1.1351 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1352 +  DoSetRange(parent, index, parent, index + 1, newRoot);
  1.1353 +}
  1.1354 +
  1.1355 +NS_IMETHODIMP
  1.1356 +nsRange::SelectNodeContents(nsIDOMNode* aN)
  1.1357 +{
  1.1358 +  nsCOMPtr<nsINode> node = do_QueryInterface(aN);
  1.1359 +  NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1360 +
  1.1361 +  ErrorResult rv;
  1.1362 +  SelectNodeContents(*node, rv);
  1.1363 +  return rv.ErrorCode();
  1.1364 +}
  1.1365 +
  1.1366 +void
  1.1367 +nsRange::SelectNodeContents(nsINode& aNode, ErrorResult& aRv)
  1.1368 +{
  1.1369 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.1370 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.1371 +    return;
  1.1372 +  }
  1.1373 +
  1.1374 +  nsINode* newRoot = IsValidBoundary(&aNode);
  1.1375 +  if (!newRoot) {
  1.1376 +    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.1377 +    return;
  1.1378 +  }
  1.1379 +
  1.1380 +  AutoInvalidateSelection atEndOfBlock(this);
  1.1381 +  DoSetRange(&aNode, 0, &aNode, aNode.Length(), newRoot);
  1.1382 +}
  1.1383 +
  1.1384 +// The Subtree Content Iterator only returns subtrees that are
  1.1385 +// completely within a given range. It doesn't return a CharacterData
  1.1386 +// node that contains either the start or end point of the range.,
  1.1387 +// nor does it return element nodes when nothing in the element is selected.
  1.1388 +// We need an iterator that will also include these start/end points
  1.1389 +// so that our methods/algorithms aren't cluttered with special
  1.1390 +// case code that tries to include these points while iterating.
  1.1391 +//
  1.1392 +// The RangeSubtreeIterator class mimics the nsIContentIterator
  1.1393 +// methods we need, so should the Content Iterator support the
  1.1394 +// start/end points in the future, we can switchover relatively
  1.1395 +// easy.
  1.1396 +
  1.1397 +class MOZ_STACK_CLASS RangeSubtreeIterator
  1.1398 +{
  1.1399 +private:
  1.1400 +
  1.1401 +  enum RangeSubtreeIterState { eDone=0,
  1.1402 +                               eUseStart,
  1.1403 +                               eUseIterator,
  1.1404 +                               eUseEnd };
  1.1405 +
  1.1406 +  nsCOMPtr<nsIContentIterator>  mIter;
  1.1407 +  RangeSubtreeIterState         mIterState;
  1.1408 +
  1.1409 +  nsCOMPtr<nsINode> mStart;
  1.1410 +  nsCOMPtr<nsINode> mEnd;
  1.1411 +
  1.1412 +public:
  1.1413 +
  1.1414 +  RangeSubtreeIterator()
  1.1415 +    : mIterState(eDone)
  1.1416 +  {
  1.1417 +  }
  1.1418 +  ~RangeSubtreeIterator()
  1.1419 +  {
  1.1420 +  }
  1.1421 +
  1.1422 +  nsresult Init(nsRange *aRange);
  1.1423 +  already_AddRefed<nsINode> GetCurrentNode();
  1.1424 +  void First();
  1.1425 +  void Last();
  1.1426 +  void Next();
  1.1427 +  void Prev();
  1.1428 +
  1.1429 +  bool IsDone()
  1.1430 +  {
  1.1431 +    return mIterState == eDone;
  1.1432 +  }
  1.1433 +};
  1.1434 +
  1.1435 +nsresult
  1.1436 +RangeSubtreeIterator::Init(nsRange *aRange)
  1.1437 +{
  1.1438 +  mIterState = eDone;
  1.1439 +  if (aRange->Collapsed()) {
  1.1440 +    return NS_OK;
  1.1441 +  }
  1.1442 +
  1.1443 +  // Grab the start point of the range and QI it to
  1.1444 +  // a CharacterData pointer. If it is CharacterData store
  1.1445 +  // a pointer to the node.
  1.1446 +
  1.1447 +  ErrorResult rv;
  1.1448 +  nsCOMPtr<nsINode> node = aRange->GetStartContainer(rv);
  1.1449 +  if (!node) return NS_ERROR_FAILURE;
  1.1450 +
  1.1451 +  nsCOMPtr<nsIDOMCharacterData> startData = do_QueryInterface(node);
  1.1452 +  if (startData || (node->IsElement() &&
  1.1453 +                    node->AsElement()->GetChildCount() == aRange->GetStartOffset(rv))) {
  1.1454 +    mStart = node;
  1.1455 +  }
  1.1456 +
  1.1457 +  // Grab the end point of the range and QI it to
  1.1458 +  // a CharacterData pointer. If it is CharacterData store
  1.1459 +  // a pointer to the node.
  1.1460 +
  1.1461 +  node = aRange->GetEndContainer(rv);
  1.1462 +  if (!node) return NS_ERROR_FAILURE;
  1.1463 +
  1.1464 +  nsCOMPtr<nsIDOMCharacterData> endData = do_QueryInterface(node);
  1.1465 +  if (endData || (node->IsElement() && aRange->GetEndOffset(rv) == 0)) {
  1.1466 +    mEnd = node;
  1.1467 +  }
  1.1468 +
  1.1469 +  if (mStart && mStart == mEnd)
  1.1470 +  {
  1.1471 +    // The range starts and stops in the same CharacterData
  1.1472 +    // node. Null out the end pointer so we only visit the
  1.1473 +    // node once!
  1.1474 +
  1.1475 +    mEnd = nullptr;
  1.1476 +  }
  1.1477 +  else
  1.1478 +  {
  1.1479 +    // Now create a Content Subtree Iterator to be used
  1.1480 +    // for the subtrees between the end points!
  1.1481 +
  1.1482 +    mIter = NS_NewContentSubtreeIterator();
  1.1483 +
  1.1484 +    nsresult res = mIter->Init(aRange);
  1.1485 +    if (NS_FAILED(res)) return res;
  1.1486 +
  1.1487 +    if (mIter->IsDone())
  1.1488 +    {
  1.1489 +      // The subtree iterator thinks there's nothing
  1.1490 +      // to iterate over, so just free it up so we
  1.1491 +      // don't accidentally call into it.
  1.1492 +
  1.1493 +      mIter = nullptr;
  1.1494 +    }
  1.1495 +  }
  1.1496 +
  1.1497 +  // Initialize the iterator by calling First().
  1.1498 +  // Note that we are ignoring the return value on purpose!
  1.1499 +
  1.1500 +  First();
  1.1501 +
  1.1502 +  return NS_OK;
  1.1503 +}
  1.1504 +
  1.1505 +already_AddRefed<nsINode>
  1.1506 +RangeSubtreeIterator::GetCurrentNode()
  1.1507 +{
  1.1508 +  nsCOMPtr<nsINode> node;
  1.1509 +
  1.1510 +  if (mIterState == eUseStart && mStart) {
  1.1511 +    node = mStart;
  1.1512 +  } else if (mIterState == eUseEnd && mEnd) {
  1.1513 +    node = mEnd;
  1.1514 +  } else if (mIterState == eUseIterator && mIter) {
  1.1515 +    node = mIter->GetCurrentNode();
  1.1516 +  }
  1.1517 +
  1.1518 +  return node.forget();
  1.1519 +}
  1.1520 +
  1.1521 +void
  1.1522 +RangeSubtreeIterator::First()
  1.1523 +{
  1.1524 +  if (mStart)
  1.1525 +    mIterState = eUseStart;
  1.1526 +  else if (mIter)
  1.1527 +  {
  1.1528 +    mIter->First();
  1.1529 +
  1.1530 +    mIterState = eUseIterator;
  1.1531 +  }
  1.1532 +  else if (mEnd)
  1.1533 +    mIterState = eUseEnd;
  1.1534 +  else
  1.1535 +    mIterState = eDone;
  1.1536 +}
  1.1537 +
  1.1538 +void
  1.1539 +RangeSubtreeIterator::Last()
  1.1540 +{
  1.1541 +  if (mEnd)
  1.1542 +    mIterState = eUseEnd;
  1.1543 +  else if (mIter)
  1.1544 +  {
  1.1545 +    mIter->Last();
  1.1546 +
  1.1547 +    mIterState = eUseIterator;
  1.1548 +  }
  1.1549 +  else if (mStart)
  1.1550 +    mIterState = eUseStart;
  1.1551 +  else
  1.1552 +    mIterState = eDone;
  1.1553 +}
  1.1554 +
  1.1555 +void
  1.1556 +RangeSubtreeIterator::Next()
  1.1557 +{
  1.1558 +  if (mIterState == eUseStart)
  1.1559 +  {
  1.1560 +    if (mIter)
  1.1561 +    {
  1.1562 +      mIter->First();
  1.1563 +
  1.1564 +      mIterState = eUseIterator;
  1.1565 +    }
  1.1566 +    else if (mEnd)
  1.1567 +      mIterState = eUseEnd;
  1.1568 +    else
  1.1569 +      mIterState = eDone;
  1.1570 +  }
  1.1571 +  else if (mIterState == eUseIterator)
  1.1572 +  {
  1.1573 +    mIter->Next();
  1.1574 +
  1.1575 +    if (mIter->IsDone())
  1.1576 +    {
  1.1577 +      if (mEnd)
  1.1578 +        mIterState = eUseEnd;
  1.1579 +      else
  1.1580 +        mIterState = eDone;
  1.1581 +    }
  1.1582 +  }
  1.1583 +  else
  1.1584 +    mIterState = eDone;
  1.1585 +}
  1.1586 +
  1.1587 +void
  1.1588 +RangeSubtreeIterator::Prev()
  1.1589 +{
  1.1590 +  if (mIterState == eUseEnd)
  1.1591 +  {
  1.1592 +    if (mIter)
  1.1593 +    {
  1.1594 +      mIter->Last();
  1.1595 +
  1.1596 +      mIterState = eUseIterator;
  1.1597 +    }
  1.1598 +    else if (mStart)
  1.1599 +      mIterState = eUseStart;
  1.1600 +    else
  1.1601 +      mIterState = eDone;
  1.1602 +  }
  1.1603 +  else if (mIterState == eUseIterator)
  1.1604 +  {
  1.1605 +    mIter->Prev();
  1.1606 +
  1.1607 +    if (mIter->IsDone())
  1.1608 +    {
  1.1609 +      if (mStart)
  1.1610 +        mIterState = eUseStart;
  1.1611 +      else
  1.1612 +        mIterState = eDone;
  1.1613 +    }
  1.1614 +  }
  1.1615 +  else
  1.1616 +    mIterState = eDone;
  1.1617 +}
  1.1618 +
  1.1619 +
  1.1620 +// CollapseRangeAfterDelete() is a utility method that is used by
  1.1621 +// DeleteContents() and ExtractContents() to collapse the range
  1.1622 +// in the correct place, under the range's root container (the
  1.1623 +// range end points common container) as outlined by the Range spec:
  1.1624 +//
  1.1625 +// http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/ranges.html
  1.1626 +// The assumption made by this method is that the delete or extract
  1.1627 +// has been done already, and left the range in a state where there is
  1.1628 +// no content between the 2 end points.
  1.1629 +
  1.1630 +static nsresult
  1.1631 +CollapseRangeAfterDelete(nsRange* aRange)
  1.1632 +{
  1.1633 +  NS_ENSURE_ARG_POINTER(aRange);
  1.1634 +
  1.1635 +  // Check if range gravity took care of collapsing the range for us!
  1.1636 +  if (aRange->Collapsed())
  1.1637 +  {
  1.1638 +    // aRange is collapsed so there's nothing for us to do.
  1.1639 +    //
  1.1640 +    // There are 2 possible scenarios here:
  1.1641 +    //
  1.1642 +    // 1. aRange could've been collapsed prior to the delete/extract,
  1.1643 +    //    which would've resulted in nothing being removed, so aRange
  1.1644 +    //    is already where it should be.
  1.1645 +    //
  1.1646 +    // 2. Prior to the delete/extract, aRange's start and end were in
  1.1647 +    //    the same container which would mean everything between them
  1.1648 +    //    was removed, causing range gravity to collapse the range.
  1.1649 +
  1.1650 +    return NS_OK;
  1.1651 +  }
  1.1652 +
  1.1653 +  // aRange isn't collapsed so figure out the appropriate place to collapse!
  1.1654 +  // First get both end points and their common ancestor.
  1.1655 +
  1.1656 +  ErrorResult rv;
  1.1657 +  nsCOMPtr<nsINode> commonAncestor = aRange->GetCommonAncestorContainer(rv);
  1.1658 +  if (rv.Failed()) return rv.ErrorCode();
  1.1659 +
  1.1660 +  nsCOMPtr<nsINode> startContainer = aRange->GetStartContainer(rv);
  1.1661 +  if (rv.Failed()) return rv.ErrorCode();
  1.1662 +  nsCOMPtr<nsINode> endContainer = aRange->GetEndContainer(rv);
  1.1663 +  if (rv.Failed()) return rv.ErrorCode();
  1.1664 +
  1.1665 +  // Collapse to one of the end points if they are already in the
  1.1666 +  // commonAncestor. This should work ok since this method is called
  1.1667 +  // immediately after a delete or extract that leaves no content
  1.1668 +  // between the 2 end points!
  1.1669 +
  1.1670 +  if (startContainer == commonAncestor)
  1.1671 +    return aRange->Collapse(true);
  1.1672 +  if (endContainer == commonAncestor)
  1.1673 +    return aRange->Collapse(false);
  1.1674 +
  1.1675 +  // End points are at differing levels. We want to collapse to the
  1.1676 +  // point that is between the 2 subtrees that contain each point,
  1.1677 +  // under the common ancestor.
  1.1678 +
  1.1679 +  nsCOMPtr<nsINode> nodeToSelect(startContainer);
  1.1680 +
  1.1681 +  while (nodeToSelect)
  1.1682 +  {
  1.1683 +    nsCOMPtr<nsINode> parent = nodeToSelect->GetParentNode();
  1.1684 +    if (parent == commonAncestor)
  1.1685 +      break; // We found the nodeToSelect!
  1.1686 +
  1.1687 +    nodeToSelect = parent;
  1.1688 +  }
  1.1689 +
  1.1690 +  if (!nodeToSelect)
  1.1691 +    return NS_ERROR_FAILURE; // This should never happen!
  1.1692 +
  1.1693 +  aRange->SelectNode(*nodeToSelect, rv);
  1.1694 +  if (rv.Failed()) return rv.ErrorCode();
  1.1695 +
  1.1696 +  return aRange->Collapse(false);
  1.1697 +}
  1.1698 +
  1.1699 +/**
  1.1700 + * Split a data node into two parts.
  1.1701 + *
  1.1702 + * @param aStartNode          The original node we are trying to split.
  1.1703 + * @param aStartIndex         The index at which to split.
  1.1704 + * @param aEndNode            The second node.
  1.1705 + * @param aCloneAfterOriginal Set false if the original node should be the
  1.1706 + *                            latter one after split.
  1.1707 + */
  1.1708 +static nsresult SplitDataNode(nsIDOMCharacterData* aStartNode,
  1.1709 +                              uint32_t aStartIndex,
  1.1710 +                              nsIDOMCharacterData** aEndNode,
  1.1711 +                              bool aCloneAfterOriginal = true)
  1.1712 +{
  1.1713 +  nsresult rv;
  1.1714 +  nsCOMPtr<nsINode> node = do_QueryInterface(aStartNode);
  1.1715 +  NS_ENSURE_STATE(node && node->IsNodeOfType(nsINode::eDATA_NODE));
  1.1716 +  nsGenericDOMDataNode* dataNode = static_cast<nsGenericDOMDataNode*>(node.get());
  1.1717 +
  1.1718 +  nsCOMPtr<nsIContent> newData;
  1.1719 +  rv = dataNode->SplitData(aStartIndex, getter_AddRefs(newData),
  1.1720 +                           aCloneAfterOriginal);
  1.1721 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1722 +  return CallQueryInterface(newData, aEndNode);
  1.1723 +}
  1.1724 +
  1.1725 +NS_IMETHODIMP
  1.1726 +PrependChild(nsINode* aParent, nsINode* aChild)
  1.1727 +{
  1.1728 +  nsCOMPtr<nsINode> first = aParent->GetFirstChild();
  1.1729 +  ErrorResult rv;
  1.1730 +  aParent->InsertBefore(*aChild, first, rv);
  1.1731 +  return rv.ErrorCode();
  1.1732 +}
  1.1733 +
  1.1734 +// Helper function for CutContents, making sure that the current node wasn't
  1.1735 +// removed by mutation events (bug 766426)
  1.1736 +static bool
  1.1737 +ValidateCurrentNode(nsRange* aRange, RangeSubtreeIterator& aIter)
  1.1738 +{
  1.1739 +  bool before, after;
  1.1740 +  nsCOMPtr<nsINode> node = aIter.GetCurrentNode();
  1.1741 +  if (!node) {
  1.1742 +    // We don't have to worry that the node was removed if it doesn't exist,
  1.1743 +    // e.g., the iterator is done.
  1.1744 +    return true;
  1.1745 +  }
  1.1746 +
  1.1747 +  nsresult res = nsRange::CompareNodeToRange(node, aRange, &before, &after);
  1.1748 +
  1.1749 +  return NS_SUCCEEDED(res) && !before && !after;
  1.1750 +}
  1.1751 +
  1.1752 +nsresult
  1.1753 +nsRange::CutContents(DocumentFragment** aFragment)
  1.1754 +{
  1.1755 +  if (aFragment) {
  1.1756 +    *aFragment = nullptr;
  1.1757 +  }
  1.1758 +
  1.1759 +  nsCOMPtr<nsIDocument> doc = mStartParent->OwnerDoc();
  1.1760 +
  1.1761 +  ErrorResult res;
  1.1762 +  nsCOMPtr<nsINode> commonAncestor = GetCommonAncestorContainer(res);
  1.1763 +  NS_ENSURE_SUCCESS(res.ErrorCode(), res.ErrorCode());
  1.1764 +
  1.1765 +  // If aFragment isn't null, create a temporary fragment to hold our return.
  1.1766 +  nsRefPtr<DocumentFragment> retval;
  1.1767 +  if (aFragment) {
  1.1768 +    retval = new DocumentFragment(doc->NodeInfoManager());
  1.1769 +  }
  1.1770 +  nsCOMPtr<nsINode> commonCloneAncestor = retval.get();
  1.1771 +
  1.1772 +  // Batch possible DOMSubtreeModified events.
  1.1773 +  mozAutoSubtreeModified subtree(mRoot ? mRoot->OwnerDoc(): nullptr, nullptr);
  1.1774 +
  1.1775 +  // Save the range end points locally to avoid interference
  1.1776 +  // of Range gravity during our edits!
  1.1777 +
  1.1778 +  nsCOMPtr<nsINode> startContainer = mStartParent;
  1.1779 +  int32_t              startOffset = mStartOffset;
  1.1780 +  nsCOMPtr<nsINode> endContainer = mEndParent;
  1.1781 +  int32_t              endOffset = mEndOffset;
  1.1782 +
  1.1783 +  if (retval) {
  1.1784 +    // For extractContents(), abort early if there's a doctype (bug 719533).
  1.1785 +    // This can happen only if the common ancestor is a document, in which case
  1.1786 +    // we just need to find its doctype child and check if that's in the range.
  1.1787 +    nsCOMPtr<nsIDocument> commonAncestorDocument = do_QueryInterface(commonAncestor);
  1.1788 +    if (commonAncestorDocument) {
  1.1789 +      nsRefPtr<DocumentType> doctype = commonAncestorDocument->GetDoctype();
  1.1790 +
  1.1791 +      if (doctype &&
  1.1792 +          nsContentUtils::ComparePoints(startContainer, startOffset,
  1.1793 +                                        doctype, 0) < 0 &&
  1.1794 +          nsContentUtils::ComparePoints(doctype, 0,
  1.1795 +                                        endContainer, endOffset) < 0) {
  1.1796 +        return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
  1.1797 +      }
  1.1798 +    }
  1.1799 +  }
  1.1800 +
  1.1801 +  // Create and initialize a subtree iterator that will give
  1.1802 +  // us all the subtrees within the range.
  1.1803 +
  1.1804 +  RangeSubtreeIterator iter;
  1.1805 +
  1.1806 +  nsresult rv = iter.Init(this);
  1.1807 +  if (NS_FAILED(rv)) return rv;
  1.1808 +
  1.1809 +  if (iter.IsDone())
  1.1810 +  {
  1.1811 +    // There's nothing for us to delete.
  1.1812 +    rv = CollapseRangeAfterDelete(this);
  1.1813 +    if (NS_SUCCEEDED(rv) && aFragment) {
  1.1814 +      NS_ADDREF(*aFragment = retval);
  1.1815 +    }
  1.1816 +    return rv;
  1.1817 +  }
  1.1818 +
  1.1819 +  // We delete backwards to avoid iterator problems!
  1.1820 +
  1.1821 +  iter.Last();
  1.1822 +
  1.1823 +  bool handled = false;
  1.1824 +
  1.1825 +  // With the exception of text nodes that contain one of the range
  1.1826 +  // end points, the subtree iterator should only give us back subtrees
  1.1827 +  // that are completely contained between the range's end points.
  1.1828 +
  1.1829 +  while (!iter.IsDone())
  1.1830 +  {
  1.1831 +    nsCOMPtr<nsINode> nodeToResult;
  1.1832 +    nsCOMPtr<nsINode> node = iter.GetCurrentNode();
  1.1833 +
  1.1834 +    // Before we delete anything, advance the iterator to the
  1.1835 +    // next subtree.
  1.1836 +
  1.1837 +    iter.Prev();
  1.1838 +
  1.1839 +    handled = false;
  1.1840 +
  1.1841 +    // If it's CharacterData, make sure we might need to delete
  1.1842 +    // part of the data, instead of removing the whole node.
  1.1843 +    //
  1.1844 +    // XXX_kin: We need to also handle ProcessingInstruction
  1.1845 +    // XXX_kin: according to the spec.
  1.1846 +
  1.1847 +    nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(node));
  1.1848 +
  1.1849 +    if (charData)
  1.1850 +    {
  1.1851 +      uint32_t dataLength = 0;
  1.1852 +
  1.1853 +      if (node == startContainer)
  1.1854 +      {
  1.1855 +        if (node == endContainer)
  1.1856 +        {
  1.1857 +          // This range is completely contained within a single text node.
  1.1858 +          // Delete or extract the data between startOffset and endOffset.
  1.1859 +
  1.1860 +          if (endOffset > startOffset)
  1.1861 +          {
  1.1862 +            if (retval) {
  1.1863 +              nsAutoString cutValue;
  1.1864 +              rv = charData->SubstringData(startOffset, endOffset - startOffset,
  1.1865 +                                           cutValue);
  1.1866 +              NS_ENSURE_SUCCESS(rv, rv);
  1.1867 +              nsCOMPtr<nsIDOMNode> clone;
  1.1868 +              rv = charData->CloneNode(false, 1, getter_AddRefs(clone));
  1.1869 +              NS_ENSURE_SUCCESS(rv, rv);
  1.1870 +              clone->SetNodeValue(cutValue);
  1.1871 +              nodeToResult = do_QueryInterface(clone);
  1.1872 +            }
  1.1873 +
  1.1874 +            nsMutationGuard guard;
  1.1875 +            rv = charData->DeleteData(startOffset, endOffset - startOffset);
  1.1876 +            NS_ENSURE_SUCCESS(rv, rv);
  1.1877 +            NS_ENSURE_STATE(!guard.Mutated(0) ||
  1.1878 +                            ValidateCurrentNode(this, iter));
  1.1879 +          }
  1.1880 +
  1.1881 +          handled = true;
  1.1882 +        }
  1.1883 +        else
  1.1884 +        {
  1.1885 +          // Delete or extract everything after startOffset.
  1.1886 +
  1.1887 +          rv = charData->GetLength(&dataLength);
  1.1888 +          NS_ENSURE_SUCCESS(rv, rv);
  1.1889 +
  1.1890 +          if (dataLength >= (uint32_t)startOffset)
  1.1891 +          {
  1.1892 +            nsMutationGuard guard;
  1.1893 +            nsCOMPtr<nsIDOMCharacterData> cutNode;
  1.1894 +            rv = SplitDataNode(charData, startOffset, getter_AddRefs(cutNode));
  1.1895 +            NS_ENSURE_SUCCESS(rv, rv);
  1.1896 +            NS_ENSURE_STATE(!guard.Mutated(1) ||
  1.1897 +                            ValidateCurrentNode(this, iter));
  1.1898 +            nodeToResult = do_QueryInterface(cutNode);
  1.1899 +          }
  1.1900 +
  1.1901 +          handled = true;
  1.1902 +        }
  1.1903 +      }
  1.1904 +      else if (node == endContainer)
  1.1905 +      {
  1.1906 +        // Delete or extract everything before endOffset.
  1.1907 +
  1.1908 +        if (endOffset >= 0)
  1.1909 +        {
  1.1910 +          nsMutationGuard guard;
  1.1911 +          nsCOMPtr<nsIDOMCharacterData> cutNode;
  1.1912 +          /* The Range spec clearly states clones get cut and original nodes
  1.1913 +             remain behind, so use false as the last parameter.
  1.1914 +          */
  1.1915 +          rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
  1.1916 +                             false);
  1.1917 +          NS_ENSURE_SUCCESS(rv, rv);
  1.1918 +          NS_ENSURE_STATE(!guard.Mutated(1) ||
  1.1919 +                          ValidateCurrentNode(this, iter));
  1.1920 +          nodeToResult = do_QueryInterface(cutNode);
  1.1921 +        }
  1.1922 +
  1.1923 +        handled = true;
  1.1924 +      }
  1.1925 +    }
  1.1926 +
  1.1927 +    if (!handled && (node == endContainer || node == startContainer))
  1.1928 +    {
  1.1929 +      if (node && node->IsElement() &&
  1.1930 +          ((node == endContainer && endOffset == 0) ||
  1.1931 +           (node == startContainer &&
  1.1932 +            int32_t(node->AsElement()->GetChildCount()) == startOffset)))
  1.1933 +      {
  1.1934 +        if (retval) {
  1.1935 +          ErrorResult rv;
  1.1936 +          nodeToResult = node->CloneNode(false, rv);
  1.1937 +          NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
  1.1938 +        }
  1.1939 +        handled = true;
  1.1940 +      }
  1.1941 +    }
  1.1942 +
  1.1943 +    if (!handled)
  1.1944 +    {
  1.1945 +      // node was not handled above, so it must be completely contained
  1.1946 +      // within the range. Just remove it from the tree!
  1.1947 +      nodeToResult = node;
  1.1948 +    }
  1.1949 +
  1.1950 +    uint32_t parentCount = 0;
  1.1951 +    // Set the result to document fragment if we have 'retval'.
  1.1952 +    if (retval) {
  1.1953 +      nsCOMPtr<nsINode> oldCommonAncestor = commonAncestor;
  1.1954 +      if (!iter.IsDone()) {
  1.1955 +        // Setup the parameters for the next iteration of the loop.
  1.1956 +        nsCOMPtr<nsINode> prevNode = iter.GetCurrentNode();
  1.1957 +        NS_ENSURE_STATE(prevNode);
  1.1958 +
  1.1959 +        // Get node's and prevNode's common parent. Do this before moving
  1.1960 +        // nodes from original DOM to result fragment.
  1.1961 +        commonAncestor = nsContentUtils::GetCommonAncestor(node, prevNode);
  1.1962 +        NS_ENSURE_STATE(commonAncestor);
  1.1963 +
  1.1964 +        nsCOMPtr<nsINode> parentCounterNode = node;
  1.1965 +        while (parentCounterNode && parentCounterNode != commonAncestor)
  1.1966 +        {
  1.1967 +          ++parentCount;
  1.1968 +          parentCounterNode = parentCounterNode->GetParentNode();
  1.1969 +          NS_ENSURE_STATE(parentCounterNode);
  1.1970 +        }
  1.1971 +      }
  1.1972 +
  1.1973 +      // Clone the parent hierarchy between commonAncestor and node.
  1.1974 +      nsCOMPtr<nsINode> closestAncestor, farthestAncestor;
  1.1975 +      rv = CloneParentsBetween(oldCommonAncestor, node,
  1.1976 +                               getter_AddRefs(closestAncestor),
  1.1977 +                               getter_AddRefs(farthestAncestor));
  1.1978 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1979 +
  1.1980 +      if (farthestAncestor)
  1.1981 +      {
  1.1982 +        nsCOMPtr<nsINode> n = do_QueryInterface(commonCloneAncestor);
  1.1983 +        rv = PrependChild(n, farthestAncestor);
  1.1984 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1985 +      }
  1.1986 +
  1.1987 +      nsMutationGuard guard;
  1.1988 +      nsCOMPtr<nsINode> parent = nodeToResult->GetParentNode();
  1.1989 +      rv = closestAncestor ? PrependChild(closestAncestor, nodeToResult)
  1.1990 +                           : PrependChild(commonCloneAncestor, nodeToResult);
  1.1991 +      NS_ENSURE_SUCCESS(rv, rv);
  1.1992 +      NS_ENSURE_STATE(!guard.Mutated(parent ? 2 : 1) ||
  1.1993 +                      ValidateCurrentNode(this, iter));
  1.1994 +    } else if (nodeToResult) {
  1.1995 +      nsMutationGuard guard;
  1.1996 +      nsCOMPtr<nsINode> node = nodeToResult;
  1.1997 +      nsINode* parent = node->GetParentNode();
  1.1998 +      if (parent) {
  1.1999 +        mozilla::ErrorResult error;
  1.2000 +        parent->RemoveChild(*node, error);
  1.2001 +        NS_ENSURE_FALSE(error.Failed(), error.ErrorCode());
  1.2002 +      }
  1.2003 +      NS_ENSURE_STATE(!guard.Mutated(1) ||
  1.2004 +                      ValidateCurrentNode(this, iter));
  1.2005 +    }
  1.2006 +
  1.2007 +    if (!iter.IsDone() && retval) {
  1.2008 +      // Find the equivalent of commonAncestor in the cloned tree.
  1.2009 +      nsCOMPtr<nsINode> newCloneAncestor = nodeToResult;
  1.2010 +      for (uint32_t i = parentCount; i; --i)
  1.2011 +      {
  1.2012 +        newCloneAncestor = newCloneAncestor->GetParentNode();
  1.2013 +        NS_ENSURE_STATE(newCloneAncestor);
  1.2014 +      }
  1.2015 +      commonCloneAncestor = newCloneAncestor;
  1.2016 +    }
  1.2017 +  }
  1.2018 +
  1.2019 +  rv = CollapseRangeAfterDelete(this);
  1.2020 +  if (NS_SUCCEEDED(rv) && aFragment) {
  1.2021 +    NS_ADDREF(*aFragment = retval);
  1.2022 +  }
  1.2023 +  return rv;
  1.2024 +}
  1.2025 +
  1.2026 +NS_IMETHODIMP
  1.2027 +nsRange::DeleteContents()
  1.2028 +{
  1.2029 +  return CutContents(nullptr);
  1.2030 +}
  1.2031 +
  1.2032 +void
  1.2033 +nsRange::DeleteContents(ErrorResult& aRv)
  1.2034 +{
  1.2035 +  aRv = CutContents(nullptr);
  1.2036 +}
  1.2037 +
  1.2038 +NS_IMETHODIMP
  1.2039 +nsRange::ExtractContents(nsIDOMDocumentFragment** aReturn)
  1.2040 +{
  1.2041 +  NS_ENSURE_ARG_POINTER(aReturn);
  1.2042 +  nsRefPtr<DocumentFragment> fragment;
  1.2043 +  nsresult rv = CutContents(getter_AddRefs(fragment));
  1.2044 +  fragment.forget(aReturn);
  1.2045 +  return rv;
  1.2046 +}
  1.2047 +
  1.2048 +already_AddRefed<DocumentFragment>
  1.2049 +nsRange::ExtractContents(ErrorResult& rv)
  1.2050 +{
  1.2051 +  nsRefPtr<DocumentFragment> fragment;
  1.2052 +  rv = CutContents(getter_AddRefs(fragment));
  1.2053 +  return fragment.forget();
  1.2054 +}
  1.2055 +
  1.2056 +NS_IMETHODIMP
  1.2057 +nsRange::CompareBoundaryPoints(uint16_t aHow, nsIDOMRange* aOtherRange,
  1.2058 +                               int16_t* aCmpRet)
  1.2059 +{
  1.2060 +  nsRange* otherRange = static_cast<nsRange*>(aOtherRange);
  1.2061 +  NS_ENSURE_TRUE(otherRange, NS_ERROR_NULL_POINTER);
  1.2062 +
  1.2063 +  ErrorResult rv;
  1.2064 +  *aCmpRet = CompareBoundaryPoints(aHow, *otherRange, rv);
  1.2065 +  return rv.ErrorCode();
  1.2066 +}
  1.2067 +
  1.2068 +int16_t
  1.2069 +nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
  1.2070 +                               ErrorResult& rv)
  1.2071 +{
  1.2072 +  if (!mIsPositioned || !aOtherRange.IsPositioned()) {
  1.2073 +    rv.Throw(NS_ERROR_NOT_INITIALIZED);
  1.2074 +    return 0;
  1.2075 +  }
  1.2076 +
  1.2077 +  nsINode *ourNode, *otherNode;
  1.2078 +  int32_t ourOffset, otherOffset;
  1.2079 +
  1.2080 +  switch (aHow) {
  1.2081 +    case nsIDOMRange::START_TO_START:
  1.2082 +      ourNode = mStartParent;
  1.2083 +      ourOffset = mStartOffset;
  1.2084 +      otherNode = aOtherRange.GetStartParent();
  1.2085 +      otherOffset = aOtherRange.StartOffset();
  1.2086 +      break;
  1.2087 +    case nsIDOMRange::START_TO_END:
  1.2088 +      ourNode = mEndParent;
  1.2089 +      ourOffset = mEndOffset;
  1.2090 +      otherNode = aOtherRange.GetStartParent();
  1.2091 +      otherOffset = aOtherRange.StartOffset();
  1.2092 +      break;
  1.2093 +    case nsIDOMRange::END_TO_START:
  1.2094 +      ourNode = mStartParent;
  1.2095 +      ourOffset = mStartOffset;
  1.2096 +      otherNode = aOtherRange.GetEndParent();
  1.2097 +      otherOffset = aOtherRange.EndOffset();
  1.2098 +      break;
  1.2099 +    case nsIDOMRange::END_TO_END:
  1.2100 +      ourNode = mEndParent;
  1.2101 +      ourOffset = mEndOffset;
  1.2102 +      otherNode = aOtherRange.GetEndParent();
  1.2103 +      otherOffset = aOtherRange.EndOffset();
  1.2104 +      break;
  1.2105 +    default:
  1.2106 +      // We were passed an illegal value
  1.2107 +      rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
  1.2108 +      return 0;
  1.2109 +  }
  1.2110 +
  1.2111 +  if (mRoot != aOtherRange.GetRoot()) {
  1.2112 +    rv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
  1.2113 +    return 0;
  1.2114 +  }
  1.2115 +
  1.2116 +  return nsContentUtils::ComparePoints(ourNode, ourOffset,
  1.2117 +                                       otherNode, otherOffset);
  1.2118 +}
  1.2119 +
  1.2120 +/* static */ nsresult
  1.2121 +nsRange::CloneParentsBetween(nsINode *aAncestor,
  1.2122 +                             nsINode *aNode,
  1.2123 +                             nsINode **aClosestAncestor,
  1.2124 +                             nsINode **aFarthestAncestor)
  1.2125 +{
  1.2126 +  NS_ENSURE_ARG_POINTER((aAncestor && aNode && aClosestAncestor && aFarthestAncestor));
  1.2127 +
  1.2128 +  *aClosestAncestor  = nullptr;
  1.2129 +  *aFarthestAncestor = nullptr;
  1.2130 +
  1.2131 +  if (aAncestor == aNode)
  1.2132 +    return NS_OK;
  1.2133 +
  1.2134 +  nsCOMPtr<nsINode> firstParent, lastParent;
  1.2135 +  nsCOMPtr<nsINode> parent = aNode->GetParentNode();
  1.2136 +
  1.2137 +  while(parent && parent != aAncestor)
  1.2138 +  {
  1.2139 +    ErrorResult rv;
  1.2140 +    nsCOMPtr<nsINode> clone = parent->CloneNode(false, rv);
  1.2141 +
  1.2142 +    if (rv.Failed()) {
  1.2143 +      return rv.ErrorCode();
  1.2144 +    }
  1.2145 +    if (!clone) {
  1.2146 +      return NS_ERROR_FAILURE;
  1.2147 +    }
  1.2148 +
  1.2149 +    if (! firstParent) {
  1.2150 +      firstParent = lastParent = clone;
  1.2151 +    } else {
  1.2152 +      clone->AppendChild(*lastParent, rv);
  1.2153 +      if (rv.Failed()) return rv.ErrorCode();
  1.2154 +
  1.2155 +      lastParent = clone;
  1.2156 +    }
  1.2157 +
  1.2158 +    parent = parent->GetParentNode();
  1.2159 +  }
  1.2160 +
  1.2161 +  *aClosestAncestor  = firstParent;
  1.2162 +  NS_IF_ADDREF(*aClosestAncestor);
  1.2163 +
  1.2164 +  *aFarthestAncestor = lastParent;
  1.2165 +  NS_IF_ADDREF(*aFarthestAncestor);
  1.2166 +
  1.2167 +  return NS_OK;
  1.2168 +}
  1.2169 +
  1.2170 +NS_IMETHODIMP
  1.2171 +nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
  1.2172 +{
  1.2173 +  ErrorResult rv;
  1.2174 +  *aReturn = CloneContents(rv).take();
  1.2175 +  return rv.ErrorCode();
  1.2176 +}
  1.2177 +
  1.2178 +already_AddRefed<DocumentFragment>
  1.2179 +nsRange::CloneContents(ErrorResult& aRv)
  1.2180 +{
  1.2181 +  nsCOMPtr<nsINode> commonAncestor = GetCommonAncestorContainer(aRv);
  1.2182 +  MOZ_ASSERT(!aRv.Failed(), "GetCommonAncestorContainer() shouldn't fail!");
  1.2183 +
  1.2184 +  nsCOMPtr<nsIDocument> doc = mStartParent->OwnerDoc();
  1.2185 +  NS_ASSERTION(doc, "CloneContents needs a document to continue.");
  1.2186 +  if (!doc) {
  1.2187 +    aRv.Throw(NS_ERROR_FAILURE);
  1.2188 +    return nullptr;
  1.2189 +  }
  1.2190 +
  1.2191 +  // Create a new document fragment in the context of this document,
  1.2192 +  // which might be null
  1.2193 +
  1.2194 +
  1.2195 +  nsRefPtr<DocumentFragment> clonedFrag =
  1.2196 +    new DocumentFragment(doc->NodeInfoManager());
  1.2197 +
  1.2198 +  nsCOMPtr<nsINode> commonCloneAncestor = clonedFrag.get();
  1.2199 +
  1.2200 +  // Create and initialize a subtree iterator that will give
  1.2201 +  // us all the subtrees within the range.
  1.2202 +
  1.2203 +  RangeSubtreeIterator iter;
  1.2204 +
  1.2205 +  aRv = iter.Init(this);
  1.2206 +  if (aRv.Failed()) {
  1.2207 +    return nullptr;
  1.2208 +  }
  1.2209 +
  1.2210 +  if (iter.IsDone())
  1.2211 +  {
  1.2212 +    // There's nothing to add to the doc frag, we must be done!
  1.2213 +    return clonedFrag.forget();
  1.2214 +  }
  1.2215 +
  1.2216 +  iter.First();
  1.2217 +
  1.2218 +  // With the exception of text nodes that contain one of the range
  1.2219 +  // end points and elements which don't have any content selected the subtree
  1.2220 +  // iterator should only give us back subtrees that are completely contained
  1.2221 +  // between the range's end points.
  1.2222 +  //
  1.2223 +  // Unfortunately these subtrees don't contain the parent hierarchy/context
  1.2224 +  // that the Range spec requires us to return. This loop clones the
  1.2225 +  // parent hierarchy, adds a cloned version of the subtree, to it, then
  1.2226 +  // correctly places this new subtree into the doc fragment.
  1.2227 +
  1.2228 +  while (!iter.IsDone())
  1.2229 +  {
  1.2230 +    nsCOMPtr<nsINode> node = iter.GetCurrentNode();
  1.2231 +    bool deepClone = !node->IsElement() ||
  1.2232 +                       (!(node == mEndParent && mEndOffset == 0) &&
  1.2233 +                        !(node == mStartParent &&
  1.2234 +                          mStartOffset ==
  1.2235 +                            int32_t(node->AsElement()->GetChildCount())));
  1.2236 +
  1.2237 +    // Clone the current subtree!
  1.2238 +
  1.2239 +    nsCOMPtr<nsINode> clone = node->CloneNode(deepClone, aRv);
  1.2240 +    if (aRv.Failed()) {
  1.2241 +      return nullptr;
  1.2242 +    }
  1.2243 +
  1.2244 +    // If it's CharacterData, make sure we only clone what
  1.2245 +    // is in the range.
  1.2246 +    //
  1.2247 +    // XXX_kin: We need to also handle ProcessingInstruction
  1.2248 +    // XXX_kin: according to the spec.
  1.2249 +
  1.2250 +    nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(clone));
  1.2251 +
  1.2252 +    if (charData)
  1.2253 +    {
  1.2254 +      if (node == mEndParent)
  1.2255 +      {
  1.2256 +        // We only need the data before mEndOffset, so get rid of any
  1.2257 +        // data after it.
  1.2258 +
  1.2259 +        uint32_t dataLength = 0;
  1.2260 +        aRv = charData->GetLength(&dataLength);
  1.2261 +        if (aRv.Failed()) {
  1.2262 +          return nullptr;
  1.2263 +        }
  1.2264 +
  1.2265 +        if (dataLength > (uint32_t)mEndOffset)
  1.2266 +        {
  1.2267 +          aRv = charData->DeleteData(mEndOffset, dataLength - mEndOffset);
  1.2268 +          if (aRv.Failed()) {
  1.2269 +            return nullptr;
  1.2270 +          }
  1.2271 +        }
  1.2272 +      }
  1.2273 +
  1.2274 +      if (node == mStartParent)
  1.2275 +      {
  1.2276 +        // We don't need any data before mStartOffset, so just
  1.2277 +        // delete it!
  1.2278 +
  1.2279 +        if (mStartOffset > 0)
  1.2280 +        {
  1.2281 +          aRv = charData->DeleteData(0, mStartOffset);
  1.2282 +          if (aRv.Failed()) {
  1.2283 +            return nullptr;
  1.2284 +          }
  1.2285 +        }
  1.2286 +      }
  1.2287 +    }
  1.2288 +
  1.2289 +    // Clone the parent hierarchy between commonAncestor and node.
  1.2290 +
  1.2291 +    nsCOMPtr<nsINode> closestAncestor, farthestAncestor;
  1.2292 +
  1.2293 +    aRv = CloneParentsBetween(commonAncestor, node,
  1.2294 +                              getter_AddRefs(closestAncestor),
  1.2295 +                              getter_AddRefs(farthestAncestor));
  1.2296 +
  1.2297 +    if (aRv.Failed()) {
  1.2298 +      return nullptr;
  1.2299 +    }
  1.2300 +
  1.2301 +    // Hook the parent hierarchy/context of the subtree into the clone tree.
  1.2302 +
  1.2303 +    if (farthestAncestor)
  1.2304 +    {
  1.2305 +      commonCloneAncestor->AppendChild(*farthestAncestor, aRv);
  1.2306 +
  1.2307 +      if (aRv.Failed()) {
  1.2308 +        return nullptr;
  1.2309 +      }
  1.2310 +    }
  1.2311 +
  1.2312 +    // Place the cloned subtree into the cloned doc frag tree!
  1.2313 +
  1.2314 +    nsCOMPtr<nsINode> cloneNode = do_QueryInterface(clone);
  1.2315 +    if (closestAncestor)
  1.2316 +    {
  1.2317 +      // Append the subtree under closestAncestor since it is the
  1.2318 +      // immediate parent of the subtree.
  1.2319 +
  1.2320 +      closestAncestor->AppendChild(*cloneNode, aRv);
  1.2321 +    }
  1.2322 +    else
  1.2323 +    {
  1.2324 +      // If we get here, there is no missing parent hierarchy between
  1.2325 +      // commonAncestor and node, so just append clone to commonCloneAncestor.
  1.2326 +
  1.2327 +      commonCloneAncestor->AppendChild(*cloneNode, aRv);
  1.2328 +    }
  1.2329 +    if (aRv.Failed()) {
  1.2330 +      return nullptr;
  1.2331 +    }
  1.2332 +
  1.2333 +    // Get the next subtree to be processed. The idea here is to setup
  1.2334 +    // the parameters for the next iteration of the loop.
  1.2335 +
  1.2336 +    iter.Next();
  1.2337 +
  1.2338 +    if (iter.IsDone())
  1.2339 +      break; // We must be done!
  1.2340 +
  1.2341 +    nsCOMPtr<nsINode> nextNode = iter.GetCurrentNode();
  1.2342 +    if (!nextNode) {
  1.2343 +      aRv.Throw(NS_ERROR_FAILURE);
  1.2344 +      return nullptr;
  1.2345 +    }
  1.2346 +
  1.2347 +    // Get node and nextNode's common parent.
  1.2348 +    commonAncestor = nsContentUtils::GetCommonAncestor(node, nextNode);
  1.2349 +
  1.2350 +    if (!commonAncestor) {
  1.2351 +      aRv.Throw(NS_ERROR_FAILURE);
  1.2352 +      return nullptr;
  1.2353 +    }
  1.2354 +
  1.2355 +    // Find the equivalent of commonAncestor in the cloned tree!
  1.2356 +
  1.2357 +    while (node && node != commonAncestor)
  1.2358 +    {
  1.2359 +      node = node->GetParentNode();
  1.2360 +      if (aRv.Failed()) {
  1.2361 +        return nullptr;
  1.2362 +      }
  1.2363 +
  1.2364 +      if (!node) {
  1.2365 +        aRv.Throw(NS_ERROR_FAILURE);
  1.2366 +        return nullptr;
  1.2367 +      }
  1.2368 +
  1.2369 +      cloneNode = cloneNode->GetParentNode();
  1.2370 +      if (!cloneNode) {
  1.2371 +        aRv.Throw(NS_ERROR_FAILURE);
  1.2372 +        return nullptr;
  1.2373 +      }
  1.2374 +    }
  1.2375 +
  1.2376 +    commonCloneAncestor = cloneNode;
  1.2377 +  }
  1.2378 +
  1.2379 +  return clonedFrag.forget();
  1.2380 +}
  1.2381 +
  1.2382 +already_AddRefed<nsRange>
  1.2383 +nsRange::CloneRange() const
  1.2384 +{
  1.2385 +  nsRefPtr<nsRange> range = new nsRange(mOwner);
  1.2386 +
  1.2387 +  range->SetMaySpanAnonymousSubtrees(mMaySpanAnonymousSubtrees);
  1.2388 +
  1.2389 +  range->DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, mRoot);
  1.2390 +
  1.2391 +  return range.forget();
  1.2392 +}
  1.2393 +
  1.2394 +NS_IMETHODIMP
  1.2395 +nsRange::CloneRange(nsIDOMRange** aReturn)
  1.2396 +{
  1.2397 +  *aReturn = CloneRange().take();
  1.2398 +  return NS_OK;
  1.2399 +}
  1.2400 +
  1.2401 +NS_IMETHODIMP
  1.2402 +nsRange::InsertNode(nsIDOMNode* aNode)
  1.2403 +{
  1.2404 +  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
  1.2405 +  if (!node) {
  1.2406 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.2407 +  }
  1.2408 +
  1.2409 +  ErrorResult rv;
  1.2410 +  InsertNode(*node, rv);
  1.2411 +  return rv.ErrorCode();
  1.2412 +}
  1.2413 +
  1.2414 +void
  1.2415 +nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
  1.2416 +{
  1.2417 +  if (!nsContentUtils::CanCallerAccess(&aNode)) {
  1.2418 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.2419 +    return;
  1.2420 +  }
  1.2421 +
  1.2422 +  int32_t tStartOffset = StartOffset();
  1.2423 +
  1.2424 +  nsCOMPtr<nsINode> tStartContainer = GetStartContainer(aRv);
  1.2425 +  if (aRv.Failed()) {
  1.2426 +    return;
  1.2427 +  }
  1.2428 +
  1.2429 +  // This is the node we'll be inserting before, and its parent
  1.2430 +  nsCOMPtr<nsINode> referenceNode;
  1.2431 +  nsCOMPtr<nsINode> referenceParentNode = tStartContainer;
  1.2432 +
  1.2433 +  nsCOMPtr<nsIDOMText> startTextNode(do_QueryInterface(tStartContainer));
  1.2434 +  nsCOMPtr<nsIDOMNodeList> tChildList;
  1.2435 +  if (startTextNode) {
  1.2436 +    referenceParentNode = tStartContainer->GetParentNode();
  1.2437 +    if (!referenceParentNode) {
  1.2438 +      aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1.2439 +      return;
  1.2440 +    }
  1.2441 +
  1.2442 +    nsCOMPtr<nsIDOMText> secondPart;
  1.2443 +    aRv = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart));
  1.2444 +    if (aRv.Failed()) {
  1.2445 +      return;
  1.2446 +    }
  1.2447 +
  1.2448 +    referenceNode = do_QueryInterface(secondPart);
  1.2449 +  } else {
  1.2450 +    aRv = tStartContainer->AsDOMNode()->GetChildNodes(getter_AddRefs(tChildList));
  1.2451 +    if (aRv.Failed()) {
  1.2452 +      return;
  1.2453 +    }
  1.2454 +
  1.2455 +    // find the insertion point in the DOM and insert the Node
  1.2456 +    nsCOMPtr<nsIDOMNode> q;
  1.2457 +    aRv = tChildList->Item(tStartOffset, getter_AddRefs(q));
  1.2458 +    referenceNode = do_QueryInterface(q);
  1.2459 +    if (aRv.Failed()) {
  1.2460 +      return;
  1.2461 +    }
  1.2462 +  }
  1.2463 +
  1.2464 +  // We might need to update the end to include the new node (bug 433662).
  1.2465 +  // Ideally we'd only do this if needed, but it's tricky to know when it's
  1.2466 +  // needed in advance (bug 765799).
  1.2467 +  int32_t newOffset;
  1.2468 +
  1.2469 +  if (referenceNode) {
  1.2470 +    newOffset = IndexOf(referenceNode);
  1.2471 +  } else {
  1.2472 +    uint32_t length;
  1.2473 +    aRv = tChildList->GetLength(&length);
  1.2474 +    if (aRv.Failed()) {
  1.2475 +      return;
  1.2476 +    }
  1.2477 +
  1.2478 +    newOffset = length;
  1.2479 +  }
  1.2480 +
  1.2481 +  if (aNode.NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  1.2482 +    newOffset += aNode.GetChildCount();
  1.2483 +  } else {
  1.2484 +    newOffset++;
  1.2485 +  }
  1.2486 +
  1.2487 +  // Now actually insert the node
  1.2488 +  nsCOMPtr<nsINode> tResultNode;
  1.2489 +  tResultNode = referenceParentNode->InsertBefore(aNode, referenceNode, aRv);
  1.2490 +  if (aRv.Failed()) {
  1.2491 +    return;
  1.2492 +  }
  1.2493 +
  1.2494 +  if (Collapsed()) {
  1.2495 +    aRv = SetEnd(referenceParentNode, newOffset);
  1.2496 +  }
  1.2497 +}
  1.2498 +
  1.2499 +NS_IMETHODIMP
  1.2500 +nsRange::SurroundContents(nsIDOMNode* aNewParent)
  1.2501 +{
  1.2502 +  nsCOMPtr<nsINode> node = do_QueryInterface(aNewParent);
  1.2503 +  if (!node) {
  1.2504 +    return NS_ERROR_DOM_NOT_OBJECT_ERR;
  1.2505 +  }
  1.2506 +  ErrorResult rv;
  1.2507 +  SurroundContents(*node, rv);
  1.2508 +  return rv.ErrorCode();
  1.2509 +}
  1.2510 +
  1.2511 +void
  1.2512 +nsRange::SurroundContents(nsINode& aNewParent, ErrorResult& aRv)
  1.2513 +{
  1.2514 +  if (!nsContentUtils::CanCallerAccess(&aNewParent)) {
  1.2515 +    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  1.2516 +    return;
  1.2517 +  }
  1.2518 +
  1.2519 +  if (!mRoot) {
  1.2520 +    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  1.2521 +    return;
  1.2522 +  }
  1.2523 +  // INVALID_STATE_ERROR: Raised if the Range partially selects a non-text
  1.2524 +  // node.
  1.2525 +  if (mStartParent != mEndParent) {
  1.2526 +    bool startIsText = mStartParent->IsNodeOfType(nsINode::eTEXT);
  1.2527 +    bool endIsText = mEndParent->IsNodeOfType(nsINode::eTEXT);
  1.2528 +    nsINode* startGrandParent = mStartParent->GetParentNode();
  1.2529 +    nsINode* endGrandParent = mEndParent->GetParentNode();
  1.2530 +    if (!((startIsText && endIsText &&
  1.2531 +           startGrandParent &&
  1.2532 +           startGrandParent == endGrandParent) ||
  1.2533 +          (startIsText &&
  1.2534 +           startGrandParent &&
  1.2535 +           startGrandParent == mEndParent) ||
  1.2536 +          (endIsText &&
  1.2537 +           endGrandParent &&
  1.2538 +           endGrandParent == mStartParent))) {
  1.2539 +      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
  1.2540 +      return;
  1.2541 +    }
  1.2542 +  }
  1.2543 +
  1.2544 +  // INVALID_NODE_TYPE_ERROR if aNewParent is something that can't be inserted
  1.2545 +  // (Document, DocumentType, DocumentFragment)
  1.2546 +  uint16_t nodeType = aNewParent.NodeType();
  1.2547 +  if (nodeType == nsIDOMNode::DOCUMENT_NODE ||
  1.2548 +      nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE ||
  1.2549 +      nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  1.2550 +    aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
  1.2551 +    return;
  1.2552 +  }
  1.2553 +
  1.2554 +  // Extract the contents within the range.
  1.2555 +
  1.2556 +  nsRefPtr<DocumentFragment> docFrag = ExtractContents(aRv);
  1.2557 +
  1.2558 +  if (aRv.Failed()) {
  1.2559 +    return;
  1.2560 +  }
  1.2561 +
  1.2562 +  if (!docFrag) {
  1.2563 +    aRv.Throw(NS_ERROR_FAILURE);
  1.2564 +    return;
  1.2565 +  }
  1.2566 +
  1.2567 +  // Spec says we need to remove all of aNewParent's
  1.2568 +  // children prior to insertion.
  1.2569 +
  1.2570 +  nsCOMPtr<nsINodeList> children = aNewParent.ChildNodes();
  1.2571 +  if (!children) {
  1.2572 +    aRv.Throw(NS_ERROR_FAILURE);
  1.2573 +    return;
  1.2574 +  }
  1.2575 +
  1.2576 +  uint32_t numChildren = children->Length();
  1.2577 +
  1.2578 +  while (numChildren)
  1.2579 +  {
  1.2580 +    nsCOMPtr<nsINode> child = children->Item(--numChildren);
  1.2581 +    if (!child) {
  1.2582 +      aRv.Throw(NS_ERROR_FAILURE);
  1.2583 +      return;
  1.2584 +    }
  1.2585 +
  1.2586 +    aNewParent.RemoveChild(*child, aRv);
  1.2587 +    if (aRv.Failed()) {
  1.2588 +      return;
  1.2589 +    }
  1.2590 +  }
  1.2591 +
  1.2592 +  // Insert aNewParent at the range's start point.
  1.2593 +
  1.2594 +  InsertNode(aNewParent, aRv);
  1.2595 +  if (aRv.Failed()) {
  1.2596 +    return;
  1.2597 +  }
  1.2598 +
  1.2599 +  // Append the content we extracted under aNewParent.
  1.2600 +  aNewParent.AppendChild(*docFrag, aRv);
  1.2601 +  if (aRv.Failed()) {
  1.2602 +    return;
  1.2603 +  }
  1.2604 +
  1.2605 +  // Select aNewParent, and its contents.
  1.2606 +
  1.2607 +  SelectNode(aNewParent, aRv);
  1.2608 +}
  1.2609 +
  1.2610 +NS_IMETHODIMP
  1.2611 +nsRange::ToString(nsAString& aReturn)
  1.2612 +{
  1.2613 +  // clear the string
  1.2614 +  aReturn.Truncate();
  1.2615 +
  1.2616 +  // If we're unpositioned, return the empty string
  1.2617 +  if (!mIsPositioned) {
  1.2618 +    return NS_OK;
  1.2619 +  }
  1.2620 +
  1.2621 +#ifdef DEBUG_range
  1.2622 +      printf("Range dump: -----------------------\n");
  1.2623 +#endif /* DEBUG */
  1.2624 +
  1.2625 +  // effeciency hack for simple case
  1.2626 +  if (mStartParent == mEndParent)
  1.2627 +  {
  1.2628 +    nsCOMPtr<nsIDOMText> textNode( do_QueryInterface(mStartParent) );
  1.2629 +
  1.2630 +    if (textNode)
  1.2631 +    {
  1.2632 +#ifdef DEBUG_range
  1.2633 +      // If debug, dump it:
  1.2634 +      nsCOMPtr<nsIContent> cN (do_QueryInterface(mStartParent));
  1.2635 +      if (cN) cN->List(stdout);
  1.2636 +      printf("End Range dump: -----------------------\n");
  1.2637 +#endif /* DEBUG */
  1.2638 +
  1.2639 +      // grab the text
  1.2640 +      if (NS_FAILED(textNode->SubstringData(mStartOffset,mEndOffset-mStartOffset,aReturn)))
  1.2641 +        return NS_ERROR_UNEXPECTED;
  1.2642 +      return NS_OK;
  1.2643 +    }
  1.2644 +  }
  1.2645 +
  1.2646 +  /* complex case: mStartParent != mEndParent, or mStartParent not a text node
  1.2647 +     revisit - there are potential optimizations here and also tradeoffs.
  1.2648 +  */
  1.2649 +
  1.2650 +  nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
  1.2651 +  nsresult rv = iter->Init(this);
  1.2652 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2653 +
  1.2654 +  nsString tempString;
  1.2655 +
  1.2656 +  // loop through the content iterator, which returns nodes in the range in 
  1.2657 +  // close tag order, and grab the text from any text node
  1.2658 +  while (!iter->IsDone())
  1.2659 +  {
  1.2660 +    nsINode *n = iter->GetCurrentNode();
  1.2661 +
  1.2662 +#ifdef DEBUG_range
  1.2663 +    // If debug, dump it:
  1.2664 +    n->List(stdout);
  1.2665 +#endif /* DEBUG */
  1.2666 +    nsCOMPtr<nsIDOMText> textNode(do_QueryInterface(n));
  1.2667 +    if (textNode) // if it's a text node, get the text
  1.2668 +    {
  1.2669 +      if (n == mStartParent) // only include text past start offset
  1.2670 +      {
  1.2671 +        uint32_t strLength;
  1.2672 +        textNode->GetLength(&strLength);
  1.2673 +        textNode->SubstringData(mStartOffset,strLength-mStartOffset,tempString);
  1.2674 +        aReturn += tempString;
  1.2675 +      }
  1.2676 +      else if (n == mEndParent)  // only include text before end offset
  1.2677 +      {
  1.2678 +        textNode->SubstringData(0,mEndOffset,tempString);
  1.2679 +        aReturn += tempString;
  1.2680 +      }
  1.2681 +      else  // grab the whole kit-n-kaboodle
  1.2682 +      {
  1.2683 +        textNode->GetData(tempString);
  1.2684 +        aReturn += tempString;
  1.2685 +      }
  1.2686 +    }
  1.2687 +
  1.2688 +    iter->Next();
  1.2689 +  }
  1.2690 +
  1.2691 +#ifdef DEBUG_range
  1.2692 +  printf("End Range dump: -----------------------\n");
  1.2693 +#endif /* DEBUG */
  1.2694 +  return NS_OK;
  1.2695 +}
  1.2696 +
  1.2697 +
  1.2698 +
  1.2699 +NS_IMETHODIMP
  1.2700 +nsRange::Detach()
  1.2701 +{
  1.2702 +  // No-op, but still set mIsDetached for telemetry (bug 702948)
  1.2703 +  mIsDetached = true;
  1.2704 +  return NS_OK;
  1.2705 +}
  1.2706 +
  1.2707 +NS_IMETHODIMP
  1.2708 +nsRange::CreateContextualFragment(const nsAString& aFragment,
  1.2709 +                                  nsIDOMDocumentFragment** aReturn)
  1.2710 +{
  1.2711 +  if (mIsPositioned) {
  1.2712 +    return nsContentUtils::CreateContextualFragment(mStartParent, aFragment,
  1.2713 +                                                    false, aReturn);
  1.2714 +  }
  1.2715 +  return NS_ERROR_FAILURE;
  1.2716 +}
  1.2717 +
  1.2718 +already_AddRefed<DocumentFragment>
  1.2719 +nsRange::CreateContextualFragment(const nsAString& aFragment, ErrorResult& aRv)
  1.2720 +{
  1.2721 +  if (!mIsPositioned) {
  1.2722 +    aRv.Throw(NS_ERROR_FAILURE);
  1.2723 +    return nullptr;
  1.2724 +  }
  1.2725 +
  1.2726 +  return nsContentUtils::CreateContextualFragment(mStartParent, aFragment,
  1.2727 +                                                  false, aRv);
  1.2728 +}
  1.2729 +
  1.2730 +static void ExtractRectFromOffset(nsIFrame* aFrame,
  1.2731 +                                  const nsIFrame* aRelativeTo, 
  1.2732 +                                  const int32_t aOffset, nsRect* aR, bool aKeepLeft)
  1.2733 +{
  1.2734 +  nsPoint point;
  1.2735 +  aFrame->GetPointFromOffset(aOffset, &point);
  1.2736 +
  1.2737 +  point += aFrame->GetOffsetTo(aRelativeTo);
  1.2738 +
  1.2739 +  //given a point.x, extract left or right portion of rect aR
  1.2740 +  //point.x has to be within this rect
  1.2741 +  NS_ASSERTION(aR->x <= point.x && point.x <= aR->XMost(),
  1.2742 +                   "point.x should not be outside of rect r");
  1.2743 +
  1.2744 +  if (aKeepLeft) {
  1.2745 +    aR->width = point.x - aR->x;
  1.2746 +  } else {
  1.2747 +    aR->width = aR->XMost() - point.x;
  1.2748 +    aR->x = point.x;
  1.2749 +  }
  1.2750 +}
  1.2751 +
  1.2752 +static nsTextFrame*
  1.2753 +GetTextFrameForContent(nsIContent* aContent)
  1.2754 +{
  1.2755 +  nsIPresShell* presShell = aContent->OwnerDoc()->GetShell();
  1.2756 +  if (presShell) {
  1.2757 +    presShell->FrameConstructor()->EnsureFrameForTextNode(
  1.2758 +        static_cast<nsGenericDOMDataNode*>(aContent));
  1.2759 +    aContent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
  1.2760 +    nsIFrame* frame = aContent->GetPrimaryFrame();
  1.2761 +    if (frame && frame->GetType() == nsGkAtoms::textFrame) {
  1.2762 +      return static_cast<nsTextFrame*>(frame);
  1.2763 +    }
  1.2764 +  }
  1.2765 +  return nullptr;
  1.2766 +}
  1.2767 +
  1.2768 +static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
  1.2769 +                                   nsIContent* aContent, int32_t aStartOffset, int32_t aEndOffset)
  1.2770 +{
  1.2771 +  nsTextFrame* textFrame = GetTextFrameForContent(aContent);
  1.2772 +  if (textFrame) {
  1.2773 +    nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
  1.2774 +    for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
  1.2775 +      int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd();
  1.2776 +      if (fend <= aStartOffset || fstart >= aEndOffset)
  1.2777 +        continue;
  1.2778 +
  1.2779 +      // overlapping with the offset we want
  1.2780 +      f->EnsureTextRun(nsTextFrame::eInflated);
  1.2781 +      NS_ENSURE_TRUE(f->GetTextRun(nsTextFrame::eInflated), NS_ERROR_OUT_OF_MEMORY);
  1.2782 +      bool rtl = f->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft();
  1.2783 +      nsRect r(f->GetOffsetTo(relativeTo), f->GetSize());
  1.2784 +      if (fstart < aStartOffset) {
  1.2785 +        // aStartOffset is within this frame
  1.2786 +        ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl);
  1.2787 +      }
  1.2788 +      if (fend > aEndOffset) {
  1.2789 +        // aEndOffset is in the middle of this frame
  1.2790 +        ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl);
  1.2791 +      }
  1.2792 +      aCallback->AddRect(r);
  1.2793 +    }
  1.2794 +  }
  1.2795 +  return NS_OK;
  1.2796 +}
  1.2797 +
  1.2798 +static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
  1.2799 +                               nsRange* aRange,
  1.2800 +                               nsINode* aStartParent, int32_t aStartOffset,
  1.2801 +                               nsINode* aEndParent, int32_t aEndOffset)
  1.2802 +{
  1.2803 +  // Hold strong pointers across the flush
  1.2804 +  nsCOMPtr<nsINode> startContainer = aStartParent;
  1.2805 +  nsCOMPtr<nsINode> endContainer = aEndParent;
  1.2806 +
  1.2807 +  // Flush out layout so our frames are up to date.
  1.2808 +  if (!aStartParent->IsInDoc()) {
  1.2809 +    return;
  1.2810 +  }
  1.2811 +
  1.2812 +  aStartParent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
  1.2813 +
  1.2814 +  // Recheck whether we're still in the document
  1.2815 +  if (!aStartParent->IsInDoc()) {
  1.2816 +    return;
  1.2817 +  }
  1.2818 +
  1.2819 +  RangeSubtreeIterator iter;
  1.2820 +
  1.2821 +  nsresult rv = iter.Init(aRange);
  1.2822 +  if (NS_FAILED(rv)) return;
  1.2823 +
  1.2824 +  if (iter.IsDone()) {
  1.2825 +    // the range is collapsed, only continue if the cursor is in a text node
  1.2826 +    nsCOMPtr<nsIContent> content = do_QueryInterface(aStartParent);
  1.2827 +    if (content && content->IsNodeOfType(nsINode::eTEXT)) {
  1.2828 +      nsTextFrame* textFrame = GetTextFrameForContent(content);
  1.2829 +      if (textFrame) {
  1.2830 +        int32_t outOffset;
  1.2831 +        nsIFrame* outFrame;
  1.2832 +        textFrame->GetChildFrameContainingOffset(aStartOffset, false, 
  1.2833 +          &outOffset, &outFrame);
  1.2834 +        if (outFrame) {
  1.2835 +           nsIFrame* relativeTo =
  1.2836 +             nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
  1.2837 +           nsRect r(outFrame->GetOffsetTo(relativeTo), outFrame->GetSize());
  1.2838 +           ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false);
  1.2839 +           r.width = 0;
  1.2840 +           aCollector->AddRect(r);
  1.2841 +        }
  1.2842 +      }
  1.2843 +    }
  1.2844 +    return;
  1.2845 +  }
  1.2846 +
  1.2847 +  do {
  1.2848 +    nsCOMPtr<nsINode> node = iter.GetCurrentNode();
  1.2849 +    iter.Next();
  1.2850 +    nsCOMPtr<nsIContent> content = do_QueryInterface(node);
  1.2851 +    if (!content)
  1.2852 +      continue;
  1.2853 +    if (content->IsNodeOfType(nsINode::eTEXT)) {
  1.2854 +       if (node == startContainer) {
  1.2855 +         int32_t offset = startContainer == endContainer ?
  1.2856 +           aEndOffset : content->GetText()->GetLength();
  1.2857 +         GetPartialTextRect(aCollector, content, aStartOffset, offset);
  1.2858 +         continue;
  1.2859 +       } else if (node == endContainer) {
  1.2860 +         GetPartialTextRect(aCollector, content, 0, aEndOffset);
  1.2861 +         continue;
  1.2862 +       }
  1.2863 +    }
  1.2864 +
  1.2865 +    nsIFrame* frame = content->GetPrimaryFrame();
  1.2866 +    if (frame) {
  1.2867 +      nsLayoutUtils::GetAllInFlowRects(frame,
  1.2868 +        nsLayoutUtils::GetContainingBlockForClientRect(frame), aCollector);
  1.2869 +    }
  1.2870 +  } while (!iter.IsDone());
  1.2871 +}
  1.2872 +
  1.2873 +NS_IMETHODIMP
  1.2874 +nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult)
  1.2875 +{
  1.2876 +  *aResult = GetBoundingClientRect().take();
  1.2877 +  return NS_OK;
  1.2878 +}
  1.2879 +
  1.2880 +already_AddRefed<DOMRect>
  1.2881 +nsRange::GetBoundingClientRect()
  1.2882 +{
  1.2883 +  nsRefPtr<DOMRect> rect = new DOMRect(ToSupports(this));
  1.2884 +  if (!mStartParent) {
  1.2885 +    return rect.forget();
  1.2886 +  }
  1.2887 +
  1.2888 +  nsLayoutUtils::RectAccumulator accumulator;
  1.2889 +  CollectClientRects(&accumulator, this, mStartParent, mStartOffset, 
  1.2890 +    mEndParent, mEndOffset);
  1.2891 +
  1.2892 +  nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect : 
  1.2893 +    accumulator.mResultRect;
  1.2894 +  rect->SetLayoutRect(r);
  1.2895 +  return rect.forget();
  1.2896 +}
  1.2897 +
  1.2898 +NS_IMETHODIMP
  1.2899 +nsRange::GetClientRects(nsIDOMClientRectList** aResult)
  1.2900 +{
  1.2901 +  *aResult = GetClientRects().take();
  1.2902 +  return NS_OK;
  1.2903 +}
  1.2904 +
  1.2905 +already_AddRefed<DOMRectList>
  1.2906 +nsRange::GetClientRects()
  1.2907 +{
  1.2908 +  if (!mStartParent) {
  1.2909 +    return nullptr;
  1.2910 +  }
  1.2911 +
  1.2912 +  nsRefPtr<DOMRectList> rectList =
  1.2913 +    new DOMRectList(static_cast<nsIDOMRange*>(this));
  1.2914 +
  1.2915 +  nsLayoutUtils::RectListBuilder builder(rectList);
  1.2916 +
  1.2917 +  CollectClientRects(&builder, this, mStartParent, mStartOffset, 
  1.2918 +    mEndParent, mEndOffset);
  1.2919 +  return rectList.forget();
  1.2920 +}
  1.2921 +
  1.2922 +NS_IMETHODIMP
  1.2923 +nsRange::GetUsedFontFaces(nsIDOMFontFaceList** aResult)
  1.2924 +{
  1.2925 +  *aResult = nullptr;
  1.2926 +
  1.2927 +  NS_ENSURE_TRUE(mStartParent, NS_ERROR_UNEXPECTED);
  1.2928 +
  1.2929 +  nsCOMPtr<nsINode> startContainer = do_QueryInterface(mStartParent);
  1.2930 +  nsCOMPtr<nsINode> endContainer = do_QueryInterface(mEndParent);
  1.2931 +
  1.2932 +  // Flush out layout so our frames are up to date.
  1.2933 +  nsIDocument* doc = mStartParent->OwnerDoc();
  1.2934 +  NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
  1.2935 +  doc->FlushPendingNotifications(Flush_Frames);
  1.2936 +
  1.2937 +  // Recheck whether we're still in the document
  1.2938 +  NS_ENSURE_TRUE(mStartParent->IsInDoc(), NS_ERROR_UNEXPECTED);
  1.2939 +
  1.2940 +  nsRefPtr<nsFontFaceList> fontFaceList = new nsFontFaceList();
  1.2941 +
  1.2942 +  RangeSubtreeIterator iter;
  1.2943 +  nsresult rv = iter.Init(this);
  1.2944 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2945 +
  1.2946 +  while (!iter.IsDone()) {
  1.2947 +    // only collect anything if the range is not collapsed
  1.2948 +    nsCOMPtr<nsINode> node = iter.GetCurrentNode();
  1.2949 +    iter.Next();
  1.2950 +
  1.2951 +    nsCOMPtr<nsIContent> content = do_QueryInterface(node);
  1.2952 +    if (!content) {
  1.2953 +      continue;
  1.2954 +    }
  1.2955 +    nsIFrame* frame = content->GetPrimaryFrame();
  1.2956 +    if (!frame) {
  1.2957 +      continue;
  1.2958 +    }
  1.2959 +
  1.2960 +    if (content->IsNodeOfType(nsINode::eTEXT)) {
  1.2961 +       if (node == startContainer) {
  1.2962 +         int32_t offset = startContainer == endContainer ?
  1.2963 +           mEndOffset : content->GetText()->GetLength();
  1.2964 +         nsLayoutUtils::GetFontFacesForText(frame, mStartOffset, offset,
  1.2965 +                                            true, fontFaceList);
  1.2966 +         continue;
  1.2967 +       }
  1.2968 +       if (node == endContainer) {
  1.2969 +         nsLayoutUtils::GetFontFacesForText(frame, 0, mEndOffset,
  1.2970 +                                            true, fontFaceList);
  1.2971 +         continue;
  1.2972 +       }
  1.2973 +    }
  1.2974 +
  1.2975 +    nsLayoutUtils::GetFontFacesForFrames(frame, fontFaceList);
  1.2976 +  }
  1.2977 +
  1.2978 +  fontFaceList.forget(aResult);
  1.2979 +  return NS_OK;
  1.2980 +}
  1.2981 +
  1.2982 +nsINode*
  1.2983 +nsRange::GetRegisteredCommonAncestor()
  1.2984 +{
  1.2985 +  NS_ASSERTION(IsInSelection(),
  1.2986 +               "GetRegisteredCommonAncestor only valid for range in selection");
  1.2987 +  nsINode* ancestor = GetNextRangeCommonAncestor(mStartParent);
  1.2988 +  while (ancestor) {
  1.2989 +    RangeHashTable* ranges =
  1.2990 +      static_cast<RangeHashTable*>(ancestor->GetProperty(nsGkAtoms::range));
  1.2991 +    if (ranges->GetEntry(this)) {
  1.2992 +      break;
  1.2993 +    }
  1.2994 +    ancestor = GetNextRangeCommonAncestor(ancestor->GetParentNode());
  1.2995 +  }
  1.2996 +  NS_ASSERTION(ancestor, "can't find common ancestor for selected range");
  1.2997 +  return ancestor;
  1.2998 +}
  1.2999 +
  1.3000 +/* static */ bool nsRange::AutoInvalidateSelection::mIsNested;
  1.3001 +
  1.3002 +nsRange::AutoInvalidateSelection::~AutoInvalidateSelection()
  1.3003 +{
  1.3004 +  NS_ASSERTION(mWasInSelection == mRange->IsInSelection(),
  1.3005 +               "Range got unselected in AutoInvalidateSelection block");
  1.3006 +  if (!mCommonAncestor) {
  1.3007 +    return;
  1.3008 +  }
  1.3009 +  mIsNested = false;
  1.3010 +  ::InvalidateAllFrames(mCommonAncestor);
  1.3011 +  nsINode* commonAncestor = mRange->GetRegisteredCommonAncestor();
  1.3012 +  if (commonAncestor != mCommonAncestor) {
  1.3013 +    ::InvalidateAllFrames(commonAncestor);
  1.3014 +  }
  1.3015 +}
  1.3016 +
  1.3017 +/* static */ already_AddRefed<nsRange>
  1.3018 +nsRange::Constructor(const GlobalObject& aGlobal,
  1.3019 +                     ErrorResult& aRv)
  1.3020 +{
  1.3021 +  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
  1.3022 +  if (!window || !window->GetDoc()) {
  1.3023 +    aRv.Throw(NS_ERROR_FAILURE);
  1.3024 +    return nullptr;
  1.3025 +  }
  1.3026 +
  1.3027 +  return window->GetDoc()->CreateRange(aRv);
  1.3028 +}

mercurial