PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/TeXmacs-1.0.7.11-src/src/Plugins/MacOS/cg_renderer.cpp

#
C++ | 618 lines | 464 code | 82 blank | 72 comment | 92 complexity | 5ffbfed37c018d7dcd04fb5fbcce9175 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /******************************************************************************
  2. * MODULE : cg_renderer.cpp
  3. * DESCRIPTION: CoreGraphics drawing interface class
  4. * COPYRIGHT : (C) 2008 Massimiliano Gubinelli
  5. *******************************************************************************
  6. * This software falls under the GNU general public license and comes WITHOUT
  7. * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
  8. * If you don't have this file, write to the Free Software Foundation, Inc.,
  9. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  10. ******************************************************************************/
  11. #include "cg_renderer.hpp"
  12. #include "analyze.hpp"
  13. #include "image_files.hpp"
  14. #include "file.hpp"
  15. #include "iterator.hpp"
  16. #include "gui.hpp" // for INTERRUPT_EVENT, INTERRUPTED_EVENT
  17. #include "font.hpp" // for the definition of font
  18. #include "Freetype/tt_file.hpp" // tt_font_find
  19. #include "mac_images.h"
  20. /******************************************************************************
  21. * CG images
  22. ******************************************************************************/
  23. struct cg_image_rep: concrete_struct {
  24. CGImageRef img;
  25. SI xo,yo;
  26. int w,h;
  27. cg_image_rep (CGImageRef img2, SI xo2, SI yo2, int w2, int h2) :
  28. img (img2), xo (xo2), yo (yo2), w (w2), h (h2) { CGImageRetain(img); };
  29. ~cg_image_rep() { CGImageRelease(img); };
  30. friend class cg_image;
  31. };
  32. class cg_image {
  33. CONCRETE_NULL(cg_image);
  34. cg_image (CGImageRef img2, SI xo2, SI yo2, int w2, int h2):
  35. rep (tm_new <cg_image_rep> (img2, xo2, yo2, w2, h2)) {}
  36. };
  37. CONCRETE_NULL_CODE(cg_image);
  38. /******************************************************************************
  39. * Global support variables for all cg_renderers
  40. ******************************************************************************/
  41. static hashmap<basic_character,cg_image> character_image; // bitmaps of all characters
  42. static hashmap<string,cg_image> images;
  43. /******************************************************************************
  44. * cg_renderer
  45. ******************************************************************************/
  46. void
  47. cg_set_color (CGContextRef cxt, color col) {
  48. int r, g, b, a;
  49. get_rgb_color (col, r, g, b, a);
  50. CGContextSetRGBFillColor(cxt, r/255.0, g/255.0, b/255.0, a/255.0);
  51. CGContextSetRGBStrokeColor(cxt, r/255.0, g/255.0, b/255.0, a/255.0);
  52. }
  53. cg_renderer_rep::cg_renderer_rep (int w2, int h2):
  54. basic_renderer_rep(w2,h2), context(NULL)
  55. {
  56. }
  57. cg_renderer_rep::~cg_renderer_rep () {
  58. if (context) end();
  59. }
  60. void
  61. cg_renderer_rep::begin (void * c) {
  62. context = (CGContextRef)c;
  63. CGContextRetain(context);
  64. CGContextBeginPage(context, NULL);
  65. }
  66. void
  67. cg_renderer_rep::end () {
  68. CGContextEndPage(context);
  69. CGContextRelease(context);
  70. context = NULL;
  71. }
  72. void
  73. cg_renderer_rep::next_page () {
  74. CGContextEndPage(context);
  75. CGContextBeginPage(context, NULL);
  76. }
  77. void
  78. cg_renderer_rep::set_color (color c) {
  79. basic_renderer_rep::set_color(c);
  80. cg_set_color(context,cur_fg);
  81. }
  82. void
  83. cg_renderer_rep::set_line_style (SI lw, int type, bool round) {
  84. (void) type;
  85. CGContextSetLineCap(context, round? kCGLineCapRound : kCGLineCapSquare);
  86. CGContextSetLineJoin(context, kCGLineJoinRound);
  87. CGContextSetLineWidth(context, lw <= pixel ? 1 : ((lw+thicken) / (1.0*pixel)));
  88. }
  89. void
  90. cg_renderer_rep::line (SI x1, SI y1, SI x2, SI y2) {
  91. decode (x1, y1);
  92. decode (x2, y2);
  93. // y1--; y2--; // top-left origin to bottom-left origin conversion
  94. CGContextSetShouldAntialias(context, true);
  95. CGPoint points[2]= { CGPointMake(x1,y1), CGPointMake(x2,y2) };
  96. CGContextStrokeLineSegments(context, points, 2);
  97. }
  98. void
  99. cg_renderer_rep::lines (array<SI> x, array<SI> y) {
  100. int i, n= N(x);
  101. if ((N(y) != n) || (n<1)) return;
  102. STACK_NEW_ARRAY (pnt, CGPoint, n);
  103. CGContextSetShouldAntialias(context, true);
  104. for (i=0; i<n; i++) {
  105. SI xx= x[i], yy= y[i];
  106. decode (xx, yy);
  107. pnt[i] = CGPointMake(xx,yy);
  108. if (i>0) {
  109. CGContextStrokeLineSegments(context, pnt + (i - 1), 2); // FIX: hack
  110. }
  111. }
  112. STACK_DELETE_ARRAY (pnt);
  113. }
  114. void
  115. cg_renderer_rep::clear (SI x1, SI y1, SI x2, SI y2) {
  116. x1= max (x1, cx1-ox); y1= max (y1, cy1-oy);
  117. x2= min (x2, cx2-ox); y2= min (y2, cy2-oy);
  118. // outer_round (x1, y1, x2, y2); might still be needed somewhere
  119. decode (x1, y1);
  120. decode (x2, y2);
  121. if ((x1>=x2) || (y1<=y2)) return;
  122. cg_set_color (context, cur_bg);
  123. CGContextSetShouldAntialias(context, false);
  124. CGContextFillRect(context, CGRectMake(x1, y2, x2-x1, y1-y2) );
  125. cg_set_color (context, cur_fg);
  126. }
  127. void
  128. cg_renderer_rep::fill (SI x1, SI y1, SI x2, SI y2) {
  129. if ((x2>x1) && ((x2-x1)<pixel)) {
  130. SI d= pixel-(x2-x1);
  131. x1 -= (d>>1);
  132. x2 += ((d+1)>>1);
  133. }
  134. if ((y2>y1) && ((y2-y1)<pixel)) {
  135. SI d= pixel-(y2-y1);
  136. y1 -= (d>>1);
  137. y2 += ((d+1)>>1);
  138. }
  139. x1= max (x1, cx1-ox); y1= max (y1, cy1-oy);
  140. x2= min (x2, cx2-ox); y2= min (y2, cy2-oy);
  141. // outer_round (x1, y1, x2, y2); might still be needed somewhere
  142. if ((x1>=x2) || (y1>=y2)) return;
  143. decode (x1, y1);
  144. decode (x2, y2);
  145. // cg_set_color (context, cur_fg);
  146. CGContextSetShouldAntialias (context, false);
  147. CGContextFillRect (context, CGRectMake(x1, y2, x2-x1, y1-y2) );
  148. }
  149. void
  150. cg_renderer_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
  151. (void) alpha; (void) delta;
  152. if ((x1>=x2) || (y1>=y2)) return;
  153. decode (x1, y1);
  154. decode (x2, y2);
  155. //FIXME: XDrawArc (dpy, win, gc, x1, y2, x2-x1, y1-y2, alpha, delta);
  156. }
  157. void
  158. cg_renderer_rep::fill_arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
  159. (void) alpha; (void) delta;
  160. if ((x1>=x2) || (y1>=y2)) return;
  161. decode (x1, y1);
  162. decode (x2, y2);
  163. //FIXME: XFillArc (dpy, win, gc, x1, y2, x2-x1, y1-y2, alpha, delta);
  164. }
  165. void
  166. cg_renderer_rep::polygon (array<SI> x, array<SI> y, bool convex) {
  167. int i, n= N(x);
  168. if ((N(y) != n) || (n<1)) return;
  169. CGContextBeginPath(context);
  170. for (i=0; i<n; i++) {
  171. SI xx= x[i], yy= y[i];
  172. decode (xx, yy);
  173. if (i==0) CGContextMoveToPoint (context, xx, yy);
  174. else CGContextAddLineToPoint(context, xx ,yy);
  175. }
  176. CGContextClosePath (context);
  177. // cg_set_color (context, cur_fg);
  178. CGContextSetShouldAntialias (context, true);
  179. if (convex) CGContextEOFillPath (context);
  180. else CGContextFillPath (context);
  181. }
  182. /******************************************************************************
  183. * Image rendering
  184. ******************************************************************************/
  185. struct cg_cache_image_rep: cache_image_element_rep {
  186. cg_cache_image_rep (int w2, int h2, time_t time2, CGImageRef ptr2) :
  187. cache_image_element_rep(w2,h2,time2,ptr2) { CGImageRetain((CGImageRef)ptr); };
  188. virtual ~cg_cache_image_rep() { CGImageRelease((CGImageRef)ptr); };
  189. };
  190. void
  191. cg_renderer_rep::image (url u, SI w, SI h, SI x, SI y,
  192. double cx1, double cy1, double cx2, double cy2,
  193. int alpha)
  194. {
  195. // Given an image of original size (W, H),
  196. // we display the part (cx1 * W, xy1 * H, cx2 * W, cy2 * H)
  197. // at position (x, y) in a rectangle of size (w, h)
  198. // if (DEBUG_EVENTS) cout << "cg_renderer_rep::image " << as_string(u) << LF;
  199. (void) alpha;
  200. w= w/pixel; h= h/pixel;
  201. decode (x, y);
  202. //painter.setRenderHints (0);
  203. //painter.drawRect (QRect (x, y-h, w, h));
  204. CGImageRef pm = NULL;
  205. tree lookup= tuple (u->t);
  206. lookup << as_string (w ) << as_string (h )
  207. << as_string (cx1) << as_string (cy1)
  208. << as_string (cx2) << as_string (cy2) << "cg-image" ;
  209. cache_image_element ci = get_image_cache(lookup);
  210. if (!is_nil(ci)) {
  211. pm = static_cast<CGImageRef> (ci->ptr);
  212. } else {
  213. if (suffix (u) == "png") {
  214. // rendering
  215. string suu = as_string (u);
  216. char * buf = as_charp(suu);
  217. // cout << suu << LF;
  218. CFURLRef uu = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)buf, N(suu), false);
  219. tm_delete (buf);
  220. CGImageSourceRef source = CGImageSourceCreateWithURL ( uu, NULL );
  221. pm = CGImageSourceCreateImageAtIndex(source, 0, NULL);
  222. CFRelease(source);
  223. CFRelease(uu);
  224. } else if (suffix (u) == "ps" ||
  225. suffix (u) == "eps" ||
  226. suffix (u) == "pdf") {
  227. url temp= url_temp (".png");
  228. // system ("convert", u, temp);
  229. mac_image_to_png (u, temp);
  230. string suu = as_string (temp);
  231. char * buf = as_charp(suu);
  232. //cout << suu << LF;
  233. CFURLRef uu = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)buf, N(suu), false);
  234. tm_delete (buf);
  235. CGImageSourceRef source = CGImageSourceCreateWithURL ( uu, NULL );
  236. pm = CGImageSourceCreateImageAtIndex(source, 0, NULL);
  237. CFRelease(source);
  238. CFRelease(uu);
  239. remove (temp);
  240. }
  241. if (pm == NULL ) {
  242. cout << "TeXmacs] warning: cannot render " << as_string (u) << "\n";
  243. return;
  244. }
  245. // caching
  246. ci = tm_new <cg_cache_image_rep> (w,h, texmacs_time(), pm);
  247. set_image_cache(lookup, ci);
  248. (ci->nr)++;
  249. }
  250. CGContextSetShouldAntialias(context, false);
  251. CGContextSaveGState(context);
  252. CGContextTranslateCTM(context, x,y);
  253. CGContextScaleCTM(context,1.0,-1.0);
  254. CGContextDrawImage(context, CGRectMake(0, 0, w, h), pm);
  255. CGContextRestoreGState(context);
  256. }
  257. void
  258. cg_renderer_rep::draw_clipped (CGImageRef im, int w, int h, SI x, SI y) {
  259. decode (x , y );
  260. y--; // top-left origin to bottom-left origin conversion
  261. // clear(x1,y1,x2,y2);
  262. CGContextSetShouldAntialias(context, true);
  263. // CGContextSetBlendMode(context,kCGBlendModeSourceAtop);
  264. CGContextDrawImage(context, CGRectMake(x,y,w,h), im);
  265. }
  266. static hashmap<string,pointer> native_fonts;
  267. static hashset<string> native_loaded;
  268. int
  269. posixStringToFSSpec(FSSpec *fss, CFStringRef posixPath, bool isDirectory) {
  270. FSRef fsRef;
  271. FSSpec fileSpec;
  272. // create a URL from the posix path:
  273. CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,posixPath,kCFURLPOSIXPathStyle,isDirectory);
  274. // check to be sure the URL was created properly:
  275. if (url == 0) {
  276. //fprintf(stderr,"Can't get URL");
  277. return(1);
  278. }
  279. // use the CF function to extract an FSRef from the URL:
  280. if (CFURLGetFSRef(url, &fsRef) == 0){
  281. //fprintf(stderr,"Can't get FSRef.\n");
  282. CFRelease(url);
  283. return(1);
  284. }
  285. // use Carbon call to get the FSSpec from the FSRef
  286. if (FSGetCatalogInfo (&fsRef, kFSCatInfoNone, 0, 0, &fileSpec, 0) != noErr) {
  287. //fprintf(stderr,"Can't get FSSpec.\n");
  288. CFRelease(url);
  289. return(1);
  290. }
  291. // We have a valid FSSpec! Clean up and return it:
  292. CFRelease(url);
  293. *fss = fileSpec;
  294. return 0;
  295. }
  296. bool
  297. cg_renderer_rep::native_draw (int ch, font_glyphs fn, SI x, SI y) {
  298. string name= fn->res_name;
  299. unsigned char c= ch;
  300. if (ch >= 256) {
  301. name= name * "-" * as_string (ch / 256);
  302. c= (unsigned char) (ch & 255);
  303. }
  304. // cout << name << LF;
  305. int size;
  306. {
  307. // find size (weird)
  308. int pos1 = search_forwards (".", name);
  309. int pos2= search_backwards (":", name);
  310. string sz = name(pos2+1,pos1);
  311. size = as_int(sz);
  312. }
  313. CGFontRef f = (CGFontRef)native_fonts(name);
  314. if ((f == NULL)&&(! native_loaded->contains(name))) {
  315. native_loaded->insert(name);
  316. string ttf;
  317. int pos = search_forwards (".", name);
  318. string root = (pos==-1? name: name (0, pos));
  319. if ((pos!=-1) && ends (name, "tt")) {
  320. int pos2= search_backwards (":", name);
  321. root= name (0, pos2);
  322. url u= tt_font_find (root);
  323. if (suffix (u) == "pfb") {
  324. // cout << u << LF;
  325. url v= url_temp (".otf");
  326. string vs = concretize(v);
  327. system ("/Users/mgubi/t/t1wrap/T1Wrap " * concretize(u) * " > " * vs);
  328. FSSpec fss;
  329. ATSFontRef atsFont;
  330. ATSFontContainerRef container;
  331. char *p = as_charp(vs);
  332. CFStringRef font_filename = CFStringCreateWithCString(NULL,p,kCFStringEncodingASCII);
  333. if (posixStringToFSSpec(&fss,font_filename,false)) {
  334. cout << "Cannot load font" << vs << LF;
  335. } else {
  336. int status = ATSFontActivateFromFileSpecification(&fss,kATSFontContextLocal,kATSFontFormatUnspecified,NULL,NULL,&container);
  337. cout << "Font " << vs << " loaded" << LF;
  338. ItemCount count;
  339. status = ATSFontFindFromContainer(container, 0, 1, &atsFont, &count);
  340. f = CGFontCreateWithPlatformFont((void*)&atsFont);
  341. native_fonts(name) = f;
  342. }
  343. tm_delete (p);
  344. CFRelease(font_filename);
  345. remove (v);
  346. }
  347. }
  348. } // end caching
  349. if (f) {
  350. decode (x , y );
  351. y--; // top-left origin to bottom-left origin conversion
  352. CGContextRef cgc = context;
  353. CGContextSetFont(cgc,f);
  354. CGContextSetFontSize(cgc,size);
  355. CGAffineTransform kHorizontalMatrix = { PIXEL*600.0/(pixel*72.0), 0.0, 0.0, -PIXEL*600.0/(pixel*72.0), 0.0, 0.0 };
  356. CGContextSetTextMatrix(cgc, kHorizontalMatrix);
  357. CGContextSetTextDrawingMode(cgc, kCGTextFill);
  358. CGContextSetShouldAntialias(cgc,true);
  359. CGContextSetShouldSmoothFonts(cgc,true);
  360. // CGContextSetBlendMode(context,kCGBlendModeSourceAtop);
  361. // cg_set_color (context, cur_fg);
  362. CGGlyph buf[1] = {c};
  363. CGContextShowGlyphsAtPoint(cgc,x,y,(CGGlyph*)buf,1);
  364. }
  365. return true;
  366. }
  367. CGContextRef
  368. MyCreateBitmapContext (int pixelsWide, int pixelsHigh) {
  369. int bitmapBytesPerRow = (pixelsWide * 4);
  370. int bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
  371. CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
  372. void *bitmapData = malloc( bitmapByteCount );
  373. if (bitmapData == NULL) {
  374. //fprintf (stderr, "Memory not allocated!");
  375. return NULL;
  376. }
  377. CGContextRef context = CGBitmapContextCreate (bitmapData, pixelsWide, pixelsHigh, 8,
  378. bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
  379. if (context == NULL) {
  380. free (bitmapData);
  381. // fprintf (stderr, "Context not created!");
  382. return NULL;
  383. }
  384. CGColorSpaceRelease (colorSpace);
  385. return context;
  386. }
  387. void
  388. cg_renderer_rep::draw (int c, font_glyphs fng, SI x, SI y) {
  389. // get the pixmap
  390. basic_character xc (c, fng, sfactor, 0, 0);
  391. cg_image mi = character_image [xc];
  392. if (is_nil(mi)) {
  393. SI xo, yo;
  394. glyph pre_gl= fng->get (c); if (is_nil (pre_gl)) return;
  395. glyph gl= shrink (pre_gl, sfactor, sfactor, xo, yo);
  396. int i, j, w= gl->width, h= gl->height;
  397. CGImageRef im = NULL;
  398. {
  399. CGContextRef ic = MyCreateBitmapContext(w,h);
  400. int nr_cols= sfactor*sfactor;
  401. if (nr_cols >= 64) nr_cols= 64;
  402. //CGContextSetShouldAntialias(ic,true);
  403. CGContextSetBlendMode(ic,kCGBlendModeCopy);
  404. //CGContextSetRGBFillColor(ic,1.0,1.0,1.0,0.0);
  405. //CGContextFillRect(ic,CGRectMake(0,0,w,h));
  406. for (j=0; j<h; j++)
  407. for (i=0; i<w; i++) {
  408. int col = gl->get_x (i, j);
  409. CGContextSetRGBFillColor(ic, 0.0,0.0,0.0, ((255*col)/(nr_cols+1))/255.0);
  410. CGContextFillRect(ic,CGRectMake(i,j,1,1));
  411. }
  412. im = CGBitmapContextCreateImage (ic);
  413. CGContextRelease (ic);
  414. }
  415. cg_image mi2 (im, xo, yo, w, h);
  416. mi = mi2;
  417. CGImageRelease(im); // cg_image retains im
  418. character_image (xc)= mi;
  419. }
  420. // draw the character
  421. {
  422. (void) w; (void) h;
  423. int x1= x- mi->xo*sfactor;
  424. int y1= y+ mi->yo*sfactor;
  425. decode (x1, y1);
  426. y1--; // top-left origin to bottom-left origin conversion
  427. CGRect r = CGRectMake(x1,y1,mi->w,mi->h);
  428. CGContextSetShouldAntialias (context, true);
  429. CGContextSaveGState (context);
  430. // cg_set_color (context, cur_fg);
  431. CGContextClipToMask (context, r, mi->img);
  432. CGContextFillRect (context, r);
  433. CGContextRestoreGState (context);
  434. }
  435. }
  436. /******************************************************************************
  437. * Setting up and displaying xpm pixmaps
  438. ******************************************************************************/
  439. static CGImageRef xpm_init(url file_name)
  440. {
  441. tree t= xpm_load (file_name);
  442. // get main info
  443. int ok, i=0, j, k, w, h, c, b, x, y;
  444. string s= as_string (t[0]);
  445. skip_spaces (s, i);
  446. ok= read_int (s, i, w);
  447. skip_spaces (s, i);
  448. ok= read_int (s, i, h) && ok;
  449. skip_spaces (s, i);
  450. ok= read_int (s, i, c) && ok;
  451. skip_spaces (s, i);
  452. ok= read_int (s, i, b) && ok;
  453. if ((!ok) || (N(t)<(c+1)) || (c<=0)) {
  454. cerr << "File name= " << file_name << "\n";
  455. FAILED ("invalid xpm");
  456. }
  457. // setup colors
  458. string first_name;
  459. hashmap<string,color> pmcs;
  460. for (k=0; k<c; k++) {
  461. string s = as_string (t[k+1]);
  462. string name= "";
  463. string def = "none";
  464. if (N(s)<b) i=N(s);
  465. else { name= s(0,b); i=b; }
  466. if (k==0) first_name= name;
  467. skip_spaces (s, i);
  468. if ((i<N(s)) && (s[i]=='s')) {
  469. i++;
  470. skip_spaces (s, i);
  471. while ((i<N(s)) && (s[i]!=' ') && (s[i]!='\t')) i++;
  472. skip_spaces (s, i);
  473. }
  474. if ((i<N(s)) && (s[i]=='c')) {
  475. i++;
  476. skip_spaces (s, i);
  477. j=i;
  478. while ((i<N(s)) && (s[i]!=' ') && (s[i]!='\t')) i++;
  479. def= locase_all (s (j, i));
  480. }
  481. pmcs(name)= xpm_to_color(def);
  482. }
  483. CGContextRef ic = MyCreateBitmapContext(w,h);
  484. CGContextSetBlendMode(ic,kCGBlendModeCopy);
  485. // setup pixmap
  486. for (y=0; y<h; y++) {
  487. if (N(t)< (y+c+1)) s= "";
  488. else s= as_string (t[y+c+1]);
  489. for (x=0; x<w; x++) {
  490. string name;
  491. if (N(s)<(b*(x+1))) name= first_name;
  492. else name= s (b*x, b*(x+1));
  493. color col = pmcs[(pmcs->contains (name) ? name : first_name)];
  494. cg_set_color (ic, col);
  495. CGContextFillRect (ic,CGRectMake(x,y,1,1));
  496. }
  497. }
  498. CGImageRef im = CGBitmapContextCreateImage (ic);
  499. CGContextRelease (ic);
  500. return im;
  501. }
  502. extern int char_clip;
  503. CGImageRef
  504. cg_renderer_rep::xpm_image (url file_name) {
  505. CGImageRef pxm= NULL;
  506. cg_image mi= images [as_string (file_name)];
  507. if (is_nil (mi)) {
  508. pxm = xpm_init(file_name);
  509. cg_image mi2 (pxm, 0, 0, CGImageGetWidth (pxm), CGImageGetHeight (pxm));
  510. mi= mi2;
  511. images (as_string (file_name))= mi2;
  512. CGImageRelease(pxm);
  513. } else pxm= mi->img;
  514. return pxm;
  515. }
  516. void
  517. cg_renderer_rep::xpm (url file_name, SI x, SI y) {
  518. y -= pixel; // counter balance shift in draw_clipped
  519. CGImageRef image = xpm_image (file_name);
  520. ASSERT (sfactor == 1, "shrinking factor should be 1");
  521. int w = CGImageGetWidth(image);
  522. int h = CGImageGetHeight(image);
  523. int old_clip= char_clip;
  524. char_clip = true;
  525. draw_clipped (image, w, h, x, y);
  526. char_clip = old_clip;
  527. }
  528. /******************************************************************************
  529. * main coregraphics renderer
  530. ******************************************************************************/
  531. static cg_renderer_rep* the_renderer= NULL;
  532. cg_renderer_rep*
  533. the_cg_renderer () {
  534. if (!the_renderer) the_renderer= tm_new <cg_renderer_rep> ();
  535. return the_renderer;
  536. }