Le 09/06/2016 09:53, Jean-Marc Lasgouttes a écrit :
Le 08/06/2016 à 01:30, Guillaume Munch a écrit :
Try changing 'return rc;' to 'return std::move(rc);' (twice).

Unfortunately, with Georg's recent changes, I don't think that your
patches still apply. The best would be to publish the branch you are
working on in the features repository and remerge it as needed.

I believe clang is right and gcc is wrong. gcc treats rc as an rvalue,
which makes the conversion into unique_ptr<Revertible> valid. But rc
should not be considered as an rvalue, because the standard only allows
the case when the return type matches the type of the expression (up
to cv-qualifiers).

Hmm, this is way above my head :) But the rule of thumb "clang is
usually right" is usually right.




I was about to push the rebased version with the corrections suggested
by your tests. I can either push now, or please can you confirm that the
attached RefChanger.h compiles?

Independently, can we drop clang 3.0? Starting from 3.1, clang support
anonymous functions, which are sometimes very convenient.

As for unicode.cpp, the error is in gcc 4.7 as well, thanks to which I
could check that it is corrected as I suggested, that is, explicitly
defining the move constructor as defaulted. This departs from the
specification and is very annoying. To begin with, this can cause silent
errors if the copy constructor is defined. Then the user writes move(p)
and it calls the copy constructor instead. Is it important to support
gcc 4.7?


(P.S.: I've got:

configure: WARNING: zlib.h: present but cannot be compiled
configure: WARNING: zlib.h: check for missing prerequisite headers?
configure: WARNING: zlib.h: see the Autoconf documentation
configure: WARNING: zlib.h: section "Present But Cannot Be Compiled"
configure: WARNING: zlib.h: proceeding with the compiler's result
configure: WARNING: ## -------------------------------------- ##
configure: WARNING: ## Report this to lyx-devel@lists.lyx.org ##
configure: WARNING: ## -------------------------------------- ##

just because of a typo in CXX. Shouldn't configure check that the
compiler executable exists first and foremost?)

>From fef91058ea3610ef20bb241c9aae0df707911715 Mon Sep 17 00:00:00 2001
From: Guillaume Munch <g...@lyx.org>
Date: Mon, 23 May 2016 22:30:23 +0100
Subject: [PATCH] RefChanger

RefChanger temporarily assigns a value to a non-const reference of any
kind. RefChanger provides a flexible and uniform generalisation of the various
scope guards previously derived from the old Changer class in MetricsInfo.h.

As before, a temporary assignment lasts as long as the Changer object lives. But
the new Changer is movable. In particular, contorsions are no longer needed to
change a private field. Special code can be moved into the appropriate classes,
and it is no longer necessary to create a new class for each specific use.

Syntax change:

   FontSetChanger dummy(mi.base, value);
-> Changer dummy = mi.base.changeFontSet(value);

New function for generating arbitrary Changers:

  Changer dummy = make_change(ref, val, condition);

Bugfix:

* Fix the display of \displaystyle{\substack{\frac{xyz}{}}} (missing style
  change).
---
 src/FontInfo.cpp                    |  21 ++++
 src/FontInfo.h                      |  11 ++
 src/MetricsInfo.cpp                 | 242 +++++++++---------------------------
 src/MetricsInfo.h                   | 130 +++----------------
 src/insets/InsetScript.cpp          |   4 +-
 src/mathed/InsetMathAMSArray.cpp    |   8 +-
 src/mathed/InsetMathArray.cpp       |   4 +-
 src/mathed/InsetMathBoldSymbol.cpp  |   4 +-
 src/mathed/InsetMathBox.cpp         |  12 +-
 src/mathed/InsetMathChar.cpp        |  12 +-
 src/mathed/InsetMathDecoration.cpp  |   4 +-
 src/mathed/InsetMathEnsureMath.cpp  |   4 +-
 src/mathed/InsetMathFont.cpp        |   4 +-
 src/mathed/InsetMathFontOld.cpp     |   4 +-
 src/mathed/InsetMathFrac.cpp        | 103 ++++++---------
 src/mathed/InsetMathHull.cpp        |  16 +--
 src/mathed/InsetMathOverset.cpp     |   5 +-
 src/mathed/InsetMathPar.cpp         |   4 +-
 src/mathed/InsetMathScript.cpp      |   4 +-
 src/mathed/InsetMathSideset.cpp     |   4 +-
 src/mathed/InsetMathSize.cpp        |   4 +-
 src/mathed/InsetMathSpecialChar.cpp |   4 +-
 src/mathed/InsetMathStackrel.cpp    |   5 +-
 src/mathed/InsetMathSubstack.cpp    |   9 +-
 src/mathed/InsetMathSymbol.cpp      |   5 +-
 src/mathed/InsetMathTabular.cpp     |   4 +-
 src/mathed/InsetMathUnderset.cpp    |   5 +-
 src/mathed/InsetMathXArrow.cpp      |   4 +-
 src/mathed/InsetMathXYArrow.cpp     |   6 +-
 src/mathed/MathMacro.cpp            |   4 +-
 src/mathed/MathMacroTemplate.cpp    |  12 +-
 src/support/Changer.h               |  32 +++++
 src/support/Makefile.am             |   2 +
 src/support/RefChanger.h            |  74 +++++++++++
 34 files changed, 337 insertions(+), 433 deletions(-)
 create mode 100644 src/support/Changer.h
 create mode 100644 src/support/RefChanger.h

diff --git a/src/FontInfo.cpp b/src/FontInfo.cpp
index e611288..9edf97e 100644
--- a/src/FontInfo.cpp
+++ b/src/FontInfo.cpp
@@ -21,6 +21,7 @@
 #include "support/debug.h"
 #include "support/docstring.h"
 #include "support/lstrings.h"
+#include "support/RefChanger.h"
 
 #include <ostream>
 #include <sstream>
@@ -245,6 +246,26 @@ FontInfo & FontInfo::realize(FontInfo const & tmplt)
 }
 
 
+Changer FontInfo::changeColor(ColorCode const color, bool cond)
+{
+	return make_change(color_, color, cond);
+}
+
+
+Changer FontInfo::changeShape(FontShape const shape, bool cond)
+{
+	return make_change(shape_, shape, cond);
+}
+
+
+Changer FontInfo::change(FontInfo font, bool realiz, bool cond)
+{
+	if (realiz)
+		font.realize(*this);
+	return make_change(*this, font, cond);
+}
+
+
 /// Updates a misc setting according to request
 static FontState setMisc(FontState newfont,
 	FontState org)
diff --git a/src/FontInfo.h b/src/FontInfo.h
index c31c7fa..5743098 100644
--- a/src/FontInfo.h
+++ b/src/FontInfo.h
@@ -18,7 +18,10 @@
 #include "Color.h"
 #include "ColorCode.h"
 #include "FontEnums.h"
+
 #include "support/strfwd.h"
+#include "support/Changer.h"
+
 
 namespace lyx {
 
@@ -136,6 +139,14 @@ public:
 		}
 	}
 
+	/// Temporarily replace the color with \param color.
+	Changer changeColor(ColorCode const color, bool cond = true);
+	/// Temporarily replace the shape with \param shape.
+	Changer changeShape(FontShape const shape, bool cond = true);
+	/// Temporarily replace the FontInfo with \param font, and optionally
+	/// \param realize the \param font against the current FontInfo.
+	Changer change(FontInfo font, bool realize = false, bool cond = true);
+
 private:
 	friend bool operator==(FontInfo const & lhs, FontInfo const & rhs);
 
diff --git a/src/MetricsInfo.cpp b/src/MetricsInfo.cpp
index 2b954d3..0dd7683 100644
--- a/src/MetricsInfo.cpp
+++ b/src/MetricsInfo.cpp
@@ -22,10 +22,11 @@
 
 #include "support/docstring.h"
 #include "support/lassert.h"
+#include "support/RefChanger.h"
+
 
 using namespace std;
 
