Bug 751323 - Cleanup nsHTMLEditRules::RemoveEmptyNodes(); r=ehsan

This commit is contained in:
Ms2ger 2012-05-05 11:00:06 +02:00
parent 6490825be5
commit 9f3641f0f6
5 changed files with 84 additions and 89 deletions

View File

@ -71,6 +71,7 @@ GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node")
GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before") GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before")
GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after") GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after")
GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image") GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image")
GK_ATOM(mozquote, "_moz_quote")
GK_ATOM(_moz_original_size, "_moz_original_size") GK_ATOM(_moz_original_size, "_moz_original_size")
GK_ATOM(_moz_target, "_moz_target") GK_ATOM(_moz_target, "_moz_target")
GK_ATOM(_moz_type, "_moz-type") GK_ATOM(_moz_type, "_moz-type")

View File

@ -7932,10 +7932,6 @@ nsHTMLEditRules::InDifferentTableElements(nsIDOMNode *aNode1, nsIDOMNode *aNode2
nsresult nsresult
nsHTMLEditRules::RemoveEmptyNodes() nsHTMLEditRules::RemoveEmptyNodes()
{ {
nsCOMArray<nsIDOMNode> arrayOfEmptyNodes, arrayOfEmptyCites;
nsCOMPtr<nsISupports> isupports;
PRInt32 nodeCount,j;
// some general notes on the algorithm used here: the goal is to examine all the // some general notes on the algorithm used here: the goal is to examine all the
// nodes in mDocChangeRange, and remove the empty ones. We do this by using a // nodes in mDocChangeRange, and remove the empty ones. We do this by using a
// content iterator to traverse all the nodes in the range, and placing the empty // content iterator to traverse all the nodes in the range, and placing the empty
@ -7966,48 +7962,41 @@ nsHTMLEditRules::RemoveEmptyNodes()
nsresult res = iter->Init(mDocChangeRange); nsresult res = iter->Init(mDocChangeRange);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
nsTArray<nsIDOMNode*> skipList; nsCOMArray<nsINode> arrayOfEmptyNodes, arrayOfEmptyCites;
nsTArray<nsINode*> skipList;
// check for empty nodes // check for empty nodes
while (!iter->IsDone()) while (!iter->IsDone()) {
{ nsINode* node = iter->GetCurrentNode();
nsCOMPtr<nsIDOMNode> node, parent;
node = do_QueryInterface(iter->GetCurrentNode());
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
node->GetParentNode(getter_AddRefs(parent)); nsINode* parent = node->GetNodeParent();
PRUint32 idx = skipList.IndexOf(node); PRUint32 idx = skipList.IndexOf(node);
if (idx != skipList.NoIndex) if (idx != skipList.NoIndex) {
{
// this node is on our skip list. Skip processing for this node, // this node is on our skip list. Skip processing for this node,
// and replace its value in the skip list with the value of its parent // and replace its value in the skip list with the value of its parent
skipList[idx] = parent; skipList[idx] = parent;
} } else {
else
{
bool bIsCandidate = false; bool bIsCandidate = false;
bool bIsEmptyNode = false; bool bIsEmptyNode = false;
bool bIsMailCite = false; bool bIsMailCite = false;
if (node->IsElement()) {
dom::Element* element = node->AsElement();
if (element->IsHTML(nsGkAtoms::body)) {
// don't delete the body // don't delete the body
if (!nsTextEditUtils::IsBody(node)) } else if ((bIsMailCite = nsHTMLEditUtils::IsMailCite(element)) ||
{ element->IsHTML(nsGkAtoms::a) ||
nsHTMLEditUtils::IsInlineStyle(element) ||
nsHTMLEditUtils::IsList(element) ||
element->IsHTML(nsGkAtoms::div)) {
// only consider certain nodes to be empty for purposes of removal // only consider certain nodes to be empty for purposes of removal
if ( (bIsMailCite = nsHTMLEditUtils::IsMailCite(node)) ||
nsEditor::NodeIsType(node, nsEditProperty::a) ||
nsHTMLEditUtils::IsInlineStyle(node) ||
nsHTMLEditUtils::IsList(node) ||
nsHTMLEditUtils::IsDiv(node) )
{
bIsCandidate = true; bIsCandidate = true;
} } else if (nsHTMLEditUtils::IsFormatNode(element) ||
nsHTMLEditUtils::IsListItem(element) ||
element->IsHTML(nsGkAtoms::blockquote)) {
// these node types are candidates if selection is not in them // these node types are candidates if selection is not in them
else if (nsHTMLEditUtils::IsFormatNode(node) ||
nsHTMLEditUtils::IsListItem(node) ||
nsHTMLEditUtils::IsBlockquote(node) )
{
// if it is one of these, don't delete if selection inside. // if it is one of these, don't delete if selection inside.
// this is so we can create empty headings, etc, for the // this is so we can create empty headings, etc, for the
// user to type into. // user to type into.
@ -8021,28 +8010,23 @@ nsHTMLEditRules::RemoveEmptyNodes()
} }
} }
if (bIsCandidate) if (bIsCandidate) {
{ // we delete mailcites even if they have a solo br in them
if (bIsMailCite) // we delete mailcites even if they have a solo br in them // other nodes we require to be empty
res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, true, true); res = mHTMLEditor->IsEmptyNode(node->AsDOMNode(), &bIsEmptyNode,
else // other nodes we require to be empty bIsMailCite, true);
res = mHTMLEditor->IsEmptyNode(node, &bIsEmptyNode, false, true);
NS_ENSURE_SUCCESS(res, res); NS_ENSURE_SUCCESS(res, res);
if (bIsEmptyNode) if (bIsEmptyNode) {
{ if (bIsMailCite) {
if (bIsMailCite) // mailcites go on a separate list from other empty nodes // mailcites go on a separate list from other empty nodes
{
arrayOfEmptyCites.AppendObject(node); arrayOfEmptyCites.AppendObject(node);
} } else {
else
{
arrayOfEmptyNodes.AppendObject(node); arrayOfEmptyNodes.AppendObject(node);
} }
} }
} }
if (!bIsEmptyNode) if (!bIsEmptyNode) {
{
// put parent on skip list // put parent on skip list
skipList.AppendElement(parent); skipList.AppendElement(parent);
} }
@ -8052,10 +8036,9 @@ nsHTMLEditRules::RemoveEmptyNodes()
} }
// now delete the empty nodes // now delete the empty nodes
nodeCount = arrayOfEmptyNodes.Count(); PRInt32 nodeCount = arrayOfEmptyNodes.Count();
for (j = 0; j < nodeCount; j++) for (PRInt32 j = 0; j < nodeCount; j++) {
{ nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyNodes[0]->AsDOMNode();
nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyNodes[0];
arrayOfEmptyNodes.RemoveObjectAt(0); arrayOfEmptyNodes.RemoveObjectAt(0);
if (mHTMLEditor->IsModifiableNode(delNode)) { if (mHTMLEditor->IsModifiableNode(delNode)) {
res = mHTMLEditor->DeleteNode(delNode); res = mHTMLEditor->DeleteNode(delNode);
@ -8066,9 +8049,8 @@ nsHTMLEditRules::RemoveEmptyNodes()
// now delete the empty mailcites // now delete the empty mailcites
// this is a separate step because we want to pull out any br's and preserve them. // this is a separate step because we want to pull out any br's and preserve them.
nodeCount = arrayOfEmptyCites.Count(); nodeCount = arrayOfEmptyCites.Count();
for (j = 0; j < nodeCount; j++) for (PRInt32 j = 0; j < nodeCount; j++) {
{ nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyCites[0]->AsDOMNode();
nsCOMPtr<nsIDOMNode> delNode = arrayOfEmptyCites[0];
arrayOfEmptyCites.RemoveObjectAt(0); arrayOfEmptyCites.RemoveObjectAt(0);
bool bIsEmptyNode; bool bIsEmptyNode;
res = mHTMLEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true); res = mHTMLEditor->IsEmptyNode(delNode, &bIsEmptyNode, false, true);
@ -8092,10 +8074,12 @@ nsHTMLEditRules::RemoveEmptyNodes()
} }
nsresult nsresult
nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, bool *aResult) nsHTMLEditRules::SelectionEndpointInNode(nsINode* aNode, bool* aResult)
{ {
NS_ENSURE_TRUE(aNode && aResult, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(aNode && aResult, NS_ERROR_NULL_POINTER);
nsIDOMNode* node = aNode->AsDOMNode();
*aResult = false; *aResult = false;
nsCOMPtr<nsISelection>selection; nsCOMPtr<nsISelection>selection;
@ -8120,13 +8104,11 @@ nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, bool *aResult)
range->GetStartContainer(getter_AddRefs(startParent)); range->GetStartContainer(getter_AddRefs(startParent));
if (startParent) if (startParent)
{ {
if (aNode == startParent) if (node == startParent) {
{
*aResult = true; *aResult = true;
return NS_OK; return NS_OK;
} }
if (nsEditorUtils::IsDescendantOf(startParent, aNode)) if (nsEditorUtils::IsDescendantOf(startParent, node)) {
{
*aResult = true; *aResult = true;
return NS_OK; return NS_OK;
} }
@ -8135,13 +8117,11 @@ nsHTMLEditRules::SelectionEndpointInNode(nsIDOMNode *aNode, bool *aResult)
if (startParent == endParent) continue; if (startParent == endParent) continue;
if (endParent) if (endParent)
{ {
if (aNode == endParent) if (node == endParent) {
{
*aResult = true; *aResult = true;
return NS_OK; return NS_OK;
} }
if (nsEditorUtils::IsDescendantOf(endParent, aNode)) if (nsEditorUtils::IsDescendantOf(endParent, node)) {
{
*aResult = true; *aResult = true;
return NS_OK; return NS_OK;
} }

View File

@ -290,7 +290,7 @@ protected:
nsCOMPtr<nsIDOMNode> *outSelectableNode); nsCOMPtr<nsIDOMNode> *outSelectableNode);
nsresult InDifferentTableElements(nsIDOMNode *aNode1, nsIDOMNode *aNode2, bool *aResult); nsresult InDifferentTableElements(nsIDOMNode *aNode1, nsIDOMNode *aNode2, bool *aResult);
nsresult RemoveEmptyNodes(); nsresult RemoveEmptyNodes();
nsresult SelectionEndpointInNode(nsIDOMNode *aNode, bool *aResult); nsresult SelectionEndpointInNode(nsINode *aNode, bool *aResult);
nsresult UpdateDocChangeRange(nsIDOMRange *aRange); nsresult UpdateDocChangeRange(nsIDOMRange *aRange);
nsresult ConfirmSelectionInBody(); nsresult ConfirmSelectionInBody();
nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode); nsresult InsertMozBRIfNeeded(nsIDOMNode *aNode);

View File

@ -72,7 +72,15 @@ bool
nsHTMLEditUtils::IsInlineStyle(nsIDOMNode *node) nsHTMLEditUtils::IsInlineStyle(nsIDOMNode *node)
{ {
NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsInlineStyle"); NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsInlineStyle");
nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(node); nsCOMPtr<dom::Element> element = do_QueryInterface(node);
return element && IsInlineStyle(element);
}
bool
nsHTMLEditUtils::IsInlineStyle(dom::Element* aElement)
{
MOZ_ASSERT(aElement);
nsIAtom* nodeAtom = aElement->Tag();
return (nodeAtom == nsEditProperty::b) return (nodeAtom == nsEditProperty::b)
|| (nodeAtom == nsEditProperty::i) || (nodeAtom == nsEditProperty::i)
|| (nodeAtom == nsEditProperty::u) || (nodeAtom == nsEditProperty::u)
@ -94,7 +102,15 @@ bool
nsHTMLEditUtils::IsFormatNode(nsIDOMNode *node) nsHTMLEditUtils::IsFormatNode(nsIDOMNode *node)
{ {
NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsFormatNode"); NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsFormatNode");
nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(node); nsCOMPtr<dom::Element> element = do_QueryInterface(node);
return element && IsFormatNode(element);
}
bool
nsHTMLEditUtils::IsFormatNode(dom::Element* aElement)
{
MOZ_ASSERT(aElement);
nsIAtom* nodeAtom = aElement->Tag();
return (nodeAtom == nsEditProperty::p) return (nodeAtom == nsEditProperty::p)
|| (nodeAtom == nsEditProperty::pre) || (nodeAtom == nsEditProperty::pre)
|| (nodeAtom == nsEditProperty::h1) || (nodeAtom == nsEditProperty::h1)
@ -424,32 +440,27 @@ nsHTMLEditUtils::IsMozDiv(nsIDOMNode *node)
// IsMailCite: true if node an html blockquote with type=cite // IsMailCite: true if node an html blockquote with type=cite
// //
bool bool
nsHTMLEditUtils::IsMailCite(nsIDOMNode *node) nsHTMLEditUtils::IsMailCite(nsIDOMNode* aNode)
{ {
NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsMailCite"); NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsMailCite");
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(node); nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
if (!elem) { return element && IsMailCite(element);
return false;
} }
nsAutoString attrName (NS_LITERAL_STRING("type"));
bool
nsHTMLEditUtils::IsMailCite(dom::Element* aElement)
{
MOZ_ASSERT(aElement);
// don't ask me why, but our html mailcites are id'd by "type=cite"... // don't ask me why, but our html mailcites are id'd by "type=cite"...
nsAutoString attrVal; if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsresult res = elem->GetAttribute(attrName, attrVal); NS_LITERAL_STRING("cite"), eIgnoreCase)) {
ToLowerCase(attrVal);
if (NS_SUCCEEDED(res))
{
if (attrVal.EqualsLiteral("cite"))
return true; return true;
} }
// ... but our plaintext mailcites by "_moz_quote=true". go figure. // ... but our plaintext mailcites by "_moz_quote=true". go figure.
attrName.AssignLiteral("_moz_quote"); if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozquote,
res = elem->GetAttribute(attrName, attrVal); NS_LITERAL_STRING("true"), eIgnoreCase)) {
if (NS_SUCCEEDED(res))
{
ToLowerCase(attrVal);
if (attrVal.EqualsLiteral("true"))
return true; return true;
} }

View File

@ -56,7 +56,9 @@ public:
static bool IsSmall(nsIDOMNode *aNode); static bool IsSmall(nsIDOMNode *aNode);
// from nsHTMLEditRules: // from nsHTMLEditRules:
static bool IsInlineStyle(mozilla::dom::Element* aNode);
static bool IsInlineStyle(nsIDOMNode *aNode); static bool IsInlineStyle(nsIDOMNode *aNode);
static bool IsFormatNode(mozilla::dom::Element* aNode);
static bool IsFormatNode(nsIDOMNode *aNode); static bool IsFormatNode(nsIDOMNode *aNode);
static bool IsNodeThatCanOutdent(nsIDOMNode *aNode); static bool IsNodeThatCanOutdent(nsIDOMNode *aNode);
static bool IsHeader(nsIDOMNode *aNode); static bool IsHeader(nsIDOMNode *aNode);
@ -85,6 +87,7 @@ public:
static bool IsNamedAnchor(nsIDOMNode *aNode); static bool IsNamedAnchor(nsIDOMNode *aNode);
static bool IsDiv(nsIDOMNode *aNode); static bool IsDiv(nsIDOMNode *aNode);
static bool IsMozDiv(nsIDOMNode *aNode); static bool IsMozDiv(nsIDOMNode *aNode);
static bool IsMailCite(mozilla::dom::Element* aNode);
static bool IsMailCite(nsIDOMNode *aNode); static bool IsMailCite(nsIDOMNode *aNode);
static bool IsFormWidget(mozilla::dom::Element* aNode); static bool IsFormWidget(mozilla::dom::Element* aNode);
static bool IsFormWidget(nsIDOMNode *aNode); static bool IsFormWidget(nsIDOMNode *aNode);