Logo ROOT   6.08/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  //TODO: why don't I have asserts on parameters here?
80 
81  //Create attributed string with one attribue: the font.
82  CFStringRef keys[] = {kCTFontAttributeName};
83  CFTypeRef values[] = {font};
84 
85  Init(textLine, 1, keys, values);
86 }
87 
88 //_________________________________________________________________
89 TextLine::TextLine(const std::vector<UniChar> &unichars, CTFontRef font)
90  : fCTLine(0),
91  fCTFont(font)
92 
93 {
94  //TODO: why don't I have asserts on parameters here?
95 
96  //Create attributed string with one attribue: the font.
97  CFStringRef keys[] = {kCTFontAttributeName};
98  CFTypeRef values[] = {font};
99 
100  Init(unichars, 1, keys, values);
101 }
102 
103 //_________________________________________________________________
104 TextLine::TextLine(const char *textLine, CTFontRef font, Color_t color)
105  : fCTLine(0),
106  fCTFont(font)
107 {
108  //TODO: why don't I have asserts on parameters here?
109 
110  //Create attributed string with font and color.
112 
113  const CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
114  if (!rgbColorSpace.Get())
115  throw std::runtime_error("TextLine: color space");
116 
117  Float_t rgba[] = {0.f, 0.f, 0.f, 1.f};
118  GetTextColorForIndex(color, rgba[0], rgba[1], rgba[2], rgba[3]);
119  const CGFloat cgRgba[] = {rgba[0], rgba[1], rgba[2], rgba[3]};
120 
121  const CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), cgRgba));
122  //Not clear from docs, if textColor.Get() can be 0.
123 
124  CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
125  CFTypeRef values[] = {font, textColor.Get()};
126 
127  Init(textLine, 2, keys, values);
128 }
129 
130 //_________________________________________________________________
131 TextLine::TextLine(const char *textLine, CTFontRef font, const CGFloat *rgb)
132  : fCTLine(0),
133  fCTFont(font)
134 {
135  //TODO: why don't I have asserts on parameters here?
136 
137  //Create attributed string with font and color.
139  CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
140 
141  if (!rgbColorSpace.Get())
142  throw std::runtime_error("TexLine: color space is null");
143 
144  CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), rgb));
145  //Not clear from docs, if textColor can be 0.
146 
147  CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
148  CFTypeRef values[] = {font, textColor.Get()};
149 
150  Init(textLine, 2, keys, values);
151 }
152 
153 //_________________________________________________________________
154 TextLine::TextLine(const std::vector<UniChar> &unichars, CTFontRef font, Color_t color)
155  : fCTLine(0),
156  fCTFont(font)
157 {
158  //TODO: why don't I have asserts on parameters here?
159 
160  //Create attributed string with font and color.
161  //TODO: Make code more general, this constructor is copy&paste.
163 
164  const CFScopeGuard<CGColorSpaceRef> rgbColorSpace(CGColorSpaceCreateDeviceRGB());
165  if (!rgbColorSpace.Get())
166  throw std::runtime_error("TextLine: color space");
167 
168  Float_t rgba[] = {0.f, 0.f, 0.f, 1.f};
169  GetTextColorForIndex(color, rgba[0], rgba[1], rgba[2], rgba[3]);
170  const CGFloat cgRgba[] = {rgba[0], rgba[1], rgba[2], rgba[3]};
171 
172  const CFScopeGuard<CGColorRef> textColor(CGColorCreate(rgbColorSpace.Get(), cgRgba));
173  //Not clear from docs, if textColor.Get() can be 0.
174 
175  CFStringRef keys[] = {kCTFontAttributeName, kCTForegroundColorAttributeName};
176  CFTypeRef values[] = {font, textColor.Get()};
177 
178  Init(unichars, 2, keys, values);
179 }
180 
181 
182 //_________________________________________________________________
184 {
185  CFRelease(fCTLine);
186 }
187 
188 
189 //_________________________________________________________________
191 {
192  //The old 'fallback' version:
193  CGFloat ascent = 0., descent = 0., leading = 0.;
194  w = UInt_t(CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading));
195  h = UInt_t(ascent);// + descent + leading);
196 }
197 
198 
199 //_________________________________________________________________
200 void TextLine::GetAscentDescent(Int_t &asc, Int_t &desc)const
201 {
202  //The old 'fallback' version:
203  CGFloat ascent = 0., descent = 0., leading = 0.;
204  CTLineGetTypographicBounds(fCTLine, &ascent, &descent, &leading);
205  asc = Int_t(ascent);
206  desc = Int_t(descent);
207  //The new 'experimental':
208  //with Core Text descent for a string '2' has some
209  //quite big value, making all TText to be way too high.
210  CFArrayRef runs = CTLineGetGlyphRuns(fCTLine);
211  if (runs && CFArrayGetCount(runs) && fCTFont) {
212  CTRunRef firstRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runs, 0));
213  CGRect box = BBoxForCTRun(fCTFont, firstRun);
214  if (CGRectIsNull(box))
215  return;
216 
217  for (CFIndex i = 1, e = CFArrayGetCount(runs); i < e; ++i) {
218  CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runs, i));
219  CGRect nextBox = BBoxForCTRun(fCTFont, run);
220  if (CGRectIsNull(nextBox))
221  return;
222  box = CGRectUnion(box, nextBox);
223  }
224 
225  asc = Int_t(TMath::Ceil(box.size.height) + box.origin.y);
226  desc = Int_t(TMath::Abs(TMath::Floor(box.origin.y)));
227  }
228 }
229 
230 
231 //_________________________________________________________________
232 void TextLine::Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
233 {
235 
236  //Strong reference must be replaced with scope guards.
237  const CFScopeGuard<CFDictionaryRef> stringAttribs(CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
238  nAttribs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
239  if (!stringAttribs.Get())
240  throw std::runtime_error("TextLine: null attribs");
241 
242  const CFScopeGuard<CFStringRef> wrappedCString(CFStringCreateWithCString(kCFAllocatorDefault, textLine, kCFStringEncodingMacRoman));
243  if (!wrappedCString.Get())
244  throw std::runtime_error("TextLine: cstr wrapper");
245 
246  CFScopeGuard<CFAttributedStringRef> attributedString(CFAttributedStringCreate(kCFAllocatorDefault,
247  wrappedCString.Get(), stringAttribs.Get()));
248  fCTLine = CTLineCreateWithAttributedString(attributedString.Get());
249 
250  if (!fCTLine)
251  throw std::runtime_error("TextLine: attrib string");
252 }
253 
254 //_________________________________________________________________
255 void TextLine::Init(const std::vector<UniChar> &unichars, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
256 {
258 
259  const CFScopeGuard<CFStringRef> wrappedUniString(CFStringCreateWithCharacters(kCFAllocatorDefault, &unichars[0], unichars.size()));
260  const CFScopeGuard<CFDictionaryRef> stringAttribs(CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
261  nAttribs, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
262 
263  if (!stringAttribs.Get())
264  throw std::runtime_error("TextLine: null attribs");
265 
266  if (!wrappedUniString.Get())
267  throw std::runtime_error("TextLine: cstr wrapper");
268 
269  const CFScopeGuard<CFAttributedStringRef> attributedString(CFAttributedStringCreate(kCFAllocatorDefault,
270  wrappedUniString.Get(), stringAttribs.Get()));
271  fCTLine = CTLineCreateWithAttributedString(attributedString.Get());
272 
273  if (!fCTLine)
274  throw std::runtime_error("TextLine: attrib string");
275 }
276 
277 //_________________________________________________________________
278 void TextLine::DrawLine(CGContextRef ctx)const
279 {
280  assert(ctx != 0 && "DrawLine, ctx parameter is null");
281  CTLineDraw(fCTLine, ctx);
282 }
283 
284 
285 //______________________________________________________________________________
286 void TextLine::DrawLine(CGContextRef ctx, Double_t x, Double_t y)const
287 {
288  assert(ctx != 0 && "DrawLine, ctx parameter is null");
289 
290  CGContextSetAllowsAntialiasing(ctx, 1);
291  UInt_t w = 0, h = 0;
292 
293  GetBounds(w, h);
294 
295  Double_t xc = 0., yc = 0.;
296  const UInt_t hAlign = UInt_t(gVirtualX->GetTextAlign() / 10);
297  switch (hAlign) {
298  case 1:
299  xc = 0.5 * w;
300  break;
301  case 2:
302  break;
303  case 3:
304  xc = -0.5 * w;
305  break;
306  }
307 
308  const UInt_t vAlign = UInt_t(gVirtualX->GetTextAlign() % 10);
309  switch (vAlign) {
310  case 1:
311  yc = 0.5 * h;
312  break;
313  case 2:
314  break;
315  case 3:
316  yc = -0.5 * h;
317  break;
318  }
319 
320  CGContextSetTextPosition(ctx, 0., 0.);
321  CGContextTranslateCTM(ctx, x, y);
322  CGContextRotateCTM(ctx, gVirtualX->GetTextAngle() * TMath::DegToRad());
323  CGContextTranslateCTM(ctx, xc, yc);
324  CGContextTranslateCTM(ctx, -0.5 * w, -0.5 * h);
325 
326  DrawLine(ctx);
327 }
328 
329 //______________________________________________________________________________
330 void DrawTextLineNoKerning(CGContextRef ctx, CTFontRef font, const std::vector<UniChar> &text, Int_t x, Int_t y)
331 {
332  typedef std::vector<CGSize>::size_type size_type;
333 
334  if (!text.size())//This can happen with ROOT's GUI.
335  return;
336 
337  assert(ctx != 0 && "DrawTextLineNoKerning, ctx parameter is null");
338  assert(font != 0 && "DrawTextLineNoKerning, font parameter is null");
339  assert(text.size() && "DrawTextLineNoKerning, text parameter is an empty vector");
340 
341  std::vector<CGGlyph> glyphs(text.size());
342  if (!CTFontGetGlyphsForCharacters(font, &text[0], &glyphs[0], text.size())) {
343  ::Error("DrawTextLineNoKerning", "Font could not encode all Unicode characters in a text");
344  return;
345  }
346 
347  std::vector<CGSize> glyphAdvances(glyphs.size());
348  CTFontGetAdvancesForGlyphs(font, horizontalFontOrientation, &glyphs[0], &glyphAdvances[0], glyphs.size());
349 
350  CGFloat currentX = x;
351  std::vector<CGPoint> glyphPositions(glyphs.size());
352  glyphPositions[0].x = currentX;
353  glyphPositions[0].y = y;
354 
355  for (size_type i = 1; i < glyphs.size(); ++i) {
356  currentX += std::ceil(glyphAdvances[i - 1].width);
357  glyphPositions[i].x = currentX;
358  glyphPositions[i].y = y;
359  }
360 
361  CTFontDrawGlyphs(font, &glyphs[0], &glyphPositions[0], glyphs.size(), ctx);
362 }
363 
364 }//Quartz
365 }//ROOT
void GetAscentDescent(Int_t &asc, Int_t &desc) const
Definition: QuartzText.mm:200
Double_t Floor(Double_t x)
Definition: TMath.h:473
void GetBounds(UInt_t &w, UInt_t &h) const
Definition: QuartzText.mm:190
This namespace contains pre-defined functions to be used in conjuction with TExecutor::Map and TExecu...
Definition: StringConv.hxx:21
float Float_t
Definition: RtypesCore.h:53
Double_t DegToRad()
Definition: TMath.h:50
TH1 * h
Definition: legend2.C:5
#define gROOT
Definition: TROOT.h:364
int Int_t
Definition: RtypesCore.h:41
TArc * a
Definition: textangle.C:12
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:110
Double_t x[n]
Definition: legend1.C:17
const CTFontOrientation horizontalFontOrientation
Definition: QuartzText.mm:39
const CTFontOrientation defaultFontOrientation
Definition: QuartzText.mm:38
short Color_t
Definition: RtypesCore.h:79
TRandom2 r(17)
unsigned int UInt_t
Definition: RtypesCore.h:42
void run(bool only_compile=false)
Definition: run.C:1
#define gVirtualX
Definition: TVirtualX.h:362
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:23
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:467
void DrawLine(CGContextRef ctx) const
Definition: QuartzText.mm:278
void DrawTextLineNoKerning(CGContextRef ctx, CTFontRef font, const std::vector< UniChar > &text, Int_t x, Int_t y)
Definition: QuartzText.mm:330
void Init(const char *textLine, UInt_t nAttribs, CFStringRef *keys, CFTypeRef *values)
Definition: QuartzText.mm:232
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.