From ffb865d6e82fccdaa64d5e0aa4e3beea3fcad003 Mon Sep 17 00:00:00 2001 From: Guillaume Munch Date: Sun, 20 Nov 2016 20:08:11 +0100 Subject: [PATCH] Clean up and fixes to fractions metrics and drawing * Factor code for easier maintainance. * Avoid computing metrics several times. This duplication explained the exponential blowup during the metrics phase for nested fractions (see b2b87330). This happened in particular when using lyxproofs which heavily uses nested \dfracs for on-screen drawing. * Call MetricsBase::changeScript instead of MetricsBase::changeFrac for \nicefrac and \unitfrac. --- src/mathed/InsetMathFrac.cpp | 250 +++++++++++++++++++---------------- 1 file changed, 137 insertions(+), 113 deletions(-) diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp index 5662923b7b..42cc3a2f58 100644 --- a/src/mathed/InsetMathFrac.cpp +++ b/src/mathed/InsetMathFrac.cpp @@ -152,62 +152,71 @@ void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const { Dimension dim0, dim1, dim2; - // This could be simplified, including avoiding useless recalculation of - // cell metrics - if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) { - if (nargs() == 1) { - Changer dummy = mi.base.font.changeShape(UP_SHAPE); - cell(0).metrics(mi, dim0); - dim.wid = dim0.width()+ 3; - dim.asc = dim0.asc; - dim.des = dim0.des; - } else if (nargs() == 2) { - cell(0).metrics(mi, dim0); - Changer dummy = mi.base.font.changeShape(UP_SHAPE); - cell(1).metrics(mi, dim1); - dim.wid = dim0.width() + dim1.wid + 5; - dim.asc = max(dim0.asc, dim1.asc); - dim.des = max(dim0.des, dim1.des); - } else { + switch (kind_) { + case UNIT: { + // \unitone, \unittwo + dim.wid = 0; + int unit_cell = 0; + // is there an extra cell holding the value being given a dimension? + // (this is \unittwo) + if (nargs() == 2) { + cell(0).metrics(mi, dim1); + dim.wid += dim1.wid + 4; + unit_cell = 1; + } + Changer dummy = mi.base.font.changeShape(UP_SHAPE); + cell(unit_cell).metrics(mi, dim0); + dim.wid += dim0.width() + 1; + dim.asc = max(dim0.asc, dim1.asc); + dim.des = max(dim0.des, dim1.des); + } + break; + + case UNITFRAC: + case NICEFRAC: { + // \unitfrac, \unitfracthree, \nicefrac + dim.wid = 0; + // is there an extra cell holding the value being given a dimension? + // (this is \unitfracthree) + if (kind_ == UNITFRAC && nargs() == 3) { cell(2).metrics(mi, dim2); - Changer dummy = mi.base.font.changeShape(UP_SHAPE); - Changer dummy2 = mi.base.changeFrac(); - cell(0).metrics(mi, dim0); - cell(1).metrics(mi, dim1); - dim.wid = dim0.width() + dim1.wid + dim2.wid + 10; - dim.asc = max(dim2.asc, dim0.height() + 5); - dim.des = max(dim2.des, dim1.height() - 5); + dim.wid += dim2.wid + 4; } - } else { - // general cell metrics used for \frac - Changer dummy = mi.base.changeFrac(); - // FIXME: Exponential blowup + Changer dummy = mi.base.font.changeShape(UP_SHAPE, kind_ == UNITFRAC); + Changer dummy2 = mi.base.changeScript(); cell(0).metrics(mi, dim0); cell(1).metrics(mi, dim1); - if (nargs() == 3) - cell(2).metrics(mi, dim2); - // metrics for special fraction types - if (kind_ == NICEFRAC || kind_ == UNITFRAC) { - Changer dummy2 = mi.base.font.changeShape(UP_SHAPE, kind_ == UNITFRAC); - dim.wid = dim0.width() + dim1.wid + 5; - dim.asc = dim0.height() + 5; - dim.des = dim1.height() - 5; - } else { - if (kind_ == CFRAC || kind_ == CFRACLEFT || kind_ == CFRACRIGHT - || kind_ == DFRAC || kind_ == TFRAC) { - // \cfrac and \dfrac are always in display size - // \tfrac is in always in text size - Changer dummy2 = mi.base.font.changeStyle((kind_ == TFRAC) - ? LM_ST_SCRIPT - : LM_ST_DISPLAY); - cell(0).metrics(mi, dim0); - cell(1).metrics(mi, dim1); - } - dim.wid = max(dim0.wid, dim1.wid) + 2; - dim.asc = dim0.height() + 2 + 5; - dim.des = dim1.height() + 2 - 5; - } + dim.wid += dim0.wid + dim1.wid + 5; + dim.asc = max(dim2.asc, dim0.height() + 5); + dim.des = max(dim2.des, dim1.height() - 5); } + break; + + case FRAC: + case CFRAC: + case CFRACLEFT: + case CFRACRIGHT: + case DFRAC: + case TFRAC: + case OVER: + case ATOP: { + Changer dummy = + // \tfrac is always in text size + (kind_ == TFRAC) ? mi.base.font.changeStyle(LM_ST_SCRIPT) : + // \cfrac and \dfrac are always in display size + (kind_ == CFRAC + || kind_ == CFRACLEFT + || kind_ == CFRACRIGHT + || kind_ == DFRAC) ? mi.base.font.changeStyle(LM_ST_DISPLAY) : + // all others + mi.base.changeFrac(); + cell(0).metrics(mi, dim0); + cell(1).metrics(mi, dim1); + dim.wid = max(dim0.wid, dim1.wid) + 2; + dim.asc = dim0.height() + 2 + 5; + dim.des = dim1.height() + 2 - 5; + } + } //switch (kind_) metricsMarkers(mi, dim); } @@ -217,74 +226,89 @@ void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const setPosCache(pi, x, y); Dimension const dim = dimension(*pi.base.bv); Dimension const dim0 = cell(0).dimension(*pi.base.bv); - if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) { - if (nargs() == 1) { - Changer dummy = pi.base.font.changeShape(UP_SHAPE); - cell(0).draw(pi, x + 1, y); - } else if (nargs() == 2) { + switch (kind_) { + case UNIT: { + // \unitone, \unittwo + int xx = x; + int unit_cell = 0; + // is there an extra cell holding the value being given a dimension? + // (this is \unittwo) + if (nargs() == 2) { cell(0).draw(pi, x + 1, y); - Changer dummy = pi.base.font.changeShape(UP_SHAPE); - cell(1).draw(pi, x + dim0.width() + 5, y); - } else { + xx += dim0.wid + 4; + unit_cell = 1; + } + Changer dummy = pi.base.font.changeShape(UP_SHAPE); + cell(unit_cell).draw(pi, xx + 1, y); + } + break; + + case UNITFRAC: + case NICEFRAC: { + // \unitfrac, \unitfracthree, \nicefrac + int xx = x; + // is there an extra cell holding the value being given a dimension? + // (this is \unitfracthree) + if (kind_ == UNITFRAC && nargs() == 3) { cell(2).draw(pi, x + 1, y); - Changer dummy = pi.base.font.changeShape(UP_SHAPE); - Changer dummy2 = pi.base.changeFrac(); - Dimension const dim1 = cell(1).dimension(*pi.base.bv); - Dimension const dim2 = cell(2).dimension(*pi.base.bv); - int xx = x + dim2.wid + 5; - cell(0).draw(pi, xx + 2, - y - dim0.des - 5); - cell(1).draw(pi, xx + dim0.width() + 5, - y + dim1.asc / 2); + xx += cell(2).dimension(*pi.base.bv).wid + 4; } - } else { - Changer dummy = pi.base.changeFrac(); + Changer dummy = pi.base.font.changeShape(UP_SHAPE, kind_ == UNITFRAC); + // nice fraction + // FIXME: + // * the solidus should be \kern-2mu/\kern-1mu. + // * the vertical offset of the first cell should be such that the + // top of M in the first cell matches the one of the + // surrounding text. + Changer dummy2 = pi.base.changeScript(); + cell(0).draw(pi, xx + 2, y - dim0.des - 5); Dimension const dim1 = cell(1).dimension(*pi.base.bv); - int m = x + dim.wid / 2; - if (kind_ == NICEFRAC) { - cell(0).draw(pi, x + 2, - y - dim0.des - 5); - cell(1).draw(pi, x + dim0.width() + 5, - y + dim1.asc / 2); - } else if (kind_ == UNITFRAC) { - Changer dummy2 = pi.base.font.changeShape(UP_SHAPE); - cell(0).draw(pi, x + 2, y - dim0.des - 5); - cell(1).draw(pi, x + dim0.width() + 5, y + dim1.asc / 2); - } else if (kind_ == FRAC || kind_ == ATOP || kind_ == OVER - || kind_ == TFRAC) { - // tfrac is in always in text size - Changer dummy2 = pi.base.font.changeStyle(LM_ST_SCRIPT, - kind_ == TFRAC); - cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5); - cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5); - } else { - // \cfrac and \dfrac are always in display size - Changer dummy2 = pi.base.font.changeStyle(LM_ST_DISPLAY); - if (kind_ == CFRAC || kind_ == DFRAC) - cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 2 - 5); - else if (kind_ == CFRACLEFT) - cell(0).draw(pi, x + 2, y - dim0.des - 2 - 5); - else if (kind_ == CFRACRIGHT) - cell(0).draw(pi, x + dim.wid - dim0.wid - 2, - y - dim0.des - 2 - 5); - cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5); - } - } - if (kind_ == NICEFRAC || kind_ == UNITFRAC) { + cell(1).draw(pi, xx + dim0.wid + 5, y + dim1.asc / 2); // Diag line: - int xx = x; - if (nargs() == 3) - xx += cell(2).dimension(*pi.base.bv).wid + 5; - pi.pain.line(xx + dim0.wid, - y + dim.des - 2, - xx + dim0.wid + 5, - y - dim.asc + 2, pi.base.font.color()); + pi.pain.line(xx + dim0.wid + 1, y + dim.des - 2, + xx + dim0.wid + 6, y - dim.asc + 2, + pi.base.font.color()); + } + break; + + case FRAC: + case CFRAC: + case CFRACLEFT: + case CFRACRIGHT: + case DFRAC: + case TFRAC: + case OVER: + case ATOP: { + Changer dummy = + // \tfrac is always in text size + (kind_ == TFRAC) ? pi.base.font.changeStyle(LM_ST_SCRIPT) : + // \cfrac and \dfrac are always in display size + (kind_ == CFRAC + || kind_ == CFRACLEFT + || kind_ == CFRACRIGHT + || kind_ == DFRAC) ? pi.base.font.changeStyle(LM_ST_DISPLAY) : + // all others + pi.base.changeFrac(); + Dimension const dim1 = cell(1).dimension(*pi.base.bv); + int m = x + dim.wid / 2; + int xx = + // align left + (kind_ == CFRACLEFT) ? x + 2 : + // align right + (kind_ == CFRACRIGHT) ? x + dim.wid - dim0.wid - 2 : + // center + m - dim0.wid / 2; + // FIXME: vertical offset should be based on ex + //int dy = theFontMetrics(pi.base.font).ex() / 2; + cell(0).draw(pi, xx, y - dim0.des - 2 - 5); + // center + cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 2 - 5); + // horizontal line + if (kind_ != ATOP) + pi.pain.line(x + 1, y - 5, + x + dim.wid - 2, y - 5, pi.base.font.color()); } - if (kind_ == FRAC || kind_ == CFRAC || kind_ == CFRACLEFT - || kind_ == CFRACRIGHT || kind_ == DFRAC - || kind_ == TFRAC || kind_ == OVER) - pi.pain.line(x + 1, y - 5, - x + dim.wid - 2, y - 5, pi.base.font.color()); + } //switch (kind_) drawMarkers(pi, x, y); } -- 2.39.5