Home | History | Annotate | Download | only in gfx
      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 
     72   const Range& selection() const { return selection_; }
     73   size_t caret_pos() const { return selection_.end(); }
     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.
     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