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