]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/MathData.cpp
Fix a crash with uninitialized buffer member of MathData
[lyx.git] / src / mathed / MathData.cpp
index 322a8e9ceba2b8378a213d0e96cbf48d332e7978..9bfd558fe2856d8e1475648b8c9b1963255cf25a 100644 (file)
@@ -17,7 +17,7 @@
 #include "InsetMathFont.h"
 #include "InsetMathScript.h"
 #include "MacroTable.h"
-#include "MathMacro.h"
+#include "InsetMathMacro.h"
 #include "MathStream.h"
 #include "MathSupport.h"
 #include "MetricsInfo.h"
@@ -48,10 +48,18 @@ namespace lyx {
 
 MathData::MathData(Buffer * buf, const_iterator from, const_iterator to)
        : base_type(from, to), minasc_(0), mindes_(0), slevel_(0),
-         sshift_(0), kerning_(0), buffer_(buf)
+         sshift_(0), buffer_(buf)
 {}
 
 
+void MathData::setBuffer(Buffer & b)
+{
+       buffer_ = &b;
+       for (MathAtom & at : *this)
+               at.nucleus()->setBuffer(b);
+}
+
+
 MathAtom & MathData::operator[](pos_type pos)
 {
        LBUFERR(pos < size());
@@ -212,11 +220,6 @@ bool MathData::contains(MathData const & ar) const
 }
 
 
-void MathData::touch() const
-{
-}
-
-
 bool MathData::addToMathRow(MathRow & mrow, MetricsInfo & mi) const
 {
        bool has_contents = false;
@@ -264,25 +267,45 @@ bool isInside(DocIterator const & it, MathData const & ar,
 #endif
 
 
-void MathData::metrics(MetricsInfo & mi, Dimension & dim) const
+void MathData::metrics(MetricsInfo & mi, Dimension & dim, bool tight) const
 {
        frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
-       dim = fm.dimension('I');
-       int xascent = fm.dimension('x').ascent();
-       if (xascent >= dim.asc)
-               xascent = (2 * dim.asc) / 3;
+       BufferView * bv = mi.base.bv;
+       int const Iascent = fm.dimension('I').ascent();
+       int xascent = fm.xHeight();
+       if (xascent >= Iascent)
+               xascent = (2 * Iascent) / 3;
        minasc_ = xascent;
        mindes_ = (3 * xascent) / 4;
        slevel_ = (4 * xascent) / 5;
        sshift_ = xascent / 4;
 
        MathRow mrow(mi, this);
-       mrow_cache_[mi.base.bv] = mrow;
        mrow.metrics(mi, dim);
-       kerning_ = mrow.kerning(mi.base.bv);
 
-       // Cache the dimension.
-       mi.base.bv->coordCache().arrays().add(this, dim);
+       // Set a minimal ascent/descent for the cell
+       if (tight)
+               // FIXME: this is the minimal ascent seen empirically, check
+               // what the TeXbook says.
+               dim.asc = max(dim.asc, fm.xHeight());
+       else {
+               dim.asc = max(dim.asc, fm.maxAscent());
+               dim.des = max(dim.des, fm.maxDescent());
+       }
+
+       // This is one of the the few points where the drawing font is known,
+       // so that we can set the caret vertical dimensions.
+       mrow.caret_ascent = min(dim.asc, fm.maxAscent());
+       mrow.caret_descent = min(dim.des, fm.maxDescent());
+       /// do the same for math cells linearized in the row
+       MathRow caret_row = MathRow(mrow.caret_ascent, mrow.caret_descent);
+       for (auto const & e : mrow)
+               if (e.type == MathRow::BEGIN && e.ar)
+                       bv->setMathRow(e.ar, caret_row);
+
+       // Cache row and dimension.
+       bv->setMathRow(this, mrow);
+       bv->coordCache().arrays().add(this, dim);
 }
 
 
@@ -323,20 +346,10 @@ void MathData::drawSelection(PainterInfo & pi, int const x, int const y) const
 void MathData::draw(PainterInfo & pi, int const x, int const y) const
 {
        //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl;
-       BufferView & bv  = *pi.base.bv;
-       setXY(bv, x, y);
-
-       Dimension const & dim = bv.coordCache().getArrays().dim(this);
-
-       // don't draw outside the workarea
-       if (y + dim.descent() <= 0
-               || y - dim.ascent() >= bv.workHeight()
-               || x + dim.width() <= 0
-               || x >= bv. workWidth())
-               return;
+       setXY(*pi.base.bv, x, y);
 
        drawSelection(pi, x, y);
-       MathRow const & mrow = mrow_cache_[pi.base.bv];
+       MathRow const & mrow = pi.base.bv->mathRow(this);
        mrow.draw(pi, x, y);
 }
 
@@ -367,6 +380,12 @@ void MathData::drawT(TextPainter & pain, int x, int y) const
 }
 
 
+int MathData::kerning(BufferView const * bv) const
+{
+       return  bv->mathRow(this).kerning(bv);
+}
+
+
 void MathData::updateBuffer(ParIterator const & it, UpdateType utype)
 {
        // pass down
@@ -383,18 +402,18 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc,
        // If we are editing a macro, we cannot update it immediately,
        // otherwise wrong undo steps will be recorded (bug 6208).
        InsetMath const * inmath = cur ? cur->inset().asInsetMath() : 0;
-       MathMacro const * inmacro = inmath ? inmath->asMacro() : 0;
+       InsetMathMacro const * inmacro = inmath ? inmath->asMacro() : 0;
        docstring const edited_name = inmacro ? inmacro->name() : docstring();
 
        // go over the array and look for macros
        for (size_t i = 0; i < size(); ++i) {
-               MathMacro * macroInset = operator[](i).nucleus()->asMacro();
+               InsetMathMacro * macroInset = operator[](i).nucleus()->asMacro();
                if (!macroInset || macroInset->macroName().empty()
                                || macroInset->macroName()[0] == '^'
                                || macroInset->macroName()[0] == '_'
                                || (macroInset->name() == edited_name
                                    && macroInset->displayMode() ==
-                                               MathMacro::DISPLAY_UNFOLDED))
+                                               InsetMathMacro::DISPLAY_UNFOLDED))
                        continue;
 
                // get macro
@@ -408,23 +427,23 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc,
                }
 
                // store old and compute new display mode
-               MathMacro::DisplayMode newDisplayMode;
-               MathMacro::DisplayMode oldDisplayMode = macroInset->displayMode();
+               InsetMathMacro::DisplayMode newDisplayMode;
+               InsetMathMacro::DisplayMode oldDisplayMode = macroInset->displayMode();
                newDisplayMode = macroInset->computeDisplayMode();
 
                // arity changed or other reason to detach?
-               if (oldDisplayMode == MathMacro::DISPLAY_NORMAL
+               if (oldDisplayMode == InsetMathMacro::DISPLAY_NORMAL
                    && (macroInset->arity() != macroNumArgs
                        || macroInset->optionals() != macroOptionals
-                       || newDisplayMode == MathMacro::DISPLAY_UNFOLDED))
+                       || newDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED))
                        detachMacroParameters(cur, i);
 
                // the macro could have been copied while resizing this
                macroInset = operator[](i).nucleus()->asMacro();
 
                // Cursor in \label?
