42 const CFStringRef fixedFontNames[FontCache::nPadFonts] =
44 CFSTR(
"TimesNewRomanPS-ItalicMT"),
45 CFSTR(
"TimesNewRomanPS-BoldMT"),
46 CFSTR(
"TimesNewRomanPS-BoldItalicMT"),
48 CFSTR(
"Helvetica-Oblique"),
49 CFSTR(
"Helvetica-Bold"),
50 CFSTR(
"Helvetica-BoldOblique"),
52 CFSTR(
"Courier-Oblique"),
53 CFSTR(
"Courier-Bold"),
54 CFSTR(
"Courier-BoldOblique"),
56 CFSTR(
"TimesNewRomanPSMT"),
58 CFSTR(
"Symbol-Italic")
62 CTFontCollectionRef CreateFontCollection(
const X11::XLFDName &)
64 CTFontCollectionRef ctCollection = CTFontCollectionCreateFromAvailableFonts(0);
66 ::Error(
"CreateFontCollection",
"CTFontCollectionCreateFromAvailableFonts failed");
106 bool GetFamilyName(CTFontDescriptorRef fontDescriptor, std::vector<char> &name)
109 assert(fontDescriptor != 0 &&
"GetFamilyName, parameter 'fontDescriptor' is null");
113 Util::CFScopeGuard<CFStringRef> cfFamilyName((CFStringRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute));
114 if (
const CFIndex cfLen = CFStringGetLength(cfFamilyName.Get())) {
115 name.resize(cfLen + 1);
116 if (CFStringGetCString(cfFamilyName.Get(), &name[0], name.size(), kCFStringEncodingMacRoman))
123 #ifdef MAC_OS_X_VERSION_10_9
126 bool GetPostscriptName(CTFontDescriptorRef fontDescriptor, std::vector<char> &name)
129 assert(fontDescriptor != 0 &&
"GetPostscriptName, parameter 'fontDescriptor' is null");
133 Util::CFScopeGuard<CFStringRef> cfFamilyName((CFStringRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontNameAttribute));
135 if (
const CFIndex cfLen = CFStringGetLength(cfFamilyName.Get())) {
136 name.resize(cfLen + 1);
137 if (CFStringGetCString(cfFamilyName.Get(), &name[0], name.size(), kCFStringEncodingMacRoman))
147 void GetWeightAndSlant(CTFontDescriptorRef fontDescriptor, X11::XLFDName &newXLFD)
150 const Util::CFScopeGuard<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute));
152 if (CFNumberRef symbolTraits = (CFNumberRef)CFDictionaryGetValue(traits.Get(), kCTFontSymbolicTrait)) {
154 CFNumberGetValue(symbolTraits, kCFNumberIntType, &val);
155 if (val & kCTFontItalicTrait)
156 newXLFD.fSlant = X11::kFSItalic;
158 newXLFD.fSlant = X11::kFSRegular;
160 if (val & kCTFontBoldTrait)
161 newXLFD.fWeight = X11::kFWBold;
163 newXLFD.fWeight = X11::kFWMedium;
185 void GetPixelSize(CTFontDescriptorRef fontDescriptor, X11::XLFDName &newXLFD)
187 const Util::CFScopeGuard<CFNumberRef> size((CFNumberRef)CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontSizeAttribute));
190 if(CFNumberIsFloatType(size.Get())) {
192 CFNumberGetValue(size.Get(), kCFNumberDoubleType, &val);
195 CFNumberGetValue(size.Get(), kCFNumberIntType, &pixelSize);
198 newXLFD.fPixelSize = pixelSize;
203 void CreateXLFDString(
const X11::XLFDName &xlfd, std::string &xlfdString)
205 xlfdString =
"-CoreText-";
206 xlfdString += xlfd.fFamilyName;
208 if (xlfd.fWeight == X11::kFWBold)
209 xlfdString += "-bold";
211 xlfdString += "-normal";
213 if (xlfd.fSlant == X11::kFSItalic)
218 xlfdString += "-*-*";
220 if (xlfd.fPixelSize) {
221 std::ostringstream out;
222 out<<xlfd.fPixelSize;
224 xlfdString += out.str();
228 xlfdString += "-*-*-*-*-*-*-*-";
234 FontCache::FontCache()
235 : fSymbolFontRegistered(false)
238 fXLFDtoPostscriptNames["helvetica"] =
"Helvetica";
239 fXLFDtoPostscriptNames["courier"] =
"Courier";
240 fXLFDtoPostscriptNames["times"] =
"Times-Roman";
244 FontStruct_t FontCache::LoadFont(
const X11::XLFDName &xlfd)
246 using Util::CFScopeGuard;
247 using Util::CFStrongReference;
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));
254 const CFScopeGuard<CFStringRef> fontName(CFStringCreateWithCString(kCFAllocatorDefault, xlfd.fFamilyName.c_str(), kCFStringEncodingMacRoman));
257 const CFStrongReference<CTFontRef> baseFont(CTFontCreateWithName(fontName.Get(), xlfd.fPixelSize, 0),
false);
259 if (!baseFont.Get()) {
260 ::Error(
"FontCache::LoadFont",
"CTFontCreateWithName failed for %s", xlfd.fFamilyName.c_str());
261 return FontStruct_t();
264 CTFontSymbolicTraits symbolicTraits = CTFontSymbolicTraits();
266 if (xlfd.fWeight == X11::kFWBold)
267 symbolicTraits |= kCTFontBoldTrait;
268 if (xlfd.fSlant == X11::kFSItalic)
269 symbolicTraits |= kCTFontItalicTrait;
271 if (symbolicTraits) {
272 const CFStrongReference<CTFontRef> font(CTFontCreateCopyWithSymbolicTraits(baseFont.Get(), xlfd.fPixelSize, 0, symbolicTraits, symbolicTraits),
false);
274 if (fLoadedFonts.find(font.Get()) == fLoadedFonts.end())
275 fLoadedFonts[font.Get()] = font;
277 return reinterpret_cast<FontStruct_t
>(font.Get());
281 if (fLoadedFonts.find(baseFont.Get()) == fLoadedFonts.end())
282 fLoadedFonts[baseFont.Get()] = baseFont;
284 return reinterpret_cast<FontStruct_t
>(baseFont.Get());
288 void FontCache::UnloadFont(FontStruct_t font)
290 CTFontRef fontRef = (CTFontRef)font;
291 font_iterator fontIter = fLoadedFonts.find(fontRef);
293 assert(fontIter != fLoadedFonts.end() &&
"Attempt to unload font, not created by font manager");
295 fLoadedFonts.erase(fontIter);
299 char **FontCache::ListFonts(
const X11::XLFDName &xlfd,
int maxNames,
int &count)
301 typedef std::vector<char>::size_type size_type;
312 const Util::CFScopeGuard<CTFontCollectionRef> collectionGuard(CreateFontCollection(xlfd));
313 if (!collectionGuard.Get())
316 Util::CFScopeGuard<CFArrayRef> fonts(CTFontCollectionCreateMatchingFontDescriptors(collectionGuard.Get()));
318 ::Error(
"FontCache::ListFonts",
"CTFontCollectionCreateMatchingFontDescriptors failed %s", xlfd.fFamilyName.c_str());
322 std::vector<char> xlfdData;
324 std::vector<char> familyName;
325 X11::XLFDName newXLFD;
326 std::string xlfdString;
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);
332 if (!GetFamilyName(font, familyName))
335 if (xlfd.fFamilyName !=
"*" && xlfd.fFamilyName != &familyName[0])
338 newXLFD.fFamilyName = &familyName[0];
343 if (newXLFD.fFamilyName.find(
'-') != std::string::npos)
346 GetWeightAndSlant(font, newXLFD);
349 if (xlfd.fWeight != X11::kFWAny && newXLFD.fWeight != xlfd.fWeight)
351 if (xlfd.fSlant != X11::kFSAny && newXLFD.fSlant != xlfd.fSlant)
354 if (xlfd.fPixelSize) {
355 GetPixelSize(font, newXLFD);
357 if (!newXLFD.fPixelSize)
358 newXLFD.fPixelSize = xlfd.fPixelSize;
361 #ifdef MAC_OS_X_VERSION_10_9
366 std::vector<char> postscriptName;
367 if (GetPostscriptName(font, postscriptName)) {
368 if (fXLFDtoPostscriptNames.find(&familyName[0]) == fXLFDtoPostscriptNames.end())
369 fXLFDtoPostscriptNames[&familyName[0]] = &postscriptName[0];
375 CreateXLFDString(newXLFD, xlfdString);
377 xlfdData.insert(xlfdData.end(), xlfdString.begin(), xlfdString.end());
378 xlfdData.push_back(0);
383 if (xlfdData.size()) {
384 fFontLists.push_back(fDummyList);
385 fFontLists.back().fStringData.swap(xlfdData);
387 std::vector<char> &data = fFontLists.back().fStringData;
388 std::vector<char *> &list = fFontLists.back().fList;
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]);
402 void FontCache::FreeFontNames(
char **fontList)
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);
414 assert(0 &&
"FreeFontNames, unknown fontList");
418 unsigned FontCache::GetTextWidth(FontStruct_t font,
const char *text,
int nChars)
420 typedef std::vector<CGSize>::size_type size_type;
422 CTFontRef fontRef = (CTFontRef)font;
423 assert(fLoadedFonts.find(fontRef) != fLoadedFonts.end() &&
"Font was not created by font manager");
427 nChars = std::strlen(text);
429 std::vector<UniChar> unichars(text, text + nChars);
432 std::vector<CGGlyph> glyphs(unichars.size());
433 CTFontGetGlyphsForCharacters(fontRef, &unichars[0], &glyphs[0], unichars.size());
436 std::vector<CGSize> glyphAdvances(glyphs.size());
437 CTFontGetAdvancesForGlyphs(fontRef, Quartz::horizontalFontOrientation, &glyphs[0], &glyphAdvances[0], glyphs.size());
439 CGFloat textWidth = 0.;
440 for (size_type i = 0, e = glyphAdvances.size(); i < e; ++i)
441 textWidth += std::ceil(glyphAdvances[i].width);
448 void FontCache::GetFontProperties(FontStruct_t font,
int &maxAscent,
int &maxDescent)
450 CTFontRef fontRef = (CTFontRef)font;
452 assert(fLoadedFonts.find(fontRef) != fLoadedFonts.end() &&
"Font was not created by font manager");
455 maxAscent = int(CTFontGetAscent(fontRef) + 0.5) + 2;
456 maxDescent = int(CTFontGetDescent(fontRef) + 0.5);
457 }
catch (
const std::exception &) {
464 CTFontRef FontCache::SelectFont(Font_t fontIndex, Float_t fontSize)
468 if (fontIndex > nPadFonts || !fontIndex) {
469 ::Warning(
"FontCache::SelectFont",
"Font with index %d was requested", fontIndex);
474 if (fontIndex == 11 || fontIndex == 14)
475 return SelectSymbolFont(fontSize, fontIndex);
477 const UInt_t fixedSize = UInt_t(fontSize);
478 font_map_iterator it = fFonts[fontIndex].find(fixedSize);
480 if (it == fFonts[fontIndex].end()) {
483 const CTFontGuard_t font(CTFontCreateWithName(fixedFontNames[fontIndex], fixedSize, 0),
false);
485 ::Error(
"FontCache::SelectFont",
"CTFontCreateWithName failed for font %d", fontIndex);
489 fFonts[fontIndex][fixedSize] = font;
490 return fSelectedFont = font.Get();
491 }
catch (
const std::exception &) {
496 return fSelectedFont = it->second.Get();
500 CTFontRef FontCache::SelectSymbolFont(Float_t fontSize,
unsigned fontIndex)
502 assert(fontIndex == 11 || fontIndex == 14 &&
"SelectSymbolFont, parameter fontIndex has invalid value");
504 const UInt_t fixedSize = UInt_t(fontSize);
505 font_map_iterator it = fFonts[fontIndex].find(fixedSize);
507 if (it == fFonts[fontIndex].end()) {
509 const char *
const fontDirectoryPath = gEnv->GetValue(
"Root.TTFontPath",TROOT::GetTTFFontDir());
510 char *
const fontFileName = gSystem->Which(fontDirectoryPath,
"symbol.ttf", kReadPermission);
512 const Util::ScopedArray<char> arrayGuard(fontFileName);
514 if (!fontFileName || fontFileName[0] == 0) {
515 ::Error(
"FontCache::SelectSymbolFont",
"symbol.ttf file not found");
520 const Util::CFScopeGuard<CFStringRef> path(CFStringCreateWithCString(kCFAllocatorDefault, fontFileName, kCFURLPOSIXPathStyle));
522 ::Error(
"FontCache::SelectSymbolFont",
"CFStringCreateWithCString failed");
526 const Util::CFScopeGuard<CFURLRef> fontURL(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.Get(), kCFURLPOSIXPathStyle,
false));
527 if (!fontURL.Get()) {
528 ::Error(
"FontCache::SelectSymbolFont",
"CFURLCreateWithFileSystemPath failed");
533 if (!fSymbolFontRegistered) {
535 fSymbolFontRegistered = CTFontManagerRegisterFontsForURL(fontURL.Get(), kCTFontManagerScopeProcess, &err);
536 if (!fSymbolFontRegistered) {
537 ::Error(
"FontCache::SelectSymbolFont",
"CTFontManagerRegisterFontsForURL failed");
544 const Util::CFScopeGuard<CFArrayRef> arr(CTFontManagerCreateFontDescriptorsFromURL(fontURL.Get()));
546 ::Error(
"FontCache::SelectSymbolFont",
"CTFontManagerCreateFontDescriptorsFromURL failed");
550 CTFontDescriptorRef fontDesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(arr.Get(), 0);
552 const CGAffineTransform shearMatrix = {1., 0., 0.26794, 1., 0., 0.};
553 const CTFontGuard_t font(CTFontCreateWithFontDescriptorAndOptions(fontDesc, fixedSize,
554 fontIndex == 11 ? &CGAffineTransformIdentity :
555 &shearMatrix, kCTFontOptionsDefault),
false);
557 ::Error(
"FontCache::SelectSymbolFont",
"CTFontCreateWithFontDescriptor failed");
561 fFonts[fontIndex][fixedSize] = font;
562 return fSelectedFont = font.Get();
563 }
catch (
const std::exception &) {
569 return fSelectedFont = it->second.Get();
573 void FontCache::GetTextBounds(UInt_t &w, UInt_t &h,
const char *text)
const
575 assert(fSelectedFont != 0 &&
"GetTextBounds: no font was selected");
578 const Quartz::TextLine ctLine(text, fSelectedFont);
579 ctLine.GetBounds(w, h);
581 }
catch (
const std::exception &) {
587 void FontCache::GetTextBounds(UInt_t &w, UInt_t &h,
const std::vector<UniChar> &unichars)
const
589 assert(fSelectedFont != 0 &&
"GetTextBounds: no font was selected");
592 const Quartz::TextLine ctLine(unichars, fSelectedFont);
593 ctLine.GetBounds(w, h);
595 }
catch (
const std::exception &) {
601 double FontCache::GetAscent()
const
603 assert(fSelectedFont != 0 &&
"GetAscent, no font was selected");
604 return CTFontGetAscent(fSelectedFont) + 1;
608 double FontCache::GetAscent(
const char *text)
const
610 assert(text != 0 &&
"GetAscent, parameter 'text' is null");
611 assert(fSelectedFont != 0 &&
"GetAscent, no font was selected");
614 const Quartz::TextLine ctLine(text, fSelectedFont);
615 Int_t ascent = 0, descent = 0;
616 ctLine.GetAscentDescent(ascent, descent);
618 }
catch (
const std::exception &) {
624 double FontCache::GetAscent(
const std::vector<UniChar> &unichars)
const
626 assert(fSelectedFont != 0 &&
"GetAscent, no font was selected");
629 const Quartz::TextLine ctLine(unichars, fSelectedFont);
630 Int_t ascent = 0, descent = 0;
631 ctLine.GetAscentDescent(ascent, descent);
633 }
catch (
const std::exception &) {
639 double FontCache::GetDescent()
const
641 assert(fSelectedFont != 0 &&
"GetDescent, no font was selected");
642 return CTFontGetDescent(fSelectedFont) + 1;
646 double FontCache::GetDescent(
const char *text)
const
648 assert(text != 0 &&
"GetDescent, parameter 'text' is null");
649 assert(fSelectedFont != 0 &&
"GetDescent, no font was selected");
652 const Quartz::TextLine ctLine(text, fSelectedFont);
653 Int_t ascent = 0, descent = 0;
654 ctLine.GetAscentDescent(ascent, descent);
656 }
catch (
const std::exception &) {
662 double FontCache::GetDescent(
const std::vector<UniChar> &unichars)
const
664 assert(fSelectedFont != 0 &&
"GetDescent, no font was selected");
667 const Quartz::TextLine ctLine(unichars, fSelectedFont);
668 Int_t ascent = 0, descent = 0;
669 ctLine.GetAscentDescent(ascent, descent);
671 }
catch (
const std::exception &) {
677 double FontCache::GetLeading()
const
679 assert(fSelectedFont != 0 &&
"GetLeading, no font was selected");
680 return CTFontGetLeading(fSelectedFont);