-
 namespace lyx {
 
 /////////////////////////////////////////////////////////////////////////
@@ -46,6 +47,33 @@ MetricsBase::MetricsBase(BufferView * b, FontInfo const & f, int w)
 {}
 
 
+Changer MetricsBase::changeFontSet(docstring const & name, bool cond)
+{
+	RefChanger<MetricsBase> rc = make_save(*this);
+	if (!cond)
+		rc->keep();
+	else {
+		ColorCode oldcolor = font.color();
+		docstring const oldname = from_ascii(fontname);
+		fontname = to_utf8(name);
+		font = sane_font;
+		augmentFont(font, name);
+		font.setSize(rc->old.font.size());
+		if (name != "lyxtex"
+		    && ((isTextFont(oldname) && oldcolor != Color_foreground)
+		        || (isMathFont(oldname) && oldcolor != Color_math)))
+			font.setColor(oldcolor);
+	}
+	return move(rc);
+}
+
+
+Changer MetricsBase::changeFontSet(char const * name, bool cond)
+{
+	return changeFontSet(from_ascii(name), cond);
+}
+
+
 /////////////////////////////////////////////////////////////////////////
 //
 // MetricsInfo
@@ -117,210 +145,64 @@ Color PainterInfo::textColor(Color const & color) const
 }
 
 
-/////////////////////////////////////////////////////////////////////////
-//
-// ScriptChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-Styles smallerScriptStyle(Styles st)
+Changer MetricsBase::changeScript(bool cond)
 {
-	switch (st) {
+	Styles st;
+	switch (style) {
 		case LM_ST_DISPLAY:
 		case LM_ST_TEXT:
-			return LM_ST_SCRIPT;
+			st = LM_ST_SCRIPT;
 		case LM_ST_SCRIPT:
 		case LM_ST_SCRIPTSCRIPT:
-		default: // shut up compiler
-			return LM_ST_SCRIPTSCRIPT;
+			st = LM_ST_SCRIPTSCRIPT;
 	}
+	return changeStyle(st, cond);
 }
 
 
-ScriptChanger::ScriptChanger(MetricsBase & mb)
-	: StyleChanger(mb, smallerScriptStyle(mb.style))
-{}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// FracChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-Styles smallerFracStyle(Styles st)
+Changer MetricsBase::changeFrac(bool cond)
 {
-	switch (st) {
-		case LM_ST_DISPLAY:
-			return LM_ST_TEXT;
-		case LM_ST_TEXT:
-			return LM_ST_SCRIPT;
-		case LM_ST_SCRIPT:
-		case LM_ST_SCRIPTSCRIPT:
-		default: // shut up compiler
-			return LM_ST_SCRIPTSCRIPT;
+	Styles st;
+	switch (style) {
+	case LM_ST_DISPLAY:
+		st = LM_ST_TEXT;
+	case LM_ST_TEXT:
+		st = LM_ST_SCRIPT;
+	case LM_ST_SCRIPT:
+	case LM_ST_SCRIPTSCRIPT:
+		st = LM_ST_SCRIPTSCRIPT;
 	}
+	return changeStyle(st, cond);
 }
 
 
-FracChanger::FracChanger(MetricsBase & mb)
-	: StyleChanger(mb, smallerFracStyle(mb.style))
-{}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// ArrayChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-ArrayChanger::ArrayChanger(MetricsBase & mb)
-	: StyleChanger(mb, mb.style == LM_ST_DISPLAY ? LM_ST_TEXT : mb.style)
-{}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// ShapeChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-ShapeChanger::ShapeChanger(FontInfo & font, FontShape shape)
-	: Changer<FontInfo, FontShape>(font, font.shape())
+Changer MetricsBase::changeArray(bool cond)
 {
-	orig_.setShape(shape);
+	return changeStyle(style == LM_ST_DISPLAY ? LM_ST_TEXT : style, cond);
 }
 
 
-ShapeChanger::~ShapeChanger()
-{
-	orig_.setShape(save_);
-}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// StyleChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-StyleChanger::StyleChanger(MetricsBase & mb, Styles style)
-	: Changer<MetricsBase>(mb)
+Changer MetricsBase::changeStyle(Styles new_style, bool cond)
 {
 	static const int diff[4][4] =
 		{ { 0, 0, -3, -5 },
 		  { 0, 0, -3, -5 },
 		  { 3, 3,  0, -2 },
 		  { 5, 5,  2,  0 } };
-	int t = diff[mb.style][style];
-	if (t > 0)
-		while (t--)
-			mb.font.incSize();
-	else
-		while (t++)
-			mb.font.decSize();
-	mb.style = style;
-}
-
-
-StyleChanger::~StyleChanger()
-{
-	orig_ = save_;
-}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// FontSetChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-FontSetChanger::FontSetChanger(MetricsBase & mb, char const * name,
-				bool really_change_font)
-	: Changer<MetricsBase>(mb), change_(really_change_font)
-{
-	if (change_) {
-		FontSize oldsize = save_.font.size();
-		ColorCode oldcolor = save_.font.color();
-		docstring const oldname = from_ascii(save_.fontname);
-		mb.fontname = name;
-		mb.font = sane_font;
-		augmentFont(mb.font, from_ascii(name));
-		mb.font.setSize(oldsize);
-		if (string(name) != "lyxtex"
-		    && ((isTextFont(oldname) && oldcolor != Color_foreground)
-			|| (isMathFont(oldname) && oldcolor != Color_math)))
-			mb.font.setColor(oldcolor);
+	int t = diff[style][new_style];
+	RefChanger<MetricsBase> rc = make_save(*this);
+	if (!cond)
+		rc->keep();
+	else {
+		if (t > 0)
+			while (t--)
+				font.incSize();
+		else
+			while (t++)
+				font.decSize();
+		style = new_style;
 	}
-}
-
-
-FontSetChanger::FontSetChanger(MetricsBase & mb, docstring const & name,
-				bool really_change_font)
-	: Changer<MetricsBase>(mb), change_(really_change_font)
-{
-	if (change_) {
-		FontSize oldsize = save_.font.size();
-		ColorCode oldcolor = save_.font.color();
-		docstring const oldname = from_ascii(save_.fontname);
-		mb.fontname = to_utf8(name);
-		mb.font = sane_font;
-		augmentFont(mb.font, name);
-		mb.font.setSize(oldsize);
-		if (name != "lyxtex"
-		    && ((isTextFont(oldname) && oldcolor != Color_foreground)
-			|| (isMathFont(oldname) && oldcolor != Color_math)))
-			mb.font.setColor(oldcolor);
-	}
-}
-
-
-FontSetChanger::~FontSetChanger()
-{
-	if (change_)
-		orig_ = save_;
-}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// WidthChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-WidthChanger::WidthChanger(MetricsBase & mb, int w)
-	: Changer<MetricsBase>(mb)
-{
-	mb.textwidth = w;
-}
-
-
-WidthChanger::~WidthChanger()
-{
-	orig_ = save_;
-}
-
-
-/////////////////////////////////////////////////////////////////////////
-//
-// ColorChanger
-//
-/////////////////////////////////////////////////////////////////////////
-
-ColorChanger::ColorChanger(FontInfo & font, ColorCode color,
-			   bool really_change_color)
-	: Changer<FontInfo, ColorCode>(font, font.color()), change_(really_change_color)
-{
-	if (change_) {
-		font.setColor(color);
-	}
-}
-
-
-ColorChanger::~ColorChanger()
-{
-	if (change_)
-		orig_.setColor(save_);
+	return move(rc);
 }
 
 
diff --git a/src/MetricsInfo.h b/src/MetricsInfo.h
index 195d705..4fc18af 100644
--- a/src/MetricsInfo.h
+++ b/src/MetricsInfo.h
@@ -18,6 +18,8 @@
 #include "FontInfo.h"
 
 #include "support/strfwd.h"
+#include "support/Changer.h"
+
 
 #include <string>
 
@@ -31,6 +33,7 @@ class MacroContext;
 
 
 /// Standard Sizes (mode styles)
+/// note: These values are hard-coded in changeStyle
 enum Styles {
 	///
 	LM_ST_DISPLAY = 0,
@@ -63,6 +66,18 @@ public:
 	std::string fontname;
 	/// This is the width available in pixels
 	int textwidth;
+
+	/// Temporarily change a full font.
+	Changer changeFontSet(docstring const & font, bool cond = true);
+	Changer changeFontSet(char const * font, bool cond = true);
+	/// Temporarily change the font size and the math style.
+	Changer changeStyle(Styles style, bool cond = true);
+	// Temporarily change to the style suitable for use in fractions
+	Changer changeFrac(bool cond = true);
+	// Temporarily change to the style suitable for use in tabulars and arrays
+	Changer changeArray(bool cond = true);
+	// Temporarily change the style to (script)script style
+	Changer changeScript(bool cond = true);
 };
 
 
@@ -127,121 +142,6 @@ public:
 
 class TextMetricsInfo {};
 
-
-/// Generic base for temporarily changing things. The derived class is
-/// responsible for restoring the original state when the Changer is
-/// destructed.
-template <class Struct, class Temp = Struct>
-class Changer {
-protected:
-	///
-	Changer(Struct & orig, Temp const & save) : orig_(orig), save_(save) {}
-	///
-	Changer(Struct & orig) : orig_(orig), save_(orig) {}
-	///
-	Struct & orig_;
-	///
-	Temp save_;
-};
-
-
-
-// temporarily change some aspect of a font
-class FontChanger : public Changer<FontInfo> {
-public:
-	///
-	FontChanger(FontInfo & orig, docstring const & font);
-	FontChanger(MetricsBase & mb, char const * const font);
-	///
-	~FontChanger();
-};
-
-
-// temporarily change a full font
-class FontSetChanger : public Changer<MetricsBase> {
-public:
-	///
-	FontSetChanger(MetricsBase & mb, docstring const & font,
-			bool really_change_font = true);
-	FontSetChanger(MetricsBase & mb, char const * const font,
-			bool really_change_font = true);
-	///
-	~FontSetChanger();
-private:
-	///
-	bool change_;
-};
-
-
-// temporarily change the style
-class StyleChanger : public Changer<MetricsBase> {
-public:
-	///
-	StyleChanger(MetricsBase & mb, Styles style);
-	///
-	~StyleChanger();
-};
-
-
-// temporarily change the style to script style
-class ScriptChanger : public StyleChanger {
-public:
-	///
-	ScriptChanger(MetricsBase & mb);
-};
-
-
-// temporarily change the style suitable for use in fractions
-class FracChanger : public StyleChanger {
-public:
-	///
-	FracChanger(MetricsBase & mb);
-};
-
-
-// temporarily change the style suitable for use in tabulars and arrays
-class ArrayChanger : public StyleChanger {
-public:
-	///
-	ArrayChanger(MetricsBase & mb);
-};
-
-
-
-// temporarily change the shape of a font
-class ShapeChanger : public Changer<FontInfo, FontShape> {
-public:
-	///
-	ShapeChanger(FontInfo & font, FontShape shape);
-	///
-	~ShapeChanger();
-};
-
-
-// temporarily change the available text width
-class WidthChanger : public Changer<MetricsBase>
-{
-public:
-	///
-	WidthChanger(MetricsBase & mb, int width);
-	///
-	~WidthChanger();
-};
-
-
-// temporarily change the used color
-class ColorChanger : public Changer<FontInfo, ColorCode> {
-public:
-	///
-	ColorChanger(FontInfo & font, ColorCode color,
-		     bool really_change_color = true);
-	///
-	~ColorChanger();
-private:
-	///
-	bool change_;
-};
-
 } // namespace lyx
 
 #endif
diff --git a/src/insets/InsetScript.cpp b/src/insets/InsetScript.cpp
index bee4c54..fec226f 100644
--- a/src/insets/InsetScript.cpp
+++ b/src/insets/InsetScript.cpp
@@ -160,7 +160,7 @@ Inset::DisplayType InsetScript::display() const
 void InsetScript::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	int const shift = params_.shift(mi.base.font);
-	ScriptChanger dummy(mi.base);
+	Changer dummy = mi.base.changeScript();
 	InsetText::metrics(mi, dim);
 	dim.asc -= shift;
 	dim.des += shift;
@@ -170,7 +170,7 @@ void InsetScript::metrics(MetricsInfo & mi, Dimension & dim) const
 void InsetScript::draw(PainterInfo & pi, int x, int y) const
 {
 	int const shift = params_.shift(pi.base.font);
-	ScriptChanger dummy(pi.base);
+	Changer dummy = pi.base.changeScript();
 	InsetText::draw(pi, x, y + shift);
 }
 
diff --git a/src/mathed/InsetMathAMSArray.cpp b/src/mathed/InsetMathAMSArray.cpp
index 13d7a94..8112352 100644
--- a/src/mathed/InsetMathAMSArray.cpp
+++ b/src/mathed/InsetMathAMSArray.cpp
@@ -20,8 +20,8 @@
 
 #include "FuncRequest.h"
 #include "FuncStatus.h"
+
 #include "support/gettext.h"
-
 #include "support/lstrings.h"
 
 #include <sstream>
@@ -85,7 +85,7 @@ char const * InsetMathAMSArray::name_right() const
 
 void InsetMathAMSArray::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	ArrayChanger dummy(mi.base);
+	Changer dummy = mi.base.changeArray();
 	InsetMathGrid::metrics(mi, dim);
 	dim.wid += 14;
 }
