Logo ROOT   6.16/01
Reference Guide
QuartzText.mm
Go to the documentation of this file.
1// @(#)root/graf2d:$Id$
2// Author: Timur Pocheptsov 26/01/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#include <stdexcept>
13#include <cassert>
14#include <vector>
15#include <cmath>
16
17#include <Availability.h>
18
19#include "QuartzText.h"
20#include "CocoaUtils.h"
21#include "TVirtualX.h"
22#include "TColor.h"
23#include "TError.h"
24#include "TROOT.h"
25#include "TMath.h"
26
27namespace ROOT {
28namespace Quartz {
29
30#ifdef MAC_OS_X_VERSION_10_11
31
32const CTFontOrientation defaultFontOrientation = kCTFontOrientationDefault;
33const CTFontOrientation horizontalFontOrientation = kCTFontOrientationHorizontal;
34const CTFontOrientation verticalFontOrientation = kCTFontOrientationVertical;
35
36#else
37// Constants deprecated starting from 10.11
38const CTFontOrientation defaultFontOrientation = kCTFontDefaultOrientation;
39const CTFontOrientation horizontalFontOrientation = kCTFontHorizontalOrientation;
40const CTFontOrientation verticalFontOrientation = kCTFontVerticalOrientation;
41
42#endif
43
44namespace {
45
46//______________________________________________________________________________
47void GetTextColorForIndex(Color_t colorIndex, Float_t &r, Float_t &g, Float_t &b, Float_t &a)
48{
49 if (const TColor * const color = gROOT->GetColor(colorIndex)) {
50 color->GetRGB(r, g, b);
51 a = color->GetAlpha();
52 }
53}
54
55//_________________________________________________________________
56CGRect BBoxForCTRun(CTFontRef font, CTRunRef run)
57{
58 assert(font != 0 && "BBoxForCTRun, parameter 'font' is null");
59 assert(run != 0 && "BBoxForCTRun, parameter 'run' is null");
60
61 CGRect bbox = {};
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);
67 }
68
69 return bbox;
70}
71
72}
73
74//_________________________________________________________________
75TextLine::TextLine(const char *textLine, CTFontRef font)
76 : fCTLine(0),
77 fCTFont(font)
78{
79 //Create attributed string with one attribue: the font.
80 CFStringRef keys[] = {kCTFontAttributeName};
81 CFTypeRef values[] = {font};
82
83 Init(textLine, 1, keys, values);
84}
85
86//_________________________________________________________________
87TextLine::TextLine(const std::vector<UniChar> &unichars, CTFontRef font)
88 : fCTLine(0),
89 fCTFont(font)
90
91{
92 //Create attributed string with one attribue: the font.
93 CFStringRef keys[] = {kCTFontAttributeName};
94 CFTypeRef values[] = {font};
95
96 Init(unichars, 1, keys, values);
97}
98
99//_________________________________________________________________
100TextLine::TextLine(const char *textLine, CTFontRef font, Color_t color)
101 : fCTLine(0),
102 fCTFont(font)
103{
104 //Create attributed string with font and color.
106
107 const CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
108 if (!rgbColorSpace.Get())
109 throw std::runtime_error("TextLine: color space");
110
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]};
114
115 const CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), cgRgba));
116 //Not clear from docs, if textColor.Get() can be 0.
117
118 CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
119 CFTypeRef values[] = {font, textColor.Get()};
120
121 Init(textLine, 2, keys, values);
122}
123
124//_________________________________________________________________
125TextLine::TextLine(const char *textLine, CTFontRef font, const CGFloat *rgb)
126 : fCTLine(0),
127 fCTFont(font)
128{
129 //Create attributed string with font and color.
131 CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
132
133 if (!rgbColorSpace.Get())
134 throw std::runtime_error("TexLine: color space is null");
135
136 CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), rgb));
137 //Not clear from docs, if textColor can be 0.
138
139 CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
140 CFTypeRef values[] = {font, textColor.Get()};
141
142 Init(textLine, 2, keys, values);
143}
144
145//_________________________________________________________________
146TextLine::TextLine(const std::vector<UniChar> &unichars, CTFontRef font, Color_t color)
147 : fCTLine(0),
148 fCTFont(font)
149{
150 //Create attributed string with font and color.
152
153 const CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
154 if (!rgbColorSpace.Get())
155 throw std::runtime_error("TextLine: color space");
156
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]};
160
161 const CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), cgRgba));
162 //Not clear from docs, if textColor.Get() can be 0.
163
164 CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
165 CFTypeRef values[] = {font, textColor.Get()};
166
167 Init(unichars, 2, keys, values);
168}
169
170
171//_________________________________________________________________
173{
174 CFRelease(fCTLine);
175}
176
177
178//_________________________________________________________________
180{
181 //The old 'fallback' version:
182 CGFloat ascent = 0., descent = 0., leading = 0.;
183 w = UInt_t(CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading));
184 h = UInt_t(ascent);// + descent + leading);
185}
186
187
188//_________________________________________________________________
190{
191 //The old 'fallback' version:
192 CGFloat ascent = 0., descent = 0., leading = 0.;
193 CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading);
194 asc = Int_t(ascent);
195 desc = Int_t(descent);
196 //The new 'experimental':
197 //with Core Text descent for a string '2' has some
198 //quite big value, making all TText to be way too high.
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))
204 return;
205
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))
210 return;
211 box = CGRectUnion(box, nextBox);
212 }
213
214 asc = Int_t(TMath::Ceil(box.size.height) + box.origin.y);
215 desc = Int_t(TMath::Abs(TMath::Floor(box.origin.y)));
216 }
217}
218
219
220//_________________________________________________________________
221void TextLine::Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
222{
224
225 //Strong reference must be replaced with scope guards.
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");
230
231 const CFScopeGuard<CFStringRef> wrappedCString(CFStringCreateWithCString(kCFAllocatorDefault, textLine, kCFStringEncodingMacRoman));
232 if (!wrappedCString.Get())
233 throw std::runtime_error("TextLine: cstr wrapper");
234
235 CFScopeGuard<CFAttributedStringRef> attributedString(CFAttributedStringCreate(kCFAllocatorDefault,
236 wrappedCString.Get(), stringAttribs.Get()));
237 fCTLine = CTLineCreateWithAttributedString(attributedString.Get());
238
239 if (!fCTLine)
240 throw std::runtime_error("TextLine: attrib string");
241}
242
243//_________________________________________________________________
244void TextLine::Init(const std::vector<UniChar> &unichars, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
245{
247
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));
251
252 if (!stringAttribs.Get())
253 throw std::runtime_error("TextLine: null attribs");
254
255 if (!wrappedUniString.Get())
256 throw std::runtime_error("TextLine: cstr wrapper");
257
258 const CFScopeGuard<CFAttributedStringRef> attributedString(CFAttributedStringCreate(kCFAllocatorDefault,
259 wrappedUniString.Get(), stringAttribs.Get()));
260 fCTLine = CTLineCreateWithAttributedString(attributedString.Get());
261
262 if (!fCTLine)
263 throw std::runtime_error("TextLine: attrib string");
264}
265
266//_________________________________________________________________
267void TextLine::DrawLine(CGContextRef ctx)const
268{
269 assert(ctx != 0 && "DrawLine, ctx parameter is null");
270 CTLineDraw(fCTLine, ctx);
271}
272
273
274//______________________________________________________________________________
275void TextLine::DrawLine(CGContextRef ctx, Double_t x, Double_t y)const
276{
277 assert(ctx != 0 && "DrawLine, ctx parameter is null");
278
279 CGContextSetAllowsAntialiasing(ctx, 1);
280 UInt_t w = 0, h = 0;
281
282 GetBounds(w, h);
283
284 Double_t xc = 0., yc = 0.;
285 const UInt_t hAlign = UInt_t(gVirtualX->GetTextAlign() / 10);
286 switch (hAlign) {
287 case 1:
288 xc = 0.5 * w;
289 break;
290 case 2:
291 break;
292 case 3:
293 xc = -0.5 * w;
294 break;
295 }
296
297 const UInt_t vAlign = UInt_t(gVirtualX->GetTextAlign() % 10);
298 switch (vAlign) {
299 case 1:
300 yc = 0.5 * h;
301 break;
302 case 2:
303 break;
304 case 3:
305 yc = -0.5 * h;
306 break;
307 }
308
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);
314
315 DrawLine(ctx);
316}
317
318//______________________________________________________________________________
319void DrawTextLineNoKerning(CGContextRef ctx, CTFontRef font, const std::vector<UniChar> &text, Int_t x, Int_t y)
320{
321 typedef std::vector<CGSize>::size_type size_type;
322
323 if (!text.size())//This can happen with ROOT's GUI.
324 return;
325
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");
329
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");
333 return;
334 }
335
336 std::vector<CGSize> glyphAdvances(glyphs.size());
337 CTFontGetAdvancesForGlyphs(font, horizontalFontOrientation, &glyphs[0], &glyphAdvances[0], glyphs.size());
338
339 CGFloat currentX = x;
340 std::vector<CGPoint> glyphPositions(glyphs.size());
341 glyphPositions[0].x = currentX;
342 glyphPositions[0].y = y;
343
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;
348 }
349
350 CTFontDrawGlyphs(font, &glyphs[0], &glyphPositions[0], glyphs.size(), ctx);
351}
352
353}//Quartz
354}//ROOT
ROOT::R::TRInterface & r
Definition: Object.C:4
#define b(i)
Definition: RSha256.hxx:100
#define g(i)
Definition: RSha256.hxx:105
#define h(i)
Definition: RSha256.hxx:106
#define e(i)
Definition: RSha256.hxx:103
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
double Double_t
Definition: RtypesCore.h:55
short Color_t
Definition: RtypesCore.h:79
float Float_t
Definition: RtypesCore.h:53
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
void Error(const char *location, const char *msgfmt,...)
double ceil(double)
#define gROOT
Definition: TROOT.h:410
#define gVirtualX
Definition: TVirtualX.h:345
void GetBounds(UInt_t &w, UInt_t &h) const
Definition: QuartzText.mm:179
void GetAscentDescent(Int_t &asc, Int_t &desc) const
Definition: QuartzText.mm:189
void Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
Definition: QuartzText.mm:221
TextLine(const char *textLine, CTFontRef font)
Definition: QuartzText.mm:75
void DrawLine(CGContextRef ctx) const
Definition: QuartzText.mm:267
The color creation and management class.
Definition: TColor.h:19
TText * text
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition: fillpatterns.C:1
Double_t y[n]
Definition: legend1.C:17
Double_t x[n]
Definition: legend1.C:17
const CTFontOrientation defaultFontOrientation
Definition: QuartzText.mm:38
void DrawTextLineNoKerning(CGContextRef ctx, CTFontRef font, const std::vector< UniChar > &text, Int_t x, Int_t y)
Definition: QuartzText.mm:319
const CTFontOrientation horizontalFontOrientation
Definition: QuartzText.mm:39
const CTFontOrientation verticalFontOrientation
Definition: QuartzText.mm:40
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Double_t Floor(Double_t x)
Definition: TMath.h:691
Double_t Ceil(Double_t x)
Definition: TMath.h:683
constexpr Double_t DegToRad()
Conversion from degree to radian:
Definition: TMath.h:82
Short_t Abs(Short_t d)
Definition: TMathBase.h:120
auto * a
Definition: textangle.C:12