blob: 70357536276352b21ff439cc1de78027dda6cf81 [file] [log] [blame]
/*
* Copyright (C) 2004, 2006, 2009 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 TextIterator_h
#define TextIterator_h
#include "core/CoreExport.h"
#include "core/dom/Range.h"
#include "core/editing/Forward.h"
#include "core/editing/finder/FindOptions.h"
#include "core/editing/iterators/FullyClippedStateStack.h"
#include "core/editing/iterators/TextIteratorBehavior.h"
#include "core/editing/iterators/TextIteratorTextNodeHandler.h"
#include "core/editing/iterators/TextIteratorTextState.h"
#include "platform/heap/Handle.h"
namespace blink {
CORE_EXPORT String
PlainText(const EphemeralRange&,
const TextIteratorBehavior& = TextIteratorBehavior());
String PlainText(const EphemeralRangeInFlatTree&,
const TextIteratorBehavior& = TextIteratorBehavior());
// Iterates through the DOM range, returning all the text, and 0-length
// boundaries at points where replaced elements break up the text flow. The
// text comes back in chunks so as to optimize for performance of the iteration.
template <typename Strategy>
class CORE_TEMPLATE_CLASS_EXPORT TextIteratorAlgorithm {
STACK_ALLOCATED();
public:
// [start, end] indicates the document range that the iteration should take
// place within (both ends inclusive).
TextIteratorAlgorithm(const PositionTemplate<Strategy>& start,
const PositionTemplate<Strategy>& end,
const TextIteratorBehavior& = TextIteratorBehavior());
// Same behavior as previous constructor but takes an EphemeralRange instead
// of two Positions
TextIteratorAlgorithm(const EphemeralRangeTemplate<Strategy>&,
const TextIteratorBehavior& = TextIteratorBehavior());
~TextIteratorAlgorithm();
bool AtEnd() const { return !text_state_.PositionNode() || should_stop_; }
void Advance();
bool IsInsideAtomicInlineElement() const;
EphemeralRangeTemplate<Strategy> Range() const;
Node* GetNode() const;
Document* OwnerDocument() const;
Node* CurrentContainer() const;
int StartOffsetInCurrentContainer() const;
int EndOffsetInCurrentContainer() const;
PositionTemplate<Strategy> StartPositionInCurrentContainer() const;
PositionTemplate<Strategy> EndPositionInCurrentContainer() const;
const TextIteratorTextState& GetText() const { return text_state_; }
int length() const { return text_state_.length(); }
UChar CharacterAt(unsigned index) const {
return text_state_.CharacterAt(index);
}
bool BreaksAtReplacedElement() {
return !behavior_.DoesNotBreakAtReplacedElement();
}
// Calculate the minimum |actualLength >= minLength| such that code units
// with offset range [position, position + actualLength) are whole code
// points. Append these code points to |output| and return |actualLength|.
int CopyTextTo(ForwardsTextBuffer* output,
int position,
int min_length) const;
int CopyTextTo(ForwardsTextBuffer* output, int position = 0) const;
// Computes the length of the given range using a text iterator according to
// the specified iteration behavior. The default iteration behavior is to
// always emit object replacement characters for replaced elements.
// TODO(editing-dev): We should remove start/end version of |RangeLength()|.
static int RangeLength(
const PositionTemplate<Strategy>& start,
const PositionTemplate<Strategy>& end,
const TextIteratorBehavior& =
TextIteratorBehavior::DefaultRangeLengthBehavior());
static int RangeLength(
const EphemeralRangeTemplate<Strategy>&,
const TextIteratorBehavior& =
TextIteratorBehavior::DefaultRangeLengthBehavior());
static bool ShouldEmitTabBeforeNode(Node*);
static bool ShouldEmitNewlineBeforeNode(Node&);
static bool ShouldEmitNewlineAfterNode(Node&);
static bool ShouldEmitNewlineForNode(Node*, bool emits_original_text);
static bool SupportsAltText(Node*);
private:
enum IterationProgress {
kHandledNone,
kHandledOpenShadowRoots,
kHandledUserAgentShadowRoot,
kHandledNode,
kHandledChildren
};
void ExitNode();
bool ShouldRepresentNodeOffsetZero();
bool ShouldEmitSpaceBeforeAndAfterNode(Node*);
void RepresentNodeOffsetZero();
// Returns true if text is emitted from the remembered progress (if any).
bool HandleRememberedProgress();
void HandleTextNode();
void HandleReplacedElement();
void HandleNonTextNode();
void SpliceBuffer(UChar,
Node* text_node,
Node* offset_base_node,
unsigned text_start_offset,
unsigned text_end_offset);
// Used by selection preservation code. There should be one character emitted
// between every VisiblePosition in the Range used to create the TextIterator.
// FIXME <rdar://problem/6028818>: This functionality should eventually be
// phased out when we rewrite moveParagraphs to not clone/destroy moved
// content.
bool EmitsCharactersBetweenAllVisiblePositions() const {
return behavior_.EmitsCharactersBetweenAllVisiblePositions();
}
bool EntersTextControls() const { return behavior_.EntersTextControls(); }
// Used in pasting inside password field.
bool EmitsOriginalText() const { return behavior_.EmitsOriginalText(); }
// Used when the visibility of the style should not affect text gathering.
bool IgnoresStyleVisibility() const {
return behavior_.IgnoresStyleVisibility();
}
// Used when the iteration should stop if form controls are reached.
bool StopsOnFormControls() const { return behavior_.StopsOnFormControls(); }
bool EmitsImageAltText() const { return behavior_.EmitsImageAltText(); }
bool EntersOpenShadowRoots() const {
return behavior_.EntersOpenShadowRoots();
}
bool EmitsObjectReplacementCharacter() const {
return behavior_.EmitsObjectReplacementCharacter();
}
bool ExcludesAutofilledValue() const {
return behavior_.ExcludeAutofilledValue();
}
bool DoesNotBreakAtReplacedElement() const {
return behavior_.DoesNotBreakAtReplacedElement();
}
// Clipboard should respect user-select style attribute
bool SkipsUnselectableContent() const {
return behavior_.SkipsUnselectableContent();
}
bool ForInnerText() const { return behavior_.ForInnerText(); }
bool IsBetweenSurrogatePair(unsigned position) const;
// Append code units with offset range [position, position + copyLength)
// to the output buffer.
void CopyCodeUnitsTo(ForwardsTextBuffer* output,
unsigned position,
unsigned copy_length) const;
// The range.
const Member<Node> start_container_;
const unsigned start_offset_;
const Member<Node> end_container_;
const unsigned end_offset_;
// |m_endNode| stores |Strategy::childAt(*m_endContainer, m_endOffset - 1)|,
// if it exists, or |nullptr| otherwise.
const Member<Node> end_node_;
const Member<Node> past_end_node_;
// Current position, not necessarily of the text being returned, but position
// as we walk through the DOM tree.
Member<Node> node_;
IterationProgress iteration_progress_;
FullyClippedStateStackAlgorithm<Strategy> fully_clipped_stack_;
unsigned shadow_depth_;
// Used when there is still some pending text from the current node; when
// these are false, we go back to normal iterating.
bool needs_another_newline_ = false;
bool needs_handle_replaced_element_ = false;
Member<Text> last_text_node_;
const TextIteratorBehavior behavior_;
// Used when stopsOnFormControls() is true to determine if the iterator should
// keep advancing.
bool should_stop_ = false;
// Used for use counter |InnerTextWithShadowTree| and
// |SelectionToStringWithShadowTree|, we should not use other purpose.
bool handle_shadow_root_ = false;
// Contains state of emitted text.
TextIteratorTextState text_state_;
// Helper for extracting text content from text nodes.
TextIteratorTextNodeHandler text_node_handler_;
};
extern template class CORE_EXTERN_TEMPLATE_EXPORT
TextIteratorAlgorithm<EditingStrategy>;
extern template class CORE_EXTERN_TEMPLATE_EXPORT
TextIteratorAlgorithm<EditingInFlatTreeStrategy>;
using TextIterator = TextIteratorAlgorithm<EditingStrategy>;
using TextIteratorInFlatTree = TextIteratorAlgorithm<EditingInFlatTreeStrategy>;
} // namespace blink
#endif // TextIterator_h