chromium/third_party/blink/renderer/core/editing/editing_utilities.cc

/*
 * Copyright (C) 2004, 2005, 2006, 2007 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.
 */

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "third_party/blink/renderer/core/editing/editing_utilities.h"

#include "base/trace_event/trace_event.h"
#include "third_party/blink/renderer/core/clipboard/clipboard_mime_types.h"
#include "third_party/blink/renderer/core/clipboard/data_object.h"
#include "third_party/blink/renderer/core/clipboard/data_transfer.h"
#include "third_party/blink/renderer/core/clipboard/data_transfer_access_policy.h"
#include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/commands/editing_commands_utilities.h"
#include "third_party/blink/renderer/core/editing/editing_strategy.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/ime/edit_context.h"
#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/editing/local_caret_rect.h"
#include "third_party/blink/renderer/core/editing/plain_text_range.h"
#include "third_party/blink/renderer/core/editing/position_iterator.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
#include "third_party/blink/renderer/core/editing/state_machines/backspace_state_machine.h"
#include "third_party/blink/renderer/core/editing/state_machines/backward_grapheme_boundary_state_machine.h"
#include "third_party/blink/renderer/core/editing/state_machines/forward_grapheme_boundary_state_machine.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/editing/visible_selection.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/html/forms/text_control_element.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
#include "third_party/blink/renderer/core/html/html_br_element.h"
#include "third_party/blink/renderer/core/html/html_div_element.h"
#include "third_party/blink/renderer/core/html/html_dlist_element.h"
#include "third_party/blink/renderer/core/html/html_embed_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/html_li_element.h"
#include "third_party/blink/renderer/core/html/html_object_element.h"
#include "third_party/blink/renderer/core/html/html_olist_element.h"
#include "third_party/blink/renderer/core/html/html_paragraph_element.h"
#include "third_party/blink/renderer/core/html/html_span_element.h"
#include "third_party/blink/renderer/core/html/html_table_cell_element.h"
#include "third_party/blink/renderer/core/html/html_table_element.h"
#include "third_party/blink/renderer/core/html/html_ulist_element.h"
#include "third_party/blink/renderer/core/html/image_document.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_element_factory.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/svg/svg_image_element.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/unicode.h"

