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 <sys/types.h>
20 #include <string.h>
21 #include <assert.h>
22 #include <stdlib.h>
23 
24 #include "netsurf/inttypes.h"
25 #include "utils/nsoption.h"
26 #include "utils/log.h"
27 #include "netsurf/bitmap.h"
28 #include "netsurf/mouse.h"
29 
30 #include "atari/bitmap.h"
31 #include "atari/plot/plot.h"
32 
33 
34 /*
35  * param bpp bits per pixel,
36  * param w width of the buffer (in pixel)
37  * param h height of the buffer (in pixel)
38  * param flags MFDB_FLAG_NOALLOC | MFDB_FLAG_ZEROMEM | MFDB_FLAG_STAND
39  * returns size of the fd_addr buffer required or allocated
40 */
init_mfdb(int bpp,int w,int h,uint32_t flags,MFDB * out)41 int init_mfdb(int bpp, int w, int h, uint32_t flags, MFDB * out )
42 {
43 	int dststride;
44 	dststride = MFDB_STRIDE( w );
45 	int size = MFDB_SIZE( bpp, dststride, h );
46 	if( bpp > 0 ) {
47 		if( (flags & MFDB_FLAG_NOALLOC) == 0  ) {
48 			out->fd_addr = malloc( size );
49 			if( out->fd_addr == NULL ){
50 				return( 0 );
51 			}
52 			if( (flags & MFDB_FLAG_ZEROMEM) ){
53 				memset( out->fd_addr, 0, size );
54 			}
55 		}
56 		out->fd_stand = (flags & MFDB_FLAG_STAND) ? 1 : 0;
57 		out->fd_nplanes = (short)bpp;
58 		out->fd_r1 = out->fd_r2 = out->fd_r3 = 0;
59 	} else {
60 		memset( out, 0, sizeof(MFDB) );
61 	}
62 	out->fd_w = dststride;
63 	out->fd_h = h;
64 	out->fd_wdwidth = dststride >> 4;
65 	return( size );
66 }
67 
68 
69 /**
70  * Create a bitmap.
71  *
72  * \param  w	width of image in pixels
73  * \param  h 	height of image in pixels
74  * \param  bpp	number of BYTES per pixel
75  * \param  rowstride 	linewidth in bytes
76  * \param  state 	a flag word indicating the initial state
77  * \param  pixdata 	NULL or an memory address to use as the bitmap pixdata
78  * \return an opaque struct bitmap, or NULL on memory exhaustion
79  */
atari_bitmap_create_ex(int w,int h,short bpp,int rowstride,unsigned int state,void * pixdata)80 static void *atari_bitmap_create_ex( int w, int h, short bpp, int rowstride, unsigned int state, void * pixdata )
81 {
82     struct bitmap * bitmap;
83 
84     NSLOG(netsurf, INFO,
85 	  "width %d (rowstride: %d, bpp: %d), height %d, state %u", w,
86 	  rowstride, bpp, h, state);
87 
88 	if( rowstride == 0) {
89 		rowstride = bpp * w;
90 	}
91 
92 	assert( rowstride >= (w * bpp) );
93     bitmap = calloc(1 , sizeof(struct bitmap) );
94     if (bitmap) {
95 		if( pixdata == NULL) {
96           	bitmap->pixdata = calloc(1, (rowstride * h)+128);
97 		}
98 		else {
99 			bitmap->pixdata = pixdata;
100 		}
101 
102         if (bitmap->pixdata != NULL) {
103 			bitmap->width = w;
104 			bitmap->height = h;
105 			bitmap->opaque = (state & BITMAP_OPAQUE) ? true : false;
106 			bitmap->bpp = bpp;
107 			bitmap->resized = NULL;
108 			bitmap->rowstride = rowstride;
109         } else {
110 			free(bitmap);
111 			bitmap=NULL;
112 			NSLOG(netsurf, INFO, "Out of memory!");
113 		}
114 	}
115 	NSLOG(netsurf, INFO, "bitmap %p", bitmap);
116 	return bitmap;
117 }
118 
119 
120 /* exported interface documented in atari/bitmap.h */
atari_bitmap_create(int w,int h,unsigned int state)121 void *atari_bitmap_create(int w, int h, unsigned int state)
122 {
123 	return atari_bitmap_create_ex( w, h, NS_BMP_DEFAULT_BPP, w * NS_BMP_DEFAULT_BPP, state, NULL );
124 }
125 
126 /**
127  * The bitmap image has changed, so flush any persistant cache.
128  *
129  * \param  bitmap  a bitmap, as returned by bitmap_create()
130  */
bitmap_modified(void * bitmap)131 static void bitmap_modified(void *bitmap)
132 {
133 	struct bitmap *bm = bitmap;
134 	if( bm->resized != NULL ) {
135 		atari_bitmap_destroy( bm->resized );
136 		bm->resized = NULL;
137 	}
138 	if( bm->converted ){
139 		if( bm->pixdata != bm->native.fd_addr ){
140 			free( bm->native.fd_addr );
141 		}
142 		bm->native.fd_addr = NULL;
143 		bm->converted = false;
144 	}
145 }
146 
147 
148 /* exported interface documented in atari/bitmap.h */
atari_bitmap_realloc(int w,int h,short bpp,int rowstride,unsigned int state,void * bmp)149 void *atari_bitmap_realloc( int w, int h, short bpp, int rowstride, unsigned int state, void * bmp )
150 {
151 	struct bitmap * bitmap = bmp;
152 	int newsize = rowstride * h;
153 
154 	if( bitmap == NULL ) {
155 		return( NULL );
156 	}
157 
158 	assert( bitmap->pixdata != NULL );
159 	int oldsize = bitmap->rowstride * bitmap->height;
160 	bool doalloc = (state & BITMAP_GROW) ? (newsize > oldsize) : (newsize != oldsize);
161 	if( newsize > oldsize )
162 		assert( doalloc == true );
163 	if( doalloc ) {
164 		// TODO: set red band to a specific value and check the red band
165 		// on bitmap_destroy()
166 		bitmap->pixdata = realloc( bitmap->pixdata, newsize + 128 );
167 		if( bitmap->pixdata == NULL )
168 			return( NULL );
169 	}
170 
171 	if( state & BITMAP_CLEAR ){
172 		memset( bitmap->pixdata, 0x00, newsize + 128  );
173 	}
174 
175 	bitmap->width = w;
176 	bitmap->height = h;
177 	bitmap->bpp = bpp;
178 	bitmap->resized = NULL;
179 	bitmap->rowstride = rowstride;
180 	bitmap_modified( bitmap );
181 	return( bitmap );
182 }
183 
184 
185 /**
186  * Return a pointer to the pixel data in a bitmap.
187  *
188  * \param  bitmap  a bitmap, as returned by bitmap_create()
189  * \return pointer to the pixel buffer
190  *
191  * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
192  * of rows. The width of a row in bytes is given by bitmap_get_rowstride().
193  */
bitmap_get_buffer(void * bitmap)194 static unsigned char *bitmap_get_buffer(void *bitmap)
195 {
196 	struct bitmap *bm = bitmap;
197 
198 	if (bitmap == NULL) {
199 		NSLOG(netsurf, INFO, "NULL bitmap!");
200 		return NULL;
201 	}
202 
203 	return bm->pixdata;
204 }
205 
206 
207 /* exported interface documented in atari/bitmap.h */
atari_bitmap_buffer_size(void * bitmap)208 size_t atari_bitmap_buffer_size(void *bitmap)
209 {
210 	struct bitmap * bm = bitmap;
211 	if( bm == NULL )
212 		return 0;
213 	return( bm->rowstride * bm->height );
214 }
215 
216 
217 /* exported interface documented in atari/bitmap.h */
atari_bitmap_get_rowstride(void * bitmap)218 size_t atari_bitmap_get_rowstride(void *bitmap)
219 {
220 	struct bitmap *bm = bitmap;
221 
222 	if (bitmap == NULL) {
223 		NSLOG(netsurf, INFO, "NULL bitmap!");
224 		return 0;
225 	}
226 	return bm->rowstride;
227 }
228 
229 
230 /* exported interface documented in atari/bitmap.h */
atari_bitmap_destroy(void * bitmap)231 void atari_bitmap_destroy(void *bitmap)
232 {
233 	struct bitmap *bm = bitmap;
234 
235 	if (bitmap == NULL) {
236 		NSLOG(netsurf, INFO, "NULL bitmap!");
237 		return;
238 	}
239 
240 	if( bm->resized != NULL ) {
241 		atari_bitmap_destroy(bm->resized);
242 	}
243 	if( bm->converted && ( bm->native.fd_addr != bm->pixdata ) ) {
244 		free( bm->native.fd_addr );
245 	}
246 	free(bm->pixdata);
247 	free(bm);
248 }
249 
250 
251 /**
252  * Save a bitmap in the platform's native format.
253  *
254  * \param  bitmap  a bitmap, as returned by bitmap_create()
255  * \param  path    pathname for file
256  * \param flags flags controlling how the bitmap is saved.
257  * \return true on success, false on error and error reported
258  */
259 
bitmap_save(void * bitmap,const char * path,unsigned flags)260 static bool bitmap_save(void *bitmap, const char *path, unsigned flags)
261 {
262 	return true;
263 }
264 
265 
266 /**
267  * Sets whether a bitmap should be plotted opaque
268  *
269  * \param  bitmap  a bitmap, as returned by bitmap_create()
270  * \param  opaque  whether the bitmap should be plotted opaque
271  */
bitmap_set_opaque(void * bitmap,bool opaque)272 static void bitmap_set_opaque(void *bitmap, bool opaque)
273 {
274 	struct bitmap *bm = bitmap;
275 
276     if (bitmap == NULL) {
277 		NSLOG(netsurf, INFO, "NULL bitmap!");
278 		return;
279 	}
280 
281 	NSLOG(netsurf, INFO, "setting bitmap %p to %s", bm,
282               opaque ? "opaque" : "transparent");
283     bm->opaque = opaque;
284 }
285 
286 
287 /**
288  * Tests whether a bitmap has an opaque alpha channel
289  *
290  * \param  bitmap  a bitmap, as returned by bitmap_create()
291  * \return whether the bitmap is opaque
292  */
bitmap_test_opaque(void * bitmap)293 static bool bitmap_test_opaque(void *bitmap)
294 {
295 	int tst;
296 	struct bitmap *bm = bitmap;
297 
298 	if (bitmap == NULL) {
299 		NSLOG(netsurf, INFO, "NULL bitmap!");
300 		return false;
301 	}
302 
303     if( nsoption_int(atari_transparency) == 0 ){
304         return( true );
305     }
306 
307 	tst = bm->width * bm->height;
308 
309 	while (tst-- > 0) {
310 		if (bm->pixdata[(tst << 2) + 3] != 0xff) {
311 				NSLOG(netsurf, INFO,
312 				      "bitmap %p has transparency", bm);
313 					return false;
314 		}
315 	}
316 	NSLOG(netsurf, INFO, "bitmap %p is opaque", bm);
317 	return true;
318 }
319 
320 
321 /* exported interface documented in atari/bitmap.h */
atari_bitmap_get_opaque(void * bitmap)322 bool atari_bitmap_get_opaque(void *bitmap)
323 {
324 	struct bitmap *bm = bitmap;
325 
326         if (bitmap == NULL) {
327                 NSLOG(netsurf, INFO, "NULL bitmap!");
328                 return false;
329         }
330 
331 	return bm->opaque;
332 }
333 
334 
335 /* exported interface documented in atari/bitmap.h */
atari_bitmap_get_width(void * bitmap)336 int atari_bitmap_get_width(void *bitmap)
337 {
338 	struct bitmap *bm = bitmap;
339 
340 	if (bitmap == NULL) {
341 		NSLOG(netsurf, INFO, "NULL bitmap!");
342 		return 0;
343 	}
344 
345 	return(bm->width);
346 }
347 
348 
349 /* exported interface documented in atari/bitmap.h */
atari_bitmap_get_height(void * bitmap)350 int atari_bitmap_get_height(void *bitmap)
351 {
352 	struct bitmap *bm = bitmap;
353 
354 	if (bitmap == NULL) {
355 		NSLOG(netsurf, INFO, "NULL bitmap!");
356 		return 0;
357 	}
358 	return(bm->height);
359 }
360 
361 
362 /**
363  *	Gets the number of BYTES per pixel.
364  */
bitmap_get_bpp(void * bitmap)365 static size_t bitmap_get_bpp(void *bitmap)
366 {
367 	struct bitmap *bm = bitmap;
368 	return bm->bpp;
369 }
370 
371 /* exported interface documented in atari/bitmap.h */
atari_bitmap_resize(struct bitmap * img,HermesHandle hermes_h,HermesFormat * fmt,int nw,int nh)372 bool atari_bitmap_resize(struct bitmap *img, HermesHandle hermes_h,
373 		HermesFormat *fmt, int nw, int nh)
374 {
375 	unsigned int state = 0;
376 	short bpp = bitmap_get_bpp( img );
377 	int stride = atari_bitmap_get_rowstride( img );
378 	int err;
379 
380 	if( img->resized != NULL ) {
381 		if( img->resized->width != nw || img->resized->height != nh ) {
382 			atari_bitmap_destroy( img->resized );
383 			img->resized = NULL;
384 		} else {
385 			/* the bitmap is already resized */
386 			return(true);
387 		}
388 	}
389 
390 	/* allocate the mem for resized bitmap */
391 	if (img->opaque == true) {
392 		state |= BITMAP_OPAQUE;
393 	}
394 	img->resized = atari_bitmap_create_ex( nw, nh, bpp, nw*bpp, state, NULL );
395 	if( img->resized == NULL ) {
396 			printf("W: %d, H: %d, bpp: %d\n", nw, nh, bpp);
397 			assert(img->resized);
398 			return(false);
399 	}
400 
401 	/* allocate an converter, only for resizing */
402 	err = Hermes_ConverterRequest( hermes_h,
403 			fmt,
404 			fmt
405 	);
406 	if( err == 0 ) {
407 		return(false);
408 	}
409 
410 	err = Hermes_ConverterCopy( hermes_h,
411 		img->pixdata,
412 		0,		/* x src coord of top left in pixel coords */
413 		0,		/* y src coord of top left in pixel coords */
414 		atari_bitmap_get_width( img ),
415 		atari_bitmap_get_height( img ),
416 		stride, 	/* stride as bytes */
417 		img->resized->pixdata,
418 		0,		/* x dst coord of top left in pixel coords */
419 		0,		/* y dst coord of top left in pixel coords */
420 		nw, nh,
421 		atari_bitmap_get_rowstride(img->resized) /* stride as bytes */
422 	);
423 	if( err == 0 ) {
424 		atari_bitmap_destroy( img->resized );
425 		img->resized = NULL;
426 		return(false);
427 	}
428 
429 	return(true);
430 }
431 
bitmap_render(struct bitmap * bitmap,struct hlcache_handle * content)432 static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
433 {
434 	return NSERROR_NOT_IMPLEMENTED;
435 }
436 
437 static struct gui_bitmap_table bitmap_table = {
438 	.create = atari_bitmap_create,
439 	.destroy = atari_bitmap_destroy,
440 	.set_opaque = bitmap_set_opaque,
441 	.get_opaque = atari_bitmap_get_opaque,
442 	.test_opaque = bitmap_test_opaque,
443 	.get_buffer = bitmap_get_buffer,
444 	.get_rowstride = atari_bitmap_get_rowstride,
445 	.get_width = atari_bitmap_get_width,
446 	.get_height = atari_bitmap_get_height,
447 	.get_bpp = bitmap_get_bpp,
448 	.save = bitmap_save,
449 	.modified = bitmap_modified,
450 	.render = bitmap_render,
451 };
452 
453 struct gui_bitmap_table *atari_bitmap_table = &bitmap_table;
454 
455 /*
456  * Local Variables:
457  * c-basic-offset:8
458  * End:
459  */
460