diff --git a/editor/libeditor/nsHTMLEditRules.cpp b/editor/libeditor/nsHTMLEditRules.cpp index 9fd0e90743b3..f05e522f5822 100644 --- a/editor/libeditor/nsHTMLEditRules.cpp +++ b/editor/libeditor/nsHTMLEditRules.cpp @@ -841,11 +841,11 @@ nsHTMLEditRules::GetAlignment(bool *aMixed, nsIHTMLEditor::EAlignment *aAlign) NS_ENSURE_SUCCESS(res, res); // use these ranges to construct a list of nodes to act on. - nsCOMArray arrayOfNodes; + nsTArray> arrayOfNodes; res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, - EditAction::align, true); + EditAction::align, TouchContent::no); NS_ENSURE_SUCCESS(res, res); - nodeToExamine = arrayOfNodes.SafeObjectAt(0); + nodeToExamine = GetAsDOMNode(arrayOfNodes.SafeElementAt(0)); } NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER); @@ -3870,10 +3870,15 @@ nsHTMLEditRules::WillHTMLIndent(Selection* aSelection, NS_ENSURE_SUCCESS(res, res); // use these ranges to contruct a list of nodes to act on. - nsCOMArray arrayOfNodes; - res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, EditAction::indent); + nsTArray> array; + res = GetNodesForOperation(arrayOfRanges, array, EditAction::indent); NS_ENSURE_SUCCESS(res, res); + nsCOMArray arrayOfNodes; + for (auto& node : array) { + arrayOfNodes.AppendObject(GetAsDOMNode(node)); + } + // if nothing visible in list, make an empty block if (ListIsEmptyLine(arrayOfNodes)) { @@ -5859,184 +5864,153 @@ nsHTMLEditRules::PromoteRange(nsRange* inRange, EditAction inOperationType) return res; } +class NodeComparator +{ + public: + bool Equals(const nsINode* node, const nsIDOMNode* domNode) const + { + return domNode == GetAsDOMNode(const_cast(node)); + } +}; + class nsUniqueFunctor : public nsBoolDomIterFunctor { public: - explicit nsUniqueFunctor(nsCOMArray &aArray) : mArray(aArray) + explicit nsUniqueFunctor(nsTArray> &aArray) : mArray(aArray) { } // used to build list of all nodes iterator covers virtual bool operator()(nsIDOMNode* aNode) const { - return mArray.IndexOf(aNode) < 0; + return !mArray.Contains(aNode, NodeComparator()); } private: - nsCOMArray &mArray; + nsTArray>& mArray; }; -/////////////////////////////////////////////////////////////////////////// -// GetNodesForOperation: run through the ranges in the array and construct -// a new array of nodes to be acted on. -// -nsresult -nsHTMLEditRules::GetNodesForOperation(nsTArray>& inArrayOfRanges, - nsCOMArray& outArrayOfNodes, - EditAction inOperationType, - bool aDontTouchContent) +/////////////////////////////////////////////////////////////////////////////// +// GetNodesForOperation: Run through the ranges in the array and construct a +// new array of nodes to be acted on. +// +nsresult +nsHTMLEditRules::GetNodesForOperation(nsTArray>& aArrayOfRanges, + nsTArray>& aOutArrayOfNodes, + EditAction aOperationType, + TouchContent aTouchContent) { - int32_t rangeCount = inArrayOfRanges.Length(); - - int32_t i; - nsRefPtr opRange; + NS_ENSURE_STATE(mHTMLEditor); + nsCOMPtr kungFuDeathGrip(mHTMLEditor); - nsresult res = NS_OK; - - // bust up any inlines that cross our range endpoints, - // but only if we are allowed to touch content. - - if (!aDontTouchContent) - { + int32_t rangeCount = aArrayOfRanges.Length(); + nsresult res; + + // Bust up any inlines that cross our range endpoints, but only if we are + // allowed to touch content. + + if (aTouchContent == TouchContent::yes) { nsTArray> rangeItemArray; rangeItemArray.AppendElements(rangeCount); - NS_ASSERTION(static_cast(rangeCount) == rangeItemArray.Length(), - "How did that happen?"); - - // first register ranges for special editor gravity - for (i = 0; i < rangeCount; i++) - { - opRange = inArrayOfRanges[0]; + // First register ranges for special editor gravity + for (int32_t i = 0; i < rangeCount; i++) { rangeItemArray[i] = new nsRangeStore(); - rangeItemArray[i]->StoreRange(opRange); - NS_ENSURE_STATE(mHTMLEditor); + rangeItemArray[i]->StoreRange(aArrayOfRanges[0]); mHTMLEditor->mRangeUpdater.RegisterRangeItem(rangeItemArray[i]); - inArrayOfRanges.RemoveElementAt(0); - } - // now bust up inlines. Safe to start at rangeCount-1, since we - // asserted we have enough items above. - for (i = rangeCount-1; i >= 0 && NS_SUCCEEDED(res); i--) - { - res = BustUpInlinesAtRangeEndpoints(*rangeItemArray[i]); - } - // then unregister the ranges - for (i = 0; i < rangeCount; i++) - { - nsRangeStore* item = rangeItemArray[i]; - NS_ENSURE_STATE(mHTMLEditor); + aArrayOfRanges.RemoveElementAt(0); + } + // Now bust up inlines. + for (auto& item : Reversed(rangeItemArray)) { + res = BustUpInlinesAtRangeEndpoints(*item); + if (NS_FAILED(res)) { + break; + } + } + // Then unregister the ranges + for (auto& item : rangeItemArray) { mHTMLEditor->mRangeUpdater.DropRangeItem(item); - opRange = item->GetRange(); - inArrayOfRanges.AppendElement(opRange); + aArrayOfRanges.AppendElement(item->GetRange()); } NS_ENSURE_SUCCESS(res, res); } - // gather up a list of all the nodes - for (i = 0; i < rangeCount; i++) - { - opRange = inArrayOfRanges[i]; - - nsDOMSubtreeIterator iter(*opRange); - if (outArrayOfNodes.Count() == 0) { - nsTrivialFunctor functor; - iter.AppendList(functor, outArrayOfNodes); - } - else { - // We don't want duplicates in outArrayOfNodes, so we use an + // Gather up a list of all the nodes + for (auto& range : aArrayOfRanges) { + nsDOMSubtreeIterator iter(*range); + if (aOutArrayOfNodes.Length() == 0) { + iter.AppendList(nsTrivialFunctor(), aOutArrayOfNodes); + } else { + // We don't want duplicates in aOutArrayOfNodes, so we use an // iterator/functor that only return nodes that are not already in - // outArrayOfNodes. - nsCOMArray nodes; - nsUniqueFunctor functor(outArrayOfNodes); - iter.AppendList(functor, nodes); - if (!outArrayOfNodes.AppendObjects(nodes)) - return NS_ERROR_OUT_OF_MEMORY; + // aOutArrayOfNodes. + nsTArray> nodes; + iter.AppendList(nsUniqueFunctor(aOutArrayOfNodes), nodes); + aOutArrayOfNodes.AppendElements(nodes); } - } + } - // certain operations should not act on li's and td's, but rather inside - // them. alter the list as needed - if (inOperationType == EditAction::makeBasicBlock) { - int32_t listCount = outArrayOfNodes.Count(); - for (i=listCount-1; i>=0; i--) - { - nsCOMPtr node = outArrayOfNodes[i]; - if (nsHTMLEditUtils::IsListItem(node)) - { - int32_t j=i; - outArrayOfNodes.RemoveObjectAt(i); - res = GetInnerContent(node, outArrayOfNodes, &j); - NS_ENSURE_SUCCESS(res, res); + // Certain operations should not act on li's and td's, but rather inside + // them. Alter the list as needed. + if (aOperationType == EditAction::makeBasicBlock) { + for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) { + nsCOMPtr node = aOutArrayOfNodes[i]; + if (nsHTMLEditUtils::IsListItem(node)) { + int32_t j = i; + aOutArrayOfNodes.RemoveElementAt(i); + GetInnerContent(*node, aOutArrayOfNodes, &j); + } + } + // Indent/outdent already do something special for list items, but we still + // need to make sure we don't act on table elements + } else if (aOperationType == EditAction::outdent || + aOperationType == EditAction::indent || + aOperationType == EditAction::setAbsolutePosition) { + for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) { + nsCOMPtr node = aOutArrayOfNodes[i]; + if (nsHTMLEditUtils::IsTableElementButNotTable(node)) { + int32_t j = i; + aOutArrayOfNodes.RemoveElementAt(i); + GetInnerContent(*node, aOutArrayOfNodes, &j); } } } - // indent/outdent already do something special for list items, but - // we still need to make sure we don't act on table elements - else if (inOperationType == EditAction::outdent || - inOperationType == EditAction::indent || - inOperationType == EditAction::setAbsolutePosition) { - int32_t listCount = outArrayOfNodes.Count(); - for (i=listCount-1; i>=0; i--) - { - nsCOMPtr node = outArrayOfNodes[i]; - if (nsHTMLEditUtils::IsTableElementButNotTable(node)) - { - int32_t j=i; - outArrayOfNodes.RemoveObjectAt(i); - res = GetInnerContent(node, outArrayOfNodes, &j); - NS_ENSURE_SUCCESS(res, res); - } - } - } - // outdent should look inside of divs. - if (inOperationType == EditAction::outdent && - (!mHTMLEditor || !mHTMLEditor->IsCSSEnabled())) { - NS_ENSURE_STATE(mHTMLEditor); - int32_t listCount = outArrayOfNodes.Count(); - for (i=listCount-1; i>=0; i--) - { - nsCOMPtr node = outArrayOfNodes[i]; - if (nsHTMLEditUtils::IsDiv(node)) - { - int32_t j=i; - outArrayOfNodes.RemoveObjectAt(i); - res = GetInnerContent(node, outArrayOfNodes, &j, false, false); - NS_ENSURE_SUCCESS(res, res); + // Outdent should look inside of divs. + if (aOperationType == EditAction::outdent && + !mHTMLEditor->IsCSSEnabled()) { + for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) { + nsCOMPtr node = aOutArrayOfNodes[i]; + if (node->IsHTMLElement(nsGkAtoms::div)) { + int32_t j = i; + aOutArrayOfNodes.RemoveElementAt(i); + GetInnerContent(*node, aOutArrayOfNodes, &j, Lists::no, Tables::no); } } } - // post process the list to break up inline containers that contain br's. - // but only for operations that might care, like making lists or para's... - if (inOperationType == EditAction::makeBasicBlock || - inOperationType == EditAction::makeList || - inOperationType == EditAction::align || - inOperationType == EditAction::setAbsolutePosition || - inOperationType == EditAction::indent || - inOperationType == EditAction::outdent) { - int32_t listCount = outArrayOfNodes.Count(); - for (i=listCount-1; i>=0; i--) - { - nsCOMPtr node = do_QueryInterface(outArrayOfNodes[i]); - NS_ENSURE_STATE(node); - if (!aDontTouchContent && IsInlineNode(GetAsDOMNode(node)) && - (!mHTMLEditor || mHTMLEditor->IsContainer(node)) && - (!mHTMLEditor || !mHTMLEditor->IsTextNode(node))) - { - NS_ENSURE_STATE(mHTMLEditor); + // Post-process the list to break up inline containers that contain br's, but + // only for operations that might care, like making lists or paragraphs + if (aOperationType == EditAction::makeBasicBlock || + aOperationType == EditAction::makeList || + aOperationType == EditAction::align || + aOperationType == EditAction::setAbsolutePosition || + aOperationType == EditAction::indent || + aOperationType == EditAction::outdent) { + for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) { + nsCOMPtr node = aOutArrayOfNodes[i]; + if (aTouchContent == TouchContent::yes && + IsInlineNode(GetAsDOMNode(node)) && mHTMLEditor->IsContainer(node) && + !mHTMLEditor->IsTextNode(node)) { nsTArray> arrayOfInlines; res = BustUpInlinesAtBRs(*node, arrayOfInlines); NS_ENSURE_SUCCESS(res, res); - nsCOMArray arrayOfInlinesDOM; - for (auto& inlineNode : arrayOfInlines) { - arrayOfInlinesDOM.AppendObject(GetAsDOMNode(inlineNode)); - } - // put these nodes in outArrayOfNodes, replacing the current node - outArrayOfNodes.RemoveObjectAt(i); - outArrayOfNodes.InsertObjectsAt(arrayOfInlinesDOM, i); + + // Put these nodes in aOutArrayOfNodes, replacing the current node + aOutArrayOfNodes.RemoveElementAt(i); + aOutArrayOfNodes.InsertElementsAt(i, arrayOfInlines); } } } - return res; + return NS_OK; } @@ -6433,7 +6407,12 @@ nsHTMLEditRules::GetNodesFromPoint(::DOMPoint point, arrayOfRanges.AppendElement(range); // use these ranges to contruct a list of nodes to act on. - res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent); + nsTArray> array; + res = GetNodesForOperation(arrayOfRanges, array, operation, dontTouchContent + ? TouchContent::no : TouchContent::yes); + for (auto& node : array) { + arrayOfNodes.AppendObject(GetAsDOMNode(node)); + } return res; } @@ -6457,7 +6436,12 @@ nsHTMLEditRules::GetNodesFromSelection(Selection* selection, NS_ENSURE_SUCCESS(res, res); // use these ranges to contruct a list of nodes to act on. - res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, operation, dontTouchContent); + nsTArray> array; + res = GetNodesForOperation(arrayOfRanges, array, operation, dontTouchContent + ? TouchContent::no : TouchContent::yes); + for (auto& node : array) { + arrayOfNodes.AppendObject(GetAsDOMNode(node)); + } return res; } @@ -9079,11 +9063,15 @@ nsHTMLEditRules::WillAbsolutePosition(Selection* aSelection, NS_ENSURE_SUCCESS(res, res); // use these ranges to contruct a list of nodes to act on. - nsCOMArray arrayOfNodes; - res = GetNodesForOperation(arrayOfRanges, arrayOfNodes, + nsTArray> array; + res = GetNodesForOperation(arrayOfRanges, array, EditAction::setAbsolutePosition); NS_ENSURE_SUCCESS(res, res); + nsCOMArray arrayOfNodes; + for (auto& node : array) { + arrayOfNodes.AppendObject(GetAsDOMNode(node)); + } // if nothing visible in list, make an empty block if (ListIsEmptyLine(arrayOfNodes)) { diff --git a/editor/libeditor/nsHTMLEditRules.h b/editor/libeditor/nsHTMLEditRules.h index e4d030a64845..b589c3d28d7d 100644 --- a/editor/libeditor/nsHTMLEditRules.h +++ b/editor/libeditor/nsHTMLEditRules.h @@ -276,10 +276,11 @@ protected: nsTArray>& outArrayOfRanges, EditAction inOperationType); nsresult PromoteRange(nsRange* inRange, EditAction inOperationType); - nsresult GetNodesForOperation(nsTArray>& inArrayOfRanges, - nsCOMArray& outArrayOfNodes, - EditAction inOperationType, - bool aDontTouchContent=false); + enum class TouchContent { no, yes }; + nsresult GetNodesForOperation(nsTArray>& aArrayOfRanges, + nsTArray>& aOutArrayOfNodes, + EditAction aOperationType, + TouchContent aTouchContent = TouchContent::yes); nsresult GetChildNodesForOperation(nsIDOMNode *inNode, nsCOMArray& outArrayOfNodes); nsresult GetNodesFromPoint(::DOMPoint point,