2015-10-02 15:26:28 +00:00
|
|
|
# -*- org -*-
|
|
|
|
Understanding the painting process
|
|
|
|
|
2015-10-02 13:30:16 +00:00
|
|
|
This file tries to describe the state of the metrics/painting
|
|
|
|
mechanism, and identify the improvements that could be made. The first
|
|
|
|
section can be read alone, although the context for them is really
|
|
|
|
given in the following ones.
|
|
|
|
|
|
|
|
Please keep this file up to date as the code evolves!!!
|
|
|
|
|
|
|
|
Abbreviations:
|
|
|
|
bv: BufferView
|
|
|
|
pm: ParagraphMetrics
|
|
|
|
tm::TextMetrics
|
|
|
|
|
|
|
|
* Questions / Ideas
|
|
|
|
|
|
|
|
These questions are consequences of the description made in the
|
|
|
|
following section. Some actions are proposed.
|
|
|
|
|
|
|
|
** SinglePar update
|
|
|
|
|
|
|
|
The flag Update::SinglePar is set in many places but never acted on.
|
|
|
|
Instead, metrics update is skipped whenever the recorded height of
|
|
|
|
current paragraph did not change and Update::Force was not specified.
|
|
|
|
Is it better to keep that (which incurs extra work) or to condition it
|
|
|
|
on Update::SinglePar? If the first solution is kept, the flag
|
|
|
|
SingleParUpdate shall be removed.
|
|
|
|
|
|
|
|
Moreover, I fail to see (yet) where the 'single' part of the program
|
|
|
|
is acted on.
|
|
|
|
|
|
|
|
** Buffer::change issues
|
|
|
|
|
|
|
|
When calling Buffer::changed outside of bv::processUpdateFlags,
|
2015-10-12 14:11:58 +00:00
|
|
|
how do we know that the update strategy is set correctly? It is
|
2015-10-02 13:30:16 +00:00
|
|
|
possible to reset the strategy at the end of bv::draw. What would be
|
|
|
|
a good value? NoScreenUpdate?
|
|
|
|
|
|
|
|
On a related note, what is the semantics of a call to
|
|
|
|
Buffer::changed(false)? What does the caller mean?
|
|
|
|
|
2015-10-12 14:11:58 +00:00
|
|
|
** How to avoid redraw with FitCursor when the cursor is already OK?
|
2015-10-02 13:30:16 +00:00
|
|
|
|
2015-10-04 20:28:36 +00:00
|
|
|
In this case, we invoke Buffer::change(false) with drawing disabled
|
|
|
|
and NoScreenUpdate strategy.
|
2015-10-03 22:03:46 +00:00
|
|
|
|
2015-10-04 20:28:36 +00:00
|
|
|
In the draw phase, bv::checkCursorScrollOffset (the horizontal
|
|
|
|
scrolling machinery) will change the strategy to FullScreenUpdate if
|
|
|
|
the current row needs further scrolling.
|
|
|
|
|
|
|
|
When the update strategy it kept to NoScreenUpdate, there is currently
|
|
|
|
a no-draw full repaint, which should not be necessary. It would be
|
|
|
|
possible to avoid that if the call to checkCursorScrollOffset was done
|
|
|
|
in bv::processUpdateFlags instead of bv::draw.
|
|
|
|
|
|
|
|
The global idea would be to extend FitCursor to cover also horizontal
|
|
|
|
cursor.
|
2015-10-03 22:03:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
* Proposals
|
|
|
|
|
2016-03-20 19:02:05 +00:00
|
|
|
|
2016-03-04 23:09:34 +00:00
|
|
|
* Clean-up of drawing code
|
2015-10-03 22:03:46 +00:00
|
|
|
|
2016-03-04 23:09:34 +00:00
|
|
|
The goal is to make painting with drawing disable fast enough that it
|
|
|
|
can be used after every metrics computation. Then we can separate real
|
|
|
|
drawing from metrics.
|
2015-10-03 22:03:46 +00:00
|
|
|
|
2016-03-04 23:09:34 +00:00
|
|
|
** DONE RowPainter
|
|
|
|
|
|
|
|
Inset position is set in paintInset, paintOnlyInsets, and paintText.
|
|
|
|
This should be done only once in paintInset
|
|
|
|
|
|
|
|
** DONE TextMetrics::drawParagraph
|
|
|
|
|
|
|
|
We can really simplify the code when drawing is disabled only
|
|
|
|
paintInset needs to be called.
|
|
|
|
+ do right at the start when drawing is already disabled
|
|
|
|
+ do it in the loop for rows that are not visible on screen.
|
|
|
|
|
|
|
|
The only thing we want to do here is to set inset positions (for
|
|
|
|
text). The other insets still use the painter with drawing disabled.
|
|
|
|
|
2016-03-20 19:02:05 +00:00
|
|
|
** DONE Painter::text
|
2016-03-04 23:09:34 +00:00
|
|
|
|
|
|
|
We cannot remove (or make private) the version that uses a
|
|
|
|
FontInfo because it is used by PainterInfo::draw. Document this and
|
|
|
|
remove unused arguments rtl and double spacing. This would become a specialized helper.
|
|
|
|
Proposed solution: keep the existing function, but private and without
|
|
|
|
optional arguments.
|
|
|
|
|
|
|
|
Avoid to return (and thus compute) the width of strings?
|
|
|
|
+ used by InsetSpecialChar (fixable)
|
|
|
|
+ used by textDecoration() in text(): more difficult to fix
|
|
|
|
|
|
|
|
Idea: add a version of text where wordspacing and textwidth (giving
|
|
|
|
the width of strings) are required parameters and remove optional
|
|
|
|
version.
|
|
|
|
|
|
|
|
==> more versions, no optional parameters.
|
|
|
|
|
2016-04-08 14:34:46 +00:00
|
|
|
** DONE When a document ends with a newline, add the bottom margin anyway
|
|
|
|
|
|
|
|
The code that tests for a newline was added at 6bb98d07 in 2007.
|
|
|
|
|
|
|
|
** When a paragraph ends with a newline, compute correctly the height of the extra row.
|
|
|
|
** Rewrite TextMetrics::completionPosAndDim using row information
|
|
|
|
|
|
|
|
Currently it uses setRowHeight in a very weird way. In particular the
|
|
|
|
topBottomSpace parameter should be removed after that.
|
|
|
|
|
|
|
|
** Rewrite TextMetrics::editXY, checkInsetHit using row information (getPosNearX)?
|
|
|
|
|
|
|
|
The helper version should return a Row::Element instead of an InsetTable.
|
|
|
|
|
|
|
|
** TODO make Inset::display() more useful
|
|
|
|
|
|
|
|
[This has been started in the features/betterbreak branch. Time will
|
|
|
|
tell whether it really helps. The question in particular is the
|
|
|
|
handling of separator insets]
|
2016-03-20 19:02:05 +00:00
|
|
|
|
|
|
|
Extending the DisplayType enum would allow to remove special cases
|
|
|
|
from the code.
|
|
|
|
|
|
|
|
The enumeration could be like
|
|
|
|
: Inline = 0
|
|
|
|
: BreakBefore = 1 // break row before this inset
|
|
|
|
: BreakAfter = 2 // break row after this inset
|
|
|
|
: CanBreakAfter = 4 // optionally break row after this inset
|
|
|
|
: AlignLeft = 8
|
|
|
|
: AlignRight = 16
|
|
|
|
: NoBoundary = 32 // do not allow cursor to go at the end of the row
|
|
|
|
: //before display inset
|
|
|
|
: Display = BreakBefore|BreakAfter
|
|
|
|
|
|
|
|
A display equation would be Display, other could be Display|AlignLeft
|
|
|
|
BreakAfter can be used by Newline or separator insets
|
|
|
|
CanBreakAfter can be used by the optional hyphen InsetSpecialChar.
|
|
|
|
|
2016-03-04 23:09:34 +00:00
|
|
|
** Set inset position during metrics phase
|
|
|
|
|
|
|
|
In order to do that, a no-paint drawing will be initiated after every
|
|
|
|
redoParagraph. This code path will need to be made as fast as possible.
|
|
|
|
|
|
|
|
Effect: avoid depending on actual drawing having taken place. In turn,
|
|
|
|
it will allow to do drawing on paint events, like any reasonable
|
|
|
|
application would do.
|
|
|
|
|
|
|
|
** Cleanup after complete metrics
|
|
|
|
Then the following can be done:
|
|
|
|
+ remove hack in InsetMathNest::drawSelection
|
|
|
|
+ remove painting when not inside in drawParagraph
|
|
|
|
+ remove Cursor::inCoordCache?
|
|
|
|
|
|
|
|
** Use Row for MathData
|
|
|
|
|
|
|
|
It may not be so difficult. Implement x2pos and pos2x from
|
|
|
|
the TM:cursorX and TM::getPosNearX, and use them for both text and
|
|
|
|
math.
|
|
|
|
|
|
|
|
Will the strings display OK if drawing string-wise?
|
|
|
|
|
|
|
|
Then it would be possible to streamline drawing with disabled painter.
|
|
|
|
|
|
|
|
** Paint directly to screen
|
|
|
|
|
|
|
|
Instead of using an intermediary pixmap. I have no idea of how
|
|
|
|
difficult it will prove.
|
|
|
|
One benefit will be that subpixel aliasing will work again (#9972)
|
2015-10-02 13:30:16 +00:00
|
|
|
|
|
|
|
** Merging bv::updateMetrics and tm::metrics
|
|
|
|
|
|
|
|
While the full metrics computation tries hard to limit the number of
|
|
|
|
paragraphs that are rebroken, the version that is used for inner inset
|
|
|
|
does not try any such optimization. This can be very bad for very tall
|
2015-10-03 22:03:46 +00:00
|
|
|
insets. We should re-use the bv::updateMetrics logic:
|
|
|
|
+ transfer all the logic of bv::updateMetrics to tm.
|
2016-03-04 23:09:34 +00:00
|
|
|
+ Main InsetText should not be special.
|
2015-10-03 22:03:46 +00:00
|
|
|
|
2016-03-04 23:09:34 +00:00
|
|
|
The difficuly for a tall table cell for example, is that it may be
|
|
|
|
necessary to break the whole contents to know the width of the cell.
|
2015-10-02 13:30:16 +00:00
|
|
|
|
|
|
|
|
2015-10-04 20:28:36 +00:00
|
|
|
* Description of current drawing mechanism
|
|
|
|
|
2015-10-12 14:11:58 +00:00
|
|
|
** Two stage drawing
|
2015-10-02 13:30:16 +00:00
|
|
|
|
|
|
|
There are two parts to drawing the work area:
|
|
|
|
|
|
|
|
+ the metrics phase computes the size of insets and breaks the
|
|
|
|
paragraphs into rows. It stores the dimension of insets (both
|
2015-10-12 14:11:58 +00:00
|
|
|
normal and math) in bv::coordCache.
|
2015-10-02 13:30:16 +00:00
|
|
|
|
|
|
|
+ the drawing phase draws the contents and caches the inset
|
|
|
|
positions. Since the caching of positions is useful in itself,
|
|
|
|
there is a provision for drawing "without" drawing when the only
|
|
|
|
thing we want is to cache inset positions
|
|
|
|
(Painter::setDrawingEnabled).
|
|
|
|
|
|
|
|
The machinery is controlled via bv::processUpdateFlags. This method is
|
|
|
|
called at the end of bv::mouseEventDispatch and in
|
|
|
|
GuiApplication::dispatch, via the updateCurrentView method. There are
|
|
|
|
also several calls in code related to dialogs. We should evaluate
|
|
|
|
whether this is correct.
|
|
|
|
|
|
|
|
Depending on the Update::flags passed to the method, it sets an update
|
|
|
|
strategy in (NoScreenUpdate, SingleParUpdate, FullScreenUpdate,
|
|
|
|
DecorationUpdate). It triggers a recomputation of the metrics when either:
|
|
|
|
|
|
|
|
+ Update::Force has been specified
|
|
|
|
+ Update::FitCursor has been specified and there is a need to scroll
|
|
|
|
the display.
|
2015-10-02 15:26:28 +00:00
|
|
|
+ the current paragraph, after rebreak, does not have the same height as in
|
2015-10-02 13:30:16 +00:00
|
|
|
existing metrics. Note that the Update::SinglePar flag is *never*
|
|
|
|
taken into account.
|
|
|
|
|
|
|
|
The screen is drawn (with appropriate update strategy), except when
|
|
|
|
update flag is Update::None.
|
|
|
|
|
|
|
|
|
2015-10-04 20:28:36 +00:00
|
|
|
** Metrics computation
|
2015-10-02 13:30:16 +00:00
|
|
|
|
|
|
|
This is triggered by bv::updateMetrics, which calls tm::redoParagraph for
|
|
|
|
+ all visible paragraphs
|
|
|
|
+ paragraph above the screen (up to one page)
|
|
|
|
+ paragraphs below the screen (up to one page again)
|
|
|
|
|
|
|
|
The paragraphs outside of the screen are required to make PageUp/Down
|
|
|
|
work.
|
|
|
|
|
|
|
|
tm::redoParagraph will call Inset::metrics for each inset. In the case
|
|
|
|
of text insets, this will invoke recursively tm::metrics, which redoes
|
|
|
|
all the paragraphs of the inset.
|
|
|
|
|
|
|
|
|
2015-10-04 20:28:36 +00:00
|
|
|
** Drawing the work area.
|
2015-10-02 13:30:16 +00:00
|
|
|
|
|
|
|
This is done in bv::draw. This method is triggered mainly by
|
|
|
|
Buffer::changed, which draws all the work areas that show the given buffer.
|
|
|
|
|
|
|
|
Note that, When Buffer::changed is called outside of
|
|
|
|
bv::processUpdateFlags, it is not clear whether the update strategy
|
|
|
|
has been set to a reasonable value beforehand.
|
|
|
|
|
|
|
|
The action depends on the update strategy:
|
|
|
|
|
|
|
|
+ NoScreenUpdate: repaint the whole screen with drawing disabled.
|
|
|
|
This is only needed to update the inset positions. I am not sure
|
|
|
|
when this is necessary, actually. This is triggered when:
|
|
|
|
- Update::FitCursor is set but the cursor is already visible. It is
|
|
|
|
not clear why something needs to be done in this case, since this
|
|
|
|
should be equivalent to Update::None.
|
|
|
|
- this is also set when update flag is Update::None, but this value
|
|
|
|
is AFAICS not acted on in the code (meaning that nothing happens
|
|
|
|
at all in this case).
|
|
|
|
|
|
|
|
+ FullScreenUpdate: repaint the whole screen. This is set when:
|
|
|
|
- updateMetrics has been invoked.
|
|
|
|
- scroll value of current row has changed (although this should not
|
|
|
|
be necessary).
|
|
|
|
|
|
|
|
+ DecorationUpdate: actually like FullScreenUpdate, although it is
|
|
|
|
intended to only update inset decorations. This triggers when:
|
|
|
|
- Update::Decoration is set (without Update::Force) as flag.
|
|
|
|
- An hovered inset is detected.
|
|
|
|
|
|
|
|
+ SingleParUpdate: only tries to repaint current paragraph in a way
|
|
|
|
that is not yet very clear to me.
|