summaryrefslogtreecommitdiffstats
path: root/ui/gfx/selection_model.h
blob: 356416df9c3394fb87ec2dafe32058ef2eac5869 (plain)
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
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// 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 <string>

#include "ui/gfx/gfx_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
};
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 GFX_EXPORT 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);

  const Range& selection() const { return selection_; }
  size_t caret_pos() const { return selection_.end(); }
  LogicalCursorDirection caret_affinity() const { return caret_affinity_; }

  // WARNING: Generally the selection start should not be changed without
  // considering the effect on the caret affinity.
  void set_selection_start(size_t pos) { selection_.set_start(pos); }

  bool operator==(const SelectionModel& sel) const;
  bool operator!=(const SelectionModel& sel) const { return !(*this == sel); }

  std::string ToString() const;

 private:
  // Logical selection. The logical caret position is the end of the selection.
  Range selection_;

  // 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_;
};

}  // namespace gfx

#endif  // UI_GFX_SELECTION_MODEL_H_