| /* |
| * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FRAME_SELECTION_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FRAME_SELECTION_H_ |
| |
| #include <memory> |
| |
| #include "base/macros.h" |
| #include "base/optional.h" |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/dom/synchronous_mutation_observer.h" |
| #include "third_party/blink/renderer/core/editing/forward.h" |
| #include "third_party/blink/renderer/core/editing/set_selection_options.h" |
| #include "third_party/blink/renderer/platform/geometry/int_rect.h" |
| #include "third_party/blink/renderer/platform/geometry/layout_rect.h" |
| #include "third_party/blink/renderer/platform/heap/handle.h" |
| #include "third_party/blink/renderer/platform/scroll/scroll_alignment.h" |
| |
| namespace blink { |
| |
| class DisplayItemClient; |
| class Element; |
| class LayoutBlock; |
| class LayoutText; |
| class LocalFrame; |
| class FrameCaret; |
| class GranularityStrategy; |
| class GraphicsContext; |
| class NGPaintFragment; |
| class Range; |
| class SelectionEditor; |
| class LayoutSelection; |
| enum class SelectionModifyAlteration; |
| enum class SelectionModifyDirection; |
| enum class SelectionState; |
| class TextIteratorBehavior; |
| struct PaintInvalidatorContext; |
| |
| enum RevealExtentOption { kRevealExtent, kDoNotRevealExtent }; |
| |
| enum class CaretVisibility; |
| |
| enum class HandleVisibility { kNotVisible, kVisible }; |
| enum class SelectSoftLineBreak { kNotSelected, kSelected }; |
| |
| // This is return type of ComputeLayoutSelectionStatus(paintfragment). |
| // This structure represents how the fragment is selected. |
| // |start|, |end| : Selection start/end offset. This offset is based on |
| // the text of NGInlineNode of a parent block thus |
| // |fragemnt.StartOffset <= start <= end <= fragment.EndOffset|. |
| // |start| == |end| means this fragment is not selected. |
| // |line_break| : This value represents If this fragment is selected and |
| // selection wraps soft line break. |
| struct LayoutSelectionStatus { |
| STACK_ALLOCATED(); |
| |
| public: |
| LayoutSelectionStatus(unsigned passed_start, |
| unsigned passed_end, |
| SelectSoftLineBreak passed_line_break) |
| : start(passed_start), end(passed_end), line_break(passed_line_break) { |
| DCHECK_LE(start, end); |
| } |
| bool operator==(const LayoutSelectionStatus& other) const { |
| return start == other.start && end == other.end && |
| line_break == other.line_break; |
| } |
| |
| unsigned start; |
| unsigned end; |
| SelectSoftLineBreak line_break; |
| }; |
| |
| enum class SelectionIncludeEnd { kInclude, kNotInclude }; |
| |
| struct LayoutTextSelectionStatus { |
| STACK_ALLOCATED(); |
| |
| public: |
| LayoutTextSelectionStatus(unsigned passed_start, |
| unsigned passed_end, |
| SelectionIncludeEnd passed_include_end) |
| : start(passed_start), end(passed_end), include_end(passed_include_end) { |
| DCHECK_LE(start, end); |
| } |
| bool operator==(const LayoutTextSelectionStatus& other) const { |
| return start == other.start && end == other.end && |
| include_end == other.include_end; |
| } |
| bool IsEmpty() const { return start == 0 && end == 0; } |
| |
| unsigned start; |
| unsigned end; |
| SelectionIncludeEnd include_end; |
| }; |
| |
| class CORE_EXPORT FrameSelection final |
| : public GarbageCollectedFinalized<FrameSelection>, |
| public SynchronousMutationObserver { |
| USING_GARBAGE_COLLECTED_MIXIN(FrameSelection); |
| |
| public: |
| static FrameSelection* Create(LocalFrame& frame) { |
| return MakeGarbageCollected<FrameSelection>(frame); |
| } |
| |
| explicit FrameSelection(LocalFrame&); |
| ~FrameSelection(); |
| |
| bool IsAvailable() const { return LifecycleContext(); } |
| // You should not call |document()| when |!isAvailable()|. |
| Document& GetDocument() const; |
| LocalFrame* GetFrame() const { return frame_; } |
| Element* RootEditableElementOrDocumentElement() const; |
| size_t CharacterIndexForPoint(const IntPoint&) const; |
| |
| // An implementation of |WebFrame::moveCaretSelection()| |
| void MoveCaretSelection(const IntPoint&); |
| |
| VisibleSelection ComputeVisibleSelectionInDOMTree() const; |
| VisibleSelectionInFlatTree ComputeVisibleSelectionInFlatTree() const; |
| |
| // TODO(editing-dev): We should replace |
| // |computeVisibleSelectionInDOMTreeDeprecated()| with update layout and |
| // |computeVisibleSelectionInDOMTree()| to increase places hoisting update |
| // layout. |
| VisibleSelection ComputeVisibleSelectionInDOMTreeDeprecated() const; |
| |
| void SetSelection(const SelectionInDOMTree&, const SetSelectionOptions&); |
| void SetSelectionAndEndTyping(const SelectionInDOMTree&); |
| void SelectAll(SetSelectionBy); |
| void SelectAll(); |
| void SelectSubString(const Element&, int offset, int count); |
| void Clear(); |
| bool IsHidden() const; |
| |
| // TODO(tkent): These two functions were added to fix crbug.com/695211 without |
| // changing focus behavior. Once we fix crbug.com/690272, we can remove these |
| // functions. |
| // setSelectionDeprecated() returns true if didSetSelectionDeprecated() should |
| // be called. |
| bool SetSelectionDeprecated(const SelectionInDOMTree&, |
| const SetSelectionOptions&); |
| void DidSetSelectionDeprecated(const SetSelectionOptions&); |
| |
| // Call this after doing user-triggered selections to make it easy to delete |
| // the frame you entirely selected. |
| void SelectFrameElementInParentIfFullySelected(); |
| |
| bool Contains(const LayoutPoint&); |
| |
| bool Modify(SelectionModifyAlteration, |
| SelectionModifyDirection, |
| TextGranularity, |
| SetSelectionBy); |
| |
| // Moves the selection extent based on the selection granularity strategy. |
| // This function does not allow the selection to collapse. If the new |
| // extent is resolved to the same position as the current base, this |
| // function will do nothing. |
| void MoveRangeSelectionExtent(const IntPoint&); |
| void MoveRangeSelection(const IntPoint& base_point, |
| const IntPoint& extent_point, |
| TextGranularity); |
| |
| TextGranularity Granularity() const { return granularity_; } |
| |
| // Returns true if specified layout block should paint caret. This function is |
| // called during painting only. |
| bool ShouldPaintCaret(const LayoutBlock&) const; |
| |
| // Bounds of (possibly transformed) caret in absolute coords |
| IntRect AbsoluteCaretBounds() const; |
| |
| // Returns anchor and focus bounds in absolute coords. |
| // If the selection range is empty, returns the caret bounds. |
| // Note: this updates styles and layout, use cautiously. |
| bool ComputeAbsoluteBounds(IntRect& anchor, IntRect& focus) const; |
| |
| void DidChangeFocus(); |
| |
| SelectionInDOMTree GetSelectionInDOMTree() const; |
| bool IsDirectional() const; |
| |
| void DidAttachDocument(Document*); |
| |
| void DidLayout(); |
| void CommitAppearanceIfNeeded(); |
| void SetCaretVisible(bool caret_is_visible); |
| void ScheduleVisualUpdate() const; |
| void ScheduleVisualUpdateForPaintInvalidationIfNeeded() const; |
| |
| // Paint invalidation methods delegating to FrameCaret. |
| void ClearPreviousCaretVisualRect(const LayoutBlock&); |
| void LayoutBlockWillBeDestroyed(const LayoutBlock&); |
| void UpdateStyleAndLayoutIfNeeded(); |
| void InvalidatePaint(const LayoutBlock&, const PaintInvalidatorContext&); |
| |
| void PaintCaret(GraphicsContext&, const LayoutPoint&); |
| |
| // Used to suspend caret blinking while the mouse is down. |
| void SetCaretBlinkingSuspended(bool); |
| bool IsCaretBlinkingSuspended() const; |
| |
| // Focus |
| bool SelectionHasFocus() const; |
| void SetFrameIsFocused(bool); |
| bool FrameIsFocused() const { return focused_; } |
| bool FrameIsFocusedAndActive() const; |
| void PageActivationChanged(); |
| |
| bool IsHandleVisible() const { return is_handle_visible_; } |
| bool ShouldShrinkNextTap() const { return should_shrink_next_tap_; } |
| |
| // Returns true if a word is selected. |
| bool SelectWordAroundCaret(); |
| |
| #ifndef NDEBUG |
| void ShowTreeForThis() const; |
| #endif |
| |
| void SetFocusedNodeIfNeeded(); |
| void NotifyTextControlOfSelectionChange(SetSelectionBy); |
| |
| String SelectedHTMLForClipboard() const; |
| String SelectedText(const TextIteratorBehavior&) const; |
| String SelectedText() const; |
| String SelectedTextForClipboard() const; |
| |
| // This returns last layouted selection bounds of LayoutSelection rather than |
| // SelectionEditor keeps. |
| LayoutRect AbsoluteUnclippedBounds() const; |
| |
| // TODO(tkent): This function has a bug that scrolling doesn't work well in |
| // a case of RangeSelection. crbug.com/443061 |
| void RevealSelection( |
| const ScrollAlignment& = ScrollAlignment::kAlignCenterIfNeeded, |
| RevealExtentOption = kDoNotRevealExtent); |
| void SetSelectionFromNone(); |
| |
| void UpdateAppearance(); |
| bool ShouldShowBlockCursor() const; |
| void SetShouldShowBlockCursor(bool); |
| |
| void CacheRangeOfDocument(Range*); |
| Range* DocumentCachedRange() const; |
| void ClearDocumentCachedRange(); |
| |
| FrameCaret& FrameCaretForTesting() const { return *frame_caret_; } |
| |
| LayoutTextSelectionStatus ComputeLayoutSelectionStatus( |
| const LayoutText& text) const; |
| LayoutSelectionStatus ComputeLayoutSelectionStatus( |
| const NGPaintFragment&) const; |
| |
| void Trace(blink::Visitor*) override; |
| |
| private: |
| friend class CaretDisplayItemClientTest; |
| friend class FrameSelectionTest; |
| friend class PaintControllerPaintTestBase; |
| friend class SelectionControllerTest; |
| |
| const DisplayItemClient& CaretDisplayItemClientForTesting() const; |
| |
| // Note: We have |selectionInFlatTree()| for unit tests, we should |
| // use |visibleSelection<EditingInFlatTreeStrategy>()|. |
| VisibleSelectionInFlatTree GetSelectionInFlatTree() const; |
| |
| void NotifyAccessibilityForSelectionChange(); |
| void NotifyCompositorForSelectionChange(); |
| void NotifyEventHandlerForSelectionChange(); |
| |
| void FocusedOrActiveStateChanged(); |
| |
| GranularityStrategy* GetGranularityStrategy(); |
| |
| IntRect ComputeRectToScroll(RevealExtentOption); |
| |
| void MoveRangeSelectionInternal(const SelectionInDOMTree&, TextGranularity); |
| |
| // Implementation of |SynchronousMutationObserver| member functions. |
| void ContextDestroyed(Document*) final; |
| void NodeChildrenWillBeRemoved(ContainerNode&) final; |
| void NodeWillBeRemoved(Node&) final; |
| |
| Member<LocalFrame> frame_; |
| const Member<LayoutSelection> layout_selection_; |
| const Member<SelectionEditor> selection_editor_; |
| |
| TextGranularity granularity_; |
| LayoutUnit x_pos_for_vertical_arrow_navigation_; |
| |
| bool focused_ : 1; |
| bool is_handle_visible_ = false; |
| // TODO(editing-dev): We should change is_directional_ type to enum. |
| // as directional can have three values forward, backward or directionless. |
| bool is_directional_; |
| bool should_shrink_next_tap_ = false; |
| |
| // Controls text granularity used to adjust the selection's extent in |
| // moveRangeSelectionExtent. |
| std::unique_ptr<GranularityStrategy> granularity_strategy_; |
| |
| const Member<FrameCaret> frame_caret_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FrameSelection); |
| }; |
| |
| } // namespace blink |
| |
| #ifndef NDEBUG |
| // Outside the WebCore namespace for ease of invocation from gdb. |
| void showTree(const blink::FrameSelection&); |
| void showTree(const blink::FrameSelection*); |
| #endif |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_FRAME_SELECTION_H_ |