Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/editor/libeditor/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 18 kB image not shown  

Quelle  WhiteSpaceVisibilityKeeper.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 WhiteSpaceVisibilityKeeper_h
#define WhiteSpaceVisibilityKeeper_h

#include "EditAction.h"
#include "EditorBase.h"
#include "EditorForwards.h"
#include "EditorDOMPoint.h"  // for EditorDOMPoint
#include "EditorUtils.h"     // for CaretPoint
#include "HTMLEditHelpers.h"
#include "HTMLEditor.h"
#include "HTMLEditUtils.h"
#include "WSRunScanner.h"

#include "mozilla/Assertions.h"
#include "mozilla/Maybe.h"
#include "mozilla/Result.h"
#include "mozilla/StaticPrefs_editor.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/Text.h"
#include "nsCOMPtr.h"
#include "nsIContent.h"

namespace mozilla {

/**
 * WhiteSpaceVisibilityKeeper class helps `HTMLEditor` modifying the DOM tree
 * with keeps white-space sequence visibility automatically.  E.g., invisible
 * leading/trailing white-spaces becomes visible, this class members delete
 * them.  E.g., when splitting visible-white-space sequence, this class may
 * replace ASCII white-spaces at split edges with NBSPs.
 */

class WhiteSpaceVisibilityKeeper final {
 private:
  using AutoTransactionsConserveSelection =
      EditorBase::AutoTransactionsConserveSelection;
  using EditorType = EditorBase::EditorType;
  using Element = dom::Element;
  using HTMLBRElement = dom::HTMLBRElement;
  using IgnoreNonEditableNodes = WSRunScanner::IgnoreNonEditableNodes;
  using InsertTextTo = EditorBase::InsertTextTo;
  using LineBreakType = HTMLEditor::LineBreakType;
  using PointPosition = WSRunScanner::PointPosition;
  using ReferHTMLDefaultStyle = WSRunScanner::ReferHTMLDefaultStyle;
  using TextFragmentData = WSRunScanner::TextFragmentData;
  using VisibleWhiteSpacesData = WSRunScanner::VisibleWhiteSpacesData;

 public:
  WhiteSpaceVisibilityKeeper() = delete;
  explicit WhiteSpaceVisibilityKeeper(
      const WhiteSpaceVisibilityKeeper& aOther) = delete;
  WhiteSpaceVisibilityKeeper(WhiteSpaceVisibilityKeeper&& aOther) = delete;

