Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  EditorDOMAPIWrapper.h

  Sprache: C
 

/* 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/. */


#ifndef EditorDOMAPIWrapper_h
#define EditorDOMAPIWrapper_h

#include "EditorBase.h"  // for EditorBase
#include "HTMLEditor.h"  // for HTMLEditor

#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/CharacterData.h"
#include "mozilla/dom/Element.h"
#include "nsAtom.h"
#include "nsDOMCSSDeclaration.h"
#include "nsIContent.h"
#include "nsIMutationObserver.h"
#include "nsINode.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "nsStyledElement.h"

namespace mozilla {

static void MakeHumanFriendly(nsAutoString& aStr) {
  aStr.ReplaceSubstring(u"\n", u"\\n");
  aStr.ReplaceSubstring(u"\r", u"\\r");
  aStr.ReplaceSubstring(u"\t", u"\\t");
  aStr.ReplaceSubstring(u"\f", u"\\f");
  aStr.ReplaceSubstring(u"\u00A0", u" ");
  for (char16_t ch = 0; ch <= 0x20; ch++) {
    aStr.ReplaceSubstring(
        nsDependentSubstring(&ch, 1),
        NS_ConvertASCIItoUTF16(nsPrintfCString("&#x%X04", ch)));
  }
}

static void MakeHumanFriendly(nsAutoCString& aStr) {
  aStr.ReplaceSubstring("\n""\\n");
  aStr.ReplaceSubstring("\r""\\r");
  aStr.ReplaceSubstring("\t""\\t");
  aStr.ReplaceSubstring("\f""\\f");
  aStr.ReplaceSubstring("\u00A0"" ");
  for (char ch = 0; ch <= 0x20; ch++) {
    aStr.ReplaceSubstring(nsDependentCSubstring(&ch, 1),
                          nsPrintfCString("&#x%X04", ch));
  }
}

class NodeToString : public nsAutoCString {
 public:
  explicit NodeToString(const nsINode* aNode) {
    if (!aNode) {
      Assign("null");
      return;
    }
    if (const dom::CharacterData* const characterData =
            dom::CharacterData::FromNode(aNode)) {
      nsAutoString data;
      characterData->AppendTextTo(data);
      if (data.Length() > 10) {
        data.Truncate(10);
        data.Append(u"...");
      }
      MakeHumanFriendly(data);
      Assign(nsPrintfCString("%s, data=\"%s\" (length=%zu)",
                             ToString(*characterData).c_str(),
                             NS_ConvertUTF16toUTF8(data).get(), data.Length()));
      return;
    }
    Assign(ToString(*aNode).c_str());
  }
};

class MarkSelectionAndShrinkLongString : public nsAutoString {
 public:
  MarkSelectionAndShrinkLongString(const nsAutoString& aString,
                                   uint32_t aStartOffset, uint32_t aEndOffset)
      : nsAutoString(aString) {
    if (aStartOffset <= aString.Length() && aEndOffset <= aString.Length() &&
        aStartOffset <= aEndOffset) {
      Insert(u']', aEndOffset);
      Insert(u'[', aStartOffset);
      if (aString.Length() > 30) {
        if (aEndOffset + 10 <= Length()) {
          Replace(aEndOffset + 6, Length(), u"...");
        }
        if (aStartOffset > 8) {
          Replace(0, aStartOffset - 5, u"...");
        }
      }
    } else if (aString.Length() > 30) {
      Truncate(30);
      Append(u"...");
    }
  }
};

/**
 * The base class of wrappers of DOM API which modifies the DOM.  Editor should
 * update DOM via the following classes unless the node has not been connected
 * to any document yet.
 */

class MOZ_STACK_CLASS AutoDOMAPIWrapperBase {
 protected:
  using CharacterData = dom::CharacterData;
  using Element = dom::Element;

 public:
  // This method is available only while a subclass is calling a DOM API.
  [[nodiscard]] virtual bool IsExpectedContentAppended(
      nsIContent* aFirstNewContent) const {
    return false;
  }
  // This method is available only while a subclass is calling a DOM API.
  [[nodiscard]] virtual bool IsExpectedContentInserted(
      nsIContent* aChild) const {
    return false;
  }
  // This method is available only while a subclass is calling a DOM API.
  [[nodiscard]] virtual bool IsExpectedContentWillBeRemoved(
      nsIContent* aChild) const {
    return false;
  }
  // This method is available only while a subclass is calling a DOM API.
  [[nodiscard]] virtual bool IsExpectedAttributeChanged(
      Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute,
      AttrModType aModType, const nsAttrValue* aOldValue) const {
    return false;
  }
  // This method is available only while a subclass is calling a DOM API.
  [[nodiscard]] virtual bool IsExpectedCharacterDataChanged(
      nsIContent* aContent, const CharacterDataChangeInfo& aInfo) const {
    return false;
  }

