1 /*
2 * Copyright 2008, 2009, 2012, 2016 Chris Young <chris@unsatisfactorysoftware.co.uk>
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 "amiga/os3support.h"
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <proto/exec.h>
24 #ifdef __amigaos4__
25 #include <graphics/blitattr.h>
26 #include <graphics/composite.h>
27 #endif
28 #include <graphics/gfxbase.h>
29 #include <proto/datatypes.h>
30 #include <datatypes/pictureclass.h>
31 #include <proto/dos.h>
32 #include <proto/intuition.h>
33 #include <proto/utility.h>
34
35 #include <proto/guigfx.h>
36 #include <guigfx/guigfx.h>
37 #include <render/render.h>
38 #ifndef __amigaos4__
39 #include <inline/guigfx.h>
40 #endif
41
42 #ifdef __amigaos4__
43 #include <exec/extmem.h>
44 #include <sys/param.h>
45 #endif
46 #include "assert.h"
47
48 #include "utils/log.h"
49 #include "utils/nsoption.h"
50 #include "utils/nsurl.h"
51 #include "utils/messages.h"
52 #include "netsurf/bitmap.h"
53 #include "netsurf/content.h"
54
55 #include "amiga/gui.h"
56 #include "amiga/bitmap.h"
57 #include "amiga/plotters.h"
58 #include "amiga/memory.h"
59 #include "amiga/misc.h"
60 #include "amiga/rtg.h"
61 #include "amiga/schedule.h"
62
63 // disable use of "triangle mode" for scaling
64 #ifdef AMI_NS_TRIANGLE_SCALING
65 #undef AMI_NS_TRIANGLE_SCALING
66 #endif
67
68 struct bitmap {
69 int width;
70 int height;
71 UBYTE *pixdata;
72 struct ExtMemIFace *iextmem;
73 uint32 size;
74 bool opaque;
75 int native;
76 struct BitMap *nativebm;
77 int nativebmwidth;
78 int nativebmheight;
79 PLANEPTR native_mask;
80 Object *dto;
81 APTR drawhandle;
82 struct nsurl *url; /* temporary storage space */
83 char *title; /* temporary storage space */
84 ULONG *icondata; /* for appicons */
85 };
86
87 enum {
88 AMI_NSBM_NONE = 0,
89 AMI_NSBM_TRUECOLOUR,
90 AMI_NSBM_PALETTEMAPPED
91 };
92
93 struct vertex {
94 float x, y;
95 float s, t, w;
96 };
97
98 #define VTX(I,X,Y,S,T) vtx[I].x = X; vtx[I].y = Y; vtx[I].s = S; vtx[I].t = T; vtx[I].w = 1.0f;
99 #define VTX_RECT(SX,SY,SW,SH,DX,DY,DW,DH) \
100 VTX(0, DX, DY, SX, SY); \
101 VTX(1, DX + DW, DY, SX + SW, SY); \
102 VTX(2, DX, DY + DH, SX, SY + SH); \
103 VTX(3, DX + DW, DY, SX + SW, SY); \
104 VTX(4, DX, DY + DH, SX, SY + SH); \
105 VTX(5, DX + DW, DY + DH, SX + SW, SY + SH);
106
107 static APTR pool_bitmap = NULL;
108 static bool guigfx_warned = false;
109
110 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_create(int width,int height,unsigned int state)111 void *amiga_bitmap_create(int width, int height, unsigned int state)
112 {
113 struct bitmap *bitmap;
114
115 if(pool_bitmap == NULL) pool_bitmap = ami_memory_itempool_create(sizeof(struct bitmap));
116
117 bitmap = ami_memory_itempool_alloc(pool_bitmap, sizeof(struct bitmap));
118 if(bitmap == NULL) return NULL;
119
120 bitmap->size = width * height * 4;
121
122 #ifdef __amigaos4__
123 if(nsoption_bool(use_extmem) == true) {
124 uint64 size64 = bitmap->size;
125 bitmap->iextmem = AllocSysObjectTags(ASOT_EXTMEM,
126 ASOEXTMEM_Size, &size64,
127 ASOEXTMEM_AllocationPolicy, EXTMEMPOLICY_IMMEDIATE,
128 TAG_END);
129
130 bitmap->pixdata = NULL;
131 UBYTE *pixdata = amiga_bitmap_get_buffer(bitmap);
132 memset(pixdata, 0xff, bitmap->size);
133 } else
134 #endif
135 {
136 bitmap->pixdata = ami_memory_clear_alloc(bitmap->size, 0xff);
137 }
138
139 bitmap->width = width;
140 bitmap->height = height;
141
142 if(state & BITMAP_OPAQUE) bitmap->opaque = true;
143 else bitmap->opaque = false;
144
145 bitmap->nativebm = NULL;
146 bitmap->nativebmwidth = 0;
147 bitmap->nativebmheight = 0;
148 bitmap->native_mask = NULL;
149 bitmap->drawhandle = NULL;
150 bitmap->url = NULL;
151 bitmap->title = NULL;
152 bitmap->icondata = NULL;
153 bitmap->native = AMI_NSBM_NONE;
154
155 return bitmap;
156 }
157
amiga_bitmap_unmap_buffer(void * p)158 static void amiga_bitmap_unmap_buffer(void *p)
159 {
160 #ifdef __amigaos4__
161 struct bitmap *bm = p;
162
163 if((nsoption_bool(use_extmem) == true) && (bm->pixdata != NULL)) {
164 NSLOG(netsurf, INFO,
165 "Unmapping ExtMem object %p for bitmap %p",
166 bm->iextmem,
167 bm);
168 bm->iextmem->Unmap(bm->pixdata, bm->size);
169 bm->pixdata = NULL;
170 }
171 #endif
172 }
173
174 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_get_buffer(void * bitmap)175 unsigned char *amiga_bitmap_get_buffer(void *bitmap)
176 {
177 struct bitmap *bm = bitmap;
178
179 #ifdef __amigaos4__
180 if(nsoption_bool(use_extmem) == true) {
181 if(bm->pixdata == NULL) {
182 NSLOG(netsurf, INFO,
183 "Mapping ExtMem object %p for bitmap %p",
184 bm->iextmem,
185 bm);
186 bm->pixdata = bm->iextmem->Map(NULL, bm->size, 0LL, 0);
187 }
188
189 /* unmap the buffer after one second */
190 ami_schedule(1000, amiga_bitmap_unmap_buffer, bm);
191 }
192 #endif
193
194 return bm->pixdata;
195 }
196
197 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_get_rowstride(void * bitmap)198 size_t amiga_bitmap_get_rowstride(void *bitmap)
199 {
200 struct bitmap *bm = bitmap;
201
202 if(bm)
203 {
204 return ((bm->width)*4);
205 }
206 else
207 {
208 return 0;
209 }
210 }
211
212
213 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_destroy(void * bitmap)214 void amiga_bitmap_destroy(void *bitmap)
215 {
216 struct bitmap *bm = bitmap;
217
218 if(bm)
219 {
220 if((bm->nativebm)) { // && (bm->native == AMI_NSBM_TRUECOLOUR)) {
221 ami_rtg_freebitmap(bm->nativebm);
222 }
223
224 if(bm->native_mask) FreeRaster(bm->native_mask, bm->width, bm->height);
225
226 #ifdef __amigaos4__
227 if(nsoption_bool(use_extmem) == true) {
228 ami_schedule(-1, amiga_bitmap_unmap_buffer, bm);
229 amiga_bitmap_unmap_buffer(bm);
230 FreeSysObject(ASOT_EXTMEM, bm->iextmem);
231 bm->iextmem = NULL;
232 } else
233 #endif
234 {
235 if(bm->drawhandle) ReleaseDrawHandle(bm->drawhandle);
236 ami_memory_clear_free(bm->pixdata);
237 }
238
239 if(bm->url) nsurl_unref(bm->url);
240 if(bm->title) free(bm->title);
241
242 bm->pixdata = NULL;
243 bm->nativebm = NULL;
244 bm->native_mask = NULL;
245 bm->drawhandle = NULL;
246 bm->url = NULL;
247 bm->title = NULL;
248
249 ami_memory_itempool_free(pool_bitmap, bm, sizeof(struct bitmap));
250 bm = NULL;
251 }
252 }
253
254
255 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_save(void * bitmap,const char * path,unsigned flags)256 bool amiga_bitmap_save(void *bitmap, const char *path, unsigned flags)
257 {
258 int err = 0;
259 Object *dto = NULL;
260
261 if((dto = ami_datatype_object_from_bitmap(bitmap)))
262 {
263 if (flags & AMI_BITMAP_SCALE_ICON) {
264 IDoMethod(dto, PDTM_SCALE, 16, 16, 0);
265
266 if((DoDTMethod(dto, 0, 0, DTM_PROCLAYOUT, 0, 1)) == 0) {
267 return false;
268 }
269 }
270
271 err = SaveDTObjectA(dto, NULL, NULL, path, DTWM_IFF, FALSE, NULL);
272 DisposeDTObject(dto);
273 }
274
275 if(err == 0) return false;
276 else return true;
277 }
278
279
280 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_modified(void * bitmap)281 void amiga_bitmap_modified(void *bitmap)
282 {
283 struct bitmap *bm = bitmap;
284
285 #ifdef __amigaos4__
286 /* unmap the buffer after 0.5s - we might need it imminently */
287 ami_schedule(500, amiga_bitmap_unmap_buffer, bm);
288 #endif
289
290 if(bm->nativebm) ami_rtg_freebitmap(bm->nativebm);
291 if(bm->drawhandle) ReleaseDrawHandle(bm->drawhandle);
292 if(bm->native_mask) FreeRaster(bm->native_mask, bm->width, bm->height);
293 bm->nativebm = NULL;
294 bm->drawhandle = NULL;
295 bm->native_mask = NULL;
296 bm->native = AMI_NSBM_NONE;
297 }
298
299
300 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_set_opaque(void * bitmap,bool opaque)301 void amiga_bitmap_set_opaque(void *bitmap, bool opaque)
302 {
303 struct bitmap *bm = bitmap;
304 assert(bitmap);
305 bm->opaque = opaque;
306 }
307
308
309 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_test_opaque(void * bitmap)310 bool amiga_bitmap_test_opaque(void *bitmap)
311 {
312 struct bitmap *bm = bitmap;
313 uint32 p = bm->width * bm->height;
314 uint32 a = 0;
315 uint32 *bmi = (uint32 *)amiga_bitmap_get_buffer(bm);
316
317 assert(bitmap);
318
319 for(a=0;a<p;a+=4)
320 {
321 if ((*bmi & 0x000000ffU) != 0x000000ffU) return false;
322 bmi++;
323 }
324 return true;
325 }
326
327
328 /* exported function documented in amiga/bitmap.h */
amiga_bitmap_get_opaque(void * bitmap)329 bool amiga_bitmap_get_opaque(void *bitmap)
330 {
331 struct bitmap *bm = bitmap;
332 assert(bitmap);
333 return bm->opaque;
334 }
335
336 /**
337 * get width of a bitmap.
338 */
bitmap_get_width(void * bitmap)339 int bitmap_get_width(void *bitmap)
340 {
341 struct bitmap *bm = bitmap;
342
343 if(bm)
344 {
345 return(bm->width);
346 }
347 else
348 {
349 return 0;
350 }
351 }
352
353 /**
354 * get height of a bitmap.
355 */
bitmap_get_height(void * bitmap)356 int bitmap_get_height(void *bitmap)
357 {
358 struct bitmap *bm = bitmap;
359
360 if(bm)
361 {
362 return(bm->height);
363 }
364 else
365 {
366 return 0;
367 }
368 }
369
370
371 /**
372 * Find the bytes per pixel of a bitmap
373 *
374 * \param vbitmap a bitmap, as returned by bitmap_create()
375 * \return bytes per pixel
376 */
bitmap_get_bpp(void * vbitmap)377 static size_t bitmap_get_bpp(void *vbitmap)
378 {
379 struct bitmap *bitmap = (struct bitmap *)vbitmap;
380 assert(bitmap);
381 return 4;
382 }
383
ami_bitmap_argb_to_rgba(struct bitmap * bm)384 static void ami_bitmap_argb_to_rgba(struct bitmap *bm)
385 {
386 if(bm == NULL) return;
387
388 ULONG *data = (ULONG *)amiga_bitmap_get_buffer(bm);
389 for(int i = 0; i < (bm->width * bm->height); i++) {
390 data[i] = (data[i] << 8) | (data[i] >> 24);
391 }
392 }
393
ami_bitmap_rgba_to_argb(struct bitmap * bm)394 static void ami_bitmap_rgba_to_argb(struct bitmap *bm)
395 {
396 if(bm == NULL) return;
397
398 ULONG *data = (ULONG *)amiga_bitmap_get_buffer(bm);
399 for(int i = 0; i < (bm->width * bm->height); i++) {
400 data[i] = (data[ i] >> 8) | (data[i] << 24);
401 }
402 }
403
404 #ifdef BITMAP_DUMP
bitmap_dump(struct bitmap * bitmap)405 void bitmap_dump(struct bitmap *bitmap)
406 {
407 int x,y;
408 ULONG *bm = (ULONG *)amiga_bitmap_get_buffer(bitmap);
409
410 printf("Width=%ld, Height=%ld, Opaque=%s\nnativebm=%lx, width=%ld, height=%ld\n",
411 bitmap->width, bitmap->height, bitmap->opaque ? "true" : "false",
412 bitmap->nativebm, bitmap->nativebmwidth, bitmap->nativebmheight);
413
414 for(y = 0; y < bitmap->height; y++) {
415 for(x = 0; x < bitmap->width; x++) {
416 printf("%lx ", bm[(y*bitmap->width) + x]);
417 }
418 printf("\n");
419 }
420 }
421 #endif
422
ami_datatype_object_from_bitmap(struct bitmap * bitmap)423 Object *ami_datatype_object_from_bitmap(struct bitmap *bitmap)
424 {
425 Object *dto;
426 struct BitMapHeader *bmhd;
427
428 if((dto = NewDTObject(NULL,
429 DTA_SourceType,DTST_RAM,
430 DTA_GroupID,GID_PICTURE,
431 //DTA_BaseName,"ilbm",
432 PDTA_DestMode,PMODE_V43,
433 TAG_DONE)))
434 {
435 if(GetDTAttrs(dto,PDTA_BitMapHeader,&bmhd,TAG_DONE))
436 {
437 bmhd->bmh_Width = (UWORD)bitmap_get_width(bitmap);
438 bmhd->bmh_Height = (UWORD)bitmap_get_height(bitmap);
439 bmhd->bmh_Depth = (UBYTE)bitmap_get_bpp(bitmap) * 8;
440 if(!amiga_bitmap_get_opaque(bitmap)) bmhd->bmh_Masking = mskHasAlpha;
441 }
442
443 SetDTAttrs(dto,NULL,NULL,
444 DTA_ObjName, bitmap->url ? nsurl_access(bitmap->url) : "",
445 DTA_ObjAnnotation,bitmap->title,
446 DTA_ObjAuthor,messages_get("NetSurf"),
447 DTA_NominalHoriz,bitmap_get_width(bitmap),
448 DTA_NominalVert,bitmap_get_height(bitmap),
449 PDTA_SourceMode,PMODE_V43,
450 TAG_DONE);
451
452 IDoMethod(dto, PDTM_WRITEPIXELARRAY, amiga_bitmap_get_buffer(bitmap),
453 PBPAFMT_RGBA, amiga_bitmap_get_rowstride(bitmap), 0, 0,
454 bitmap_get_width(bitmap), bitmap_get_height(bitmap));
455 }
456
457 return dto;
458 }
459
460 /* Quick way to get an object on disk into a struct bitmap */
ami_bitmap_from_datatype(char * filename)461 struct bitmap *ami_bitmap_from_datatype(char *filename)
462 {
463 Object *dto;
464 struct bitmap *bm = NULL;
465
466 if((dto = NewDTObject(filename,
467 DTA_GroupID, GID_PICTURE,
468 PDTA_DestMode, PMODE_V43,
469 PDTA_PromoteMask, TRUE,
470 TAG_DONE))) {
471 struct BitMapHeader *bmh;
472
473 if(GetDTAttrs(dto, PDTA_BitMapHeader, &bmh, TAG_DONE))
474 {
475 bm = amiga_bitmap_create(bmh->bmh_Width, bmh->bmh_Height, 0);
476
477 IDoMethod(dto, PDTM_READPIXELARRAY, amiga_bitmap_get_buffer(bm),
478 PBPAFMT_RGBA, amiga_bitmap_get_rowstride(bm), 0, 0,
479 bmh->bmh_Width, bmh->bmh_Height);
480
481 amiga_bitmap_set_opaque(bm, amiga_bitmap_test_opaque(bm));
482 }
483 DisposeDTObject(dto);
484 }
485
486 return bm;
487 }
488
ami_bitmap_get_generic(struct bitmap * bitmap,int width,int height,struct BitMap * restrict friendbm,int type)489 static inline struct BitMap *ami_bitmap_get_generic(struct bitmap *bitmap,
490 int width, int height, struct BitMap *restrict friendbm, int type)
491 {
492 struct BitMap *restrict tbm = NULL;
493 struct Screen *scrn = ami_gui_get_screen();
494
495 if(bitmap->nativebm)
496 {
497 if((bitmap->nativebmwidth == width) && (bitmap->nativebmheight == height)) {
498 tbm = bitmap->nativebm;
499 return tbm;
500 } else if((bitmap->nativebmwidth == bitmap->width) &&
501 (bitmap->nativebmheight == bitmap->height)) { // >= width/height ?
502 tbm = bitmap->nativebm;
503 } else {
504 if(bitmap->nativebm) amiga_bitmap_modified(bitmap);
505 }
506 }
507
508 if(tbm == NULL) {
509 if(type == AMI_NSBM_TRUECOLOUR) {
510 tbm = ami_rtg_allocbitmap(bitmap->width, bitmap->height, 32, 0,
511 friendbm, AMI_BITMAP_FORMAT);
512 if(tbm == NULL) return NULL;
513
514 ami_rtg_writepixelarray(amiga_bitmap_get_buffer(bitmap),
515 tbm, bitmap->width, bitmap->height,
516 bitmap->width * 4, AMI_BITMAP_FORMAT);
517 } else {
518 tbm = ami_rtg_allocbitmap(width, height,
519 8, 0, friendbm, AMI_BITMAP_FORMAT);
520 if(tbm == NULL) return NULL;
521
522 if(GuiGFXBase != NULL) {
523 struct RastPort rp;
524 InitRastPort(&rp);
525 rp.BitMap = tbm;
526 ULONG dithermode = DITHERMODE_NONE;
527
528 if(nsoption_int(dither_quality) == 1) {
529 dithermode = DITHERMODE_EDD;
530 } else if(nsoption_int(dither_quality) == 2) {
531 dithermode = DITHERMODE_FS;
532 }
533
534 ami_bitmap_rgba_to_argb(bitmap);
535 bitmap->drawhandle = ObtainDrawHandle(
536 NULL,
537 &rp,
538 scrn->ViewPort.ColorMap,
539 GGFX_DitherMode, dithermode,
540 TAG_DONE);
541 if(bitmap->drawhandle) {
542 APTR ddh = CreateDirectDrawHandle(bitmap->drawhandle,
543 bitmap->width, bitmap->height,
544 width, height, NULL);
545
546 DirectDrawTrueColor(ddh, (ULONG *)amiga_bitmap_get_buffer(bitmap), 0, 0, TAG_DONE);
547 DeleteDirectDrawHandle(ddh);
548 ReleaseDrawHandle(bitmap->drawhandle);
549 bitmap->drawhandle = NULL;
550 }
551 ami_bitmap_argb_to_rgba(bitmap);
552 } else {
553 if(guigfx_warned == false) {
554 amiga_warn_user("BMConvErr", NULL);
555 guigfx_warned = true;
556 }
557 }
558 }
559
560 if(((type == AMI_NSBM_TRUECOLOUR) && (nsoption_int(cache_bitmaps) == 2)) ||
561 ((type == AMI_NSBM_PALETTEMAPPED) && (((bitmap->width == width) &&
562 (bitmap->height == height) && (nsoption_int(cache_bitmaps) == 2)) ||
563 (nsoption_int(cache_bitmaps) >= 1)))) {
564 bitmap->nativebm = tbm;
565 if(type == AMI_NSBM_TRUECOLOUR) {
566 bitmap->nativebmwidth = bitmap->width;
567 bitmap->nativebmheight = bitmap->height;
568 } else {
569 bitmap->nativebmwidth = width;
570 bitmap->nativebmheight = height;
571 }
572 bitmap->native = type;
573 }
574
575 if(type == AMI_NSBM_PALETTEMAPPED)
576 return tbm;
577 }
578
579 if((bitmap->width != width) || (bitmap->height != height)) {
580 struct BitMap *restrict scaledbm;
581 struct BitScaleArgs bsa;
582 int depth = 32;
583 if(type == AMI_NSBM_PALETTEMAPPED) depth = 8;
584
585 scaledbm = ami_rtg_allocbitmap(width, height, depth, 0,
586 friendbm, AMI_BITMAP_FORMAT);
587 #ifdef __amigaos4__
588 if(__builtin_expect(((GfxBase->LibNode.lib_Version >= 53) &&
589 (type == AMI_NSBM_TRUECOLOUR)), 1)) {
590 /* AutoDoc says v52, but this function isn't in OS4.0, so checking for v53 (OS4.1)
591 * Additionally, when we use friend BitMaps in non 32-bit modes it freezes the OS */
592
593 uint32 flags = 0;
594 uint32 err = COMPERR_Success;
595 #ifdef AMI_NS_TRIANGLE_SCALING
596 struct vertex vtx[6];
597 VTX_RECT(0, 0, bitmap->width, bitmap->height, 0, 0, width, height);
598
599 flags = COMPFLAG_HardwareOnly;
600 if(nsoption_bool(scale_quality) == true) flags |= COMPFLAG_SrcFilter;
601
602 err = CompositeTags(COMPOSITE_Src, tbm, scaledbm,
603 COMPTAG_VertexArray, vtx,
604 COMPTAG_VertexFormat, COMPVF_STW0_Present,
605 COMPTAG_NumTriangles, 2,
606 COMPTAG_Flags, flags,
607 COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
608 TAG_DONE);
609
610 if (err != COMPERR_Success) {
611 NSLOG(netsurf, INFO,
612 "Composite error %ld - falling back",
613 err);
614 /* If it failed, do it again the way
615 * which works in software
616 */
617 #else
618 {
619 #endif
620 flags = 0;
621 if(nsoption_bool(scale_quality) == true) flags |= COMPFLAG_SrcFilter;
622
623 err = CompositeTags(COMPOSITE_Src, tbm, scaledbm,
624 COMPTAG_ScaleX, COMP_FLOAT_TO_FIX((float)width/bitmap->width),
625 COMPTAG_ScaleY, COMP_FLOAT_TO_FIX((float)height/bitmap->height),
626 COMPTAG_Flags, flags,
627 COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
628 TAG_DONE);
629 /* If it still fails... it's non-fatal */
630 NSLOG(netsurf, INFO,
631 "Fallback returned error %ld", err);
632 }
633 } else /* Do it the old-fashioned way. This is pretty slow, even on OS4.1 */
634 #endif
635 {
636 bsa.bsa_SrcX = 0;
637 bsa.bsa_SrcY = 0;
638 bsa.bsa_SrcWidth = bitmap->width;
639 bsa.bsa_SrcHeight = bitmap->height;
640 bsa.bsa_DestX = 0;
641 bsa.bsa_DestY = 0;
642 bsa.bsa_XSrcFactor = bitmap->width;
643 bsa.bsa_XDestFactor = width;
644 bsa.bsa_YSrcFactor = bitmap->height;
645 bsa.bsa_YDestFactor = height;
646 bsa.bsa_SrcBitMap = tbm;
647 bsa.bsa_DestBitMap = scaledbm;
648 bsa.bsa_Flags = 0;
649
650 BitMapScale(&bsa);
651 }
652
653 if(bitmap->nativebm != tbm) ami_rtg_freebitmap(bitmap->nativebm);
654 ami_rtg_freebitmap(tbm);
655 tbm = scaledbm;
656 bitmap->nativebm = NULL;
657 bitmap->native = AMI_NSBM_NONE;
658
659 if(nsoption_int(cache_bitmaps) >= 1)
660 {
661 bitmap->nativebm = tbm;
662 bitmap->nativebmwidth = width;
663 bitmap->nativebmheight = height;
664 bitmap->native = type;
665 }
666 }
667
668 return tbm;
669 }
670
671
672 static inline struct BitMap *ami_bitmap_get_truecolour(struct bitmap *bitmap,
673 int width, int height, struct BitMap *friendbm)
674 {
675 if((bitmap->native != AMI_NSBM_NONE) && (bitmap->native != AMI_NSBM_TRUECOLOUR)) {
676 amiga_bitmap_modified(bitmap);
677 }
678
679 return ami_bitmap_get_generic(bitmap, width, height, friendbm, AMI_NSBM_TRUECOLOUR);
680 }
681
682 PLANEPTR ami_bitmap_get_mask(struct bitmap *bitmap, int width,
683 int height, struct BitMap *n_bm)
684 {
685 uint32 *bmi = (uint32 *) amiga_bitmap_get_buffer(bitmap);
686 UBYTE maskbit = 0;
687 ULONG bm_width;
688 int y, x, bpr;
689
690 if((height != bitmap->height) || (width != bitmap->width)) return NULL;
691 if(amiga_bitmap_get_opaque(bitmap) == true) return NULL;
692 if(bitmap->native_mask) return bitmap->native_mask;
693
694 bm_width = GetBitMapAttr(n_bm, BMA_WIDTH);
695 bpr = RASSIZE(bm_width, 1);
696 bitmap->native_mask = AllocRaster(bm_width, height);
697 SetMem(bitmap->native_mask, 0, bpr * height);
698
699 for(y=0; y<height; y++) {
700 for(x=0; x<width; x++) {
701 if ((*bmi & 0x000000ffU) <= (ULONG)nsoption_int(mask_alpha)) maskbit = 0;
702 else maskbit = 1;
703 bmi++;
704 bitmap->native_mask[(y*bpr) + (x/8)] |=
705 maskbit << (7 - (x % 8));
706 }
707 }
708
709 return bitmap->native_mask;
710 }
711
712 static inline struct BitMap *ami_bitmap_get_palettemapped(struct bitmap *bitmap,
713 int width, int height, struct BitMap *friendbm)
714 {
715 if((bitmap->native != AMI_NSBM_NONE) && (bitmap->native != AMI_NSBM_PALETTEMAPPED)) {
716 amiga_bitmap_modified(bitmap);
717 }
718
719 return ami_bitmap_get_generic(bitmap, width, height, friendbm, AMI_NSBM_PALETTEMAPPED);
720 }
721
722 struct BitMap *ami_bitmap_get_native(struct bitmap *bitmap,
723 int width, int height, bool palette_mapped, struct BitMap *friendbm)
724 {
725 if(bitmap == NULL) return NULL;
726
727 if(__builtin_expect(palette_mapped == true, 0)) {
728 return ami_bitmap_get_palettemapped(bitmap, width, height, friendbm);
729 } else {
730 return ami_bitmap_get_truecolour(bitmap, width, height, friendbm);
731 }
732 }
733
734 void ami_bitmap_fini(void)
735 {
736 if(pool_bitmap) ami_memory_itempool_delete(pool_bitmap);
737 pool_bitmap = NULL;
738 }
739
740 static nserror bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
741 {
742 #ifdef __amigaos4__
743 NSLOG(netsurf, INFO, "Entering bitmap_render");
744
745 int plot_width;
746 int plot_height;
747 struct gui_globals *bm_globals;
748
749 plot_width = MIN(content_get_width(content), bitmap->width);
750 plot_height = ((plot_width * bitmap->height) + (bitmap->width / 2)) /
751 bitmap->width;
752
753 bm_globals = ami_plot_ra_alloc(bitmap->width, bitmap->height, true, false);
754 ami_clearclipreg(bm_globals);
755
756 struct redraw_context ctx = {
757 .interactive = false,
758 .background_images = true,
759 .plot = &amiplot,
760 .priv = bm_globals
761 };
762
763 content_scaled_redraw(content, plot_width, plot_height, &ctx);
764
765 BltBitMapTags( BLITA_SrcX, 0,
766 BLITA_SrcY, 0,
767 BLITA_Width, bitmap->width,
768 BLITA_Height, bitmap->height,
769 BLITA_Source, ami_plot_ra_get_bitmap(bm_globals),
770 BLITA_SrcType, BLITT_BITMAP,
771 BLITA_Dest, amiga_bitmap_get_buffer(bitmap),
772 BLITA_DestType, BLITT_ARGB32,
773 BLITA_DestBytesPerRow, 4 * bitmap->width,
774 BLITA_DestX, 0,
775 BLITA_DestY, 0,
776 TAG_DONE);
777
778 ami_bitmap_argb_to_rgba(bitmap);
779
780 /**\todo In theory we should be able to move the bitmap to our native area
781 to try to avoid re-conversion (at the expense of memory) */
782
783 ami_plot_ra_free(bm_globals);
784 amiga_bitmap_set_opaque(bitmap, true);
785 #else
786 #warning FIXME for OS3 (in current state none of bitmap_render can work!)
787 #endif
788
789 return NSERROR_OK;
790 }
791
792 void ami_bitmap_set_url(struct bitmap *bm, struct nsurl *url)
793 {
794 if(bm->url != NULL) return;
795 bm->url = nsurl_ref(url);
796 }
797
798 void ami_bitmap_set_title(struct bitmap *bm, const char *title)
799 {
800 if(bm->title != NULL) return;
801 bm->title = strdup(title);
802 }
803
804 void ami_bitmap_set_icondata(struct bitmap *bm, ULONG *icondata)
805 {
806 bm->icondata = icondata;
807 }
808
809 void ami_bitmap_free_icondata(struct bitmap *bm)
810 {
811 if(bm->icondata) free(bm->icondata);
812 bm->icondata = NULL;
813 }
814
815 bool ami_bitmap_is_nativebm(struct bitmap *bm, struct BitMap *nbm)
816 {
817 if(bm->nativebm == nbm) return true;
818 else return false;
819 }
820
821
822 static struct gui_bitmap_table bitmap_table = {
823 .create = amiga_bitmap_create,
824 .destroy = amiga_bitmap_destroy,
825 .set_opaque = amiga_bitmap_set_opaque,
826 .get_opaque = amiga_bitmap_get_opaque,
827 .test_opaque = amiga_bitmap_test_opaque,
828 .get_buffer = amiga_bitmap_get_buffer,
829 .get_rowstride = amiga_bitmap_get_rowstride,
830 .get_width = bitmap_get_width,
831 .get_height = bitmap_get_height,
832 .get_bpp = bitmap_get_bpp,
833 .save = amiga_bitmap_save,
834 .modified = amiga_bitmap_modified,
835 .render = bitmap_render,
836 };
837
838 struct gui_bitmap_table *amiga_bitmap_table = &bitmap_table;
839