  /**
   * Remove invisible leading white-spaces and trailing white-spaces if there
   * are around aPoint.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<CaretPoint, nsresult>
  DeleteInvisibleASCIIWhiteSpaces(HTMLEditor& aHTMLEditor,
                                  const EditorDOMPoint& aPoint);

  /**
   * PrepareToSplitBlockElement() makes sure that the invisible white-spaces
   * not to become visible and returns splittable point.
   *
   * @param aHTMLEditor         The HTML editor.
   * @param aPointToSplit       The splitting point in aSplittingBlockElement.
   * @param aSplittingBlockElement  A block element which will be split.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  PrepareToSplitBlockElement(HTMLEditor& aHTMLEditor,
                             const EditorDOMPoint& aPointToSplit,
                             const Element& aSplittingBlockElement);

  enum class NormalizeOption {
    // If set, don't normalize white-spaces before the point.
    HandleOnlyFollowingWhiteSpaces,
    // If set, don't normalize white-spaces after the point.
    HandleOnlyPrecedingWhiteSpaces,
    // If set, don't normalize following white-spaces if starts with an NBSP.
    StopIfFollowingWhiteSpacesStartsWithNBSP,
    // If set, don't normalize preceding white-spaces if ends with an NBSP.
    StopIfPrecedingWhiteSpacesEndsWithNBP,
  };
  using NormalizeOptions = EnumSet<NormalizeOption>;

  /**
   * Normalize preceding white-spaces of aPoint.  aPoint should not be middle of
   * a Text node.
   *
   * @return If this updates some characters of the last `Text` node, this
   * returns the end of the `Text`.  Otherwise, this returns the position
   * of the found `Text` which ends with a visible character or aPoint.
   * Note that returning aPoint does not mean nothing is changed.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  NormalizeWhiteSpacesBefore(HTMLEditor& aHTMLEditor,
                             const EditorDOMPoint& aPoint,
                             NormalizeOptions aOptions);

  /**
   * Normalize following white-spaces of aPoint.  aPoint should not be middle of
   * a Text node.
   *
   * @return If this updates some characters of the first `Text` node, this
   * returns the start of the `Text`.  Otherwise, this returns the position
   * of the found `Text` which starts with a visible character or aPoint.
   * Note that returning aPoint does not mean nothing is changed.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  NormalizeWhiteSpacesAfter(HTMLEditor& aHTMLEditor,
                            const EditorDOMPoint& aPoint,
                            NormalizeOptions aOptions);

  /**
   * Normalize surrounding white-spaces of aPointToSplit.  This may normalize
   * 2 `Text` nodes if the point is surrounded by them.
   * Note that this is designed only for the new normalizer.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  NormalizeWhiteSpacesToSplitAt(HTMLEditor& aHTMLEditor,
                                const EditorDOMPoint& aPointToSplit,
                                NormalizeOptions aOptions);

  /**
   * Normalize surrounding white-spaces of both boundaries of aRangeToDelete.
   * This returns the range which should be deleted later.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMRange, nsresult>
  NormalizeSurroundingWhiteSpacesToJoin(HTMLEditor& aHTMLEditor,
                                        const EditorDOMRange& aRangeToDelete);

  /**
   * MergeFirstLineOfRightBlockElementIntoDescendantLeftBlockElement() merges
   * first line in aRightBlockElement into end of aLeftBlockElement which
   * is a descendant of aRightBlockElement.
   *
   * @param aHTMLEditor         The HTML editor.
   * @param aLeftBlockElement   The content will be merged into end of
   *                            this element.
   * @param aRightBlockElement  The first line in this element will be
   *                            moved to aLeftBlockElement.
   * @param aAtRightBlockChild  At a child of aRightBlockElement and inclusive
   *                            ancestor of aLeftBlockElement.
   * @param aListElementTagName Set some if aRightBlockElement is a list
   *                            element and it'll be merged with another
   *                            list element.
   * @param aEditingHost        The editing host.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<MoveNodeResult, nsresult>
  MergeFirstLineOfRightBlockElementIntoDescendantLeftBlockElement(
      HTMLEditor& aHTMLEditor, Element& aLeftBlockElement,
      Element& aRightBlockElement, const EditorDOMPoint& aAtRightBlockChild,
      const Maybe<nsAtom*>& aListElementTagName,
      const HTMLBRElement* aPrecedingInvisibleBRElement,
      const Element& aEditingHost);

  /**
   * MergeFirstLineOfRightBlockElementIntoAncestorLeftBlockElement() merges
   * first line in aRightBlockElement into end of aLeftBlockElement which
   * is an ancestor of aRightBlockElement, then, removes aRightBlockElement
   * if it becomes empty.
   *
   * @param aHTMLEditor         The HTML editor.
   * @param aLeftBlockElement   The content will be merged into end of
   *                            this element.
   * @param aRightBlockElement  The first line in this element will be
   *                            moved to aLeftBlockElement and maybe
   *                            removed when this becomes empty.
   * @param aAtLeftBlockChild   At a child of aLeftBlockElement and inclusive
   *                            ancestor of aRightBlockElement.
   * @param aLeftContentInBlock The content whose inclusive ancestor is
   *                            aLeftBlockElement.
   * @param aListElementTagName Set some if aRightBlockElement is a list
   *                            element and it'll be merged with another
   *                            list element.
   * @param aEditingHost        The editing host.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<MoveNodeResult, nsresult>
  MergeFirstLineOfRightBlockElementIntoAncestorLeftBlockElement(
      HTMLEditor& aHTMLEditor, Element& aLeftBlockElement,
      Element& aRightBlockElement, const EditorDOMPoint& aAtLeftBlockChild,
      nsIContent& aLeftContentInBlock,
      const Maybe<nsAtom*>& aListElementTagName,
      const HTMLBRElement* aPrecedingInvisibleBRElement,
      const Element& aEditingHost);

  /**
   * MergeFirstLineOfRightBlockElementIntoLeftBlockElement() merges first
   * line in aRightBlockElement into end of aLeftBlockElement and removes
   * aRightBlockElement when it has only one line.
   *
   * @param aHTMLEditor         The HTML editor.
   * @param aLeftBlockElement   The content will be merged into end of
   *                            this element.
   * @param aRightBlockElement  The first line in this element will be
   *                            moved to aLeftBlockElement and maybe
   *                            removed when this becomes empty.
   * @param aListElementTagName Set some if aRightBlockElement is a list
   *                            element and its type needs to be changed.
   * @param aEditingHost        The editing host.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<MoveNodeResult, nsresult>
  MergeFirstLineOfRightBlockElementIntoLeftBlockElement(
      HTMLEditor& aHTMLEditor, Element& aLeftBlockElement,
      Element& aRightBlockElement, const Maybe<nsAtom*>& aListElementTagName,
      const HTMLBRElement* aPrecedingInvisibleBRElement,
      const Element& aEditingHost);

  /**
   * InsertLineBreak() inserts a line break at (before) aPointToInsert and
   * delete unnecessary white-spaces around there and/or replaces white-spaces
   * with non-breaking spaces.  Note that if the point is in a text node, the
   * text node will be split and insert new <br> node between the left node
   * and the right node.
   *
   * @param aPointToInsert  The point to insert new line break.  Note that
   *                        it'll be inserted before this point.  I.e., the
   *                        point will be the point of new line break.
   * @return                If succeeded, returns the new line break and
   *                        point to put caret.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<CreateLineBreakResult,
                                                 nsresult>
  InsertLineBreak(LineBreakType aLineBreakType, HTMLEditor& aHTMLEditor,
                  const EditorDOMPoint& aPointToInsert);

  using InsertTextFor = EditorBase::InsertTextFor;

  /**
   * Insert aStringToInsert to aPointToInsert and makes any needed adjustments
   * to white-spaces around the insertion point.
   *
   * @param aStringToInsert     The string to insert.
   * @param aRangeToBeReplaced  The range to be replaced.
   * @param aInsertTextTo       Whether forcibly creates a new `Text` node in
   *                            specific condition or use existing `Text` if
   *                            available.
   * @param aEditingHost        The editing host at aPointToInsert.
   */

