diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp index 10782cfbda3..d1811d1615c 100644 --- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -2942,10 +2942,10 @@ nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection, res = GetTopEnclosingMailCite(startNode, address_of(citeNode), IsPlaintextEditor()); NS_ENSURE_SUCCESS(res, res); - if (citeNode) - { + if (citeNode) { + nsCOMPtr cite = do_QueryInterface(citeNode); bool isEmpty = true, seenBR = false; - mHTMLEditor->IsEmptyNodeImpl(citeNode, &isEmpty, true, true, false, &seenBR); + mHTMLEditor->IsEmptyNodeImpl(cite, &isEmpty, true, true, false, &seenBR); if (isEmpty) { nsCOMPtr parent, brNode; diff --git a/editor/libeditor/html/nsHTMLEditUtils.cpp b/editor/libeditor/html/nsHTMLEditUtils.cpp index 45fb5dc14b4..da636ffbb56 100644 --- a/editor/libeditor/html/nsHTMLEditUtils.cpp +++ b/editor/libeditor/html/nsHTMLEditUtils.cpp @@ -35,9 +35,12 @@ * * ***** END LICENSE BLOCK ***** */ -#include "mozilla/Util.h" - #include "nsHTMLEditUtils.h" + +#include "mozilla/Assertions.h" +#include "mozilla/Util.h" +#include "mozilla/dom/Element.h" + #include "nsTextEditUtils.h" #include "nsString.h" @@ -177,7 +180,15 @@ bool nsHTMLEditUtils::IsListItem(nsIDOMNode *node) { NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsListItem"); - nsCOMPtr nodeAtom = nsEditor::GetTag(node); + nsCOMPtr element = do_QueryInterface(node); + return element && IsListItem(element); +} + +bool +nsHTMLEditUtils::IsListItem(dom::Element* node) +{ + MOZ_ASSERT(node); + nsCOMPtr nodeAtom = node->Tag(); return (nodeAtom == nsEditProperty::li) || (nodeAtom == nsEditProperty::dd) || (nodeAtom == nsEditProperty::dt); @@ -245,7 +256,15 @@ bool nsHTMLEditUtils::IsTableCell(nsIDOMNode *node) { NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsTableCell"); - nsCOMPtr nodeAtom = nsEditor::GetTag(node); + nsCOMPtr element = do_QueryInterface(node); + return element && IsTableCell(element); +} + +bool +nsHTMLEditUtils::IsTableCell(dom::Element* node) +{ + MOZ_ASSERT(node); + nsCOMPtr nodeAtom = node->Tag(); return (nodeAtom == nsEditProperty::td) || (nodeAtom == nsEditProperty::th); } @@ -268,11 +287,19 @@ nsHTMLEditUtils::IsTableCellOrCaption(nsIDOMNode *node) /////////////////////////////////////////////////////////////////////////// // IsList: true if node an html list // -bool +bool nsHTMLEditUtils::IsList(nsIDOMNode *node) { NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsList"); - nsCOMPtr nodeAtom = nsEditor::GetTag(node); + nsCOMPtr element = do_QueryInterface(node); + return element && IsList(element); +} + +bool +nsHTMLEditUtils::IsList(dom::Element* node) +{ + MOZ_ASSERT(node); + nsCOMPtr nodeAtom = node->Tag(); return (nodeAtom == nsEditProperty::ul) || (nodeAtom == nsEditProperty::ol) || (nodeAtom == nsEditProperty::dl); @@ -345,15 +372,21 @@ nsHTMLEditUtils::IsLink(nsIDOMNode *aNode) bool nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode) { - NS_ENSURE_TRUE(aNode, false); - nsCOMPtr anchor = do_QueryInterface(aNode); - if (anchor) - { - nsAutoString tmpText; - if (NS_SUCCEEDED(anchor->GetName(tmpText)) && !tmpText.IsEmpty()) - return true; + nsCOMPtr element = do_QueryInterface(aNode); + return element && IsNamedAnchor(element); +} + +bool +nsHTMLEditUtils::IsNamedAnchor(dom::Element* aNode) +{ + MOZ_ASSERT(aNode); + if (!aNode->IsHTML(nsGkAtoms::a)) { + return false; } - return false; + + nsAutoString text; + return aNode->GetAttr(kNameSpaceID_None, nsGkAtoms::name, text) && + !text.IsEmpty(); } @@ -419,11 +452,19 @@ nsHTMLEditUtils::IsMailCite(nsIDOMNode *node) /////////////////////////////////////////////////////////////////////////// // IsFormWidget: true if node is a form widget of some kind // -bool +bool nsHTMLEditUtils::IsFormWidget(nsIDOMNode *node) { NS_PRECONDITION(node, "null node passed to nsHTMLEditUtils::IsFormWidget"); - nsCOMPtr nodeAtom = nsEditor::GetTag(node); + nsCOMPtr element = do_QueryInterface(node); + return element && IsFormWidget(element); +} + +bool +nsHTMLEditUtils::IsFormWidget(dom::Element* node) +{ + MOZ_ASSERT(node); + nsCOMPtr nodeAtom = node->Tag(); return (nodeAtom == nsEditProperty::textarea) || (nodeAtom == nsEditProperty::select) || (nodeAtom == nsEditProperty::button) diff --git a/editor/libeditor/html/nsHTMLEditUtils.h b/editor/libeditor/html/nsHTMLEditUtils.h index 4543f6d6771..5da26773737 100644 --- a/editor/libeditor/html/nsHTMLEditUtils.h +++ b/editor/libeditor/html/nsHTMLEditUtils.h @@ -40,6 +40,12 @@ #include "prtypes.h" // for PRInt32 +namespace mozilla { +namespace dom { +class Element; +} // namespace dom +} // namespace mozilla + class nsIDOMNode; class nsHTMLEditUtils @@ -56,13 +62,16 @@ public: static bool IsHeader(nsIDOMNode *aNode); static bool IsParagraph(nsIDOMNode *aNode); static bool IsHR(nsIDOMNode *aNode); + static bool IsListItem(mozilla::dom::Element* aNode); static bool IsListItem(nsIDOMNode *aNode); static bool IsTable(nsIDOMNode *aNode); static bool IsTableRow(nsIDOMNode *aNode); static bool IsTableElement(nsIDOMNode *aNode); static bool IsTableElementButNotTable(nsIDOMNode *aNode); + static bool IsTableCell(mozilla::dom::Element* node); static bool IsTableCell(nsIDOMNode *aNode); static bool IsTableCellOrCaption(nsIDOMNode *aNode); + static bool IsList(mozilla::dom::Element* aNode); static bool IsList(nsIDOMNode *aNode); static bool IsOrderedList(nsIDOMNode *aNode); static bool IsUnorderedList(nsIDOMNode *aNode); @@ -71,10 +80,12 @@ public: static bool IsAnchor(nsIDOMNode *aNode); static bool IsImage(nsIDOMNode *aNode); static bool IsLink(nsIDOMNode *aNode); + static bool IsNamedAnchor(mozilla::dom::Element* aNode); static bool IsNamedAnchor(nsIDOMNode *aNode); static bool IsDiv(nsIDOMNode *aNode); static bool IsMozDiv(nsIDOMNode *aNode); static bool IsMailCite(nsIDOMNode *aNode); + static bool IsFormWidget(mozilla::dom::Element* aNode); static bool IsFormWidget(nsIDOMNode *aNode); static bool SupportsAlignAttr(nsIDOMNode *aNode); static bool CanContain(PRInt32 aParent, PRInt32 aChild); diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 10315b3c01d..dec29f54895 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -3953,7 +3953,14 @@ nsHTMLEditor::TagCanContainTag(const nsAString& aParentTag, const nsAString& aCh return nsHTMLEditUtils::CanContain(parentTagEnum, childTagEnum); } -bool +bool +nsHTMLEditor::IsContainer(nsINode* aNode) +{ + nsCOMPtr node = do_QueryInterface(aNode); + return IsContainer(node); +} + +bool nsHTMLEditor::IsContainer(nsIDOMNode *aNode) { if (!aNode) { @@ -4773,13 +4780,10 @@ bool nsHTMLEditor::IsTextInDirtyFrameVisible(nsIContent *aNode) { bool isEmptyTextNode; - nsCOMPtr node = do_QueryInterface(aNode); - nsresult res = IsVisTextNode(node, &isEmptyTextNode, false); - if (NS_FAILED(res)) - { + nsresult rv = IsVisTextNode(aNode, &isEmptyTextNode, false); + if (NS_FAILED(rv)) { // We are following the historical decision: // if we don't know, we say it's visible... - return true; } @@ -4790,6 +4794,15 @@ nsHTMLEditor::IsTextInDirtyFrameVisible(nsIContent *aNode) /////////////////////////////////////////////////////////////////////////// // IsVisTextNode: figure out if textnode aTextNode has any visible content. // +nsresult +nsHTMLEditor::IsVisTextNode(nsIContent* aNode, + bool* outIsEmptyNode, + bool aSafeToAskFrames) +{ + nsCOMPtr node = do_QueryInterface(aNode); + return IsVisTextNode(node); +} + nsresult nsHTMLEditor::IsVisTextNode( nsIDOMNode* aNode, bool *outIsEmptyNode, @@ -4861,10 +4874,11 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, bool aListOrCellNotEmpty, bool aSafeToAskFrames) { - NS_ENSURE_TRUE(aNode && outIsEmptyNode, NS_ERROR_NULL_POINTER); + nsCOMPtr node = do_QueryInterface(aNode); + NS_ENSURE_TRUE(node && outIsEmptyNode, NS_ERROR_NULL_POINTER); *outIsEmptyNode = true; bool seenBR = false; - return IsEmptyNodeImpl(aNode, outIsEmptyNode, aSingleBRDoesntCount, + return IsEmptyNodeImpl(node, outIsEmptyNode, aSingleBRDoesntCount, aListOrCellNotEmpty, aSafeToAskFrames, &seenBR); } @@ -4872,20 +4886,17 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode, // IsEmptyNodeImpl: workhorse for IsEmptyNode. // nsresult -nsHTMLEditor::IsEmptyNodeImpl( nsIDOMNode *aNode, - bool *outIsEmptyNode, - bool aSingleBRDoesntCount, - bool aListOrCellNotEmpty, - bool aSafeToAskFrames, - bool *aSeenBR) +nsHTMLEditor::IsEmptyNodeImpl(nsINode* aNode, + bool *outIsEmptyNode, + bool aSingleBRDoesntCount, + bool aListOrCellNotEmpty, + bool aSafeToAskFrames, + bool *aSeenBR) { NS_ENSURE_TRUE(aNode && outIsEmptyNode && aSeenBR, NS_ERROR_NULL_POINTER); - nsresult res = NS_OK; - if (nsEditor::IsTextNode(aNode)) - { - res = IsVisTextNode(aNode, outIsEmptyNode, aSafeToAskFrames); - return res; + if (aNode->NodeType() == nsIDOMNode::TEXT_NODE) { + return IsVisTextNode(static_cast(aNode), outIsEmptyNode, aSafeToAskFrames); } // if it's not a text node (handled above) and it's not a container, @@ -4894,74 +4905,72 @@ nsHTMLEditor::IsEmptyNodeImpl( nsIDOMNode *aNode, // anchors are containers, named anchors are "empty" but we don't // want to treat them as such. Also, don't call ListItems or table // cells empty if caller desires. Form Widgets not empty. - if (!IsContainer(aNode) || nsHTMLEditUtils::IsNamedAnchor(aNode) || - nsHTMLEditUtils::IsFormWidget(aNode) || - (aListOrCellNotEmpty && nsHTMLEditUtils::IsListItem(aNode)) || - (aListOrCellNotEmpty && nsHTMLEditUtils::IsTableCell(aNode)) ) - { + if (!IsContainer(aNode) || + (aNode->IsElement() && + (nsHTMLEditUtils::IsNamedAnchor(aNode->AsElement()) || + nsHTMLEditUtils::IsFormWidget(aNode->AsElement()) || + (aListOrCellNotEmpty && + (nsHTMLEditUtils::IsListItem(aNode->AsElement()) || + nsHTMLEditUtils::IsTableCell(aNode->AsElement())))))) { *outIsEmptyNode = false; return NS_OK; } // need this for later - bool isListItemOrCell = - nsHTMLEditUtils::IsListItem(aNode) || nsHTMLEditUtils::IsTableCell(aNode); + bool isListItemOrCell = aNode->IsElement() && + (nsHTMLEditUtils::IsListItem(aNode->AsElement()) || + nsHTMLEditUtils::IsTableCell(aNode->AsElement())); // loop over children of node. if no children, or all children are either // empty text nodes or non-editable, then node qualifies as empty - nsCOMPtr child; - aNode->GetFirstChild(getter_AddRefs(child)); - - while (child) - { - nsCOMPtr node = child; - // is the node editable and non-empty? if so, return false - if (nsEditor::IsEditable(node)) - { - if (nsEditor::IsTextNode(node)) - { - res = IsVisTextNode(node, outIsEmptyNode, aSafeToAskFrames); - NS_ENSURE_SUCCESS(res, res); + for (nsCOMPtr child = aNode->GetFirstChild(); + child; + child = child->GetNextSibling()) { + // Is the child editable and non-empty? if so, return false + if (nsEditor::IsEditable(child)) { + if (child->NodeType() == nsIDOMNode::TEXT_NODE) { + nsresult rv = IsVisTextNode(child, outIsEmptyNode, aSafeToAskFrames); + NS_ENSURE_SUCCESS(rv, rv); // break out if we find we aren't emtpy if (!*outIsEmptyNode) { return NS_OK; } - } - else // an editable, non-text node. we need to check it's content. - { - // is it the node we are iterating over? - if (node == aNode) break; - else if (aSingleBRDoesntCount && !*aSeenBR && nsTextEditUtils::IsBreak(node)) - { + } else { + // An editable, non-text node. We need to check its content. + // Is it the node we are iterating over? + if (child == aNode) { + break; + } + + if (aSingleBRDoesntCount && !*aSeenBR && child->IsHTML(nsGkAtoms::br)) { // the first br in a block doesn't count if the caller so indicated *aSeenBR = true; - } - else - { + } else { // is it an empty node of some sort? // note: list items or table cells are not considered empty // if they contain other lists or tables - if (isListItemOrCell) - { - if (nsHTMLEditUtils::IsList(node) || nsHTMLEditUtils::IsTable(node)) - { // break out if we find we aren't empty + if (child->IsElement()) { + if (isListItemOrCell) { + if (nsHTMLEditUtils::IsList(child->AsElement()) || child->IsHTML(nsGkAtoms::table)) { + // break out if we find we aren't empty + *outIsEmptyNode = false; + return NS_OK; + } + } else if (nsHTMLEditUtils::IsFormWidget(child->AsElement())) { + // is it a form widget? + // break out if we find we aren't empty *outIsEmptyNode = false; return NS_OK; } } - // is it a form widget? - else if (nsHTMLEditUtils::IsFormWidget(node)) - { // break out if we find we aren't empty - *outIsEmptyNode = false; - return NS_OK; - } - + bool isEmptyNode = true; - res = IsEmptyNodeImpl(node, &isEmptyNode, aSingleBRDoesntCount, - aListOrCellNotEmpty, aSafeToAskFrames, aSeenBR); - NS_ENSURE_SUCCESS(res, res); - if (!isEmptyNode) - { + nsresult rv = IsEmptyNodeImpl(child, &isEmptyNode, + aSingleBRDoesntCount, + aListOrCellNotEmpty, aSafeToAskFrames, + aSeenBR); + NS_ENSURE_SUCCESS(rv, rv); + if (!isEmptyNode) { // otherwise it ain't empty *outIsEmptyNode = false; return NS_OK; @@ -4969,7 +4978,6 @@ nsHTMLEditor::IsEmptyNodeImpl( nsIDOMNode *aNode, } } } - node->GetNextSibling(getter_AddRefs(child)); } return NS_OK; diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index 51356971d8f..64ef81a8801 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -324,6 +324,7 @@ public: virtual bool TagCanContainTag(const nsAString& aParentTag, const nsAString& aChildTag); /** returns true if aNode is a container */ + virtual bool IsContainer(nsINode* aNode); virtual bool IsContainer(nsIDOMNode *aNode); /** make the given selection span the entire document */ @@ -387,6 +388,9 @@ public: virtual bool IsTextInDirtyFrameVisible(nsIContent *aNode); + nsresult IsVisTextNode(nsIContent* aNode, + bool* outIsEmptyNode, + bool aSafeToAskFrames); nsresult IsVisTextNode( nsIDOMNode *aNode, bool *outIsEmptyNode, bool aSafeToAskFrames); @@ -394,7 +398,7 @@ public: bool aMozBRDoesntCount = false, bool aListOrCellNotEmpty = false, bool aSafeToAskFrames = false); - nsresult IsEmptyNodeImpl(nsIDOMNode *aNode, + nsresult IsEmptyNodeImpl(nsINode* aNode, bool *outIsEmptyBlock, bool aMozBRDoesntCount, bool aListOrCellNotEmpty,