17 #include <Availability.h>
30 #ifdef MAC_OS_X_VERSION_10_11
32 const CTFontOrientation defaultFontOrientation = kCTFontOrientationDefault;
33 const CTFontOrientation horizontalFontOrientation = kCTFontOrientationHorizontal;
34 const CTFontOrientation verticalFontOrientation = kCTFontOrientationVertical;
38 const CTFontOrientation defaultFontOrientation = kCTFontDefaultOrientation;
39 const CTFontOrientation horizontalFontOrientation = kCTFontHorizontalOrientation;
40 const CTFontOrientation verticalFontOrientation = kCTFontVerticalOrientation;
47 void GetTextColorForIndex(Color_t colorIndex, Float_t &r, Float_t &g, Float_t &b, Float_t &a)
49 if (
const TColor *
const color = gROOT->GetColor(colorIndex)) {
50 color->GetRGB(r, g, b);
51 a = color->GetAlpha();
56 CGRect BBoxForCTRun(CTFontRef font, CTRunRef run)
58 assert(font != 0 &&
"BBoxForCTRun, parameter 'font' is null");
59 assert(run != 0 &&
"BBoxForCTRun, parameter 'run' is null");
62 if (
const CFIndex nGlyphs = CTRunGetGlyphCount(run)) {
63 std::vector<CGGlyph> glyphs(nGlyphs);
64 CTRunGetGlyphs(run, CFRangeMake(0, 0), &glyphs[0]);
65 bbox = CTFontGetBoundingRectsForGlyphs(font, defaultFontOrientation,
66 &glyphs[0], 0, nGlyphs);
75 TextLine::TextLine(
const char *textLine, CTFontRef font)
80 CFStringRef keys[] = {kCTFontAttributeName};
81 CFTypeRef values[] = {font};
83 Init(textLine, 1, keys, values);
87 TextLine::TextLine(
const std::vector<UniChar> &unichars, CTFontRef font)
93 CFStringRef keys[] = {kCTFontAttributeName};
94 CFTypeRef values[] = {font};
96 Init(unichars, 1, keys, values);
100 TextLine::TextLine(
const char *textLine, CTFontRef font, Color_t color)
105 using MacOSX::Util::CFScopeGuard;
107 const CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
108 if (!rgbColorSpace.Get())
109 throw std::runtime_error(
"TextLine: color space");
111 Float_t rgba[] = {0.f, 0.f, 0.f, 1.f};
112 GetTextColorForIndex(color, rgba[0], rgba[1], rgba[2], rgba[3]);
113 const CGFloat cgRgba[] = {rgba[0], rgba[1], rgba[2], rgba[3]};
115 const CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), cgRgba));
118 CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
119 CFTypeRef values[] = {font, textColor.Get()};
121 Init(textLine, 2, keys, values);
125 TextLine::TextLine(
const char *textLine, CTFontRef font,
const CGFloat *rgb)
130 using ROOT::MacOSX::Util::CFScopeGuard;
131 CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
133 if (!rgbColorSpace.Get())
134 throw std::runtime_error(
"TexLine: color space is null");
136 CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), rgb));
139 CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
140 CFTypeRef values[] = {font, textColor.Get()};
142 Init(textLine, 2, keys, values);
146 TextLine::TextLine(
const std::vector<UniChar> &unichars, CTFontRef font, Color_t color)
151 using MacOSX::Util::CFScopeGuard;
153 const CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
154 if (!rgbColorSpace.Get())
155 throw std::runtime_error(
"TextLine: color space");
157 Float_t rgba[] = {0.f, 0.f, 0.f, 1.f};
158 GetTextColorForIndex(color, rgba[0], rgba[1], rgba[2], rgba[3]);
159 const CGFloat cgRgba[] = {rgba[0], rgba[1], rgba[2], rgba[3]};
161 const CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), cgRgba));
164 CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
165 CFTypeRef values[] = {font, textColor.Get()};
167 Init(unichars, 2, keys, values);
172 TextLine::~TextLine()
179 void TextLine::GetBounds(UInt_t &w, UInt_t &h)
const
182 CGFloat ascent = 0., descent = 0., leading = 0.;
183 w = UInt_t(CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading));
189 void TextLine::GetAscentDescent(Int_t &asc, Int_t &desc)
const
192 CGFloat ascent = 0., descent = 0., leading = 0.;
193 CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading);
195 desc = Int_t(descent);
199 CFArrayRef runs = CTLineGetGlyphRuns(fCTLine);
200 if (runs && CFArrayGetCount(runs) && fCTFont) {
201 CTRunRef firstRun =
static_cast<CTRunRef
>(CFArrayGetValueAtIndex(runs, 0));
202 CGRect box = BBoxForCTRun(fCTFont, firstRun);
203 if (CGRectIsNull(box))
206 for (CFIndex i = 1, e = CFArrayGetCount(runs); i < e; ++i) {
207 CTRunRef run =
static_cast<CTRunRef
>(CFArrayGetValueAtIndex(runs, i));
208 CGRect nextBox = BBoxForCTRun(fCTFont, run);
209 if (CGRectIsNull(nextBox))
211 box = CGRectUnion(box, nextBox);
214 asc = Int_t(TMath::Ceil(box.size.height) + box.origin.y);
215 desc = Int_t(TMath::Abs(TMath::Floor(box.origin.y)));
221 void TextLine::Init(
const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
223 using MacOSX::Util::CFScopeGuard;
226 const CFScopeGuard<CFDictionaryRef> stringAttribs(CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
227 nAttribs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
228 if (!stringAttribs.Get())
229 throw std::runtime_error(
"TextLine: null attribs");
231 const CFScopeGuard<CFStringRef> wrappedCString(CFStringCreateWithCString(kCFAllocatorDefault, textLine, kCFStringEncodingMacRoman));
232 if (!wrappedCString.Get())
233 throw std::runtime_error(
"TextLine: cstr wrapper");
235 CFScopeGuard<CFAttributedStringRef> attributedString(CFAttributedStringCreate(kCFAllocatorDefault,
236 wrappedCString.Get(), stringAttribs.Get()));
237 fCTLine = CTLineCreateWithAttributedString(attributedString.Get());
240 throw std::runtime_error(
"TextLine: attrib string");
244 void TextLine::Init(
const std::vector<UniChar> &unichars, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
246 using MacOSX::Util::CFScopeGuard;
248 const CFScopeGuard<CFStringRef> wrappedUniString(CFStringCreateWithCharacters(kCFAllocatorDefault, &unichars[0], unichars.size()));
249 const CFScopeGuard<CFDictionaryRef> stringAttribs(CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
250 nAttribs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
252 if (!stringAttribs.Get())
253 throw std::runtime_error(
"TextLine: null attribs");
255 if (!wrappedUniString.Get())
256 throw std::runtime_error(
"TextLine: cstr wrapper");
258 const CFScopeGuard<CFAttributedStringRef> attributedString(CFAttributedStringCreate(kCFAllocatorDefault,
259 wrappedUniString.Get(), stringAttribs.Get()));
260 fCTLine = CTLineCreateWithAttributedString(attributedString.Get());
263 throw std::runtime_error(
"TextLine: attrib string");
267 void TextLine::DrawLine(CGContextRef ctx)
const
269 assert(ctx != 0 &&
"DrawLine, ctx parameter is null");
270 CTLineDraw(fCTLine, ctx);
275 void TextLine::DrawLine(CGContextRef ctx, Double_t x, Double_t y)
const
277 assert(ctx != 0 &&
"DrawLine, ctx parameter is null");
279 CGContextSetAllowsAntialiasing(ctx, 1);
284 Double_t xc = 0., yc = 0.;
285 const UInt_t hAlign = UInt_t(gVirtualX->GetTextAlign() / 10);
297 const UInt_t vAlign = UInt_t(gVirtualX->GetTextAlign() % 10);
309 CGContextSetTextPosition(ctx, 0., 0.);
310 CGContextTranslateCTM(ctx, x, y);
311 CGContextRotateCTM(ctx, gVirtualX->GetTextAngle() * TMath::DegToRad());
312 CGContextTranslateCTM(ctx, xc, yc);
313 CGContextTranslateCTM(ctx, -0.5 * w, -0.5 * h);
319 void DrawTextLineNoKerning(CGContextRef ctx, CTFontRef font,
const std::vector<UniChar> &text, Int_t x, Int_t y)
321 typedef std::vector<CGSize>::size_type size_type;
326 assert(ctx != 0 &&
"DrawTextLineNoKerning, ctx parameter is null");
327 assert(font != 0 &&
"DrawTextLineNoKerning, font parameter is null");
328 assert(text.size() &&
"DrawTextLineNoKerning, text parameter is an empty vector");
330 std::vector<CGGlyph> glyphs(text.size());
331 if (!CTFontGetGlyphsForCharacters(font, &text[0], &glyphs[0], text.size())) {
332 ::Error(
"DrawTextLineNoKerning",
"Font could not encode all Unicode characters in a text");
336 std::vector<CGSize> glyphAdvances(glyphs.size());
337 CTFontGetAdvancesForGlyphs(font, horizontalFontOrientation, &glyphs[0], &glyphAdvances[0], glyphs.size());
339 CGFloat currentX = x;
340 std::vector<CGPoint> glyphPositions(glyphs.size());
341 glyphPositions[0].x = currentX;
342 glyphPositions[0].y = y;
344 for (size_type i = 1; i < glyphs.size(); ++i) {
345 currentX += std::ceil(glyphAdvances[i - 1].width);
346 glyphPositions[i].x = currentX;
347 glyphPositions[i].y = y;
350 CTFontDrawGlyphs(font, &glyphs[0], &glyphPositions[0], glyphs.size(), ctx);