1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_SELECTION_MODEL_H_
#define UI_GFX_SELECTION_MODEL_H_
#include <stddef.h>
#include <iosfwd>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "ui/gfx/range/range.h"
namespace gfx {
// VisualCursorDirection and LogicalCursorDirection represent directions of
// motion of the cursor in BiDi text. The combinations that make sense are:
//
// base::i18n::TextDirection VisualCursorDirection LogicalCursorDirection
// LEFT_TO_RIGHT CURSOR_LEFT CURSOR_BACKWARD
// LEFT_TO_RIGHT CURSOR_RIGHT CURSOR_FORWARD
// RIGHT_TO_LEFT CURSOR_RIGHT CURSOR_BACKWARD
// RIGHT_TO_LEFT CURSOR_LEFT CURSOR_FORWARD
enum VisualCursorDirection {
CURSOR_LEFT,
CURSOR_RIGHT,
CURSOR_UP,
CURSOR_DOWN
};
enum LogicalCursorDirection {
CURSOR_BACKWARD,
CURSOR_FORWARD
};
// TODO(xji): publish bidi-editing guide line and replace the place holder.
// SelectionModel is used to represent the logical selection and visual
// position of cursor.
//
// For bi-directional text, the mapping between visual position and logical
// position is not one-to-one. For example, logical text "abcDEF" where capital
// letters stand for Hebrew, the visual display is "abcFED". According to the
// bidi editing guide (http://bidi-editing-guideline):
// 1. If pointing to the right half of the cell of a LTR character, the current
// position must be set after this character and the caret must be displayed
// after this character.
// 2. If pointing to the right half of the cell of a RTL character, the current
// position must be set before this character and the caret must be displayed
// before this character.
//
// Pointing to the right half of 'c' and pointing to the right half of 'D' both
// set the logical cursor position to 3. But the cursor displayed visually at
// different places:
// Pointing to the right half of 'c' displays the cursor right of 'c' as
// "abc|FED".
// Pointing to the right half of 'D' displays the cursor right of 'D' as
// "abcFED|".
// So, besides the logical selection start point and end point, we need extra
// information to specify to which character the visual cursor is bound. This
// is given by a "caret affinity" which is either CURSOR_BACKWARD (indicating
// the trailing half of the 'c' in this case) or CURSOR_FORWARD (indicating
// the leading half of the 'D').
class COMPONENT_EXPORT(GFX) SelectionModel {
public:
// Create a default SelectionModel to be overwritten later.
SelectionModel();
// Create a SelectionModel representing a caret |position| without a
// selection. The |affinity| is meaningful only when the caret is positioned
// between bidi runs that are not visually contiguous: in that case, it
// indicates the run to which the caret is attached for display purposes.
SelectionModel(size_t position, LogicalCursorDirection affinity);
// Create a SelectionModel representing a selection (which may be empty).
// The caret position is the end of the range.
SelectionModel(const Range& selection, LogicalCursorDirection affinity);
// Create a SelectionModel representing multiple selections (which may be
// empty but not overlapping). The end of the first range determines the caret
// position.
SelectionModel(const std::vector<Range>& selections,
LogicalCursorDirection affinity);
SelectionModel(const SelectionModel& selection_model);
~SelectionModel();
// |selection| should overlap with neither |selection_| nor
// |secondary_selections_|.
void AddSecondarySelection(const Range& selection);
const Range& selection() const { return selection_; }
size_t caret_pos() const { return selection_.end(); }
LogicalCursorDirection caret_affinity() const { return caret_affinity_; }
const std::vector<Range>& secondary_selections() const {
return secondary_selections_;
}
std::vector<Range> GetAllSelections() const;
// WARNING: Generally the selection start should not be changed without
// considering the effect on the caret affinity.
void set_selection_start(uint32_t pos) { selection_.set_start(pos); }
friend bool operator==(const SelectionModel&,
const SelectionModel&) = default;
std::string ToString() const;
private:
// Logical selection. The logical caret position is the end of the selection.
Range selection_;
// Secondary selections not associated with the cursor. Do not overlap.
std::vector<Range> secondary_selections_;
// The logical direction from the caret position (selection_.end()) to the
// character it is attached to for display purposes. This matters only when
// the surrounding characters are not visually contiguous, which happens only
// in bidi text (and only at bidi run boundaries). The text is treated as
// though it was surrounded on both sides by runs in the dominant text
// direction. For example, supposing the dominant direction is LTR and the
// logical text is "abcDEF", where DEF is right-to-left text, the visual
// cursor will display as follows:
// caret position CURSOR_BACKWARD affinity CURSOR_FORWARD affinity
// 0 |abcFED |abcFED
// 1 a|bcFED a|bcFED
// 2 ab|cFED ab|cFED
// 3 abc|FED abcFED|
// 4 abcFE|D abcFE|D
// 5 abcF|ED abcF|ED
// 6 abc|FED abcFED|
LogicalCursorDirection caret_affinity_;
};
COMPONENT_EXPORT(GFX)
std::ostream& operator<<(std::ostream& out, const SelectionModel& model);
} // namespace gfx
#endif // UI_GFX_SELECTION_MODEL_H_
|