1 /**
2  * \file MathClass.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jean-Marc Lasgouttes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10 
11 #include <config.h>
12 
13 #include "MathClass.h"
14 #include "MathSupport.h"
15 
16 #include "MetricsInfo.h"
17 #include "FontInfo.h"
18 
19 #include "support/debug.h"
20 #include "support/docstring.h"
21 #include "support/lassert.h"
22 
23 #include <ostream>
24 
25 using namespace std;
26 
27 namespace lyx {
28 
29 
class_to_string(MathClass const mc)30 docstring const class_to_string(MathClass const mc)
31 {
32 	string s;
33 	switch (mc) {
34 	case MC_ORD:
35 		s = "mathord";
36 		break;
37 	case MC_OP:
38 		s = "mathop";
39 		break;
40 	case MC_BIN:
41 		s = "mathbin";
42 		break;
43 	case MC_REL:
44 		s = "mathrel";
45 		break;
46 	case MC_OPEN:
47 		s = "mathopen";
48 		break;
49 	case MC_CLOSE:
50 		s = "mathclose";
51 		break;
52 	case MC_PUNCT:
53 		s = "mathpunct";
54 		break;
55 	case MC_INNER:
56 		s = "mathinner";
57 		break;
58 	case MC_UNKNOWN:
59 		LATTEST(false);
60 		s = "mathord";
61 	}
62 	return from_ascii(s);
63 }
64 
65 
string_to_class(docstring const & s)66 MathClass string_to_class(docstring const &s)
67 {
68 	if (s  == "mathop")
69 		return MC_OP;
70 	else if (s  == "mathbin")
71 		return MC_BIN;
72 	else if (s  == "mathrel")
73 		return MC_REL;
74 	else if (s  == "mathopen")
75 		return MC_OPEN;
76 	else if (s  == "mathclose")
77 		return MC_CLOSE;
78 	else if (s  == "mathpunct")
79 		return MC_PUNCT;
80 	else if (s  == "mathinner")
81 		return MC_INNER;
82 	else  if (s  == "mathord")
83 		return MC_ORD;
84 	else
85 		return MC_UNKNOWN;
86 }
87 
88 
89 /*
90  * The TeXbook presents in Appendix G a set of 22 rules (!) explaining
91  * how to typeset mathematic formulas. Of interest here are rules 5
92  * and 6:
93 
94  * 5. If the current item is a Bin atom, and if this was the first
95  *    atom in the list, or if the most recent previous atom was Bin,
96  *    Op, Rel, Open, or Punct, change the current Bin to Ord [and
97  *    continue with Rule 14. Otherwise continue with Rule 17]
98  *
99  * 6. If the current item is a Rel or Close or Punct atom, and if the
100  *    most recent previous atom was Bin, change that previous Bin to
101  *    Ord. [Continue with Rule 17.]
102  */
update_class(MathClass & mc,MathClass const prev,MathClass const next)103 void update_class(MathClass & mc, MathClass const prev, MathClass const next)
104 {
105 	if (mc == MC_BIN
106 		&& (prev == MC_BIN || prev == MC_OP || prev == MC_OPEN
107 			|| prev == MC_PUNCT || prev == MC_REL
108 			|| next == MC_CLOSE || next == MC_PUNCT || next == MC_REL))
109 		mc = MC_ORD;
110 }
111 
112 
113 /*
114  * This table of spacing between two classes can be found p. 170 of
115  * The TeXbook.
116  *
117  * The line is the class of the first class, and the column the second
118  * class. The number encodes the spacing between the two atoms, as
119  * follows
120  *
121  * + 0: no spacing
122  * + 1: thin mu skip
123  * + 2: med mu skip
124  * + 3: thick mu skip
125  * + 9: should never happen
126  * + negative value: either 0 if the atom is in script or scriptscript mode,
127  *   or the spacing given by the absolute value.
128  */
129 int pair_spc[MC_UNKNOWN][MC_UNKNOWN] = {
130 //	 ORD    OP   BIN   REL  OPEN CLOSE PUNCT INNER
131 	{  0,    1,   -2,   -3,    0,    0,    0,   -1}, // ORD
132 	{  1,    1,    9,   -3,    0,    0,    0,   -1}, // OP
133 	{ -2,   -2,    9,    9,   -2,    9,    9,   -2}, // BIN
134 	{ -3,   -3,    9,    0,   -3,    0,    0,   -3}, // REL
135 	{  0,    0,    9,    0,    0,    0,    0,    0}, // OPEN
136 	{  0,    1,   -2,   -3,    0,    0,    0,   -1}, // CLOSE
137 	{ -1,   -1,    9,   -1,   -1,   -1,   -1,   -1}, // PUNCT
138 	{ -1,    1,   -2,   -3,   -1,    0,   -1,   -1}, // INNER
139 };
140 
141 
class_spacing(MathClass const mc1,MathClass const mc2,MetricsBase const & mb)142 int class_spacing(MathClass const mc1, MathClass const mc2,
143                   MetricsBase const & mb)
144 {
145 	int spc_code = pair_spc[mc1][mc2];
146 	//lyxerr << class_to_string(mc1) << "+" << class_to_string(mc2)
147 	//	   << "=" << spc_code << " @" << mb.style << endl;
148 	if (spc_code < 0) {
149 		switch (mb.font.style()) {
150 		case LM_ST_DISPLAY:
151 		case LM_ST_TEXT:
152 			spc_code = abs(spc_code);
153 			break;
154 		case LM_ST_SCRIPT:
155 		case LM_ST_SCRIPTSCRIPT:
156 			spc_code = 0;
157 		}
158 	}
159 
160 	int spc = 0;
161 	switch(spc_code) {
162 	case 0:
163 		break;
164 	case 1:
165 		spc = mathed_thinmuskip(mb.font);
166 		break;
167 	case 2:
168 		spc = mathed_medmuskip(mb.font);
169 		break;
170 	case 3:
171 		spc = mathed_thickmuskip(mb.font);
172 		break;
173 	default:
174 		LYXERR0("Impossible pair of classes: (" << mc1 << ", " << mc2 << ")");
175 		LATTEST(false);
176 	}
177 	return spc;
178 }
179 
180 } // namespace lyx
181