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