This project is archived. The ideas here evolved into Pretext, a production-ready library for DOM-free text measurement with full i18n support. Use Pretext instead. If you have any issue or question about this repo, please file it to Pretext instead.
This project tries to solve the difficult parts of custom cross-browser multi-line text layout with full internationalization support.
This is not intended to be an ease of use API. It is expected to be used by other libraries to build easy to use and powerful APIs on top of.
It takes a sequence of text pieces, each with its own font and turns it into several runs per line.
The goal of this project is primarily to solve these three problems:
-
Provide sufficient low-level access to reimplement all CSS text layout features in JavaScript including column layouts, shape wrapping and regions.
-
Keep the same level of i18n and line breaking features as the native web browser. You should not have to compromise on this.
-
High performance and small file size. After JIT has stabilized, the performance goal is to be within 1.5x of equivalent native algorithms on common content. (Not yet benchmarked.)
- Reorder RTL content according to the Unicode Bidirectional Algorithm.
- Measure the width of each run using native text shaping.
- Split runs at the end of line breaks using the Unicode Line Breaking Algorithm. Inserting hyphenation marks where needed.
- TODO: Cut runs off at overflow and insert ellipsis.
- Provide an easy out of the box API. Integrate into a high level layout API.
- Render the text to the screen. Use HTML, SVG, Canvas or WebGL to rasterize a run.
- Position runs horizontally or vertically. Use a custom layout algorithm to position the runs using horizontal and vertical alignment.
- Provide per glyph metrics.
Note: Browsers currently doesn't provide detailed per glyph metrics. Therefore there is no API to go more granular than a Run. I'd like to expose a slightly slower way to on-demand ask for per character offsets within a Run. That way you can implement custom text selection. E.g. in Canvas.
- Intl.v8BreakIterator: Used to find appropriate line breaks. For languages like Thai and Khmer this requires dictionary based line breaks which we don't want to ship with the library. If this is not available, a polyfill is used which covers most cases but isn't quite as good for those languages.
- CanvasRenderingContext2D.measureText: Used to perform text shaping of a single run of text.
Note: This library uses the CSS property unicode-bidi: bidi-override to disable the bidi algorithm since it does its own bidi algorithm. Ideally this should provide a minor perf improvement by avoiding applying it twice.
There are a number of use cases for why you would like to do layout in JavaScript:
-
Implement new CSS features that doesn't yet exist.
-
Layout SVG content that can't be expressed with the CSS box model.
-
Manipulate the pixels and positioning of the rasterized input using Canvas 2D or WebGL.
-
Compute layout asynchronously.
-
Generate content conditionally during a single layout pass.
The library API is designed with an inlining compiler in mind.
Example:
function configure(extract) {
return function process(obj) {
var { x, y, z } = extract(obj);
if (z) {
return z;
}
return x + y;
}
}Usage in your library:
var Layout = configure(function(data) {
return { x: data.style.left, y: data.style.top };
});This might normally create an extra allocation and unnecessary code paths. You're expected to inline this library using a compiler so that it turns into:
var Layout = function process(obj) {
var x = obj.style.left;
var y = obj.style.top;
return x + y;
}This allows us to make an extensible API without having to worry about performance concerns.
Intrinsic size. In CSS there is a notion of Intrinsic Size. It is basically the potential minimum/maximum width and height of a piece of content. This calculation needs to be done slightly differently from a normal layout pass. However, all the necessary pieces are already there.
Dictionary-based hyphenation using a Hyphenation API once browsers expose it. This allows you to model the CSS hyphens: auto feature.
Vertical text layout with proper bidi rotation and line breaks.