Logo ROOT   6.12/07
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 
27 namespace ROOT {
28 namespace Quartz {
29 
30 #ifdef MAC_OS_X_VERSION_10_11
31 
32 const CTFontOrientation defaultFontOrientation = kCTFontOrientationDefault;
33 const CTFontOrientation horizontalFontOrientation = kCTFontOrientationHorizontal;
34 const CTFontOrientation verticalFontOrientation = kCTFontOrientationVertical;
35 
36 #else
37 // Constants deprecated starting from 10.11
38 const CTFontOrientation defaultFontOrientation = kCTFontDefaultOrientation;
39 const CTFontOrientation horizontalFontOrientation = kCTFontHorizontalOrientation;
40 const CTFontOrientation verticalFontOrientation = kCTFontVerticalOrientation;
41 
42 #endif
43 
44 namespace {
45 
46 //______________________________________________________________________________
47 void 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 //_________________________________________________________________
56 CGRect 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 //_________________________________________________________________
75 TextLine::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 //_________________________________________________________________
87 TextLine::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 //_________________________________________________________________
100 TextLine::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 //_________________________________________________________________
125 TextLine::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 //_________________________________________________________________
146 TextLine::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 //_________________________________________________________________
189 void TextLine::GetAscentDescent(Int_t &asc, Int_t &desc)const
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 //_________________________________________________________________
221 void 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 //_________________________________________________________________
244 void 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 //_________________________________________________________________
267 void TextLine::DrawLine(CGContextRef ctx)const
268 {
269  assert(ctx != 0 && "DrawLine, ctx parameter is null");
270  CTLineDraw(fCTLine, ctx);
271 }
272 
273 
274 //______________________________________________________________________________
275 void 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 //______________________________________________________________________________
319 void 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
void GetAscentDescent(Int_t &asc, Int_t &desc) const
Definition: QuartzText.mm:189
Double_t Floor(Double_t x)
Definition: TMath.h:599
void GetBounds(UInt_t &w, UInt_t &h) const
Definition: QuartzText.mm:179
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
float Float_t
Definition: RtypesCore.h:53
TH1 * h
Definition: legend2.C:5
#define gROOT
Definition: TROOT.h:402
int Int_t
Definition: RtypesCore.h:41
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition: fillpatterns.C:1
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
Double_t x[n]
Definition: legend1.C:17
const CTFontOrientation horizontalFontOrientation
Definition: QuartzText.mm:39
constexpr Double_t DegToRad()
Definition: TMath.h:64
const CTFontOrientation defaultFontOrientation
Definition: QuartzText.mm:38
short Color_t
Definition: RtypesCore.h:79
ROOT::R::TRInterface & r
Definition: Object.C:4
auto * a
Definition: textangle.C:12
unsigned int UInt_t
Definition: RtypesCore.h:42
#define gVirtualX
Definition: TVirtualX.h:350
TextLine(const char *textLine, CTFontRef font)
Definition: QuartzText.mm:75
double Double_t
Definition: RtypesCore.h:55
const CTFontOrientation verticalFontOrientation
Definition: QuartzText.mm:40
TText * text
Double_t y[n]
Definition: legend1.C:17
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
The color creation and management class.
Definition: TColor.h:19
double ceil(double)
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
Double_t Ceil(Double_t x)
Definition: TMath.h:593
void DrawLine(CGContextRef ctx) const
Definition: QuartzText.mm:267
void DrawTextLineNoKerning(CGContextRef ctx, CTFontRef font, const std::vector< UniChar > &text, Int_t x, Int_t y)
Definition: QuartzText.mm:319
void Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
Definition: QuartzText.mm:221
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.
static constexpr double g