commit d222e0f48e17eb838d8320f30f82b4c96b3e496e
Author: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date:   Sun Jul 16 01:25:03 2017 +0200

    three-stage drawing: add a nodraw stage
    
    Normally the two stages of drawing are
    1/ compute metrics of insets/rows/paragraphs/mathrow...
    2/ draw the elements and cache their positions
    
    Now the three stages are
    1/ metrics
    2/ nodraw: do not draw the elements, but cache their position
    3/ draw the elements (and store again their position; it does not
       seems to hurt performance).
    
    Revive the NullPainter: this replaces the setDrawingEnabled mechanism
    with a painter that does nothing. The advantage is that updatePosCache
    (renamed from setPosCache) does not need anymore to be invoked from
    the frontend.
    
    updatePosCache (the nodraw stage) is called at the end of
    BufferView::updateMetrics.
---
 src/BufferView.cpp                    |   27 ++++++--
 src/BufferView.h                      |    5 +-
 src/RowPainter.cpp                    |    2 +-
 src/TextMetrics.cpp                   |   18 ++----
 src/frontends/Makefile.am             |    1 +
 src/frontends/NullPainter.h           |  109 +++++++++++++++++++++++++++++++++
 src/frontends/Painter.h               |   11 +---
 src/frontends/qt4/GuiPainter.cpp      |   26 +--------
 src/frontends/qt4/GuiPainter.h        |    3 +
 src/frontends/qt4/GuiWorkArea.cpp     |   14 ++--
 src/mathed/InsetMathMacroTemplate.cpp |   18 ++----
 11 files changed, 160 insertions(+), 74 deletions(-)

diff --git a/src/BufferView.cpp b/src/BufferView.cpp
index e141f34..94e448d 100644
--- a/src/BufferView.cpp
+++ b/src/BufferView.cpp
@@ -70,6 +70,7 @@
 #include "frontends/Application.h"
 #include "frontends/Delegates.h"
 #include "frontends/FontMetrics.h"
+#include "frontends/NullPainter.h"
 #include "frontends/Painter.h"
 #include "frontends/Selection.h"
 
@@ -2732,6 +2733,9 @@ void BufferView::updateMetrics()
 
        d->update_strategy_ = FullScreenUpdate;
 
+       // Now update the positions of insets in the cache.
+       updatePosCache();
+
        if (lyxerr.debugging(Debug::WORKAREA)) {
                LYXERR(Debug::WORKAREA, "BufferView::updateMetrics");
                d->coord_cache_.dump();
@@ -2739,6 +2743,15 @@ void BufferView::updateMetrics()
 }
 
 
+void BufferView::updatePosCache()
+{
+       // this is the "nodraw" drawing stage: only set the positions of the
+       // insets in metrics cache.
+       frontend::NullPainter np;
+       draw(np);
+}
+
+
 void BufferView::insertLyXFile(FileName const & fname)
 {
        LASSERT(d->cursor_.inTexted(), return);
@@ -2984,12 +2997,11 @@ void BufferView::checkCursorScrollOffset(PainterInfo & 
pi)
                 * at this point.
                 */
                // Force the recomputation of inset positions
-               bool const drawing = pi.pain.isDrawingEnabled();
-               pi.pain.setDrawingEnabled(false);
+               frontend::NullPainter np;
+               PainterInfo(this, np);
                // No need to care about vertical position.
                RowPainter rp(pi, buffer().text(), row, 
-d->horiz_scroll_offset_, 0);
                rp.paintText();
-               pi.pain.setDrawingEnabled(drawing);
        }
 
        // Current x position of the cursor in pixels
