author | Trevor Saunders <trev.saunders@gmail.com> |
Thu, 07 Feb 2013 07:09:41 -0500 | |
changeset 124495 | 5410bada8645304318a9c85cc647b673488cc094 |
parent 124494 | 66483dfa678f846fe70fdedb843a7877a17ea6ba |
child 124496 | e1538a45f97bb8dbeec9881653e5c0f56d06d296 |
push id | 24451 |
push user | trev.saunders@gmail.com |
push date | Tue, 12 Mar 2013 14:37:45 +0000 |
treeherder | mozilla-inbound@5410bada8645 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz, smaug |
bugs | 825341 |
milestone | 22.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/CLOBBER +++ b/CLOBBER @@ -10,9 +10,9 @@ # O <-- Users coming from both parents need to Clobber # / \ # O O # | | # O <-- Clobber O <-- Clobber # # Note: The description below will be part of the error message shown to users. # -Bug 847120 needs a clobber +Bug 825341 appears to need a clobber
--- a/accessible/src/generic/HyperTextAccessible.cpp +++ b/accessible/src/generic/HyperTextAccessible.cpp @@ -1821,17 +1821,17 @@ HyperTextAccessible::SetSelectionBounds( NS_ENSURE_STATE(domSel); uint32_t rangeCount = domSel->GetRangeCount(); if (rangeCount < static_cast<uint32_t>(aSelectionNum)) return NS_ERROR_INVALID_ARG; nsRefPtr<nsRange> range; if (aSelectionNum == rangeCount) - range = new nsRange(); + range = new nsRange(mContent); else range = domSel->GetRangeAt(aSelectionNum); nsresult rv = HypertextOffsetsToDOMRange(startOffset, endOffset, range); NS_ENSURE_SUCCESS(rv, rv); // If new range was created then add it, otherwise notify selection listeners // that existing selection range was changed. @@ -1883,17 +1883,17 @@ HyperTextAccessible::RemoveSelection(int // in unsigned long scrollType); NS_IMETHODIMP HyperTextAccessible::ScrollSubstringTo(int32_t aStartIndex, int32_t aEndIndex, uint32_t aScrollType) { if (IsDefunct()) return NS_ERROR_FAILURE; - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mContent); nsresult rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex, range); NS_ENSURE_SUCCESS(rv, rv); return nsCoreUtils::ScrollSubstringTo(GetFrame(), range, aScrollType); } // void nsIAccessibleText:: // scrollSubstringToPoint(in long startIndex, in long endIndex, @@ -1907,17 +1907,17 @@ HyperTextAccessible::ScrollSubstringToPo { nsIFrame *frame = GetFrame(); if (!frame) return NS_ERROR_FAILURE; nsIntPoint coords = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType, this); - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mContent); nsresult rv = HypertextOffsetsToDOMRange(aStartIndex, aEndIndex, range); NS_ENSURE_SUCCESS(rv, rv); nsPresContext* presContext = frame->PresContext(); nsPoint coordsInAppUnits = coords.ToAppUnits(presContext->AppUnitsPerDevPixel()); bool initialScrolled = false;
--- a/accessible/src/windows/msaa/TextLeafAccessibleWrap.cpp +++ b/accessible/src/windows/msaa/TextLeafAccessibleWrap.cpp @@ -153,17 +153,17 @@ TextLeafAccessibleWrap::scrollToSubstrin /* [in] */ unsigned int aStartIndex, /* [in] */ unsigned int aEndIndex) { A11Y_TRYBLOCK_BEGIN if (IsDefunct()) return E_FAIL; - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mContent); if (NS_FAILED(range->SetStart(mContent, aStartIndex))) return E_FAIL; if (NS_FAILED(range->SetEnd(mContent, aEndIndex))) return E_FAIL; nsresult rv = nsCoreUtils::ScrollSubstringTo(GetFrame(), range,
--- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -107,16 +107,17 @@ namespace mozilla { class Selection; namespace layers { class LayerManager; } // namespace layers namespace dom { +class DocumentFragment; class Element; } // namespace dom } // namespace mozilla extern const char kLoadAsData[]; enum EventNameType { @@ -361,16 +362,17 @@ public: */ static nsresult CheckSameOrigin(const nsINode* aTrustedNode, nsIDOMNode* aUnTrustedNode); static nsresult CheckSameOrigin(const nsINode* aTrustedNode, const nsINode* unTrustedNode); // Check if the (JS) caller can access aNode. static bool CanCallerAccess(nsIDOMNode *aNode); + static bool CanCallerAccess(nsINode* aNode); // Check if the (JS) caller can access aWindow. // aWindow can be either outer or inner window. static bool CanCallerAccess(nsPIDOMWindow* aWindow); /** * Get the window through the JS context that's currently on the stack. * If there's no JS context currently on the stack, returns null. @@ -1079,16 +1081,20 @@ public: * @param aFragment the string which is parsed to a DocumentFragment * @param aReturn the resulting fragment * @param aPreventScriptExecution whether to mark scripts as already started */ static nsresult CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment, bool aPreventScriptExecution, nsIDOMDocumentFragment** aReturn); + static already_AddRefed<mozilla::dom::DocumentFragment> + CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment, + bool aPreventScriptExecution, + mozilla::ErrorResult& aRv); /** * Invoke the fragment parsing algorithm (innerHTML) using the HTML parser. * * @param aSourceBuffer the string being set as innerHTML * @param aTargetNode the target container * @param aContextLocalName local name of context node * @param aContextNamespace namespace of context node
--- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -2467,16 +2467,20 @@ NS_NewSVGDocument(nsIDocument** aInstanc nsresult NS_NewImageDocument(nsIDocument** aInstancePtrResult); #ifdef MOZ_MEDIA nsresult NS_NewVideoDocument(nsIDocument** aInstancePtrResult); #endif +already_AddRefed<mozilla::dom::DocumentFragment> +NS_NewDocumentFragment(nsNodeInfoManager* aNodeInfoManager, + mozilla::ErrorResult& aRv); + nsresult NS_NewDocumentFragment(nsIDOMDocumentFragment** aInstancePtrResult, nsNodeInfoManager *aNodeInfoManager); // Note: it's the caller's responsibility to create or get aPrincipal as needed // -- this method will not attempt to get a principal based on aDocumentURI. // Also, both aDocumentURI and aBaseURI must not be null. nsresult
--- a/content/base/src/DocumentFragment.cpp +++ b/content/base/src/DocumentFragment.cpp @@ -17,30 +17,43 @@ #include "nsDOMString.h" #include "nsContentUtils.h" #include "mozilla/dom/DocumentFragmentBinding.h" nsresult NS_NewDocumentFragment(nsIDOMDocumentFragment** aInstancePtrResult, nsNodeInfoManager *aNodeInfoManager) { + mozilla::ErrorResult rv; + *aInstancePtrResult = NS_NewDocumentFragment(aNodeInfoManager, rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed<mozilla::dom::DocumentFragment> +NS_NewDocumentFragment(nsNodeInfoManager* aNodeInfoManager, + mozilla::ErrorResult& aRv) +{ using namespace mozilla::dom; - NS_ENSURE_ARG(aNodeInfoManager); + if (!aNodeInfoManager) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return nullptr; + } - nsCOMPtr<nsINodeInfo> nodeInfo; - nodeInfo = aNodeInfoManager->GetNodeInfo(nsGkAtoms::documentFragmentNodeName, - nullptr, kNameSpaceID_None, - nsIDOMNode::DOCUMENT_FRAGMENT_NODE); - NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY); + nsCOMPtr<nsINodeInfo> nodeInfo = + aNodeInfoManager->GetNodeInfo(nsGkAtoms::documentFragmentNodeName, + nullptr, kNameSpaceID_None, + nsIDOMNode::DOCUMENT_FRAGMENT_NODE); + if (!nodeInfo) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } - DocumentFragment *it = new DocumentFragment(nodeInfo.forget()); - NS_ADDREF(*aInstancePtrResult = it); - - return NS_OK; + nsRefPtr<DocumentFragment> it = new DocumentFragment(nodeInfo.forget()); + return it.forget(); } namespace mozilla { namespace dom { DocumentFragment::DocumentFragment(already_AddRefed<nsINodeInfo> aNodeInfo) : FragmentOrElement(aNodeInfo) {
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -163,16 +163,17 @@ #include "nsIEditor.h" #include "mozilla/Attributes.h" #include "nsIParserService.h" #include "nsIDOMScriptObjectFactory.h" #include "nsSandboxFlags.h" #include "nsSVGFeatures.h" #include "MediaDecoder.h" #include "DecoderTraits.h" +#include "mozilla/dom/DocumentFragment.h" #include "nsWrapperCacheInlines.h" #include "nsViewportInfo.h" extern "C" int MOZ_XMLTranslateEntity(const char* ptr, const char* end, const char** next, PRUnichar* result); extern "C" int MOZ_XMLCheckQName(const char* ptr, const char* end, int ns_aware, const char** colon); @@ -1584,33 +1585,39 @@ nsContentUtils::CanCallerAccess(nsIPrinc // is chrome. return IsCallerChrome(); } // static bool nsContentUtils::CanCallerAccess(nsIDOMNode *aNode) { + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); + NS_ENSURE_TRUE(node, false); + return CanCallerAccess(node); +} + +// static +bool +nsContentUtils::CanCallerAccess(nsINode* aNode) +{ // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother // with the system principal games? But really, there should be a simpler // API here, dammit. nsCOMPtr<nsIPrincipal> subjectPrincipal; nsresult rv = sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); NS_ENSURE_SUCCESS(rv, false); if (!subjectPrincipal) { // we're running as system, grant access to the node. return true; } - nsCOMPtr<nsINode> node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(node, false); - - return CanCallerAccess(subjectPrincipal, node->NodePrincipal()); + return CanCallerAccess(subjectPrincipal, aNode->NodePrincipal()); } // static bool nsContentUtils::CanCallerAccess(nsPIDOMWindow* aWindow) { // XXXbz why not check the IsCapabilityEnabled thing up front, and not bother // with the system principal games? But really, there should be a simpler @@ -4040,75 +4047,87 @@ nsContentUtils::IsValidNodeName(nsIAtom /* static */ nsresult nsContentUtils::CreateContextualFragment(nsINode* aContextNode, const nsAString& aFragment, bool aPreventScriptExecution, nsIDOMDocumentFragment** aReturn) { - *aReturn = nullptr; - NS_ENSURE_ARG(aContextNode); + ErrorResult rv; + *aReturn = CreateContextualFragment(aContextNode, aFragment, + aPreventScriptExecution, rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed<DocumentFragment> +nsContentUtils::CreateContextualFragment(nsINode* aContextNode, + const nsAString& aFragment, + bool aPreventScriptExecution, + ErrorResult& aRv) +{ + if (!aContextNode) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return nullptr; + } // If we don't have a document here, we can't get the right security context // for compiling event handlers... so just bail out. nsCOMPtr<nsIDocument> document = aContextNode->OwnerDoc(); bool isHTML = document->IsHTML(); #ifdef DEBUG nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document); NS_ASSERTION(!isHTML || htmlDoc, "Should have HTMLDocument here!"); #endif if (isHTML) { - nsCOMPtr<nsIDOMDocumentFragment> frag; - NS_NewDocumentFragment(getter_AddRefs(frag), document->NodeInfoManager()); + nsRefPtr<DocumentFragment> frag = + NS_NewDocumentFragment(document->NodeInfoManager(), aRv); nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode); if (contextAsContent && !contextAsContent->IsElement()) { contextAsContent = contextAsContent->GetParent(); if (contextAsContent && !contextAsContent->IsElement()) { // can this even happen? contextAsContent = nullptr; } } - nsresult rv; - nsCOMPtr<nsIContent> fragment = do_QueryInterface(frag); if (contextAsContent && !contextAsContent->IsHTML(nsGkAtoms::html)) { - rv = ParseFragmentHTML(aFragment, - fragment, - contextAsContent->Tag(), - contextAsContent->GetNameSpaceID(), - (document->GetCompatibilityMode() == + aRv = ParseFragmentHTML(aFragment, frag, + contextAsContent->Tag(), + contextAsContent->GetNameSpaceID(), + (document->GetCompatibilityMode() == eCompatibility_NavQuirks), - aPreventScriptExecution); + aPreventScriptExecution); } else { - rv = ParseFragmentHTML(aFragment, - fragment, - nsGkAtoms::body, - kNameSpaceID_XHTML, - (document->GetCompatibilityMode() == + aRv = ParseFragmentHTML(aFragment, frag, + nsGkAtoms::body, + kNameSpaceID_XHTML, + (document->GetCompatibilityMode() == eCompatibility_NavQuirks), - aPreventScriptExecution); + aPreventScriptExecution); } - frag.forget(aReturn); - return rv; + return frag.forget(); } nsAutoTArray<nsString, 32> tagStack; nsAutoString uriStr, nameStr; nsCOMPtr<nsIContent> content = do_QueryInterface(aContextNode); // just in case we have a text node if (content && !content->IsElement()) content = content->GetParent(); while (content && content->IsElement()) { nsString& tagName = *tagStack.AppendElement(); - NS_ENSURE_TRUE(&tagName, NS_ERROR_OUT_OF_MEMORY); + if (!&tagName) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } tagName = content->NodeInfo()->QualifiedName(); // see if we need to add xmlns declarations uint32_t count = content->GetAttrCount(); bool setDefaultNamespace = false; if (count > 0) { uint32_t index; @@ -4144,21 +4163,20 @@ nsContentUtils::CreateContextualFragment tagName.Append(NS_LITERAL_STRING(" xmlns=\"") + uriStr + NS_LITERAL_STRING("\"")); } } content = content->GetParent(); } - return ParseFragmentXML(aFragment, - document, - tagStack, - aPreventScriptExecution, - aReturn); + nsCOMPtr<nsIDOMDocumentFragment> frag; + aRv = ParseFragmentXML(aFragment, document, tagStack, + aPreventScriptExecution, getter_AddRefs(frag)); + return static_cast<DocumentFragment*>(frag.forget().get()); } /* static */ void nsContentUtils::DropFragmentParsers() { NS_IF_RELEASE(sHTMLFragmentParser); NS_IF_RELEASE(sXMLFragmentParser);
--- a/content/base/src/nsCopySupport.cpp +++ b/content/base/src/nsCopySupport.cpp @@ -289,17 +289,17 @@ nsCopySupport::GetTransferableForNode(ns nsITransferable** aTransferable) { nsCOMPtr<nsISelection> selection; // Make a temporary selection with aNode in a single range. nsresult rv = NS_NewDomSelection(getter_AddRefs(selection)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aNode); rv = range->SelectNode(node); NS_ENSURE_SUCCESS(rv, rv); rv = selection->AddRange(range); NS_ENSURE_SUCCESS(rv, rv); // It's not the primary selection - so don't skip invisible content. uint32_t flags = 0; return SelectionCopyHelper(selection, aDoc, false, 0, flags, aTransferable);
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -5568,17 +5568,17 @@ nsDocument::CreateRange(nsIDOMRange** aR ErrorResult rv; *aReturn = nsIDocument::CreateRange(rv).get(); return rv.ErrorCode(); } already_AddRefed<nsRange> nsIDocument::CreateRange(ErrorResult& rv) { - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(this); nsresult res = range->Set(this, 0, this, 0); if (NS_FAILED(res)) { rv.Throw(res); return nullptr; } return range.forget(); }
--- a/content/base/src/nsRange.cpp +++ b/content/base/src/nsRange.cpp @@ -24,37 +24,33 @@ #include "nsIDOMNodeList.h" #include "nsGkAtoms.h" #include "nsContentUtils.h" #include "nsGenericDOMDataNode.h" #include "nsClientRect.h" #include "nsLayoutUtils.h" #include "nsTextFrame.h" #include "nsFontFaceList.h" +#include "mozilla/dom/DocumentFragment.h" +#include "mozilla/dom/RangeBinding.h" #include "mozilla/Telemetry.h" #include "mozilla/Likely.h" using namespace mozilla; +JSObject* +nsRange::WrapObject(JSContext* aCx, JSObject* aScope) +{ + return dom::RangeBinding::Wrap(aCx, aScope, this); +} + /****************************************************** * stack based utilty class for managing monitor ******************************************************/ -// NS_ERROR_DOM_NOT_OBJECT_ERR is not the correct one to throw, but spec doesn't say -// what is -#define VALIDATE_ACCESS(node_) \ - PR_BEGIN_MACRO \ - if (!node_) { \ - return NS_ERROR_DOM_NOT_OBJECT_ERR; \ - } \ - if (!nsContentUtils::CanCallerAccess(node_)) { \ - return NS_ERROR_DOM_SECURITY_ERR; \ - } \ - PR_END_MACRO - static void InvalidateAllFrames(nsINode* aNode) { NS_PRECONDITION(aNode, "bad arg"); nsIFrame* frame = nullptr; switch (aNode->NodeType()) { case nsIDOMNode::TEXT_NODE: case nsIDOMNode::ELEMENT_NODE: @@ -219,19 +215,22 @@ nsRange::~nsRange() nsresult nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset, nsIDOMNode* aEndParent, int32_t aEndOffset, nsRange** aRange) { MOZ_ASSERT(aRange); *aRange = NULL; - nsRefPtr<nsRange> range = new nsRange(); - - nsresult rv = range->SetStart(aStartParent, aStartOffset); + nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent); + NS_ENSURE_ARG_POINTER(startParent); + + nsRefPtr<nsRange> range = new nsRange(startParent); + + nsresult rv = range->SetStart(startParent, aStartOffset); NS_ENSURE_SUCCESS(rv, rv); rv = range->SetEnd(aEndParent, aEndOffset); NS_ENSURE_SUCCESS(rv, rv); range.forget(aRange); return NS_OK; } @@ -255,32 +254,42 @@ nsRange::CreateRange(nsIDOMNode* aStartP NS_IMPL_CYCLE_COLLECTING_ADDREF(nsRange) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsRange) DOMCI_DATA(Range, nsRange) // QueryInterface implementation for nsRange NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsRange) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsIDOMRange) NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMRange) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Range) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsRange) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner); tmp->Reset(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStartParent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndParent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsRange) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END + + static void RangeHashTableDtor(void* aObject, nsIAtom* aPropertyName, void* aPropertyValue, void* aData) { nsRange::RangeHashTable* ranges = static_cast<nsRange::RangeHashTable*>(aPropertyValue); delete ranges; } @@ -682,108 +691,138 @@ nsRange::ParentChainChanged(nsIContent * } /****************************************************** * Utilities for comparing points: API from nsIDOMRange ******************************************************/ NS_IMETHODIMP nsRange::IsPointInRange(nsIDOMNode* aParent, int32_t aOffset, bool* aResult) { - int16_t compareResult = 0; - nsresult rv = ComparePoint(aParent, aOffset, &compareResult); - // If the node isn't in the range's document, it clearly isn't in the range. - if (rv == NS_ERROR_DOM_WRONG_DOCUMENT_ERR) { - *aResult = false; - return NS_OK; + nsCOMPtr<nsINode> parent = do_QueryInterface(aParent); + if (!parent) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; } - *aResult = compareResult == 0; - - return rv; + ErrorResult rv; + *aResult = IsPointInRange(*parent, aOffset, rv); + return rv.ErrorCode(); } - + +bool +nsRange::IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv) +{ + uint16_t compareResult = ComparePoint(aParent, aOffset, aRv); + // If the node isn't in the range's document, it clearly isn't in the range. + if (aRv.ErrorCode() == NS_ERROR_DOM_WRONG_DOCUMENT_ERR) { + aRv = NS_OK; + return false; + } + + return compareResult == 0; +} + // returns -1 if point is before range, 0 if point is in range, // 1 if point is after range. NS_IMETHODIMP nsRange::ComparePoint(nsIDOMNode* aParent, int32_t aOffset, int16_t* aResult) { - // our range is in a good state? - if (!mIsPositioned) - return NS_ERROR_NOT_INITIALIZED; - nsCOMPtr<nsINode> parent = do_QueryInterface(aParent); NS_ENSURE_TRUE(parent, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); - if (!nsContentUtils::ContentIsDescendantOf(parent, mRoot)) { - return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; + ErrorResult rv; + *aResult = ComparePoint(*parent, aOffset, rv); + return rv.ErrorCode(); +} + +int16_t +nsRange::ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv) +{ + // our range is in a good state? + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return 0; } - - if (parent->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + + if (!nsContentUtils::ContentIsDescendantOf(&aParent, mRoot)) { + aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); + return 0; } - if (aOffset < 0 || uint32_t(aOffset) > parent->Length()) { - return NS_ERROR_DOM_INDEX_SIZE_ERR; + if (aParent.NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { + aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); + return 0; } - + + if (aOffset > aParent.Length()) { + aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + return 0; + } + int32_t cmp; - if ((cmp = nsContentUtils::ComparePoints(parent, aOffset, + if ((cmp = nsContentUtils::ComparePoints(&aParent, aOffset, mStartParent, mStartOffset)) <= 0) { - - *aResult = cmp; + + return cmp; } - else if (nsContentUtils::ComparePoints(mEndParent, mEndOffset, - parent, aOffset) == -1) { - *aResult = 1; + if (nsContentUtils::ComparePoints(mEndParent, mEndOffset, + &aParent, aOffset) == -1) { + return 1; } - else { - *aResult = 0; - } - - return NS_OK; + + return 0; } NS_IMETHODIMP nsRange::IntersectsNode(nsIDOMNode* aNode, bool* aResult) { *aResult = false; nsCOMPtr<nsINode> node = do_QueryInterface(aNode); // TODO: This should throw a TypeError. NS_ENSURE_ARG(node); - NS_ENSURE_TRUE(mIsPositioned, NS_ERROR_NOT_INITIALIZED); + ErrorResult rv; + *aResult = IntersectsNode(*node, rv); + return rv.ErrorCode(); +} + +bool +nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv) +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return false; + } // Step 3. - nsINode* parent = node->GetParentNode(); + nsINode* parent = aNode.GetParentNode(); if (!parent) { // Steps 2 and 4. // |parent| is null, so |node|'s root is |node| itself. - *aResult = (GetRoot() == node); - return NS_OK; + return GetRoot() == &aNode; } // Step 5. - int32_t nodeIndex = parent->IndexOf(node); + int32_t nodeIndex = parent->IndexOf(&aNode); // Steps 6-7. // Note: if disconnected is true, ComparePoints returns 1. bool disconnected = false; - *aResult = nsContentUtils::ComparePoints(mStartParent, mStartOffset, - parent, nodeIndex + 1, - &disconnected) < 0 && - nsContentUtils::ComparePoints(parent, nodeIndex, - mEndParent, mEndOffset, - &disconnected) < 0; + bool result = nsContentUtils::ComparePoints(mStartParent, mStartOffset, + parent, nodeIndex + 1, + &disconnected) < 0 && + nsContentUtils::ComparePoints(parent, nodeIndex, + mEndParent, mEndOffset, + &disconnected) < 0; // Step 2. if (disconnected) { - *aResult = false; + result = false; } - return NS_OK; + return result; } /****************************************************** * Private helper routines ******************************************************/ // It's important that all setting of the range start/end points // go through this function, which will do all the right voodoo @@ -851,29 +890,33 @@ nsRange::DoSetRange(nsINode* aStartN, in } // This needs to be the last thing this function does. See comment // in ParentChainChanged. mRoot = aRoot; } static int32_t +IndexOf(nsINode* aChild) +{ + nsINode* parent = aChild->GetParentNode(); + + return parent ? parent->IndexOf(aChild) : -1; +} + +static int32_t IndexOf(nsIDOMNode* aChildNode) { // convert node to nsIContent, so that we can find the child index nsCOMPtr<nsINode> child = do_QueryInterface(aChildNode); if (!child) { return -1; } - - nsINode *parent = child->GetParentNode(); - - // finally we get the index - return parent ? parent->IndexOf(child) : -1; + return IndexOf(child); } nsINode* nsRange::GetCommonAncestor() const { return mIsPositioned ? nsContentUtils::GetCommonAncestor(mStartParent, mEndParent) : nullptr; @@ -893,71 +936,125 @@ NS_IMETHODIMP nsRange::GetStartContainer(nsIDOMNode** aStartParent) { if (!mIsPositioned) return NS_ERROR_NOT_INITIALIZED; return CallQueryInterface(mStartParent, aStartParent); } +nsINode* +nsRange::GetStartContainer(ErrorResult& aRv) const +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return nullptr; + } + + return mStartParent; +} + NS_IMETHODIMP nsRange::GetStartOffset(int32_t* aStartOffset) { if (!mIsPositioned) return NS_ERROR_NOT_INITIALIZED; *aStartOffset = mStartOffset; return NS_OK; } +uint32_t +nsRange::GetStartOffset(ErrorResult& aRv) const +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return 0; + } + + return mStartOffset; +} + NS_IMETHODIMP nsRange::GetEndContainer(nsIDOMNode** aEndParent) { if (!mIsPositioned) return NS_ERROR_NOT_INITIALIZED; return CallQueryInterface(mEndParent, aEndParent); } +nsINode* +nsRange::GetEndContainer(ErrorResult& aRv) const +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return nullptr; + } + + return mEndParent; +} + NS_IMETHODIMP nsRange::GetEndOffset(int32_t* aEndOffset) { if (!mIsPositioned) return NS_ERROR_NOT_INITIALIZED; *aEndOffset = mEndOffset; return NS_OK; } +uint32_t +nsRange::GetEndOffset(ErrorResult& aRv) const +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return 0; + } + + return mEndOffset; +} + NS_IMETHODIMP nsRange::GetCollapsed(bool* aIsCollapsed) { if (!mIsPositioned) return NS_ERROR_NOT_INITIALIZED; *aIsCollapsed = Collapsed(); return NS_OK; } +nsINode* +nsRange::GetCommonAncestorContainer(ErrorResult& aRv) const +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_NOT_INITIALIZED); + return nullptr; + } + + return nsContentUtils::GetCommonAncestor(mStartParent, mEndParent); +} + NS_IMETHODIMP nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent) { - *aCommonParent = nullptr; - if (!mIsPositioned) - return NS_ERROR_NOT_INITIALIZED; - - nsINode* container = nsContentUtils::GetCommonAncestor(mStartParent, mEndParent); - if (container) { - return CallQueryInterface(container, aCommonParent); + ErrorResult rv; + nsINode* commonAncestor = GetCommonAncestorContainer(rv); + if (commonAncestor) { + NS_ADDREF(*aCommonParent = commonAncestor->AsDOMNode()); + } else { + *aCommonParent = nullptr; } - return NS_ERROR_NOT_INITIALIZED; + return rv.ErrorCode(); } nsINode* nsRange::IsValidBoundary(nsINode* aNode) { if (!aNode) { return nullptr; } @@ -998,24 +1095,39 @@ nsRange::IsValidBoundary(nsINode* aNode) root->IsNodeOfType(nsINode::eATTRIBUTE), "Creating a DOM Range using root which isn't in DOM!"); #endif // We allow this because of backward compatibility. return root; } +void +nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + AutoInvalidateSelection atEndOfBlock(this); + aRv = SetStart(&aNode, aOffset); +} + NS_IMETHODIMP nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset) { - VALIDATE_ACCESS(aParent); - nsCOMPtr<nsINode> parent = do_QueryInterface(aParent); - AutoInvalidateSelection atEndOfBlock(this); - return SetStart(parent, aOffset); + if (!parent) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; + } + + ErrorResult rv; + SetStart(*parent, aOffset, rv); + return rv.ErrorCode(); } /* virtual */ nsresult nsRange::SetStart(nsINode* aParent, int32_t aOffset) { nsINode* newRoot = IsValidBoundary(aParent); NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); @@ -1033,55 +1145,90 @@ nsRange::SetStart(nsINode* aParent, int3 return NS_OK; } DoSetRange(aParent, aOffset, mEndParent, mEndOffset, mRoot); return NS_OK; } +void +nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + AutoInvalidateSelection atEndOfBlock(this); + aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode)); +} + NS_IMETHODIMP nsRange::SetStartBefore(nsIDOMNode* aSibling) { - VALIDATE_ACCESS(aSibling); - - nsCOMPtr<nsIDOMNode> parent; - nsresult rv = aSibling->GetParentNode(getter_AddRefs(parent)); - if (NS_FAILED(rv) || !parent) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling); + if (!sibling) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; } - return SetStart(parent, IndexOf(aSibling)); + ErrorResult rv; + SetStartBefore(*sibling, rv); + return rv.ErrorCode(); +} + +void +nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + AutoInvalidateSelection atEndOfBlock(this); + aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1); } NS_IMETHODIMP nsRange::SetStartAfter(nsIDOMNode* aSibling) { - VALIDATE_ACCESS(aSibling); - - nsCOMPtr<nsIDOMNode> nParent; - nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent)); - if (NS_FAILED(res) || !nParent) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling); + if (!sibling) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; } - return SetStart(nParent, IndexOf(aSibling) + 1); + ErrorResult rv; + SetStartAfter(*sibling, rv); + return rv.ErrorCode(); +} + +void +nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + AutoInvalidateSelection atEndOfBlock(this); + aRv = SetEnd(&aNode, aOffset); } NS_IMETHODIMP nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset) { - VALIDATE_ACCESS(aParent); - - AutoInvalidateSelection atEndOfBlock(this); nsCOMPtr<nsINode> parent = do_QueryInterface(aParent); - return SetEnd(parent, aOffset); + if (!parent) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; + } + + ErrorResult rv; + SetEnd(*parent, aOffset, rv); + return rv.ErrorCode(); } - /* virtual */ nsresult nsRange::SetEnd(nsINode* aParent, int32_t aOffset) { nsINode* newRoot = IsValidBoundary(aParent); NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) { return NS_ERROR_DOM_INDEX_SIZE_ERR; @@ -1097,42 +1244,64 @@ nsRange::SetEnd(nsINode* aParent, int32_ return NS_OK; } DoSetRange(mStartParent, mStartOffset, aParent, aOffset, mRoot); return NS_OK; } +void +nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + AutoInvalidateSelection atEndOfBlock(this); + aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode)); +} + NS_IMETHODIMP nsRange::SetEndBefore(nsIDOMNode* aSibling) { - VALIDATE_ACCESS(aSibling); - - nsCOMPtr<nsIDOMNode> nParent; - nsresult rv = aSibling->GetParentNode(getter_AddRefs(nParent)); - if (NS_FAILED(rv) || !nParent) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling); + if (!sibling) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; } - return SetEnd(nParent, IndexOf(aSibling)); + ErrorResult rv; + SetEndBefore(*sibling, rv); + return rv.ErrorCode(); +} + +void +nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + AutoInvalidateSelection atEndOfBlock(this); + aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1); } NS_IMETHODIMP nsRange::SetEndAfter(nsIDOMNode* aSibling) { - VALIDATE_ACCESS(aSibling); - - nsCOMPtr<nsIDOMNode> nParent; - nsresult res = aSibling->GetParentNode(getter_AddRefs(nParent)); - if (NS_FAILED(res) || !nParent) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + nsCOMPtr<nsINode> sibling = do_QueryInterface(aSibling); + if (!sibling) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; } - return SetEnd(nParent, IndexOf(aSibling) + 1); + ErrorResult rv; + SetEndAfter(*sibling, rv); + return rv.ErrorCode(); } NS_IMETHODIMP nsRange::Collapse(bool aToStart) { if (!mIsPositioned) return NS_ERROR_NOT_INITIALIZED; @@ -1143,49 +1312,76 @@ nsRange::Collapse(bool aToStart) DoSetRange(mEndParent, mEndOffset, mEndParent, mEndOffset, mRoot); return NS_OK; } NS_IMETHODIMP nsRange::SelectNode(nsIDOMNode* aN) { - VALIDATE_ACCESS(aN); - nsCOMPtr<nsINode> node = do_QueryInterface(aN); NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); - nsINode* parent = node->GetParentNode(); + ErrorResult rv; + SelectNode(*node, rv); + return rv.ErrorCode(); +} + +void +nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + nsINode* parent = aNode.GetParentNode(); nsINode* newRoot = IsValidBoundary(parent); - NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); - - int32_t index = parent->IndexOf(node); + if (!newRoot) { + aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); + return; + } + + int32_t index = parent->IndexOf(&aNode); if (index < 0) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); + return; } AutoInvalidateSelection atEndOfBlock(this); DoSetRange(parent, index, parent, index + 1, newRoot); - - return NS_OK; } NS_IMETHODIMP nsRange::SelectNodeContents(nsIDOMNode* aN) { - VALIDATE_ACCESS(aN); - nsCOMPtr<nsINode> node = do_QueryInterface(aN); - nsINode* newRoot = IsValidBoundary(node); - NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); - + NS_ENSURE_TRUE(node, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); + + ErrorResult rv; + SelectNodeContents(*node, rv); + return rv.ErrorCode(); +} + +void +nsRange::SelectNodeContents(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + nsINode* newRoot = IsValidBoundary(&aNode); + if (!newRoot) { + aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); + return; + } + AutoInvalidateSelection atEndOfBlock(this); - DoSetRange(node, 0, node, node->Length(), newRoot); - - return NS_OK; + DoSetRange(&aNode, 0, &aNode, aNode.Length(), newRoot); } // The Subtree Content Iterator only returns subtrees that are // completely within a given range. It doesn't return a CharacterData // node that contains either the start or end point of the range., // nor does it return element nodes when nothing in the element is selected. // We need an iterator that will also include these start/end points // so that our methods/algorithms aren't cluttered with special @@ -1579,38 +1775,37 @@ ValidateCurrentNode(nsRange* aRange, Ran nsCOMPtr<nsINode> node = do_QueryInterface(domNode); MOZ_ASSERT(node); nsresult res = nsRange::CompareNodeToRange(node, aRange, &before, &after); return NS_SUCCEEDED(res) && !before && !after; } -nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment) +nsresult +nsRange::CutContents(dom::DocumentFragment** aFragment) { if (aFragment) { *aFragment = nullptr; } - nsresult rv; - nsCOMPtr<nsIDocument> doc = mStartParent->OwnerDoc(); nsCOMPtr<nsIDOMNode> commonAncestor; - rv = GetCommonAncestorContainer(getter_AddRefs(commonAncestor)); + nsresult rv = GetCommonAncestorContainer(getter_AddRefs(commonAncestor)); NS_ENSURE_SUCCESS(rv, rv); // If aFragment isn't null, create a temporary fragment to hold our return. - nsCOMPtr<nsIDOMDocumentFragment> retval; + nsRefPtr<dom::DocumentFragment> retval; if (aFragment) { - rv = NS_NewDocumentFragment(getter_AddRefs(retval), - doc->NodeInfoManager()); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult error; + retval = NS_NewDocumentFragment(doc->NodeInfoManager(), error); + NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); } - nsCOMPtr<nsIDOMNode> commonCloneAncestor(do_QueryInterface(retval)); + nsCOMPtr<nsIDOMNode> commonCloneAncestor = retval.get(); // Batch possible DOMSubtreeModified events. mozAutoSubtreeModified subtree(mRoot ? mRoot->OwnerDoc(): nullptr, nullptr); // Save the range end points locally to avoid interference // of Range gravity during our edits! nsCOMPtr<nsIDOMNode> startContainer = do_QueryInterface(mStartParent); @@ -1870,73 +2065,102 @@ nsresult nsRange::CutContents(nsIDOMDocu } NS_IMETHODIMP nsRange::DeleteContents() { return CutContents(nullptr); } +void +nsRange::DeleteContents(ErrorResult& aRv) +{ + aRv = CutContents(nullptr); +} + NS_IMETHODIMP nsRange::ExtractContents(nsIDOMDocumentFragment** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); - return CutContents(aReturn); + nsRefPtr<dom::DocumentFragment> fragment; + nsresult rv = CutContents(getter_AddRefs(fragment)); + fragment.forget(aReturn); + return rv; +} + +already_AddRefed<dom::DocumentFragment> +nsRange::ExtractContents(ErrorResult& rv) +{ + nsRefPtr<dom::DocumentFragment> fragment; + rv = CutContents(getter_AddRefs(fragment)); + return fragment.forget(); } NS_IMETHODIMP nsRange::CompareBoundaryPoints(uint16_t aHow, nsIDOMRange* aOtherRange, int16_t* aCmpRet) { nsRange* otherRange = static_cast<nsRange*>(aOtherRange); NS_ENSURE_TRUE(otherRange, NS_ERROR_NULL_POINTER); - if (!mIsPositioned || !otherRange->IsPositioned()) - return NS_ERROR_NOT_INITIALIZED; + ErrorResult rv; + *aCmpRet = CompareBoundaryPoints(aHow, *otherRange, rv); + return rv.ErrorCode(); +} + +int16_t +nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange, + ErrorResult& rv) +{ + if (!mIsPositioned || !aOtherRange.IsPositioned()) { + rv.Throw(NS_ERROR_NOT_INITIALIZED); + return 0; + } nsINode *ourNode, *otherNode; int32_t ourOffset, otherOffset; switch (aHow) { case nsIDOMRange::START_TO_START: ourNode = mStartParent; ourOffset = mStartOffset; - otherNode = otherRange->GetStartParent(); - otherOffset = otherRange->StartOffset(); + otherNode = aOtherRange.GetStartParent(); + otherOffset = aOtherRange.StartOffset(); break; case nsIDOMRange::START_TO_END: ourNode = mEndParent; ourOffset = mEndOffset; - otherNode = otherRange->GetStartParent(); - otherOffset = otherRange->StartOffset(); + otherNode = aOtherRange.GetStartParent(); + otherOffset = aOtherRange.StartOffset(); break; case nsIDOMRange::END_TO_START: ourNode = mStartParent; ourOffset = mStartOffset; - otherNode = otherRange->GetEndParent(); - otherOffset = otherRange->EndOffset(); + otherNode = aOtherRange.GetEndParent(); + otherOffset = aOtherRange.EndOffset(); break; case nsIDOMRange::END_TO_END: ourNode = mEndParent; ourOffset = mEndOffset; - otherNode = otherRange->GetEndParent(); - otherOffset = otherRange->EndOffset(); + otherNode = aOtherRange.GetEndParent(); + otherOffset = aOtherRange.EndOffset(); break; default: // We were passed an illegal value - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return 0; } - if (mRoot != otherRange->GetRoot()) - return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; - - *aCmpRet = nsContentUtils::ComparePoints(ourNode, ourOffset, - otherNode, otherOffset); - - return NS_OK; + if (mRoot != aOtherRange.GetRoot()) { + rv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); + return 0; + } + + return nsContentUtils::ComparePoints(ourNode, ourOffset, + otherNode, otherOffset); } /* static */ nsresult nsRange::CloneParentsBetween(nsIDOMNode *aAncestor, nsIDOMNode *aNode, nsIDOMNode **aClosestAncestor, nsIDOMNode **aFarthestAncestor) { @@ -1983,55 +2207,68 @@ nsRange::CloneParentsBetween(nsIDOMNode NS_IF_ADDREF(*aFarthestAncestor); return NS_OK; } NS_IMETHODIMP nsRange::CloneContents(nsIDOMDocumentFragment** aReturn) { - nsresult res; + ErrorResult rv; + *aReturn = CloneContents(rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed<dom::DocumentFragment> +nsRange::CloneContents(ErrorResult& aRv) +{ nsCOMPtr<nsIDOMNode> commonAncestor; - res = GetCommonAncestorContainer(getter_AddRefs(commonAncestor)); - if (NS_FAILED(res)) return res; + aRv = GetCommonAncestorContainer(getter_AddRefs(commonAncestor)); + MOZ_ASSERT(!aRv.Failed(), "GetCommonAncestorContainer() shouldn't fail!"); nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mStartParent->OwnerDoc()); NS_ASSERTION(document, "CloneContents needs a document to continue."); - if (!document) return NS_ERROR_FAILURE; + if (!document) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } // Create a new document fragment in the context of this document, // which might be null - nsCOMPtr<nsIDOMDocumentFragment> clonedFrag; nsCOMPtr<nsIDocument> doc(do_QueryInterface(document)); - res = NS_NewDocumentFragment(getter_AddRefs(clonedFrag), - doc->NodeInfoManager()); - if (NS_FAILED(res)) return res; - - nsCOMPtr<nsIDOMNode> commonCloneAncestor(do_QueryInterface(clonedFrag)); - if (!commonCloneAncestor) return NS_ERROR_FAILURE; + nsRefPtr<dom::DocumentFragment> clonedFrag = + NS_NewDocumentFragment(doc->NodeInfoManager(), aRv); + if (aRv.Failed()) { + return nullptr; + } + + nsCOMPtr<nsIDOMNode> commonCloneAncestor = clonedFrag.get(); + if (!commonCloneAncestor) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } // Create and initialize a subtree iterator that will give // us all the subtrees within the range. RangeSubtreeIterator iter; - res = iter.Init(this); - if (NS_FAILED(res)) return res; + aRv = iter.Init(this); + if (aRv.Failed()) { + return nullptr; + } if (iter.IsDone()) { // There's nothing to add to the doc frag, we must be done! - - *aReturn = clonedFrag; - NS_IF_ADDREF(*aReturn); - return NS_OK; + return clonedFrag.forget(); } iter.First(); // With the exception of text nodes that contain one of the range // end points and elements which don't have any content selected the subtree // iterator should only give us back subtrees that are completely contained // between the range's end points. @@ -2049,18 +2286,20 @@ nsRange::CloneContents(nsIDOMDocumentFra (!(iNode == mEndParent && mEndOffset == 0) && !(iNode == mStartParent && mStartOffset == int32_t(iNode->AsElement()->GetChildCount()))); // Clone the current subtree! nsCOMPtr<nsIDOMNode> clone; - res = node->CloneNode(deepClone, 1, getter_AddRefs(clone)); - if (NS_FAILED(res)) return res; + aRv = node->CloneNode(deepClone, 1, getter_AddRefs(clone)); + if (aRv.Failed()) { + return nullptr; + } // If it's CharacterData, make sure we only clone what // is in the range. // // XXX_kin: We need to also handle ProcessingInstruction // XXX_kin: according to the spec. nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(clone)); @@ -2068,124 +2307,150 @@ nsRange::CloneContents(nsIDOMDocumentFra if (charData) { if (iNode == mEndParent) { // We only need the data before mEndOffset, so get rid of any // data after it. uint32_t dataLength = 0; - res = charData->GetLength(&dataLength); - if (NS_FAILED(res)) return res; + aRv = charData->GetLength(&dataLength); + if (aRv.Failed()) { + return nullptr; + } if (dataLength > (uint32_t)mEndOffset) { - res = charData->DeleteData(mEndOffset, dataLength - mEndOffset); - if (NS_FAILED(res)) return res; + aRv = charData->DeleteData(mEndOffset, dataLength - mEndOffset); + if (aRv.Failed()) { + return nullptr; + } } } if (iNode == mStartParent) { // We don't need any data before mStartOffset, so just // delete it! if (mStartOffset > 0) { - res = charData->DeleteData(0, mStartOffset); - if (NS_FAILED(res)) return res; + aRv = charData->DeleteData(0, mStartOffset); + if (aRv.Failed()) { + return nullptr; + } } } } // Clone the parent hierarchy between commonAncestor and node. nsCOMPtr<nsIDOMNode> closestAncestor, farthestAncestor; - res = CloneParentsBetween(commonAncestor, node, + aRv = CloneParentsBetween(commonAncestor, node, getter_AddRefs(closestAncestor), getter_AddRefs(farthestAncestor)); - if (NS_FAILED(res)) return res; + if (aRv.Failed()) { + return nullptr; + } // Hook the parent hierarchy/context of the subtree into the clone tree. nsCOMPtr<nsIDOMNode> tmpNode; if (farthestAncestor) { - res = commonCloneAncestor->AppendChild(farthestAncestor, + aRv = commonCloneAncestor->AppendChild(farthestAncestor, getter_AddRefs(tmpNode)); - if (NS_FAILED(res)) return res; + if (aRv.Failed()) { + return nullptr; + } } // Place the cloned subtree into the cloned doc frag tree! if (closestAncestor) { // Append the subtree under closestAncestor since it is the // immediate parent of the subtree. - res = closestAncestor->AppendChild(clone, getter_AddRefs(tmpNode)); + aRv = closestAncestor->AppendChild(clone, getter_AddRefs(tmpNode)); } else { // If we get here, there is no missing parent hierarchy between // commonAncestor and node, so just append clone to commonCloneAncestor. - res = commonCloneAncestor->AppendChild(clone, getter_AddRefs(tmpNode)); + aRv = commonCloneAncestor->AppendChild(clone, getter_AddRefs(tmpNode)); } - if (NS_FAILED(res)) return res; + if (aRv.Failed()) { + return nullptr; + } // Get the next subtree to be processed. The idea here is to setup // the parameters for the next iteration of the loop. iter.Next(); if (iter.IsDone()) break; // We must be done! nsCOMPtr<nsIDOMNode> nextNode(iter.GetCurrentNode()); - if (!nextNode) return NS_ERROR_FAILURE; + if (!nextNode) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } // Get node and nextNode's common parent. nsContentUtils::GetCommonAncestor(node, nextNode, getter_AddRefs(commonAncestor)); - if (!commonAncestor) - return NS_ERROR_FAILURE; + if (!commonAncestor) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } // Find the equivalent of commonAncestor in the cloned tree! while (node && node != commonAncestor) { tmpNode = node; - res = tmpNode->GetParentNode(getter_AddRefs(node)); - if (NS_FAILED(res)) return res; - if (!node) return NS_ERROR_FAILURE; + aRv = tmpNode->GetParentNode(getter_AddRefs(node)); + if (aRv.Failed()) { + return nullptr; + } + + if (!node) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } tmpNode = clone; - res = tmpNode->GetParentNode(getter_AddRefs(clone)); - if (NS_FAILED(res)) return res; - if (!clone) return NS_ERROR_FAILURE; + aRv = tmpNode->GetParentNode(getter_AddRefs(clone)); + if (aRv.Failed()) { + return nullptr; + } + + if (!clone) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } } commonCloneAncestor = clone; } - *aReturn = clonedFrag; - NS_IF_ADDREF(*aReturn); - - return NS_OK; + return clonedFrag.forget(); } already_AddRefed<nsRange> nsRange::CloneRange() const { - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mOwner); range->SetMaySpanAnonymousSubtrees(mMaySpanAnonymousSubtrees); range->DoSetRange(mStartParent, mStartOffset, mEndParent, mEndOffset, mRoot); return range.forget(); } @@ -2194,169 +2459,232 @@ nsRange::CloneRange(nsIDOMRange** aRetur { *aReturn = CloneRange().get(); return NS_OK; } NS_IMETHODIMP nsRange::InsertNode(nsIDOMNode* aNode) { - VALIDATE_ACCESS(aNode); - - nsresult res; - int32_t tStartOffset; - this->GetStartOffset(&tStartOffset); + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); + if (!node) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; + } + + ErrorResult rv; + InsertNode(*node, rv); + return rv.ErrorCode(); +} + +void +nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNode)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + int32_t tStartOffset = StartOffset(); nsCOMPtr<nsIDOMNode> tStartContainer; - res = this->GetStartContainer(getter_AddRefs(tStartContainer)); - NS_ENSURE_SUCCESS(res, res); + aRv = this->GetStartContainer(getter_AddRefs(tStartContainer)); + if (aRv.Failed()) { + return; + } // This is the node we'll be inserting before, and its parent nsCOMPtr<nsIDOMNode> referenceNode; nsCOMPtr<nsIDOMNode> referenceParentNode = tStartContainer; nsCOMPtr<nsIDOMText> startTextNode(do_QueryInterface(tStartContainer)); nsCOMPtr<nsIDOMNodeList> tChildList; if (startTextNode) { - res = tStartContainer->GetParentNode(getter_AddRefs(referenceParentNode)); - NS_ENSURE_SUCCESS(res, res); - NS_ENSURE_TRUE(referenceParentNode, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + aRv = tStartContainer->GetParentNode(getter_AddRefs(referenceParentNode)); + if (aRv.Failed()) { + return; + } + + if (!referenceParentNode) { + aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + return; + } nsCOMPtr<nsIDOMText> secondPart; - res = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart)); - NS_ENSURE_SUCCESS(res, res); + aRv = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart)); + if (aRv.Failed()) { + return; + } referenceNode = secondPart; } else { - res = tStartContainer->GetChildNodes(getter_AddRefs(tChildList)); - NS_ENSURE_SUCCESS(res, res); + aRv = tStartContainer->GetChildNodes(getter_AddRefs(tChildList)); + if (aRv.Failed()) { + return; + } // find the insertion point in the DOM and insert the Node - res = tChildList->Item(tStartOffset, getter_AddRefs(referenceNode)); - NS_ENSURE_SUCCESS(res, res); + aRv = tChildList->Item(tStartOffset, getter_AddRefs(referenceNode)); + if (aRv.Failed()) { + return; + } } // We might need to update the end to include the new node (bug 433662). // Ideally we'd only do this if needed, but it's tricky to know when it's // needed in advance (bug 765799). int32_t newOffset; if (referenceNode) { newOffset = IndexOf(referenceNode); } else { uint32_t length; - res = tChildList->GetLength(&length); - NS_ENSURE_SUCCESS(res, res); + aRv = tChildList->GetLength(&length); + if (aRv.Failed()) { + return; + } + newOffset = length; } - nsCOMPtr<nsINode> node = do_QueryInterface(aNode); - NS_ENSURE_STATE(node); - if (node->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { - newOffset += node->GetChildCount(); + if (aNode.NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { + newOffset += aNode.GetChildCount(); } else { newOffset++; } // Now actually insert the node nsCOMPtr<nsIDOMNode> tResultNode; - res = referenceParentNode->InsertBefore(aNode, referenceNode, getter_AddRefs(tResultNode)); - NS_ENSURE_SUCCESS(res, res); + nsCOMPtr<nsIDOMNode> node = aNode.AsDOMNode(); + if (!node) { + aRv.Throw(NS_ERROR_DOM_NOT_OBJECT_ERR); + return; + } + aRv = referenceParentNode->InsertBefore(node, referenceNode, getter_AddRefs(tResultNode)); + if (aRv.Failed()) { + return; + } if (Collapsed()) { - return SetEnd(referenceParentNode, newOffset); + aRv = SetEnd(referenceParentNode, newOffset); } - return NS_OK; } NS_IMETHODIMP nsRange::SurroundContents(nsIDOMNode* aNewParent) { - VALIDATE_ACCESS(aNewParent); - - NS_ENSURE_TRUE(mRoot, NS_ERROR_DOM_INVALID_STATE_ERR); + nsCOMPtr<nsINode> node = do_QueryInterface(aNewParent); + if (!node) { + return NS_ERROR_DOM_NOT_OBJECT_ERR; + } + ErrorResult rv; + SurroundContents(*node, rv); + return rv.ErrorCode(); +} + +void +nsRange::SurroundContents(nsINode& aNewParent, ErrorResult& aRv) +{ + if (!nsContentUtils::CanCallerAccess(&aNewParent)) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; + } + + if (!mRoot) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } // INVALID_STATE_ERROR: Raised if the Range partially selects a non-text // node. if (mStartParent != mEndParent) { bool startIsText = mStartParent->IsNodeOfType(nsINode::eTEXT); bool endIsText = mEndParent->IsNodeOfType(nsINode::eTEXT); nsINode* startGrandParent = mStartParent->GetParentNode(); nsINode* endGrandParent = mEndParent->GetParentNode(); - NS_ENSURE_TRUE((startIsText && endIsText && - startGrandParent && - startGrandParent == endGrandParent) || - (startIsText && - startGrandParent && - startGrandParent == mEndParent) || - (endIsText && - endGrandParent && - endGrandParent == mStartParent), - NS_ERROR_DOM_INVALID_STATE_ERR); + if (!((startIsText && endIsText && + startGrandParent && + startGrandParent == endGrandParent) || + (startIsText && + startGrandParent && + startGrandParent == mEndParent) || + (endIsText && + endGrandParent && + endGrandParent == mStartParent))) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } } // INVALID_NODE_TYPE_ERROR if aNewParent is something that can't be inserted // (Document, DocumentType, DocumentFragment) - uint16_t nodeType; - nsresult res = aNewParent->GetNodeType(&nodeType); - if (NS_FAILED(res)) return res; + uint16_t nodeType = aNewParent.NodeType(); if (nodeType == nsIDOMNode::DOCUMENT_NODE || nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE || nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { - return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR; + aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR); + return; } // Extract the contents within the range. nsCOMPtr<nsIDOMDocumentFragment> docFrag; - res = ExtractContents(getter_AddRefs(docFrag)); - - if (NS_FAILED(res)) return res; - if (!docFrag) return NS_ERROR_FAILURE; + aRv = ExtractContents(getter_AddRefs(docFrag)); + + if (aRv.Failed()) { + return; + } + + if (!docFrag) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } // Spec says we need to remove all of aNewParent's // children prior to insertion. - nsCOMPtr<nsIDOMNodeList> children; - res = aNewParent->GetChildNodes(getter_AddRefs(children)); - - if (NS_FAILED(res)) return res; - if (!children) return NS_ERROR_FAILURE; - - uint32_t numChildren = 0; - res = children->GetLength(&numChildren); - if (NS_FAILED(res)) return res; + nsCOMPtr<nsINodeList> children = aNewParent.ChildNodes(); + if (!children) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + uint32_t numChildren = children->Length(); nsCOMPtr<nsIDOMNode> tmpNode; while (numChildren) { - nsCOMPtr<nsIDOMNode> child; - res = children->Item(--numChildren, getter_AddRefs(child)); - - if (NS_FAILED(res)) return res; - if (!child) return NS_ERROR_FAILURE; - - res = aNewParent->RemoveChild(child, getter_AddRefs(tmpNode)); - if (NS_FAILED(res)) return res; + nsCOMPtr<nsINode> child = children->Item(--numChildren); + if (!child) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + aNewParent.RemoveChild(*child, aRv); + if (aRv.Failed()) { + return; + } } // Insert aNewParent at the range's start point. - res = InsertNode(aNewParent); - if (NS_FAILED(res)) return res; + InsertNode(aNewParent, aRv); + if (aRv.Failed()) { + return; + } // Append the content we extracted under aNewParent. - - res = aNewParent->AppendChild(docFrag, getter_AddRefs(tmpNode)); - if (NS_FAILED(res)) return res; + aRv = aNewParent.AsDOMNode()->AppendChild(docFrag, getter_AddRefs(tmpNode)); + if (aRv.Failed()) { + return; + } // Select aNewParent, and its contents. - return SelectNode(aNewParent); + SelectNode(aNewParent, aRv); } NS_IMETHODIMP nsRange::ToString(nsAString& aReturn) { // clear the string aReturn.Truncate(); @@ -2457,16 +2785,28 @@ nsRange::CreateContextualFragment(const { if (mIsPositioned) { return nsContentUtils::CreateContextualFragment(mStartParent, aFragment, false, aReturn); } return NS_ERROR_FAILURE; } +already_AddRefed<dom::DocumentFragment> +nsRange::CreateContextualFragment(const nsAString& aFragment, ErrorResult& aRv) +{ + if (!mIsPositioned) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + return nsContentUtils::CreateContextualFragment(mStartParent, aFragment, + false, aRv); +} + static void ExtractRectFromOffset(nsIFrame* aFrame, const nsIFrame* aRelativeTo, const int32_t aOffset, nsRect* aR, bool aKeepLeft) { nsPoint point; aFrame->GetPointFromOffset(aOffset, &point); point += aFrame->GetOffsetTo(aRelativeTo); @@ -2589,61 +2929,64 @@ static void CollectClientRects(nsLayoutU nsLayoutUtils::GetContainingBlockForClientRect(frame), aCollector); } } while (!iter.IsDone()); } NS_IMETHODIMP nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult) { - *aResult = nullptr; - - // Weak ref, since we addref it below - nsClientRect* rect = new nsClientRect(); - if (!rect) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(*aResult = rect); - + *aResult = GetBoundingClientRect().get(); + return NS_OK; +} + +already_AddRefed<nsIDOMClientRect> +nsRange::GetBoundingClientRect() +{ + nsRefPtr<nsClientRect> rect = new nsClientRect(); if (!mStartParent) - return NS_OK; + return rect.forget(); nsLayoutUtils::RectAccumulator accumulator; - CollectClientRects(&accumulator, this, mStartParent, mStartOffset, mEndParent, mEndOffset); nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect : accumulator.mResultRect; rect->SetLayoutRect(r); - return NS_OK; + return rect.forget(); } NS_IMETHODIMP nsRange::GetClientRects(nsIDOMClientRectList** aResult) { - *aResult = nullptr; - + ErrorResult rv; + *aResult = GetClientRects(rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed<nsClientRectList> +nsRange::GetClientRects(ErrorResult& rv) +{ if (!mStartParent) - return NS_OK; + return nullptr; nsRefPtr<nsClientRectList> rectList = new nsClientRectList(static_cast<nsIDOMRange*>(this)); - if (!rectList) - return NS_ERROR_OUT_OF_MEMORY; nsLayoutUtils::RectListBuilder builder(rectList); CollectClientRects(&builder, this, mStartParent, mStartOffset, mEndParent, mEndOffset); - if (NS_FAILED(builder.mRV)) - return builder.mRV; - rectList.forget(aResult); - return NS_OK; + if (NS_FAILED(builder.mRV)) { + rv.Throw(builder.mRV); + return nullptr; + } + return rectList.forget(); } NS_IMETHODIMP nsRange::GetUsedFontFaces(nsIDOMFontFaceList** aResult) { *aResult = nullptr; NS_ENSURE_TRUE(mStartParent, NS_ERROR_UNEXPECTED);
--- a/content/base/src/nsRange.h +++ b/content/base/src/nsRange.h @@ -7,52 +7,71 @@ * Implementation of the DOM nsIDOMRange object. */ #ifndef nsRange_h___ #define nsRange_h___ #include "nsIDOMRange.h" #include "nsCOMPtr.h" -#include "nsIDOMDocumentFragment.h" #include "nsINode.h" +#include "nsIDocument.h" #include "nsIDOMNode.h" #include "prmon.h" #include "nsStubMutationObserver.h" +#include "nsWrapperCache.h" +#include "mozilla/Attributes.h" -class nsRange : public nsIDOMRange, - public nsStubMutationObserver +class nsClientRectList; +class nsIDOMDocumentFragment; + +namespace mozilla { +class ErrorResult; +namespace dom { +class DocumentFragment; +} +} + +class nsRange MOZ_FINAL : public nsIDOMRange, + public nsStubMutationObserver, + public nsWrapperCache { + typedef mozilla::ErrorResult ErrorResult; + public: - nsRange() + nsRange(nsINode* aNode) : mRoot(nullptr) , mStartOffset(0) , mEndOffset(0) , mIsPositioned(false) , mIsDetached(false) , mMaySpanAnonymousSubtrees(false) , mInSelection(false) , mStartOffsetWasIncremented(false) , mEndOffsetWasIncremented(false) #ifdef DEBUG , mAssertNextInsertOrAppendIndex(-1) , mAssertNextInsertOrAppendNode(nullptr) #endif - {} + { + SetIsDOMBinding(); + MOZ_ASSERT(aNode, "range isn't in a document!"); + mOwner = aNode->OwnerDoc(); + } virtual ~nsRange(); static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset, nsIDOMNode* aEndParent, int32_t aEndOffset, nsRange** aRange); static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset, nsIDOMNode* aEndParent, int32_t aEndOffset, nsIDOMRange** aRange); NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsRange, nsIDOMRange) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsRange, nsIDOMRange) // nsIDOMRange interface NS_DECL_NSIDOMRANGE nsINode* GetRoot() const { return mRoot; } @@ -77,22 +96,16 @@ public: return mEndOffset; } bool IsPositioned() const { return mIsPositioned; } - bool Collapsed() const - { - return mIsPositioned && mStartParent == mEndParent && - mStartOffset == mEndOffset; - } - void SetMaySpanAnonymousSubtrees(bool aMaySpanAnonymousSubtrees) { mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees; } /** * Return true iff this range is part of at least one Selection object * and isn't detached. @@ -141,28 +154,67 @@ public: // nsIMutationObserver methods NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + // WebIDL + bool Collapsed() const + { + return mIsPositioned && mStartParent == mEndParent && + mStartOffset == mEndOffset; + } + already_AddRefed<mozilla::dom::DocumentFragment> + CreateContextualFragment(const nsAString& aString, ErrorResult& aError); + already_AddRefed<mozilla::dom::DocumentFragment> + CloneContents(ErrorResult& aErr); + int16_t CompareBoundaryPoints(uint16_t aHow, nsRange& aOther, + ErrorResult& aErr); + int16_t ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aErr); + void DeleteContents(ErrorResult& aRv); + already_AddRefed<mozilla::dom::DocumentFragment> + ExtractContents(ErrorResult& aErr); + nsINode* GetCommonAncestorContainer(ErrorResult& aRv) const; + nsINode* GetStartContainer(ErrorResult& aRv) const; + uint32_t GetStartOffset(ErrorResult& aRv) const; + nsINode* GetEndContainer(ErrorResult& aRv) const; + uint32_t GetEndOffset(ErrorResult& aRv) const; + void InsertNode(nsINode& aNode, ErrorResult& aErr); + bool IntersectsNode(nsINode& aNode, ErrorResult& aRv); + bool IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aErr); + void SelectNode(nsINode& aNode, ErrorResult& aErr); + void SelectNodeContents(nsINode& aNode, ErrorResult& aErr); + void SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr); + void SetEndAfter(nsINode& aNode, ErrorResult& aErr); + void SetEndBefore(nsINode& aNode, ErrorResult& aErr); + void SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aErr); + void SetStartAfter(nsINode& aNode, ErrorResult& aErr); + void SetStartBefore(nsINode& aNode, ErrorResult& aErr); + void SurroundContents(nsINode& aNode, ErrorResult& aErr); + already_AddRefed<nsIDOMClientRect> GetBoundingClientRect(); + already_AddRefed<nsClientRectList> GetClientRects(ErrorResult& aErr); + + nsINode* GetParentObject() const { return mOwner; } + virtual JSObject* WrapObject(JSContext* cx, JSObject* scope) MOZ_OVERRIDE MOZ_FINAL; + private: // no copy's or assigns nsRange(const nsRange&); nsRange& operator=(const nsRange&); /** * Cut or delete the range's contents. * * @param aFragment nsIDOMDocumentFragment containing the nodes. * May be null to indicate the caller doesn't want a fragment. */ - nsresult CutContents(nsIDOMDocumentFragment** frag); + nsresult CutContents(mozilla::dom::DocumentFragment** frag); static nsresult CloneParentsBetween(nsIDOMNode *aAncestor, nsIDOMNode *aNode, nsIDOMNode **aClosestAncestor, nsIDOMNode **aFarthestAncestor); public: /****************************************************************************** @@ -219,17 +271,18 @@ protected: ~AutoInvalidateSelection(); nsRange* mRange; nsRefPtr<nsINode> mCommonAncestor; #ifdef DEBUG bool mWasInSelection; #endif static bool mIsNested; }; - + + nsCOMPtr<nsIDocument> mOwner; nsCOMPtr<nsINode> mRoot; nsCOMPtr<nsINode> mStartParent; nsCOMPtr<nsINode> mEndParent; int32_t mStartOffset; int32_t mEndOffset; bool mIsPositioned; bool mIsDetached;
--- a/content/events/src/nsContentEventHandler.cpp +++ b/content/events/src/nsContentEventHandler.cpp @@ -510,17 +510,17 @@ nsContentEventHandler::OnQueryTextConten { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) return rv; NS_ASSERTION(aEvent->mReply.mString.IsEmpty(), "The reply string must be empty"); - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mRootContent); rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, aEvent->mInput.mLength, false); NS_ENSURE_SUCCESS(rv, rv); rv = GenerateFlatTextContent(range, aEvent->mReply.mString); NS_ENSURE_SUCCESS(rv, rv); aEvent->mSucceeded = true; @@ -567,17 +567,17 @@ static nsresult GetFrameForTextRect(nsIN nsresult nsContentEventHandler::OnQueryTextRect(nsQueryContentEvent* aEvent) { nsresult rv = Init(aEvent); if (NS_FAILED(rv)) return rv; - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mRootContent); rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, aEvent->mInput.mLength, true); NS_ENSURE_SUCCESS(rv, rv); // used to iterate over all contents and their frames nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator(); iter->Init(range); @@ -711,17 +711,17 @@ nsContentEventHandler::OnQueryCaretRect( aEvent->mReply.mRect = rect.ToOutsidePixels(caretFrame->PresContext()->AppUnitsPerDevPixel()); aEvent->mSucceeded = true; return NS_OK; } } // Otherwise, we should set the guessed caret rect. - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mRootContent); rv = SetRangeFromFlatTextOffset(range, aEvent->mInput.mOffset, 0, true); NS_ENSURE_SUCCESS(rv, rv); int32_t offsetInFrame; nsIFrame* frame; rv = GetStartFrameAndOffset(range, &frame, &offsetInFrame); NS_ENSURE_SUCCESS(rv, rv); @@ -894,19 +894,20 @@ nsContentEventHandler::OnQueryDOMWidgetH } nsresult nsContentEventHandler::GetFlatTextOffsetOfRange(nsIContent* aRootContent, nsINode* aNode, int32_t aNodeOffset, uint32_t* aNativeOffset) { + NS_ENSURE_STATE(aRootContent); NS_ASSERTION(aNativeOffset, "param is invalid"); - nsRefPtr<nsRange> prev = new nsRange(); + nsRefPtr<nsRange> prev = new nsRange(aRootContent); nsCOMPtr<nsIDOMNode> rootDOMNode(do_QueryInterface(aRootContent)); prev->SetStart(rootDOMNode, 0); nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(aNode)); NS_ASSERTION(startDOMNode, "startNode doesn't have nsIDOMNode"); prev->SetEnd(startDOMNode, aNodeOffset); nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator(); @@ -1028,17 +1029,17 @@ nsContentEventHandler::OnSelectionEvent( if (rv != NS_ERROR_NOT_AVAILABLE) { NS_ENSURE_SUCCESS(rv, rv); } else { rv = Init(aEvent); NS_ENSURE_SUCCESS(rv, rv); } // Get range from offset and length - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mRootContent); NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY); rv = SetRangeFromFlatTextOffset(range, aEvent->mOffset, aEvent->mLength, aEvent->mExpandToClusterBoundary); NS_ENSURE_SUCCESS(rv, rv); nsINode* startNode = range->GetStartParent(); nsINode* endNode = range->GetEndParent(); int32_t startOffset = range->StartOffset();
--- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -3156,17 +3156,17 @@ nsIContent* nsHTMLMediaElement::GetNextS { nsCOMPtr<nsIDOMNode> thisDomNode = do_QueryObject(this); mSourceLoadCandidate = nullptr; nsresult rv = NS_OK; if (!mSourcePointer) { // First time this has been run, create a selection to cover children. - mSourcePointer = new nsRange(); + mSourcePointer = new nsRange(this); rv = mSourcePointer->SelectNodeContents(thisDomNode); if (NS_FAILED(rv)) return nullptr; rv = mSourcePointer->Collapse(true); if (NS_FAILED(rv)) return nullptr; }
--- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2600,17 +2600,17 @@ nsHTMLDocument::DeferredContentEditableC nsIDocShell *docshell = window->GetDocShell(); if (!docshell) return; nsCOMPtr<nsIEditor> editor; docshell->GetEditor(getter_AddRefs(editor)); if (editor) { - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aElement); rv = range->SelectNode(node); if (NS_FAILED(rv)) { // The node might be detached from the document at this point, // which would cause this call to fail. In this case, we can // safely ignore the contenteditable count change. return; }
--- a/content/test/unit/test_range.js +++ b/content/test/unit/test_range.js @@ -358,25 +358,25 @@ function run_miscellaneous_tests() { if ((endOffset > startOffset) && (startContainer == endContainer) && (startContainer instanceof C_i.nsIDOMText)) { // Invalid start node try { baseRange.setStart(null, 0); do_throw("Should have thrown NOT_OBJECT_ERR!"); } catch (e) { - do_check_eq(e.name, "NS_ERROR_DOM_NOT_OBJECT_ERR"); + do_check_eq(e instanceof TypeError, true); } // Invalid start node try { baseRange.setStart({}, 0); do_throw("Should have thrown SecurityError!"); } catch (e) { - do_check_eq(e.name, "SecurityError"); + do_check_true(e instanceof TypeError); } // Invalid index try { baseRange.setStart(startContainer, -1); do_throw("Should have thrown IndexSizeError!"); } catch (e) { do_check_eq(e.name, "IndexSizeError");
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -567,16 +567,24 @@ DOMInterfaces = { 'nativeOwnership': 'refcounted' }, 'PropertyNodeList': { 'headerFile': 'HTMLPropertiesCollection.h', 'resultNotAddRefed': [ 'item' ] }, +'Range': { + 'nativeType': 'nsRange', + 'resultNotAddRefed': [ 'startContainer', 'endContainer', 'commonAncestorContainer' ], + 'binaryNames': { + '__stringifier': 'ToString' + } +}, + 'Rect': { 'nativeType': 'nsDOMCSSRect', 'resultNotAddRefed': [ 'top', 'right', 'bottom', 'left' ] }, 'RGBColor': { 'nativeOwnership': 'refcounted', 'nativeType': 'nsDOMCSSRGBColor', @@ -1221,17 +1229,16 @@ addExternalIface('MozXULTemplateBuilder' addExternalIface('MozNamedAttrMap') addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True) addExternalIface('nsISupports', nativeType='nsISupports') addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True) addExternalIface('OutputStream', nativeType='nsIOutputStream', notflattened=True) addExternalIface('Principal', nativeType='nsIPrincipal', headerFile='nsIPrincipal.h', notflattened=True) -addExternalIface('Range', nativeType='nsRange') addExternalIface('Selection', nativeType='nsISelection') addExternalIface('StyleSheet', nativeType='nsIStyleSheet') addExternalIface('StyleSheetList') addExternalIface('SVGAnimatedEnumeration', headerFile='nsIDOMSVGAnimatedEnum.h') addExternalIface('SVGAnimatedNumber') addExternalIface('SVGAnimatedString') addExternalIface('SVGLength') addExternalIface('SVGNumber')
--- a/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json +++ b/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json @@ -70,55 +70,16 @@ "Attr interface: existence and properties of interface prototype object's \"constructor\" property": true, "Attr interface: attribute name": true, "Attr interface: attribute value": true, "Stringification of document.querySelector(\"[id]\").attributes[0]": "debug", "CharacterData interface: operation remove()": true, "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"remove\" with the proper type (7)": true, "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"remove\" with the proper type (7)": true, "CharacterData interface: document.createComment(\"abc\") must inherit property \"remove\" with the proper type (7)": true, - "Range interface: existence and properties of interface object": true, - "Range interface: existence and properties of interface prototype object": true, - "Range interface: existence and properties of interface prototype object's \"constructor\" property": true, - "Range interface: attribute startContainer": true, - "Range interface: attribute startOffset": true, - "Range interface: attribute endContainer": true, - "Range interface: attribute endOffset": true, - "Range interface: attribute collapsed": true, - "Range interface: attribute commonAncestorContainer": true, - "Range interface: calling setStart(Node,unsigned long) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling setEnd(Node,unsigned long) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling setStartBefore(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling setStartAfter(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling setEndBefore(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling setEndAfter(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling collapse(boolean) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling selectNode(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling selectNodeContents(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling compareBoundaryPoints(unsigned short,Range) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling insertNode(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling surroundContents(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling isPointInRange(Node,unsigned long) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling comparePoint(Node,unsigned long) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling intersectsNode(Node) on document.createRange() with too few arguments must throw TypeError": true, - "Range interface: calling setStart(Node,unsigned long) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling setEnd(Node,unsigned long) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling setStartBefore(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling setStartAfter(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling setEndBefore(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling setEndAfter(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling collapse(boolean) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling selectNode(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling selectNodeContents(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling compareBoundaryPoints(unsigned short,Range) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling insertNode(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling surroundContents(Node) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling isPointInRange(Node,unsigned long) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling comparePoint(Node,unsigned long) on detachedRange with too few arguments must throw TypeError": true, - "Range interface: calling intersectsNode(Node) on detachedRange with too few arguments must throw TypeError": true, "NodeFilter interface: existence and properties of interface object": true, "NodeFilter interface: existence and properties of interface prototype object": true, "NodeFilter interface: existence and properties of interface prototype object's \"constructor\" property": true, "NodeFilter interface: constant FILTER_ACCEPT on interface prototype object": true, "NodeFilter interface: constant FILTER_REJECT on interface prototype object": true, "NodeFilter interface: constant FILTER_SKIP on interface prototype object": true, "NodeFilter interface: constant SHOW_ALL on interface prototype object": true, "NodeFilter interface: constant SHOW_ELEMENT on interface prototype object": true,
--- a/dom/imptests/failures/webapps/DOMCore/tests/submissions/Ms2ger/Makefile.in +++ b/dom/imptests/failures/webapps/DOMCore/tests/submissions/Ms2ger/Makefile.in @@ -20,15 +20,14 @@ MOCHITEST_FILES := \ test_Event-defaultPrevented.html.json \ test_EventTarget-dispatchEvent.html.json \ test_Node-isEqualNode.xhtml.json \ test_NodeFilter-constants.html.json \ test_Range-attributes.html.json \ test_Range-commonAncestorContainer.html.json \ test_Range-comparePoint.html.json \ test_Range-detach.html.json \ - test_Range-intersectsNode-binding.html.json \ test_attributes.html.json \ test_case.html.json \ test_historical.html.json \ $(NULL) include $(topsrcdir)/config/rules.mk
--- a/dom/imptests/failures/webapps/DOMCore/tests/submissions/Ms2ger/test_Range-comparePoint.html.json +++ b/dom/imptests/failures/webapps/DOMCore/tests/submissions/Ms2ger/test_Range-comparePoint.html.json @@ -1,4 +1,3 @@ { - "Range.comparePoint": true, - "Range.comparePoint 1": true + "Range.comparePoint": true }
deleted file mode 100644 --- a/dom/imptests/failures/webapps/DOMCore/tests/submissions/Ms2ger/test_Range-intersectsNode-binding.html.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Calling intersectsNode without an argument or with an invalid argument should throw a TypeError.": true -}
--- a/dom/interfaces/core/nsIDOMDocumentFragment.idl +++ b/dom/interfaces/core/nsIDOMDocumentFragment.idl @@ -9,12 +9,12 @@ * DocumentFragment is a "lightweight" or "minimal" Document object. * nsIDOMDocumentFragment is used in situations where the Document * interface can potentially be a heavyweight interface. * * For more information on this interface please see * http://www.w3.org/TR/DOM-Level-2-Core/ */ -[scriptable, uuid(b098fc8f-9ef4-4de8-bbd0-4a0fc712dd6e)] +[scriptable, builtinclass, uuid(b098fc8f-9ef4-4de8-bbd0-4a0fc712dd6e)] interface nsIDOMDocumentFragment : nsIDOMNode { };
--- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -12,17 +12,16 @@ * http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface * http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface * * http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl */ interface Attr; interface Comment; -interface Range; interface StyleSheetList; interface Touch; interface TouchList; interface WindowProxy; interface nsISupports; enum VisibilityState { "hidden", "visible" };
--- a/dom/webidl/Range.webidl +++ b/dom/webidl/Range.webidl @@ -1,52 +1,90 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://www.w3.org/TR/2012/WD-dom-20120105/ + * http://dom.spec.whatwg.org/#range + * http://domparsing.spec.whatwg.org/#dom-range-createcontextualfragment + * http://dvcs.w3.org/hg/csswg/raw-file/tip/cssom-view/Overview.html#extensions-to-the-range-interface * * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ +interface ClientRect; + interface Range { + [Throws] readonly attribute Node startContainer; + [Throws] readonly attribute unsigned long startOffset; + [Throws] readonly attribute Node endContainer; + [Throws] readonly attribute unsigned long endOffset; readonly attribute boolean collapsed; + [Throws] readonly attribute Node commonAncestorContainer; + [Throws] void setStart(Node refNode, unsigned long offset); + [Throws] void setEnd(Node refNode, unsigned long offset); + [Throws] void setStartBefore(Node refNode); + [Throws] void setStartAfter(Node refNode); + [Throws] void setEndBefore(Node refNode); + [Throws] void setEndAfter(Node refNode); void collapse(boolean toStart); + [Throws] void selectNode(Node refNode); + [Throws] void selectNodeContents(Node refNode); const unsigned short START_TO_START = 0; const unsigned short START_TO_END = 1; const unsigned short END_TO_END = 2; const unsigned short END_TO_START = 3; + [Throws] short compareBoundaryPoints(unsigned short how, Range sourceRange); - + [Throws] void deleteContents(); + [Throws] DocumentFragment extractContents(); + [Throws] DocumentFragment cloneContents(); + [Throws] void insertNode(Node node); + [Throws] void surroundContents(Node newParent); Range cloneRange(); void detach(); + [Throws] boolean isPointInRange(Node node, unsigned long offset); + [Throws] short comparePoint(Node node, unsigned long offset); + [Throws] boolean intersectsNode(Node node); stringifier; }; + +// http://domparsing.spec.whatwg.org/#dom-range-createcontextualfragment +partial interface Range { + [Throws] + DocumentFragment createContextualFragment(DOMString fragment); +}; + +// http://dvcs.w3.org/hg/csswg/raw-file/tip/cssom-view/Overview.html#extensions-to-the-range-interface +partial interface Range { + [Throws] + ClientRectList getClientRects(); + ClientRect getBoundingClientRect(); +};
--- a/dom/webidl/WebIDL.mk +++ b/dom/webidl/WebIDL.mk @@ -128,16 +128,17 @@ webidl_files = \ NodeList.webidl \ PaintRequest.webidl \ PaintRequestList.webidl \ PannerNode.webidl \ Performance.webidl \ PerformanceNavigation.webidl \ PerformanceTiming.webidl \ ProcessingInstruction.webidl \ + Range.webidl \ Rect.webidl \ RGBColor.webidl \ RTCConfiguration.webidl \ Screen.webidl \ SVGAElement.webidl \ SVGAltGlyphElement.webidl \ SVGAngle.webidl \ SVGAnimatedAngle.webidl \
--- a/editor/libeditor/base/IMETextTxn.cpp +++ b/editor/libeditor/base/IMETextTxn.cpp @@ -309,18 +309,23 @@ NS_IMETHODIMP IMETextTxn::CollapseTextSe continue; result= selCon->GetSelection(TextRangeToSelection(textRangeType), getter_AddRefs(imeSel)); NS_ASSERTION(NS_SUCCEEDED(result), "Cannot get selction"); if(NS_FAILED(result)) break; - nsRefPtr<nsRange> newRange = new nsRange(); - result = newRange->SetStart(mElement,mOffset+selectionStart); + nsCOMPtr<nsIContent> content = do_QueryInterface(mElement); + if (!content) { + break; + } + + nsRefPtr<nsRange> newRange = new nsRange(content); + result = newRange->SetStart(content, mOffset+selectionStart); NS_ASSERTION(NS_SUCCEEDED(result), "Cannot SetStart"); if(NS_FAILED(result)) break; result = newRange->SetEnd(mElement,mOffset+selectionEnd); NS_ASSERTION(NS_SUCCEEDED(result), "Cannot SetEnd"); if(NS_FAILED(result)) break;
--- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -242,30 +242,36 @@ nsHTMLEditRules::Init(nsPlaintextEditor nsAdoptingCString returnInEmptyLIKillsList = Preferences::GetCString(kPrefName); // only when "false", becomes FALSE. Otherwise (including empty), TRUE. // XXX Why was this pref designed as a string and not bool? mReturnInEmptyLIKillsList = !returnInEmptyLIKillsList.EqualsLiteral("false"); // make a utility range for use by the listenter - mUtilRange = new nsRange(); + nsCOMPtr<nsINode> node = mHTMLEditor->GetRoot(); + if (!node) { + node = mHTMLEditor->GetDocument(); + } + + NS_ENSURE_STATE(node); + + mUtilRange = new nsRange(node); // set up mDocChangeRange to be whole doc - nsCOMPtr<nsIDOMElement> rootElem = do_QueryInterface(mHTMLEditor->GetRoot()); - if (rootElem) - { - // temporarily turn off rules sniffing - nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this); - if (!mDocChangeRange) - { - mDocChangeRange = new nsRange(); - } - mDocChangeRange->SelectNode(rootElem); - res = AdjustSpecialBreaks(); + // temporarily turn off rules sniffing + nsAutoLockRulesSniffing lockIt((nsTextEditRules*)this); + if (!mDocChangeRange) { + mDocChangeRange = new nsRange(node); + } + + if (node->IsElement()) { + ErrorResult rv; + mDocChangeRange->SelectNode(*node, rv); + res = AdjustSpecialBreaks(node); NS_ENSURE_SUCCESS(res, res); } // add ourselves as a listener to edit actions res = mHTMLEditor->AddEditActionListener(this); return res; } @@ -1435,17 +1441,19 @@ nsHTMLEditRules::WillInsertText(EditActi nsCOMPtr<nsISelection> selection(aSelection); nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection)); selPriv->SetInterlinePosition(false); if (curNode) aSelection->Collapse(curNode, curOffset); // manually update the doc changed range so that AfterEdit will clean up // the correct portion of the document. if (!mDocChangeRange) { - mDocChangeRange = new nsRange(); + nsCOMPtr<nsINode> node = do_QueryInterface(selNode); + NS_ENSURE_STATE(node); + mDocChangeRange = new nsRange(node); } res = mDocChangeRange->SetStart(selNode, selOffset); NS_ENSURE_SUCCESS(res, res); if (curNode) res = mDocChangeRange->SetEnd(curNode, curOffset); else res = mDocChangeRange->SetEnd(selNode, selOffset); NS_ENSURE_SUCCESS(res, res); @@ -5064,17 +5072,19 @@ nsHTMLEditRules::ExpandSelectionForDelet { // find block node containing br nsCOMPtr<nsIDOMNode> brBlock = firstBRParent; if (!IsBlockNode(brBlock)) brBlock = nsHTMLEditor::GetBlockNodeParent(brBlock); bool nodeBefore=false, nodeAfter=false; // create a range that represents expanded selection - nsRefPtr<nsRange> range = new nsRange(); + nsCOMPtr<nsINode> node = do_QueryInterface(selStartNode); + NS_ENSURE_STATE(node); + nsRefPtr<nsRange> range = new nsRange(node); res = range->SetStart(selStartNode, selStartOffset); NS_ENSURE_SUCCESS(res, res); res = range->SetEnd(selEndNode, selEndOffset); NS_ENSURE_SUCCESS(res, res); // check if block is entirely inside range nsCOMPtr<nsIContent> brContentBlock = do_QueryInterface(brBlock); res = nsRange::CompareNodeToRange(brContentBlock, range, &nodeBefore, &nodeAfter); @@ -6111,17 +6121,19 @@ nsHTMLEditRules::GetNodesFromPoint(DOMPo nsresult res; // get our point nsCOMPtr<nsIDOMNode> node; int32_t offset; point.GetPoint(node, offset); // use it to make a range - nsRefPtr<nsRange> range = new nsRange(); + nsCOMPtr<nsINode> nativeNode = do_QueryInterface(node); + NS_ENSURE_STATE(nativeNode); + nsRefPtr<nsRange> range = new nsRange(nativeNode); res = range->SetStart(node, offset); NS_ENSURE_SUCCESS(res, res); /* SetStart() will also set the end for this new range res = range->SetEnd(node, offset); NS_ENSURE_SUCCESS(res, res); */ // expand the range to include adjacent inlines res = PromoteRange(range, operation); @@ -7291,17 +7303,19 @@ nsHTMLEditRules::PinSelectionToNewBlock( // get the (collapsed) selection location nsCOMPtr<nsIDOMNode> selNode, temp; int32_t selOffset; nsresult res = mHTMLEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset); NS_ENSURE_SUCCESS(res, res); temp = selNode; // use ranges and sRangeHelper to compare sel point to new block - nsRefPtr<nsRange> range = new nsRange(); + nsCOMPtr<nsINode> node = do_QueryInterface(selNode); + NS_ENSURE_STATE(node); + nsRefPtr<nsRange> range = new nsRange(node); res = range->SetStart(selNode, selOffset); NS_ENSURE_SUCCESS(res, res); res = range->SetEnd(selNode, selOffset); NS_ENSURE_SUCCESS(res, res); nsCOMPtr<nsIContent> block (do_QueryInterface(mNewBlock)); NS_ENSURE_TRUE(block, NS_ERROR_NO_INTERFACE); bool nodeBefore, nodeAfter; res = nsRange::CompareNodeToRange(block, range, &nodeBefore, &nodeAfter);
--- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -3248,17 +3248,17 @@ nsHTMLEditor::ContentInserted(nsIDocumen if (IsMozEditorBogusNode(aChild)) { // Ignore insertion of the bogus node return; } mRules->DocumentModified(); // Update spellcheck for only the newly-inserted node (bug 743819) if (mInlineSpellChecker) { - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aChild); nsresult res = range->Set(aContainer, aIndexInContainer, aContainer, aIndexInContainer + 1); if (NS_SUCCEEDED(res)) { mInlineSpellChecker->SpellCheckRange(range); } } } }
--- a/editor/libeditor/html/nsWSRunObject.cpp +++ b/editor/libeditor/html/nsWSRunObject.cpp @@ -1479,18 +1479,20 @@ nsWSRunObject::DeleteChars(nsIDOMNode *a NS_ENSURE_SUCCESS(res, res); } break; } else { if (!range) { - range = new nsRange(); - res = range->SetStart(aStartNode, aStartOffset); + nsCOMPtr<nsINode> startNode = do_QueryInterface(aStartNode); + NS_ENSURE_STATE(startNode); + range = new nsRange(startNode); + res = range->SetStart(startNode, aStartOffset); NS_ENSURE_SUCCESS(res, res); res = range->SetEnd(aEndNode, aEndOffset); NS_ENSURE_SUCCESS(res, res); } bool nodeBefore, nodeAfter; nsCOMPtr<nsIContent> content (do_QueryInterface(node)); res = nsRange::CompareNodeToRange(content, range, &nodeBefore, &nodeAfter); NS_ENSURE_SUCCESS(res, res);
--- a/editor/libeditor/html/tests/test_bug629845.html +++ b/editor/libeditor/html/tests/test_bug629845.html @@ -21,20 +21,22 @@ function initFrame(frame) document.getElementsByTagName('button')[0].click(); } function command(aName) { var frame = document.getElementsByTagName('iframe')[0]; + is(frame.contentDocument.designMode, "on", "design mode should be on!"); var caught = false; try { frame.contentDocument.execCommand(aName, false, null); } catch (e) { + ok(false, "exception " + e + " was thrown"); caught = true; } ok(!caught, "No exception should have been thrown."); // Stop the document load before finishing, just to be clean. document.getElementsByTagName('iframe')[0].contentWindow.document.close(); SimpleTest.finish();
--- a/editor/txtsvc/src/nsFilteredContentIterator.cpp +++ b/editor/txtsvc/src/nsFilteredContentIterator.cpp @@ -52,23 +52,24 @@ NS_IMPL_CYCLE_COLLECTION_5(nsFilteredCon mPreIterator, mFilter, mRange) //------------------------------------------------------------ nsresult nsFilteredContentIterator::Init(nsINode* aRoot) { + NS_ENSURE_ARG_POINTER(aRoot); NS_ENSURE_TRUE(mPreIterator, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); mIsOutOfRange = false; mDirection = eForward; mCurrentIterator = mPreIterator; - mRange = new nsRange(); + mRange = new nsRange(aRoot); nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(aRoot)); if (domNode) { mRange->SelectNode(domNode); } nsresult rv = mPreIterator->Init(mRange); NS_ENSURE_SUCCESS(rv, rv); return mIterator->Init(mRange);
--- a/editor/txtsvc/src/nsTextServicesDocument.cpp +++ b/editor/txtsvc/src/nsTextServicesDocument.cpp @@ -2065,17 +2065,20 @@ nsTextServicesDocument::CreateDocumentCo { *aRange = NULL; nsCOMPtr<nsIDOMNode> node; nsresult rv = GetDocumentContentRootNode(getter_AddRefs(node)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); - nsRefPtr<nsRange> range = new nsRange(); + nsCOMPtr<nsINode> nativeNode = do_QueryInterface(node); + NS_ENSURE_STATE(nativeNode); + + nsRefPtr<nsRange> range = new nsRange(nativeNode); rv = range->SelectNodeContents(node); NS_ENSURE_SUCCESS(rv, rv); range.forget(aRange); return NS_OK; }
--- a/embedding/components/find/src/nsFind.cpp +++ b/embedding/components/find/src/nsFind.cpp @@ -142,16 +142,18 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFindC NS_IMPL_CYCLE_COLLECTION_6(nsFindContentIterator, mOuterIterator, mInnerIterator, mStartOuterContent, mEndOuterContent, mEndNode, mStartNode) nsresult nsFindContentIterator::Init(nsIDOMNode* aStartNode, int32_t aStartOffset, nsIDOMNode* aEndNode, int32_t aEndOffset) { + NS_ENSURE_ARG_POINTER(aStartNode); + NS_ENSURE_ARG_POINTER(aEndNode); if (!mOuterIterator) { if (mFindBackward) { // Use post-order in the reverse case, so we get parents // before children in case we want to prevent descending // into a node. mOuterIterator = do_CreateInstance(kCContentIteratorCID); } else { @@ -269,17 +271,20 @@ nsFindContentIterator::Reset() nsCOMPtr<nsIContent> endContent(do_QueryInterface(mEndNode)); if (endContent) { mEndOuterContent = endContent->FindFirstNonChromeOnlyAccessContent(); } // Note: OK to just set up the outer iterator here; if our range has a native // anonymous endpoint we'll end up setting up an inner iterator, and // reset the outer one in the process. - nsCOMPtr<nsIDOMRange> range = nsFind::CreateRange(); + nsCOMPtr<nsINode> node = do_QueryInterface(mStartNode); + NS_ENSURE_TRUE_VOID(node); + + nsCOMPtr<nsIDOMRange> range = nsFind::CreateRange(node); range->SetStart(mStartNode, mStartOffset); range->SetEnd(mEndNode, mEndOffset); mOuterIterator->Init(range); if (!mFindBackward) { if (mStartOuterContent != startContent) { // the start node was an anonymous text node SetupInnerIterator(mStartOuterContent); @@ -361,20 +366,19 @@ nsFindContentIterator::SetupInnerIterato // don't mess with disabled input fields uint32_t editorFlags = 0; editor->GetFlags(&editorFlags); if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask) return; nsCOMPtr<nsIDOMElement> rootElement; editor->GetRootElement(getter_AddRefs(rootElement)); - nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement)); - nsCOMPtr<nsIDOMRange> innerRange = nsFind::CreateRange(); - nsCOMPtr<nsIDOMRange> outerRange = nsFind::CreateRange(); + nsCOMPtr<nsIDOMRange> innerRange = nsFind::CreateRange(aContent); + nsCOMPtr<nsIDOMRange> outerRange = nsFind::CreateRange(aContent); if (!innerRange || !outerRange) { return; } // now create the inner-iterator mInnerIterator = do_CreateInstance(kCPreContentIteratorCID); if (mInnerIterator) { @@ -1136,17 +1140,17 @@ nsFind::Find(const PRUnichar *aPatText, { #ifdef DEBUG_FIND printf("Found a match!\n"); #endif // Make the range: nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent; - nsCOMPtr<nsIDOMRange> range = CreateRange(); + nsCOMPtr<nsIDOMRange> range = CreateRange(tc); if (range) { int32_t matchStartOffset, matchEndOffset; // convert char index to range point: int32_t mao = matchAnchorOffset + (mFindBackward ? 1 : 0); if (mFindBackward) { startParent = do_QueryInterface(tc); @@ -1250,14 +1254,14 @@ nsFind::Find(const PRUnichar *aPatText, // Out of nodes, and didn't match. ResetAll(); return NS_OK; } /* static */ already_AddRefed<nsIDOMRange> -nsFind::CreateRange() +nsFind::CreateRange(nsINode* aNode) { - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aNode); range->SetMaySpanAnonymousSubtrees(true); return range.forget(); }
--- a/embedding/components/find/src/nsFind.h +++ b/embedding/components/find/src/nsFind.h @@ -30,17 +30,17 @@ class nsFind : public nsIFind public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_NSIFIND NS_DECL_CYCLE_COLLECTION_CLASS(nsFind) nsFind(); virtual ~nsFind(); - static already_AddRefed<nsIDOMRange> CreateRange(); + static already_AddRefed<nsIDOMRange> CreateRange(nsINode* aNode); protected: // Parameters set from the interface: //nsCOMPtr<nsIDOMRange> mRange; // search only in this range bool mFindBackward; bool mCaseSensitive; nsCOMPtr<nsIWordBreaker> mWordBreaker;
--- a/embedding/components/find/src/nsWebBrowserFind.cpp +++ b/embedding/components/find/src/nsWebBrowserFind.cpp @@ -722,21 +722,21 @@ nsresult nsWebBrowserFind::SearchInFrame // Now make sure the content (for actual finding) and frame (for // selection) models are up to date. theDoc->FlushPendingNotifications(Flush_Frames); nsCOMPtr<nsISelection> sel; GetFrameSelection(aWindow, getter_AddRefs(sel)); NS_ENSURE_ARG_POINTER(sel); - nsCOMPtr<nsIDOMRange> searchRange = nsFind::CreateRange(); + nsCOMPtr<nsIDOMRange> searchRange = nsFind::CreateRange(theDoc); NS_ENSURE_ARG_POINTER(searchRange); - nsCOMPtr<nsIDOMRange> startPt = nsFind::CreateRange(); + nsCOMPtr<nsIDOMRange> startPt = nsFind::CreateRange(theDoc); NS_ENSURE_ARG_POINTER(startPt); - nsCOMPtr<nsIDOMRange> endPt = nsFind::CreateRange(); + nsCOMPtr<nsIDOMRange> endPt = nsFind::CreateRange(theDoc); NS_ENSURE_ARG_POINTER(endPt); nsCOMPtr<nsIDOMRange> foundRange; // If !aWrapping, search from selection to end if (!aWrapping) rv = GetSearchLimits(searchRange, startPt, endPt, domDoc, sel, false);
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -127,17 +127,20 @@ mozInlineSpellStatus::InitForEditorChang mOp = eOpChangeDelete; mRange = nullptr; return NS_OK; } mOp = eOpChange; // range to check - mRange = new nsRange(); + nsCOMPtr<nsINode> prevNode = do_QueryInterface(aPreviousNode); + NS_ENSURE_STATE(prevNode); + + mRange = new nsRange(prevNode); // ...we need to put the start and end in the correct order int16_t cmpResult; rv = mAnchorRange->ComparePoint(aPreviousNode, aPreviousOffset, &cmpResult); NS_ENSURE_SUCCESS(rv, rv); if (cmpResult < 0) { // previous anchor node is before the current anchor rv = mRange->SetStart(aPreviousNode, aPreviousOffset);
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp +++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp @@ -312,20 +312,21 @@ mozInlineSpellWordUtil::GetNextWord(nsAS // mozInlineSpellWordUtil::MakeRange // // Convenience function for creating a range over the current document. nsresult mozInlineSpellWordUtil::MakeRange(NodeOffset aBegin, NodeOffset aEnd, nsRange** aRange) { + NS_ENSURE_ARG_POINTER(aBegin.mNode); if (!mDOMDocument) return NS_ERROR_NOT_INITIALIZED; - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aBegin.mNode); nsresult rv = range->Set(aBegin.mNode, aBegin.mOffset, aEnd.mNode, aEnd.mOffset); NS_ENSURE_SUCCESS(rv, rv); range.forget(aRange); return NS_OK; }
--- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -2909,17 +2909,17 @@ PresShell::GoToAnchor(const nsAString& a // Should we select the target? This action is controlled by a // preference: the default is to not select. bool selectAnchor = Preferences::GetBool("layout.selectanchor"); // Even if select anchor pref is false, we must still move the // caret there. That way tabbing will start from the new // location - nsRefPtr<nsIDOMRange> jumpToRange = new nsRange(); + nsRefPtr<nsIDOMRange> jumpToRange = new nsRange(mDocument); while (content && content->GetFirstChild()) { content = content->GetFirstChild(); } nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content)); NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor"); jumpToRange->SelectNodeContents(node); // Select the anchor nsISelection* sel = mSelection-> @@ -4811,17 +4811,17 @@ PresShell::RenderNode(nsIDOMNode* aNode, nsRect area; nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems; // nothing to draw if the node isn't in a document nsCOMPtr<nsINode> node = do_QueryInterface(aNode); if (!node->IsInDoc()) return nullptr; - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(node); if (NS_FAILED(range->SelectNode(aNode))) return nullptr; RangePaintInfo* info = CreateRangePaintInfo(range, area, false); if (info && !rangeItems.AppendElement(info)) { delete info; return nullptr; }
--- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -773,17 +773,17 @@ nsTextControlFrame::SetSelectionInternal nsIDOMNode *aEndNode, int32_t aEndOffset, nsITextControlFrame::SelectionDirection aDirection) { // Create a new range to represent the new selection. // Note that we use a new range to avoid having to do // isIncreasing checks to avoid possible errors. - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(mContent); nsresult rv = range->SetStart(aStartNode, aStartOffset); NS_ENSURE_SUCCESS(rv, rv); rv = range->SetEnd(aEndNode, aEndOffset); NS_ENSURE_SUCCESS(rv, rv); // Get the selection, clear it and add the new range to it! nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
--- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -1461,17 +1461,17 @@ nsFrameSelection::TakeFocus(nsIContent * bool changes = mChangesDuringBatching; mBatching = 1; if (aMultipleSelection) { // Remove existing collapsed ranges as there's no point in having // non-anchor/focus collapsed ranges. mDomSelections[index]->RemoveCollapsedRanges(); - nsRefPtr<nsRange> newRange = new nsRange(); + nsRefPtr<nsRange> newRange = new nsRange(aNewFocus); newRange->SetStart(aNewFocus, aContentOffset); newRange->SetEnd(aNewFocus, aContentOffset); mDomSelections[index]->AddRange(newRange); mBatching = batching; mChangesDuringBatching = changes; } else @@ -2861,17 +2861,17 @@ Selection::GetTableSelectionType(nsIDOMR return NS_OK; } nsresult nsFrameSelection::CreateAndAddRange(nsINode *aParentNode, int32_t aOffset) { if (!aParentNode) return NS_ERROR_NULL_POINTER; - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aParentNode); // Set range around child at given offset nsresult result = range->SetStart(aParentNode, aOffset); if (NS_FAILED(result)) return result; result = range->SetEnd(aParentNode, aOffset+1); if (NS_FAILED(result)) return result; int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL); @@ -3271,17 +3271,17 @@ Selection::SubtractRange(RangeData* aRan // If the existing range left overlaps the new range (aSubtract) then // cmp < 0, and cmp2 < 0 // If it right overlaps the new range then cmp > 0 and cmp2 > 0 // If it fully contains the new range, then cmp < 0 and cmp2 > 0 if (cmp2 > 0) { // We need to add a new RangeData to the output, running from // the end of aSubtract to the end of range - nsRefPtr<nsRange> postOverlap = new nsRange(); + nsRefPtr<nsRange> postOverlap = new nsRange(aSubtract->GetEndParent()); rv = postOverlap->SetStart(aSubtract->GetEndParent(), aSubtract->EndOffset()); NS_ENSURE_SUCCESS(rv, rv); rv = postOverlap->SetEnd(range->GetEndParent(), range->EndOffset()); NS_ENSURE_SUCCESS(rv, rv); if (!postOverlap->Collapsed()) { @@ -3289,17 +3289,17 @@ Selection::SubtractRange(RangeData* aRan return NS_ERROR_OUT_OF_MEMORY; (*aOutput)[0].mTextRangeStyle = aRange->mTextRangeStyle; } } if (cmp < 0) { // We need to add a new RangeData to the output, running from // the start of the range to the start of aSubtract - nsRefPtr<nsRange> preOverlap = new nsRange(); + nsRefPtr<nsRange> preOverlap = new nsRange(range->GetStartParent()); nsresult rv = preOverlap->SetStart(range->GetStartParent(), range->StartOffset()); NS_ENSURE_SUCCESS(rv, rv); rv = preOverlap->SetEnd(aSubtract->GetStartParent(), aSubtract->StartOffset()); NS_ENSURE_SUCCESS(rv, rv); @@ -4393,17 +4393,17 @@ Selection::Collapse(nsINode* aParentNode nsresult result; // Delete all of the current ranges nsRefPtr<nsPresContext> presContext = GetPresContext(); Clear(presContext); // Turn off signal for table selection mFrameSelection->ClearTableCellSelection(); - nsRefPtr<nsRange> range = new nsRange(); + nsRefPtr<nsRange> range = new nsRange(aParentNode); result = range->SetEnd(aParentNode, aOffset); if (NS_FAILED(result)) return result; result = range->SetStart(aParentNode, aOffset); if (NS_FAILED(result)) return result; #ifdef DEBUG_SELECTION @@ -4649,17 +4649,17 @@ Selection::Extend(nsINode* aParentNode, aParentNode, aOffset, &disconnected); //compare anchor to new cursor int32_t result3 = nsContentUtils::ComparePoints(anchorNode, anchorOffset, aParentNode, aOffset, &disconnected); nsRefPtr<nsPresContext> presContext = GetPresContext(); - nsRefPtr<nsRange> difRange = new nsRange(); + nsRefPtr<nsRange> difRange = new nsRange(aParentNode); if ((result1 == 0 && result3 < 0) || (result1 <= 0 && result2 < 0)){//a1,2 a,1,2 //select from 1 to 2 unless they are collapsed res = range->SetEnd(aParentNode, aOffset); if (NS_FAILED(res)) return res; dir = eDirNext; res = difRange->SetEnd(range->GetEndParent(), range->EndOffset()); nsresult tmp = difRange->SetStart(focusNode, focusOffset);
--- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -2425,18 +2425,21 @@ CloneRangeToSelection(nsRange* aRange, n aRange->GetEndContainer(getter_AddRefs(endContainer)); int32_t endOffset = aRange->EndOffset(); NS_ENSURE_TRUE_VOID(startContainer && endContainer); nsCOMPtr<nsIDOMNode> newStart = GetEqualNodeInCloneTree(startContainer, aDoc); nsCOMPtr<nsIDOMNode> newEnd = GetEqualNodeInCloneTree(endContainer, aDoc); NS_ENSURE_TRUE_VOID(newStart && newEnd); - nsRefPtr<nsRange> range = new nsRange(); - nsresult rv = range->SetStart(newStart, startOffset); + nsCOMPtr<nsINode> newStartNode = do_QueryInterface(newStart); + NS_ENSURE_TRUE_VOID(newStartNode); + + nsRefPtr<nsRange> range = new nsRange(newStartNode); + nsresult rv = range->SetStart(newStartNode, startOffset); NS_ENSURE_SUCCESS_VOID(rv); rv = range->SetEnd(newEnd, endOffset); NS_ENSURE_SUCCESS_VOID(rv); aSelection->AddRange(range); } static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc)
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp +++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp @@ -89,19 +89,20 @@ nsTypeAheadFind::~nsTypeAheadFind() prefInternal->RemoveObserver("accessibility.browsewithcaret", this); } } nsresult nsTypeAheadFind::Init(nsIDocShell* aDocShell) { nsCOMPtr<nsIPrefBranch> prefInternal(do_GetService(NS_PREFSERVICE_CONTRACTID)); - mSearchRange = new nsRange(); - mStartPointRange = new nsRange(); - mEndPointRange = new nsRange(); + + mSearchRange = nullptr; + mStartPointRange = nullptr; + mEndPointRange = nullptr; if (!prefInternal || !EnsureFind()) return NS_ERROR_FAILURE; SetDocShell(aDocShell); // ----------- Listen to prefs ------------------ nsresult rv = prefInternal->AddObserver("accessibility.browsewithcaret", this, true); NS_ENSURE_SUCCESS(rv, rv); @@ -161,22 +162,22 @@ nsTypeAheadFind::SetDocShell(nsIDocShell { mDocShell = do_GetWeakReference(aDocShell); mWebBrowserFind = do_GetInterface(aDocShell); NS_ENSURE_TRUE(mWebBrowserFind, NS_ERROR_FAILURE); nsCOMPtr<nsIPresShell> presShell; presShell = aDocShell->GetPresShell(); - mPresShell = do_GetWeakReference(presShell); + mPresShell = do_GetWeakReference(presShell); mStartFindRange = nullptr; - mStartPointRange = new nsRange(); - mSearchRange = new nsRange(); - mEndPointRange = new nsRange(); + mStartPointRange = nullptr; + mSearchRange = nullptr; + mEndPointRange = nullptr; mFoundLink = nullptr; mFoundEditable = nullptr; mCurrentWindow = nullptr; mSelectionController = nullptr; mFind = nullptr; @@ -356,16 +357,20 @@ nsTypeAheadFind::FindItNow(nsIPresShell selectionController.get() : nullptr, aIsFirstVisiblePreferred, aFindPrev, getter_AddRefs(presShell), getter_AddRefs(presContext)))) { return NS_ERROR_FAILURE; } int16_t rangeCompareResult = 0; + if (!mStartPointRange) { + mStartPointRange = new nsRange(presShell->GetDocument()); + } + mStartPointRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, mSearchRange, &rangeCompareResult); // No need to wrap find in doc if starting at beginning bool hasWrapped = (rangeCompareResult < 0); if (mTypeAheadBuffer.IsEmpty() || !EnsureFind()) return NS_ERROR_FAILURE; mFind->SetFindBackwards(aFindPrev); @@ -616,16 +621,20 @@ nsTypeAheadFind::FindItNow(nsIPresShell continue; } if (aFindPrev) { // Reverse mode: swap start and end points, so that we start // at end of document and go to beginning nsCOMPtr<nsIDOMRange> tempRange; mStartPointRange->CloneRange(getter_AddRefs(tempRange)); + if (!mEndPointRange) { + mEndPointRange = new nsRange(presShell->GetDocument()); + } + mStartPointRange = mEndPointRange; mEndPointRange = tempRange; } continue; } // ------------- Failed -------------- @@ -714,16 +723,24 @@ nsTypeAheadFind::GetSearchContainers(nsI nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootContent)); if (!rootNode) return NS_ERROR_FAILURE; uint32_t childCount = rootContent->GetChildCount(); + if (!mSearchRange) { + mSearchRange = new nsRange(rootContent); + } + + if (!mEndPointRange) { + mEndPointRange = new nsRange(rootContent); + } + mSearchRange->SelectNodeContents(rootNode); mEndPointRange->SetEnd(rootNode, childCount); mEndPointRange->Collapse(false); // collapse to end // Consider current selection as null if // it's not in the currently focused document nsCOMPtr<nsIDOMRange> currentSelectionRange; @@ -731,16 +748,20 @@ nsTypeAheadFind::GetSearchContainers(nsI if (aSelectionController && selectionPresShell && selectionPresShell == presShell) { nsCOMPtr<nsISelection> selection; aSelectionController->GetSelection( nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); if (selection) selection->GetRangeAt(0, getter_AddRefs(currentSelectionRange)); } + if (!mStartPointRange) { + mStartPointRange = new nsRange(doc); + } + if (!currentSelectionRange) { // Ensure visible range, move forward if necessary // This uses ignores the return value, but usese the side effect of // IsRangeVisible. It returns the first visible range after searchRange IsRangeVisible(presShell, presContext, mSearchRange, aIsFirstVisiblePreferred, true, getter_AddRefs(mStartPointRange), nullptr); }