@@ -95,10 +95,10 @@ void InsetMathAMSArray::draw(PainterInfo & pi, int x, int y) const
 {
 	Dimension const dim = dimension(*pi.base.bv);
 	int const yy = y - dim.ascent();
-	// Drawing the deco after an ArrayChanger does not work
+	// Drawing the deco after changeArray does not work
 	mathed_draw_deco(pi, x + 1, yy, 5, dim.height(), from_ascii(name_left()));
 	mathed_draw_deco(pi, x + dim.width() - 8, yy, 5, dim.height(), from_ascii(name_right()));
-	ArrayChanger dummy(pi.base);
+	Changer dummy = pi.base.changeArray();
 	InsetMathGrid::drawWithMargin(pi, x, y, 6, 8);
 }
 
diff --git a/src/mathed/InsetMathArray.cpp b/src/mathed/InsetMathArray.cpp
index d5f9164..b6b358d 100644
--- a/src/mathed/InsetMathArray.cpp
+++ b/src/mathed/InsetMathArray.cpp
@@ -74,7 +74,7 @@ Inset * InsetMathArray::clone() const
 
 void InsetMathArray::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	ArrayChanger dummy(mi.base);
+	Changer dummy = mi.base.changeArray();
 	InsetMathGrid::metrics(mi, dim);
 	dim.wid += 6;
 }
@@ -91,7 +91,7 @@ Dimension const InsetMathArray::dimension(BufferView const & bv) const
 void InsetMathArray::draw(PainterInfo & pi, int x, int y) const
 {
 	setPosCache(pi, x, y);
-	ArrayChanger dummy(pi.base);
+	Changer dummy = pi.base.changeArray();
 	InsetMathGrid::drawWithMargin(pi, x, y, 4, 2);
 }
 
diff --git a/src/mathed/InsetMathBoldSymbol.cpp b/src/mathed/InsetMathBoldSymbol.cpp
index 465a7bf..215bd5f 100644
--- a/src/mathed/InsetMathBoldSymbol.cpp
+++ b/src/mathed/InsetMathBoldSymbol.cpp
@@ -49,7 +49,7 @@ docstring InsetMathBoldSymbol::name() const
 
 void InsetMathBoldSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	//FontSetChanger dummy(mi.base, "mathbf");
+	//Changer dummy = mi.base.changeFontSet("mathbf");
 	cell(0).metrics(mi, dim);
 	metricsMarkers(dim);
 	++dim.wid;  // for 'double stroke'
@@ -58,7 +58,7 @@ void InsetMathBoldSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void InsetMathBoldSymbol::draw(PainterInfo & pi, int x, int y) const
 {
-	//FontSetChanger dummy(pi.base, "mathbf");
+	//Changer dummy = pi.base.changeFontSet("mathbf");
 	cell(0).draw(pi, x + 1, y);
 	cell(0).draw(pi, x + 2, y);
 	drawMarkers(pi, x, y);
diff --git a/src/mathed/InsetMathBox.cpp b/src/mathed/InsetMathBox.cpp
index aee9381..e9e483c 100644
--- a/src/mathed/InsetMathBox.cpp
+++ b/src/mathed/InsetMathBox.cpp
@@ -81,7 +81,7 @@ void InsetMathBox::htmlize(HtmlStream & ms) const
 
 void InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy(mi.base, "textnormal");
+	Changer dummy = mi.base.changeFontSet("textnormal");
 	cell(0).metrics(mi, dim);
 	metricsMarkers(dim);
 }