  template <typename EditorDOMPointType>
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<InsertTextResult, nsresult>
  InsertText(HTMLEditor& aHTMLEditor, const nsAString& aStringToInsert,
             const EditorDOMPointType& aPointToInsert,
             InsertTextTo aInsertTextTo, const Element& aEditingHost) {
    return WhiteSpaceVisibilityKeeper::
        InsertTextOrInsertOrUpdateCompositionString(
            aHTMLEditor, aStringToInsert, EditorDOMRange(aPointToInsert),
            aInsertTextTo, InsertTextFor::NormalText, aEditingHost);
  }

  /**
   * Insert aCompositionString to the start boundary of aCompositionStringRange
   * or update existing composition string with aCompositionString.
   * If inserting composition string, this may normalize white-spaces around
   * there.  However, if updating composition string, this will skip it to
   * avoid CompositionTransaction work.
   *
   * @param aCompositionString  The new composition string.
   * @param aCompositionStringRange
   *                            If there is old composition string, this should
   *                            cover all of it.  Otherwise, this should be
   *                            collapsed and indicate the insertion point.
   * @param aEditingHost        The editing host at aCompositionStringRange.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<InsertTextResult, nsresult>
  InsertOrUpdateCompositionString(HTMLEditor& aHTMLEditor,
                                  const nsAString& aCompositionString,
                                  const EditorDOMRange& aCompositionStringRange,
                                  InsertTextFor aPurpose,
                                  const Element& aEditingHost) {
    MOZ_ASSERT(EditorBase::InsertingTextForComposition(aPurpose));
    return InsertTextOrInsertOrUpdateCompositionString(
        aHTMLEditor, aCompositionString, aCompositionStringRange,
        HTMLEditor::InsertTextTo::ExistingTextNodeIfAvailable, aPurpose,
        aEditingHost);
  }

  /**
   * Normalize white-space sequence containing aPoint or starts from next to
   * aPoint.  This assumes all white-spaces in the sequence is visible.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsresult
  NormalizeVisibleWhiteSpacesWithoutDeletingInvisibleWhiteSpaces(
      HTMLEditor& aHTMLEditor, const EditorDOMPointInText& aPoint);

  /**
   * Delete aContentToDelete and may remove/replace white-spaces around it.
   * Then, if deleting content makes 2 text nodes around it are adjacent
   * siblings, this joins them and put selection at the joined point.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<CaretPoint, nsresult>
  DeleteContentNodeAndJoinTextNodesAroundIt(HTMLEditor& aHTMLEditor,
                                            nsIContent& aContentToDelete,
                                            const EditorDOMPoint& aCaretPoint,
                                            const Element& aEditingHost);

 private:
  /**
   * ReplaceTextAndRemoveEmptyTextNodes() replaces the range between
   * aRangeToReplace with aReplaceString simply.  Additionally, removes
   * empty text nodes in the range.
   *
   * @param aRangeToReplace     Range to replace text.
   * @param aReplaceString      The new string.  Empty string is allowed.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsresult
  ReplaceTextAndRemoveEmptyTextNodes(
      HTMLEditor& aHTMLEditor, const EditorDOMRangeInTexts& aRangeToReplace,
      const nsAString& aReplaceString);

  /**
   * Normalize surrounding white-spaces of aPointToSplit.
   *
   * @return The split point which you specified before.  Note that the result
   *         may be different from aPointToSplit if this deletes some invisible
   *         white-spaces.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  NormalizeWhiteSpacesToSplitTextNodeAt(
      HTMLEditor& aHTMLEditor, const EditorDOMPointInText& aPointToSplit,
      NormalizeOptions aOptions);

  /**
   * Normalize surrounding white-spaces of the range between aOffset - aOffset +
   * aLength.
   *
   * @return The delete range after normalized.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMRange, nsresult>
  NormalizeSurroundingWhiteSpacesToDeleteCharacters(HTMLEditor& aHTMLEditor,
                                                    dom::Text& aTextNode,
                                                    uint32_t aOffset,
                                                    uint32_t aLength);

  /**
   * Delete leading or trailing invisible white-spaces around block boundaries
   * or collapsed white-spaces in a white-space sequence if aPoint is around
   * them.
   *
   * @param aHTMLEditor The HTMLEditor.
   * @param aPoint      Point must be in an editable content node.
   * @return            If deleted some invisible white-spaces, returns the
   *                    removed point.
   *                    If this does nothing, returns unset point.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  EnsureNoInvisibleWhiteSpaces(HTMLEditor& aHTMLEditor,
                               const EditorDOMPoint& aPoint);

  /**
   * Delete preceding invisible white-spaces before aPoint.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsresult
  EnsureNoInvisibleWhiteSpacesBefore(HTMLEditor& aHTMLEditor,
                                     const EditorDOMPoint& aPoint);

  /**
   * Delete following invisible white-spaces after aPoint.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsresult
  EnsureNoInvisibleWhiteSpacesAfter(HTMLEditor& aHTMLEditor,
                                    const EditorDOMPoint& aPoint);

  /**
   * If aPoint points a collapsible white-space, normalize entire the
   * white-space sequence.
   *
   * @return Equivalent point of aPoint after normalizing the white-spaces.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<EditorDOMPoint, nsresult>
  NormalizeWhiteSpacesAt(HTMLEditor& aHTMLEditor,
                         const EditorDOMPointInText& aPoint);

  /**
   * Insert aStringToInsert to aRangeToBeReplaced.StartRef() with normalizing
   * white-spaces around there.
   *
   * @param aStringToInsert     The string to insert.
   * @param aRangeToBeReplaced  If you insert non-composing text, this MUST be
   *                            collapsed to the insertion point.
   *                            If you update composition string, this may be
   *                            not collapsed.  The range is required to
   *                            normalizing the new composition string.
   *                            Therefore, this should match the range of the
   *                            latest composition string.
   * @param aInsertTextTo       Whether forcibly creates a new `Text` node in
   *                            specific condition or use existing `Text` if
   *                            available.
   * @param aPurpose            Whether it's handling normal text input or
   *                            updating composition.
   * @param aEditingHost        The editing host at aRangeToBeReplaced.
   */

  [[nodiscard]] MOZ_CAN_RUN_SCRIPT static Result<InsertTextResult, nsresult>
  InsertTextOrInsertOrUpdateCompositionString(
      HTMLEditor& aHTMLEditor, const nsAString& aStringToInsert,
      const EditorDOMRange& aRangeToBeReplaced, InsertTextTo aInsertTextTo,
      InsertTextFor aPurpose, const Element& aEditingHost);
};

}  // namespace mozilla

#endif  // #ifndef WhiteSpaceVisibilityKeeper_h

Messung V0.5 in Prozent
C=87 H=100 G=93

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet am  2026-08-25) ¤

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