io7m | single-page | multi-page | JSycamore User Manual
3.1. Menus
Previous
3. Standard Components
Up
3.3. Buttons
Next

# 3.2. Text

- 3.2.1. Description
- 3.2.2. Text Sections
- 3.2.3. Font
- 3.2.4. Font Services
- 3.2.5. Measured Lines
- 3.2.6. Text Models
  - 3.2.6.1. Overview
  - 3.2.6.2. Multi-Line Model
    - 3.2.6.2.1. Description
    - 3.2.6.2.2. Selection
  - 3.2.6.3. Single-Line Model
    - 3.2.6.3.1. Description
    - 3.2.6.3.2. Selection

## 3.2.1. Description

1
The text components are a family of components that provide the ability to display, format, select, and modify text.

### 3.2.1.2. Text Area

## 3.2.2. Text Sections

1
The jsycamore package works in terms of immutable text sections. The concept of a text section is rather loosely defined, but it can be most easily thought of as representing a single paragraph of text. Each text section has an associated text direction indicating that the text is in a left-to-right language (such as English), or that the text is in a right-to-left language (such as Arabic, or Hebrew). There is currently no support for mixing directions within a single text section, although having many text sections with varying directions inside a single text view is fully supported.

### 3.2.2.2. Mixed Text Area

## 3.2.3. Font

1
A font defines the appearance and (ultimately) the layout of text. A font combines a typeface, a size, and a style (such as bold, italic, etc).
2
Fonts contain all the information required to determine what the bounding box will be for a given piece of text, and much more detailed information not limited to the widths and heights of individual characters. It is for this reason that fonts are considered to be an essential part of the layout of a given piece of text rather than just part of its appearance: A text view might be sized correctly for a specific piece of text using font F, but might be woefully undersized for the same piece of text using font G. The font interface exposes text formatting methods that can take a text section and a page width, and return a set of one or more measured lines that represent the original text section broken into lines using the given page width as a maximum line length. This line wrapping functionality is used by multi-line text models.
3
Fonts are represented as instances of the abstract SyFontType interface. The jsycamore package provides implementations that are backed by standard Java AWT fonts, but any font system that can provide the information required by the SyFontType interface could theoretically be used.

## 3.2.4. Font Services

1
Font instances are obtained by providing an immutable font description to a font directory service represented by the SyFontDirectoryServiceType interface. A font directory service aggregates font services, represented by the SyFontServiceType interface, typically by loading instances of these services from ServiceLoader.
2
Applications are required to ensure that they include font modules for the fonts they use. There is no support for reading fonts directly from the host system as this would make applications behave differently on different host systems.
3
The jsycamore package includes the following optional font modules:

### 3.2.4.4. Included Fonts

Name | Module | Font
--- | --- | ---
DejaVu Sans | com.io7m.jsycamore.font.dejavu | DejaVu Sans
York | com.io7m.jsycamore.font.york | York Sans

## 3.2.5. Measured Lines

1
A measured line is an immutable value containing a single line of text augmented with information derived from an associated font. It contains enough information to answer questions such as "If the user clicks the text at the parent-relative position (x, y), which character within the text did they click on?".
2
The text location information returned by measured line queries includes information not limited to the character at the given location, whether the location is at the leading edge of a character, the index of the character within the given line, and a bounding box for use in rendering a caret.

## 3.2.6. Text Models

## 3.2.6.1. Overview

1
A text model is a mutable structure that handles wrapping, editing, and selection operations for text. A text model may either be single-line or multi-line.

## 3.2.6.2. Multi-Line Model

## 3.2.6.2.1. Description

1
A multi-line text model is a mutable structure that maintains a list of text sections, and transforms the text sections into a potentially much larger list of measured lines based upon a given page width value.

## 3.2.6.2.2. Selection

1
The work required to implement text selection in a multi-line model is relatively complex. The model must correctly handle forward selection and backward selection, and must do so in the presence of text sections having different text directions within the same model.
2
In order to reason about text selections, it is necessary to describe the property of logical ordering for characters in text. A character C is considered logically earlier in a given piece of text than a character B if C would be encountered before B in terms of reading order for the text. For example, in the English sentence "The quick brown fox jumped over the lazy dogs", the character q is logically earlier than the character z when the sentence is read. Conveniently, this order matches the order in which the characters are actually stored as strings in memory, and the order does not change regardless of the text direction of the language in which the text is written. Accordingly, the logically later property is simply the inverse of the logically earlier property.
3
The output of the text selection progress is the inclusive lower and inclusive upper bounds of the selection in logical order, and a set of selection region bounding boxes that can be used during rendering to render selection boxes around the relevant text. The selection regions are trivial to create; the selection region for a given line is the union of the bounding boxes of the characters that are selected on that line (taken from the associated font), and the set of regions for all lines spanned by the selection is the set of per-line regions.
4
Forward selection is the process of the user dragging the mouse across text, starting from an initial position in the text and moving the mouse to a logically later position in the text. For example:

### 3.2.6.2.2.5. Forward Selection LTR

6
In the diagram above, the user is performing a forward selection in left-to-right text. The text consists of two measured lines. The dotted arrows represent the mouse dragging directions. The user placed the cursor before the letter q in "quick" and dragged the cursor rightwards and then downwards. This results in a selection that spans the two lines. The selection is a forward selection because the selection progressed in a manner that started from a position that is logically earlier in the text, and progressed to a location that is logically later in the text.
7
Backward selection is the process of the user dragging the mouse across text, starting from an initial position in the text and moving the mouse to a logically earlier position in the text according to the text direction. For example:

