1 /* grTCairo5.c -
2  *
3  * Copyright 2017 Open Circuit Design
4  *
5  *	Manipulate the programable cursor on the graphics display.
6  *
7  * Written by Chuan Chen
8  */
9 
10 #include <stdio.h>
11 #include <X11/Xlib.h>
12 
13 #include <cairo/cairo-xlib.h>
14 
15 #include "tcltk/tclmagic.h"
16 #include "utils/magic.h"
17 #include "utils/styles.h"
18 #include "utils/hash.h"
19 #include "textio/textio.h"
20 #include "utils/geometry.h"
21 #include "graphics/glyphs.h"
22 #include "windows/windows.h"
23 #include "graphics/graphics.h"
24 #include "graphics/graphicsInt.h"
25 #include "grTkCommon.h"
26 #include "grTCairoInt.h"
27 
28 extern Display	*grXdpy;
29 extern int	 grXscrn;
30 extern HashTable grTCairoWindowTable;
31 
32 
33 /*
34  * ----------------------------------------------------------------------------
35  * GrTCairoDrawGlyph --
36  *
37  *	Draw one glyph on the display.
38  *
39  * Results:
40  *	None.
41  *
42  * Side effects:
43  *	Draws pixels.
44  * ----------------------------------------------------------------------------
45  */
46 
47 void
GrTCairoDrawGlyph(gl,p)48 GrTCairoDrawGlyph (gl, p)
49 GrGlyph *gl;		/* A single glyph */
50 Point *p;			/* screen pos of lower left corner */
51 {
52 	Rect bBox;
53 	bool anyObscure;
54 	LinkedRect *ob;
55 	TCairoData *tcairodata = (TCairoData *)tcairoCurrent.mw->w_grdata2;
56 
57 	GR_CHECK_LOCK();
58 
59 	/* We're going to change the graphics state without affecting */
60 	/* the standard color and mask saved values, so we had better */
61 	/* flush all rects & lines first.				  */
62 	GR_TCAIRO_FLUSH_BATCH();
63 
64 	bBox.r_ll = *p;
65 	bBox.r_xtop = p->p_x + gl->gr_xsize - 1;
66 	bBox.r_ytop = p->p_y + gl->gr_ysize - 1;
67 
68 	anyObscure = FALSE;
69 	for (ob = grCurObscure; ob != NULL; ob = ob->r_next) {
70 		if (GEO_TOUCH( &(ob->r_r), &bBox)) {
71 			anyObscure = TRUE;
72 			break;
73 		}
74 	}
75 	if ((!anyObscure) && (GEO_SURROUND(&grCurClip, &bBox)) ) {
76 		int *pixelp, x, y, thisp, lastp;
77 		int color, red, green, blue, mask;
78 
79 		/* no clipping, try to go quickly */
80 		pixelp = gl->gr_pixels;
81 		thisp = -1;
82 		for (y = 0; y < gl->gr_ysize; y++) {
83 			int x1, y1;
84 
85 			y1 = bBox.r_ybot + y;
86 			for (x = 0; x < gl->gr_xsize; x++) {
87 				lastp = thisp;
88 				thisp = *pixelp++;
89 				if (thisp != 0)
90 				{
91 					/* Note: mask has traditionally been 0-127 */
92 					if (thisp != lastp) {
93 						if (lastp != -1) {
94 							cairo_fill(tcairodata->context);
95 						}
96 						mask = GrStyleTable[thisp].mask << 1;
97 						color = GrStyleTable[thisp].color;
98 						GrGetColor(color, &red, &green, &blue);
99 						cairo_set_source_rgba(tcairodata->context, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0));
100 					}
101 					x1 = bBox.r_xbot + x;
102 					cairo_rectangle(tcairodata->context, x1, y1, 1, 1);
103 				}
104 			}
105 		}
106 		if (lastp != -1) {
107 			cairo_fill(tcairodata->context);
108 		}
109 	} else {
110 		/* do pixel by pixel clipping */
111 		int y, yloc;
112 
113 		yloc = bBox.r_ybot;
114 		for (y = 0; y < gl->gr_ysize; y++) {
115 			int startx, endx;
116 			if ( (yloc <= grCurClip.r_ytop) && (yloc >= grCurClip.r_ybot) ) {
117 				int laststartx;
118 				laststartx = bBox.r_xbot - 1;
119 				for (startx = bBox.r_xbot; startx <= bBox.r_xtop;
120 				        startx = endx + 1) {
121 					int *pixelp;
122 
123 					startx = MAX(startx, grCurClip.r_xbot);
124 					endx = MIN(bBox.r_xtop, grCurClip.r_xtop);
125 
126 					if (anyObscure) {
127 						for (ob = grCurObscure; ob != NULL; ob = ob->r_next) {
128 							if ( (ob->r_r.r_ybot <= yloc) &&
129 							        (ob->r_r.r_ytop >= yloc) ) {
130 								if (ob->r_r.r_xbot <= startx)
131 									startx = MAX(startx, ob->r_r.r_xtop + 1);
132 								else if (ob->r_r.r_xbot <= endx)
133 									endx = MIN(endx, ob->r_r.r_xbot - 1);
134 							}
135 						}
136 					}
137 
138 					/* stop if we aren't advancing */
139 					if (startx == laststartx) break;
140 					laststartx = startx;
141 					if (startx > endx) continue;
142 
143 					/* draw a section of this scan line */
144 					pixelp = &( gl->gr_pixels[y * gl->gr_xsize +
145 					                          (startx - bBox.r_xbot)]);
146 					for ( ; startx <= endx; startx++) {
147 						int color, red, green, blue, mask;
148 						if (*pixelp != 0)
149 						{
150 							mask = GrStyleTable[*pixelp].mask << 1;
151 							color = GrStyleTable[*pixelp].color;
152 							GrGetColor(color, &red, &green, &blue);
153 							cairo_set_source_rgba(tcairodata->context, ((float)red / 255), ((float)green / 255), ((float)blue / 255), ((float)mask / 127.0));
154 
155 							cairo_rectangle(tcairodata->context, startx, yloc, 1, 1);
156 							cairo_fill(tcairodata->context);
157 						}
158 						pixelp++;
159 					}
160 					startx = endx + 1;
161 				}
162 			}
163 			yloc++;
164 		}
165 	}
166 }
167 
168 
169 /*
170  * ----------------------------------------------------------------------------
171  * GrTCairoSetCursor:
172  *
173  *	Make the cursor be a new pattern, as defined in the display styles file.
174  *
175  * Results:
176  *	None.
177  *
178  * Side effects:
179  *	When the cursor is turned back on it will take on the new pattern.
180  * ----------------------------------------------------------------------------
181  */
182 
183 void
GrTCairoSetCursor(cursorNum)184 GrTCairoSetCursor(cursorNum)
185 int cursorNum;	/* The cursor number as defined in the display
186 		         * styles file.
187 		         */
188 {
189 	HashEntry	*entry;
190 	HashSearch	hs;
191 	Tk_Window	tkwind;
192 
193 	if (cursorNum >= MAX_CURSORS)
194 	{
195 		TxError("No such cursor!\n");
196 		return;
197 	}
198 
199 	tcairoCurrent.cursor = grCursors[cursorNum];
200 
201 	HashStartSearch(&hs);
202 	while (entry = HashNext(&grTCairoWindowTable, &hs))
203 	{
204 		if (HashGetValue(entry))
205 		{
206 			tkwind = (Tk_Window)entry->h_key.h_ptr;
207 			Tk_DefineCursor(tkwind, tcairoCurrent.cursor);
208 		}
209 	}
210 }
211