User:Uri/Bidi editing
This is currently a private draft. Come back later if you're interested.
My goals for this document are:
- Describe the fundamental issues involved in bidirectional editing.
- Give a high-level overview of how Mozilla currently tackles these isues.
- Point out some problems with the current approach.
- Present an abstract alternative approach, which I think can solve some of these problems.
- Finally, suggest how this new approach can be implemented within the current framework.
Before starting, one important note:
Mozilla currently implements what's known as visual caret movement. That is, pressing the left (right) arrow key always moves the caret one place to the left (right), regardless of the directionality of the text the caret is on, or of the paragraph directionality. This approach is also the system approach on Mac OS X (and always was on MacOS), but is not the system behaviour on Windows (which uses logical caret movement instead).
This document assumes that this approach is going to remain, i.e., it duscusses only visual caret movement. Some of the issues discussed below might be relevant to logical caret movement as well, but many aren't. If you're interested in the visual-vs-logical debate, see bug 167288.
The issues
The main issue involved in bidirectional editing is that there is no one-to-one relationship between a logical position in the text, and a visual position on the screen. A single logical position can map to two different visual positions, and a single visual position might map to two different logical positions.
In the following examples, I will use uppercase Latin letters to represent RTL (e.g. Hebrew) letters, whereas lowercase latin letters will represent LTR (e.g. Latin) letters. This seems to be the convention, as it makes it easier for people who can not read RTL languages to understand the examples.
Consider, for eample, the text with the following logical representation: latinHEBREWmore (this example diliberately ommits spaces, in order to avoid the issues associated with resolving their directionality). This text is displayed on the screen as latinWERBEHmore.
Consider the logical position between n and H. This is immediately after n, so it maps to the visual position between n and W. But it is also immediately before H, so it also maps to the visual position between H and m.
Now, consider the visual position between n and W. It is immediately after n, so it can be mapped to the logical position between n and H. But it also immediately after W, so it can also be mapped to the logical position between W and m.
Bidirectional text is stored logically, and (obviously) displayed visually. The caret, being a graphical element, corresponds to a visual location. The user can manipulate text and move the caret through a combination of logical operations (such as typing or deleting) and visual operations (such as using the arrow keys). Therefore, the problem of mapping between logical and visual positions in a way which will meet the expectations of the user is the central problem of bidirectional editing.
At this point, I would like to recommend reading Guidelines of a Logical User Interface (UI) for Editing Bidirectional Text by Matitiahu Allouche of IBM. This document presents a method for dealing with the problems associated with BiDi editing. It contains some useful definitions, as well as a detailed description of a logical-to-visual mapping algorithm (in the "Conversion of cursor positions" section). This document is the basis of the current Mozilla bidi editing implementation (which I'll describe below). I'd like to thank Simon Montagu for introducing me to this document.
The current Mozilla implementation
This section describes my understanding of the current system. It might contain inaccuracies. If you spot any, please let me know.
Mozilla represents the caret location internally as a (collapsed) selection, which consistes of:
- A logical position inside the content tree (i.e. a content node and an offset into that node).
- A "hint", which is a boolean value indicating how the caret arrived at the current location.
The "hint" mechanism was originally devised as way of indicating where to display the caret when it is at the end of a wrapping line. When arriving from the left (in LTR text), using the right arrow key, the caret should be displayed at the end of the line (after the space at which the line wraps). Pressing the right arrow key again, the caret should be moved to the beginning of the following line. Note that the caret remains in the same logical position - so this is a simple (non-bidi) case of where one logical position can be mapped to two visual positions. When bidi support was added to Mozilla, the "hint" mechanism's role expanded to handle other cases where one logical position maps to two visual positions, as described in the previous section.