@@ -3053,12 +3065,13 @@ void BufferView::draw(frontend::Painter & pain)
        switch (d->update_strategy_) {
 
        case NoScreenUpdate:
-               // If no screen painting is actually needed, only some the 
different
-               // coordinates of insets and paragraphs needs to be updated.
+               // no screen painting is actually needed. In nodraw stage
+               // however, the different coordinates of insets and paragraphs
+               // needs to be updated.
                LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate");
                pi.full_repaint = true;
-               pi.pain.setDrawingEnabled(false);
-               tm.draw(pi, 0, y);
+               if (pain.isNull())
+                       tm.draw(pi, 0, y);
                break;
 
        case SingleParUpdate:
diff --git a/src/BufferView.h b/src/BufferView.h
index 588e9d0..40af7c6 100644
--- a/src/BufferView.h
+++ b/src/BufferView.h
@@ -283,6 +283,10 @@ public:
        /// update the internal \c ViewMetricsInfo.
        void updateMetrics();
 
+       // this is the "nodraw" drawing stage: only set the positions of the
+       // insets in metrics cache.
+       void updatePosCache();
+
        ///
        TextMetrics const & textMetrics(Text const * t) const;
        TextMetrics & textMetrics(Text const * t);
@@ -303,7 +307,6 @@ public:
        /// get the position and height of the cursor
        void cursorPosAndHeight(Point & p, int & h) const;
 
-
        ///
        void draw(frontend::Painter & pain);
 
diff --git a/src/RowPainter.cpp b/src/RowPainter.cpp
index 1f89b25..c4b9034 100644
--- a/src/RowPainter.cpp
+++ b/src/RowPainter.cpp
@@ -576,7 +576,7 @@ void RowPainter::paintText()
                        paintStringAndSel(e);
 
                        // Paint the spelling marks if enabled.
-                       if (lyxrc.spellcheck_continuously && pi_.do_spellcheck 
&& pi_.pain.isDrawingEnabled())
+                       if (lyxrc.spellcheck_continuously && pi_.do_spellcheck 
&& !pi_.pain.isNull())
                                paintMisspelledMark(e);
                        break;
 
diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp
index 4768157..360d83b 100644
--- a/src/TextMetrics.cpp
+++ b/src/TextMetrics.cpp
@@ -1797,8 +1797,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, 
pit_type const pit, int const
                return;
        size_t const nrows = pm.rows().size();
 
-       // Use fast lane when drawing is disabled.
-       if (!pi.pain.isDrawingEnabled()) {
+       // Use fast lane in nodraw stage.
+       if (pi.pain.isNull()) {
                for (size_t i = 0; i != nrows; ++i) {
 
                        Row const & row = pm.rows()[i];
@@ -1850,17 +1850,11 @@ void TextMetrics::drawParagraph(PainterInfo & pi, 
pit_type const pit, int const
                if (i)
                        y += row.ascent();
 
-               RowPainter rp(pi, *text_, row, row_x, y);
-
                // It is not needed to draw on screen if we are not inside.
                bool const inside = (y + row.descent() >= 0
                        && y - row.ascent() < ww);
-               pi.pain.setDrawingEnabled(inside);
                if (!inside) {
-                       // Paint only the insets to set inset cache correctly
-                       // FIXME: remove paintOnlyInsets when we know that 
positions
-                       // have already been set.
-                       rp.paintOnlyInsets();
+                       // Inset positions have already been set in nodraw 
stage.
                        y += row.descent();
                        continue;
                }
@@ -1889,6 +1883,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, 
pit_type const pit, int const
                        text_->getPar(pit).spellCheck();
                }
 
+               RowPainter rp(pi, *text_, row, row_x, y);
+
                // Don't paint the row if a full repaint has not been requested
                // and if it has not changed.
                if (!pi.full_repaint && !row_has_changed) {
@@ -1919,7 +1915,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, 
pit_type const pit, int const
                                << " row_selection="    << row.selection()
                                << " full_repaint="     << pi.full_repaint
                                << " row_has_changed="  << row_has_changed
-                               << " drawingEnabled=" << 
pi.pain.isDrawingEnabled());
+                               << " null painter=" << pi.pain.isNull());
                }
 
                // Backup full_repaint status and force full repaint
@@ -1947,8 +1943,6 @@ void TextMetrics::drawParagraph(PainterInfo & pi, 
pit_type const pit, int const
                // Restore full_repaint status.
                pi.full_repaint = tmp;
        }
-       // Re-enable screen drawing for future use of the painter.
-       pi.pain.setDrawingEnabled(true);
 
        //LYXERR(Debug::PAINTING, ".");
 }
diff --git a/src/frontends/Makefile.am b/src/frontends/Makefile.am
index 862613a..22b7508 100644
--- a/src/frontends/Makefile.am
+++ b/src/frontends/Makefile.am
@@ -17,6 +17,7 @@ liblyxfrontends_a_SOURCES = \
        Delegates.h \
        KeyModifier.h \
        KeySymbol.h \
+       NullPainter.h \
        Painter.h \
        Clipboard.h \
        Selection.h \
diff --git a/src/frontends/NullPainter.h b/src/frontends/NullPainter.h
new file mode 100644
index 0000000..19ac8b6
--- /dev/null
+++ b/src/frontends/NullPainter.h
@@ -0,0 +1,109 @@
+// -*- C++ -*-
+/**
+ * \file NullPainter.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author unknown
+ * \author John Levon
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef NULLPAINTER_H
+#define NULLPAINTER_H
+
+#include "Painter.h"
+
+namespace lyx {
+
+namespace frontend {
+
+/**
+ * NullPainter - A painter instance that does nothing
+ */
+class NullPainter : public Painter {
+public:
+       NullPainter() : Painter(1) {}
+
+       ~NullPainter() {}
+
+       /// draw a line from point to point
+       void line(int, int, int, int, Color,
+               line_style = line_solid, int = thin_line) {}
+
+       ///
+       void lines(int const *, int const *, int, Color,
+               fill_style = fill_none, line_style = line_solid,
+               int = thin_line) {}
+
+       ///
+       void path(int const *, int const *, int const *, int const *,
+               int const *, int const *, int, Color,
+               fill_style = fill_none, line_style = line_solid, int = 
thin_line) {}
+
+       /// draw a rectangle
+       void rectangle(int, int, int, int, Color,
+               line_style = line_solid, int = thin_line) {}
+
+       /// draw a filled rectangle
+       void fillRectangle(int, int, int, int, Color) {}
+
+       /// draw an arc
+       void arc(int, int, unsigned int, unsigned int, int, int, Color) {}
+
+       /// draw a pixel
+       void point(int, int, Color) {}
+
+       /// draw an image from the image cache
+       void image(int, int, int, int, graphics::Image const &) {}
+
+       /// draw a string
+       void text(int, int, docstring const &, FontInfo const &) {}
+
+       /// draw a char
+       void text(int, int, char_type, FontInfo const &) {}
+
+       /// draw a string
+       void text(int, int, docstring const &, Font const &, double, double) {}
+
+       ///
+       void text(int, int, docstring const &, Font const &,
+                 Color, size_type, size_type, double, double) {}
+
+       /// This painter does not paint
+       bool isNull() const { return true; }
+
+       /// draw the underbar, strikeout, xout, uuline and uwave font attributes
+       void textDecoration(FontInfo const &, int, int, int) {}
+
+       /**
+        * Draw a string and enclose it inside a rectangle. If
+        * back color is specified, the background is cleared with
+        * the given color. If frame is specified, a thin frame is drawn
+        * around the text with the given color.
+        */
+       void rectText(int, int, docstring const &,
+                     FontInfo const &, Color, Color) {}
+
+       /// draw a string and enclose it inside a button frame
+       void buttonText(int, int, docstring const &,
+                       FontInfo const &, Color, Color, int) {}
+
+       /// draw a character of a preedit string for cjk support.
+       int preeditText(int, int, char_type, FontInfo const &,
+                       preedit_style) { return 0; }
+
+       /// start monochrome painting mode, i.e. map every color into [min,max]
+       void enterMonochromeMode(Color const &, Color const &) {}
+       /// leave monochrome painting mode
+       void leaveMonochromeMode() {}
+       /// draws a wavy line that can be used for underlining.
+       void wavyHorizontalLine(int, int, int, ColorCode) {}
+};
+
+} // namespace frontend
+} // namespace lyx
+
+#endif // NULLPAINTER_H
diff --git a/src/frontends/Painter.h b/src/frontends/Painter.h
index d03ebf4..17253b2 100644
--- a/src/frontends/Painter.h
+++ b/src/frontends/Painter.h
@@ -49,7 +49,7 @@ namespace frontend {
  */
 class Painter {
 public:
-       Painter(double pixel_ratio) : drawing_enabled_(true), 
pixel_ratio_(pixel_ratio) {}
+       Painter(double pixel_ratio) : pixel_ratio_(pixel_ratio) {}
 
        static const int thin_line;
 
@@ -147,11 +147,8 @@ public:
                          Color other, size_type from, size_type to,
                       double wordspacing, double textwidth) = 0;
 
-       void setDrawingEnabled(bool drawing_enabled)
-       { drawing_enabled_ = drawing_enabled; }
-
-       /// Indicate wether real screen drawing shall be done or not.
-       bool isDrawingEnabled() const { return drawing_enabled_; }
+       // Returns true if the painter does not actually paint.
+       virtual bool isNull() const = 0;
 
        double pixelRatio() const { return pixel_ratio_; }
 
@@ -183,8 +180,6 @@ public:
        /// draws a wavy line that can be used for underlining.
        virtual void wavyHorizontalLine(int x, int y, int width, ColorCode col) 
= 0;
 private:
-       ///
-       bool drawing_enabled_;
        /// Ratio between physical pixels and device-independent pixels
        double pixel_ratio_;
 };
