ROOT  6.06/09
Reference Guide
FontCache.mm
Go to the documentation of this file.
1 // @(#)root/graf2d:$Id$
2 // Author: Timur Pocheptsov 19/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 <string>
18 #include <cmath>
19 
20 #include "CocoaUtils.h"
21 #include "QuartzText.h"
22 #include "FontCache.h"
23 #include "TSystem.h"
24 #include "TError.h"
25 #include "TEnv.h"
26 
27 namespace ROOT {
28 namespace MacOSX {
29 namespace Details {
30 
31 namespace {
32 
33 //ROOT uses indices for fonts. Indices are in the range [1 .. 15],
34 //12 is a symbol font (quite special thing, see the code below,
35 //15 is a "symbol italic" font - shear transformation is applied.
36 
37 //TODO: actually, it's not good to assume I have these fonts for sure,
38 //find a better way to check the available fonts and search for the best
39 //match.
40 
41 const CFStringRef fixedFontNames[FontCache::nPadFonts] =
42  {
43  CFSTR("TimesNewRomanPS-ItalicMT"),
44  CFSTR("TimesNewRomanPS-BoldMT"),
45  CFSTR("TimesNewRomanPS-BoldItalicMT"),
46  CFSTR("Helvetica"),
47  CFSTR("Helvetica-Oblique"),
48  CFSTR("Helvetica-Bold"),
49  CFSTR("Helvetica-BoldOblique"),
50  CFSTR("Courier"),
51  CFSTR("Courier-Oblique"),
52  CFSTR("Courier-Bold"),
53  CFSTR("Courier-BoldOblique"),
54  CFSTR("Symbol"),
55  CFSTR("TimesNewRomanPSMT"),
56  CFSTR("Wingdings"),
57  CFSTR("Symbol-Italic")
58  };
59 
60 //______________________________________________________________________________
61 CTFontCollectionRef CreateFontCollection(const X11::XLFDName &/*xlfd*/)
62 {
63  CTFontCollectionRef ctCollection = CTFontCollectionCreateFromAvailableFonts(0);
64  if (!ctCollection)
65  ::Error("CreateFontCollection", "CTFontCollectionCreateFromAvailableFonts failed");
66 
67  return ctCollection;
68 /* CTFontCollectionRef ctCollection = 0;
69  if (xlfd.fFamilyName == "*")
70  ctCollection = CTFontCollectionCreateFromAvailableFonts(0);//Select all available fonts.
71  else {
72  //Create collection, using font descriptor?
73  const Util::CFScopeGuard<CFStringRef> fontName(CFStringCreateWithCString(kCFAllocatorDefault, xlfd.fFamilyName.c_str(), kCFStringEncodingMacRoman));
74  if (!fontName.Get()) {
75  ::Error("CreateFontCollection", "CFStringCreateWithCString failed");
76  return 0;
77  }
78 
79  const Util::CFScopeGuard<CTFontDescriptorRef> fontDescriptor(CTFontDescriptorCreateWithNameAndSize(fontName.Get(), 0.));
80  if (!fontDescriptor.Get()) {
81  ::Error("CreateFontCollection", "CTFontDescriptorCreateWithNameAndSize failed");
82  return 0;
83  }
84 
85  Util::CFScopeGuard<CFMutableArrayRef> descriptors(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
86  if (!descriptors.Get()) {
87  ::Error("CreateFontCollection", "CFArrayCreateMutable failed");
88  return 0;
89  }
90 
91  CFArrayAppendValue(descriptors.Get(), fontDescriptor.Get());
92  ctCollection = CTFontCollectionCreateWithFontDescriptors(descriptors.Get(), 0);//Oh mama, so many code just to do this :(((
93  }
94 
95  if (!ctCollection) {
96  ::Error("CreateFontCollection", "No fonts are available for family %s", xlfd.fFamilyName.c_str());//WTF???
97  return 0;
98  }
99 
100 
101  return ctCollection;*/
102 }
103 
104 //______________________________________________________________________________
105 bool GetFamilyName(CTFontDescriptorRef fontDescriptor, std::vector<char> &name)
106 {
107  //If success, this function returns a null-terminated string in a vector.
108  assert(fontDescriptor != 0 && "GetFamilyName, parameter 'fontDescriptor' is null");
109 
110  name.clear();
111 
112  Util::CFScopeGuard<CFStringRef> cfFamilyName((CFStringRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute));
113  if (const CFIndex cfLen = CFStringGetLength(cfFamilyName.Get())) {
114  name.resize(cfLen + 1);//+ 1 for '\0'.
115  if (CFStringGetCString(cfFamilyName.Get(), &name[0], name.size(), kCFStringEncodingMacRoman))
116  return true;
117  }
118 
119  return false;
120 }
121 
122 #ifdef MAC_OS_X_VERSION_10_9
123 
124 //______________________________________________________________________________
125 bool GetPostscriptName(CTFontDescriptorRef fontDescriptor, std::vector<char> &name)
126 {
127  //If success, this function returns a null-terminated string in a vector.
128  assert(fontDescriptor != 0 && "GetPostscriptName, parameter 'fontDescriptor' is null");
129 
130  name.clear();
131 
132  Util::CFScopeGuard<CFStringRef> cfFamilyName((CFStringRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontNameAttribute));
133 
134  if (const CFIndex cfLen = CFStringGetLength(cfFamilyName.Get())) {
135  name.resize(cfLen + 1);//+ 1 for '\0'.
136  if (CFStringGetCString(cfFamilyName.Get(), &name[0], name.size(), kCFStringEncodingMacRoman))
137  return true;
138  }
139 
140  return false;
141 }
142 
143 #endif
144 
145 //______________________________________________________________________________
146 void GetWeightAndSlant(CTFontDescriptorRef fontDescriptor, X11::XLFDName &newXLFD)
147 {
148  //Let's ask for a weight and pixel size.
149  const Util::CFScopeGuard<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute));
150  if (traits.Get()) {
151  if (CFNumberRef symbolTraits = (CFNumberRef)CFDictionaryGetValue(traits.Get(), kCTFontSymbolicTrait)) {
152  uint32_t val = 0;
153  CFNumberGetValue(symbolTraits, kCFNumberIntType, &val);
154  if (val & kCTFontItalicTrait)
155  newXLFD.fSlant = X11::kFSItalic;
156  else
157  newXLFD.fSlant = X11::kFSRegular;
158 
159  if (val & kCTFontBoldTrait)
160  newXLFD.fWeight = X11::kFWBold;
161  else
162  newXLFD.fWeight = X11::kFWMedium;
163  }
164 
165  /*
166  //The code below is wrong - using it, I can not identify bold or italic and always have
167  //only medium/regular.
168  if(CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(traits.Get(), kCTFontWeightTrait)) {
169  double val = 0.;
170  if (CFNumberGetValue(weight, kCFNumberDoubleType, &val))
171  newXLFD.fWeight = val > 0. ? X11::kFWBold : X11::kFWMedium;
172  }
173 
174  if(CFNumberRef slant = (CFNumberRef)CFDictionaryGetValue(traits.Get(), kCTFontSlantTrait)) {
175  double val = 0.;
176  if (CFNumberGetValue(slant, kCFNumberDoubleType, &val))
177  newXLFD.fSlant = val > 0. ? X11::kFSItalic : X11::kFSRegular;
178  }
179  */
180  }
181 }
182 
183 //______________________________________________________________________________
184 void GetPixelSize(CTFontDescriptorRef fontDescriptor, X11::XLFDName &newXLFD)
185 {
186  const Util::CFScopeGuard<CFNumberRef> size((CFNumberRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontSizeAttribute));
187  if (size.Get()) {
188  int pixelSize = 0;
189  if(CFNumberIsFloatType(size.Get())) {
190  double val = 0;
191  CFNumberGetValue(size.Get(), kCFNumberDoubleType, &val);
192  pixelSize = val;
193  } else
194  CFNumberGetValue(size.Get(), kCFNumberIntType, &pixelSize);
195 
196  if(pixelSize)
197  newXLFD.fPixelSize = pixelSize;
198  }
199 }
200 
201 //_________________________________________________________________
202 void CreateXLFDString(const X11::XLFDName &xlfd, std::string &xlfdString)
203 {
204  xlfdString = "-CoreText-"; //Fake foundry.
205  xlfdString += xlfd.fFamilyName;
206 
207  if (xlfd.fWeight == X11::kFWBold)
208  xlfdString += "-bold";
209  else
210  xlfdString += "-normal";
211 
212  if (xlfd.fSlant == X11::kFSItalic)
213  xlfdString += "-i";
214  else
215  xlfdString += "-r";
216 
217  xlfdString += "-*-*"; //width, addstyle
218 
219  if (xlfd.fPixelSize) {
220  std::ostringstream out;
221  out<<xlfd.fPixelSize;
222  xlfdString += "-";
223  xlfdString += out.str();
224  } else
225  xlfdString += "-*";
226 
227  xlfdString += "-*-*-*-*-*-*-*-";//TODO: something more reasonable?
228 }
229 
230 }
231 
232 //_________________________________________________________________
234  : fSymbolFontRegistered(false)
235 {
236  //XLFD name is not exactly PS name thus generating a warning with a new Core Text.
237  fXLFDtoPostscriptNames["helvetica"] = "Helvetica";
238  fXLFDtoPostscriptNames["courier"] = "Courier";
239  fXLFDtoPostscriptNames["times"] = "Times-Roman";
240 }
241 
242 //______________________________________________________________________________
244 {
245  using Util::CFScopeGuard;
247 
248 #ifdef MAC_OS_X_VERSION_10_9
249  PSNameMap_t::const_iterator nameIt = fXLFDtoPostscriptNames.find(xlfd.fFamilyName);
250  const std::string &psName = nameIt == fXLFDtoPostscriptNames.end() ? xlfd.fFamilyName : nameIt->second;
251  const CFScopeGuard<CFStringRef> fontName(CFStringCreateWithCString(kCFAllocatorDefault, psName.c_str(), kCFStringEncodingMacRoman));
252 #else
253  const CFScopeGuard<CFStringRef> fontName(CFStringCreateWithCString(kCFAllocatorDefault, xlfd.fFamilyName.c_str(), kCFStringEncodingMacRoman));
254 #endif
255 
256  const CFStrongReference<CTFontRef> baseFont(CTFontCreateWithName(fontName.Get(), xlfd.fPixelSize, 0), false);//false == do not retain
257 
258  if (!baseFont.Get()) {
259  ::Error("FontCache::LoadFont", "CTFontCreateWithName failed for %s", xlfd.fFamilyName.c_str());
260  return FontStruct_t();//Haha! Die ROOT, die!
261  }
262 
263  CTFontSymbolicTraits symbolicTraits = CTFontSymbolicTraits();
264 
265  if (xlfd.fWeight == X11::kFWBold)
266  symbolicTraits |= kCTFontBoldTrait;
267  if (xlfd.fSlant == X11::kFSItalic)
268  symbolicTraits |= kCTFontItalicTrait;
269 
270  if (symbolicTraits) {
271  const CFStrongReference<CTFontRef> font(CTFontCreateCopyWithSymbolicTraits(baseFont.Get(), xlfd.fPixelSize, 0, symbolicTraits, symbolicTraits), false);//false == do not retain.
272  if (font.Get()) {
273  if (fLoadedFonts.find(font.Get()) == fLoadedFonts.end())
274  fLoadedFonts[font.Get()] = font;
275 
276  return reinterpret_cast<FontStruct_t>(font.Get());
277  }
278  }
279 
280  if (fLoadedFonts.find(baseFont.Get()) == fLoadedFonts.end())
281  fLoadedFonts[baseFont.Get()] = baseFont;
282 
283  return reinterpret_cast<FontStruct_t>(baseFont.Get());
284 }
285 
286 //______________________________________________________________________________
288 {
289  CTFontRef fontRef = (CTFontRef)font;
290  font_iterator fontIter = fLoadedFonts.find(fontRef);
291 
292  assert(fontIter != fLoadedFonts.end() && "Attempt to unload font, not created by font manager");
293 
294  fLoadedFonts.erase(fontIter);
295 }
296 
297 //______________________________________________________________________________
298 char **FontCache::ListFonts(const X11::XLFDName &xlfd, int maxNames, int &count)
299 {
300  typedef std::vector<char>::size_type size_type;
301 
302  count = 0;
303 
304  //Ugly, ugly code. I should "think different"!!!
305  //To extract font names, I have to: create CFString, create font descriptor, create
306  //CFArray, create CTFontCollection, that's a mess!!!
307  //It's good I have my small and ugly RAII classes, otherwise the code will be
308  //total trash and sodomy because of all possible cleanup actions.
309 
310  //First, create a font collection.
311  const Util::CFScopeGuard<CTFontCollectionRef> collectionGuard(CreateFontCollection(xlfd));
312  if (!collectionGuard.Get())
313  return 0;
314 
315  Util::CFScopeGuard<CFArrayRef> fonts(CTFontCollectionCreateMatchingFontDescriptors(collectionGuard.Get()));
316  if (!fonts.Get()) {
317  ::Error("FontCache::ListFonts", "CTFontCollectionCreateMatchingFontDescriptors failed %s", xlfd.fFamilyName.c_str());
318  return 0;
319  }
320 
321  std::vector<char> xlfdData;
322  //familyName is actually a null-terminated string.
323  std::vector<char> familyName;
324  X11::XLFDName newXLFD;
325  std::string xlfdString;
326 
327  const CFIndex nFonts = CFArrayGetCount(fonts.Get());
328  for (CFIndex i = 0; i < nFonts && count < maxNames; ++i) {
329  CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fonts.Get(), i);
330 
331  if (!GetFamilyName(font, familyName))
332  continue;
333 
334  if (xlfd.fFamilyName != "*" && xlfd.fFamilyName != &familyName[0])
335  continue;
336 
337  newXLFD.fFamilyName = &familyName[0];
338 
339  //If family name has '-', ROOT's GUI can not parse it correctly -
340  //'-' is a separator in XLFD. Just skip this font (anyway, it wan not requested by GUI, only
341  //listed by FontCache.
342  if (newXLFD.fFamilyName.find('-') != std::string::npos)
343  continue;
344 
345  GetWeightAndSlant(font, newXLFD);
346 
347  //Check weight and slant.
348  if (xlfd.fWeight != X11::kFWAny && newXLFD.fWeight != xlfd.fWeight)
349  continue;
350  if (xlfd.fSlant != X11::kFSAny && newXLFD.fSlant != xlfd.fSlant)
351  continue;
352 
353  if (xlfd.fPixelSize) {//Size was requested.
354  GetPixelSize(font, newXLFD);
355  //Core Text supports different font sizes.
356  if (!newXLFD.fPixelSize)
357  newXLFD.fPixelSize = xlfd.fPixelSize;
358  }
359 
360 #ifdef MAC_OS_X_VERSION_10_9
361  //To avoid a warning from Core Text, save a mapping from a name seen by ROOT (family)
362  //to a right postscript name (required by Core Text).
363 
364  //It's a null-terminated string:
365  std::vector<char> postscriptName;
366  if (GetPostscriptName(font, postscriptName)) {
367  if (fXLFDtoPostscriptNames.find(&familyName[0]) == fXLFDtoPostscriptNames.end())
368  fXLFDtoPostscriptNames[&familyName[0]] = &postscriptName[0];
369  }
370 #endif
371 
372 
373  //Ok, now lets create XLFD name, and place into list.
374  CreateXLFDString(newXLFD, xlfdString);
375  //
376  xlfdData.insert(xlfdData.end(), xlfdString.begin(), xlfdString.end());
377  xlfdData.push_back(0);//terminal 0.
378  ++count;
379  }
380 
381  //Setup array with string addresses.
382  if (xlfdData.size()) {
383  fFontLists.push_back(fDummyList);
384  fFontLists.back().fStringData.swap(xlfdData);
385 
386  std::vector<char> &data = fFontLists.back().fStringData;
387  std::vector<char *> &list = fFontLists.back().fList;
388 
389  list.push_back(&data[0]);
390  for (size_type i = 1, e = data.size(); i < e; ++i) {
391  if (!data[i] && i + 1 < e)
392  list.push_back(&data[i + 1]);
393  }
394 
395  return &list[0];
396  } else
397  return 0;
398 }
399 
400 //______________________________________________________________________________
401 void FontCache::FreeFontNames(char **fontList)
402 {
403  if (!fontList)
404  return;
405 
406  for (std::list<FontList>::iterator it = fFontLists.begin(), eIt = fFontLists.end(); it != eIt; ++it) {
407  if (fontList == &it->fList[0]) {
408  fFontLists.erase(it);
409  return;
410  }
411  }
412 
413  assert(0 && "FreeFontNames, unknown fontList");
414 }
415 
416 //______________________________________________________________________________
417 unsigned FontCache::GetTextWidth(FontStruct_t font, const char *text, int nChars)
418 {
419  typedef std::vector<CGSize>::size_type size_type;
420  //
421  CTFontRef fontRef = (CTFontRef)font;
422  assert(fLoadedFonts.find(fontRef) != fLoadedFonts.end() && "Font was not created by font manager");
423 
424  //nChars is either positive, or negative (take all string).
425  if (nChars < 0)
426  nChars = std::strlen(text);
427 
428  std::vector<UniChar> unichars(text, text + nChars);
429 
430  //Extract glyphs for a text.
431  std::vector<CGGlyph> glyphs(unichars.size());
432  CTFontGetGlyphsForCharacters(fontRef, &unichars[0], &glyphs[0], unichars.size());
433 
434  //Glyps' advances for a text.
435  std::vector<CGSize> glyphAdvances(glyphs.size());
436  CTFontGetAdvancesForGlyphs(fontRef, Quartz::horizontalFontOrientation, &glyphs[0], &glyphAdvances[0], glyphs.size());
437 
438  CGFloat textWidth = 0.;
439  for (size_type i = 0, e = glyphAdvances.size(); i < e; ++i)
440  textWidth += std::ceil(glyphAdvances[i].width);
441 
442  return textWidth;
443 }
444 
445 
446 //_________________________________________________________________
447 void FontCache::GetFontProperties(FontStruct_t font, int &maxAscent, int &maxDescent)
448 {
449  CTFontRef fontRef = (CTFontRef)font;
450 
451  assert(fLoadedFonts.find(fontRef) != fLoadedFonts.end() && "Font was not created by font manager");
452 
453  try {
454  maxAscent = int(CTFontGetAscent(fontRef) + 0.5) + 2;
455  maxDescent = int(CTFontGetDescent(fontRef) + 0.5);
456  } catch (const std::exception &) {
457  throw;
458  }
459 }
460 
461 
462 //_________________________________________________________________
463 CTFontRef FontCache::SelectFont(Font_t fontIndex, Float_t fontSize)
464 {
465  fontIndex /= 10;
466 
467  if (fontIndex > nPadFonts || !fontIndex) {
468  ::Warning("FontCache::SelectFont", "Font with index %d was requested", fontIndex);
469  fontIndex = 3;//Select the Helvetica as default.
470  } else
471  fontIndex -= 1;
472 
473  if (fontIndex == 11 || fontIndex == 14)//Special case, our own symbol.ttf file.
474  return SelectSymbolFont(fontSize, fontIndex);
475 
476  const UInt_t fixedSize = UInt_t(fontSize);
477  font_map_iterator it = fFonts[fontIndex].find(fixedSize);
478 
479  if (it == fFonts[fontIndex].end()) {
480  //Insert the new font.
481  try {
482  const CTFontGuard_t font(CTFontCreateWithName(fixedFontNames[fontIndex], fixedSize, 0), false);
483  if (!font.Get()) {//With Apple's lame documentation it's not clear, if function can return 0.
484  ::Error("FontCache::SelectFont", "CTFontCreateWithName failed for font %d", fontIndex);
485  return 0;
486  }
487 
488  fFonts[fontIndex][fixedSize] = font;//Insetion can throw.
489  return fSelectedFont = font.Get();
490  } catch (const std::exception &) {//Bad alloc.
491  return 0;
492  }
493  }
494 
495  return fSelectedFont = it->second.Get();
496 }
497 
498 //_________________________________________________________________
499 CTFontRef FontCache::SelectSymbolFont(Float_t fontSize, unsigned fontIndex)
500 {
501  assert(fontIndex == 11 || fontIndex == 14 && "SelectSymbolFont, parameter fontIndex has invalid value");
502 
503  const UInt_t fixedSize = UInt_t(fontSize);
504  font_map_iterator it = fFonts[fontIndex].find(fixedSize);//In ROOT, 11 is a font from symbol.ttf.
505 
506  if (it == fFonts[fontIndex].end()) {
507  //This GetValue + Which I took from Olivier's code.
508  const char * const fontDirectoryPath = gEnv->GetValue("Root.TTFontPath","$(ROOTSYS)/fonts");//This one I do not own.
509  char * const fontFileName = gSystem->Which(fontDirectoryPath, "symbol.ttf", kReadPermission);//This must be deleted.
510 
511  const Util::ScopedArray<char> arrayGuard(fontFileName);
512 
513  if (!fontFileName || fontFileName[0] == 0) {
514  ::Error("FontCache::SelectSymbolFont", "symbol.ttf file not found");
515  return 0;
516  }
517 
518  try {
519  const Util::CFScopeGuard<CFStringRef> path(CFStringCreateWithCString(kCFAllocatorDefault, fontFileName, kCFURLPOSIXPathStyle));
520  if (!path.Get()) {
521  ::Error("FontCache::SelectSymbolFont", "CFStringCreateWithCString failed");
522  return 0;
523  }
524 
525  const Util::CFScopeGuard<CFURLRef> fontURL(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.Get(), kCFURLPOSIXPathStyle, false));
526  if (!fontURL.Get()) {
527  ::Error("FontCache::SelectSymbolFont", "CFURLCreateWithFileSystemPath failed");
528  return 0;
529  }
530 
531  //Try to register this font.
532  if (!fSymbolFontRegistered) {
533  CFErrorRef err = 0;
534  fSymbolFontRegistered = CTFontManagerRegisterFontsForURL(fontURL.Get(), kCTFontManagerScopeProcess, &err);
535  if (!fSymbolFontRegistered) {
536  ::Error("FontCache::SelectSymbolFont", "CTFontManagerRegisterFontsForURL failed");
537  if (err)
538  CFRelease(err);
539  return 0;
540  }
541  }
542 
543  const Util::CFScopeGuard<CFArrayRef> arr(CTFontManagerCreateFontDescriptorsFromURL(fontURL.Get()));
544  if (!arr.Get()) {
545  ::Error("FontCache::SelectSymbolFont", "CTFontManagerCreateFontDescriptorsFromURL failed");
546  return 0;
547  }
548 
549  CTFontDescriptorRef fontDesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(arr.Get(), 0);
550 
551  const CGAffineTransform shearMatrix = {1., 0., 0.26794, 1., 0., 0.};//Yes, these are hardcoded values, taken from TPDF class.
552  const CTFontGuard_t font(CTFontCreateWithFontDescriptorAndOptions(fontDesc, fixedSize,
553  fontIndex == 11 ? &CGAffineTransformIdentity :
554  &shearMatrix, kCTFontOptionsDefault), false);
555  if (!font.Get()) {
556  ::Error("FontCache::SelectSymbolFont", "CTFontCreateWithFontDescriptor failed");
557  return 0;
558  }
559 
560  fFonts[fontIndex][fixedSize] = font;//This can throw.
561  return fSelectedFont = font.Get();
562  } catch (const std::exception &) {//Bad alloc.
563  //RAII destructors should do their work.
564  return 0;
565  }
566  }
567 
568  return fSelectedFont = it->second.Get();
569 }
570 
571 //_________________________________________________________________
572 void FontCache::GetTextBounds(UInt_t &w, UInt_t &h, const char *text)const
573 {
574  assert(fSelectedFont != 0 && "GetTextBounds: no font was selected");
575 
576  try {
577  const Quartz::TextLine ctLine(text, fSelectedFont);
578  ctLine.GetBounds(w, h);
579  h += 2;
580  } catch (const std::exception &) {
581  throw;
582  }
583 }
584 
585 //_________________________________________________________________
586 void FontCache::GetTextBounds(UInt_t &w, UInt_t &h, const std::vector<UniChar> &unichars)const
587 {
588  assert(fSelectedFont != 0 && "GetTextBounds: no font was selected");
589 
590  try {
591  const Quartz::TextLine ctLine(unichars, fSelectedFont);
592  ctLine.GetBounds(w, h);
593  h += 2;
594  } catch (const std::exception &) {
595  throw;
596  }
597 }
598 
599 //_________________________________________________________________
600 double FontCache::GetAscent()const
601 {
602  assert(fSelectedFont != 0 && "GetAscent, no font was selected");
603  return CTFontGetAscent(fSelectedFont) + 1;
604 }
605 
606 //_________________________________________________________________
607 double FontCache::GetAscent(const char *text)const
608 {
609  assert(text != 0 && "GetAscent, parameter 'text' is null");
610  assert(fSelectedFont != 0 && "GetAscent, no font was selected");
611 
612  try {
613  const Quartz::TextLine ctLine(text, fSelectedFont);
614  Int_t ascent = 0, descent = 0;
615  ctLine.GetAscentDescent(ascent, descent);
616  return ascent;
617  } catch (const std::exception &) {
618  throw;
619  }
620 }
621 
622 //_________________________________________________________________
623 double FontCache::GetAscent(const std::vector<UniChar> &unichars)const
624 {
625  assert(fSelectedFont != 0 && "GetAscent, no font was selected");
626 
627  try {
628  const Quartz::TextLine ctLine(unichars, fSelectedFont);
629  Int_t ascent = 0, descent = 0;
630  ctLine.GetAscentDescent(ascent, descent);
631  return ascent;
632  } catch (const std::exception &) {
633  throw;
634  }
635 }
636 
637 //_________________________________________________________________
639 {
640  assert(fSelectedFont != 0 && "GetDescent, no font was selected");
641  return CTFontGetDescent(fSelectedFont) + 1;
642 }
643 
644 //_________________________________________________________________
645 double FontCache::GetDescent(const char *text)const
646 {
647  assert(text != 0 && "GetDescent, parameter 'text' is null");
648  assert(fSelectedFont != 0 && "GetDescent, no font was selected");
649 
650  try {
651  const Quartz::TextLine ctLine(text, fSelectedFont);
652  Int_t ascent = 0, descent = 0;
653  ctLine.GetAscentDescent(ascent, descent);
654  return descent;
655  } catch (const std::exception &) {
656  throw;
657  }
658 }
659 
660 //_________________________________________________________________
661 double FontCache::GetDescent(const std::vector<UniChar> &unichars)const
662 {
663  assert(fSelectedFont != 0 && "GetDescent, no font was selected");
664 
665  try {
666  const Quartz::TextLine ctLine(unichars, fSelectedFont);
667  Int_t ascent = 0, descent = 0;
668  ctLine.GetAscentDescent(ascent, descent);
669  return descent;
670  } catch (const std::exception &) {
671  throw;
672  }
673 }
674 
675 //_________________________________________________________________
677 {
678  assert(fSelectedFont != 0 && "GetLeading, no font was selected");
679  return CTFontGetLeading(fSelectedFont);
680 }
681 
682 
683 }//Details
684 }//MacOSX
685 }//ROOT
char ** ListFonts(const X11::XLFDName &xlfd, int maxNames, int &count)
Definition: FontCache.mm:298
Handle_t FontStruct_t
Definition: GuiTypes.h:40
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
FontStruct_t LoadFont(const X11::XLFDName &xlfd)
Definition: FontCache.mm:243
FontMap_t fFonts[nPadFonts]
Definition: FontCache.h:92
float Float_t
Definition: RtypesCore.h:53
void GetBounds(UInt_t &w, UInt_t &h) const
Definition: QuartzText.mm:190
#define assert(cond)
Definition: unittest.h:542
TH1 * h
Definition: legend2.C:5
std::map< CTFontRef, CTFontGuard_t > fLoadedFonts
Definition: FontCache.h:83
int Int_t
Definition: RtypesCore.h:41
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition: TSystem.cxx:1511
unsigned GetTextWidth(FontStruct_t font, const char *text, int nChars)
Definition: FontCache.mm:417
short Font_t
Definition: RtypesCore.h:75
ClassImp(TIterator) Bool_t TIterator return false
Compare two iterator objects.
Definition: TIterator.cxx:20
std::map< CTFontRef, CTFontGuard_t >::iterator font_iterator
Definition: FontCache.h:84
const CTFontOrientation horizontalFontOrientation
Definition: QuartzText.mm:39
void GetTextBounds(UInt_t &w, UInt_t &h, const char *text) const
Definition: FontCache.mm:572
void FreeFontNames(char **fontList)
Definition: FontCache.mm:401
char * out
Definition: TBase64.cxx:29
TCanvas * fonts()
Definition: fonts.C:10
void GetAscentDescent(Int_t &asc, Int_t &desc) const
Definition: QuartzText.mm:200
ROOT::R::TRInterface & r
Definition: Object.C:4
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
virtual Int_t GetValue(const char *name, Int_t dflt)
Returns the integer value for a resource.
Definition: TEnv.cxx:494
unsigned int UInt_t
Definition: RtypesCore.h:42
void Warning(const char *location, const char *msgfmt,...)
std::list< FontList > fFontLists
Definition: FontCache.h:109
FontMap_t::iterator font_map_iterator
Definition: FontCache.h:89
void GetFontProperties(FontStruct_t font, int &maxAscent, int &maxDescent)
Definition: FontCache.mm:447
TText * text
R__EXTERN TEnv * gEnv
Definition: TEnv.h:174
CTFontRef SelectFont(Font_t fontIndex, Float_t fontSize)
Definition: FontCache.mm:463
double ceil(double)
void UnloadFont(FontStruct_t font)
Definition: FontCache.mm:287
CTFontRef SelectSymbolFont(Float_t fontSize, unsigned fontIndex)
Definition: FontCache.mm:499
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.