-               if (newDisplayMode != MathMacro::DISPLAY_UNFOLDED
-                   && oldDisplayMode == MathMacro::DISPLAY_UNFOLDED) {
+               if (newDisplayMode != InsetMathMacro::DISPLAY_UNFOLDED
+                   && oldDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED) {
                        // put cursor in front of macro
                        if (cur) {
                                int macroSlice = cur->find(macroInset);
@@ -438,19 +457,19 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc,
                macroInset->setDisplayMode(newDisplayMode);
 
                // arity changed?
-               if (newDisplayMode == MathMacro::DISPLAY_NORMAL
+               if (newDisplayMode == InsetMathMacro::DISPLAY_NORMAL
                    && (macroInset->arity() != macroNumArgs
                        || macroInset->optionals() != macroOptionals)) {
                        // is it a virgin macro which was never attached to parameters?
                        bool fromInitToNormalMode
-                       = (oldDisplayMode == MathMacro::DISPLAY_INIT
-                          || oldDisplayMode == MathMacro::DISPLAY_INTERACTIVE_INIT)
-                         && newDisplayMode == MathMacro::DISPLAY_NORMAL;
+                       = (oldDisplayMode == InsetMathMacro::DISPLAY_INIT
+                          || oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT)
+                         && newDisplayMode == InsetMathMacro::DISPLAY_NORMAL;
 
                        // if the macro was entered interactively (i.e. not by paste or during
                        // loading), it should not be greedy, but the cursor should
                        // automatically jump into the macro when behind
-                       bool interactive = (oldDisplayMode == MathMacro::DISPLAY_INTERACTIVE_INIT);
+                       bool interactive = (oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT);
 
                        // attach parameters
                        attachMacroParameters(cur, i, macroNumArgs, macroOptionals,
@@ -474,7 +493,7 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc,
 
 void MathData::detachMacroParameters(DocIterator * cur, const size_type macroPos)
 {
-       MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
+       InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
        // We store this now, because the inset pointer will be invalidated in the scond loop below
        size_t const optionals = macroInset->optionals();
 
@@ -605,7 +624,7 @@ void MathData::attachMacroParameters(Cursor * cur,
        const int macroOptionals, const bool fromInitToNormalMode,
        const bool interactiveInit, const size_t appetite)
 {
-       MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
+       InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
 
        // start at atom behind the macro again, maybe with some new arguments
        // from the detach phase above, to add them back into the macro inset
@@ -739,7 +758,9 @@ void MathData::collectOptionalParameters(Cursor * cur,
                        params.push_back(optarg);
 
                // place cursor in optional argument of macro
-               if (thisSlice != -1
+               // Note: The two expressions on the first line are equivalent
+               // (see caller), but making this explicit pleases coverity.
+               if (cur && thisSlice != -1
                    && thisPos >= int(pos) && thisPos <= int(right)) {
                        int paramPos = max(0, thisPos - int(pos) - 1);
                        vector<CursorSlice> x;
@@ -779,7 +800,10 @@ void MathData::collectParameters(Cursor * cur,
                // fix cursor
                vector<CursorSlice> argSlices;
                int argPos = 0;
-               if (thisSlice != -1 && thisPos == int(pos))
+               // Note: The two expressions on the first line are equivalent
+               // (see caller), but making this explicit pleases coverity.
+               if (cur && thisSlice != -1
+                       && thisPos == int(pos))
                        cur->cutOff(thisSlice, argSlices);
 
                // which kind of parameter is it? In {}? With index x^n?
@@ -820,7 +844,10 @@ void MathData::collectParameters(Cursor * cur,
                }
 
                // put cursor in argument again
-               if (thisSlice != - 1 && thisPos == int(pos)) {
+               // Note: The first two expressions on the first line are
+               // equivalent (see caller), but making this explicit pleases
+               // coverity.
+               if (cur && thisSlice != -1 && thisPos == int(pos)) {
                        cur->append(params.size() - 1, argPos);
                        cur->append(argSlices);
                        (*cur)[thisSlice].pos() = macroPos;