blob: 92b5d9898c0c40232be17869a34466f6e00301a8 [file] [log] [blame]
/*
* Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CompositeEditCommand_h
#define CompositeEditCommand_h
#include "core/CSSPropertyNames.h"
#include "core/CoreExport.h"
#include "core/editing/commands/EditCommand.h"
#include "core/editing/commands/EditingState.h"
#include "core/editing/commands/UndoStep.h"
#include "wtf/Vector.h"
namespace blink {
class EditingStyle;
class Element;
class HTMLBRElement;
class HTMLElement;
class HTMLSpanElement;
class Text;
class EditCommandComposition final : public UndoStep {
public:
static EditCommandComposition* create(Document*,
const VisibleSelection&,
const VisibleSelection&,
InputEvent::InputType);
bool belongsTo(const LocalFrame&) const override;
void unapply() override;
void reapply() override;
InputEvent::InputType inputType() const override;
void append(SimpleEditCommand*);
void append(EditCommandComposition*);
const VisibleSelection& startingSelection() const {
return m_startingSelection;
}
const VisibleSelection& endingSelection() const { return m_endingSelection; }
void setStartingSelection(const VisibleSelection&);
void setEndingSelection(const VisibleSelection&);
Element* startingRootEditableElement() const {
return m_startingRootEditableElement.get();
}
Element* endingRootEditableElement() const {
return m_endingRootEditableElement.get();
}
DECLARE_VIRTUAL_TRACE();
private:
EditCommandComposition(Document*,
const VisibleSelection& startingSelection,
const VisibleSelection& endingSelection,
InputEvent::InputType);
Member<Document> m_document;
VisibleSelection m_startingSelection;
VisibleSelection m_endingSelection;
HeapVector<Member<SimpleEditCommand>> m_commands;
Member<Element> m_startingRootEditableElement;
Member<Element> m_endingRootEditableElement;
InputEvent::InputType m_inputType;
};
class CORE_EXPORT CompositeEditCommand : public EditCommand {
public:
enum ShouldPreserveSelection { PreserveSelection, DoNotPreserveSelection };
enum ShouldPreserveStyle { PreserveStyle, DoNotPreserveStyle };
~CompositeEditCommand() override;
// Returns |false| if the command failed. e.g. It's aborted.
bool apply();
bool isFirstCommand(EditCommand* command) {
return !m_commands.isEmpty() && m_commands.first() == command;
}
EditCommandComposition* composition() { return m_composition.get(); }
EditCommandComposition* ensureComposition();
// Append composition from an already applied command.
void appendCommandToComposite(CompositeEditCommand*);
virtual bool isReplaceSelectionCommand() const;
virtual bool isTypingCommand() const;
virtual bool isCommandGroupWrapper() const;
virtual bool isDragAndDropCommand() const;
virtual bool preservesTypingStyle() const;
virtual void setShouldRetainAutocorrectionIndicator(bool);
virtual bool shouldStopCaretBlinking() const { return false; }
DECLARE_VIRTUAL_TRACE();
protected:
explicit CompositeEditCommand(Document&);
//
// sugary-sweet convenience functions to help create and apply edit commands
// in composite commands
//
void appendNode(Node*, ContainerNode* parent, EditingState*);
void applyCommandToComposite(EditCommand*, EditingState*);
void applyCommandToComposite(CompositeEditCommand*,
const VisibleSelection&,
EditingState*);
void applyStyle(const EditingStyle*, EditingState*);
void applyStyle(const EditingStyle*,
const Position& start,
const Position& end,
EditingState*);
void applyStyledElement(Element*, EditingState*);
void removeStyledElement(Element*, EditingState*);
void deleteSelection(EditingState*,
bool smartDelete = false,
bool mergeBlocksAfterDelete = true,
bool expandForSpecialElements = true,
bool sanitizeMarkup = true);
void deleteSelection(const VisibleSelection&,
EditingState*,
bool smartDelete = false,
bool mergeBlocksAfterDelete = true,
bool expandForSpecialElements = true,
bool sanitizeMarkup = true);
virtual void deleteTextFromNode(Text*, unsigned offset, unsigned count);
bool isRemovableBlock(const Node*);
void insertNodeAfter(Node*, Node* refChild, EditingState*);
void insertNodeAt(Node*, const Position&, EditingState*);
void insertNodeAtTabSpanPosition(Node*, const Position&, EditingState*);
void insertNodeBefore(
Node*,
Node* refChild,
EditingState*,
ShouldAssumeContentIsAlwaysEditable = DoNotAssumeContentIsAlwaysEditable);
void insertParagraphSeparator(EditingState*,
bool useDefaultParagraphElement = false,
bool pasteBlockqutoeIntoUnquotedArea = false);
void insertTextIntoNode(Text*, unsigned offset, const String& text);
void mergeIdenticalElements(Element*, Element*, EditingState*);
void rebalanceWhitespace();
void rebalanceWhitespaceAt(const Position&);
void rebalanceWhitespaceOnTextSubstring(Text*,
int startOffset,
int endOffset);
void prepareWhitespaceAtPositionForSplit(Position&);
void replaceCollapsibleWhitespaceWithNonBreakingSpaceIfNeeded(
const VisiblePosition&);
bool canRebalance(const Position&) const;
bool shouldRebalanceLeadingWhitespaceFor(const String&) const;
void removeCSSProperty(Element*, CSSPropertyID);
void removeElementAttribute(Element*, const QualifiedName& attribute);
void removeChildrenInRange(Node*, unsigned from, unsigned to, EditingState*);
virtual void removeNode(
Node*,
EditingState*,
ShouldAssumeContentIsAlwaysEditable = DoNotAssumeContentIsAlwaysEditable);
HTMLSpanElement* replaceElementWithSpanPreservingChildrenAndAttributes(
HTMLElement*);
void removeNodePreservingChildren(
Node*,
EditingState*,
ShouldAssumeContentIsAlwaysEditable = DoNotAssumeContentIsAlwaysEditable);
void removeNodeAndPruneAncestors(Node*,
EditingState*,
Node* excludeNode = nullptr);
void moveRemainingSiblingsToNewParent(Node*,
Node* pastLastNodeToMove,
Element* newParent,
EditingState*);
void updatePositionForNodeRemovalPreservingChildren(Position&, Node&);
void prune(Node*, EditingState*, Node* excludeNode = nullptr);
void replaceTextInNode(Text*,
unsigned offset,
unsigned count,
const String& replacementText);
Position replaceSelectedTextInNode(const String&);
void replaceTextInNodePreservingMarkers(Text*,
unsigned offset,
unsigned count,
const String& replacementText);
Position positionOutsideTabSpan(const Position&);
void setNodeAttribute(Element*,
const QualifiedName& attribute,
const AtomicString& value);
void splitElement(Element*, Node* atChild);
void splitTextNode(Text*, unsigned offset);
void splitTextNodeContainingElement(Text*, unsigned offset);
void wrapContentsInDummySpan(Element*);
void deleteInsignificantText(Text*, unsigned start, unsigned end);
void deleteInsignificantText(const Position& start, const Position& end);
void deleteInsignificantTextDownstream(const Position&);
HTMLBRElement* appendBlockPlaceholder(Element*, EditingState*);
HTMLBRElement* insertBlockPlaceholder(const Position&, EditingState*);
HTMLBRElement* addBlockPlaceholderIfNeeded(Element*, EditingState*);
void removePlaceholderAt(const Position&);
HTMLElement* insertNewDefaultParagraphElementAt(const Position&,
EditingState*);
HTMLElement* moveParagraphContentsToNewBlockIfNecessary(const Position&,
EditingState*);
void pushAnchorElementDown(Element*, EditingState*);
void moveParagraph(const VisiblePosition&,
const VisiblePosition&,
const VisiblePosition&,
EditingState*,
ShouldPreserveSelection = DoNotPreserveSelection,
ShouldPreserveStyle = PreserveStyle,
Node* constrainingAncestor = nullptr);
void moveParagraphs(const VisiblePosition&,
const VisiblePosition&,
const VisiblePosition&,
EditingState*,
ShouldPreserveSelection = DoNotPreserveSelection,
ShouldPreserveStyle = PreserveStyle,
Node* constrainingAncestor = nullptr);
void moveParagraphWithClones(const VisiblePosition& startOfParagraphToMove,
const VisiblePosition& endOfParagraphToMove,
HTMLElement* blockElement,
Node* outerNode,
EditingState*);
void cloneParagraphUnderNewElement(const Position& start,
const Position& end,
Node* outerNode,
Element* blockElement,
EditingState*);
void cleanupAfterDeletion(EditingState*,
VisiblePosition destination = VisiblePosition());
bool breakOutOfEmptyListItem(EditingState*);
bool breakOutOfEmptyMailBlockquotedParagraph(EditingState*);
Position positionAvoidingSpecialElementBoundary(const Position&,
EditingState*);
Node* splitTreeToNode(Node*, Node*, bool splitAncestor = false);
HeapVector<Member<EditCommand>> m_commands;
private:
bool isCompositeEditCommand() const final { return true; }
Member<EditCommandComposition> m_composition;
};
DEFINE_TYPE_CASTS(CompositeEditCommand,
EditCommand,
command,
command->isCompositeEditCommand(),
command.isCompositeEditCommand());
} // namespace blink
#endif // CompositeEditCommand_h