Text Rewrite

From Inkscape Wiki
Jump to navigation Jump to search

This page tracks ideas for rewriting our text layout engine.

Our current layout engine has not aged particularly well. It's extremely difficult to work with and the additions by numerous people have left it in a wanting state. The goal here is not to change the overall layout strategy but to make it more efficient and simpler where possible.

Overview of NR Text Rendering

The Good

  • The layout engine works well.
  • The custom iterator allows movement through the different lists in a unified way: glyphs, characters, chunks, lines. etc.

The Bad

  • The classes/structures are not fully C++. In particular, they are not initialized.
  • The classes don't contain all the information they could (maybe due to concerns about memory use... which should no longer be valid). See below.
  • Documentation is a bit sparse. Some variable names could be clearer.

The Ugly

  • The use of sodipode:role="line". See below.

Specific Problems

sodipodi:role="line"

Inkscape uses the attribute sodipodi:role to keep track of new lines. This was an interesting solution to supporting multi-line text in the days of SVG 1.1. It works by replacing any new-line character by a new <tspan> with an attribute value of line and additionally 'x' and 'y' attributes. (SVG 1.2 text replaces any new-line character by a new paragraph element.) This does not work well with SVG 2 text which relies on new-line characters to mark, well, new lines. It has an additional problem in that if one pastes text from an Inkscape SVG document into another document, there are no spaces between the lines of text.

Access to information

It is difficult to readily access information at particular points in the layout process. Some work has been done to simplify access, but long chains of dereferencing still exists such as:

Layout::Direction following_span_progression = static_cast<InputStreamTextSource const *>(_flow._input_stream[it_following_span->start.iter_span->input_index])->styleGetBlockProgression();

One particular problem I encountered was accessing the original character data at particular layout steps. One would think that the Character class might contain the information, but it doesn't (didn't).

The Planned Work

Re-implement Classes/Structures

  • Make them fully modern C++.
  • Track more information, for example add the character with layout position to the Character class.
  • Look at removing the temporary classes in Layout-TNG-Compute.cpp by adding the information to other classes.

Remove sodipodi:role="line"

This attribute will be replaced by using the 'new-line' character with the 'white-space' property value 'pre-line'. Fallback SVG 1.1 text will be created at output, as is done for SVG 2 flowed text.

On reading old files, the 'sodipodi:role' attribute will need to be replaced by new-line characters.

General Cleanup and Documentation

The code will be reworked and documented as needed to produce easier to read code. This includes things like reformatting functions; renaming variables, function names, etc.; and breaking the code into smaller pieces.

Removal of SVG 1.2 Flowtext

Inkscape and Batik are the only known implementers of SVG 1.2 flowtext (both implemented only parts).

Inkscape's GUI only allowed the creation of documents with:

  • <flowRoot>
  • <flowRegion>
  • <flowPara>
  • <flowSpan>

Inkscape rendering also supports:

  • <flowDiv>
  • <flowLine>
  • <flowRegionBreak>
  • <flowRegionExclude>

We'll need to continue support legacy documents. We can do that by converting:

<flowRoot> -> <text>
<flowRegion> -> 'shape-inside'
<flowPara> -> new-line
<flowSpan> -> <tspan>
<flowDiv> -> new-line
<flowLine> -> new-line
<flowRegionBreak> -> No natural replacement, we could use vertical tab.
<flowRegionExclude> -> 'shape-exclude'

In particular, Inkscape's tutorials use <flowDiv>.