/* * Copyright 2010 Ole Loots * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * NetSurf is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "atari/plot/eddi.h" #include "atari/plot/plotter.h" #include "atari/plot/plotter_vdi.h" /* assign vdi line style to dst ( netsurf type ) */ #define NSLT2VDI(dst, src) \ dst = 0;\ switch( src->stroke_type ) {\ case PLOT_OP_TYPE_DOT: \ dst = (0xAAAA00 | 7);\ break;\ case PLOT_OP_TYPE_DASH:\ dst = 3; \ break;\ case PLOT_OP_TYPE_SOLID:\ case PLOT_OP_TYPE_NONE:\ default:\ dst = 1;\ break;\ }\ static int dtor( GEM_PLOTTER self ); static int resize( GEM_PLOTTER self, int w, int h ); static int move( GEM_PLOTTER self, short x, short y ); static int lock( GEM_PLOTTER self ); static int unlock( GEM_PLOTTER self ); static int put_pixel(GEM_PLOTTER self, int x, int y, int color ); static int copy_rect( GEM_PLOTTER self, GRECT src, GRECT dst ); static int set_clip(GEM_PLOTTER self, const struct rect * clip); static int get_clip( GEM_PLOTTER self, struct rect * out ); static int arc(GEM_PLOTTER self,int x, int y, int radius, int angle1, int angle2, const plot_style_t * pstyle); static int disc(GEM_PLOTTER self,int x, int y, int radius, const plot_style_t * pstyle); static int line(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle); static int rectangle(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle); static int polygon(GEM_PLOTTER self,const int *p, unsigned int n, const plot_style_t * pstyle); static int path(GEM_PLOTTER self,const float *p, unsigned int n, int fill, float width, int c, const float transform[6]); static int bitmap_resize( GEM_PLOTTER self, struct bitmap * img, int nw, int nh ); static int bitmap_convert( GEM_PLOTTER self, struct bitmap * img, int x, int y, GRECT * clip,uint32_t bg,uint32_t flags, MFDB *out ); static int bitmap_convert_8( GEM_PLOTTER self, struct bitmap * img,int x, int y, GRECT * clip,uint32_t bg,uint32_t flags, MFDB *out ); static int bitmap( GEM_PLOTTER self, struct bitmap * bmp, int x, int y, unsigned long bg, unsigned long flags ); static int plot_mfdb( GEM_PLOTTER self, GRECT * where, MFDB * mfdb, unsigned char fgcolor, uint32_t flags); static int text(GEM_PLOTTER self, int x, int y, const char *text,size_t length, const plot_font_style_t *fstyle); static inline void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val ); static inline unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y ); /* Set clipping for current framebuffer */ static int plotter_std_clip(GEM_PLOTTER self, const struct rect * clip); extern struct s_vdi_sysinfo vdi_sysinfo; static HermesHandle hermes_pal_h; /* hermes palette handle */ static HermesHandle hermes_cnv_h; /* hermes converter instance handle */ static HermesHandle hermes_res_h; static short prev_vdi_clip[4]; static struct bitmap snapshot; #ifdef WITH_8BPP_SUPPORT static unsigned short sys_pal[256][3]; /*RGB*/ static unsigned short pal[256][3]; /*RGB*/ static char rgb_lookup[256][4]; extern unsigned short vdi_web_pal[216][3]; #endif static inline void vsl_rgbcolor( short vdih, uint32_t cin ) { if( vdi_sysinfo.scr_bpp > 8 ) { unsigned short c[4]; rgb_to_vdi1000( (unsigned char*)&cin, (unsigned short*)&c ); vs_color( vdih, OFFSET_CUSTOM_COLOR, (unsigned short*)&c[0] ); vsl_color( vdih, OFFSET_CUSTOM_COLOR ); } else { if( vdi_sysinfo.scr_bpp >= 4 ){ vsl_color( vdih, RGB_TO_VDI(cin) ); } else vsl_color( vdih, BLACK ); } } static inline void vsf_rgbcolor( short vdih, uint32_t cin ) { if( vdi_sysinfo.scr_bpp > 8 ) { unsigned short c[4]; rgb_to_vdi1000( (unsigned char*)&cin, (unsigned short*)&c ); vs_color( vdih, OFFSET_CUSTOM_COLOR, &c[0] ); vsf_color( vdih, OFFSET_CUSTOM_COLOR ); } else { if( vdi_sysinfo.scr_bpp >= 4 ){ vsf_color( vdih, RGB_TO_VDI(cin) ); } else vsf_color( vdih, WHITE ); } } static int set_clip(GEM_PLOTTER self, const struct rect * clip) { // FIXME: consider the canvas size VIEW( self ).clipping.x0 = clip->x0; VIEW( self ).clipping.y0 = clip->y0; VIEW( self ).clipping.x1 = clip->x1; VIEW( self ).clipping.y1 = clip->y1; return ( 1 ); } static int get_clip( GEM_PLOTTER self, struct rect * out ) { out->x0 = VIEW( self ).clipping.x0; out->y0 = VIEW( self ).clipping.y0; out->x1 = VIEW( self ).clipping.x1; out->y1 = VIEW( self ).clipping.y1; return( 1 ); } /* Get current visible coords */ static inline void plotter_get_visible_grect( GEM_PLOTTER self, GRECT * out ) { out->g_x = VIEW( self ).vis_x; out->g_y = VIEW( self ).vis_y; out->g_w = VIEW( self ).vis_w; out->g_h = VIEW( self ).vis_h; } /* 1. calculate visible area of framebuffer in coords relative to framebuffer position result: this function should calculates an rectangle relative to the plot origin and size. If the ploter coords do not fall within the screen region, all values of the region are set to zero. */ static inline void update_visible_rect( GEM_PLOTTER p ) { GRECT screen; GRECT common; GRECT frame; screen.g_x = 0; screen.g_y = 0; screen.g_w = vdi_sysinfo.scr_w; screen.g_h = vdi_sysinfo.scr_h; common.g_x = frame.g_x = VIEW(p).x; common.g_y = frame.g_y = VIEW(p).y; common.g_w = frame.g_w = VIEW(p).w; common.g_h = frame.g_h = VIEW(p).h; if( rc_intersect( &screen, &common ) ) { VIEW(p).vis_w = common.g_w; VIEW(p).vis_h = common.g_h; if( VIEW(p).x < screen.g_x ) VIEW(p).vis_x = frame.g_w - common.g_w; else VIEW(p).vis_x = 0; if( VIEW(p).y get_clip( self, &c ); vq_extnd( self->vdi_handle, 1, (short*)&vdiflags); prev_vdi_clip[0] = vdiflags[45]; prev_vdi_clip[1] = vdiflags[46]; prev_vdi_clip[2] = vdiflags[47]; prev_vdi_clip[3] = vdiflags[48]; newclip[0] = VIEW(self).x + MAX(c.x0, 0); newclip[1] = VIEW(self).y + MAX(c.y0, 0); newclip[2] = MIN(VIEW(self).x+VIEW(self).w, newclip[0] + (c.x1 - c.x0) )-1; newclip[3] = MIN(VIEW(self).y+VIEW(self).h, newclip[1] + (c.y1 - c.y0) )-1; vs_clip( self->vdi_handle, 1, (short*)&newclip ); } else { vs_clip( self->vdi_handle, 1, (short *)&prev_vdi_clip ); } } int ctor_plotter_vdi( GEM_PLOTTER self , GRECT * loc_size ) { int retval = 0; int i; struct rect clip; self->dtor = dtor; self->resize= resize; self->move = move; self->lock = lock; self->unlock = unlock; self->put_pixel = put_pixel; self->copy_rect = copy_rect; self->set_clip = set_clip; self->get_clip = get_clip; self->arc = arc; self->disc = disc; self->line = line; self->rectangle = rectangle; self->polygon = polygon; self->path = path; self->bitmap = bitmap; self->bitmap_resize = bitmap_resize; /* override virtual bpp - must be in sync with screen for this driver: */ self->bpp_virt = app.nplanes; #ifdef WITH_8BPP_SUPPORT self->bitmap_convert =(app.nplanes > 8) ? bitmap_convert : bitmap_convert_8; #else self->bitmap_convert = bitmap_convert; #endif self->plot_mfdb = plot_mfdb; self->text = text; LOG(("Screen: x: %d, y: %d\n", vdi_sysinfo.scr_w, vdi_sysinfo.scr_h)); self->priv_data = malloc( sizeof(struct s_vdi_priv_data) ); if( self->priv_data == NULL ) return( 0-ERR_NO_MEM ); memset( self->priv_data, 0, sizeof(struct s_vdi_priv_data) ); memset( &VIEW(self), 0, sizeof( struct s_view) ); VIEW( self ).x = loc_size->g_x; VIEW( self ).y = loc_size->g_y; VIEW( self ).w = loc_size->g_w; VIEW( self ).h = loc_size->g_h; DUMMY_PRIV(self)->bufops = 0; DUMMY_PRIV(self)->size_buf_packed = 0; DUMMY_PRIV(self)->size_buf_planar = 0; DUMMY_PRIV(self)->buf_packed = NULL; DUMMY_PRIV(self)->buf_planar = NULL; if( vdi_sysinfo.vdiformat == VDI_FORMAT_PACK ) { self->bpp_virt = vdi_sysinfo.scr_bpp; } else { DUMMY_PRIV(self)->bufops = C2P; self->bpp_virt = 8; } VIEW(self).mem = NULL; update_visible_rect( self ); clip.x0 = 0; clip.y0 = 0; clip.x1 = VIEW(self).w; clip.y1 = VIEW(self).h; self->set_clip( self, &clip ); assert( Hermes_Init() ); /* store system palette & setup the new (web) palette: */ #ifdef WITH_8BPP_SUPPORT i = 0; unsigned char * col; unsigned char rgbcol[4]; unsigned char graytone=0; if( app.nplanes <= 8 ){ for( i=0; i<=255; i++ ) { // get the current color and save it for restore: vq_color(self->vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] ); if( i= 8 ) { if ( i < OFFSET_CUST_PAL ){ pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0]; pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1]; pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2]; //set the new palette color to websafe value: vs_color( self->vdi_handle, i, &pal[i][0] ); } if( i >= OFFSET_CUST_PAL && ivdi_handle, i, &pal[i][0] ); graytone++; } } vdi1000_to_rgb( &pal[i][0], &rgb_lookup[i][0] ); } } else { /* no need to change the palette - its application specific */ } #endif unsigned long flags = ( self->flags & PLOT_FLAG_DITHER ) ? HERMES_CONVERT_DITHER : 0; hermes_cnv_h = Hermes_ConverterInstance( flags ); assert( hermes_cnv_h ); hermes_res_h = Hermes_ConverterInstance( flags ); assert( hermes_res_h ); /* set up the src & dst format: */ /* netsurf uses RGBA ... */ DUMMY_PRIV(self)->nsfmt.a = 0xFFUL; DUMMY_PRIV(self)->nsfmt.b = 0x0FF00UL; DUMMY_PRIV(self)->nsfmt.g = 0x0FF0000UL; DUMMY_PRIV(self)->nsfmt.r = 0x0FF000000UL; DUMMY_PRIV(self)->nsfmt.bits = 32; DUMMY_PRIV(self)->nsfmt.indexed = false; DUMMY_PRIV(self)->nsfmt.has_colorkey = false; DUMMY_PRIV(self)->vfmt.r = vdi_sysinfo.mask_r; DUMMY_PRIV(self)->vfmt.g = vdi_sysinfo.mask_g; DUMMY_PRIV(self)->vfmt.b = vdi_sysinfo.mask_b; DUMMY_PRIV(self)->vfmt.a = vdi_sysinfo.mask_a; DUMMY_PRIV(self)->vfmt.bits = self->bpp_virt; DUMMY_PRIV(self)->vfmt.indexed = ( app.nplanes <= 8 ) ? 1 : 0; DUMMY_PRIV(self)->vfmt.has_colorkey = 0; return( 1 ); } static int dtor( GEM_PLOTTER self ) { int i=0; LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__)); if( VIEW(self).mem ) free( VIEW(self).mem ); #ifdef WITH_8BPP_SUPPORT if( DUMMY_PRIV(self)->vfmt.indexed ){ for( i=OFFSET_WEB_PAL; ivdi_handle, i, &sys_pal[i][0] ); } } #endif /* close Hermes stuff: */ Hermes_ConverterReturn( hermes_cnv_h ); Hermes_Done(); if( self->priv_data != NULL ){ if( DUMMY_PRIV(self)->buf_packed ) free( DUMMY_PRIV(self)->buf_packed ); if( DUMMY_PRIV(self)->buf_planar ) free( DUMMY_PRIV(self)->buf_planar ); free( self->priv_data ); } snapshot_destroy( self ); return( 1 ); } static int resize( GEM_PLOTTER self, int w, int h ) { if( w == VIEW(self).w && h == VIEW(self).h ) return( 1 ); struct rect newclip = { 0, 0, w-1, h-1 }; VIEW(self).w = w; VIEW(self).h = h; update_visible_rect( self ); set_clip( self, &newclip); LOG(("%s: %s\n", (char*)__FILE__, (char*)__FUNCTION__)); return( 1 ); } static int move( GEM_PLOTTER self,short x, short y ) { bool upd; if(x == VIEW(self).x && y == VIEW(self).y ){ return 1; } LOG(("%s: x: %d, y: %d\n",(char*)__FUNCTION__, x, y)); VIEW(self).x = x; VIEW(self).y = y; update_visible_rect( self ); return( 1 ); } static int lock( GEM_PLOTTER self ) { LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__)); if( (self->flags & PLOT_FLAG_LOCKED) != 0 ) return(1); self->flags |= PLOT_FLAG_LOCKED; if( !wind_update(BEG_UPDATE|0x100) ) return(0); if( !wind_update(BEG_MCTRL|0x100) ){ wind_update(END_UPDATE); return(0); } graf_mouse(M_OFF, NULL); return( 1 ); } static int unlock( GEM_PLOTTER self ) { LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__)); if( (self->flags & PLOT_FLAG_LOCKED) == 0 ) return(1); self->flags &= ~PLOT_FLAG_LOCKED; wind_update(END_MCTRL); wind_update(END_UPDATE); graf_mouse(M_ON, NULL); return( 1 ); } static int put_pixel(GEM_PLOTTER self, int x, int y, int color ) { LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__)); return( 1 ); } /* copy an rectangle from the plot buffer to screen */ /* because this is an on-screen plotter, this is an screen to screen copy. */ static int copy_rect( GEM_PLOTTER self, GRECT src, GRECT dst ) { MFDB devmf; MFDB scrmf; short pxy[8]; GRECT vis; /* clip to visible rect, only needed for onscreen renderer: */ plotter_get_visible_grect( self, &vis ); if( !rc_intersect(&vis, &src) ) return 1; if( !rc_intersect(&vis, &dst) ) return 1; src.g_x = VIEW(self).x + src.g_x; src.g_y = VIEW(self).y + src.g_y; dst.g_x = VIEW(self).x + dst.g_x; dst.g_y = VIEW(self).y + dst.g_y; devmf.fd_addr = NULL; devmf.fd_w = src.g_w; devmf.fd_h = src.g_h; devmf.fd_wdwidth = 0; devmf.fd_stand = 0; devmf.fd_nplanes = 0; devmf.fd_r1 = devmf.fd_r2 = devmf.fd_r3 = 0; scrmf.fd_addr = NULL; scrmf.fd_w = dst.g_w; scrmf.fd_h = dst.g_h; scrmf.fd_wdwidth = 0 ; scrmf.fd_stand = 0; scrmf.fd_nplanes = 0; scrmf.fd_r1 = scrmf.fd_r2 = scrmf.fd_r3 = 0; pxy[0] = src.g_x; pxy[1] = src.g_y; pxy[2] = pxy[0] + src.g_w-1; pxy[3] = pxy[1] + src.g_h-1; pxy[4] = dst.g_x; pxy[5] = dst.g_y; pxy[6] = pxy[4] + dst.g_w-1; pxy[7] = pxy[5] + dst.g_h-1; self->lock( self ); vro_cpyfm( self->vdi_handle, S_ONLY, (short*)&pxy, &devmf, &scrmf); self->unlock( self ); return( 1 ); } static int arc(GEM_PLOTTER self,int x, int y, int radius, int angle1, int angle2, const plot_style_t * pstyle) { //plotter_vdi_clip( self, 1); vswr_mode( self->vdi_handle, MD_REPLACE ); if( pstyle->fill_type == PLOT_OP_TYPE_NONE ) return 1; if( pstyle->fill_type != PLOT_OP_TYPE_SOLID) { vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour); vsf_perimeter( self->vdi_handle, 1); vsf_interior( self->vdi_handle, 1 ); v_arc( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius, angle1*10, angle2*10 ); } else { vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour); vsl_width( self->vdi_handle, 1 ); vsf_perimeter( self->vdi_handle, 1); v_arc( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius, angle1*10, angle2*10 ); } //plotter_vdi_clip( self, 0); return ( 1 ); } static int disc(GEM_PLOTTER self,int x, int y, int radius, const plot_style_t * pstyle) { plotter_vdi_clip( self, 1); if( pstyle->fill_type != PLOT_OP_TYPE_SOLID) { vsf_rgbcolor( self->vdi_handle, pstyle->stroke_colour ); vsf_perimeter( self->vdi_handle, 1); vsf_interior( self->vdi_handle, 0 ); v_circle( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius ); } else { vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour ); vsf_perimeter( self->vdi_handle, 0); vsf_interior( self->vdi_handle, FIS_SOLID ); v_circle( self->vdi_handle, VIEW(self).x + x, VIEW(self).y + y, radius ); } plotter_vdi_clip( self, 0); return ( 1 ); } static int line(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle) { short pxy[4]; uint32_t lt; int sw = pstyle->stroke_width; pxy[0] = VIEW(self).x + x0; pxy[1] = VIEW(self).y + y0; pxy[2] = VIEW(self).x + x1; pxy[3] = VIEW(self).y + y1; plotter_vdi_clip( self, 1); if( sw == 0) sw = 1; NSLT2VDI(lt, pstyle) vsl_type( self->vdi_handle, (lt&0x0F) ); /* if the line style is not available within VDI system,define own style: */ if( (lt&0x0F) == 7 ){ vsl_udsty(self->vdi_handle, ((lt&0xFFFF00) >> 8) ); } vsl_width( self->vdi_handle, (short)sw ); vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour ); v_pline(self->vdi_handle, 2, (short *)&pxy ); plotter_vdi_clip( self, 0); return ( 1 ); } static int rectangle(GEM_PLOTTER self,int x0, int y0, int x1, int y1, const plot_style_t * pstyle) { short pxy[4]; GRECT r, rclip, sclip; int sw = pstyle->stroke_width; uint32_t lt; /* current canvas clip: */ rclip.g_x = VIEW( self ).clipping.x0; rclip.g_y = VIEW( self ).clipping.y0; rclip.g_w = VIEW( self ).clipping.x1 - VIEW( self ).clipping.x0; rclip.g_h = VIEW( self ).clipping.y1 - VIEW( self ).clipping.y0; /* physical clipping: */ sclip.g_x = rclip.g_x; sclip.g_y = rclip.g_y; sclip.g_w = VIEW(self).vis_w; sclip.g_h = VIEW(self).vis_h; rc_intersect(&sclip, &rclip); r.g_x = x0; r.g_y = y0; r.g_w = x1 - x0; r.g_h = y1 - y0; if( !rc_intersect( &rclip, &r ) ) { return( 1 ); } if( pstyle->stroke_type != PLOT_OP_TYPE_NONE ){ /* manually draw the line, because we do not need vdi clipping for vertical / horizontal line draws. */ if( sw == 0) sw = 1; NSLT2VDI(lt, pstyle); vsl_type( self->vdi_handle, (lt&0x0F) ); /* if the line style is not available within VDI system, define own style: */ if( (lt&0x0F) == 7 ){ vsl_udsty(self->vdi_handle, ((lt&0xFFFF00) >> 8) ); } vsl_width( self->vdi_handle, (short)sw ); vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour ); /* top border: */ if( r.g_y == y0){ pxy[0] = VIEW(self).x + r.g_x; pxy[1] = VIEW(self).y + r.g_y ; pxy[2] = VIEW(self).x + r.g_x + r.g_w; pxy[3] = VIEW(self).y + r.g_y; v_pline(self->vdi_handle, 2, (short *)&pxy ); } /* right border: */ if( r.g_x + r.g_w == x1 ){ pxy[0] = VIEW(self).x + r.g_x + r.g_w; pxy[1] = VIEW(self).y + r.g_y; pxy[2] = VIEW(self).x + r.g_x + r.g_w; pxy[3] = VIEW(self).y + r.g_y + r.g_h; v_pline(self->vdi_handle, 2, (short *)&pxy ); } /* bottom border: */ if( r.g_y+r.g_h == y1 ){ pxy[0] = VIEW(self).x + r.g_x; pxy[1] = VIEW(self).y + r.g_y+r.g_h; pxy[2] = VIEW(self).x + r.g_x+r.g_w; pxy[3] = VIEW(self).y + r.g_y+r.g_h; v_pline(self->vdi_handle, 2, (short *)&pxy ); } /* left border: */ if( r.g_x == x0 ){ pxy[0] = VIEW(self).x + r.g_x; pxy[1] = VIEW(self).y + r.g_y; pxy[2] = VIEW(self).x + r.g_x; pxy[3] = VIEW(self).y + r.g_y + r.g_h; v_pline(self->vdi_handle, 2, (short *)&pxy ); } } if( pstyle->fill_type != PLOT_OP_TYPE_NONE ){ short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ? pstyle->stroke_width : 0; vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour ); vsf_perimeter( self->vdi_handle, 0); vsf_interior( self->vdi_handle, FIS_SOLID ); pxy[0] = VIEW(self).x + r.g_x + stroke_width; pxy[1] = VIEW(self).y + r.g_y + stroke_width; pxy[2] = VIEW(self).x + r.g_x + r.g_w -1 - stroke_width ; pxy[3] = VIEW(self).y + r.g_y + r.g_h -1 - stroke_width; vsf_style( self->vdi_handle, 1); v_bar( self->vdi_handle, (short*)&pxy ); } return ( 1 ); } static int polygon(GEM_PLOTTER self,const int *p, unsigned int n, const plot_style_t * pstyle) { short pxy[n*2]; unsigned int i=0; short d[4]; if( vdi_sysinfo.maxpolycoords > 0 ) assert( (signed int)n < vdi_sysinfo.maxpolycoords ); plotter_vdi_clip( self, 1); vsf_interior( self->vdi_handle, FIS_SOLID ); vsf_style( self->vdi_handle, 1); for( i = 0; ifill_type == PLOT_OP_TYPE_SOLID){ vsf_rgbcolor( self->vdi_handle, pstyle->fill_colour); v_fillarea(self->vdi_handle, n, (short*)&pxy); } else { pxy[n*2]=pxy[0]; pxy[n*2+1]=pxy[1]; vsl_rgbcolor( self->vdi_handle, pstyle->stroke_colour); v_pline(self->vdi_handle, n+1, (short *)&pxy ); } plotter_vdi_clip( self, 0); return ( 1 ); } static int path(GEM_PLOTTER self,const float *p, unsigned int n, int fill, float width, int c, const float transform[6]) { LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__)); return ( 1 ); } static inline uint32_t ablend(uint32_t pixel, uint32_t scrpixel) { int opacity = pixel & 0xFF; int transp = 0x100 - opacity; uint32_t rb, g; pixel >>= 8; scrpixel >>= 8; rb = ((pixel & 0xFF00FF) * opacity + (scrpixel & 0xFF00FF) * transp) >> 8; g = ((pixel & 0x00FF00) * opacity + (scrpixel & 0x00FF00) * transp) >> 8; return ((rb & 0xFF00FF) | (g & 0xFF00)) << 8; } static int bitmap_resize( GEM_PLOTTER self, struct bitmap * img, int nw, int nh ) { HermesFormat fmt; short bpp = bitmap_get_bpp( img ); int stride = bitmap_get_rowstride( img ); int err; if( img->resized != NULL ) { if( img->resized->width != nw || img->resized->height != nh ) { bitmap_destroy( img->resized ); img->resized = NULL; } else { /* the bitmap is already resized */ return( 0 ); } } /* allocate the mem for resized bitmap */ img->resized = bitmap_create_ex( nw, nh, bpp, nw*bpp, 0, NULL ); if( img->resized == NULL ) { printf("W: %d, H: %d, bpp: %d\n", nw, nh, bpp); assert( img->resized ); return ( -ERR_NO_MEM ); } /* allocate an converter, only for resizing */ err = Hermes_ConverterRequest( hermes_res_h, &DUMMY_PRIV(self)->nsfmt, &DUMMY_PRIV(self)->nsfmt ); if( err == 0 ) { return( -ERR_PLOTTER_NOT_AVAILABLE ); } err = Hermes_ConverterCopy( hermes_res_h, img->pixdata, 0, /* x src coord of top left in pixel coords */ 0, /* y src coord of top left in pixel coords */ bitmap_get_width( img ), bitmap_get_height( img ), stride, /* stride as bytes */ img->resized->pixdata, 0, /* x dst coord of top left in pixel coords */ 0, /* y dst coord of top left in pixel coords */ nw, nh, bitmap_get_rowstride( img->resized ) /* stride as bytes */ ); if( err == 0 ) { bitmap_destroy( img->resized ); img->resized = NULL; return( -2 ); } return( 0 ); } // create snapshot, native screen format static MFDB * snapshot_create_native_mfdb( GEM_PLOTTER self, int x, int y, int w, int h) { MFDB scr; short pxy[8]; /* allocate memory for the snapshot */ { int scr_stride = MFDB_STRIDE( w ); int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp ); if( DUMMY_PRIV(self)->size_buf_scr == 0 ){ /* init screen mfdb */ DUMMY_PRIV(self)->buf_scr.fd_addr = malloc( scr_size ); DUMMY_PRIV(self)->size_buf_scr = scr_size; } else { if( scr_size > DUMMY_PRIV(self)->size_buf_scr ) { DUMMY_PRIV(self)->buf_scr.fd_addr = realloc( DUMMY_PRIV(self)->buf_scr.fd_addr, scr_size ); DUMMY_PRIV(self)->size_buf_scr = scr_size; } } if( DUMMY_PRIV(self)->buf_scr.fd_addr == NULL ) { DUMMY_PRIV(self)->size_buf_scr = 0; return( NULL ); } DUMMY_PRIV(self)->buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp; DUMMY_PRIV(self)->buf_scr.fd_w = scr_stride; DUMMY_PRIV(self)->buf_scr.fd_h = h; DUMMY_PRIV(self)->buf_scr.fd_wdwidth = scr_stride >> 4; assert( DUMMY_PRIV(self)->buf_scr.fd_addr != NULL ); } init_mfdb( 0, w, h, 0, &scr ); pxy[0] = x; pxy[1] = y; pxy[2] = pxy[0] + w-1; pxy[3] = pxy[1] + h-1; pxy[4] = 0; pxy[5] = 0; pxy[6] = w-1; pxy[7] = h-1; vro_cpyfm( self->vdi_handle, S_ONLY, (short*)&pxy, &scr, &DUMMY_PRIV(self)->buf_scr ); return( &DUMMY_PRIV(self)->buf_scr ); } // create snapshot, vdi std. format static MFDB * snapshot_create_std_mfdb(GEM_PLOTTER self, int x, int y, int w, int h) { /* allocate memory for the snapshot */ { int scr_stride = MFDB_STRIDE( w ); int scr_size = ( ((scr_stride >> 3) * h) * app.nplanes ); if( DUMMY_PRIV(self)->size_buf_std == 0 ){ /* init screen mfdb */ DUMMY_PRIV(self)->buf_std.fd_addr = malloc( scr_size ); DUMMY_PRIV(self)->size_buf_std = scr_size; } else { if( scr_size > DUMMY_PRIV(self)->size_buf_std ) { DUMMY_PRIV(self)->buf_std.fd_addr = realloc( DUMMY_PRIV(self)->buf_std.fd_addr, scr_size ); DUMMY_PRIV(self)->size_buf_std = scr_size; } } if( DUMMY_PRIV(self)->buf_std.fd_addr == NULL ) { DUMMY_PRIV(self)->size_buf_std = 0; return( NULL ); } DUMMY_PRIV(self)->buf_std.fd_nplanes = app.nplanes; DUMMY_PRIV(self)->buf_std.fd_w = scr_stride; DUMMY_PRIV(self)->buf_std.fd_h = h; DUMMY_PRIV(self)->buf_std.fd_stand = 1; DUMMY_PRIV(self)->buf_std.fd_wdwidth = scr_stride >> 4; assert( DUMMY_PRIV(self)->buf_std.fd_addr != NULL ); } MFDB * native = snapshot_create_native_mfdb( self, x,y,w,h ); assert( native ); vr_trnfm( self->vdi_handle, native, &DUMMY_PRIV(self)->buf_std ); return( &DUMMY_PRIV(self)->buf_std ); } /* This will create an snapshot of the screen in netsurf ABGR format */ static struct bitmap * snapshot_create(GEM_PLOTTER self, int x, int y, int w, int h) { int err; MFDB * native; uint32_t start = clock(); // FIXME: This can be optimized a lot. // 1. do not copy the snapshot to the bitmap buffer // when the format of screen and bitmap equals. // just point the bitmap to the native mfdb. // 2. if we have eddi 1.1, we could optimize that further // make snapshot_create_native_mfdb just returning a pointer // to the screen. native = snapshot_create_native_mfdb( self, x, y, w, h ); if( DUMMY_PRIV(self)->vfmt.bits == 32 ) goto no_copy; /* allocate buffer for result bitmap: */ if( DUMMY_PRIV(self)->buf_scr_compat == NULL ) { DUMMY_PRIV(self)->buf_scr_compat = bitmap_create(w, h, 0); } else { DUMMY_PRIV(self)->buf_scr_compat = bitmap_realloc( w, h, DUMMY_PRIV(self)->buf_scr_compat->bpp, w * DUMMY_PRIV(self)->buf_scr_compat->bpp, BITMAP_GROW, DUMMY_PRIV(self)->buf_scr_compat ); } /* convert screen buffer to ns format: */ err = Hermes_ConverterRequest( hermes_cnv_h, &DUMMY_PRIV(self)->vfmt, &DUMMY_PRIV(self)->nsfmt ); assert( err != 0 ); err = Hermes_ConverterCopy( hermes_cnv_h, native->fd_addr, 0, /* x src coord of top left in pixel coords */ 0, /* y src coord of top left in pixel coords */ w, h, native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */ DUMMY_PRIV(self)->buf_scr_compat->pixdata, 0, /* x dst coord of top left in pixel coords */ 0, /* y dst coord of top left in pixel coords */ w, h, bitmap_get_rowstride(DUMMY_PRIV(self)->buf_scr_compat) /* stride as bytes */ ); assert( err != 0 ); return( (struct bitmap * )DUMMY_PRIV(self)->buf_scr_compat ); no_copy: snapshot.width = w; snapshot.height = h; snapshot.pixdata = native->fd_addr; snapshot.native = *native; snapshot.rowstride = MFDB_STRIDE( w )*4; uint32_t row, col; for( row = 0; rowfd_addr + ((row*native->fd_w))); for( col=0; colsize_buf_scr > CONV_KEEP_LIMIT ) { DUMMY_PRIV(self)->buf_scr.fd_addr = realloc( DUMMY_PRIV(self)->buf_scr.fd_addr, CONV_KEEP_LIMIT ); if( DUMMY_PRIV(self)->buf_scr.fd_addr != NULL ) { DUMMY_PRIV(self)->size_buf_scr = CONV_KEEP_LIMIT; } else { DUMMY_PRIV(self)->size_buf_scr = 0; } } if( DUMMY_PRIV(self)->size_buf_std > CONV_KEEP_LIMIT ) { DUMMY_PRIV(self)->buf_std.fd_addr = realloc( DUMMY_PRIV(self)->buf_std.fd_addr, CONV_KEEP_LIMIT ); if( DUMMY_PRIV(self)->buf_std.fd_addr != NULL ) { DUMMY_PRIV(self)->size_buf_std = CONV_KEEP_LIMIT; } else { DUMMY_PRIV(self)->size_buf_std = 0; } } if( DUMMY_PRIV(self)->buf_scr_compat != NULL ) { size_t bs = bitmap_buffer_size( DUMMY_PRIV(self)->buf_scr_compat ); if( bs > CONV_KEEP_LIMIT ) { int w = 0; int h = 1; w = (CONV_KEEP_LIMIT / DUMMY_PRIV(self)->buf_scr_compat->bpp); assert( CONV_KEEP_LIMIT == w*DUMMY_PRIV(self)->buf_scr_compat->bpp ); DUMMY_PRIV(self)->buf_scr_compat = bitmap_realloc( w, h, DUMMY_PRIV(self)->buf_scr_compat->bpp, CONV_KEEP_LIMIT, BITMAP_SHRINK, DUMMY_PRIV(self)->buf_scr_compat ); } } } static void snapshot_destroy( GEM_PLOTTER self ) { free( DUMMY_PRIV(self)->buf_scr.fd_addr ); if( DUMMY_PRIV(self)->buf_scr_compat != NULL ) { bitmap_destroy( DUMMY_PRIV(self)->buf_scr_compat ); } DUMMY_PRIV(self)->buf_scr.fd_addr = NULL; DUMMY_PRIV(self)->buf_scr_compat = NULL; #ifdef WITH_8BPP_SUPPORT free( DUMMY_PRIV(self)->buf_std.fd_addr ); DUMMY_PRIV(self)->buf_std.fd_addr = NULL; #endif } #ifdef WITH_8BPP_SUPPORT static inline void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val ) { short * buf; short whichbit = (1<<(15-(x%16))); buf = dst->fd_addr; buf += ((dst->fd_wdwidth*(y))+(x>>4)); *buf = (val&1) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<1)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<2)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<3)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<4)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<5)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<6)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); buf += wdplanesz; *buf = (val&(1<<7)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); } static inline unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y ) { unsigned char ret=0; short * buf; short whichbit = (1<<(15-(x%16))); buf = dst->fd_addr; buf += ((dst->fd_wdwidth*(y))+(x>>4)); if( *buf & whichbit ) ret |= 1; buf += wdplanesz; if( *buf & whichbit ) ret |= 2; buf += wdplanesz; if( *buf & whichbit ) ret |= 4; buf += wdplanesz; if( *buf & whichbit ) ret |= 8; buf += wdplanesz; if( *buf & whichbit ) ret |= 16; buf += wdplanesz; if( *buf & whichbit ) ret |= 32; buf += wdplanesz; if( *buf & whichbit ) ret |= 64; buf += wdplanesz; if( *buf & whichbit ) ret |= 128; return( ret ); } static int bitmap_convert_8( GEM_PLOTTER self, struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ) { MFDB native; MFDB stdform; int dststride; /* stride of dest. image */ int dstsize; /* size of dest. in byte */ int err; int bw, bh; int process_w, process_h; struct bitmap * scrbuf = NULL; struct bitmap * source; bool cache = ( flags & BITMAPF_BUFFER_NATIVE ); bool opaque = bitmap_get_opaque( img ); if( opaque == false ){ if( ( (self->flags & PLOT_FLAG_TRANS) == 0) && ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ opaque = true; } } assert( clip->g_h > 0 ); assert( clip->g_w > 0 ); process_w = bw = bitmap_get_width( img ); process_h = bh = bitmap_get_height( img ); // The converted bitmap can be saved for subsequent blits, when // the bitmap is fully opaque if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){ if( img->converted == true ){ *out = img->native; return( 0 ); } if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ cache = true; } } if( ( flags & BITMAPF_MONOGLYPH ) != 0 ){ assert(cache == false); } /* (re)allocate buffer for out image: */ /* altough the buffer is named "buf_packed" on 8bit systems */ /* it's not... */ if( cache == false ){ // the size of the output will match the size of the clipping: dststride = MFDB_STRIDE( clip->g_w ); dstsize = ( ((dststride >> 3) * clip->g_h) * self->bpp_virt ); if( dstsize > DUMMY_PRIV(self)->size_buf_packed) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; if( DUMMY_PRIV(self)->buf_packed == NULL ) DUMMY_PRIV(self)->buf_packed =(void*)malloc( blocks * CONV_BLOCK_SIZE ); else DUMMY_PRIV(self)->buf_packed =(void*)realloc( DUMMY_PRIV(self)->buf_packed, blocks * CONV_BLOCK_SIZE ); assert( DUMMY_PRIV(self)->buf_packed ); if( DUMMY_PRIV(self)->buf_packed == NULL ) { return( 0-ERR_NO_MEM ); } DUMMY_PRIV(self)->size_buf_packed = blocks * CONV_BLOCK_SIZE; } native.fd_addr = DUMMY_PRIV(self)->buf_packed; } else { // the output image will be completly saved, so size of the output // image will match the input image size. dststride = MFDB_STRIDE( bw ); dstsize = ( ((dststride >> 3) * bh) * self->bpp_virt ); assert( out->fd_addr == NULL ); native.fd_addr = (void*)malloc( dstsize ); if( native.fd_addr == NULL ){ if( scrbuf != NULL ) bitmap_destroy( scrbuf ); return( 0-ERR_NO_MEM ); } } /* on 8 bit systems we must convert the TC (ABGR) image to vdi standard format. ( only tested for 256 colors ) and then convert it to native format with v_trnfm() */ // realloc mem for stdform if( opaque == false ){ // point image to snapshot buffer, otherwise allocate mem MFDB * bg = snapshot_create_std_mfdb( self, x, y, clip->g_w, clip->g_h ); stdform.fd_addr = bg->fd_addr; bh = clip->g_h; } else { if( dstsize > DUMMY_PRIV(self)->size_buf_planar) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; if( DUMMY_PRIV(self)->buf_planar == NULL ) DUMMY_PRIV(self)->buf_planar =(void*)malloc( blocks * CONV_BLOCK_SIZE ); else DUMMY_PRIV(self)->buf_planar =(void*)realloc( DUMMY_PRIV(self)->buf_planar, blocks * CONV_BLOCK_SIZE ); assert( DUMMY_PRIV(self)->buf_planar ); if( DUMMY_PRIV(self)->buf_planar == NULL ) { return( 0-ERR_NO_MEM ); } DUMMY_PRIV(self)->size_buf_planar = blocks * CONV_BLOCK_SIZE; } stdform.fd_addr = DUMMY_PRIV(self)->buf_planar; } stdform.fd_w = dststride; stdform.fd_h = bh; stdform.fd_wdwidth = dststride >> 4; stdform.fd_stand = 1; stdform.fd_nplanes = (short)self->bpp_virt; stdform.fd_r1 = stdform.fd_r2 = stdform.fd_r3 = 0; int img_stride = bitmap_get_rowstride(img); uint32_t prev_pixel = 0x12345678; unsigned long col = 0; unsigned char val = 0; uint32_t * row; uint32_t pixel; int wdplanesize = stdform.fd_wdwidth*stdform.fd_h; if( opaque == false ){ // apply transparency and convert to vdi std format unsigned long bgcol = 0; unsigned char prev_col = 0; for( y=0; yg_h; y++ ){ row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y))); for( x=0; xg_w; x++ ){ pixel = row[x+clip->g_x]; if( (pixel&0xFF) == 0 ){ continue; } if( (pixel&0xFF) < 0xF0 ){ col = get_stdpx( &stdform, wdplanesize,x,y ); if( (col != prev_col) || (y == 0) ) bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8); if( prev_col != col || prev_pixel != pixel ){ prev_col = col; pixel = ablend( pixel, bgcol ); prev_pixel = pixel; pixel = pixel >> 8; /* convert pixel value to vdi color index: */ col = ( ((pixel&0xFF)<<16) | (pixel&0xFF00) | ((pixel&0xFF0000)>>16) ); val = RGB_TO_VDI( col ); } set_stdpx( &stdform, wdplanesize, x, y, val ); } else { if( pixel != prev_pixel ){ /* convert pixel value to vdi color index: */ pixel = pixel >> 8; col = ( ((pixel&0xFF)<<16) | (pixel&0xFF00) | ((pixel&0xFF0000)>>16) ); val = RGB_TO_VDI( col ); prev_pixel = pixel; } set_stdpx( &stdform, wdplanesize, x, y, val ); } } } // adjust output position: clip->g_x = 0; clip->g_y = 0; } else { // convert the whole image data to vdi std format. for( y=0; y < bh; y++ ){ row = (uint32_t *)(img->pixdata + (img_stride * y)); for( x=0; x < bw; x++ ){ pixel = row[x]; if( pixel != prev_pixel ){ /* convert pixel value to vdi color index: */ pixel = pixel >> 8; col = ( ((pixel&0xFF)<<16) | (pixel&0xFF00) | ((pixel&0xFF0000)>>16) ); val = RGB_TO_VDI( col ); prev_pixel = pixel; } set_stdpx( &stdform, wdplanesize, x, y, val ); } } } // convert into native format: native.fd_w = stdform.fd_w; native.fd_h = stdform.fd_h; native.fd_wdwidth = stdform.fd_wdwidth; native.fd_stand = 0; native.fd_nplanes = (short)self->bpp_virt; native.fd_r1 = native.fd_r2 = native.fd_r3 = 0; vr_trnfm( self->vdi_handle, &stdform, &native ); *out = native; if( cache == true ){ img->native = native; img->converted = true; } return(0); } #endif /* * * Convert bitmap to the native screen format * self: the plotter instance * img: the bitmap * x: coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) * y: coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) * clip: which area of the bitmap shall be drawn * bg: background color * flags: blit flags * out: the result MFDB */ static int bitmap_convert( GEM_PLOTTER self, struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ) { int dststride; /* stride of dest. image */ int dstsize; /* size of dest. in byte */ int err; int bw, bh; struct bitmap * scrbuf = NULL; struct bitmap * source; bool cache = ( flags & BITMAPF_BUFFER_NATIVE ); bool opaque = bitmap_get_opaque( img ); if( opaque == false ){ if( ( (self->flags & PLOT_FLAG_TRANS) == 0) && ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ opaque = true; } } assert( clip->g_h > 0 ); assert( clip->g_w > 0 ); bw = bitmap_get_width( img ); bh = bitmap_get_height( img ); // The converted bitmap can be saved for subsequent blits, WHEN: // A.) the bitmap is fully opaque OR // B.) the bitmap is completly inside the window // the latter one is important for alpha blits, // because we must get the window background to apply transparency // If the image is not completly within the window, // we can't get the whole background for the image. // this only works if the image isn't used at several different places. // In fact in case of alpha bitmap caching it is only used for the // toolbar buttons right now. if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){ if( img->converted == true ){ *out = img->native; return( 0 ); } if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ cache = true; } } /* rem. if eddi xy is installed, we could directly access the screen! */ /* apply transparency to the image: */ if( ( opaque == false ) ) { uint32_t * imgrow; uint32_t * screenrow; int img_x, img_y; /* points into old bitmap */ int screen_x, screen_y; /* pointers into new bitmap */ /* copy the screen to an temp buffer: */ scrbuf = snapshot_create(self, x, y, clip->g_w, clip->g_h ); if( scrbuf != NULL ) { // copy blended pixels to the new buffer (which contains screen content): int img_stride = bitmap_get_rowstride(img); int screen_stride = bitmap_get_rowstride(scrbuf); for( img_y = clip->g_y, screen_y = 0; screen_y < clip->g_h; screen_y++, img_y++) { imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); screenrow = (uint32_t *)(scrbuf->pixdata + (screen_stride * screen_y)); for( img_x = clip->g_x, screen_x = 0; screen_x < clip->g_w; screen_x++, img_x++ ) { // when the pixel isn't fully opaque,...: if( (imgrow[img_x] & 0x0FF) != 0 ){ screenrow[screen_x] = ablend( imgrow[img_x], screenrow[screen_x]); } // FIXME, maybe this loop would be faster??: // --- //if( (imgrow[img_x] & 0x0FF) != 0xFF ){ // imgrow[screen_x] = ablend( imgrow[img_x], screenrow[screen_x]); //} // or maybe even this??? // --- //if( (imgrow[img_x] & 0x0FF) == 0xFF ){ // screenrow[screen_x] = imgrow[img_x]; //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) { // screenrow[screen_x] = ablend( imgrow[img_x], screenrow[screen_x]); //} } } assert( clip->g_w <= bw ); assert( clip->g_h <= bh ); /* adjust size which gets converted: */ bw = clip->g_w; bh = clip->g_h; /* adjust output position: */ clip->g_x = 0; clip->g_y = 0; /* set the source of conversion: */ source = scrbuf; } } else { source = img; } /* (re)allocate buffer for converted image: */ dststride = MFDB_STRIDE( bw ); dstsize = ( ((dststride >> 3) * bh) * self->bpp_virt ); if( cache == false ){ if( dstsize > DUMMY_PRIV(self)->size_buf_packed) { int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; if( DUMMY_PRIV(self)->buf_packed == NULL ) DUMMY_PRIV(self)->buf_packed =(void*)malloc( blocks * CONV_BLOCK_SIZE ); else DUMMY_PRIV(self)->buf_packed =(void*)realloc( DUMMY_PRIV(self)->buf_packed, blocks * CONV_BLOCK_SIZE ); assert( DUMMY_PRIV(self)->buf_packed ); if( DUMMY_PRIV(self)->buf_packed == NULL ) { if( scrbuf != NULL ) bitmap_destroy( scrbuf ); return( 0-ERR_NO_MEM ); } DUMMY_PRIV(self)->size_buf_packed = blocks * CONV_BLOCK_SIZE; } out->fd_addr = DUMMY_PRIV(self)->buf_packed; } else { assert( out->fd_addr == NULL ); out->fd_addr = (void*)malloc( dstsize ); if( out->fd_addr == NULL ){ if( scrbuf != NULL ) bitmap_destroy( scrbuf ); return( 0-ERR_NO_MEM ); } } out->fd_w = dststride; out->fd_h = bh; out->fd_wdwidth = dststride >> 4; out->fd_stand = 0; out->fd_nplanes = (short)self->bpp_virt; out->fd_r1 = out->fd_r2 = out->fd_r3 = 0; err = Hermes_ConverterRequest( hermes_cnv_h, &DUMMY_PRIV(self)->nsfmt, &DUMMY_PRIV(self)->vfmt ); assert( err != 0 ); // FIXME: here we can use the same optimization which is used for // the snapshot creation. /* convert image to virtual format: */ err = Hermes_ConverterCopy( hermes_cnv_h, source->pixdata, 0, /* x src coord of top left in pixel coords */ 0, /* y src coord of top left in pixel coords */ bw, bh, source->rowstride, /* stride as bytes */ out->fd_addr, 0, /* x dst coord of top left in pixel coords */ 0, /* y dst coord of top left in pixel coords */ bw, bh, (dststride >> 3) * self->bpp_virt /* stride as bytes */ ); assert( err != 0 ); if( cache == true ){ img->native = *out; img->converted = true; } return( 0 ); } static void convert_bitmap_done( GEM_PLOTTER self ) { if( DUMMY_PRIV(self)->size_buf_packed > CONV_KEEP_LIMIT ) { /* free the mem if it was an large allocation ... */ DUMMY_PRIV(self)->buf_packed = realloc( DUMMY_PRIV(self)->buf_packed, CONV_KEEP_LIMIT ); DUMMY_PRIV(self)->size_buf_packed = CONV_KEEP_LIMIT; } snapshot_suspend( self ); } static int bitmap( GEM_PLOTTER self, struct bitmap * bmp, int x, int y, unsigned long bg, unsigned long flags ) { MFDB src_mf; MFDB scrmf; short pxy[8]; GRECT off, clip, vis; int screen_x, screen_y; src_mf.fd_addr = NULL; scrmf.fd_addr = NULL; off.g_x = x; off.g_y = y; off.g_h = bmp->height; off.g_w = bmp->width; // clip plotter clip rectangle: clip.g_x = VIEW( self ).clipping.x0; clip.g_y = VIEW( self ).clipping.y0; clip.g_w = VIEW( self ).clipping.x1 - VIEW( self ).clipping.x0; clip.g_h = VIEW( self ).clipping.y1 - VIEW( self ).clipping.y0; if( !rc_intersect( &clip, &off) ) { return( 1 ); } // clip the visible rectangle of the plot area // this is the area of the plotter which falls into // screen region: plotter_get_visible_grect( self, &vis ); if( !rc_intersect( &vis, &off) ) { return( 1 ); } screen_x = VIEW(self).x + off.g_x; screen_y = VIEW(self).y + off.g_y; // convert the clipping relative to bitmap: off.g_x = off.g_x - x; off.g_y = off.g_y - y; assert( (off.g_x >= 0) && (off.g_y >= 0) ); /* Convert the Bitmap to native screen format - ready for output. */ /* This includes blending transparent pixels: */ if( self->bitmap_convert( self, bmp, screen_x, screen_y, &off, bg, flags, &src_mf) != 0 ) { return( 1 ); } // setup the src region: pxy[0] = off.g_x; pxy[1] = off.g_y; pxy[2] = off.g_x + off.g_w-1; pxy[3] = off.g_y + off.g_h-1; // setup the target region: pxy[4] = screen_x; pxy[5] = screen_y; pxy[6] = screen_x + off.g_w-1; pxy[7] = screen_y + off.g_h-1; vro_cpyfm( self->vdi_handle, S_ONLY, (short*)&pxy, &src_mf, &scrmf); convert_bitmap_done( self ); return( 1 ); } static int plot_mfdb (GEM_PLOTTER self, GRECT * loc, MFDB * insrc, unsigned char fgcolor, uint32_t flags) { MFDB screen, tran; MFDB * src; short pxy[8]; short c[2] = {fgcolor, WHITE}; GRECT off; plotter_get_clip_grect( self, &off ); if( rc_intersect(loc, &off) == 0 ){ return( 1 ); } init_mfdb( 0, loc->g_w, loc->g_h, 0, &screen ); if( insrc->fd_stand ){ int size = init_mfdb( insrc->fd_nplanes, loc->g_w, loc->g_h, MFDB_FLAG_NOALLOC, &tran ); if( DUMMY_PRIV(self)->size_buf_scr == 0 ){ DUMMY_PRIV(self)->buf_scr.fd_addr = malloc( size ); DUMMY_PRIV(self)->size_buf_scr = size; } else { if( size > DUMMY_PRIV(self)->size_buf_scr ) { DUMMY_PRIV(self)->buf_scr.fd_addr = realloc( DUMMY_PRIV(self)->buf_scr.fd_addr, size ); DUMMY_PRIV(self)->size_buf_scr = size; } } tran.fd_addr = DUMMY_PRIV(self)->buf_scr.fd_addr; vr_trnfm( self->vdi_handle, insrc, &tran ); src = &tran; } else { src = insrc; } pxy[0] = off.g_x - loc->g_x; pxy[1] = off.g_y - loc->g_y; pxy[2] = pxy[0] + off.g_w - 1; pxy[3] = pxy[1] + off.g_h - 1; pxy[4] = VIEW(self).x + off.g_x; pxy[5] = VIEW(self).y + off.g_y; pxy[6] = pxy[4] + off.g_w-1; pxy[7] = pxy[5] + off.g_h-1; if( flags & PLOT_FLAG_TRANS && src->fd_nplanes == 1){ vrt_cpyfm( self->vdi_handle, MD_TRANS, (short*)pxy, src, &screen, (short*)&c ); } else { /* this method only plots transparent bitmaps, right now... */ } return( 1 ); } static int text(GEM_PLOTTER self, int x, int y, const char *text, size_t length, const plot_font_style_t *fstyle) { self->font_plotter->text( self->font_plotter, x, y, text, length, fstyle ); return ( 1 ); }