It still looks as if update() has a tendency to get expensive if certain nice-to-have or necessary features are triggered from there.
A good part of the complications come from top_y() which needs to be more or less up-to-date as it is used in: 1 LyXText::checkInsetHit(int x, int y) for finding the visible paragraphs (as an indication where to search for visible insets that might have been hit) 2 LyXText::cursorPrevious()/cursorNext(), the MOUSE_MOTION handler for setCursorFromCoordinates(cur, x, y); 3 rowpainter: paintPars() for putting a paragraph/row at a certain y-coordinate 4 rowpainter: paintText() for finding the visible paragraphs 5 BufferView_pimpl::update() for finding the visible paragraphs (to re-break them) 6 BufferView_pimpl::scrollDocView() for calling text->setCursorFromCoordinates(bv_->cursor(), 0, y); 7 BufferView::Pimpl::scroll(int lines) for calling crollDocView and workarea().setScrollbarParams() 8 LyXScreen::showCursor() for showing the cursor at a certain position 9 LyXScreen::fitCursor() for putting the cursor at a certain position 10 InsetCollapsablei/Tabular::draw() for some fancy coordinate correction Now, is this needed? I don't think so, but I might be wrong. Let's consider the cursor itself as well as a y-offset 'new_top_y' from top of the visible screen as "primary" information. Now: 1 LyXText::checkInsetHit(int x, int y) for finding the visible paragraphs (as an indication where to search for visible insets that might have been hit) 2 LyXText::cursorPrevious()/cursorNext(), the MOUSE_MOTION handler for setCursorFromCoordinates(cur, x, y); could be solved by checking a few paragraphs in the vicinity of the cursor. Of course, these better should have been rebroken lately, but even if not we could do so in O(1) by re-breaking the current par, and possibly the par above if this is visible and possibly the par above ... etc. There's a limited number of them as each row has a positive height. 3 rowpainter: paintPars() for putting a paragraph/row at a certain y-coordinate Well, we are given new_top_y, so we know where to draw things. 4 rowpainter: paintText() for finding the visible paragraphs 5 BufferView_pimpl::update() for finding the visible paragraphs (to re-break them) Same as 1 and 2. 6 BufferView_pimpl::scrollDocView() for calling text->setCursorFromCoordinates(bv_->cursor(), 0, y); 7 BufferView::Pimpl::scroll(int lines) for calling crollDocView and workarea().setScrollbarParams() That's interesting as this is the place where we actually would need absolute heights in the whole document. However, as this only affects the scrollbar, some approximation should be in order. Using the count of visible toplevel paragraphs in relation to the total number of toplevel paragraphs as well as well as the offset of the cursor's toplevel par in relation to the total is such approximation and I claim this is good enough. 8 LyXScreen::showCursor() for showing the cursor at a certain position We are given new_top_y. 9 LyXScreen::fitCursor() for putting the cursor at a certain position As simple as setting new_top_y to a new value. 10 InsetCollapsable/Tabular::draw() for some fancy coordinate correction No need for correction in screen-absolute coordinates. Note that the dreaded 'put cursor into never explored land' problem would be magically solved. We put the cursor physically there (by assigning from a DocIterator or similar) and set new_top_y to, well, 100 or so. Now it's update time: rebreak all visible outerlevel pars starting with the cursor par and going up and down as needed. And we are done. So now the interesting question: What do I miss? Andre' PS: There'll still be O(n) parts for updateCounters() and similar. However, those have been there before and were tolerable in 1.3.x.