1 /*
2  * Copyright 2010 Ole Loots <ole@monochrom.net>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <assert.h>
20 #include <sys/types.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <limits.h>
24 #include <math.h>
25 #include <stdbool.h>
26 #include <mt_gem.h>
27 #include <mint/osbind.h>
28 
29 #include "utils/log.h"
30 #include "utils/utf8.h"
31 #include "utils/utils.h"
32 #include "netsurf/bitmap.h"
33 #include "netsurf/plotters.h"
34 #include "netsurf/mouse.h"
35 
36 #include "atari/gui.h"
37 #include "atari/osspec.h"
38 #include "atari/misc.h"
39 #include "atari/bitmap.h"
40 #include "utils/nsoption.h"
41 #include "atari/plot/eddi.h"
42 #include "atari/plot/fontplot.h"
43 #include "atari/plot/plot.h"
44 
45 void vq_scrninfo(VdiHdl handle, short *work_out);
46 
47 struct s_view {
48     short x;                /**< drawing (screen) offset x                */
49     short y;                /**< drawing (screen) offset y                */
50     short w;                /**< width of buffer, not in sync with vis_w  */
51     short h;                /**< height of buffer, not in sync with vis_w */
52     short vis_x;            /**< visible rectangle of the screen buffer   */
53     short vis_y;            /**< coords are relative to plot location     */
54     short vis_w;            /**< clipped to screen dimensions             */
55     short vis_h;            /**< visible width                            */
56     struct rect abs_clipping; /**< The toplevel clipping rectangle        */
57     struct rect clipping;   /**< actual clipping rectangle                */
58     float scale;
59 };
60 
61 /**
62  * Garbage collection of the snapshot routine
63  *
64  * this should be called after you are done with the data returned by
65  *  snapshot_create don't access the screenshot after you called this
66  *  function
67  */
68 static void snapshot_suspend(void);
69 
70 /**
71  * destroy memory used by screenshot
72  */
73 static void snapshot_destroy(void);
74 
75 #ifdef WITH_8BPP_SUPPORT
76 static unsigned short sys_pal[256][3]; /*RGB*/
77 static unsigned short pal[256][3];     /*RGB*/
78 static char rgb_lookup[256][4];
79 short web_std_colors[6] = {0, 51, 102, 153, 204, 255};
80 
81 unsigned short vdi_web_pal[216][3] = {
82     {0x000,0x000,0x000}, {0x0c8,0x000,0x000}, {0x190,0x000,0x000},
83     {0x258,0x000,0x000}, {0x320,0x000,0x000}, {0x3e8,0x000,0x000},
84     {0x000,0x0c8,0x000}, {0x0c8,0x0c8,0x000}, {0x190,0x0c8,0x000},
85     {0x258,0x0c8,0x000}, {0x320,0x0c8,0x000}, {0x3e8,0x0c8,0x000},
86     {0x000,0x190,0x000}, {0x0c8,0x190,0x000}, {0x190,0x190,0x000},
87     {0x258,0x190,0x000}, {0x320,0x190,0x000}, {0x3e8,0x190,0x000},
88     {0x000,0x258,0x000}, {0x0c8,0x258,0x000}, {0x190,0x258,0x000},
89     {0x258,0x258,0x000}, {0x320,0x258,0x000}, {0x3e8,0x258,0x000},
90     {0x000,0x320,0x000}, {0x0c8,0x320,0x000}, {0x190,0x320,0x000},
91     {0x258,0x320,0x000}, {0x320,0x320,0x000}, {0x3e8,0x320,0x000},
92     {0x000,0x3e8,0x000}, {0x0c8,0x3e8,0x000}, {0x190,0x3e8,0x000},
93     {0x258,0x3e8,0x000}, {0x320,0x3e8,0x000}, {0x3e8,0x3e8,0x000},
94     {0x000,0x000,0x0c8}, {0x0c8,0x000,0x0c8}, {0x190,0x000,0x0c8},
95     {0x258,0x000,0x0c8}, {0x320,0x000,0x0c8}, {0x3e8,0x000,0x0c8},
96     {0x000,0x0c8,0x0c8}, {0x0c8,0x0c8,0x0c8}, {0x190,0x0c8,0x0c8},
97     {0x258,0x0c8,0x0c8}, {0x320,0x0c8,0x0c8}, {0x3e8,0x0c8,0x0c8},
98     {0x000,0x190,0x0c8}, {0x0c8,0x190,0x0c8}, {0x190,0x190,0x0c8},
99     {0x258,0x190,0x0c8}, {0x320,0x190,0x0c8}, {0x3e8,0x190,0x0c8},
100     {0x000,0x258,0x0c8}, {0x0c8,0x258,0x0c8}, {0x190,0x258,0x0c8},
101     {0x258,0x258,0x0c8}, {0x320,0x258,0x0c8}, {0x3e8,0x258,0x0c8},
102     {0x000,0x320,0x0c8}, {0x0c8,0x320,0x0c8}, {0x190,0x320,0x0c8},
103     {0x258,0x320,0x0c8}, {0x320,0x320,0x0c8}, {0x3e8,0x320,0x0c8},
104     {0x000,0x3e8,0x0c8}, {0x0c8,0x3e8,0x0c8}, {0x190,0x3e8,0x0c8},
105     {0x258,0x3e8,0x0c8}, {0x320,0x3e8,0x0c8}, {0x3e8,0x3e8,0x0c8},
106     {0x000,0x000,0x190}, {0x0c8,0x000,0x190}, {0x190,0x000,0x190},
107     {0x258,0x000,0x190}, {0x320,0x000,0x190}, {0x3e8,0x000,0x190},
108     {0x000,0x0c8,0x190}, {0x0c8,0x0c8,0x190}, {0x190,0x0c8,0x190},
109     {0x258,0x0c8,0x190}, {0x320,0x0c8,0x190}, {0x3e8,0x0c8,0x190},
110     {0x000,0x190,0x190}, {0x0c8,0x190,0x190}, {0x190,0x190,0x190},
111     {0x258,0x190,0x190}, {0x320,0x190,0x190}, {0x3e8,0x190,0x190},
112     {0x000,0x258,0x190}, {0x0c8,0x258,0x190}, {0x190,0x258,0x190},
113     {0x258,0x258,0x190}, {0x320,0x258,0x190}, {0x3e8,0x258,0x190},
114     {0x000,0x320,0x190}, {0x0c8,0x320,0x190}, {0x190,0x320,0x190},
115     {0x258,0x320,0x190}, {0x320,0x320,0x190}, {0x3e8,0x320,0x190},
116     {0x000,0x3e8,0x190}, {0x0c8,0x3e8,0x190}, {0x190,0x3e8,0x190},
117     {0x258,0x3e8,0x190}, {0x320,0x3e8,0x190}, {0x3e8,0x3e8,0x190},
118     {0x000,0x000,0x258}, {0x0c8,0x000,0x258}, {0x190,0x000,0x258},
119     {0x258,0x000,0x258}, {0x320,0x000,0x258}, {0x3e8,0x000,0x258},
120     {0x000,0x0c8,0x258}, {0x0c8,0x0c8,0x258}, {0x190,0x0c8,0x258},
121     {0x258,0x0c8,0x258}, {0x320,0x0c8,0x258}, {0x3e8,0x0c8,0x258},
122     {0x000,0x190,0x258}, {0x0c8,0x190,0x258}, {0x190,0x190,0x258},
123     {0x258,0x190,0x258}, {0x320,0x190,0x258}, {0x3e8,0x190,0x258},
124     {0x000,0x258,0x258}, {0x0c8,0x258,0x258}, {0x190,0x258,0x258},
125     {0x258,0x258,0x258}, {0x320,0x258,0x258}, {0x3e8,0x258,0x258},
126     {0x000,0x320,0x258}, {0x0c8,0x320,0x258}, {0x190,0x320,0x258},
127     {0x258,0x320,0x258}, {0x320,0x320,0x258}, {0x3e8,0x320,0x258},
128     {0x000,0x3e8,0x258}, {0x0c8,0x3e8,0x258}, {0x190,0x3e8,0x258},
129     {0x258,0x3e8,0x258}, {0x320,0x3e8,0x258}, {0x3e8,0x3e8,0x258},
130     {0x000,0x000,0x320}, {0x0c8,0x000,0x320}, {0x190,0x000,0x320},
131     {0x258,0x000,0x320}, {0x320,0x000,0x320}, {0x3e8,0x000,0x320},
132     {0x000,0x0c8,0x320}, {0x0c8,0x0c8,0x320}, {0x190,0x0c8,0x320},
133     {0x258,0x0c8,0x320}, {0x320,0x0c8,0x320}, {0x3e8,0x0c8,0x320},
134     {0x000,0x190,0x320}, {0x0c8,0x190,0x320}, {0x190,0x190,0x320},
135     {0x258,0x190,0x320}, {0x320,0x190,0x320}, {0x3e8,0x190,0x320},
136     {0x000,0x258,0x320}, {0x0c8,0x258,0x320}, {0x190,0x258,0x320},
137     {0x258,0x258,0x320}, {0x320,0x258,0x320}, {0x3e8,0x258,0x320},
138     {0x000,0x320,0x320}, {0x0c8,0x320,0x320}, {0x190,0x320,0x320},
139     {0x258,0x320,0x320}, {0x320,0x320,0x320}, {0x3e8,0x320,0x320},
140     {0x000,0x3e8,0x320}, {0x0c8,0x3e8,0x320}, {0x190,0x3e8,0x320},
141     {0x258,0x3e8,0x320}, {0x320,0x3e8,0x320}, {0x3e8,0x3e8,0x320},
142     {0x000,0x000,0x3e8}, {0x0c8,0x000,0x3e8}, {0x190,0x000,0x3e8},
143     {0x258,0x000,0x3e8}, {0x320,0x000,0x3e8}, {0x3e8,0x000,0x3e8},
144     {0x000,0x0c8,0x3e8}, {0x0c8,0x0c8,0x3e8}, {0x190,0x0c8,0x3e8},
145     {0x258,0x0c8,0x3e8}, {0x320,0x0c8,0x3e8}, {0x3e8,0x0c8,0x3e8},
146     {0x000,0x190,0x3e8}, {0x0c8,0x190,0x3e8}, {0x190,0x190,0x3e8},
147     {0x258,0x190,0x3e8}, {0x320,0x190,0x3e8}, {0x3e8,0x190,0x3e8},
148     {0x000,0x258,0x3e8}, {0x0c8,0x258,0x3e8}, {0x190,0x258,0x3e8},
149     {0x258,0x258,0x3e8}, {0x320,0x258,0x3e8}, {0x3e8,0x258,0x3e8},
150     {0x000,0x320,0x3e8}, {0x0c8,0x320,0x3e8}, {0x190,0x320,0x3e8},
151     {0x258,0x320,0x3e8}, {0x320,0x320,0x3e8}, {0x3e8,0x320,0x3e8},
152     {0x000,0x3e8,0x3e8}, {0x0c8,0x3e8,0x3e8}, {0x190,0x3e8,0x3e8},
153     {0x258,0x3e8,0x3e8}, {0x320,0x3e8,0x3e8}, {0x3e8,0x3e8,0x3e8}
154 };
155 #endif
156 
157 /* Error code translations: */
158 static const char * plot_error_codes[] = {
159     "None",
160     "ERR_BUFFERSIZE_EXCEEDS_SCREEN",
161     "ERR_NO_MEM",
162     "ERR_PLOTTER_NOT_AVAILABLE"
163 };
164 
165 FONT_PLOTTER fplotter = NULL;
166 
167 extern short vdih;
168 
169 /* temp buffer for bitmap conversion: */
170 static void * buf_packed;
171 static int size_buf_packed;
172 
173 /* temp buffer for bitmap conversion: */
174 void * buf_planar;
175 int size_buf_planar;
176 
177 /* buffer for plot operations that require device format, */
178 /* currently used for transparent mfdb blits and snapshots: */
179 static MFDB buf_scr;
180 static int size_buf_scr;
181 
182 /* buffer for std form, used during 8bpp snapshot */
183 MFDB buf_std;
184 int size_buf_std;
185 
186 struct bitmap * buf_scr_compat;
187 
188 /* intermediate bitmap format */
189 static HermesFormat vfmt;
190 
191 /* no screen format here, hermes may not suitable for it */
192 
193 /* netsurf source bitmap format */
194 static HermesFormat nsfmt;
195 
196 struct s_vdi_sysinfo vdi_sysinfo;
197 /* bit depth of framebuffers: */
198 static int atari_plot_bpp_virt;
199 static struct s_view view;
200 
201 //static HermesHandle hermes_pal_h; /* hermes palette handle */
202 static HermesHandle hermes_cnv_h; /* hermes converter instance handle */
203 static HermesHandle hermes_res_h;
204 
205 //static short prev_vdi_clip[4];
206 static struct bitmap snapshot;
207 
208 VdiHdl atari_plot_vdi_handle = -1;
209 unsigned long atari_plot_flags;
210 unsigned long atari_font_flags;
211 
212 typedef bool (*bitmap_convert_fnc)(struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out  );
213 static bitmap_convert_fnc bitmap_convert;
214 
215 /* exported interface documented in atari/plot.h */
plot_err_str(int i)216 const char* plot_err_str(int i)
217 {
218     return (plot_error_codes[abs(i)]);
219 }
220 
221 
222 /**
223  * Set line drawing color by passing netsurf XBGR "colour" type.
224  *
225  * \param vdih The vdi handle
226  * \param cin  The netsurf colour value
227  */
vsl_rgbcolor(short vdih,colour cin)228 inline static void vsl_rgbcolor(short vdih, colour cin)
229 {
230 #ifdef WITH_8BPP_SUPPORT
231     if( vdi_sysinfo.scr_bpp > 8 ) {
232 #endif
233 	RGB1000 c; /* a struct with three (RGB) shorts */
234 	rgb_to_vdi1000( (unsigned char*)&cin, &c);
235 	vs_color(vdih, OFFSET_CUSTOM_COLOR, (short *)&c);
236 	vsl_color(vdih, OFFSET_CUSTOM_COLOR);
237 #ifdef WITH_8BPP_SUPPORT
238     } else {
239 	if( vdi_sysinfo.scr_bpp >= 4 ){
240 	    vsl_color(vdih, RGB_TO_VDI(cin));
241 	}
242 	else
243 	    vsl_color(vdih, BLACK);
244     }
245 #endif
246 }
247 
248 
249 /**
250  * Set fill color by passing netsurf XBGR "colour" type.
251  *
252  * \param vdih The vdi handle
253  * \param cin  The netsurf colour value
254  */
vsf_rgbcolor(short vdih,colour cin)255 inline static void vsf_rgbcolor(short vdih, colour cin)
256 {
257 #ifdef WITH_8BPP_SUPPORT
258     if( vdi_sysinfo.scr_bpp > 8 ) {
259 #endif
260 	RGB1000 c; /* a struct with three (RGB) shorts */
261 	rgb_to_vdi1000( (unsigned char*)&cin, &c);
262 	vs_color( vdih, OFFSET_CUSTOM_COLOR, (short *)&c);
263 	vsf_color( vdih, OFFSET_CUSTOM_COLOR );
264 #ifdef WITH_8BPP_SUPPORT
265     } else {
266 	if( vdi_sysinfo.scr_bpp >= 4 ){
267 	    vsf_color( vdih, RGB_TO_VDI(cin) );
268 	}
269 	else
270 	    vsf_color( vdih, WHITE );
271     }
272 #endif
273 }
274 
275 
276 /**
277  * Get current visible coords
278  */
plot_get_visible_grect(GRECT * out)279 inline static void plot_get_visible_grect(GRECT * out)
280 {
281     out->g_x = view.vis_x;
282     out->g_y = view.vis_y;
283     out->g_w = view.vis_w;
284     out->g_h = view.vis_h;
285 }
286 
287 
288 /* calculate visible area of framebuffer in coords relative to framebuffer */
289 /* position                                                                */
290 /*  result:                                                                */
291 /* this function should calculates an rectangle relative to the plot origin*/
292 /*  and size.                                                              */
293 /*      If the ploter coords do not fall within the screen region,         */
294 /*      all values of the region are set to zero.                          */
update_visible_rect(void)295 inline static void update_visible_rect(void)
296 {
297     GRECT screen;           // dimensions of the screen
298     GRECT frame;            // dimensions of the drawing area
299     GRECT common;           // dimensions of intersection of both
300 
301     screen.g_x = 0;
302     screen.g_y = 0;
303     screen.g_w = vdi_sysinfo.scr_w;
304     screen.g_h = vdi_sysinfo.scr_h;
305 
306     common.g_x = frame.g_x = view.x;
307     common.g_y = frame.g_y = view.y;
308     common.g_w = frame.g_w = view.w;
309     common.g_h = frame.g_h = view.h;
310 
311     if (rc_intersect(&screen, &common)) {
312 	view.vis_w = common.g_w;
313 	view.vis_h = common.g_h;
314 	if (view.x < screen.g_x)
315 	    view.vis_x = frame.g_w - common.g_w;
316 	else
317 	    view.vis_x = 0;
318 	if (view.y <screen.g_y)
319 	    view.vis_y = frame.g_h - common.g_h;
320 	else
321 	    view.vis_y = 0;
322     } else {
323 	view.vis_w = view.vis_h = 0;
324 	view.vis_x = view.vis_y = 0;
325     }
326 }
327 
328 
329 /**
330  * Returns the visible parts of the box
331  *
332  * The returned values are relative coords within framebuffer,
333  * relative to screen coords (normally starting at 0,0 )
334  */
fbrect_to_screen(GRECT box,GRECT * ret)335 inline static bool fbrect_to_screen(GRECT box, GRECT * ret)
336 {
337     GRECT out, vis, screen;
338 
339     screen.g_x = 0;
340     screen.g_y = 0;
341     screen.g_w = vdi_sysinfo.scr_w;
342     screen.g_h = vdi_sysinfo.scr_h;
343 
344     /* get visible region: */
345     vis.g_x = view.x;
346     vis.g_y = view.y;
347     vis.g_w = view.w;
348     vis.g_h = view.h;
349 
350     if ( !rc_intersect( &screen, &vis ) ) {
351 	return( false );
352     }
353     vis.g_x = view.w - vis.g_w;
354     vis.g_y = view.h - vis.g_h;
355 
356     /* clip box to visible region: */
357     if( !rc_intersect(&vis, &box) ) {
358 	return( false );
359     }
360     out.g_x = box.g_x + view.x;
361     out.g_y = box.g_y + view.y;
362     out.g_w = box.g_w;
363     out.g_h = box.g_h;
364     *ret = out;
365     return ( true );
366 }
367 
368 
369 /**
370  * copy an rectangle from the plot buffer to screen
371  *
372  * because this is an on-screen plotter, this is an screen to screen copy.
373  */
plot_copy_rect(GRECT src,GRECT dst)374 bool plot_copy_rect(GRECT src, GRECT dst)
375 {
376     MFDB devmf;
377     MFDB scrmf;
378     short pxy[8];
379     GRECT vis;
380 
381     /* clip to visible rect, only needed for onscreen renderer: */
382     plot_get_visible_grect(&vis );
383 
384     if( !rc_intersect(&vis, &src) )
385 	return(true);
386     if( !rc_intersect(&vis, &dst) )
387 	return(true);
388 
389     src.g_x = view.x + src.g_x;
390     src.g_y = view.y + src.g_y;
391     dst.g_x = view.x + dst.g_x;
392     dst.g_y = view.y + dst.g_y;
393 
394     devmf.fd_addr = NULL;
395     devmf.fd_w = src.g_w;
396     devmf.fd_h = src.g_h;
397     devmf.fd_wdwidth = 0;
398     devmf.fd_stand = 0;
399     devmf.fd_nplanes = 0;
400     devmf.fd_r1 = devmf.fd_r2 = devmf.fd_r3 = 0;
401 
402     scrmf.fd_addr = NULL;
403     scrmf.fd_w = dst.g_w;
404     scrmf.fd_h = dst.g_h;
405     scrmf.fd_wdwidth = 0 ;
406     scrmf.fd_stand = 0;
407     scrmf.fd_nplanes = 0;
408     scrmf.fd_r1 = scrmf.fd_r2 = scrmf.fd_r3 = 0;
409 
410     pxy[0] = src.g_x;
411     pxy[1] = src.g_y;
412     pxy[2] = pxy[0] + src.g_w-1;
413     pxy[3] = pxy[1] + src.g_h-1;
414     pxy[4] = dst.g_x;
415     pxy[5] = dst.g_y;
416     pxy[6] = pxy[4] + dst.g_w-1;
417     pxy[7] = pxy[5] + dst.g_h-1;
418     plot_lock();
419     vro_cpyfm( atari_plot_vdi_handle, S_ONLY, (short*)&pxy, &devmf,  &scrmf);
420     plot_unlock();
421 
422     return(true);
423 }
424 
425 
426 /**
427  * Fill the screen info structure.
428  *
429  * \param vdih The handle
430  * \param[out] info The infor structure to fill.
431  */
read_vdi_sysinfo(short vdih,struct s_vdi_sysinfo * info)432 static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info)
433 {
434     /** \todo this long is being cast to a pointer */
435     unsigned long cookie_EdDI=0;
436     short out[300];
437     memset( info, 0, sizeof(struct s_vdi_sysinfo) );
438 
439     info->vdi_handle = vdih;
440     if ( tos_getcookie(C_EdDI, (long *)&cookie_EdDI) == C_NOTFOUND ) {
441 	info->EdDiVersion = 0;
442     } else {
443 	info->EdDiVersion = EdDI_version( (void *)cookie_EdDI );
444     }
445 
446     memset( &out, 0, sizeof(short)*300 );
447     vq_extnd( vdih, 0, (short*)&out );
448     info->scr_w = out[0]+1;
449     info->scr_h = out[1]+1;
450     if( out[39] == 2 ) {
451 	info->scr_bpp = 1;
452 	info->colors = out[39];
453     } else {
454 	info->colors = out[39];
455     }
456 
457     memset( &out, 0, sizeof(short)*300 );
458     vq_extnd( vdih, 1, (short*)&out );
459     info->scr_bpp = out[4];
460     info->maxpolycoords = out[14];
461     info->maxintin = out[15];
462     if( out[30] & 1 ) {
463 	info->rasterscale = true;
464     } else {
465 	info->rasterscale = false;
466     }
467 
468     switch( info->scr_bpp ) {
469     case 8:
470 	info->pixelsize=1;
471 	break;
472     case 15:
473     case 16:
474 	info->pixelsize=2;
475 	break;
476     case 24:
477 	info->pixelsize=3;
478 	break;
479     case 32:
480 	info->pixelsize=4;
481 	break;
482     case 64:
483 	info->pixelsize=8;
484 	break;
485     default:
486 	info->pixelsize=1;
487 	break;
488 
489     }
490     info->pitch = info->scr_w * info->pixelsize;
491     info->vdiformat = ( (info->scr_bpp <= 8) ? VDI_FORMAT_INTER : VDI_FORMAT_PACK);
492     info->screensize = ( info->scr_w * info->pixelsize )  * info->scr_h;
493 
494     if( info->EdDiVersion >= EDDI_10 ) {
495 	memset( &out, 0, sizeof(short)*300 );
496 	vq_scrninfo(vdih, (short*)&out);
497 	info->vdiformat = out[0];
498 	info->clut = out[1];
499 	info->scr_bpp = out[2];
500 	info->hicolors =  *((unsigned long*) &out[3]);
501 	if( info->EdDiVersion >= EDDI_11 ) {
502 	    info->pitch = out[5];
503 	    info->screen = (void *) *((unsigned long *) &out[6]);
504 	}
505 
506 	switch( info->clut ) {
507 
508 	case VDI_CLUT_HARDWARE:
509 	    break;
510 
511 	case VDI_CLUT_SOFTWARE:
512 	{
513 	    int component; /* red, green, blue, alpha, overlay */
514 	    int num_bit;
515 	    unsigned short *tmp_p;
516 
517 	    /* We can build masks with info here */
518 	    tmp_p = (unsigned short *) &out[16];
519 	    for (component=0; component<5; component++) {
520 		for (num_bit=0; num_bit<16; num_bit++) {
521 		    unsigned short val;
522 
523 		    val = *tmp_p++;
524 
525 		    if (val == 0xffff) {
526 			continue;
527 		    }
528 
529 		    switch(component) {
530 		    case 0:
531 			info->mask_r |= 1<< val;
532 			break;
533 		    case 1:
534 			info->mask_g |= 1<< val;
535 			break;
536 		    case 2:
537 			info->mask_b |= 1<< val;
538 			break;
539 		    case 3:
540 			info->mask_a |= 1<< val;
541 			break;
542 		    }
543 		}
544 	    }
545 	}
546 
547 	/* Remove lower green bits for Intel endian screen */
548 	if ((info->mask_g == ((7<<13)|3)) ||
549 	    (info->mask_g == ((7<<13)|7))) {
550 	    info->mask_g &= ~(7<<13);
551 	}
552 	break;
553 
554 	case VDI_CLUT_NONE:
555 	    break;
556 	}
557     }
558 }
559 
560 
561 /**
562  *  Convert an RGB color to an VDI Color
563  */
rgb_to_vdi1000(unsigned char * in,RGB1000 * out)564 inline void rgb_to_vdi1000(unsigned char * in, RGB1000 *out)
565 {
566     double r = ((double)in[3]/255); /* prozentsatz red   */
567     double g = ((double)in[2]/255); /* prozentsatz green */
568     double b = ((double)in[1]/255); /* prozentsatz blue  */
569     out->red = 1000 * r + 0.5;
570     out->green = 1000 * g + 0.5;
571     out->blue = 1000 * b + 0.5;
572     return;
573 }
574 
575 
vdi1000_to_rgb(unsigned short * in,unsigned char * out)576 inline void vdi1000_to_rgb(unsigned short * in, unsigned char * out)
577 {
578     double r = ((double)in[0]/1000); /* prozentsatz red   */
579     double g = ((double)in[1]/1000); /* prozentsatz green */
580     double b = ((double)in[2]/1000); /* prozentsatz blue  */
581     out[2] = 255 * r + 0.5;
582     out[1] = 255 * g + 0.5;
583     out[0] = 255 * b + 0.5;
584     return;
585 }
586 
587 
588 #ifdef WITH_8BPP_SUPPORT
589 /**
590  * Set pixel within an 8 bit VDI standard bitmap.
591  */
592 inline static void
set_stdpx(MFDB * dst,int wdplanesz,int x,int y,unsigned char val)593 set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val )
594 {
595     short * buf;
596     short whichbit = (1<<(15-(x%16)));
597 
598     buf = dst->fd_addr;
599     buf += ((dst->fd_wdwidth*(y))+(x>>4));
600 
601     *buf = (val&1) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
602 
603     buf += wdplanesz;
604     *buf = (val&(1<<1)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
605 
606     buf += wdplanesz;
607     *buf = (val&(1<<2)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
608 
609     buf += wdplanesz;
610     *buf = (val&(1<<3)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
611 
612     buf += wdplanesz;
613     *buf = (val&(1<<4)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
614 
615     buf += wdplanesz;
616     *buf = (val&(1<<5)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
617 
618     buf += wdplanesz;
619     *buf = (val&(1<<6)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
620 
621     buf += wdplanesz;
622     *buf = (val&(1<<7)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit));
623 }
624 
625 
626 /**
627  * Read pixel from an 8 bit VDI standard bitmap.
628  */
get_stdpx(MFDB * dst,int wdplanesz,int x,int y)629 inline static unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y)
630 {
631     unsigned char ret=0;
632     short * buf;
633     short whichbit = (1<<(15-(x%16)));
634 
635     buf = dst->fd_addr;
636     buf += ((dst->fd_wdwidth*(y))+(x>>4));
637 
638     if( *buf & whichbit )
639 	ret |= 1;
640 
641     buf += wdplanesz;
642     if( *buf & whichbit )
643 	ret |= 2;
644 
645     buf += wdplanesz;
646     if( *buf & whichbit )
647 	ret |= 4;
648 
649     buf += wdplanesz;
650     if( *buf & whichbit )
651 	ret |= 8;
652 
653     buf += wdplanesz;
654     if( *buf & whichbit )
655 	ret |= 16;
656 
657     buf += wdplanesz;
658     if( *buf & whichbit )
659 	ret |= 32;
660 
661     buf += wdplanesz;
662     if( *buf & whichbit )
663 	ret |= 64;
664 
665     buf += wdplanesz;
666     if( *buf & whichbit )
667 	ret |= 128;
668 
669     return( ret );
670 }
671 
672 /**
673  * Convert an RGB color into an index into the 216 colors web pallette
674  */
rgb_to_666_index(unsigned char r,unsigned char g,unsigned char b)675 inline short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b)
676 {
677     short i;
678     unsigned char rgb[3] = {r,g,b};
679     unsigned char tval[3];
680 
681     int diff_a, diff_b, diff_c;
682     diff_a = abs(r-g);
683     diff_b = abs(r-b);
684     diff_c = abs(r-b);
685     if( diff_a < 2 && diff_b < 2 && diff_c < 2 ) {
686 	if( (r!=0XFF) && (g!=0XFF) && (b!=0XFF)  ) {
687 	    if( ((r&0xF0)>>4) != 0 )
688 		//printf("conv gray: %x -> %d\n", ((r&0xF0)>>4) , (OFFSET_CUST_PAL) + ((r&0xF0)>>4) );
689 		return( (OFFSET_CUST_PAL - OFFSET_WEB_PAL) + ((r&0xF0)>>4) );
690 	}
691     }
692 
693     /* convert each 8bit color to 6bit web color: */
694     for( i=0; i<3; i++) {
695 	if(0 == rgb[i] % web_std_colors[1] ) {
696 	    tval[i] = rgb[i] / web_std_colors[1];
697 	} else {
698 	    int pos = ((short)rgb[i] / web_std_colors[1]);
699 	    if( abs(rgb[i] - web_std_colors[pos]) > abs(rgb[i] - web_std_colors[pos+1]) )
700 		tval[i] = pos+1;
701 	    else
702 		tval[i] = pos;
703 	}
704     }
705     return(tval[2]*36+tval[1]*6+tval[0]);
706 }
707 #endif
708 
709 
dump_vdi_info(short vdih)710 static void dump_vdi_info(short vdih)
711 {
712     struct s_vdi_sysinfo temp;
713     read_vdi_sysinfo( vdih, &temp );
714     printf("struct s_vdi_sysinfo {\n");
715     printf("        short vdi_handle: %d\n", temp.vdi_handle);
716     printf("        short scr_w: %d \n", temp.scr_w);
717     printf("        short scr_h: %d\n", temp.scr_h);
718     printf("        short scr_bpp: %d\n", temp.scr_bpp);
719     printf("        int colors: %d\n", temp.colors);
720     printf("        ulong hicolors: %lu\n", temp.hicolors);
721     printf("        short pixelsize: %d\n", temp.pixelsize);
722     printf("        unsigned short pitch: %d\n", temp.pitch);
723     printf("        unsigned short vdiformat: %d\n", temp.vdiformat);
724     printf("        unsigned short clut: %d\n", temp.clut);
725     printf("        void * screen: 0x0%p\n", temp.screen);
726     printf("        unsigned long  screensize: %lu\n", temp.screensize);
727     printf("        unsigned long  mask_r: 0x0%08lx\n", temp.mask_r);
728     printf("        unsigned long  mask_g: 0x0%08lx\n", temp.mask_g);
729     printf("        unsigned long  mask_b: 0x0%08lx\n", temp.mask_b);
730     printf("        unsigned long  mask_a: 0x0%08lx\n", temp.mask_a);
731     printf("        short maxintin: %d\n", temp.maxintin);
732     printf("        short maxpolycoords: %d\n", temp.maxpolycoords);
733     printf("        unsigned long EdDiVersion: 0x0%03lx\n", temp.EdDiVersion);
734     printf("        unsigned short rasterscale: 0x%2x\n", temp.rasterscale);
735     printf("};\n");
736 }
737 
738 
739 /**
740  * Create an snapshot of the screen image in device format.
741  */
snapshot_create_native_mfdb(int x,int y,int w,int h)742 static MFDB * snapshot_create_native_mfdb(int x, int y, int w, int h)
743 {
744     MFDB scr;
745     short pxy[8];
746 
747     /* allocate memory for the snapshot */
748     {
749 	int scr_stride = MFDB_STRIDE( w );
750 	int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
751 	if(size_buf_scr == 0 ){
752 	    /* init screen mfdb */
753 	    buf_scr.fd_addr = malloc( scr_size );
754 	    size_buf_scr = scr_size;
755 	} else {
756 	    if( scr_size >size_buf_scr ) {
757 		buf_scr.fd_addr = realloc(
758 		    buf_scr.fd_addr, scr_size
759 		    );
760 		size_buf_scr = scr_size;
761 	    }
762 	}
763 	if(buf_scr.fd_addr == NULL ) {
764 	    size_buf_scr = 0;
765 	    return( NULL );
766 	}
767 	buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp;
768 	buf_scr.fd_w = scr_stride;
769 	buf_scr.fd_h = h;
770 	buf_scr.fd_wdwidth = scr_stride >> 4;
771 	assert(buf_scr.fd_addr != NULL );
772     }
773     init_mfdb( 0, w, h, 0, &scr );
774     pxy[0] = x;
775     pxy[1] = y;
776     pxy[2] = pxy[0] + w-1;
777     pxy[3] = pxy[1] + h-1;
778     pxy[4] = 0;
779     pxy[5] = 0;
780     pxy[6] = w-1;
781     pxy[7] = h-1;
782     vro_cpyfm(
783 	atari_plot_vdi_handle, S_ONLY, (short*)&pxy,
784 	&scr,  &buf_scr
785 	);
786 
787     return( &buf_scr );
788 }
789 
790 
791 /**
792  * Create an snapshot of the screen in netsurf ABGR format
793  *
794  * This creates an snapshot in RGBA format (NetSurf's native format)
795  *
796  * Capture the screen at x,y location
797  *
798  * \param x absolute screen coords
799  * \param y absolute screen coords
800  * \param w width
801  * \param h height
802  */
snapshot_create(int x,int y,int w,int h)803 static struct bitmap *snapshot_create(int x, int y, int w, int h)
804 {
805     int err;
806     MFDB * native;
807     // uint32_t start = clock();
808 
809     // FIXME:   This can be optimized a lot.
810     //          1. do not copy the snapshot to the bitmap buffer
811     //              when the format of screen and bitmap equals.
812     //              just point the bitmap to the native mfdb.
813     //          2. if we have eddi 1.1, we could optimize that further
814     //              make snapshot_create_native_mfdb just returning a pointer
815     //              to the screen.
816 
817     native = snapshot_create_native_mfdb(x, y, w, h );
818 
819     if(vfmt.bits == 32 )
820 	goto no_copy;
821 
822     /* allocate buffer for result bitmap: */
823     if(buf_scr_compat == NULL ) {
824 	buf_scr_compat = atari_bitmap_create(w, h, 0);
825     } else {
826 	buf_scr_compat = atari_bitmap_realloc( w, h,
827 					       buf_scr_compat->bpp,
828 					       w *buf_scr_compat->bpp,
829 					       BITMAP_GROW,
830 					       buf_scr_compat );
831     }
832 
833     /* convert screen buffer to ns format: */
834     err = Hermes_ConverterRequest( hermes_cnv_h,
835 				   &vfmt,
836 				   &nsfmt
837 	);
838     assert( err != 0 );
839     err = Hermes_ConverterCopy( hermes_cnv_h,
840 				native->fd_addr,
841 				0, /* x src coord of top left in pixel coords */
842 				0, /* y src coord of top left in pixel coords */
843 				w, h,
844 				native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */
845 				buf_scr_compat->pixdata,
846 				0, /* x dst coord of top left in pixel coords */
847 				0, /* y dst coord of top left in pixel coords */
848 				w, h,
849 				atari_bitmap_get_rowstride(buf_scr_compat) /* stride as bytes */
850 	);
851     assert( err != 0 );
852     return( (struct bitmap * )buf_scr_compat );
853 
854 no_copy:
855 
856     snapshot.width = w;
857     snapshot.height = h;
858     snapshot.pixdata = native->fd_addr;
859     snapshot.native = *native;
860     snapshot.rowstride = MFDB_STRIDE( w )*4;
861 
862     uint32_t row, col;
863     for (row = 0; row<(uint32_t)h; row++) {
864 	// fd_w matches stride!
865 	uint32_t *rowptr = ((uint32_t*)native->fd_addr + ((row*native->fd_w)));
866 	for (col=0; col<(uint32_t)w; col++) {
867 	    *(rowptr+col) = (*(rowptr+col)<<8);
868 	}
869     }
870     return( &snapshot );
871 }
872 
873 
874 /**
875  * Notify the snapshot interface that the last snapshot is no longer in use.
876  */
snapshot_suspend(void)877 static void snapshot_suspend(void)
878 {
879     if(size_buf_scr > CONV_KEEP_LIMIT  ) {
880 	buf_scr.fd_addr = realloc(
881 	    buf_scr.fd_addr, CONV_KEEP_LIMIT
882 	    );
883 	if(buf_scr.fd_addr != NULL ) {
884 	    size_buf_scr = CONV_KEEP_LIMIT;
885 	} else {
886 	    size_buf_scr = 0;
887 	}
888     }
889 
890 #ifdef WITH_8BPP_SUPPORT
891     if(size_buf_std > CONV_KEEP_LIMIT  ) {
892 	buf_std.fd_addr = realloc(
893 	    buf_std.fd_addr, CONV_KEEP_LIMIT
894 	    );
895 	if(buf_std.fd_addr != NULL ) {
896 	    size_buf_std = CONV_KEEP_LIMIT;
897 	} else {
898 	    size_buf_std = 0;
899 	}
900     }
901 #endif
902 
903     if(buf_scr_compat != NULL ) {
904 	size_t bs = atari_bitmap_buffer_size(buf_scr_compat );
905 	if( bs > CONV_KEEP_LIMIT ) {
906 	    int w = 0;
907 	    int h = 1;
908 	    w = (CONV_KEEP_LIMIT /buf_scr_compat->bpp);
909 	    assert( CONV_KEEP_LIMIT == w*buf_scr_compat->bpp );
910 	    buf_scr_compat = atari_bitmap_realloc( w, h,
911 						   buf_scr_compat->bpp,
912 						   CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat
913 		);
914 	}
915     }
916 }
917 
918 
919 /**
920  * Shut down the snapshot interface.
921  */
snapshot_destroy(void)922 static void snapshot_destroy(void)
923 {
924 
925     free(buf_scr.fd_addr);
926     if( buf_scr_compat != NULL) {
927 	atari_bitmap_destroy(buf_scr_compat);
928     }
929 
930     buf_scr.fd_addr = NULL;
931     buf_scr_compat = NULL;
932 
933 #ifdef WITH_8BPP_SUPPORT
934     free(buf_std.fd_addr);
935     buf_std.fd_addr = NULL;
936 #endif
937 }
938 
939 
ablend(uint32_t pixel,uint32_t scrpixel)940 inline static uint32_t ablend(uint32_t pixel, uint32_t scrpixel)
941 {
942     int opacity = pixel & 0xFF;
943     int transp = 0x100 - opacity;
944     uint32_t rb, g;
945     pixel >>= 8;
946     scrpixel >>= 8;
947     rb = ((pixel & 0xFF00FF) * opacity +
948 	  (scrpixel & 0xFF00FF) * transp) >> 8;
949     g  = ((pixel & 0x00FF00) * opacity +
950 	  (scrpixel & 0x00FF00) * transp) >> 8;
951 
952     return ((rb & 0xFF00FF) | (g & 0xFF00)) << 8;
953 }
954 
955 
956 /**
957  * Alpha blends an image, using one pixel as the background.
958  *
959  * The bitmap receives the result.
960  */
ablend_pixel(struct bitmap * img,uint32_t bg,GRECT * clip)961 inline static bool ablend_pixel(struct bitmap * img, uint32_t bg, GRECT * clip)
962 {
963     uint32_t * imgrow;
964     int img_x, img_y, img_stride;
965 
966     img_stride= atari_bitmap_get_rowstride(img);
967 
968     for( img_y = 0; img_y < clip->g_h; img_y++) {
969 	imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y));
970 	for( img_x = 0; img_x < clip->g_w; img_x++ ) {
971 	    imgrow[img_x] = ablend( imgrow[img_x], bg );
972 	}
973     }
974     return(true);
975 }
976 
977 
978 /**
979  * Aplha blends the foreground image onto thebackground images.
980  *
981  * The background receives the blended image pixels.
982  */
983 inline static bool
ablend_bitmap(struct bitmap * img,struct bitmap * bg,GRECT * img_clip,GRECT * bg_clip)984 ablend_bitmap(struct bitmap *img,
985 	      struct bitmap *bg,
986 	      GRECT *img_clip,
987 	      GRECT * bg_clip )
988 {
989     uint32_t * imgrow;
990     uint32_t * screenrow;
991     int img_x, img_y, bg_x, bg_y, img_stride, bg_stride;
992 
993     bg_clip = bg_clip;
994     img_stride = atari_bitmap_get_rowstride(img);
995     bg_stride = atari_bitmap_get_rowstride(bg);
996 
997     for( img_y = img_clip->g_y, bg_y = 0; bg_y < img_clip->g_h; bg_y++, img_y++) {
998 	imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y));
999 	screenrow = (uint32_t *)(bg->pixdata + (bg_stride * bg_y));
1000 	for( img_x = img_clip->g_x, bg_x = 0; bg_x < img_clip->g_w; bg_x++, img_x++ ) {
1001 
1002 	    // when the pixel isn't fully transparent,...:
1003 	    if( (imgrow[img_x] & 0x0FF) != 0 ){
1004 		screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
1005 	    }
1006 
1007 	    // FIXME, maybe this loop would be faster??:
1008 	    // ---
1009 	    //if( (imgrow[img_x] & 0x0FF) != 0xFF ){
1010 	    //  imgrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
1011 	    //}
1012 
1013 	    // or maybe even this???
1014 	    // ---
1015 	    //if(  (imgrow[img_x] & 0x0FF) == 0xFF ){
1016 	    //  screenrow[bg_x] = imgrow[img_x];
1017 	    //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) {
1018 	    //  screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]);
1019 	    //}
1020 	}
1021     }
1022     return(false);
1023 }
1024 
1025 
1026 #ifdef WITH_8BPP_SUPPORT
1027 
1028 /**
1029  * Create an snapshot of the screen image in VDI standard format (8 bit).
1030  */
snapshot_create_std_mfdb(int x,int y,int w,int h)1031 static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h)
1032 {
1033     /* allocate memory for the snapshot */
1034     {
1035 	int scr_stride = MFDB_STRIDE( w );
1036 	int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp );
1037 	if(size_buf_std == 0 ){
1038 	    /* init screen mfdb */
1039 	    buf_std.fd_addr = malloc( scr_size );
1040 	    size_buf_std = scr_size;
1041 	} else {
1042 	    if( scr_size >size_buf_std ) {
1043 		buf_std.fd_addr = realloc(
1044 		    buf_std.fd_addr, scr_size
1045 		    );
1046 		size_buf_std = scr_size;
1047 	    }
1048 	}
1049 	if(buf_std.fd_addr == NULL ) {
1050 	    size_buf_std = 0;
1051 	    return( NULL );
1052 	}
1053 	buf_std.fd_nplanes = 8;
1054 	buf_std.fd_w = scr_stride;
1055 	buf_std.fd_h = h;
1056 	buf_std.fd_stand = 1;
1057 	buf_std.fd_wdwidth = scr_stride >> 4;
1058 	assert(buf_std.fd_addr != NULL );
1059     }
1060     MFDB * native = snapshot_create_native_mfdb(x,y,w,h );
1061     assert( native );
1062 
1063     vr_trnfm(atari_plot_vdi_handle, native, &buf_std);
1064     return( &buf_std );
1065 }
1066 
1067 
1068 /**
1069  * Convert an bitmap to an 8 bit device dependant MFDB
1070  * \param img the bitmap (only tested with 32bit bitmaps)
1071  * \param x screen coord of the background
1072  * \param y screen coord of the background
1073  * \param clip the region of the image that get's converted
1074  * \param bg the background used for cheap transparency
1075  * \param flags
1076  * \param out receives the converted bitmap (still owned by the plot API)
1077  *
1078  */
1079 static bool
bitmap_convert_8(struct bitmap * img,int x,int y,GRECT * clip,uint32_t bg,uint32_t flags,MFDB * out)1080 bitmap_convert_8(struct bitmap *img,
1081 		 int x,
1082 		 int y,
1083 		 GRECT *clip,
1084 		 uint32_t bg,
1085 		 uint32_t flags,
1086 		 MFDB *out)
1087 {
1088     MFDB native;
1089     MFDB stdform;
1090     int dststride;                      /* stride of dest. image */
1091     int dstsize;                        /* size of dest. in byte */
1092     int bw, bh;
1093     struct bitmap * scrbuf = NULL;
1094     bool cache =  ( flags & BITMAPF_BUFFER_NATIVE );
1095     bool opaque = atari_bitmap_get_opaque( img );
1096 
1097     if( opaque == false ){
1098 	if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0)
1099 	    &&
1100 	    ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){
1101 	    opaque = true;
1102 	}
1103     }
1104 
1105     assert( clip->g_h > 0 );
1106     assert( clip->g_w > 0 );
1107 
1108     bw = atari_bitmap_get_width( img );
1109     bh = atari_bitmap_get_height( img );
1110 
1111     // The converted bitmap can be saved for subsequent blits, when
1112     // the bitmap is fully opaque
1113 
1114     if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){
1115 	if( img->converted == true ){
1116 	    *out = img->native;
1117 	    return( 0 );
1118 	}
1119 	if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){
1120 	    cache = true;
1121 	}
1122     }
1123     if( ( flags & BITMAPF_MONOGLYPH ) != 0 ){
1124 	assert(cache == false);
1125     }
1126 
1127     /* (re)allocate buffer for out image: */
1128     /* altough the buffer is named "buf_packed" on 8bit systems */
1129     /* it's not... */
1130     if( cache == false ){
1131 	// the size of the output will match the size of the clipping:
1132 	dststride = MFDB_STRIDE( clip->g_w );
1133 	dstsize = ( ((dststride >> 3) * clip->g_h) * atari_plot_bpp_virt);
1134 	if (dstsize > size_buf_packed) {
1135 	    int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
1136 	    void *buf;
1137 	    if (buf_packed == NULL) {
1138 		buf = malloc( blocks * CONV_BLOCK_SIZE);
1139 	    } else {
1140 		buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE);
1141 	    }
1142 	    if (buf == NULL) {
1143 		return( 0-ERR_NO_MEM );
1144 	    }
1145 	    buf_packed = buf;
1146 	    size_buf_packed = blocks * CONV_BLOCK_SIZE;
1147 	}
1148 	native.fd_addr = buf_packed;
1149     }
1150     else {
1151 	// the output image will be completly saved, so size of the output
1152 	// image will match the input image size.
1153 	dststride = MFDB_STRIDE( bw );
1154 	dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt);
1155 	assert( out->fd_addr == NULL );
1156 	native.fd_addr = malloc( dstsize );
1157 	if (native.fd_addr == NULL){
1158 	    if (scrbuf != NULL)
1159 		atari_bitmap_destroy(scrbuf);
1160 	    return( 0-ERR_NO_MEM );
1161 	}
1162     }
1163 
1164 
1165     /*
1166       on 8 bit systems we must convert the TC (ABGR) image
1167       to vdi standard format. ( only tested for 256 colors )
1168       and then convert it to native format with v_trnfm()
1169     */
1170     // realloc mem for stdform
1171     if( opaque == false ){
1172 	// point image to snapshot buffer, otherwise allocate mem
1173 	MFDB * bg = snapshot_create_std_mfdb(x, y, clip->g_w, clip->g_h);
1174 	stdform.fd_addr = bg->fd_addr;
1175 	bh = clip->g_h;
1176     } else {
1177 	if (dstsize > size_buf_planar) {
1178 	    int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
1179 	    void *buf;
1180 	    if (buf_planar == NULL) {
1181 		buf = malloc(blocks * CONV_BLOCK_SIZE);
1182 	    } else {
1183 		buf = realloc(buf_planar, blocks * CONV_BLOCK_SIZE);
1184 	    }
1185 	    if (buf == NULL ) {
1186 		if (cache) {
1187 		    free(native.fd_addr);
1188 		}
1189 		return( 0-ERR_NO_MEM );
1190 	    }
1191 	    buf_planar = buf;
1192 	    size_buf_planar = blocks * CONV_BLOCK_SIZE;
1193 	}
1194 	stdform.fd_addr = buf_planar;
1195     }
1196     stdform.fd_w = dststride;
1197     stdform.fd_h = bh;
1198     stdform.fd_wdwidth = dststride >> 4;
1199     stdform.fd_stand = 1;
1200     stdform.fd_nplanes = (short)atari_plot_bpp_virt;
1201     stdform.fd_r1 = stdform.fd_r2 = stdform.fd_r3 = 0;
1202 
1203     int img_stride = atari_bitmap_get_rowstride(img);
1204     uint32_t prev_pixel = 0x12345678; //TODO: check for collision in first pixel
1205     unsigned long col = 0;
1206     unsigned char val = 0;
1207     uint32_t * row;
1208     uint32_t pixel;
1209     int wdplanesize = stdform.fd_wdwidth*stdform.fd_h;
1210 
1211     if( opaque == false ){
1212 	// apply transparency and convert to vdi std format
1213 	unsigned long bgcol = 0;
1214 	unsigned char prev_col = 0;
1215 	for( y=0; y<clip->g_h; y++ ){
1216 	    row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y)));
1217 	    for( x=0; x<clip->g_w; x++ ){
1218 		pixel = row[x+clip->g_x];
1219 		if( (pixel&0xFF) == 0 ){
1220 		    continue;
1221 		}
1222 		if( (pixel&0xFF) < 0xF0 ){
1223 		    col = get_stdpx( &stdform, wdplanesize,x,y );
1224 		    if( (col != prev_col) || (y == 0) )
1225 			bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8);
1226 		    if( prev_col != col || prev_pixel != pixel ){
1227 			prev_col = col;
1228 			pixel = ablend( pixel, bgcol );
1229 			prev_pixel = pixel;
1230 			pixel = pixel >> 8;
1231 			/* convert pixel value to vdi color index: */
1232 			col = ( ((pixel&0xFF)<<16)
1233 				| (pixel&0xFF00)
1234 				| ((pixel&0xFF0000)>>16) );
1235 			val = RGB_TO_VDI( col );
1236 		    }
1237 		    set_stdpx( &stdform, wdplanesize, x, y, val );
1238 		} else {
1239 		    if( pixel != prev_pixel ){
1240 			/* convert pixel value to vdi color index: */
1241 			pixel = pixel >> 8;
1242 			col = ( ((pixel&0xFF)<<16)
1243 				| (pixel&0xFF00)
1244 				| ((pixel&0xFF0000)>>16) );
1245 			val = RGB_TO_VDI( col );
1246 			prev_pixel = pixel;
1247 		    }
1248 		    set_stdpx( &stdform, wdplanesize, x, y, val );
1249 		}
1250 	    }
1251 	}
1252 	// adjust output position:
1253 	clip->g_x = 0;
1254 	clip->g_y = 0;
1255     } else {
1256 	// convert the whole image data to vdi std format.
1257 	for( y=0; y < bh; y++ ){
1258 	    row = (uint32_t *)(img->pixdata + (img_stride * y));
1259 	    for( x=0; x < bw; x++ ){
1260 		pixel = row[x];
1261 		if( pixel != prev_pixel ){
1262 		    /* convert pixel value to vdi color index: */
1263 		    pixel = pixel >> 8;
1264 		    col = ( ((pixel&0xFF)<<16)
1265 			    | (pixel&0xFF00)
1266 			    | ((pixel&0xFF0000)>>16) );
1267 		    val = RGB_TO_VDI( col );
1268 		    prev_pixel = pixel;
1269 		}
1270 		set_stdpx( &stdform, wdplanesize, x, y, val );
1271 	    }
1272 	}
1273     }
1274 
1275     // convert into native format:
1276     native.fd_w = stdform.fd_w;
1277     native.fd_h = stdform.fd_h;
1278     native.fd_wdwidth = stdform.fd_wdwidth;
1279     native.fd_stand = 0;
1280     native.fd_nplanes = (short)atari_plot_bpp_virt;
1281     native.fd_r1 = native.fd_r2 = native.fd_r3 = 0;
1282     vr_trnfm(atari_plot_vdi_handle, &stdform, &native );
1283     *out = native;
1284     if( cache == true ){
1285 	img->native = native;
1286 	img->converted = true;
1287     }
1288 
1289     return(0);
1290 }
1291 #endif
1292 
1293 
1294 /**
1295  * Convert bitmap to the native screen format
1296  *
1297  * \param img the bitmap
1298  * \param x coordinate where the bitmap REGION (described in clip)
1299  *           shall be drawn (screen coords)
1300  * \param y coordinate where the bitmap REGION (described in clip)
1301  *           shall be drawn (screen coords)
1302  * \param clip which area of the bitmap shall be drawn
1303  * \param bg background color
1304  * \param flags blit flags
1305  * \param out the result MFDB
1306  */
1307 static bool
bitmap_convert_tc(struct bitmap * img,int x,int y,GRECT * clip,uint32_t bg,uint32_t flags,MFDB * out)1308 bitmap_convert_tc(struct bitmap *img,
1309 		  int x,
1310 		  int y,
1311 		  GRECT *clip,
1312 		  uint32_t bg,
1313 		  uint32_t flags,
1314 		  MFDB *out)
1315 {
1316     int dststride; /* stride of dest. image */
1317     int dstsize; /* size of dest. in byte */
1318     int err;
1319     int bw, bh;
1320     struct bitmap * scrbuf = NULL;
1321     struct bitmap * source = NULL;
1322     bool cache =  ( flags & BITMAPF_BUFFER_NATIVE );
1323     bool opaque = atari_bitmap_get_opaque( img );
1324 
1325     if (opaque == false ) {
1326 	if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0)
1327 	    &&
1328 	    ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){
1329 	    opaque = true;
1330 	}
1331     }
1332 
1333     assert( clip->g_h > 0 );
1334     assert( clip->g_w > 0 );
1335 
1336     bw = atari_bitmap_get_width( img );
1337     bh = atari_bitmap_get_height( img );
1338 
1339     // The converted bitmap can be saved for subsequent blits, WHEN:
1340     // A.) the bitmap is fully opaque OR
1341     // B.) the bitmap is completly inside the window
1342     // the latter one is important for alpha blits,
1343     // because we must get the window background to apply transparency
1344     // If the image is not completly within the window,
1345     // we can't get the whole background for the image.
1346     // this only works if the image isn't used at several different places.
1347     // In fact in case of alpha bitmap caching it is only used for the
1348     // toolbar buttons right now.
1349 
1350     if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){
1351 	if( img->converted == true ){
1352 	    *out = img->native;
1353 	    return( 0 );
1354 	}
1355 	if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){
1356 	    cache = true;
1357 	}
1358     }
1359 
1360     /* rem. if eddi xy is installed, we could directly access the screen! */
1361     /* apply transparency to the image: */
1362     if (( opaque == false )) {
1363 	/* copy the screen to an temp buffer: */
1364 	if ((flags & BITMAPF_BUFFER_NATIVE) == 0) {
1365 	    scrbuf = snapshot_create(x, y, clip->g_w, clip->g_h);
1366 	    if( scrbuf != NULL ) {
1367 
1368 		assert( clip->g_w <= bw );
1369 		assert( clip->g_h <= bh );
1370 
1371 		// copy blended pixels to the screen buffer:
1372 		ablend_bitmap( img, scrbuf, clip, NULL );
1373 		/* adjust size which gets converted: */
1374 		bw = clip->g_w;
1375 		bh = clip->g_h;
1376 		/* adjust output position: */
1377 		clip->g_x = 0;
1378 		clip->g_y = 0;
1379 		/* set the source of conversion: */
1380 		source = scrbuf;
1381 	    }
1382 	} else {
1383 	    /*
1384 	      The whole bitmap can be transformed to an mfdb
1385 	      (and get's cached)
1386 	    */
1387 	    GRECT region = { 0, 0, bw, bh };
1388 	    ablend_pixel( img, bg, &region );
1389 	    source = img;
1390 	}
1391     } else {
1392 	source = img;
1393     }
1394     /* (re)allocate buffer for converted image: */
1395     dststride = MFDB_STRIDE(bw);
1396     dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt );
1397     if (cache == false) {
1398 	/* ensure cache buffer is large enough */
1399 	if (dstsize > size_buf_packed) {
1400 	    int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1;
1401 	    void *buf;
1402 	    if (buf_packed == NULL) {
1403 		buf = malloc(blocks * CONV_BLOCK_SIZE);
1404 	    } else {
1405 		buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE);
1406 	    }
1407 	    if (buf == NULL ) {
1408 		if (scrbuf != NULL) {
1409 		    atari_bitmap_destroy(scrbuf);
1410 		}
1411 		return( 0-ERR_NO_MEM );
1412 	    }
1413 	    buf_packed = buf;
1414 	    size_buf_packed = blocks * CONV_BLOCK_SIZE;
1415 	}
1416 	out->fd_addr = buf_packed;
1417     } else {
1418 	assert( out->fd_addr == NULL );
1419 	out->fd_addr = (void*)malloc( dstsize );
1420 	if( out->fd_addr == NULL ){
1421 	    if( scrbuf != NULL )
1422 		atari_bitmap_destroy( scrbuf );
1423 	    return( 0-ERR_NO_MEM );
1424 	}
1425     }
1426 
1427     out->fd_w = dststride;
1428     out->fd_h = bh;
1429     out->fd_wdwidth = dststride >> 4;
1430     out->fd_stand = 0;
1431     out->fd_nplanes = (short)atari_plot_bpp_virt;
1432     out->fd_r1 = out->fd_r2 = out->fd_r3 = 0;
1433 
1434     err = Hermes_ConverterRequest(
1435 	hermes_cnv_h,
1436 	&nsfmt,
1437 	&vfmt
1438 	);
1439     assert( err != 0 );
1440 
1441     // FIXME: here we can use the same optimization which is used for
1442     // the snapshot creation.
1443 
1444     /* convert image to virtual format: */
1445     err = Hermes_ConverterCopy( hermes_cnv_h,
1446 				source->pixdata,
1447 				0, /* x src coord of top left in pixel coords */
1448 				0, /* y src coord of top left in pixel coords */
1449 				bw, bh,
1450 				source->rowstride,  /* stride as bytes */
1451 				out->fd_addr,
1452 				0, /* x dst coord of top left in pixel coords */
1453 				0,/* y dst coord of top left in pixel coords */
1454 				bw, bh,
1455 				(dststride >> 3) *  atari_plot_bpp_virt             /* stride as bytes */
1456 	);
1457     assert( err != 0 );
1458 
1459     if( cache == true ){
1460 	img->native = *out;
1461 	img->converted = true;
1462     }
1463     return( 0 );
1464 
1465 }
1466 
1467 
convert_bitmap_done(void)1468 inline static void convert_bitmap_done(void)
1469 {
1470     if (size_buf_packed > CONV_KEEP_LIMIT) {
1471 	void *buf;
1472 	/* free the mem if it was an large allocation ... */
1473 	buf = realloc(buf_packed, CONV_KEEP_LIMIT);
1474 	if (buf != NULL) {
1475 	    buf_packed = buf;
1476 	    size_buf_packed = CONV_KEEP_LIMIT;
1477 	}
1478     }
1479 }
1480 
1481 
plot_blit_bitmap(struct bitmap * bmp,int x,int y,unsigned long bg,unsigned long flags)1482 bool plot_blit_bitmap(struct bitmap * bmp, int x, int y,
1483 		      unsigned long bg, unsigned long flags )
1484 {
1485     MFDB src_mf;
1486     MFDB scrmf;
1487     short pxy[8];
1488     GRECT off, clip, vis;
1489     int screen_x, screen_y;
1490 
1491     src_mf.fd_addr = NULL;
1492     scrmf.fd_addr = NULL;
1493 
1494     off.g_x = x;
1495     off.g_y = y;
1496     off.g_h = bmp->height;
1497     off.g_w = bmp->width;
1498 
1499     // clip plotter clip rectangle:
1500     clip.g_x = view.clipping.x0;
1501     clip.g_y = view.clipping.y0;
1502     clip.g_w = view.clipping.x1 - view.clipping.x0;
1503     clip.g_h = view.clipping.y1 - view.clipping.y0;
1504 
1505     if( !rc_intersect( &clip, &off) ) {
1506 	return(true);
1507     }
1508 
1509     // clip the visible rectangle of the plot area
1510     // this is the area of the plotter which falls into
1511     // screen region:
1512     plot_get_visible_grect(&vis);
1513     if( !rc_intersect( &vis, &off) ) {
1514 	return(true);
1515     }
1516 
1517     screen_x = view.x + off.g_x;
1518     screen_y = view.y + off.g_y;
1519 
1520     // convert the clipping relative to bitmap:
1521     off.g_x = off.g_x - x;
1522     off.g_y = off.g_y - y;
1523     assert( (off.g_x >= 0) && (off.g_y >= 0) );
1524 
1525     /* Convert the Bitmap to native screen format - ready for output.   */
1526     /* This includes blending transparent pixels:                       */
1527     if (bitmap_convert(bmp, screen_x, screen_y, &off, bg, flags, &src_mf)
1528 	!= 0 ) {
1529 	return(true);
1530     }
1531 
1532     // setup the src region:
1533     pxy[0] = off.g_x;
1534     pxy[1] = off.g_y;
1535     pxy[2] = off.g_x + off.g_w-1;
1536     pxy[3] = off.g_y + off.g_h-1;
1537 
1538     // setup the target region:
1539     pxy[4] = screen_x;
1540     pxy[5] = screen_y;
1541     pxy[6] = screen_x + off.g_w-1;
1542     pxy[7] = screen_y + off.g_h-1;
1543 
1544     vro_cpyfm(atari_plot_vdi_handle, S_ONLY, (short*)&pxy, &src_mf,  &scrmf);
1545     convert_bitmap_done();
1546     snapshot_suspend();
1547     return(true);
1548 }
1549 
1550 
plot_blit_mfdb(GRECT * loc,MFDB * insrc,short fgcolor,uint32_t flags)1551 bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor,
1552 		    uint32_t flags)
1553 {
1554     MFDB screen;
1555 //  MFDB tran;
1556     MFDB * src;
1557     short pxy[8];
1558     short c[2] = {fgcolor, 0};
1559     GRECT off;
1560 
1561     plot_get_clip_grect(&off);
1562     if( rc_intersect(loc, &off) == 0 ){
1563 	return( 1 );
1564     }
1565 
1566     init_mfdb( 0, loc->g_w, loc->g_h, 0, &screen );
1567 //
1568 //  if( insrc->fd_stand){
1569 //      printf("st\n");
1570 //      int size = init_mfdb( insrc->fd_nplanes, loc->g_w, loc->g_h,
1571 //          MFDB_FLAG_NOALLOC,
1572 //          &tran
1573 //      );
1574 //      if( size_buf_scr == 0 ){
1575 //          buf_scr.fd_addr = malloc( size );
1576 //          size_buf_scr = size;
1577 //      } else {
1578 //          if( size > size_buf_scr ) {
1579 //              buf_scr.fd_addr = realloc(
1580 //                  buf_scr.fd_addr, size
1581 //              );
1582 //              size_buf_scr = size;
1583 //          }
1584 //      }
1585 //      tran.fd_addr = buf_scr.fd_addr;
1586 //      vr_trnfm(atari_plot_vdi_handle, insrc, &tran );
1587 //      src = &tran;
1588 //  } else {
1589     src = insrc;
1590 //  }
1591 
1592     pxy[0] = off.g_x - loc->g_x;
1593     pxy[1] = off.g_y - loc->g_y;
1594     pxy[2] = pxy[0] + off.g_w - 1;
1595     pxy[3] = pxy[1] + off.g_h - 1;
1596     pxy[4] = view.x + off.g_x;
1597     pxy[5] = view.y + off.g_y;
1598     pxy[6] = pxy[4] + off.g_w-1;
1599     pxy[7] = pxy[5] + off.g_h-1;
1600 
1601 
1602     if( flags & PLOT_FLAG_TRANS && src->fd_nplanes == 1){
1603 	vrt_cpyfm(atari_plot_vdi_handle, MD_REPLACE/*MD_TRANS*/, (short*)pxy, src, &screen, (short*)&c);
1604     } else {
1605 	/* this method only plots transparent bitmaps, right now... */
1606     }
1607     return( 1 );
1608 }
1609 
1610 
1611 /* exported interface documented in atari/plot.h */
plot_init(const struct redraw_context * ctx,char * fdrvrname)1612 int plot_init(const struct redraw_context *ctx, char *fdrvrname)
1613 {
1614     GRECT loc_pos = { 0, 0, 360, 400 };
1615     int err=0;
1616 
1617     if( nsoption_int(atari_dither) == 1)
1618 	atari_plot_flags |= PLOT_FLAG_DITHER;
1619     if( nsoption_int(atari_transparency) == 1 )
1620 	atari_plot_flags |= PLOT_FLAG_TRANS;
1621     if( nsoption_int(atari_font_monochrom) == 1 )
1622 	atari_font_flags |= FONTPLOT_FLAG_MONOGLYPH;
1623 
1624     if (atari_plot_vdi_handle == -1) {
1625 
1626 	short dummy;
1627 	short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1};
1628 	short work_out[57];
1629 	atari_plot_vdi_handle=graf_handle(&dummy, &dummy, &dummy, &dummy);
1630 	v_opnvwk(work_in, &atari_plot_vdi_handle, work_out);
1631 	NSLOG(netsurf, INFO, "Plot VDI handle: %d", atari_plot_vdi_handle);
1632     }
1633     read_vdi_sysinfo(atari_plot_vdi_handle, &vdi_sysinfo);
1634     if(verbose_log) {
1635 	dump_vdi_info(atari_plot_vdi_handle) ;
1636 	dump_font_drivers();
1637     }
1638 
1639     fplotter = new_font_plotter(atari_plot_vdi_handle, fdrvrname,
1640 				atari_font_flags, &err);
1641     if (err) {
1642 	const char * desc = plot_err_str(err);
1643 	NSLOG(netsurf, INFO, "Unable to load font plotter %s -> %s",
1644               fdrvrname, desc);
1645 	die("font plotter");
1646     }
1647 
1648     memset(&view, 0, sizeof(struct s_view));
1649     atari_plot_bpp_virt = vdi_sysinfo.scr_bpp;
1650     view.x = loc_pos.g_x;
1651     view.y = loc_pos.g_y;
1652     view.w = loc_pos.g_w;
1653     view.h = loc_pos.g_h;
1654     size_buf_packed = 0;
1655     size_buf_planar = 0;
1656     buf_packed = NULL;
1657     buf_planar = NULL;
1658     if( vdi_sysinfo.vdiformat == VDI_FORMAT_PACK  ) {
1659 	atari_plot_bpp_virt = vdi_sysinfo.scr_bpp;
1660     } else {
1661 	atari_plot_bpp_virt = 8;
1662     }
1663 
1664     plot_set_scale(1.0);
1665     update_visible_rect();
1666 
1667     struct rect clip;
1668     clip.x0 = 0;
1669     clip.y0 = 0;
1670     clip.x1 = view.w;
1671     clip.y1 = view.h;
1672     ctx->plot->clip(ctx, &clip);
1673 
1674     assert(Hermes_Init());
1675 
1676 #ifdef WITH_8BPP_SUPPORT
1677     bitmap_convert = (vdi_sysinfo.scr_bpp > 8) ? bitmap_convert_tc : bitmap_convert_8;
1678 
1679     /* Setup color lookup tables and palette */
1680     unsigned char rgbcol[4];
1681     if( vdi_sysinfo.scr_bpp <= 8 ){
1682 	unsigned char graytone=0;
1683 	int i;
1684 	for( i=0; i<=255; i++ ) {
1685 
1686 	    // get the current color and save it for restore:
1687 	    vq_color(atari_plot_vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] );
1688 	    if( i<OFFSET_WEB_PAL ) {
1689 		pal[i][0] = sys_pal[i][0];
1690 		pal[i][1] = sys_pal[i][1];
1691 		pal[i][2] = sys_pal[i][2];
1692 	    } else if( vdi_sysinfo.scr_bpp >= 8 ) {
1693 		if ( i < OFFSET_CUST_PAL ){
1694 		    pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0];
1695 		    pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1];
1696 		    pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2];
1697 		    //set the new palette color to websafe value:
1698 		    vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
1699 		}
1700 		if( i >= OFFSET_CUST_PAL && i<OFFSET_CUST_PAL+16 ) {
1701 		    /* here we define 20 additional gray colors... */
1702 		    rgbcol[1] = rgbcol[2] = rgbcol[3] = ((graytone&0x0F) << 4);
1703 		    rgb_to_vdi1000( &rgbcol[0], &pal[i][0] );
1704 		    vs_color(atari_plot_vdi_handle, i, &pal[i][0]);
1705 		    graytone++;
1706 		}
1707 
1708 	    }
1709 	    vdi1000_to_rgb( &pal[i][0],  &rgb_lookup[i][0] );
1710 	}
1711 
1712     } else {
1713 	/* no need to change the palette - its application specific */
1714     }
1715 #else
1716     bitmap_convert = bitmap_convert_tc;
1717 #endif
1718 
1719     /* Setup Hermes conversion handles */
1720     unsigned long hermesflags = (atari_plot_flags & PLOT_FLAG_DITHER) ? HERMES_CONVERT_DITHER : 0;
1721     hermes_cnv_h = Hermes_ConverterInstance(hermesflags);
1722     assert( hermes_cnv_h );
1723     hermes_res_h = Hermes_ConverterInstance(hermesflags);
1724     assert( hermes_res_h );
1725 
1726     /* set up the src & dst format: */
1727     /* netsurf uses RGBA ... */
1728     nsfmt.a = 0xFFUL;
1729     nsfmt.b = 0x0FF00UL;
1730     nsfmt.g = 0x0FF0000UL;
1731     nsfmt.r = 0x0FF000000UL;
1732     nsfmt.bits = 32;
1733     nsfmt.indexed = false;
1734     nsfmt.has_colorkey = false;
1735 
1736     vfmt.r = vdi_sysinfo.mask_r;
1737     vfmt.g = vdi_sysinfo.mask_g;
1738     vfmt.b = vdi_sysinfo.mask_b;
1739     vfmt.a = vdi_sysinfo.mask_a;
1740     vfmt.bits = atari_plot_bpp_virt;
1741     vfmt.indexed = (atari_plot_bpp_virt <= 8) ? 1 : 0;
1742     vfmt.has_colorkey = 0;
1743 
1744     return( err );
1745 }
1746 
1747 
plot_finalise(void)1748 int plot_finalise( void )
1749 {
1750 
1751     delete_font_plotter(fplotter);
1752 
1753 #ifdef WITH_8BPP_SUPPORT
1754     if (vfmt.indexed) {
1755 	int i;
1756 	for (i=OFFSET_WEB_PAL; i<OFFSET_CUST_PAL+16; i++) {
1757 	    vs_color(atari_plot_vdi_handle, i, &sys_pal[i][0]);
1758 	}
1759     }
1760 #endif
1761 
1762     /* close Hermes stuff: */
1763     Hermes_ConverterReturn(hermes_cnv_h);
1764     Hermes_Done();
1765 
1766     /* free up temporary buffers */
1767     free(buf_packed );
1768     free(buf_planar);
1769     snapshot_destroy();
1770 
1771     return 0;
1772 }
1773 
1774 
plot_lock(void)1775 bool plot_lock(void)
1776 {
1777     if ((atari_plot_flags & PLOT_FLAG_LOCKED) != 0)
1778 	return(true);
1779     if( !wind_update(BEG_UPDATE|0x100) )
1780 	return(false);
1781     if( !wind_update(BEG_MCTRL|0x100) ){
1782 	wind_update(END_UPDATE);
1783 	return(false);
1784     }
1785     atari_plot_flags |= PLOT_FLAG_LOCKED;
1786     graf_mouse(M_OFF, NULL);
1787     return(true);
1788 }
1789 
1790 
plot_unlock(void)1791 bool plot_unlock(void)
1792 {
1793     if( (atari_plot_flags & PLOT_FLAG_LOCKED) == 0 )
1794 	return(true);
1795     wind_update(END_MCTRL);
1796     wind_update(END_UPDATE);
1797     graf_mouse(M_ON, NULL);
1798     vs_clip_off(atari_plot_vdi_handle);
1799     atari_plot_flags &=  ~PLOT_FLAG_LOCKED;
1800     return(false);
1801 }
1802 
1803 
1804 /* exported interface documented in atari/plot.h */
1805 bool
plot_set_dimensions(const struct redraw_context * ctx,int x,int y,int w,int h)1806 plot_set_dimensions(const struct redraw_context *ctx, int x, int y, int w, int h)
1807 {
1808     bool doupdate = false;
1809     struct rect newclip = {0, 0, w, h};
1810     GRECT absclip = {x, y, w, h};
1811 
1812     if (!(w == view.w && h == view.h)) {
1813 	view.w = (short)w;
1814 	view.h = (short)h;
1815 	doupdate = true;
1816     }
1817     if (!(x == view.x && y == view.y)) {
1818 	view.x = (short)x;
1819 	view.y = (short)y;
1820 	doupdate = true;
1821     }
1822     if (doupdate==true)
1823 	update_visible_rect();
1824 
1825     //dbg_rect("plot_set_dimensions", &newclip);
1826 
1827     plot_set_abs_clipping(&absclip);
1828     ctx->plot->clip(ctx, &newclip);
1829     return(true);
1830 }
1831 
1832 
1833 /**
1834  * Get current canvas size
1835  *
1836  * \param dst the GRECT * which receives the canvas size
1837  */
plot_get_dimensions(GRECT * dst)1838 bool plot_get_dimensions(GRECT *dst)
1839 {
1840     dst->g_x = view.x;
1841     dst->g_y = view.y;
1842     dst->g_w = view.w;
1843     dst->g_h = view.h;
1844     return(true);
1845 }
1846 
1847 
1848 /**
1849  * set scale of plotter.
1850  * \param scale the new scale value
1851  * \return the old scale value
1852  */
1853 
plot_set_scale(float scale)1854 float plot_set_scale(float scale)
1855 {
1856     float ret = view.scale;
1857 
1858     view.scale = scale;
1859 
1860     return(ret);
1861 }
1862 
1863 
plot_get_scale(void)1864 float plot_get_scale(void)
1865 {
1866     return(view.scale);
1867 }
1868 
1869 
1870 /**
1871  * Subsequent calls to plot_clip will be clipped by the absolute clip.
1872  *
1873  * \param area the maximum clipping rectangle (absolute screen coords)
1874  */
plot_set_abs_clipping(const GRECT * area)1875 void plot_set_abs_clipping(const GRECT *area)
1876 {
1877     GRECT canvas;
1878 
1879     plot_get_dimensions(&canvas);
1880 
1881     if(!rc_intersect(area, &canvas)){
1882 	view.abs_clipping.x0 = 0;
1883 	view.abs_clipping.x1 = 0;
1884 	view.abs_clipping.y0 = 0;
1885 	view.abs_clipping.y1 = 0;
1886     } else {
1887 	view.abs_clipping.x0 = area->g_x;
1888 	view.abs_clipping.x1 = area->g_x + area->g_w;
1889 	view.abs_clipping.y0 = area->g_y;
1890 	view.abs_clipping.y1 = area->g_y + area->g_h;
1891     }
1892 }
1893 
1894 
1895 /**
1896  * Get the maximum clip extent, in absolute screen coords
1897  * \param dst the structure that receives the absolute clipping
1898  */
plot_get_abs_clipping(struct rect * dst)1899 void plot_get_abs_clipping(struct rect *dst)
1900 {
1901     *dst = view.abs_clipping;
1902 }
1903 
1904 
1905 /**
1906  * Get the maximum clip extent, in absolute screen coords
1907  * \param dst the structure that receives the absolute clipping
1908  */
plot_get_abs_clipping_grect(GRECT * dst)1909 void plot_get_abs_clipping_grect(GRECT *dst)
1910 {
1911     dst->g_x = view.abs_clipping.x0;
1912     dst->g_w = view.abs_clipping.x1 - view.abs_clipping.x0;
1913     dst->g_y = view.abs_clipping.y0;
1914     dst->g_h = view.abs_clipping.y1 - view.abs_clipping.y0;
1915 }
1916 
1917 
plot_get_vdi_handle(void)1918 VdiHdl plot_get_vdi_handle(void)
1919 {
1920     return(atari_plot_vdi_handle);
1921 }
1922 
1923 
plot_get_flags(void)1924 long plot_get_flags(void)
1925 {
1926     return(atari_plot_flags);
1927 }
1928 
1929 
plot_get_clip(struct rect * out)1930 bool plot_get_clip(struct rect * out)
1931 {
1932     out->x0 = view.clipping.x0;
1933     out->y0 = view.clipping.y0;
1934     out->x1 = view.clipping.x1;
1935     out->y1 = view.clipping.y1;
1936     return( true );
1937 }
1938 
1939 
plot_get_clip_grect(GRECT * out)1940 void plot_get_clip_grect(GRECT * out)
1941 {
1942     struct rect clip={0,0,0,0};
1943 
1944     plot_get_clip(&clip);
1945 
1946     out->g_x = clip.x0;
1947     out->g_y = clip.y0;
1948     out->g_w = clip.x1 - clip.x0;
1949     out->g_h = clip.y1 - clip.y0;
1950 }
1951 
1952 
plot_get_text_plotter()1953 FONT_PLOTTER plot_get_text_plotter()
1954 {
1955     return(fplotter);
1956 }
1957 
1958 
plot_set_text_plotter(FONT_PLOTTER font_plotter)1959 void plot_set_text_plotter(FONT_PLOTTER font_plotter)
1960 {
1961     fplotter = font_plotter;
1962 }
1963 
1964 
1965 /**
1966  * \brief Sets a clip rectangle for subsequent plot operations.
1967  *
1968  * \param ctx The current redraw context.
1969  * \param clip The rectangle to limit all subsequent plot
1970  *              operations within.
1971  * \return NSERROR_OK on success else error code.
1972  */
1973 static nserror
plot_clip(const struct redraw_context * ctx,const struct rect * clip)1974 plot_clip(const struct redraw_context *ctx, const struct rect *clip)
1975 {
1976     GRECT canvas, screen, gclip, maxclip;
1977     short pxy[4];
1978 
1979     screen.g_x = 0;
1980     screen.g_y = 0;
1981     screen.g_w = vdi_sysinfo.scr_w;
1982     screen.g_h = vdi_sysinfo.scr_h;
1983 
1984     plot_get_dimensions(&canvas);
1985 
1986     view.clipping.y0 = clip->y0;
1987     view.clipping.y1 = clip->y1;
1988     view.clipping.x0 = clip->x0;
1989     view.clipping.x1 = clip->x1;
1990 
1991     plot_get_clip_grect(&gclip);
1992 
1993     gclip.g_x += canvas.g_x;
1994     gclip.g_y += canvas.g_y;
1995 
1996     rc_intersect(&canvas, &gclip);
1997 
1998     if(gclip.g_h < 0){
1999 	gclip.g_h = 0;
2000     }
2001 
2002     if (!rc_intersect(&screen, &gclip)) {
2003 	//dbg_rect("cliprect: ", &view.clipping);
2004 	//dbg_grect("screen: ", &canvas);
2005 	//dbg_grect("canvas clipped: ", &gclip);
2006 	//assert(1 == 0);
2007     }
2008 
2009     // When setting VDI clipping, obey to maximum cliping rectangle:
2010     plot_get_abs_clipping_grect(&maxclip);
2011     rc_intersect(&maxclip, &gclip);
2012 
2013     //dbg_grect("canvas clipped to screen", &gclip);
2014 
2015     pxy[0] = gclip.g_x;
2016     pxy[1] = gclip.g_y;
2017     pxy[2] = pxy[0] + gclip.g_w;
2018     pxy[3] = pxy[1] + gclip.g_h;
2019 
2020     vs_clip(atari_plot_vdi_handle, 1, (short*)&pxy);
2021 
2022     return NSERROR_OK;
2023 }
2024 
2025 
2026 /**
2027  * Plots an arc
2028  *
2029  * plot an arc segment around (x,y), anticlockwise from angle1
2030  *  to angle2. Angles are measured anticlockwise from
2031  *  horizontal, in degrees.
2032  *
2033  * \param ctx The current redraw context.
2034  * \param pstyle Style controlling the arc plot.
2035  * \param x The x coordinate of the arc.
2036  * \param y The y coordinate of the arc.
2037  * \param radius The radius of the arc.
2038  * \param angle1 The start angle of the arc.
2039  * \param angle2 The finish angle of the arc.
2040  * \return NSERROR_OK on success else error code.
2041  */
2042 static nserror
plot_arc(const struct redraw_context * ctx,const plot_style_t * pstyle,int x,int y,int radius,int angle1,int angle2)2043 plot_arc(const struct redraw_context *ctx,
2044 	 const plot_style_t *pstyle,
2045 	 int x, int y, int radius, int angle1, int angle2)
2046 {
2047     vswr_mode(atari_plot_vdi_handle, MD_REPLACE);
2048     if (pstyle->fill_type == PLOT_OP_TYPE_NONE) {
2049 	return NSERROR_OK;
2050     }
2051 
2052     if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
2053 	vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
2054 	vsf_perimeter(atari_plot_vdi_handle, 1);
2055 	vsf_interior(atari_plot_vdi_handle, 1 );
2056 	v_arc(atari_plot_vdi_handle,
2057 	      view.x + x,
2058 	      view.y + y,
2059 	      radius,
2060 	      angle1 * 10,
2061 	      angle2 * 10);
2062     } else {
2063 	vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
2064 	vsl_width(atari_plot_vdi_handle, 1);
2065 	vsf_perimeter(atari_plot_vdi_handle, 1);
2066 	v_arc(atari_plot_vdi_handle,
2067 	      view.x + x,
2068 	      view.y + y, radius,
2069 	      angle1 * 10,
2070 	      angle2 * 10);
2071     }
2072 
2073     return NSERROR_OK;
2074 }
2075 
2076 
2077 /**
2078  * Plots a circle
2079  *
2080  * Plot a circle centered on (x,y), which is optionally filled.
2081  *
2082  * \param ctx The current redraw context.
2083  * \param pstyle Style controlling the circle plot.
2084  * \param x x coordinate of circle centre.
2085  * \param y y coordinate of circle centre.
2086  * \param radius circle radius.
2087  * \return NSERROR_OK on success else error code.
2088  */
2089 static nserror
plot_disc(const struct redraw_context * ctx,const plot_style_t * pstyle,int x,int y,int radius)2090 plot_disc(const struct redraw_context *ctx,
2091 	  const plot_style_t *pstyle,
2092 	  int x, int y, int radius)
2093 {
2094     if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) {
2095 	vsf_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
2096 	vsf_perimeter(atari_plot_vdi_handle, 1);
2097 	vsf_interior(atari_plot_vdi_handle, 0);
2098 	v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius);
2099     } else {
2100 	vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
2101 	vsf_perimeter(atari_plot_vdi_handle, 0);
2102 	vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
2103 	v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius);
2104     }
2105     return NSERROR_OK;
2106 }
2107 
2108 
2109 /**
2110  * Plots a line
2111  *
2112  * plot a line from (x0,y0) to (x1,y1). Coordinates are at
2113  *  centre of line width/thickness.
2114  *
2115  * \param ctx The current redraw context.
2116  * \param pstyle Style controlling the line plot.
2117  * \param line A rectangle defining the line to be drawn
2118  * \return NSERROR_OK on success else error code.
2119  */
2120 static nserror
plot_line(const struct redraw_context * ctx,const plot_style_t * pstyle,const struct rect * line)2121 plot_line(const struct redraw_context *ctx,
2122 	  const plot_style_t *pstyle,
2123 	  const struct rect *line)
2124 {
2125     short pxy[4];
2126     uint32_t lt;
2127     int sw = plot_style_fixed_to_int(pstyle->stroke_width);
2128 
2129     if (((line->x0 < 0) && (line->x1 < 0)) ||
2130 	((line->y0 < 0) && (line->y1 < 0))) {
2131 	return NSERROR_OK;
2132     }
2133 
2134     pxy[0] = view.x + MAX(0, line->x0);
2135     pxy[1] = view.y + MAX(0, line->y0);
2136     pxy[2] = view.x + MAX(0, line->x1);
2137     pxy[3] = view.y + MAX(0, line->y1);
2138 
2139     if ((line->y0 > view.h-1) && (line->y1 > view.h-1)) {
2140 	return NSERROR_OK;
2141     }
2142 
2143     //printf("view: %d,%d,%d,%d\n", view.x, view.y, view.w, view.h);
2144     //printf("line: %d,%d,%d,%d\n", x0,  y0,  x1,  y1);
2145 
2146     //plot_vdi_clip(true);
2147 
2148     if (sw == 0) {
2149 	sw = 1;
2150     }
2151     NSLT2VDI(lt, pstyle)
2152 	vsl_type(atari_plot_vdi_handle, (lt&0x0F));
2153     /* if the line style is not available within VDI system,define own style: */
2154     if ((lt&0x0F) == 7 ) {
2155 	vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8));
2156     }
2157     vsl_width(atari_plot_vdi_handle, (short)sw);
2158     vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
2159     v_pline(atari_plot_vdi_handle, 2, (short *)&pxy );
2160     //plot_vdi_clip(false);
2161 
2162     return NSERROR_OK;
2163 }
2164 
2165 
2166 /**
2167  * Plots a rectangle.
2168  *
2169  * The rectangle can be filled an outline or both controlled
2170  *  by the plot style The line can be solid, dotted or
2171  *  dashed. Top left corner at (x0,y0) and rectangle has given
2172  *  width and height.
2173  *
2174  * \param ctx The current redraw context.
2175  * \param pstyle Style controlling the rectangle plot.
2176  * \param rect A rectangle defining the line to be drawn
2177  * \return NSERROR_OK on success else error code.
2178  */
2179 static nserror
plot_rectangle(const struct redraw_context * ctx,const plot_style_t * pstyle,const struct rect * rect)2180 plot_rectangle(const struct redraw_context *ctx,
2181 	       const plot_style_t *pstyle,
2182 	       const struct rect *rect)
2183 {
2184     short pxy[4];
2185     GRECT r, rclip, sclip;
2186     int sw = plot_style_fixed_to_int(pstyle->stroke_width);
2187     uint32_t lt;
2188 
2189     /* current canvas clip: */
2190     rclip.g_x = view.clipping.x0;
2191     rclip.g_y = view.clipping.y0;
2192     rclip.g_w = view.clipping.x1 - view.clipping.x0;
2193     rclip.g_h = view.clipping.y1 - view.clipping.y0;
2194 
2195     /* physical clipping: */
2196     sclip.g_x = rclip.g_x;
2197     sclip.g_y = rclip.g_y;
2198     sclip.g_w = view.vis_w;
2199     sclip.g_h = view.vis_h;
2200 
2201     rc_intersect(&sclip, &rclip);
2202     r.g_x = rect->x0;
2203     r.g_y = rect->y0;
2204     r.g_w = rect->x1 - rect->x0;
2205     r.g_h = rect->y1 - rect->y0;
2206 
2207     if (!rc_intersect(&rclip, &r)) {
2208 	return NSERROR_OK;
2209     }
2210 
2211     if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
2212 	/*
2213 	  manually draw the line, because we do not need vdi clipping
2214 	  for vertical / horizontal line draws.
2215 	*/
2216 	if (sw == 0)
2217 	    sw = 1;
2218 
2219 	NSLT2VDI(lt, pstyle);
2220 	vsl_type(atari_plot_vdi_handle, (lt&0x0F));
2221 	/*
2222 	  if the line style is not available within VDI system,
2223 	  define own style:
2224 	*/
2225 	if ((lt&0x0F) == 7 ) {
2226 	    vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8));
2227 	}
2228 	vsl_width(atari_plot_vdi_handle, (short)sw );
2229 	vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
2230 	/* top border: */
2231 	if (r.g_y == rect->y0) {
2232 	    pxy[0] = view.x + r.g_x;
2233 	    pxy[1] = view.y + r.g_y ;
2234 	    pxy[2] = view.x + r.g_x + r.g_w;
2235 	    pxy[3] = view.y + r.g_y;
2236 	    v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
2237 	}
2238 
2239 	/* right border: */
2240 	if (r.g_x + r.g_w == rect->x1 ) {
2241 	    pxy[0] = view.x + r.g_x + r.g_w;
2242 	    pxy[1] = view.y + r.g_y;
2243 	    pxy[2] = view.x + r.g_x + r.g_w;
2244 	    pxy[3] = view.y + r.g_y + r.g_h;
2245 	    v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
2246 	}
2247 
2248 	/* bottom border: */
2249 	if ( r.g_y+r.g_h == rect->y1 ) {
2250 	    pxy[0] = view.x + r.g_x;
2251 	    pxy[1] = view.y + r.g_y+r.g_h;
2252 	    pxy[2] = view.x + r.g_x+r.g_w;
2253 	    pxy[3] = view.y + r.g_y+r.g_h;
2254 	    v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
2255 	}
2256 
2257 	/* left border: */
2258 	if ( r.g_x == rect->x0 ) {
2259 	    pxy[0] = view.x + r.g_x;
2260 	    pxy[1] = view.y + r.g_y;
2261 	    pxy[2] = view.x + r.g_x;
2262 	    pxy[3] = view.y + r.g_y + r.g_h;
2263 	    v_pline(atari_plot_vdi_handle, 2, (short *)&pxy);
2264 	}
2265     }
2266 
2267     if (pstyle->fill_type != PLOT_OP_TYPE_NONE ) {
2268 	short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ?
2269 	    plot_style_fixed_to_int(pstyle->stroke_width) : 0;
2270 
2271 	vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
2272 	vsf_perimeter(atari_plot_vdi_handle, 0);
2273 	vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
2274 
2275 
2276 	pxy[0] = view.x + r.g_x + stroke_width;
2277 	pxy[1] = view.y + r.g_y + stroke_width;
2278 	pxy[2] = view.x + r.g_x + r.g_w -1 - stroke_width;
2279 	pxy[3] = view.y + r.g_y + r.g_h -1 - stroke_width;
2280 
2281 	vsf_style(atari_plot_vdi_handle, 1);
2282 	v_bar(atari_plot_vdi_handle, (short*)&pxy);
2283     }
2284 
2285     return NSERROR_OK;
2286 }
2287 
2288 
2289 /**
2290  * Plot a polygon
2291  *
2292  * Plots a filled polygon with straight lines between
2293  * points. The lines around the edge of the ploygon are not
2294  * plotted. The polygon is filled with the non-zero winding
2295  * rule.
2296  *
2297  * \param ctx The current redraw context.
2298  * \param pstyle Style controlling the polygon plot.
2299  * \param p verticies of polygon
2300  * \param n number of verticies.
2301  * \return NSERROR_OK on success else error code.
2302  */
2303 static nserror
plot_polygon(const struct redraw_context * ctx,const plot_style_t * pstyle,const int * p,unsigned int n)2304 plot_polygon(const struct redraw_context *ctx,
2305 	     const plot_style_t *pstyle,
2306 	     const int *p,
2307 	     unsigned int n)
2308 {
2309     short pxy[n*2];
2310     unsigned int i = 0;
2311 
2312     if (vdi_sysinfo.maxpolycoords > 0)
2313 	assert( (signed int)n < vdi_sysinfo.maxpolycoords);
2314 
2315     vsf_interior(atari_plot_vdi_handle, FIS_SOLID);
2316     vsf_style(atari_plot_vdi_handle, 1);
2317     for (i = 0; i<n*2; i=i+2) {
2318 	pxy[i] = (short)view.x+p[i];
2319 	pxy[i+1] = (short)view.y+p[i+1];
2320     }
2321 
2322     if (pstyle->fill_type == PLOT_OP_TYPE_SOLID) {
2323 	vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour);
2324 	v_fillarea(atari_plot_vdi_handle, n, (short*)&pxy);
2325     } else {
2326 	pxy[n*2]=pxy[0];
2327 	pxy[n*2+1]=pxy[1];
2328 	vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour);
2329 	v_pline(atari_plot_vdi_handle, n+1,  (short *)&pxy);
2330     }
2331 
2332     return NSERROR_OK;
2333 }
2334 
2335 
2336 /**
2337  * Plots a path.
2338  *
2339  * Path plot consisting of cubic Bezier curves. Line and fill colour is
2340  *  controlled by the plot style.
2341  *
2342  * \param ctx The current redraw context.
2343  * \param pstyle Style controlling the path plot.
2344  * \param p elements of path
2345  * \param n nunber of elements on path
2346  * \param transform A transform to apply to the path.
2347  * \return NSERROR_OK on success else error code.
2348  */
2349 static nserror
plot_path(const struct redraw_context * ctx,const plot_style_t * pstyle,const float * p,unsigned int n,const float transform[6])2350 plot_path(const struct redraw_context *ctx,
2351 	  const plot_style_t *pstyle,
2352 	  const float *p,
2353 	  unsigned int n,
2354 	  const float transform[6])
2355 {
2356     /** \todo Implement atari path plot */
2357     return NSERROR_OK;
2358 }
2359 
2360 
2361 /**
2362  * Plot a bitmap
2363  *
2364  * Tiled plot of a bitmap image. (x,y) gives the top left
2365  * coordinate of an explicitly placed tile. From this tile the
2366  * image can repeat in all four directions -- up, down, left
2367  * and right -- to the extents given by the current clip
2368  * rectangle.
2369  *
2370  * The bitmap_flags say whether to tile in the x and y
2371  * directions. If not tiling in x or y directions, the single
2372  * image is plotted. The width and height give the dimensions
2373  * the image is to be scaled to.
2374  *
2375  * \param ctx The current redraw context.
2376  * \param bitmap The bitmap to plot
2377  * \param x The x coordinate to plot the bitmap
2378  * \param y The y coordiante to plot the bitmap
2379  * \param width The width of area to plot the bitmap into
2380  * \param height The height of area to plot the bitmap into
2381  * \param bg the background colour to alpha blend into
2382  * \param flags the flags controlling the type of plot operation
2383  * \return NSERROR_OK on success else error code.
2384  */
2385 static nserror
plot_bitmap(const struct redraw_context * ctx,struct bitmap * bitmap,int x,int y,int width,int height,colour bg,bitmap_flags_t flags)2386 plot_bitmap(const struct redraw_context *ctx,
2387 	    struct bitmap *bitmap,
2388 	    int x, int y,
2389 	    int width,
2390 	    int height,
2391 	    colour bg,
2392 	    bitmap_flags_t flags)
2393 {
2394     struct bitmap * bm = NULL;
2395     bool repeat_x = (flags & BITMAPF_REPEAT_X);
2396     bool repeat_y = (flags & BITMAPF_REPEAT_Y);
2397     int bmpw,bmph;
2398     struct rect clip = {0,0,0,0};
2399 
2400     bmpw = atari_bitmap_get_width(bitmap);
2401     bmph = atari_bitmap_get_height(bitmap);
2402 
2403     if(view.scale != 1.0){
2404 	width = (int)(((float)width)*view.scale);
2405 	height = (int)(((float)height)*view.scale);
2406     }
2407 
2408     if ( repeat_x || repeat_y ) {
2409 	plot_get_clip(&clip);
2410 	if (repeat_x && width == 1 && repeat_y && height == 1 ) {
2411 	    width = MAX( width, clip.x1 - x );
2412 	    height = MAX( height,  clip.y1 - y );
2413 	} else if (repeat_x && width == 1 ) {
2414 	    width = MAX( width, clip.x1 - x);
2415 	} else if (repeat_y && height == 1) {
2416 	    height = MAX( height, clip.y1 - y );
2417 	}
2418     }
2419 
2420     if (width != bmpw || height != bmph) {
2421 	atari_bitmap_resize(bitmap, hermes_res_h, &nsfmt, width, height );
2422 	if (bitmap->resized) {
2423 	    bm = bitmap->resized;
2424 	} else {
2425 	    bm = bitmap;
2426 	}
2427     } else {
2428 	bm = bitmap;
2429     }
2430 
2431     /* out of memory? */
2432     if (bm == NULL) {
2433 	printf("plot: out of memory! bmp: %p, bmpres: %p\n",
2434 	       bitmap, bitmap->resized );
2435 	return NSERROR_NOMEM;
2436     }
2437 
2438     if (!(repeat_x || repeat_y) ) {
2439 	plot_blit_bitmap(bm, x, y, bg, flags);
2440     } else {
2441 	int xf,yf;
2442 	int xoff = x;
2443 	int yoff = y;
2444 
2445 	if (yoff > clip.y0) {
2446 	    yoff = (clip.y0 - height) + ((yoff - clip.y0) % height);
2447 	}
2448 	if (xoff > clip.x0) {
2449 	    xoff = (clip.x0 - width) + ((xoff - clip.x0) % width);
2450 	}
2451 	/* for now, repeating just works in the rigth / down direction */
2452 	/*
2453 	  if( repeat_x == true )
2454 	  xoff = clip.x0;
2455 	  if(repeat_y == true )
2456 	  yoff = clip.y0;
2457 	*/
2458 
2459 	for (xf = xoff; xf < clip.x1; xf += width ) {
2460 	    for (yf = yoff; yf < clip.y1; yf += height ) {
2461 		plot_blit_bitmap(bm, xf, yf, bg, flags );
2462 		if (!repeat_y) {
2463 		    break;
2464 		}
2465 	    }
2466 	    if (!repeat_x) {
2467 		break;
2468 	    }
2469 	}
2470     }
2471 
2472     return NSERROR_OK;
2473 }
2474 
2475 
2476 /**
2477  * Text plotting.
2478  *
2479  * \param ctx The current redraw context.
2480  * \param fstyle plot style for this text
2481  * \param x x coordinate
2482  * \param y y coordinate
2483  * \param text UTF-8 string to plot
2484  * \param length length of string, in bytes
2485  * \return NSERROR_OK on success else error code.
2486  */
2487 static nserror
plot_text(const struct redraw_context * ctx,const struct plot_font_style * fstyle,int x,int y,const char * text,size_t length)2488 plot_text(const struct redraw_context *ctx,
2489 	  const struct plot_font_style *fstyle,
2490 	  int x,
2491 	  int y,
2492 	  const char *text,
2493 	  size_t length)
2494 {
2495     if (view.scale != 1.0) {
2496 	plot_font_style_t newstyle = *fstyle;
2497 	newstyle.size = (int)((float)fstyle->size*view.scale);
2498 	fplotter->text(fplotter, x, y, text, length, &newstyle);
2499     } else {
2500 	fplotter->text(fplotter, x, y, text, length, fstyle);
2501     }
2502 
2503     return NSERROR_OK;
2504 }
2505 
2506 /** atari plottr operation table */
2507 const struct plotter_table atari_plotters = {
2508     .rectangle = plot_rectangle,
2509     .line = plot_line,
2510     .polygon = plot_polygon,
2511     .clip = plot_clip,
2512     .text = plot_text,
2513     .disc = plot_disc,
2514     .arc = plot_arc,
2515     .bitmap = plot_bitmap,
2516     .path = plot_path,
2517     .flush = NULL,
2518     .group_start = NULL,
2519     .group_end = NULL,
2520     .option_knockout = true
2521 };
2522