@@ -89,7 +89,7 @@ void InsetMathBox::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void InsetMathBox::draw(PainterInfo & pi, int x, int y) const
 {
-	FontSetChanger dummy(pi.base, "textnormal");
+	Changer dummy = pi.base.changeFontSet("textnormal");
 	cell(0).draw(pi, x, y);
 	drawMarkers(pi, x, y);
 }
@@ -133,7 +133,7 @@ InsetMathFBox::InsetMathFBox(Buffer * buf)
 
 void InsetMathFBox::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy(mi.base, "textnormal");
+	Changer dummy = mi.base.changeFontSet("textnormal");
 	cell(0).metrics(mi, dim);
 	metricsMarkers2(dim, 3); // 1 pixel space, 1 frame, 1 space
 }
@@ -144,7 +144,7 @@ void InsetMathFBox::draw(PainterInfo & pi, int x, int y) const
 	Dimension const dim = dimension(*pi.base.bv);
 	pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
 		dim.width() - 2, dim.height() - 2, Color_foreground);
-	FontSetChanger dummy(pi.base, "textnormal");
+	Changer dummy = pi.base.changeFontSet("textnormal");
 	cell(0).draw(pi, x + 3, y);
 	setPosCache(pi, x, y);
 }
@@ -219,7 +219,7 @@ InsetMathMakebox::InsetMathMakebox(Buffer * buf, bool framebox)
 
 void InsetMathMakebox::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy(mi.base, "textnormal");
+	Changer dummy = mi.base.changeFontSet("textnormal");
 	
 	Dimension wdim;
 	static docstring bracket = from_ascii("[");
@@ -254,7 +254,7 @@ void InsetMathMakebox::draw(PainterInfo & pi, int x, int y) const
 {
 	drawMarkers(pi, x, y);
 	
-	FontSetChanger dummy(pi.base, "textnormal");
+	Changer dummy = pi.base.changeFontSet("textnormal");
 	BufferView const & bv = *pi.base.bv;
 	int w = mathed_char_width(pi.base.font, '[');
 	
diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp
index 2879ac9..813067e 100644
--- a/src/mathed/InsetMathChar.cpp
+++ b/src/mathed/InsetMathChar.cpp
@@ -56,13 +56,13 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 #if 1
 	if (char_ == '=' && has_math_fonts) {
-		FontSetChanger dummy(mi.base, "cmr");
+		Changer dummy = mi.base.changeFontSet("cmr");
 		dim = theFontMetrics(mi.base.font).dimension(char_);
 	} else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
-		FontSetChanger dummy(mi.base, "cmm");
+		Changer dummy = mi.base.changeFontSet("cmm");
 		dim = theFontMetrics(mi.base.font).dimension(char_);
 	} else if (!slanted(char_) && mi.base.fontname == "mathnormal") {
-		ShapeChanger dummy(mi.base.font, UP_SHAPE);
+		Changer dummy = mi.base.font.changeShape(UP_SHAPE);
 		dim = theFontMetrics(mi.base.font).dimension(char_);
 	} else {
 		frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
@@ -99,13 +99,13 @@ void InsetMathChar::draw(PainterInfo & pi, int x, int y) const
 		x += mathed_thinmuskip(pi.base.font) / 2;
 #if 1
 	if (char_ == '=' && has_math_fonts) {
-		FontSetChanger dummy(pi.base, "cmr");
+		Changer dummy = pi.base.changeFontSet("cmr");
 		pi.draw(x, y, char_);
 	} else if ((char_ == '>' || char_ == '<') && has_math_fonts) {
-		FontSetChanger dummy(pi.base, "cmm");
+		Changer dummy = pi.base.changeFontSet("cmm");
 		pi.draw(x, y, char_);
 	} else if (!slanted(char_) && pi.base.fontname == "mathnormal") {
-		ShapeChanger dummy(pi.base.font, UP_SHAPE);
+		Changer dummy = pi.base.font.changeShape(UP_SHAPE);
 		pi.draw(x, y, char_);
 	} else {
 		pi.draw(x, y, char_);
diff --git a/src/mathed/InsetMathDecoration.cpp b/src/mathed/InsetMathDecoration.cpp
index 37ae239..64ec9bd 100644
--- a/src/mathed/InsetMathDecoration.cpp
+++ b/src/mathed/InsetMathDecoration.cpp
@@ -107,7 +107,7 @@ void InsetMathDecoration::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	bool really_change_font = currentMode() == TEXT_MODE
 				&& isMathFont(from_ascii(mi.base.fontname));
-	FontSetChanger dummy(mi.base, "textnormal", really_change_font);
+	Changer dummy = mi.base.changeFontSet("textnormal", really_change_font);
 
 	cell(0).metrics(mi, dim);
 
@@ -130,7 +130,7 @@ void InsetMathDecoration::draw(PainterInfo & pi, int x, int y) const
 {
 	bool really_change_font = currentMode() == TEXT_MODE
 				&& isMathFont(from_ascii(pi.base.fontname));
-	FontSetChanger dummy(pi.base, "textnormal", really_change_font);
+	Changer dummy = pi.base.changeFontSet("textnormal", really_change_font);
 
 	cell(0).draw(pi, x + 1, y);
 	Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
diff --git a/src/mathed/InsetMathEnsureMath.cpp b/src/mathed/InsetMathEnsureMath.cpp
index cab5e77..1cc9971 100644
--- a/src/mathed/InsetMathEnsureMath.cpp
+++ b/src/mathed/InsetMathEnsureMath.cpp
@@ -37,7 +37,7 @@ Inset * InsetMathEnsureMath::clone() const
 void InsetMathEnsureMath::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	bool really_change_font = isTextFont(from_ascii(mi.base.fontname));
-	FontSetChanger dummy(mi.base, "mathnormal", really_change_font);
+	Changer dummy = mi.base.changeFontSet("mathnormal", really_change_font);
 	cell(0).metrics(mi, dim);
 	metricsMarkers(dim);
 }
@@ -46,7 +46,7 @@ void InsetMathEnsureMath::metrics(MetricsInfo & mi, Dimension & dim) const
 void InsetMathEnsureMath::draw(PainterInfo & pi, int x, int y) const
 {
 	bool really_change_font = isTextFont(from_ascii(pi.base.fontname));
-	FontSetChanger dummy(pi.base, "mathnormal", really_change_font);
+	Changer dummy = pi.base.changeFontSet("mathnormal", really_change_font);
 	cell(0).draw(pi, x, y);
 	drawMarkers(pi, x, y);
 }
diff --git a/src/mathed/InsetMathFont.cpp b/src/mathed/InsetMathFont.cpp
index 18af75d..7c15b82 100644
--- a/src/mathed/InsetMathFont.cpp
+++ b/src/mathed/InsetMathFont.cpp
@@ -58,7 +58,7 @@ bool InsetMathFont::lockedMode() const
 
 void InsetMathFont::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy(mi.base, key_->name);
+	Changer dummy = mi.base.changeFontSet(key_->name);
 	cell(0).metrics(mi, dim);
 	metricsMarkers(dim);
 }
@@ -66,7 +66,7 @@ void InsetMathFont::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void InsetMathFont::draw(PainterInfo & pi, int x, int y) const
 {
-	FontSetChanger dummy(pi.base, key_->name);
+	Changer dummy = pi.base.changeFontSet(key_->name);
 	cell(0).draw(pi, x + 1, y);
 	drawMarkers(pi, x, y);
 	setPosCache(pi, x, y);
diff --git a/src/mathed/InsetMathFontOld.cpp b/src/mathed/InsetMathFontOld.cpp
index 013808d..4c54a97 100644
--- a/src/mathed/InsetMathFontOld.cpp
+++ b/src/mathed/InsetMathFontOld.cpp
@@ -51,7 +51,7 @@ void InsetMathFontOld::metrics(MetricsInfo & mi, Dimension & dim) const
 	// When \cal is used in text mode, the font is not changed
 	bool really_change_font = font != "textcal";
 
-	FontSetChanger dummy(mi.base, font, really_change_font);
+	Changer dummy = mi.base.changeFontSet(font, really_change_font);
 	cell(0).metrics(mi, dim);
 	metricsMarkers(dim);
 }
@@ -68,7 +68,7 @@ void InsetMathFontOld::draw(PainterInfo & pi, int x, int y) const
 	// When \cal is used in text mode, the font is not changed
 	bool really_change_font = font != "textcal";
 
-	FontSetChanger dummy(pi.base, font, really_change_font);
+	Changer dummy = pi.base.changeFontSet(font, really_change_font);
 	cell(0).draw(pi, x + 1, y);
 	drawMarkers(pi, x, y);
 }