namespace blink {

FormControlType;

namespace {

std::ostream& operator<<(std::ostream& os, PositionMoveType type) {}

UChar WhitespaceRebalancingCharToAppend(const String& string,
                                        bool start_is_start_of_paragraph,
                                        bool should_emit_nbsp_before_end,
                                        wtf_size_t index,
                                        UChar previous) {}

}  // namespace

bool NeedsLayoutTreeUpdate(const Node& node) {}

template <typename PositionType>
static bool NeedsLayoutTreeUpdateAlgorithm(const PositionType& position) {}

bool NeedsLayoutTreeUpdate(const Position& position) {}

bool NeedsLayoutTreeUpdate(const PositionInFlatTree& position) {}

// Atomic means that the node has no children, or has children which are ignored
// for the purposes of editing.
bool IsAtomicNode(const Node* node) {}

bool IsAtomicNodeInFlatTree(const Node* node) {}

bool IsNodeFullyContained(const EphemeralRange& range, const Node& node) {}

// TODO(editing-dev): We should implement real version which refers
// "user-select" CSS property.
bool IsUserSelectContain(const Node& node) {}

enum EditableLevel {};
static bool HasEditableLevel(const Node& node, EditableLevel editable_level) {}

bool IsEditable(const Node& node) {}

bool IsRichlyEditable(const Node& node) {}

bool IsRootEditableElement(const Node& node) {}

Element* RootEditableElement(const Node& node) {}

ContainerNode* HighestEditableRoot(const Position& position) {}

ContainerNode* HighestEditableRoot(const PositionInFlatTree& position) {}

bool IsEditablePosition(const Position& position) {}

bool IsEditablePosition(const PositionInFlatTree& p) {}

bool IsRichlyEditablePosition(const Position& p) {}

Element* RootEditableElementOf(const Position& p) {}

Element* RootEditableElementOf(const PositionInFlatTree& p) {}

template <typename Strategy>
PositionTemplate<Strategy> NextCandidateAlgorithm(
    const PositionTemplate<Strategy>& position) {}

Position NextCandidate(const Position& position) {}

PositionInFlatTree NextCandidate(const PositionInFlatTree& position) {}

// |nextVisuallyDistinctCandidate| is similar to |nextCandidate| except
// for returning position which |downstream()| not equal to initial position's
// |downstream()|.
template <typename Strategy>
static PositionTemplate<Strategy> NextVisuallyDistinctCandidateAlgorithm(
    const PositionTemplate<Strategy>& position) {}

Position NextVisuallyDistinctCandidate(const Position& position) {}

PositionInFlatTree NextVisuallyDistinctCandidate(
    const PositionInFlatTree& position) {}

template <typename Strategy>
PositionTemplate<Strategy> PreviousCandidateAlgorithm(
    const PositionTemplate<Strategy>& position) {}

Position PreviousCandidate(const Position& position) {}

PositionInFlatTree PreviousCandidate(const PositionInFlatTree& position) {}

// |previousVisuallyDistinctCandidate| is similar to |previousCandidate| except
// for returning position which |downstream()| not equal to initial position's
// |downstream()|.
template <typename Strategy>
PositionTemplate<Strategy> PreviousVisuallyDistinctCandidateAlgorithm(
    const PositionTemplate<Strategy>& position) {}

Position PreviousVisuallyDistinctCandidate(const Position& position) {}

PositionInFlatTree PreviousVisuallyDistinctCandidate(
    const PositionInFlatTree& position) {}

template <typename Strategy>
PositionTemplate<Strategy> FirstEditablePositionAfterPositionInRootAlgorithm(
    const PositionTemplate<Strategy>& position,
    const Node& highest_root) {}

Position FirstEditablePositionAfterPositionInRoot(const Position& position,
                                                  const Node& highest_root) {}

PositionInFlatTree FirstEditablePositionAfterPositionInRoot(
    const PositionInFlatTree& position,
    const Node& highest_root) {}

template <typename Strategy>
PositionTemplate<Strategy> LastEditablePositionBeforePositionInRootAlgorithm(
    const PositionTemplate<Strategy>& position,
    const Node& highest_root) {}

Position LastEditablePositionBeforePositionInRoot(const Position& position,
                                                  const Node& highest_root) {}

PositionInFlatTree LastEditablePositionBeforePositionInRoot(
    const PositionInFlatTree& position,
    const Node& highest_root) {}

template <typename StateMachine>
int FindNextBoundaryOffset(const String& str, int current) {}

// Explicit instantiation to avoid link error for the usage in EditContext.
template int FindNextBoundaryOffset<BackwardGraphemeBoundaryStateMachine>(
    const String& str,
    int current);
template int FindNextBoundaryOffset<ForwardGraphemeBoundaryStateMachine>(
    const String& str,
    int current);

int PreviousGraphemeBoundaryOf(const Node& node, int current) {}

static int PreviousBackwardDeletionOffsetOf(const Node& node, int current) {}

int NextGraphemeBoundaryOf(const Node& node, int current) {}

template <typename Strategy>
PositionTemplate<Strategy> PreviousPositionOfAlgorithm(
    const PositionTemplate<Strategy>& position,
    PositionMoveType move_type) {}

Position PreviousPositionOf(const Position& position,
                            PositionMoveType move_type) {}

PositionInFlatTree PreviousPositionOf(const PositionInFlatTree& position,
                                      PositionMoveType move_type) {}

template <typename Strategy>
PositionTemplate<Strategy> NextPositionOfAlgorithm(
    const PositionTemplate<Strategy>& position,
    PositionMoveType move_type) {}

Position NextPositionOf(const Position& position, PositionMoveType move_type) {}

PositionInFlatTree NextPositionOf(const PositionInFlatTree& position,
                                  PositionMoveType move_type) {}

bool IsEnclosingBlock(const Node* node) {}

// TODO(yosin) Deploy this in all of the places where |enclosingBlockFlow()| and
// |enclosingBlockFlowOrTableElement()| are used.
// TODO(yosin) Callers of |Node| version of |enclosingBlock()| should use
// |Position| version The enclosing block of [table, x] for example, should be
// the block that contains the table and not the table, and this function should
// be the only one responsible for knowing about these kinds of special cases.
Element* EnclosingBlock(const Node* node, EditingBoundaryCrossingRule rule) {}

template <typename Strategy>
Element* EnclosingBlockAlgorithm(const PositionTemplate<Strategy>& position,
                                 EditingBoundaryCrossingRule rule) {}

Element* EnclosingBlock(const Position& position,
                        EditingBoundaryCrossingRule rule) {}

Element* EnclosingBlock(const PositionInFlatTree& position,
                        EditingBoundaryCrossingRule rule) {}

Element* EnclosingBlockFlowElement(const Node& node) {}

template <typename Strategy>
TextDirection DirectionOfEnclosingBlockOfAlgorithm(
    const PositionTemplate<Strategy>& position) {}

TextDirection DirectionOfEnclosingBlockOf(const Position& position) {}

TextDirection DirectionOfEnclosingBlockOf(const PositionInFlatTree& position) {}

TextDirection PrimaryDirectionOf(const Node& node) {}

String StringWithRebalancedWhitespace(const String& string,
                                      bool start_is_start_of_paragraph,
                                      bool should_emit_nbs_pbefore_end) {}

String RepeatString(const String& string, unsigned count) {}

template <typename Strategy>
static Element* TableElementJustBeforeAlgorithm(
    const VisiblePositionTemplate<Strategy>& visible_position) {}

Element* TableElementJustBefore(const VisiblePosition& visible_position) {}

Element* TableElementJustBefore(
    const VisiblePositionInFlatTree& visible_position) {}

Element* EnclosingTableCell(const Position& p) {}
Element* EnclosingTableCell(const PositionInFlatTree& p) {}

Element* TableElementJustAfter(const VisiblePosition& visible_position) {}

// Returns the position at the beginning of a node
Position PositionBeforeNode(const Node& node) {}

// Returns the position at the ending of a node
Position PositionAfterNode(const Node& node) {}

bool IsHTMLListElement(const Node* n) {}

bool IsListItem(const Node* n) {}

bool IsListItemTag(const Node* n) {}

bool IsListElementTag(const Node* n) {}

bool IsPresentationalHTMLElement(const Node* node) {}

Element* AssociatedElementOf(const Position& position) {}

Element* EnclosingElementWithTag(const Position& p,
                                 const QualifiedName& tag_name) {}

template <typename Strategy>
static Node* EnclosingNodeOfTypeAlgorithm(const PositionTemplate<Strategy>& p,
                                          bool (*node_is_of_type)(const Node*),
                                          EditingBoundaryCrossingRule rule) {}

Node* EnclosingNodeOfType(const Position& p,
                          bool (*node_is_of_type)(const Node*),
                          EditingBoundaryCrossingRule rule) {}

Node* EnclosingNodeOfType(const PositionInFlatTree& p,
                          bool (*node_is_of_type)(const Node*),
                          EditingBoundaryCrossingRule rule) {}

Node* HighestEnclosingNodeOfType(const Position& p,
                                 bool (*node_is_of_type)(const Node*),
                                 EditingBoundaryCrossingRule rule,
                                 Node* stay_within) {}

Element* EnclosingAnchorElement(const Position& p) {}

bool IsDisplayInsideTable(const Node* node) {}

bool IsTableCell(const Node* node) {}

HTMLElement* CreateDefaultParagraphElement(Document& document) {}

bool IsTabHTMLSpanElement(const Node* node) {}

bool IsTabHTMLSpanElementTextNode(const Node* node) {}

HTMLSpanElement* TabSpanElement(const Node* node) {}

static HTMLSpanElement* CreateTabSpanElement(Document& document,
                                             Text* tab_text_node) {}

HTMLSpanElement* CreateTabSpanElement(Document& document,
                                      const String& tab_text) {}

HTMLSpanElement* CreateTabSpanElement(Document& document) {}

static bool IsInPlaceholder(const TextControlElement& text_control,
                            const Position& position) {}

// Returns user-select:contain boundary element of specified position.
// Because of we've not yet implemented "user-select:contain", we consider
// following elements having "user-select:contain"
//  - root editable
//  - inner editor of text control (<input> and <textarea>)
// Note: inner editor of readonly text control isn't content editable.
// TODO(yosin): We should handle elements with "user-select:contain".
// See http:/crbug.com/658129
static Element* UserSelectContainBoundaryOf(const Position& position) {}

PositionWithAffinity PositionRespectingEditingBoundary(
    const Position& position,
    const HitTestResult& hit_test_result) {}

PositionWithAffinity AdjustForEditingBoundary(
    const PositionWithAffinity& position_with_affinity) {}

PositionWithAffinity AdjustForEditingBoundary(const Position& position) {}

Position ComputePlaceholderToCollapseAt(const Position& insertion_pos) {}

Position ComputePositionForNodeRemoval(const Position& position,
                                       const Node& node) {}

bool IsMailHTMLBlockquoteElement(const Node* node) {}

bool ElementCannotHaveEndTag(const Node& node) {}

// FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators
// to convert between VisiblePositions and indices. But TextIterator iteration
// using TextIteratorEmitsCharactersBetweenAllVisiblePositions does not exactly
// match VisiblePosition iteration, so using them to preserve a selection during
// an editing opertion is unreliable. TextIterator's
// TextIteratorEmitsCharactersBetweenAllVisiblePositions mode needs to be fixed,
// or these functions need to be changed to iterate using actual
// VisiblePositions.
// FIXME: Deploy these functions everywhere that TextIterators are used to
// convert between VisiblePositions and indices.
int IndexForVisiblePosition(const VisiblePosition& visible_position,
                            ContainerNode*& scope) {}

EphemeralRange MakeRange(const VisiblePosition& start,
                         const VisiblePosition& end) {}

template <typename Strategy>
static EphemeralRangeTemplate<Strategy> NormalizeRangeAlgorithm(
    const EphemeralRangeTemplate<Strategy>& range) {}

EphemeralRange NormalizeRange(const EphemeralRange& range) {}

EphemeralRangeInFlatTree NormalizeRange(const EphemeralRangeInFlatTree& range) {}

VisiblePosition VisiblePositionForIndex(int index, ContainerNode* scope) {}

template <typename Strategy>
bool AreSameRangesAlgorithm(Node* node,
                            const PositionTemplate<Strategy>& start_position,
                            const PositionTemplate<Strategy>& end_position) {}

bool AreSameRanges(Node* node,
                   const Position& start_position,
                   const Position& end_position) {}

bool AreSameRanges(Node* node,
                   const PositionInFlatTree& start_position,
                   const PositionInFlatTree& end_position) {}

bool IsRenderedAsNonInlineTableImageOrHR(const Node* node) {}

bool IsNonTableCellHTMLBlockElement(const Node* node) {}

bool IsBlockFlowElement(const Node& node) {}

bool IsInPasswordField(const Position& position) {}

// If current position is at grapheme boundary, return 0; otherwise, return the
// distance to its nearest left grapheme boundary.
wtf_size_t ComputeDistanceToLeftGraphemeBoundary(const Position& position) {}

// If current position is at grapheme boundary, return 0; otherwise, return the
// distance to its nearest right grapheme boundary.
wtf_size_t ComputeDistanceToRightGraphemeBoundary(const Position& position) {}

gfx::QuadF LocalToAbsoluteQuadOf(const LocalCaretRect& caret_rect) {}

const StaticRangeVector* TargetRangesForInputEvent(const Node& node) {}

DispatchEventResult DispatchBeforeInputInsertText(
    Node* target,
    const String& data,
    InputEvent::InputType input_type,
    const StaticRangeVector* ranges) {}

DispatchEventResult DispatchBeforeInputEditorCommand(
    Node* target,
    InputEvent::InputType input_type,
    const StaticRangeVector* ranges) {}

DispatchEventResult DispatchBeforeInputDataTransfer(
    Node* target,
    InputEvent::InputType input_type,
    DataTransfer* data_transfer) {}

void InsertTextAndSendInputEventsOfTypeInsertReplacementText(
    LocalFrame& frame,
    const String& replacement,
    bool allow_edit_context) {}

// |IsEmptyNonEditableNodeInEditable()| is introduced for fixing
// http://crbug.com/428986.
static bool IsEmptyNonEditableNodeInEditable(const Node& node) {}

// TODO(yosin): We should not use |IsEmptyNonEditableNodeInEditable()| in
// |EditingIgnoresContent()| since |IsEmptyNonEditableNodeInEditable()|
// requires clean layout tree.
bool EditingIgnoresContent(const Node& node) {}

ContainerNode* RootEditableElementOrTreeScopeRootNodeOf(
    const Position& position) {}

static scoped_refptr<Image> ImageFromNode(const Node& node) {}

AtomicString GetUrlStringFromNode(const Node& node) {}

void WriteImageToClipboard(SystemClipboard& system_clipboard,
                           const scoped_refptr<Image>& image,
                           const KURL& url_string,
                           const String& title) {}

void WriteImageNodeToClipboard(SystemClipboard& system_clipboard,
                               const Node& node,
                               const String& title) {}

Element* FindEventTargetFrom(LocalFrame& frame,
                             const VisibleSelection& selection) {}

HTMLImageElement* ImageElementFromImageDocument(const Document* document) {}

}  // namespace blink