There are a large number of interlocking text-related bugs related to
text frame content offsets. I tried to fix these in bug 385270 but I
got it wrong and had to back out for M7. The underlying problems
remain. I want to write down what's going on partly to keep my own
head straight and also to get feedback.

Recap: text frames store a "content offset" and "content length",
indicating the substring of the frame's DOM text node that the frame
is responsible for. Historically, these fields have been lazily
updated during reflow: the basic invariant is that frames that "have
been reflowed" have correct offset and length, but for frames that
"need to be reflowed" the offset and length fields should be
considered invalid. Therefore reflow sets the offset and length
fields. Bidi resolution also sets them, after which reflow updates
them.

This is troublesome because code that manipulates text frames has to
be aware of the possibility that the offset and length are bogus.
There are activities such as textrun construction that may touch text
frames that have been reflowed and text frames and haven't.

To address this, my patch in bug 385270 attempted to impose the
invariant at all times that the content ranges for the text frames
associated with a text node form a partition of the node's text ---
i.e. they do not overlap and their union is all the text of the node.
The main change required to achieve this was to have reflow and
AdjustOffsetsForBidi (called by bidi resolution) update the offsets of
next-in-flows when the frame's associated text grows or shrinks; if
the frame gets more text, we shrink the next-in-flows accordingly, and
if the frame loses text, that text gets associated with the next-in-
flow.

This failed for a couple of reasons. One reason is that the bidi
resolver only looks at a single block frame at a time, when it really
needs to look at an entire block continuation chain at a time (and
those frames' overflow lines) --- e.g. bidi resolution for an element
in columns should process all the columns at once. When a text node
spans columns, the bidi resolver ends up associated all the text in
the node with the frame in the column it's processing, so the frame's
content range overlaps with the content range of the frame in another
column. It's not clear how hard this would be to fix in the bidi
resolver.

Another, more fundamental issue concerns regular inline reflow. When a
text frame breaks for the first time, we set its length to the length
of the text before the break, and return to block layout. At this
point there is no next-in-flow and no frame mapping the rest of the
text, thus our invariant is violated. Normally we'd hope that a
continuation frame is created "soon" and therefore the invariant is
restored. However in some cases that doesn't happen: sometimes we
decide to push the text frame we reflowed to the next line and try to
reflow it again there. Sometimes that next line overflows the block
and so we push it to the next column or page... so the continuation
frame might not be created for a long time, or might never be created
if the text frame fits in its new location.

Here's an alternative approach. Let's get rid of the content length
field, and consider the text mapped by a text frame to be the text
between the frame's starting offset and the frame's next
continuation's starting offset (or the end of the text node if there
is no next continuation). Then we just need to ensure that content
offsets do not decrease along a continuation chain, then we're
guaranteed to have a good partition of the text. When we reflow a text
frame, we update the offsets of next-in-flows to indicate how much
text is being mapped by the current frame. If there is no next-in-
flow, we set a field in the current frame --- like the current length
field, but more like a temporary hint --- to indicate where a new
continuation should start. Until the new continuation is created, the
current frame is still considered to be mapping that text --- this is
how the issue in the above paragraph is fixed.

The bidi resolution problem still exists. I'm not sure if we should
tackle that head on, or try to work around it by having
AdjustOffsetsForBidi do clever things to maintain our invariant. Since
all we have to do is ensure the offsets are non-decreasing along the
continuation chain, it might be possible to ensure that in a
reasonable way without messing with the resolver for 1.9.

_______________________________________________
dev-tech-layout mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-layout

Reply via email to