  enum class DOMAPI {
    // AutoNodeAPIWrapper
    nsINode_AppendChild,
    nsINode_InsertBefore,
    nsINode_Remove,
    nsINode_RemoveChild,
    // AutoElementAttrAPIWrapper
    Element_SetAttr,
    Element_UnsetAttr,
    // AutoCharacterDataAPIWrapper
    CharacterData_DeleteData,
    CharacterData_InsertData,
    CharacterData_ReplaceData,
    CharacterData_SetData,
    // AutoCSSDeclarationAPIWrapper
    CSSDeclaration_SetProperty,
    CSSDeclaration_RemoveProperty,
  };

  friend std::ostream& operator<<(std::ostream& aStream, DOMAPI aType) {
    switch (aType) {
      case DOMAPI::nsINode_AppendChild:
        return aStream << "nsINode::AppendChild";
      case DOMAPI::nsINode_InsertBefore:
        return aStream << "nsINode::InsertBefore";
      case DOMAPI::nsINode_Remove:
        return aStream << "nsINode::Remove";
      case DOMAPI::nsINode_RemoveChild:
        return aStream << "nsINode::RemoveChild";
      case DOMAPI::Element_SetAttr:
        return aStream << "Element::SetAttr";
      case DOMAPI::Element_UnsetAttr:
        return aStream << "Element::UnsetAttr";
      case DOMAPI::CharacterData_DeleteData:
        return aStream << "CharacterData::DeleteData";
      case DOMAPI::CharacterData_InsertData:
        return aStream << "CharacterData::InsertData";
      case DOMAPI::CharacterData_ReplaceData:
        return aStream << "CharacterData::ReplaceData";
      case DOMAPI::CharacterData_SetData:
        return aStream << "CharacterData::SetData";
      case DOMAPI::CSSDeclaration_SetProperty:
        return aStream << "nsICSSDeclaration::SetProperty";
      case DOMAPI::CSSDeclaration_RemoveProperty:
        return aStream << "nsICSSDeclaration::DeleteProperty";
      default:
        MOZ_ASSERT_UNREACHABLE("Invalid DOMAPI value");
        return aStream << "<invalid value>";
    }
  }

  [[nodiscard]] DOMAPI Type() const { return *mType; }

#ifdef DEBUG
  virtual ~AutoDOMAPIWrapperBase() { MOZ_ASSERT(mType.isSome()); }
#endif

 protected:
  MOZ_CAN_RUN_SCRIPT explicit AutoDOMAPIWrapperBase(EditorBase& aEditorBase)
      : mEditorBase(aEditorBase) {}

  class MOZ_STACK_CLASS AutoNotifyEditorOfAPICall final {
   public:
    MOZ_CAN_RUN_SCRIPT AutoNotifyEditorOfAPICall(AutoDOMAPIWrapperBase& aBase,
                                                 DOMAPI aCallingAPI)
        : mBase(aBase) {
      aBase.mType.emplace(aCallingAPI);
      if (HTMLEditor* const htmlEditor = mBase.mEditorBase.GetAsHTMLEditor()) {
        mPrevBase = htmlEditor->OnDOMAPICallStart(mBase);
      } else {
        mPrevBase = nullptr;
      }
    }
    ~AutoNotifyEditorOfAPICall() {
      if (HTMLEditor* const htmlEditor = mBase.mEditorBase.GetAsHTMLEditor()) {
        htmlEditor->OnDOMAPICallEnd(mPrevBase);
      }
    }

   private:
    const AutoDOMAPIWrapperBase& mBase;
    const AutoDOMAPIWrapperBase* mPrevBase;
  };

  friend std::ostream& operator<<(std::ostream& aStream,
                                  const AutoDOMAPIWrapperBase& aWrapperBase);