diff --git a/src/mathed/InsetMathFrac.cpp b/src/mathed/InsetMathFrac.cpp
index 4677355..98b6733 100644
--- a/src/mathed/InsetMathFrac.cpp
+++ b/src/mathed/InsetMathFrac.cpp
@@ -22,9 +22,11 @@
 #include "MetricsInfo.h"
 #include "TextPainter.h"
 
-#include "support/lassert.h"
 #include "frontends/Painter.h"
 
+#include "support/lassert.h"
+
+
 using namespace std;
 
 namespace lyx {
@@ -125,24 +127,26 @@ void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	Dimension dim0, dim1, dim2;
 
+	// This could be simplified a lot, including avoiding useless recalculation
+	// of cell metrics
 	if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
 		if (nargs() == 1) {
-			ShapeChanger dummy2(mi.base.font, UP_SHAPE);
+			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);
-			ShapeChanger dummy2(mi.base.font, UP_SHAPE);
+			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 {
 			cell(2).metrics(mi, dim2);
-			ShapeChanger dummy2(mi.base.font, UP_SHAPE);
-			FracChanger dummy(mi.base);
+			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;
@@ -151,31 +155,25 @@ void InsetMathFrac::metrics(MetricsInfo & mi, Dimension & dim) const
 		}
 	} else {
 		// general cell metrics used for \frac
-		FracChanger dummy(mi.base);
+		Changer dummy = mi.base.changeFrac();
 		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) {
-			dim.wid = dim0.width() + dim1.wid + 5;
-			dim.asc = dim0.height() + 5;
-			dim.des = dim1.height() - 5;
-		} else if (kind_ == UNITFRAC) {
-			ShapeChanger dummy2(mi.base.font, UP_SHAPE);
+		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) {
+			if (kind_ == CFRAC || kind_ == CFRACLEFT || kind_ == CFRACRIGHT
+			    || kind_ == DFRAC || kind_ == TFRAC) {
 				// \cfrac and \dfrac are always in display size
-				StyleChanger dummy2(mi.base, LM_ST_DISPLAY);
-				cell(0).metrics(mi, dim0);
-				cell(1).metrics(mi, dim1);
-			} else if (kind_ == TFRAC) {
-				// tfrac is in always in text size
-				StyleChanger dummy2(mi.base, LM_ST_SCRIPT);
+				// \tfrac is in always in text size
+				Changer dummy2 = mi.base.changeStyle((kind_ == TFRAC)
+				                                  ? LM_ST_SCRIPT
+				                                  : LM_ST_DISPLAY);
 				cell(0).metrics(mi, dim0);
 				cell(1).metrics(mi, dim1);
 			}
@@ -195,16 +193,16 @@ void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
 	Dimension const dim0 = cell(0).dimension(*pi.base.bv);
 	if (kind_ == UNIT || (kind_ == UNITFRAC && nargs() == 3)) {
 		if (nargs() == 1) {
-			ShapeChanger dummy2(pi.base.font, UP_SHAPE);
+			Changer dummy = pi.base.font.changeShape(UP_SHAPE);
 			cell(0).draw(pi, x + 1, y);
 		} else if (nargs() == 2) {
 			cell(0).draw(pi, x + 1, y);
-			ShapeChanger dummy2(pi.base.font, UP_SHAPE);
+			Changer dummy = pi.base.font.changeShape(UP_SHAPE);
 			cell(1).draw(pi, x + dim0.width() + 5, y);
 		} else {
 			cell(2).draw(pi, x + 1, y);
-			ShapeChanger dummy2(pi.base.font, UP_SHAPE);
-			FracChanger dummy(pi.base);
+			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;
@@ -214,7 +212,7 @@ void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
 					 y + dim1.asc / 2);
 		}
 	} else {
-		FracChanger dummy(pi.base);
+		Changer dummy2 = pi.base.changeFrac();
 		Dimension const dim1 = cell(1).dimension(*pi.base.bv);
 		int m = x + dim.wid / 2;
 		if (kind_ == NICEFRAC) {
@@ -223,20 +221,18 @@ void InsetMathFrac::draw(PainterInfo & pi, int x, int y) const
 			cell(1).draw(pi, x + dim0.width() + 5,
 					y + dim1.asc / 2);
 		} else if (kind_ == UNITFRAC) {
-			ShapeChanger dummy2(pi.base.font, UP_SHAPE);
+			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) {
-			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 if (kind_ == TFRAC) {
+		} else if (kind_ == FRAC || kind_ == ATOP || kind_ == OVER
+		           || kind_ == TFRAC) {
 			// tfrac is in always in text size
-			StyleChanger dummy2(pi.base, LM_ST_SCRIPT);
+			Changer dummy2 = pi.base.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
-			StyleChanger dummy2(pi.base, LM_ST_DISPLAY);
+			Changer dummy2 = pi.base.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)
@@ -552,22 +548,12 @@ int InsetMathBinom::dw(int height) const
 void InsetMathBinom::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	Dimension dim0, dim1;
-
-	// The cells must be set while the RAII objects (StyleChanger,
-	// FracChanger) do still exist and cannot be set after the if case.
-	if (kind_ == DBINOM) {
-		StyleChanger dummy(mi.base, LM_ST_DISPLAY);
-		cell(0).metrics(mi, dim0);
-		cell(1).metrics(mi, dim1);
-	} else if (kind_ == TBINOM) {
-		StyleChanger dummy(mi.base, LM_ST_SCRIPT);
-		cell(0).metrics(mi, dim0);
-		cell(1).metrics(mi, dim1);
-	} else {
-		FracChanger dummy(mi.base);
-		cell(0).metrics(mi, dim0);
-		cell(1).metrics(mi, dim1);
-	}
+	Changer dummy =
+		(kind_ == DBINOM) ? mi.base.changeStyle(LM_ST_DISPLAY) :
+		(kind_ == TBINOM) ? mi.base.changeStyle(LM_ST_SCRIPT) :
+		                    mi.base.changeFrac();
+	cell(0).metrics(mi, dim0);
+	cell(1).metrics(mi, dim1);
 	dim.asc = dim0.height() + 4 + 5;
 	dim.des = dim1.height() + 4 - 5;
 	dim.wid = max(dim0.wid, dim1.wid) + 2 * dw(dim.height()) + 4;
@@ -587,21 +573,12 @@ void InsetMathBinom::draw(PainterInfo & pi, int x, int y) const
 		kind_ == BRACK ? from_ascii("]") : from_ascii(")");
 
 	int m = x + dim.width() / 2;
-	// The cells must be drawn while the RAII objects (StyleChanger,
-	// FracChanger) do still exist and cannot be drawn after the if case.
-	if (kind_ == DBINOM) {
-		StyleChanger dummy(pi.base, LM_ST_DISPLAY);
-		cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
-		cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
-	} else if (kind_ == TBINOM) {
-		StyleChanger dummy(pi.base, LM_ST_SCRIPT);
-		cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
-		cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
-	} else {
-		FracChanger dummy2(pi.base);
-		cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
-		cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
-	}
+	Changer dummy =
+		(kind_ == DBINOM) ? pi.base.changeStyle(LM_ST_DISPLAY) :
+		(kind_ == TBINOM) ? pi.base.changeStyle(LM_ST_SCRIPT) :
+		                    pi.base.changeFrac();
+	cell(0).draw(pi, m - dim0.wid / 2, y - dim0.des - 3 - 5);
+	cell(1).draw(pi, m - dim1.wid / 2, y + dim1.asc + 3 - 5);
 	// draw the brackets and the marker
 	mathed_draw_deco(pi, x, y - dim.ascent(), dw(dim.height()),
 		dim.height(), bra);
diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp
index e253635..53b2b74 100644
--- a/src/mathed/InsetMathHull.cpp
+++ b/src/mathed/InsetMathHull.cpp
@@ -64,6 +64,7 @@
 #include "support/gettext.h"
 #include "support/lstrings.h"
 
+
 #include <sstream>
 
 using namespace std;
@@ -487,8 +488,9 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
 		return;
 	}
 
-	FontSetChanger dummy1(mi.base, standardFont());
-	StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
+	// FIXME: Changing the same object repeatedly is inefficient.
+	Changer dummy1 = mi.base.changeFontSet(standardFont());
+	Changer dummy2 = mi.base.changeStyle(display() ? LM_ST_DISPLAY : LM_ST_TEXT);
 
 	// let the cells adjust themselves
 	InsetMathGrid::metrics(mi, dim);
@@ -499,7 +501,7 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
 	}
 
 	if (numberedType()) {
-		FontSetChanger dummy(mi.base, from_ascii("mathbf"));
+		Changer dummy = mi.base.changeFontSet(from_ascii("mathbf"));
 		int l = 0;
 		for (row_type row = 0; row < nrows(); ++row)
 			l = max(l, mathed_string_width(mi.base.font, nicelabel(row)));
@@ -580,9 +582,9 @@ void InsetMathHull::draw(PainterInfo & pi, int x, int y) const
 	ColorCode color = pi.selected && lyxrc.use_system_colors
 				? Color_selectiontext : standardColor();
 	bool const really_change_color = pi.base.font.color() == Color_none;
-	ColorChanger dummy0(pi.base.font, color, really_change_color);
-	FontSetChanger dummy1(pi.base, standardFont());
-	StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
+	Changer dummy0 = pi.base.font.changeColor(color, really_change_color);
+	Changer dummy1 = pi.base.changeFontSet(standardFont());
+	Changer dummy2 = pi.base.changeStyle(display() ? LM_ST_DISPLAY : LM_ST_TEXT);
 
 	InsetMathGrid::draw(pi, x + 1, y);
 
@@ -590,7 +592,7 @@ void InsetMathHull::draw(PainterInfo & pi, int x, int y) const
 		int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
 		for (row_type row = 0; row < nrows(); ++row) {
 			int const yy = y + rowinfo_[row].offset_;
-			FontSetChanger dummy(pi.base, from_ascii("mathrm"));
+			Changer dummy = pi.base.changeFontSet(from_ascii("mathrm"));
 			docstring const nl = nicelabel(row);
 			pi.draw(xx, yy, nl);
 		}
diff --git a/src/mathed/InsetMathOverset.cpp b/src/mathed/InsetMathOverset.cpp
index 1958471..01369b2 100644
--- a/src/mathed/InsetMathOverset.cpp
+++ b/src/mathed/InsetMathOverset.cpp
@@ -17,6 +17,7 @@
 #include "Cursor.h"
 #include "LaTeXFeatures.h"
 
+
 using namespace std;
 
 namespace lyx {
@@ -31,7 +32,7 @@ void InsetMathOverset::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	Dimension dim1;
 	cell(1).metrics(mi, dim1);
-	FracChanger dummy(mi.base);
+	Changer dummy = mi.base.changeFrac();
 	Dimension dim0;
 	cell(0).metrics(mi, dim0);
 	dim.wid = max(dim0.width(), dim1.wid) + 4;
@@ -49,7 +50,7 @@ void InsetMathOverset::draw(PainterInfo & pi, int x, int y) const
 	int m  = x + dim.wid / 2;
 	int yo = y - dim1.asc - dim0.des - 1;
 	cell(1).draw(pi, m - dim1.wid / 2, y);
-	FracChanger dummy(pi.base);
+	Changer dummy = pi.base.changeFrac();
 	cell(0).draw(pi, m - dim0.width() / 2, yo);
 	drawMarkers(pi, x, y);
 }
diff --git a/src/mathed/InsetMathPar.cpp b/src/mathed/InsetMathPar.cpp
index 0638b8e..3578399 100644
--- a/src/mathed/InsetMathPar.cpp
+++ b/src/mathed/InsetMathPar.cpp
@@ -28,14 +28,14 @@ InsetMathPar::InsetMathPar(Buffer * buf, MathData const & ar)
 
 void InsetMathPar::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy1(mi.base, "textnormal");
+	Changer dummy = mi.base.changeFontSet("textnormal");
 	InsetMathGrid::metrics(mi, dim);
 }
 
 
 void InsetMathPar::draw(PainterInfo & pi, int x, int y) const
 {
-	FontSetChanger dummy1(pi.base, "textnormal");
+	Changer dummy = pi.base.changeFontSet("textnormal");
 	InsetMathGrid::draw(pi, x, y);
 }
 