diff --git a/src/frontends/qt4/GuiPainter.cpp b/src/frontends/qt4/GuiPainter.cpp
index e832f23..bff8f9d 100644
--- a/src/frontends/qt4/GuiPainter.cpp
+++ b/src/frontends/qt4/GuiPainter.cpp
@@ -171,9 +171,6 @@ void GuiPainter::leaveMonochromeMode()
 
 void GuiPainter::point(int x, int y, Color col)
 {
-       if (!isDrawingEnabled())
-               return;
-
        setQPainterPen(computeColor(col));
        drawPoint(x, y);
 }
@@ -184,9 +181,6 @@ void GuiPainter::line(int x1, int y1, int x2, int y2,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        setQPainterPen(computeColor(col), ls, lw);
        bool const do_antialiasing = renderHints() & TextAntialiasing
                && x1 != x2 && y1 != y2 && ls != line_solid_aliased;
@@ -202,9 +196,6 @@ void GuiPainter::lines(int const * xp, int const * yp, int 
np,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        // double the size if needed
        // FIXME THREAD
        static QVector<QPoint> points(32);
@@ -247,9 +238,6 @@ void GuiPainter::path(int const * xp, int const * yp,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        QPainterPath bpath;
        // This is the starting point, so its control points are meaningless
        bpath.moveTo(xp[0], yp[0]);
@@ -278,9 +266,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h,
        line_style ls,
        int lw)
 {
-       if (!isDrawingEnabled())
-               return;
-
        setQPainterPen(computeColor(col), ls, lw);
        drawRect(x, y, w, h);
 }
@@ -288,9 +273,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h,
 
 void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col)
 {
-       if (!isDrawingEnabled())
-               return;
-
        fillRect(x, y, w, h, guiApp->colorCache().get(col));
 }
 
@@ -298,9 +280,6 @@ void GuiPainter::fillRectangle(int x, int y, int w, int h, 
Color col)
 void GuiPainter::arc(int x, int y, unsigned int w, unsigned int h,
        int a1, int a2, Color col)
 {
-       if (!isDrawingEnabled())
-               return;
-
        // LyX usings 1/64ths degree, Qt usings 1/16th
        setQPainterPen(computeColor(col));
        bool const do_antialiasing = renderHints() & TextAntialiasing;
@@ -317,9 +296,6 @@ void GuiPainter::image(int x, int y, int w, int h, 
graphics::Image const & i)
 
        fillRectangle(x, y, w, h, Color_graphicsbg);
 
-       if (!isDrawingEnabled())
-               return;
-
        QImage const image = qlimage.image();
        QRectF const drect = QRectF(x, y, w, h);
        QRectF const srect = QRectF(0, 0, image.width(), image.height());
@@ -391,7 +367,7 @@ void GuiPainter::text(int x, int y, docstring const & s,
                       double const wordspacing, double const tw)
 {
        //LYXERR0("text: x=" << x << ", s=" << s);
-       if (s.empty() || !isDrawingEnabled())
+       if (s.empty())
                return;
 
        /* Caution: The following ucs4 to QString conversions work for symbol 
fonts
diff --git a/src/frontends/qt4/GuiPainter.h b/src/frontends/qt4/GuiPainter.h
index 9657ed9..7513965 100644
--- a/src/frontends/qt4/GuiPainter.h
+++ b/src/frontends/qt4/GuiPainter.h
@@ -37,6 +37,9 @@ public:
        GuiPainter(QPaintDevice *, double pixel_ratio);
        virtual ~GuiPainter();
 
+       /// This painter paints
+       virtual bool isNull() const { return false; }
+
        /// draw a line from point to point
        virtual void line(
                int x1, int y1,
diff --git a/src/frontends/qt4/GuiWorkArea.cpp 
b/src/frontends/qt4/GuiWorkArea.cpp
index 8bf5242..ea6423a 100644
--- a/src/frontends/qt4/GuiWorkArea.cpp
+++ b/src/frontends/qt4/GuiWorkArea.cpp
@@ -16,6 +16,11 @@
 
 #include "ColorCache.h"
 #include "FontLoader.h"
+#include "GuiApplication.h"
+#include "GuiCompleter.h"
+#include "GuiKeySymbol.h"
+#include "GuiPainter.h"
+#include "GuiView.h"
 #include "Menus.h"
 
 #include "Buffer.h"
@@ -26,11 +31,6 @@
 #include "Cursor.h"
 #include "Font.h"
 #include "FuncRequest.h"
-#include "GuiApplication.h"
-#include "GuiCompleter.h"
-#include "GuiKeySymbol.h"
-#include "GuiPainter.h"
-#include "GuiView.h"
 #include "KeySymbol.h"
 #include "Language.h"
 #include "LyX.h"
@@ -1289,9 +1289,8 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
                return;
        }
 
-       GuiPainter pain(d->screen_, pixelRatio());
        d->buffer_view_->updateMetrics();
-       d->buffer_view_->draw(pain);
+       d->updateScreen();
        // FIXME: shall we use real_current_font here? (see #10478)
        FontInfo font = d->buffer_view_->cursor().getFont().fontInfo();
        FontMetrics const & fm = theFontMetrics(font);
@@ -1383,6 +1382,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e)
                        ps = Painter::preedit_cursor;
 
                // draw one character and update cur_x.
+               GuiPainter pain(d->screen_, pixelRatio());
                cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps);
        }
 
diff --git a/src/mathed/InsetMathMacroTemplate.cpp 
b/src/mathed/InsetMathMacroTemplate.cpp
index 17fc2d0..a2fc064 100644
--- a/src/mathed/InsetMathMacroTemplate.cpp
+++ b/src/mathed/InsetMathMacroTemplate.cpp
@@ -231,25 +231,17 @@ void InsetDisplayLabelBox::metrics(MetricsInfo & mi, 
Dimension & dim) const
 {
        InsetLabelBox::metrics(mi, dim);
        if (!parent_.editing(mi.base.bv)
-           && parent_.cell(parent_.displayIdx()).empty()) {
-               dim.wid = 0;
-               dim.asc = 0;
-               dim.des = 0;
-       }
+           && parent_.cell(parent_.displayIdx()).empty())
+               dim.clear();
 }
 
 
 void InsetDisplayLabelBox::draw(PainterInfo & pi, int x, int y) const
 {
        if (parent_.editing(pi.base.bv)
-           || !parent_.cell(parent_.displayIdx()).empty()) {
-               InsetLabelBox::draw(pi, x, y);
-       } else {
-               bool enabled = pi.pain.isDrawingEnabled();
-               pi.pain.setDrawingEnabled(false);
-               InsetLabelBox::draw(pi, x, y);
-               pi.pain.setDrawingEnabled(enabled);
-       }
+           || !parent_.cell(parent_.displayIdx()).empty()
+               || pi.pain.isNull())
+           InsetLabelBox::draw(pi, x, y);
 }
 
 

Reply via email to