  MOZ_KNOWN_LIVE EditorBase& mEditorBase;
  Maybe<DOMAPI> mType;
};

/**
 * Wrapper class of nsINode::AppendChild, nsINode::InsertBefore, nsINode::Remove
 * and nsINode::RemoveChild.
 */

class MOZ_STACK_CLASS AutoNodeAPIWrapper : public AutoDOMAPIWrapperBase {
 public:
  static AutoNodeAPIWrapper* FromBase(AutoDOMAPIWrapperBase* aBase) {
    switch (aBase->Type()) {
      case DOMAPI::nsINode_AppendChild:
      case DOMAPI::nsINode_InsertBefore:
      case DOMAPI::nsINode_Remove:
      case DOMAPI::nsINode_RemoveChild:
        return static_cast<AutoNodeAPIWrapper*>(aBase);
      default:
        return nullptr;
    }
  }
  static AutoNodeAPIWrapper* FromBaseOrNull(AutoDOMAPIWrapperBase* aBase) {
    return aBase ? FromBase(aBase) : nullptr;
  }
  static const AutoNodeAPIWrapper* FromBase(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBase(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }
  static const AutoNodeAPIWrapper* FromBaseOrNull(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBaseOrNull(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }

  MOZ_CAN_RUN_SCRIPT AutoNodeAPIWrapper(EditorBase& aEditorBase, nsINode& aNode)
      : AutoDOMAPIWrapperBase(aEditorBase), mNode(&aNode) {}

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult AppendChild(nsIContent& aChild) {
    mChild = &aChild;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::nsINode_AppendChild);
    IgnoredErrorResult error;
    MOZ_KnownLive(mNode)->AppendChild(aChild, error);
    error.WouldReportJSException();
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("nsINode::AppendChild() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  InsertBefore(nsIContent& aChild, nsIContent* aReferenceChild) {
    mChild = &aChild;
    mReference = aReferenceChild;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::nsINode_InsertBefore);
    IgnoredErrorResult error;
    MOZ_KnownLive(mNode)->InsertBefore(aChild, aReferenceChild, error);
    error.WouldReportJSException();
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("nsINode::InsertBefore() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult RemoveChild(nsIContent& aChild) {
    mChild = &aChild;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::nsINode_RemoveChild);
    IgnoredErrorResult error;
    MOZ_KnownLive(mNode)->RemoveChild(aChild, error);
    error.WouldReportJSException();
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("nsINode::RemoveChild() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult Remove() {
    mChild = nsIContent::FromNode(mNode);
    MOZ_ASSERT(mChild);
    mNode = mChild->GetParentNode();
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::nsINode_Remove);
    MOZ_KnownLive(mChild)->Remove();
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    return NS_OK;
  }

  [[nodiscard]] bool IsExpectedResult() const {
    switch (Type()) {
      case DOMAPI::nsINode_AppendChild:
      case DOMAPI::nsINode_InsertBefore:
        return mChild->GetParentNode() == mNode &&
               mChild->GetNextSibling() == mReference;
      case DOMAPI::nsINode_RemoveChild:
      case DOMAPI::nsINode_Remove:
        return !mChild->GetParentNode();
      default:
        MOZ_ASSERT_UNREACHABLE("Instantiated with wrong type?");
        return false;
    }
  }

  [[nodiscard]] bool IsExpectedContentAppended(
      nsIContent* aFirstNewContent) const override {
    return (Type() == DOMAPI::nsINode_AppendChild ||
            Type() == DOMAPI::nsINode_InsertBefore) &&
           aFirstNewContent == mChild && IsExpectedResult();
  }
  [[nodiscard]] bool IsExpectedContentInserted(
      nsIContent* aChild) const override {
    return (Type() == DOMAPI::nsINode_AppendChild ||
            Type() == DOMAPI::nsINode_InsertBefore) &&
           aChild == mChild && IsExpectedResult();
  }
  [[nodiscard]] bool IsExpectedContentWillBeRemoved(
      nsIContent* aChild) const override {
    if ((Type() == DOMAPI::nsINode_RemoveChild ||
         Type() == DOMAPI::nsINode_Remove) &&
        aChild == mChild && aChild->GetParentNode() == mNode) {
      return true;
    }
    return (Type() == DOMAPI::nsINode_AppendChild ||
            Type() == DOMAPI::nsINode_InsertBefore) &&
           aChild == mChild;
  }

  friend std::ostream& operator<<(std::ostream& aStream,
                                  const AutoNodeAPIWrapper& aWrapper) {
    aStream << aWrapper.Type() << "(";
    switch (aWrapper.Type()) {
      case DOMAPI::nsINode_AppendChild:
        aStream << "parent: " << NodeToString(aWrapper.mNode).get()
                << ", new child: " << NodeToString(aWrapper.mChild).get();
        break;
      case DOMAPI::nsINode_InsertBefore:
        aStream << "parent: " << NodeToString(aWrapper.mNode).get()
                << ", new child: " << NodeToString(aWrapper.mChild).get()
                << ", reference node: "
                << NodeToString(aWrapper.mReference).get();
        break;
      case DOMAPI::nsINode_Remove:
      case DOMAPI::nsINode_RemoveChild:
        aStream << "parent: " << NodeToString(aWrapper.mNode).get()
                << ", removing node: " << NodeToString(aWrapper.mChild).get();
        break;
      default:
        break;
    }
    return aStream << ")";
  }

 protected:
  // nullptr if nsINode::Remove() is called when no parent.
  nsINode* mNode;
  nsIContent* mChild = nullptr;
  nsIContent* mReference = nullptr;
};

/**
 * Wrapper class of Element::SetAttr and Element::UnsetAttr.
 */

class MOZ_STACK_CLASS AutoElementAttrAPIWrapper : public AutoDOMAPIWrapperBase {
 public:
  static AutoElementAttrAPIWrapper* FromBase(AutoDOMAPIWrapperBase* aBase) {
    switch (aBase->Type()) {
      case DOMAPI::Element_SetAttr:
      case DOMAPI::Element_UnsetAttr:
        return static_cast<AutoElementAttrAPIWrapper*>(aBase);
      default:
        return nullptr;
    }
  }
  static AutoElementAttrAPIWrapper* FromBaseOrNull(
      AutoDOMAPIWrapperBase* aBase) {
    return aBase ? FromBase(aBase) : nullptr;
  }
  static const AutoElementAttrAPIWrapper* FromBase(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBase(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }
  static const AutoElementAttrAPIWrapper* FromBaseOrNull(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBaseOrNull(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }

  MOZ_CAN_RUN_SCRIPT AutoElementAttrAPIWrapper(EditorBase& aEditorBase,
                                               Element& aElement)
      : AutoDOMAPIWrapperBase(aEditorBase), mElement(aElement) {}

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetAttr(nsAtom* aAttr,
                                                    const nsAString& aNewValue,
                                                    bool aNotify) {
    mAttr = aAttr;
    mNewValuePtr = &aNewValue;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::Element_SetAttr);
    nsresult rv =
        mElement.SetAttr(kNameSpaceID_None, aAttr, aNewValue, aNotify);
    // Don't keep storing the pointer, nobody can guarantee the lifetime.
    mNewValuePtr = nullptr;
    NS_WARNING_ASSERTION(
        NS_SUCCEEDED(rv),
        nsPrintfCString(
            "Element::SetAttr(kNameSpaceID_None, %s, %s, %s) failed",
            nsAutoAtomCString(mAttr).get(),
            NS_ConvertUTF16toUTF8(aNewValue).get(), TrueOrFalse(aNotify))
            .get());
    return rv;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult UnsetAttr(nsAtom* aAttr,
                                                      bool aNotify) {
    mAttr = aAttr;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::Element_UnsetAttr);
    nsresult rv = mElement.UnsetAttr(kNameSpaceID_None, mAttr, aNotify);
    NS_WARNING_ASSERTION(
        NS_SUCCEEDED(rv),
        nsPrintfCString("Element::UnsetAttr(kNameSpaceID_None, %s, %s) failed",
                        nsAutoAtomCString(mAttr).get(), TrueOrFalse(aNotify))
            .get());
    return rv;
  }

  [[nodiscard]] bool IsExpectedResult(const nsAString& aExpectedValue) const {
    switch (Type()) {
      case DOMAPI::Element_SetAttr: {
        nsAutoString value;
        const bool hasAttr = mElement.GetAttr(kNameSpaceID_None, mAttr, value);
        return hasAttr && value == aExpectedValue;
      }
      case DOMAPI::Element_UnsetAttr:
        return !mElement.HasAttr(kNameSpaceID_None, mAttr);
      default:
        MOZ_ASSERT_UNREACHABLE("Instantiated with wrong type?");
        return false;
    }
  }

  [[nodiscard]] virtual bool IsExpectedAttributeChanged(
      Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute,
      AttrModType aModType, const nsAttrValue* aOldValue) const {
    switch (Type()) {
      case DOMAPI::Element_SetAttr:
        return IsAdditionOrModification(aModType) && aElement == &mElement &&
               aNameSpaceID == kNameSpaceID_None && aAttribute == mAttr &&
               mNewValuePtr && IsExpectedResult(*mNewValuePtr);
      case DOMAPI::Element_UnsetAttr:
        return aModType == AttrModType::Removal && aElement == &mElement &&
               aNameSpaceID == kNameSpaceID_None && aAttribute == mAttr;
      default:
        return false;
    }
  }

  friend std::ostream& operator<<(std::ostream& aStream,
                                  const AutoElementAttrAPIWrapper& aWrapper) {
    aStream << aWrapper.Type()
            << "(element: " << NodeToString(&aWrapper.mElement).get()
            << ", attr: " << nsAutoAtomCString(aWrapper.mAttr).get();
    switch (aWrapper.Type()) {
      case DOMAPI::Element_SetAttr: {
        MOZ_ASSERT(aWrapper.mNewValuePtr);
        nsAutoString newValue(aWrapper.mNewValuePtr ? *aWrapper.mNewValuePtr
                                                    : EmptyString());
        MakeHumanFriendly(newValue);
        aStream << ", new value=\"" << NS_ConvertUTF16toUTF8(newValue).get()
                << "\"";
        break;
      }
      case DOMAPI::Element_UnsetAttr:
      default:
        break;
    }
    return aStream << ")";
  }

 protected:
  MOZ_KNOWN_LIVE Element& mElement;
  nsAtom* mAttr = nullptr;
  // For avoiding to copy the string, we store the given string pointer only
  // while calling the API because it's enough to check whether checking
  // mutations are expected ones or not.
  const nsAString* mNewValuePtr = nullptr;
};

/**
 * Wrapper class of CharacterData::DeleteData, CharacterData::InsertData,
 * CharacterData::ReplaceData and CharacterData::SetData.
 */

class MOZ_STACK_CLASS AutoCharacterDataAPIWrapper
    : public AutoDOMAPIWrapperBase {
 public:
  static AutoCharacterDataAPIWrapper* FromBase(AutoDOMAPIWrapperBase* aBase) {
    switch (aBase->Type()) {
      case DOMAPI::CharacterData_DeleteData:
      case DOMAPI::CharacterData_InsertData:
      case DOMAPI::CharacterData_ReplaceData:
      case DOMAPI::CharacterData_SetData:
        return static_cast<AutoCharacterDataAPIWrapper*>(aBase);
      default:
        return nullptr;
    }
  }
  static AutoCharacterDataAPIWrapper* FromBaseOrNull(
      AutoDOMAPIWrapperBase* aBase) {
    return aBase ? FromBase(aBase) : nullptr;
  }
  static const AutoCharacterDataAPIWrapper* FromBase(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBase(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }
  static const AutoCharacterDataAPIWrapper* FromBaseOrNull(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBaseOrNull(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }

  MOZ_CAN_RUN_SCRIPT AutoCharacterDataAPIWrapper(EditorBase& aEditorBase,
                                                 CharacterData& aNode)
      : AutoDOMAPIWrapperBase(aEditorBase), mCharacterData(aNode) {}

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult DeleteData(uint32_t aOffset,
                                                       uint32_t aLength) {
    mOffset = aOffset;
    mReplaceLength = aLength;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::CharacterData_DeleteData);
    IgnoredErrorResult error;
    mCharacterData.DeleteData(mOffset, mReplaceLength, error);
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("CharacterData::DeleteData() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertData(uint32_t aOffset,
                                                       const nsAString& aData) {
    mOffset = aOffset;
    mDataPtr = &aData;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::CharacterData_InsertData);
    IgnoredErrorResult error;
    mCharacterData.InsertData(mOffset, aData, error);
    // Don't keep storing the pointer, nobody can guarantee the lifetime.
    mDataPtr = nullptr;
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("CharacterData::InsertData() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult ReplaceData(
      uint32_t aOffset, uint32_t aReplaceLength, const nsAString& aData) {
    mOffset = aOffset;
    mReplaceLength = aReplaceLength;
    mDataPtr = &aData;
    AutoNotifyEditorOfAPICall notifier(*this,
                                       DOMAPI::CharacterData_ReplaceData);
    IgnoredErrorResult error;
    mCharacterData.ReplaceData(mOffset, mReplaceLength, aData, error);
    // Don't keep storing the pointer, nobody can guarantee the lifetime.
    mDataPtr = nullptr;
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("CharacterData::ReplaceData() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult SetData(const nsAString& aData) {
    mDataPtr = &aData;
    AutoNotifyEditorOfAPICall notifier(*this, DOMAPI::CharacterData_SetData);
    IgnoredErrorResult error;
    mCharacterData.SetData(aData, error);
    // Don't keep storing the pointer, nobody can guarantee the lifetime.
    mDataPtr = nullptr;
    if (NS_WARN_IF(mEditorBase.Destroyed())) {
      return NS_ERROR_EDITOR_DESTROYED;
    }
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING("CharacterData::SetData() failed");
      return error.StealNSResult();
    }
    return NS_OK;
  }

  /**
   * Be aware, this may be too slow for the normal path.  This should be used
   * by debugging code like assertions or logging code.
   *
   * @param aExpectedData       Specify the data which you call an above API
   *                            calling method.
   */

  [[nodiscard]] bool IsExpectedResult(const nsAString& aExpectedData) const {
    switch (Type()) {
      case DOMAPI::CharacterData_DeleteData:
        // XXX We don't check whether the final data is expected one because
        // we need to store the original value or the expected value, but that
        // may require a big buffer if the text node has long text.
        return mCharacterData.TextDataLength() >= mOffset;
      case DOMAPI::CharacterData_InsertData:
      case DOMAPI::CharacterData_ReplaceData: {
        if (MOZ_UNLIKELY(mCharacterData.TextDataLength() <
                         mOffset + aExpectedData.Length())) {
          return false;
        }
        // Let's check only the new data is expected value.
        nsAutoString data;
        mCharacterData.GetData(data);
        return Substring(data, mOffset, aExpectedData.Length()) ==
               aExpectedData;
      }
      case DOMAPI::CharacterData_SetData: {
        if (MOZ_UNLIKELY(mCharacterData.TextDataLength() !=
                         aExpectedData.Length())) {
          return false;
        }
        // We can check strictly only in this case.  However, getting the
        // value may be slow if the text node has long text.
        nsAutoString data;
        mCharacterData.GetData(data);
        return data == aExpectedData;
      }
      default:
        MOZ_ASSERT_UNREACHABLE("Instantiated with wrong type?");
        return false;
    }
  }

  [[nodiscard]] virtual bool IsExpectedCharacterDataChanged(
      nsIContent* aContent, const CharacterDataChangeInfo& aInfo) const {
    return aContent == &mCharacterData && aInfo.mChangeStart == mOffset &&
           aInfo.LengthOfRemovedText() == mReplaceLength && mDataPtr &&
           aInfo.mReplaceLength == mDataPtr->Length() && !aInfo.mDetails &&
           IsExpectedResult(*mDataPtr);
  }

  friend std::ostream& operator<<(std::ostream& aStream,
                                  const AutoCharacterDataAPIWrapper& aWrapper) {
    nsAutoString data;
    aWrapper.mCharacterData.AppendTextTo(data);
    MarkSelectionAndShrinkLongString shrunkenData(
        data, aWrapper.mOffset, aWrapper.mOffset + aWrapper.mReplaceLength);
    MakeHumanFriendly(shrunkenData);
    aStream << aWrapper.Type() << "(node: " << aWrapper.mCharacterData
            << ", data=\"" << NS_ConvertUTF16toUTF8(shrunkenData).get()
            << "\" (length=" << data.Length()
            << "), offset: " << aWrapper.mOffset
            << ", replace length: " << aWrapper.mReplaceLength;
    switch (aWrapper.Type()) {
      case DOMAPI::CharacterData_DeleteData:
        break;
      case DOMAPI::CharacterData_InsertData:
      case DOMAPI::CharacterData_ReplaceData:
      case DOMAPI::CharacterData_SetData: {
        MOZ_ASSERT(aWrapper.mDataPtr);
        nsAutoString newData(aWrapper.mDataPtr ? *aWrapper.mDataPtr
                                               : EmptyString());
        MakeHumanFriendly(newData);
        aStream << ", inserting data=\"" << NS_ConvertUTF16toUTF8(newData).get()
                << "\" (length="
                << (aWrapper.mDataPtr ? aWrapper.mDataPtr->Length() : 0u)
                << ")";
        break;
      }
      default:
        break;
    }
    return aStream << ")";
  }

 protected:
  MOZ_KNOWN_LIVE CharacterData& mCharacterData;
  uint32_t mOffset = 0;
  uint32_t mReplaceLength = 0;
  // For avoiding to copy the string, we store the given string pointer only
  // while calling the API because it's enough to check whether checking
  // mutations are expected ones or not.
  const nsAString* mDataPtr = nullptr;
};

/**
 * Wrapper class of nsICSSDeclaration::SetProperty and
 * nsICSSDeclaration::RemoveProperty which modifies `style` attribute.
 */

class MOZ_STACK_CLASS AutoCSSDeclarationAPIWrapper
    : public AutoDOMAPIWrapperBase {
 public:
  static AutoCSSDeclarationAPIWrapper* FromBase(AutoDOMAPIWrapperBase* aBase) {
    switch (aBase->Type()) {
      case DOMAPI::CSSDeclaration_SetProperty:
      case DOMAPI::CSSDeclaration_RemoveProperty:
        return static_cast<AutoCSSDeclarationAPIWrapper*>(aBase);
      default:
        return nullptr;
    }
  }
  static AutoCSSDeclarationAPIWrapper* FromBaseOrNull(
      AutoDOMAPIWrapperBase* aBase) {
    return aBase ? FromBase(aBase) : nullptr;
  }
  static const AutoCSSDeclarationAPIWrapper* FromBase(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBase(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }
  static const AutoCSSDeclarationAPIWrapper* FromBaseOrNull(
      const AutoDOMAPIWrapperBase* aBase) {
    return FromBaseOrNull(const_cast<AutoDOMAPIWrapperBase*>(aBase));
  }

  MOZ_CAN_RUN_SCRIPT AutoCSSDeclarationAPIWrapper(
      EditorBase& aEditorBase, nsStyledElement& aStyledElement,
      nsDOMCSSDeclaration* aDeclaration = nullptr)
      : AutoDOMAPIWrapperBase(aEditorBase),
        mStyledElement(aStyledElement),
        mCSSDeclaration(aDeclaration ? *aDeclaration
                                     : *aStyledElement.Style()) {}

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  SetProperty(const nsACString& aPropertyName, const nsACString& aValues,
              const nsACString& aPriority) {
    mPropertyNamePtr = &aPropertyName;
    mValuesPtr = &aValues;
    mPriorityPtr = &aPriority;
    AutoNotifyEditorOfAPICall notifier(*this,
                                       DOMAPI::CSSDeclaration_SetProperty);
    IgnoredErrorResult error;
    mCSSDeclaration->SetProperty(aPropertyName, aValues, aPriority, error);
    // Don't keep storing the pointers, nobody can guarantee the lifetime.
    mPropertyNamePtr = mValuesPtr = mPriorityPtr = nullptr;
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING(
          nsPrintfCString("nsICSSDeclaration::SetProperty(\"%s\", \"%s\", "
                          "\"%s\") failed (mStyledElement=%s)",
                          PromiseFlatCString(aPropertyName).get(),
                          PromiseFlatCString(aValues).get(),
                          PromiseFlatCString(aPriority).get(),
                          ToString(mStyledElement).c_str())
              .get());
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
  RemoveProperty(const nsACString& aPropertyName) {
    mPropertyNamePtr = &aPropertyName;
    AutoNotifyEditorOfAPICall notifier(*this,
                                       DOMAPI::CSSDeclaration_RemoveProperty);
    IgnoredErrorResult error;
    mCSSDeclaration->RemoveProperty(aPropertyName, mRemovedValue, error);
    // Don't keep storing the pointers, nobody can guarantee the lifetime.
    mPropertyNamePtr = mValuesPtr = mPriorityPtr = nullptr;
    if (MOZ_UNLIKELY(error.Failed())) {
      NS_WARNING(
          nsPrintfCString("nsICSSDeclaration::RemoveProperty(\"%s\") failed "
                          "(mStyledElement=%s, removed value=\"%s\")",
                          PromiseFlatCString(aPropertyName).get(),
                          ToString(mStyledElement).c_str(), mRemovedValue.get())
              .get());
      return error.StealNSResult();
    }
    return NS_OK;
  }

  [[nodiscard]] const nsAutoCString& RemovedValueRef() const {
    MOZ_ASSERT(Type() == DOMAPI::CSSDeclaration_RemoveProperty);
    return mRemovedValue;
  }

  [[nodiscard]] virtual bool IsExpectedAttributeChanged(
      Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute,
      AttrModType aModType, const nsAttrValue* aOldValue) const {
    // XXX We don't check the style value is expected one because it requires
    // to store the original value and compute the expected new value.
    return aAttribute == nsGkAtoms::style &&
           aNameSpaceID == kNameSpaceID_None && aElement == &mStyledElement &&
           IsAdditionOrRemoval(aModType);
  }

  friend std::ostream& operator<<(
      std::ostream& aStream, const AutoCSSDeclarationAPIWrapper& aWrapper) {
    MOZ_ASSERT(aWrapper.mPropertyNamePtr);
    aStream << aWrapper.Type()
            << "(element: " << NodeToString(&aWrapper.mStyledElement).get()
            << ", property: \""
            << (aWrapper.mPropertyNamePtr
                    ? PromiseFlatCString(*aWrapper.mPropertyNamePtr).get()
                    : "")
            << "\"";
    switch (aWrapper.Type()) {
      case DOMAPI::CSSDeclaration_SetProperty: {
        MOZ_ASSERT(aWrapper.mValuesPtr);
        nsAutoCString values(aWrapper.mValuesPtr ? *aWrapper.mValuesPtr
                                                 : EmptyCString());
        MakeHumanFriendly(values);
        aStream << ", values=\"" << values.get() << "\", priority=\""
                << (aWrapper.mPriorityPtr
                        ? PromiseFlatCString(*aWrapper.mPriorityPtr).get()
                        : "")
                << "\"";
        break;
      }
      case DOMAPI::Element_UnsetAttr:
      default:
        break;
    }
    return aStream << ")";
  }

 protected:
  MOZ_KNOWN_LIVE nsStyledElement& mStyledElement;
  MOZ_KNOWN_LIVE const OwningNonNull<nsDOMCSSDeclaration> mCSSDeclaration;
  nsAutoCString mRemovedValue;
  // For avoiding to copy the strings, we store the given string pointers only
  // while calling the API because it's enough to check whether checking
  // mutations are expected ones or not.
  const nsACString* mPropertyNamePtr = nullptr;
  const nsACString* mValuesPtr = nullptr;
  const nsACString* mPriorityPtr = nullptr;
};

inline std::ostream& operator<<(std::ostream& aStream,
                                const AutoDOMAPIWrapperBase& aWrapperBase) {
  switch (aWrapperBase.Type()) {
    case AutoDOMAPIWrapperBase::DOMAPI::nsINode_AppendChild:
    case AutoDOMAPIWrapperBase::DOMAPI::nsINode_InsertBefore:
    case AutoDOMAPIWrapperBase::DOMAPI::nsINode_Remove:
    case AutoDOMAPIWrapperBase::DOMAPI::nsINode_RemoveChild: {
      const auto* runner = AutoNodeAPIWrapper::FromBase(&aWrapperBase);
      return aStream << *runner;
    }
    case AutoDOMAPIWrapperBase::DOMAPI::Element_SetAttr:
    case AutoDOMAPIWrapperBase::DOMAPI::Element_UnsetAttr: {
      const auto* runner = AutoElementAttrAPIWrapper::FromBase(&aWrapperBase);
      return aStream << *runner;
    }
    case AutoDOMAPIWrapperBase::DOMAPI::CharacterData_DeleteData:
    case AutoDOMAPIWrapperBase::DOMAPI::CharacterData_InsertData:
    case AutoDOMAPIWrapperBase::DOMAPI::CharacterData_ReplaceData:
    case AutoDOMAPIWrapperBase::DOMAPI::CharacterData_SetData: {
      const auto* runner = AutoCharacterDataAPIWrapper::FromBase(&aWrapperBase);
      return aStream << *runner;
    }
    case AutoDOMAPIWrapperBase::DOMAPI::CSSDeclaration_SetProperty:
    case AutoDOMAPIWrapperBase::DOMAPI::CSSDeclaration_RemoveProperty: {
      const auto* runner =
          AutoCSSDeclarationAPIWrapper::FromBase(&aWrapperBase);
      return aStream << *runner;
    }
    default:
      MOZ_ASSERT_UNREACHABLE("Invalid DOMAPI value");
      return aStream << "<The wrapper has invalid DOMAPI value>";
  }
}

}  // namespace mozilla

#endif  // #ifndef EditorDOMAPIWrapper_h

Messung V0.5 in Prozent
C=95 H=100 G=97

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=738142