### 3.2.6.2.2.8. Backward Selection LTR

9
In the diagram above, the user is performing a backward selection in left-to-right text. The text consists of two measured lines. The dotted arrows represent the mouse dragging directions. The user placed the cursor before the letter t in "the" and dragged the cursor upwards and then leftwards. This results in a selection that spans the two lines. The selection is a backward selection because the selection progressed in a manner that started from a position that is logically later in the text, and progressed to a location that is logically earlier in the text.
10
For right-to-left text, the situation does not change in that forward selections progress from logically earlier positions to logically later positions, and backward selections progress from logically later positions to logically earlier positions, but the physical direction in which the user drags the selection cursor is reversed. For example:

### 3.2.6.2.2.11. Forward Selection RTL

12
In the diagram above, the user is performing a forward selection in right-to-left text. The text consists of two measured lines. The dotted arrows represent the mouse dragging directions. The user placed the cursor before the letter פ in "אנציקלופדיה" and dragged the cursor leftwards and then downwards. This results in a selection that spans the two lines. The selection is a forward selection because the selection progressed in a manner that started from a position that is logically earlier in the text, and progressed to a location that is logically later in the text.
13
Conversely, for backward selection:

### 3.2.6.2.2.14. Backward Selection RTL

15
In the diagram above, the user is performing a backward selection in right-to-left text. The text consists of two measured lines. The dotted arrows represent the mouse dragging directions. The user placed the cursor after the letter ם in "בדפים" and dragged the cursor upwards and then rightwards. This results in a selection that spans the two lines. The selection is a backward selection because the selection progressed in a manner that started from a position that is logically later in the text, and progressed to a location that is logically earlier in the text.
16
The process of text selection therefore takes the following steps:

### 3.2.6.2.2.17. Text Selection Steps

1. When the user first presses the mouse button to start dragging, determine which measured line the cursor is over based on the Y position of the cursor, then ask that line for the text location at the X and Y position of the cursor. The position is recorded as the starting or pivot point for the selection, and all subsequent positions will be considered relative to this pivot point.
2. When the user drags the mouse, determine which measured line the cursor is over based on the Y position of the cursor, then ask that line for the text location at the X and Y position of the cursor. If the location is logically before the pivot point, then the new position becomes the lower bound of the selection, and the upper bound is set to the pivot point. If the location is logically after the pivot point, then the new position becomes the upper bound of the selection, and the lower bound is set to the pivot point.

18
During each of the above steps, the lines between the lower and upper bounds of the selection in progress are examined. The lower and upper bounds may span several lines, or may simply both be on the same line. Based on the examined lines, a set of selection regions is generated. The algorithm used differs based on whether the selection is a forward selection or a backward selection. For each selection direction, the algorithm proceeds by case analysis:

### 3.2.6.2.2.19. Forward Selection Algorithm

- For each line K in lines [P .. Q]:
  1. If K > P ∧ K < Q, then we simply need to create a selection region that covers the entirety of K; it's a fully selected line that's between the starting and ending line of the selection.
  2. Otherwise, if K = P, then we need to create a selection region either from the lower bound of the selection to the end of the line, or from the lower bound of the selection to the upper bound of the selection if the upper bound happens to be on the same line.
  3. Otherwise, we must have K = Q ∧ Q ≠ P. We have already created a selection region that involves the lower bound of the selection in the previous step, therefore the only work remaining must be to create a selection region from the start of the line to the upper bound of the selection (which must be on that same line).

20
For each case in the above algorithm, we create a selection region that's relevant to the text direction of the given line. For example, a region that extends from the "start of the line" in left-to-right text is a region that starts from the leftmost edge of the text area in parent-relative space. Conversely, a region that extends from the "start of the line" in right-to-left text is a region that starts from the rightmost edge of the text area in parent-relative space.
21
For backward selection, the algorithm is similar:

### 3.2.6.2.2.22. Backward Selection Algorithm

- For each line K in lines [P .. Q]:
  1. If K > P ∧ K < Q, then we simply need to create a selection region that covers the entirety of K; it's a fully selected line that's between the starting and ending line of the selection.
  2. Otherwise, if K = P, then we need to create a selection region either from the upper bound of the selection to the start of the line, or from the upper bound of the selection to the lower bound of the selection if the lower bound happens to be on the same line.
  3. Otherwise, we must have K = Q ∧ Q ≠ P. We have already created a selection region that involves the upper bound of the selection in the previous step, therefore the only work remaining must be to create a selection region from the end of the line to the lower bound of the selection (which must be on that same line).

23
Following the above algorithm, we can correctly build selection regions that span multiple lines where each line has its own text direction:

### 3.2.6.2.2.24. Text Selection Example

## 3.2.6.3. Single-Line Model

## 3.2.6.3.1. Description

1
A single-line text model is very simple, and augments a single measured line with the information required for performing text selections.

## 3.2.6.3.2. Selection

1
Text selection for single-line models is simply the K = P case for forward and backward multi-line selections. By definition, the upper and lower bounds of selections in single-line models are always on the same line.

## Footnotes

1 | The reason for the separation of single-line and multi-line models is that the work required for single-line models is drastically simpler than the work required for multi-line models. There is no reason to pay the complexity cost of multi-line models for every single text view if multiple lines are not required.

3.1. Menus
Previous
3. Standard Components
Up
3.3. Buttons
Next
io7m | single-page | multi-page | JSycamore User Manual