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