diff --git a/src/mathed/InsetMathScript.cpp b/src/mathed/InsetMathScript.cpp
index 37f1965..bfe7d18 100644
--- a/src/mathed/InsetMathScript.cpp
+++ b/src/mathed/InsetMathScript.cpp
@@ -277,7 +277,7 @@ void InsetMathScript::metrics(MetricsInfo & mi, Dimension & dim) const
 	Dimension dim1;
 	Dimension dim2;
 	cell(0).metrics(mi, dim0);
-	ScriptChanger dummy(mi.base);
+	Changer dummy = mi.base.changeScript();
 	if (nargs() > 1)
 		cell(1).metrics(mi, dim1);
 	if (nargs() > 2)
@@ -332,7 +332,7 @@ void InsetMathScript::draw(PainterInfo & pi, int x, int y) const
 		if (editing(&bv))
 			pi.draw(x + dxx(bv), y, char_type('.'));
 	}
-	ScriptChanger dummy(pi.base);
+	Changer dummy = pi.base.changeScript();
 	if (hasUp())
 		up().draw(pi, x + dx1(bv), y - dy1(bv));
 	if (hasDown())
diff --git a/src/mathed/InsetMathSideset.cpp b/src/mathed/InsetMathSideset.cpp
index 6ed74e8..3b364ec 100644
--- a/src/mathed/InsetMathSideset.cpp
+++ b/src/mathed/InsetMathSideset.cpp
@@ -197,7 +197,7 @@ void InsetMathSideset::metrics(MetricsInfo & mi, Dimension & dim) const
 		br().metrics(mi, dimbr);
 		dimtr = dimbr;
 	}
