]> git.lyx.org Git - lyx.git/blobdiff - development/PAINTING_ANALYSIS
Tweak ruff configuration
[lyx.git] / development / PAINTING_ANALYSIS
index 08afa500ed7c84a59b7a73c24358438df52e0e08..438d7ca9c32e2ac4299effb5ff3d8fcf0f3a9410 100644 (file)
@@ -3,7 +3,7 @@ Understanding the painting process
 
 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
+sections 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!!!
@@ -11,7 +11,7 @@ Please keep this file up to date as the code evolves!!!
 Abbreviations:
 bv: BufferView
 pm: ParagraphMetrics
-tm::TextMetrics
+tm: TextMetrics
 
 * Questions / Ideas
 
@@ -20,51 +20,66 @@ 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.
+This flag only has an effect in the current BufferView, but I think it
+is useful in other views too. Doing this will require some work on the
+update pipeline, though.
 
-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,
-how do we now that the update strategy is set correctly? It is
+how do we know that the update strategy is set correctly? It is
 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?
 
-** What happens with FitCursor when the cursor is already OK?
 
-In this case, we invoke Buffer::change(false) with drawing disabled,
-which means that the paint machinery is invoked to update inset
-positions.
+** How to avoid redraw with FitCursor when the cursor is already OK?
 
-Actually, this was added as part of the horizontal scrolling GSoC
-work. We need to investigate how costly this is.
+In this case, we invoke Buffer::change(false) with drawing disabled
+and NoScreenUpdate strategy.
 
+In the draw phase, bv::checkCursorScrollOffset (the horizontal
+scrolling machinery) will change the strategy to FullScreenUpdate if
+the current row needs further scrolling.
 
-* Proposals
+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.
 
-** get rid of pm::insetDimension.
+The global idea would be to extend FitCursor to cover also horizontal
+cursor.
 
-The information contained there is already in bv::coordCache.
 
-Effect: only code simplification.
+* TODO Clean-up of drawing code
 
-** set inset position during metrics phase
+** Set Row::changed() in a finer way
 
-This implies to set inset positions relative to outer isnet during
-metrics phase and then in a second loop to descend into insets and
-update positions correctly.
+*** singleParUpdate
+
+When the height of the current paragraph changes, there is no need for
+a full screen update (at top level, at least). Only the rows after the
+current one need to have their position recomputed.
+
+
+*** redoParagraph
+
+It should be possible to check whether the new row is the same as the
+old one and keep its changed() status in this case. This would reduce
+a lot the amount of stuff to redraw.
+
+
+** Put labels and friends in the Row as elements
+
+It should not be necessary to access the Paragraph object to draw.
+Adding the static elements to Row is a lot of work, but worth it IMO.
+
+
+** When a paragraph ends with a newline, compute correctly the height of the extra row.
 
-Effect: avoid going through the painter machinery when it is not necessary.
 
 ** Merging bv::updateMetrics and tm::metrics
 
@@ -73,33 +88,35 @@ 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
 insets. We should re-use the bv::updateMetrics logic:
  + transfer all the logic of bv::updateMetrics to tm.
- +  Main InsetText should not be special.
+ + Main InsetText should not be special.
 
-** Metrics outside of visible area
+The difficulty 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.
+Also, the anchor is relative to the outer paragraph, which means that
+for a very long inset it is necessary to rebreak until the contents
+that needs to be shown (to compute the heights).
 
-Currently metrics are computed for current visible paet of text, the
-page above and the page below. It should be possible to compute hidden
-rows ony on demand, although it might be a bit slow.
+All in all, this is difficult to get right. This is less important now
+that SinglePar updates work in nested insets.
 
-There was a proposal to always compute _all_ rows, but this may become
-expensive for large files. This would though help scrolling.
 
+* Description of current drawing mechanism
 
-* Two phase drawing
+** Three-stage drawing
 
-There are two parts to drawing the work area:
+There are three 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
-   normal and math) in bv::coordCache, and the size of normal
-   insets in pm::insetDimension.
+   normal and math) in bv::coordCache and the vertical position of the
+   top-level paragraphs.
 
- + 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 nodraw drawing phase paints the screen (see below) with a null
+   painter. The only useful effect is to store the positions of
+   visible insets.
 
+ + an update() signal is sent. This in turn will trigger a paint
+   event, and the actual screen painting will happen then.
 
 The machinery is controlled via bv::processUpdateFlags. This method is
 called at the end of bv::mouseEventDispatch and in
@@ -109,38 +126,59 @@ 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:
+DecorationUpdate). It triggers a call to updateMetrics when either:
 
  + Update::Force has been specified
  + Update::FitCursor has been specified and there is a need to scroll
    the display.
- + the current paragraph, after rebreak, does not have the same height as in
-   existing metrics. Note that the Update::SinglePar flag is *never*
-   taken into account.
+ + Update::SinglePar has been specified and the current paragraph has
+   changed height.
+
+If a computation of metrics has taken place, Force is removed from the
+flags and ForceDraw is added instead.
+
+It is OK to call processUpdateFlags several times before an update. In
+this case, the effects are cumulative. processUpdateFlags executes the
+metrics-related actions, but defers the actual drawing to the next
+paint event.
 
 The screen is drawn (with appropriate update strategy), except when
 update flag is Update::None.
 
 
-* Metrics computation
+** Metrics computation (and nodraw drawing phase)
 
-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)
+This is done bv::updateMetrics. When the parameter 'force' of this
+method is true, that first thing that is done is to clear the metrics
+caches to start from a clean slate.
 
-The paragraphs outside of the screen are required to make PageUp/Down
-work.
+Then, starting upwards then downwards from the anchor paragraph
+(anchor_pit_) and its vertical position (anchor_ypos_),
+tm::updateMetrics every visible paragraph whose metrics is not know
+(all of them when force==true) is recomputed using tm::redoParagraph.
 
 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.
+all the paragraphs of the inset. Then, a single big row is created in
+tm::tokenizeParagraph, which is later broken in multiple rows by
+tm::breakParagraph.
 
+If it turns out that the top or bottom margin are incorrect (paragraphs
+are too high/low), tm::updateMetrics will be called again with fixed
+values of anchor_ypos_ (this does not incur much extra work).
 
-* Drawing the work area.
+At the end of bv::updateMetrics, bv::updatePosCache is called. It triggers
+a repaint of the document with a NullPainter (a painter that does
+nothing). This has the effect of caching all insets positions.
 
-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.
+This way of working means that scrolling can be achieved by just
+updating anchor_ypos_ and calling bv::processUpdateFlags(Update::ForceDraw).
+
+** Drawing the work area.
+
+This is done in bv::draw. This method is triggered by a paint event,
+mainly called through 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
@@ -170,3 +208,6 @@ The action depends on the update strategy:
 
  + SingleParUpdate: only tries to repaint current paragraph in a way
    that is not yet very clear to me.
+
+BufferView::draw can also be called with a null painter from
+BufferView::updateMetrics().