ROOT  6.06/09
Reference Guide
XLFDParser.mm
Go to the documentation of this file.
1 // @(#)root/graf2d:$Id$
2 // Author: Timur Pocheptsov 2/03/2012
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //#define NDEBUG
13 
14 #include <stdexcept>
15 #include <sstream>
16 #include <cassert>
17 #include <cctype>
18 
19 #include "XLFDParser.h"
20 #include "TError.h"
21 
22 //
23 // I did not find any formal description of what XLFD name can be.
24 // The first version of this code was quite strict - it expected all
25 // components to be in place, digits must be digits. But after using
26 // ROOT's GUI for some time, I noticed that ROOT can use font name like
27 // *, "fixed", "-*-" or something like this. In this case I have to set
28 // some "default" or "wildcard" names.
29 // TODO: what does X11 epxected to do, if XLFD name is bad?
30 //
31 
32 namespace ROOT {
33 namespace MacOSX {
34 namespace X11 {
35 
36 namespace {
37 
38 typedef std::string::size_type size_type;
39 
40 //______________________________________________________________________________
41 template<class T>
42 void StringToInt(const std::string &str, const std::string &componentName, T &num)
43 {
44  for (size_type i = 0, e = str.length(); i < e; ++i) {
45  const char symbol = str[i];
46  if (!std::isdigit(symbol))
47  throw std::runtime_error("bad symbol while converting component " + componentName + " into number");
48  }
49 
50  std::istringstream in(str);
51  in>>num;
52 }
53 
54 //______________________________________________________________________________
55 size_type GetXLFDNameComponentAsString(const std::string &name, const std::string & componentName,
56  size_type pos, std::string &component)
57 {
58  const size_type length = name.length();
59  if (pos + 1 >= length)
60  throw std::runtime_error("Unexpected end of name while parsing " + componentName);
61 
62  //Starting symbol must be '-'.
63  if (name[pos] != '-')
64  throw std::runtime_error("Component " + componentName + " must start from '-'");
65 
66  const size_type start = ++pos;
67  ++pos;
68  while (pos < length && name[pos] != '-')
69  ++pos;
70 
71  if (pos - start)
72  component = name.substr(start, pos - start);
73  else
74  component = "";
75 
76  return pos;
77 }
78 
79 
80 //______________________________________________________________________________
81 template<class T>
82 size_type GetXLFDNameComponentAsInteger(const std::string &name,
83  const std::string &componentName,
84  size_type pos, T &component)
85 {
86  std::string num;
87  pos = GetXLFDNameComponentAsString(name, componentName, pos, num);
88  StringToInt(num, componentName, component);
89 
90  return pos;
91 }
92 
93 
94 //______________________________________________________________________________
95 size_type ParseFoundry(const std::string &name, size_type pos, XLFDName &/*dst*/)
96 {
97  //Ignore foundry.
98  std::string dummy;
99  return GetXLFDNameComponentAsString(name, "foundry", pos, dummy);
100 }
101 
102 
103 //______________________________________________________________________________
104 size_type ParseFamilyName(const std::string &name, size_type pos, XLFDName &dst)
105 {
106  const size_type tokenEnd = GetXLFDNameComponentAsString(name, "family name", pos, dst.fFamilyName);
107 
108  //This is a "special case": ROOT uses it's own symbol.ttf, but
109  //I can not use it to render text in a GUI, and also I can not use
110  //Apple's system symbol font - it can not encode all symbols ROOT wants.
111  if (dst.fFamilyName == "symbol")
112  dst.fFamilyName = "helvetica";
113 
114  return tokenEnd;
115 }
116 
117 
118 //______________________________________________________________________________
119 size_type ParseWeight(const std::string &name, size_type pos, XLFDName &dst)
120 {
121  //Weight can be an integer, can be a word, can be a combination of a word
122  //and integer.
123  std::string weight;
124  pos = GetXLFDNameComponentAsString(name, "weight", pos, weight);
125 
126  if (weight == "*")
127  dst.fWeight = kFWAny;
128  else if (weight == "bold")
129  dst.fWeight = kFWBold;
130  else
131  dst.fWeight = kFWMedium;
132 
133  return pos;
134 }
135 
136 
137 //______________________________________________________________________________
138 size_type ParseSlant(const std::string &name, size_type pos, XLFDName &dst)
139 {
140  //Slant can be regular or italic now.
141  std::string slant;
142  pos = GetXLFDNameComponentAsString(name, "slant", pos, slant);
143 
144  //Can be 'r', 'R', 'i', 'I', 'o', 'O', '*'.
145  if (slant == "*")
146  dst.fSlant = kFSAny;
147  else if (slant == "i" || slant == "I" || slant == "o" || slant == "O")
148  dst.fSlant = kFSItalic;
149  else
150  dst.fSlant = kFSRegular;
151 
152  return pos;
153 }
154 
155 //______________________________________________________________________________
156 size_type ParseSetwidth(const std::string &name, size_type pos, XLFDName &/*dst*/)
157 {
158  //Setwidth is ignored now.
159  std::string dummy;
160  return GetXLFDNameComponentAsString(name, "setwidth", pos, dummy);
161 }
162 
163 //______________________________________________________________________________
164 size_type ParseAddstyle(const std::string &name, size_type pos, XLFDName &/*dst*/)
165 {
166  //Ignored at the moment.
167  std::string dummy;
168  return GetXLFDNameComponentAsString(name, "addstyle", pos, dummy);
169 }
170 
171 //______________________________________________________________________________
172 size_type ParsePixelSize(const std::string &name, size_type pos, XLFDName &dst)
173 {
174  //First, try to parse as string. It can be '*' == 'any size'.
175  //In the first version it was more strict - throwing and exception.
176  std::string dummy;
177 
178  size_type endOfSize = GetXLFDNameComponentAsString(name, "pixel size", pos, dummy);
179  if (dummy == "*") {
180  //Aha, ignore size.
181  dst.fPixelSize = 0;
182  return endOfSize;
183  }
184 
185  const size_type pos1 = GetXLFDNameComponentAsInteger(name, "pixel size", pos, dst.fPixelSize);
186  if (dst.fPixelSize < 12)
187  dst.fPixelSize = 12;
188  //Real size in pixel?
189  return pos1;//GetXLFDNameComponentAsInteger(name, "pixel size", pos, dst.fPixelSize);
190 }
191 
192 //______________________________________________________________________________
193 size_type ParsePointSize(const std::string &name, size_type pos, XLFDName &/*dst*/)
194 {
195  //Ignored at the moment.
196  std::string dummy;
197  return GetXLFDNameComponentAsString(name, "point size", pos, dummy);
198 }
199 
200 
201 //______________________________________________________________________________
202 size_type ParseHoriz(const std::string &name, size_type pos, XLFDName &/*dst*/)
203 {
204  //Ignored at the moment.
205  std::string dummy;
206  return GetXLFDNameComponentAsString(name, "horizontal", pos, dummy);
207 }
208 
209 
210 //______________________________________________________________________________
211 size_type ParseVert(const std::string &name, size_type pos, XLFDName &/*dst*/)
212 {
213  //Ignored at the moment.
214  std::string dummy;
215  return GetXLFDNameComponentAsString(name, "vertical", pos, dummy);
216 }
217 
218 
219 //______________________________________________________________________________
220 size_type ParseSpacing(const std::string &name, size_type pos, XLFDName &/*dst*/)
221 {
222  //Ignored at the moment.
223  std::string dummy;
224  return GetXLFDNameComponentAsString(name, "spacing", pos, dummy);
225 }
226 
227 
228 //______________________________________________________________________________
229 size_type ParseAvgwidth(const std::string &name, size_type pos, XLFDName &/*dst*/)
230 {
231  //Ignored at the moment.
232  std::string dummy;
233  return GetXLFDNameComponentAsString(name, "average width", pos, dummy);
234 }
235 
236 
237 //______________________________________________________________________________
238 size_type ParseRgstry(const std::string &name, size_type pos, XLFDName &dst)
239 {
240  return GetXLFDNameComponentAsString(name, "language", pos, dst.fRgstry);
241 }
242 
243 
244 //______________________________________________________________________________
245 size_type ParseEncoding(const std::string &name, size_type pos, XLFDName &dst)
246 {
247  return GetXLFDNameComponentAsString(name, "encoding", pos, dst.fRgstry);
248 }
249 
250 }//Anonymous namespace.
251 
252 //______________________________________________________________________________
253 XLFDName::XLFDName()
254  : fWeight(kFWAny),
255  fSlant(kFSAny),
256  fPixelSize(0)
257 {
258 }
259 
260 //______________________________________________________________________________
261 bool ParseXLFDName(const std::string &xlfdName, XLFDName &dst)
262 {
263  const size_type nameLength = xlfdName.length();
264 
265  assert(nameLength && "XLFD name is a string with a zero length");
266 
267  if (!nameLength) {
268  ::Warning("ROOT::MacOSX::X11::ParseXLFDName: ", "XLFD name is a string with a zero length");
269  return false;
270  }
271 
272  try {
273  if (xlfdName == "fixed" || xlfdName == "*") {
274  //Is this correct XLFD name???? Who knows. Replace it.
275  dst.fFamilyName = "LucidaGrande";
276  dst.fPixelSize = 12;
277  } else {
278  size_type pos = ParseFoundry(xlfdName, 0, dst);
279  if (pos + 1 < nameLength)
280  pos = ParseFamilyName(xlfdName, pos, dst);
281 
282  if (pos + 1 < nameLength)
283  pos = ParseWeight(xlfdName, pos, dst);
284  else
285  dst.fWeight = kFWMedium;
286 
287  if (pos + 1 < nameLength)
288  pos = ParseSlant(xlfdName, pos, dst);
289  else
290  dst.fSlant = kFSRegular;
291 
292  if (pos + 1 < nameLength)
293  pos = ParseSetwidth(xlfdName, pos, dst);
294  if (pos + 1 < nameLength)
295  pos = ParseAddstyle(xlfdName, pos, dst);
296  if (pos + 1 < nameLength)
297  pos = ParsePixelSize(xlfdName, pos, dst);
298  if (pos + 1 < nameLength)
299  pos = ParsePointSize(xlfdName, pos, dst);
300  if (pos + 1 < nameLength)
301  pos = ParseHoriz(xlfdName, pos, dst);
302  if (pos + 1 < nameLength)
303  pos = ParseVert(xlfdName, pos, dst);
304  if (pos + 1 < nameLength)
305  pos = ParseSpacing(xlfdName, pos, dst);
306  if (pos + 1 < nameLength)
307  pos = ParseAvgwidth(xlfdName, pos, dst);
308  if (pos + 1 < nameLength)
309  pos = ParseRgstry(xlfdName, pos, dst);
310  if (pos + 1 < nameLength)
311  pos = ParseEncoding(xlfdName, pos, dst);
312  }
313 
314  return true;
315  } catch (const std::exception &e) {
316  ::Error("ROOT::MacOSX::Quartz::ParseXLFDName", "Failed to parse XLFD name - %s", e.what());
317  return false;
318  }
319 }
320 
321 }//X11
322 }//MacOSX
323 }//ROOT
bool ParseXLFDName(const std::string &xlfdName, XLFDName &dst)
Definition: XLFDParser.mm:261
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
double T(double x)
Definition: ChebyshevPol.h:34
#define assert(cond)
Definition: unittest.h:542
void Warning(const char *location, const char *msgfmt,...)
static RooMathCoreReg dummy
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.