-	ScriptChanger dummy(mi.base);
+	Changer dummy = mi.base.changeScript();
 	if (scriptl_) {
 		bl().metrics(mi, dimbl);
 		tl().metrics(mi, dimtl);
@@ -231,7 +231,7 @@ void InsetMathSideset::draw(PainterInfo & pi, int x, int y) const
 		bl().draw(pi, x          , y);
 	if (!scriptr_)
 		br().draw(pi, x + dxr(bv), y);
-	ScriptChanger dummy(pi.base);
+	Changer dummy = pi.base.changeScript();
 	if (scriptl_) {
 		bl().draw(pi, x          , y + dyb(bv));
 		tl().draw(pi, x          , y - dyt(bv));
diff --git a/src/mathed/InsetMathSize.cpp b/src/mathed/InsetMathSize.cpp
index dc79652..3f1ef8c 100644
--- a/src/mathed/InsetMathSize.cpp
+++ b/src/mathed/InsetMathSize.cpp
@@ -43,7 +43,7 @@ Inset * InsetMathSize::clone() const
 
 void InsetMathSize::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	StyleChanger dummy(mi.base, style_);
+	Changer dummy = mi.base.changeStyle(style_);
 	cell(0).metrics(mi, dim);
 	metricsMarkers(dim);
 }
@@ -51,7 +51,7 @@ void InsetMathSize::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void InsetMathSize::draw(PainterInfo & pi, int x, int y) const
 {
-	StyleChanger dummy(pi.base, style_);
+	Changer dummy = pi.base.changeStyle(style_);
 	cell(0).draw(pi, x + 1, y);
 	drawMarkers(pi, x, y);
 }
diff --git a/src/mathed/InsetMathSpecialChar.cpp b/src/mathed/InsetMathSpecialChar.cpp
index 32e4c2a..4525ff5 100644
--- a/src/mathed/InsetMathSpecialChar.cpp
+++ b/src/mathed/InsetMathSpecialChar.cpp
@@ -56,7 +56,7 @@ Inset * InsetMathSpecialChar::clone() const
 void InsetMathSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	if (mi.base.fontname == "mathnormal") {
-		ShapeChanger dummy(mi.base.font, UP_SHAPE);
+		Changer dummy = mi.base.font.changeShape(UP_SHAPE);;
 		dim = theFontMetrics(mi.base.font).dimension(char_);
 	} else {
 		frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
@@ -69,7 +69,7 @@ void InsetMathSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const
 void InsetMathSpecialChar::draw(PainterInfo & pi, int x, int y) const
 {
 	if (pi.base.fontname == "mathnormal") {
-		ShapeChanger dummy(pi.base.font, UP_SHAPE);
+		Changer dummy = pi.base.font.changeShape(UP_SHAPE);
 		pi.draw(x, y, char_);
 	} else {
 		pi.draw(x, y, char_);
diff --git a/src/mathed/InsetMathStackrel.cpp b/src/mathed/InsetMathStackrel.cpp
index d8b9e97..5de6198 100644
--- a/src/mathed/InsetMathStackrel.cpp
+++ b/src/mathed/InsetMathStackrel.cpp
@@ -17,6 +17,7 @@
 #include "MathData.h"
 #include "MathStream.h"
 
+
 using namespace std;
 
 namespace lyx {
@@ -54,7 +55,7 @@ void InsetMathStackrel::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	Dimension dim1;
 	cell(1).metrics(mi, dim1);
-	FracChanger dummy(mi.base);
+	Changer dummy = mi.base.changeFrac();
 	Dimension dim0;
 	cell(0).metrics(mi, dim0);
 	if (nargs() > 2) {
@@ -80,7 +81,7 @@ void InsetMathStackrel::draw(PainterInfo & pi, int x, int y) const
 	int m  = x + dim.width() / 2;
 	int yo = y - dim1.ascent() - dim0.descent() - 1;
 	cell(1).draw(pi, m - dim1.width() / 2, y);
-	FracChanger dummy(pi.base);
+	Changer dummy = pi.base.changeFrac();
 	cell(0).draw(pi, m - dim0.width() / 2, yo);
 	if (nargs() > 2) {
 		Dimension const & dim2 = cell(2).dimension(*pi.base.bv);
diff --git a/src/mathed/InsetMathSubstack.cpp b/src/mathed/InsetMathSubstack.cpp
index f88f492..179d44c 100644
--- a/src/mathed/InsetMathSubstack.cpp
+++ b/src/mathed/InsetMathSubstack.cpp
@@ -44,17 +44,14 @@ Inset * InsetMathSubstack::clone() const
 
 void InsetMathSubstack::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	if (mi.base.style == LM_ST_DISPLAY) {
-		StyleChanger dummy(mi.base, LM_ST_TEXT);
-		InsetMathGrid::metrics(mi, dim);
-	} else {
-		InsetMathGrid::metrics(mi, dim);
-	}
+	Changer dummy = mi.base.changeStyle(LM_ST_TEXT, mi.base.style == LM_ST_DISPLAY);
+	InsetMathGrid::metrics(mi, dim);
 }
 
 
 void InsetMathSubstack::draw(PainterInfo & pi, int x, int y) const
 {
+	Changer dummy = pi.base.changeStyle(LM_ST_TEXT, pi.base.style == LM_ST_DISPLAY);
 	InsetMathGrid::draw(pi, x + 1, y);
 }
 
diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp
index 5a86536..bdca111 100644
--- a/src/mathed/InsetMathSymbol.cpp
+++ b/src/mathed/InsetMathSymbol.cpp
@@ -21,6 +21,7 @@
 
 #include "support/debug.h"
 #include "support/docstream.h"
+#include "support/lyxlib.h"
 #include "support/textutils.h"
 #include "support/unique_ptr.h"
 
@@ -66,7 +67,7 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
 					 sym_->extra == "mathalpha" &&
 					 mi.base.fontname == "mathit";
 	std::string const font = italic_upcase_greek ? "cmm" : sym_->inset;
-	FontSetChanger dummy(mi.base, from_ascii(font));
+	Changer dummy = mi.base.changeFontSet(from_ascii(font));
 	mathed_string_dim(mi.base.font, sym_->draw, dim);
 	docstring::const_reverse_iterator rit = sym_->draw.rbegin();
 	kerning_ = mathed_char_kerning(mi.base.font, *rit);
@@ -115,7 +116,7 @@ void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const
 	//else
 	//	x += support::iround(0.0833 * em);
 
-	FontSetChanger dummy(pi.base, from_ascii(font));
+	Changer dummy = pi.base.changeFontSet(from_ascii(font));
 	pi.draw(x, y - h_, sym_->draw);
 }
 
diff --git a/src/mathed/InsetMathTabular.cpp b/src/mathed/InsetMathTabular.cpp
index 2c814a3..40cf58d 100644
--- a/src/mathed/InsetMathTabular.cpp
+++ b/src/mathed/InsetMathTabular.cpp
@@ -43,7 +43,7 @@ Inset * InsetMathTabular::clone() const
 
 void InsetMathTabular::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy(mi.base, "textnormal");
+	Changer dummy = mi.base.changeFontSet("textnormal");
 	InsetMathGrid::metrics(mi, dim);
 	dim.wid += 6;
 }
@@ -59,7 +59,7 @@ Dimension const InsetMathTabular::dimension(BufferView const & bv) const
 
 void InsetMathTabular::draw(PainterInfo & pi, int x, int y) const
 {
-	FontSetChanger dummy(pi.base, "textnormal");
+	Changer dummy = pi.base.changeFontSet("textnormal");
 	InsetMathGrid::drawWithMargin(pi, x, y, 4, 2);
 }
 
diff --git a/src/mathed/InsetMathUnderset.cpp b/src/mathed/InsetMathUnderset.cpp
index 7632b0c..d6927d0 100644
--- a/src/mathed/InsetMathUnderset.cpp
+++ b/src/mathed/InsetMathUnderset.cpp
@@ -17,6 +17,7 @@
 #include "Cursor.h"
 #include "LaTeXFeatures.h"
 
+
 using namespace std;
 
 namespace lyx {
@@ -31,7 +32,7 @@ void InsetMathUnderset::metrics(MetricsInfo & mi, Dimension & dim) const
 {
 	Dimension dim1;
 	cell(1).metrics(mi, dim1);
-	FracChanger dummy(mi.base);
+	Changer dummy = mi.base.changeFrac();
 	Dimension dim0;
 	cell(0).metrics(mi, dim0);
 	dim.wid = max(dim0.width(), dim1.width()) + 4;
@@ -49,7 +50,7 @@ void InsetMathUnderset::draw(PainterInfo & pi, int x, int y) const
 	int m  = x + dim.wid / 2;
 	int yo = y + dim1.descent() + dim0.ascent() + 1;
 	cell(1).draw(pi, m - dim1.width() / 2, y);
-	FracChanger dummy(pi.base);
+	Changer dummy = pi.base.changeFrac();
 	cell(0).draw(pi, m - dim0.width() / 2, yo);
 	drawMarkers(pi, x, y);
 }
diff --git a/src/mathed/InsetMathXArrow.cpp b/src/mathed/InsetMathXArrow.cpp
index 8c8a497..fbdac69 100644
--- a/src/mathed/InsetMathXArrow.cpp
+++ b/src/mathed/InsetMathXArrow.cpp
@@ -40,7 +40,7 @@ Inset * InsetMathXArrow::clone() const
 
 void InsetMathXArrow::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	ScriptChanger dummy(mi.base);
+	Changer dummy = mi.base.changeScript();
 	Dimension dim0;
 	cell(0).metrics(mi, dim0);
 	Dimension dim1;
@@ -54,7 +54,7 @@ void InsetMathXArrow::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void InsetMathXArrow::draw(PainterInfo & pi, int x, int y) const
 {
-	ScriptChanger dummy(pi.base);
+	Changer dummy = pi.base.changeScript();
 	Dimension const dim = dimension(*pi.base.bv);
 	Dimension const & dim0 = cell(0).dimension(*pi.base.bv);
 	// center the cells with the decoration
diff --git a/src/mathed/InsetMathXYArrow.cpp b/src/mathed/InsetMathXYArrow.cpp
index 80aeb72..19852e5 100644
--- a/src/mathed/InsetMathXYArrow.cpp
+++ b/src/mathed/InsetMathXYArrow.cpp
@@ -82,8 +82,8 @@ MathData const & InsetMathXYArrow::sourceCell() const
 bool InsetMathXYArrow::metrics(MetricsInfo & mi) const
 {
 	InsetMathNest::metrics(mi);
-	mi_   = mi;
-	FontSetChanger dummy(mi.base, "textrm");
+	mi_ = mi;
+	Changer dummy = mi.base.changeFontSet(mi.base, "textrm");
 #if 0
 	target_ = mi.inset ? mi.inset->asXYMatrixInset() : 0;
 
@@ -105,7 +105,7 @@ bool InsetMathXYArrow::metrics(MetricsInfo & mi) const
 void InsetMathXYArrow::draw(PainterInfo & pi, int x, int y) const
 {
 	metrics(mi_);
-	FontSetChanger dummy(pi.base, "textrm");
+	Changer dummy = pi.base.changeFontSet(pi.base, "textrm");
 
 	if (editing()) {
 
diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp
index 9fe6e15..80948fd 100644
--- a/src/mathed/MathMacro.cpp
+++ b/src/mathed/MathMacro.cpp
@@ -551,10 +551,10 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
 	int expy = y;
 
 	if (d->displayMode_ == DISPLAY_INIT || d->displayMode_ == DISPLAY_INTERACTIVE_INIT) {
-		FontSetChanger dummy(pi.base, "lyxtex");
+		Changer dummy = pi.base.changeFontSet("lyxtex");
 		pi.pain.text(x, y, from_ascii("\\") + name(), pi.base.font);
 	} else if (d->displayMode_ == DISPLAY_UNFOLDED) {
-		FontSetChanger dummy(pi.base, "lyxtex");
+		Changer dummy = pi.base.changeFontSet("lyxtex");
 		pi.pain.text(x, y, from_ascii("\\"), pi.base.font);
 		x += mathed_string_width(pi.base.font, from_ascii("\\")) + 1;
 		cell(0).draw(pi, x, y);
diff --git a/src/mathed/MathMacroTemplate.cpp b/src/mathed/MathMacroTemplate.cpp
index d30fc36..eefc3a8 100644
--- a/src/mathed/MathMacroTemplate.cpp
+++ b/src/mathed/MathMacroTemplate.cpp
@@ -47,6 +47,7 @@
 #include "support/docstream.h"
 #include "support/lstrings.h"
 
+
 #include <set>
 #include <sstream>
 
@@ -542,8 +543,8 @@ void MathMacroTemplate::createLook(int args) const
 
 void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
-	StyleChanger dummy2(mi.base, LM_ST_TEXT);
+	Changer dummy1 = mi.base.changeFontSet(from_ascii("mathnormal"));
+	Changer dummy2 = mi.base.changeStyle(LM_ST_TEXT);
 
 	// valid macro?
 	MacroData const * macro = 0;
@@ -584,9 +585,10 @@ void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
 {
-	ColorChanger dummy0(pi.base.font, Color_math);
-	FontSetChanger dummy1(pi.base, from_ascii("mathnormal"));
-	StyleChanger dummy2(pi.base, LM_ST_TEXT);
+	// FIXME: Calling Changer on the same object repeatedly is inefficient.
+	Changer dummy0 = pi.base.font.changeColor(Color_math);
+	Changer dummy1 = pi.base.changeFontSet(from_ascii("mathnormal"));
+	Changer dummy2 = pi.base.changeStyle(LM_ST_TEXT);
 
 	setPosCache(pi, x, y);
 	Dimension const dim = dimension(*pi.base.bv);
diff --git a/src/support/Changer.h b/src/support/Changer.h
new file mode 100644
index 0000000..8f24ba5
--- /dev/null
+++ b/src/support/Changer.h
@@ -0,0 +1,32 @@
+// -*- C++ -*-
+/**
+ * \file Changer.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Guillaume Munch
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYX_CHANGER_H
+#define LYX_CHANGER_H
+
+#include "support/unique_ptr.h"
+
+
+namespace lyx {
+
+// Forward declaration for support/RefChanger.h
+struct Revertible {
+	virtual ~Revertible() {}
+	virtual void revert() {}
+	virtual void keep() {}
+};
+
+using Changer = unique_ptr<Revertible>;
+
+
+}
+
+#endif //LYX_CHANGER_H
diff --git a/src/support/Makefile.am b/src/support/Makefile.am
index 1487285..5748019 100644
--- a/src/support/Makefile.am
+++ b/src/support/Makefile.am
@@ -35,6 +35,7 @@ liblyxsupport_a_SOURCES = \
 	FileMonitor.cpp \
 	RandomAccessList.h \
 	bind.h \
+	Change.h \
 	ConsoleApplication.cpp \
 	ConsoleApplication.h \
 	ConsoleApplicationPrivate.h \
@@ -90,6 +91,7 @@ liblyxsupport_a_SOURCES = \
 	qstring_helpers.cpp \
 	qstring_helpers.h \
 	regex.h \
+	RefChanger.h \
 	socktools.cpp \
 	socktools.h \
 	strfwd.h \
diff --git a/src/support/RefChanger.h b/src/support/RefChanger.h
new file mode 100644
index 0000000..9b9d020
--- /dev/null
+++ b/src/support/RefChanger.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+/**
+ * \file RefChanger.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Guillaume Munch
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYX_REFCHANGER_H
+#define LYX_REFCHANGER_H
+
+#include "support/Changer.h"
+
+
+namespace lyx {
+
+/// A RefChanger records the current value of \param ref, allowing to
+/// temporarily assign new values to it.  The original value is restored
+/// automatically when the object is destroyed, unless it is disabled.
+///
+/// RefChanger is movable, and doing so prolongs the duration of the temporary
+/// assignment. This allows classes to supply their own changer methods.
+///
+/// Naturally, be careful not to extend the life of a RefChanger beyond that of
+/// the reference it modifies. The RefChanger can be disabled by calling
+/// ->keep() or ->revert(). Once disabled, the reference is never accessed
+/// again.
+template<typename X>
+class RevertibleRef : public Revertible {
+public:
+	RevertibleRef(X & ref) : ref(ref), old(ref), enabled(true) {}
+	//
+	~RevertibleRef() { revert(); }
+	//
+	void revert() {	if (enabled) { enabled = false; ref = old; } }
+	//
+	void keep() { enabled = false; }
+	//
+	X & ref;
+	X const old;
+private:
+	bool enabled;
+};
+
+template <typename X> using RefChanger = unique_ptr<RevertibleRef<X>>;
+
+
+/// Saves the value of \param ref in a movable object
+template <typename X> RefChanger<X> make_save(X & ref)
+{
+	return make_unique<RevertibleRef<X>>(ref);
+}
+
+/// Temporarily assign value \param val to \param ref. If \param cond is false,
+/// then the assignation does not happen and the RefChanger starts disabled.
+template <typename X>
+RefChanger<X> make_change(X & ref, X const val, bool cond = true)
+{
+	auto rc = make_save(ref);
+	if (!cond)
+		rc->keep();
+	else
+		ref = val;
+	return rc;
+}
+
+
+}
+
+
+#endif //LYX_REFCHANGER_H
-- 
2.7.4

Reply via email to