Bug 1324996 - Part 1. Implement nsIAtom version of SetAttribute/RemoveAttribute/CloneAttirubte. r=masayuki draft
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Tue, 20 Dec 2016 19:24:08 +0900
changeset 453396 4c0dccdc19d5ce1451155b641e3d66ebfe6cc0a3
parent 453395 f7d511576146dc87155c0b79a35369e8de966b41
child 453397 62493062ecc47138afe6cb837b982b475bebd044
push id39649
push userbmo:m_kato@ga2.so-net.ne.jp
push dateFri, 23 Dec 2016 09:13:34 +0000
reviewersmasayuki
bugs1324996
milestone53.0a1
Bug 1324996 - Part 1. Implement nsIAtom version of SetAttribute/RemoveAttribute/CloneAttirubte. r=masayuki Add nsIAtom version of the following. - CloneAttribute - RemoveAttribute - RemoveAttributeOrEquivalent - SetAttribute - SetAttributeOrEquivalent MozReview-Commit-ID: 8CutpdyVuew P1 MozReview-Commit-ID: 9MdmGcTqaxT
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
editor/libeditor/TextEditor.cpp
editor/libeditor/TextEditor.h
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -1196,22 +1196,33 @@ EditorBase::CanPasteTransferable(nsITran
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 EditorBase::SetAttribute(nsIDOMElement* aElement,
                          const nsAString& aAttribute,
                          const nsAString& aValue)
 {
+  if (NS_WARN_IF(aAttribute.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
   nsCOMPtr<Element> element = do_QueryInterface(aElement);
   NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
 
+  return SetAttribute(element, attribute, aValue);
+}
+
+nsresult
+EditorBase::SetAttribute(Element* aElement,
+                         nsIAtom* aAttribute,
+                         const nsAString& aValue)
+{
   RefPtr<ChangeAttributeTransaction> transaction =
-    CreateTxnForSetAttribute(*element, *attribute, aValue);
+    CreateTxnForSetAttribute(*aElement, *aAttribute, aValue);
   return DoTransaction(transaction);
 }
 
 NS_IMETHODIMP
 EditorBase::GetAttributeValue(nsIDOMElement* aElement,
                               const nsAString& aAttribute,
                               nsAString& aResultValue,
                               bool* aResultIsSet)
@@ -1230,22 +1241,32 @@ EditorBase::GetAttributeValue(nsIDOMElem
   }
   return rv;
 }
 
 NS_IMETHODIMP
 EditorBase::RemoveAttribute(nsIDOMElement* aElement,
                             const nsAString& aAttribute)
 {
+  if (NS_WARN_IF(aAttribute.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
   nsCOMPtr<Element> element = do_QueryInterface(aElement);
   NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
 
+  return RemoveAttribute(element, attribute);
+}
+
+nsresult
+EditorBase::RemoveAttribute(Element* aElement,
+                            nsIAtom* aAttribute)
+{
   RefPtr<ChangeAttributeTransaction> transaction =
-    CreateTxnForRemoveAttribute(*element, *attribute);
+    CreateTxnForRemoveAttribute(*aElement, *aAttribute);
   return DoTransaction(transaction);
 }
 
 bool
 EditorBase::OutputsMozDirty()
 {
   // Return true for Composer (!eEditorAllowInteraction) or mail
   // (eEditorMailMask), but false for webpages.
@@ -2175,35 +2196,38 @@ EditorBase::EndOperation()
 }
 
 NS_IMETHODIMP
 EditorBase::CloneAttribute(const nsAString& aAttribute,
                            nsIDOMNode* aDestNode,
                            nsIDOMNode* aSourceNode)
 {
   NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
-
-  nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
-  nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
+  if (NS_WARN_IF(aAttribute.IsEmpty())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<Element> destElement = do_QueryInterface(aDestNode);
+  nsCOMPtr<Element> sourceElement = do_QueryInterface(aSourceNode);
   NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
 
+  nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
+  return CloneAttribute(attribute, destElement, sourceElement);
+}
+
+nsresult
+EditorBase::CloneAttribute(nsIAtom* aAttribute,
+                           Element* aDestElement,
+                           Element* aSourceElement)
+{
   nsAutoString attrValue;
-  bool isAttrSet;
-  nsresult rv = GetAttributeValue(sourceElement,
-                                  aAttribute,
-                                  attrValue,
-                                  &isAttrSet);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (isAttrSet) {
-    rv = SetAttribute(destElement, aAttribute, attrValue);
-  } else {
-    rv = RemoveAttribute(destElement, aAttribute);
-  }
-
-  return rv;
+  if (aSourceElement->GetAttr(kNameSpaceID_None, aAttribute, attrValue)) {
+    return SetAttribute(aDestElement, aAttribute, attrValue);
+  }
+  return RemoveAttribute(aDestElement, aAttribute);
 }
 
 /**
  * @param aDest     Must be a DOM element.
  * @param aSource   Must be a DOM element.
  */
 NS_IMETHODIMP
 EditorBase::CloneAttributes(nsIDOMNode* aDest,
@@ -4585,31 +4609,42 @@ EditorBase::CreateHTMLContent(nsIAtom* a
              "check caller.");
     return nullptr;
   }
 
   return doc->CreateElem(nsDependentAtomString(aTag), nullptr,
                          kNameSpaceID_XHTML);
 }
 
-nsresult
+NS_IMETHODIMP
 EditorBase::SetAttributeOrEquivalent(nsIDOMElement* aElement,
                                      const nsAString& aAttribute,
                                      const nsAString& aValue,
                                      bool aSuppressTransaction)
 {
-  return SetAttribute(aElement, aAttribute, aValue);
-}
-
-nsresult
+  nsCOMPtr<Element> element = do_QueryInterface(aElement);
+  if (NS_WARN_IF(!element)) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
+  return SetAttributeOrEquivalent(element, attribute, aValue,
+                                  aSuppressTransaction);
+}
+
+NS_IMETHODIMP
 EditorBase::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
                                         const nsAString& aAttribute,
                                         bool aSuppressTransaction)
 {
-  return RemoveAttribute(aElement, aAttribute);
+  nsCOMPtr<Element> element = do_QueryInterface(aElement);
+  if (NS_WARN_IF(!element)) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
+  return RemoveAttributeOrEquivalent(element, attribute, aSuppressTransaction);
 }
 
 nsresult
 EditorBase::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
 {
   // NOTE: When you change this method, you should also change:
   //   * editor/libeditor/tests/test_texteditor_keyevent_handling.html
   //   * editor/libeditor/tests/test_htmleditor_keyevent_handling.html
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -229,16 +229,29 @@ public:
                                                  nsIAtom* aAttribute = nullptr,
                                                  const nsAString* aValue =
                                                  nullptr);
   nsIContent* SplitNode(nsIContent& aNode, int32_t aOffset,
                         ErrorResult& aResult);
   nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
   nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset);
 
+  nsresult CloneAttribute(nsIAtom* aAttribute, Element* aDestElement,
+                          Element* aSourceElement);
+  nsresult RemoveAttribute(Element* aElement, nsIAtom* aAttribute);
+  virtual nsresult RemoveAttributeOrEquivalent(Element* aElement,
+                                               nsIAtom* aAttribute,
+                                               bool aSuppressTransaction) = 0;
+  nsresult SetAttribute(Element* aElement, nsIAtom* aAttribute,
+                        const nsAString& aValue);
+  virtual nsresult SetAttributeOrEquivalent(Element* aElement,
+                                            nsIAtom* aAttribute,
+                                            const nsAString& aValue,
+                                            bool aSuppressTransaction) = 0;
+
   /**
    * Method to replace certain CreateElementNS() calls.
    *
    * @param aTag        Tag you want.
    */
   already_AddRefed<Element> CreateHTMLContent(nsIAtom* aTag);
 
   /**
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -4442,103 +4442,93 @@ HTMLEditor::IsEmptyNodeImpl(nsINode* aNo
   }
 
   return NS_OK;
 }
 
 // add to aElement the CSS inline styles corresponding to the HTML attribute
 // aAttribute with its value aValue
 nsresult
-HTMLEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
-                                     const nsAString& aAttribute,
+HTMLEditor::SetAttributeOrEquivalent(Element* aElement,
+                                     nsIAtom* aAttribute,
                                      const nsAString& aValue,
                                      bool aSuppressTransaction)
 {
+  MOZ_ASSERT(aElement);
+  MOZ_ASSERT(aAttribute);
+
   nsAutoScriptBlocker scriptBlocker;
 
-  if (IsCSSEnabled() && mCSSEditUtils) {
-    nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
-    MOZ_ASSERT(element);
-
-    nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
-    MOZ_ASSERT(attribute);
-
-    int32_t count =
-      mCSSEditUtils->SetCSSEquivalentToHTMLStyle(element, nullptr,
-                                                 attribute, &aValue,
-                                                 aSuppressTransaction);
-    if (count) {
-      // we found an equivalence ; let's remove the HTML attribute itself if it is set
-      nsAutoString existingValue;
-      bool wasSet = false;
-      nsresult rv =
-        GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
-      NS_ENSURE_SUCCESS(rv, rv);
-      if (!wasSet) {
-        return NS_OK;
-      }
-      return aSuppressTransaction ?
-               element->UnsetAttr(kNameSpaceID_None, attribute, true) :
-               RemoveAttribute(aElement, aAttribute);
+  if (!IsCSSEnabled() || !mCSSEditUtils) {
+    // we are not in an HTML+CSS editor; let's set the attribute the HTML way
+    return aSuppressTransaction ?
+             aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) :
+             SetAttribute(aElement, aAttribute, aValue);
+  }
+
+  int32_t count =
+    mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr,
+                                               aAttribute, &aValue,
+                                               aSuppressTransaction);
+  if (count) {
+    // we found an equivalence ; let's remove the HTML attribute itself if it
+    // is set
+    nsAutoString existingValue;
+    if (!aElement->GetAttr(kNameSpaceID_None, aAttribute, existingValue)) {
+      return NS_OK;
     }
 
-    // count is an integer that represents the number of CSS declarations applied to the
-    // element. If it is zero, we found no equivalence in this implementation for the
-    // attribute
-    if (attribute == nsGkAtoms::style) {
-      // if it is the style attribute, just add the new value to the existing style
-      // attribute's value
-      nsAutoString existingValue;
-      bool wasSet = false;
-      nsresult rv = GetAttributeValue(aElement, NS_LITERAL_STRING("style"),
-                                      existingValue, &wasSet);
-      NS_ENSURE_SUCCESS(rv, rv);
-      existingValue.Append(' ');
-      existingValue.Append(aValue);
-      return aSuppressTransaction ?
-        element->SetAttr(kNameSpaceID_None, attribute, existingValue, true) :
-        SetAttribute(aElement, aAttribute, existingValue);
-    }
-
-    // we have no CSS equivalence for this attribute and it is not the style
-    // attribute; let's set it the good'n'old HTML way
     return aSuppressTransaction ?
-             element->SetAttr(kNameSpaceID_None, attribute, aValue, true) :
-             SetAttribute(aElement, aAttribute, aValue);
-  }
-
-  // we are not in an HTML+CSS editor; let's set the attribute the HTML way
-  return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) :
-                                SetAttribute(aElement, aAttribute, aValue);
+             aElement->UnsetAttr(kNameSpaceID_None, aAttribute, true) :
+             RemoveAttribute(aElement, aAttribute);
+  }
+
+  // count is an integer that represents the number of CSS declarations applied
+  // to the element. If it is zero, we found no equivalence in this
+  // implementation for the attribute
+  if (aAttribute == nsGkAtoms::style) {
+    // if it is the style attribute, just add the new value to the existing
+    // style attribute's value
+    nsAutoString existingValue;
+    aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::style, existingValue);
+    existingValue.Append(' ');
+    existingValue.Append(aValue);
+    return aSuppressTransaction ?
+       aElement->SetAttr(kNameSpaceID_None, aAttribute, existingValue, true) :
+      SetAttribute(aElement, aAttribute, existingValue);
+  }
+
+  // we have no CSS equivalence for this attribute and it is not the style
+  // attribute; let's set it the good'n'old HTML way
+  return aSuppressTransaction ?
+           aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) :
+           SetAttribute(aElement, aAttribute, aValue);
 }
 
 nsresult
-HTMLEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
-                                        const nsAString& aAttribute,
+HTMLEditor::RemoveAttributeOrEquivalent(Element* aElement,
+                                        nsIAtom* aAttribute,
                                         bool aSuppressTransaction)
 {
-  nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
-  NS_ENSURE_TRUE(element, NS_OK);
-
-  nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
-  MOZ_ASSERT(attribute);
+  MOZ_ASSERT(aElement);
+  MOZ_ASSERT(aAttribute);
 
   if (IsCSSEnabled() && mCSSEditUtils) {
     nsresult rv =
       mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(
-        element, nullptr, attribute, nullptr, aSuppressTransaction);
+        aElement, nullptr, aAttribute, nullptr, aSuppressTransaction);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  if (!element->HasAttr(kNameSpaceID_None, attribute)) {
+  if (!aElement->HasAttr(kNameSpaceID_None, aAttribute)) {
     return NS_OK;
   }
 
   return aSuppressTransaction ?
-    element->UnsetAttr(kNameSpaceID_None, attribute, /* aNotify = */ true) :
+    aElement->UnsetAttr(kNameSpaceID_None, aAttribute, /* aNotify = */ true) :
     RemoveAttribute(aElement, aAttribute);
 }
 
 nsresult
 HTMLEditor::SetIsCSSEnabled(bool aIsCSSPrefChecked)
 {
   if (!mCSSEditUtils) {
     return NS_ERROR_NOT_INITIALIZED;
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -116,16 +116,26 @@ public:
   virtual already_AddRefed<dom::EventTarget> GetDOMEventTarget() override;
   virtual Element* GetEditorRoot() override;
   virtual already_AddRefed<nsIContent> FindSelectionRoot(
                                          nsINode *aNode) override;
   virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent) override;
   virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
   virtual bool IsEditable(nsINode* aNode) override;
   using EditorBase::IsEditable;
+  virtual nsresult RemoveAttributeOrEquivalent(
+                     Element* aElement,
+                     nsIAtom* aAttribute,
+                     bool aSuppressTransaction) override;
+  virtual nsresult SetAttributeOrEquivalent(Element* aElement,
+                                            nsIAtom* aAttribute,
+                                            const nsAString& aValue,
+                                            bool aSuppressTransaction) override;
+  using EditorBase::RemoveAttributeOrEquivalent;
+  using EditorBase::SetAttributeOrEquivalent;
 
   // nsStubMutationObserver overrides
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   // nsIHTMLEditor methods
   NS_DECL_NSIHTMLEDITOR
@@ -324,24 +334,16 @@ public:
   virtual bool IsContainer(nsINode* aNode) override;
   virtual bool IsContainer(nsIDOMNode* aNode) override;
 
   /**
    * Make the given selection span the entire document.
    */
   virtual nsresult SelectEntireDocument(Selection* aSelection) override;
 
-  NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement,
-                                      const nsAString& aAttribute,
-                                      const nsAString& aValue,
-                                      bool aSuppressTransaction) override;
-  NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
-                                         const nsAString& aAttribute,
-                                         bool aSuppressTransaction) override;
-
   /**
    * Join together any adjacent editable text nodes in the range.
    */
   nsresult CollapseAdjacentTextNodes(nsRange* aRange);
 
   virtual bool AreNodesSameType(nsIContent* aNode1,
                                 nsIContent* aNode2) override;
 
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -1613,25 +1613,25 @@ already_AddRefed<EventTarget>
 TextEditor::GetDOMEventTarget()
 {
   nsCOMPtr<EventTarget> copy = mEventTarget;
   return copy.forget();
 }
 
 
 nsresult
-TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
-                                     const nsAString& aAttribute,
+TextEditor::SetAttributeOrEquivalent(Element* aElement,
+                                     nsIAtom* aAttribute,
                                      const nsAString& aValue,
                                      bool aSuppressTransaction)
 {
   return EditorBase::SetAttribute(aElement, aAttribute, aValue);
 }
 
 nsresult
-TextEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
-                                        const nsAString& aAttribute,
+TextEditor::RemoveAttributeOrEquivalent(Element* aElement,
+                                        nsIAtom* aAttribute,
                                         bool aSuppressTransaction)
 {
   return EditorBase::RemoveAttribute(aElement, aAttribute);
 }
 
 } // namespace mozilla
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -58,24 +58,27 @@ public:
   TextEditor();
 
   // nsIPlaintextEditor methods
   NS_DECL_NSIPLAINTEXTEDITOR
 
   // nsIEditorMailSupport overrides
   NS_DECL_NSIEDITORMAILSUPPORT
 
-  // Overrides of EditorBase interface methods
-  NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement,
-                                      const nsAString& aAttribute,
-                                      const nsAString& aValue,
-                                      bool aSuppressTransaction) override;
-  NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
-                                         const nsAString& aAttribute,
-                                         bool aSuppressTransaction) override;
+  // Overrides of EditorBase
+  virtual nsresult RemoveAttributeOrEquivalent(
+                     Element* aElement,
+                     nsIAtom* aAttribute,
+                     bool aSuppressTransaction) override;
+  virtual nsresult SetAttributeOrEquivalent(Element* aElement,
+                                            nsIAtom* aAttribute,
+                                            const nsAString& aValue,
+                                            bool aSuppressTransaction) override;
+  using EditorBase::RemoveAttributeOrEquivalent;
+  using EditorBase::SetAttributeOrEquivalent;
 
   NS_IMETHOD Init(nsIDOMDocument* aDoc, nsIContent* aRoot,
                   nsISelectionController* aSelCon, uint32_t aFlags,
                   const nsAString& aValue) override;
 
   NS_IMETHOD GetDocumentIsEmpty(bool* aDocumentIsEmpty) override;
   NS_IMETHOD GetIsDocumentEditable(bool* aIsDocumentEditable) override;