2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
6 /****************************************************************************************/
8 #include <datatypes/datatypes.h>
9 #include <intuition/intuition.h>
11 #include <proto/dos.h>
12 #include <proto/alib.h>
13 #include <proto/png.h>
14 #include <proto/datatypes.h>
16 #include <aros/bigendianio.h>
17 #include <aros/asmcall.h>
19 #include "icon_intern.h"
22 #include <aros/debug.h>
24 #define ATTR_ICONX 0x80001001
25 #define ATTR_ICONY 0x80001002
26 #define ATTR_DRAWERX 0x80001003
27 #define ATTR_DRAWERY 0x80001004
28 #define ATTR_DRAWERWIDTH 0x80001005
29 #define ATTR_DRAWERHEIGHT 0x80001006
30 #define ATTR_DRAWERFLAGS 0x80001007
31 #define ATTR_UNKNOWN 0x80001008 /* probably toolwindow? */
32 #define ATTR_STACKSIZE 0x80001009
33 #define ATTR_DEFAULTTOOL 0x8000100a
34 #define ATTR_TOOLTYPE 0x8000100b
35 #define ATTR_VIEWMODES 0x8000100c //OS4 PNG use that
36 #define ATTR_DD_CURRENTX 0x8000100d //OS4 PNG use that
37 #define ATTR_DD_CURRENTY 0x8000100e //OS4 PNG use that
38 #define ATTR_TYPE 0x8000100f //OS4 PNG use that
39 #define ATTR_DRAWERFLAGS2 0x80001107 //writen from AFA to store needed dopus Magellan settings
41 #define EFFECT_NONE (0)
42 #define EFFECT_LIGHTEN (1)
43 #define EFFECT_TINT_BLUE (2)
44 #define EFFECT_XOR (3)
46 #define EFFECT EFFECT_LIGHTEN
48 /****************************************************************************************/
51 ATTR_DRAWERFLAGS: AAABC
53 C : 1-bit flag : 0 = showonlyicons 1 = showallfiles
54 B : 1-bit flag : 0 = viewastext 1 = view as icons
55 AA : 2-bit value : 0 = viewbyname, 1 = viewbydata, 2 = viewbysize, 3 = viewbytype
58 static ULONG
flags_to_ddflags(ULONG flags
)
64 ret
= DDFLAGS_SHOWALL
;
68 ret
= DDFLAGS_SHOWICONS
;
74 static ULONG
flags_to_ddviewmodes(ULONG flags
)
84 ret
= (flags
>> 2) + DDVM_BYNAME
;
90 static ULONG
dd_to_flags(struct DiskObject
*dobj
)
92 ULONG drawerflags
= 0;
94 if (dobj
->do_DrawerData
->dd_Flags
& DDFLAGS_SHOWALL
)
99 if (dobj
->do_DrawerData
->dd_ViewModes
== DDVM_BYICON
)
105 drawerflags
|= ((dobj
->do_DrawerData
->dd_ViewModes
- 2) << 2);
111 /****************************************************************************************/
113 STATIC BOOL
MakePlanarImage(struct NativeIcon
*icon
, struct Image
**img
,
114 UBYTE
*src
, struct IconBase
*IconBase
)
116 LONG width16
= (icon
->iconPNG
.width
+ 15) & ~15;
117 LONG bpr
= width16
/ 8;
118 LONG planesize
= bpr
* icon
->iconPNG
.height
;
121 ULONG
*s
= (ULONG
*)src
;
123 *img
= (struct Image
*)AllocPooled(icon
->pool
, sizeof(struct Image
) + planesize
* 2);
124 if (*img
== NULL
) return FALSE
;
126 (*img
)->Width
= icon
->iconPNG
.width
;
127 (*img
)->Height
= icon
->iconPNG
.height
;
129 (*img
)->ImageData
= (UWORD
*)(*img
+ 1);
130 (*img
)->PlanePick
= 3;
132 p1
= (UWORD
*)(*img
)->ImageData
;
133 p2
= p1
+ planesize
/ 2;
135 for(y
= 0; y
< icon
->iconPNG
.height
; y
++)
137 ULONG pixelmask
= 0x8000;
141 for(x
= 0; x
< icon
->iconPNG
.width
; x
++)
146 if ((pixel
& 0xFF000000) > 0x80000000)
148 pixel
= (((pixel
& 0x00FF0000) >> 16) +
149 ((pixel
& 0x0000FF00) >> 8) +
150 ((pixel
& 0x000000FF)) +
153 if ((pixel
& 0x000000FF) > 0x80)
155 pixel
= (((pixel
& 0x0000FF00) >> 8) +
156 ((pixel
& 0x00FF0000) >> 16) +
157 ((pixel
& 0xFF000000) >> 24) +
164 plane2dat
|= pixelmask
;
166 else if ((pixel
== 2) || (pixel
== 1))
168 /* Col 3: Amiga Blue */
169 plane1dat
|= pixelmask
;
170 plane2dat
|= pixelmask
;
175 plane1dat
|= pixelmask
;
183 *p1
++ = AROS_WORD2BE(plane1dat
);
184 *p2
++ = AROS_WORD2BE(plane2dat
);
186 plane1dat
= plane2dat
= 0;
192 if (pixelmask
!= 0x8000)
194 *p1
++ = AROS_WORD2BE(plane1dat
);
195 *p2
++ = AROS_WORD2BE(plane2dat
);
199 } /* for(y = 0; y < icon->iconPNG.height; y++) */
205 /****************************************************************************************/
207 STATIC BOOL
MakePlanarImages(struct NativeIcon
*icon
, struct IconBase
*IconBase
)
209 if (!MakePlanarImage(icon
,
210 (struct Image
**)&icon
->dobj
.do_Gadget
.GadgetRender
,
217 icon
->dobj
.do_Gadget
.Flags
|= GFLG_GADGIMAGE
;
219 if (!icon
->iconPNG
.img2
) return TRUE
;
221 if (MakePlanarImage(icon
,
222 (struct Image
**)&icon
->dobj
.do_Gadget
.SelectRender
,
226 icon
->dobj
.do_Gadget
.Flags
|= GFLG_GADGHIMAGE
;
232 /****************************************************************************************/
234 BOOL
ReadIconPNG(struct DiskObject
**ret
, BPTR file
, struct IconBase
*IconBase
)
236 static STRPTR chunknames
[] =
241 APTR chunkpointer
[] =
247 struct NativeIcon
*icon
;
251 if (Seek(file
, 0, OFFSET_END
) < 0) return FALSE
;
252 if ((filesize
= Seek(file
, 0, OFFSET_BEGINNING
)) < 0) return FALSE
;
254 pool
= CreatePool(MEMF_ANY
| MEMF_CLEAR
, 1024, 1024);
255 if (!pool
) return FALSE
;
257 icon
= AllocPooled(pool
, sizeof(struct NativeIcon
) + filesize
);
266 icon
->iconPNG
.filebuffer
= (UBYTE
*)(icon
+ 1);
267 icon
->iconPNG
.filebuffersize
= filesize
;
269 /* Need a copy of whole file in memory for icon saving :-\ Because
270 that should save file back as it was, only with modified or new
271 icOn chunk. And it must also work when loading an icon and then
272 saving it using another name. */
274 if (Read(file
, icon
->iconPNG
.filebuffer
, filesize
) != filesize
)
280 icon
->iconPNG
.handle
= PNG_LoadImageMEM(icon
->iconPNG
.filebuffer
, filesize
,
281 chunknames
, chunkpointer
, TRUE
);
283 if (!icon
->iconPNG
.handle
)
285 FreeIconPNG(&icon
->dobj
, IconBase
);
292 PNG_GetImageInfo(icon
->iconPNG
.handle
, &width
, &height
, NULL
, NULL
);
294 icon
->iconPNG
.width
= width
;
295 icon
->iconPNG
.height
= height
;
297 PNG_GetImageData(icon
->iconPNG
.handle
, (APTR
*)&icon
->iconPNG
.img1
, NULL
);
299 #define DO(x) (&x->dobj)
301 DO(icon
)->do_Magic
= WB_DISKMAGIC
;
302 DO(icon
)->do_Version
= (WB_DISKVERSION
<< 8) | WB_DISKREVISION
;
303 DO(icon
)->do_Type
= WBPROJECT
;
304 DO(icon
)->do_CurrentX
= NO_ICON_POSITION
;
305 DO(icon
)->do_CurrentY
= NO_ICON_POSITION
;
306 DO(icon
)->do_Gadget
.Width
= width
;
307 DO(icon
)->do_Gadget
.Height
= height
;
308 DO(icon
)->do_StackSize
= AROS_STACKSIZE
;
315 ULONG ttarraysize
= 0;
318 PNG_GetChunkInfo(chunkpointer
[0], (APTR
*)&chunkdata
, &chunksize
);
320 while(chunksize
>= 4)
324 BOOL need_drawerdata
= FALSE
;
326 attr
= (chunkdata
[0] << 24) | (chunkdata
[1] << 16) | (chunkdata
[2] << 8) | chunkdata
[3];
334 case ATTR_DRAWERWIDTH
:
335 case ATTR_DRAWERHEIGHT
:
336 case ATTR_DRAWERFLAGS
:
337 case ATTR_DRAWERFLAGS2
:
339 case ATTR_DD_CURRENTX
:
340 case ATTR_DD_CURRENTY
:
341 need_drawerdata
= TRUE
;
350 val
= (chunkdata
[0] << 24) | (chunkdata
[1] << 16) | (chunkdata
[2] << 8) | chunkdata
[3];
360 /* case ATTR_UNKNOWN: */
361 case ATTR_DEFAULTTOOL
:
363 val
= (IPTR
)chunkdata
;
364 chunksize
-= strlen((char *)val
) + 1;
365 chunkdata
+= strlen((char *)val
) + 1;
374 /* Unknown attribute/tag. Impossible to handle correctly
375 if we don't know if it's a string attribute or not. */
383 if (need_drawerdata
&& !(DO(icon
)->do_DrawerData
))
385 DO(icon
)->do_DrawerData
= AllocPooled(pool
, sizeof(struct DrawerData
));
386 if (!(DO(icon
)->do_DrawerData
))
392 DO(icon
)->do_DrawerData
->dd_NewWindow
.LeftEdge
= 20;
393 DO(icon
)->do_DrawerData
->dd_NewWindow
.TopEdge
= 20;
394 DO(icon
)->do_DrawerData
->dd_NewWindow
.Width
= 300;
395 DO(icon
)->do_DrawerData
->dd_NewWindow
.Height
= 200;
401 DO(icon
)->do_CurrentX
= val
;
405 DO(icon
)->do_CurrentY
= val
;
409 DO(icon
)->do_StackSize
= val
;
413 DO(icon
)->do_DrawerData
->dd_NewWindow
.LeftEdge
= (WORD
)val
;
417 DO(icon
)->do_DrawerData
->dd_NewWindow
.TopEdge
= (WORD
)val
;
420 case ATTR_DRAWERWIDTH
:
421 DO(icon
)->do_DrawerData
->dd_NewWindow
.Width
= (WORD
)val
;
424 case ATTR_DRAWERHEIGHT
:
425 DO(icon
)->do_DrawerData
->dd_NewWindow
.Height
= (WORD
)val
;
428 case ATTR_DRAWERFLAGS
:
429 DO(icon
)->do_DrawerData
->dd_Flags
= flags_to_ddflags(val
);
430 DO(icon
)->do_DrawerData
->dd_ViewModes
= flags_to_ddviewmodes(val
);
433 case ATTR_DEFAULTTOOL
:
434 DO(icon
)->do_DefaultTool
= AllocPooled(pool
, strlen((char *)val
) + 1);
435 if (DO(icon
)->do_DefaultTool
)
437 strcpy(DO(icon
)->do_DefaultTool
, (char *)val
);
447 if (ttarraysize
< ttnum
+ 1)
449 STRPTR
*old_tooltypes
= DO(icon
)->do_ToolTypes
;
450 ULONG old_ttarraysize
= ttarraysize
;
454 DO(icon
)->do_ToolTypes
= AllocPooled(pool
, ttarraysize
* sizeof(APTR
));
455 if (DO(icon
)->do_ToolTypes
)
459 memcpy(DO(icon
)->do_ToolTypes
, old_tooltypes
, (ttnum
- 1) * sizeof(APTR
));
467 if (old_tooltypes
) FreePooled(pool
, old_tooltypes
, old_ttarraysize
* sizeof(APTR
));
472 DO(icon
)->do_ToolTypes
[ttnum
- 1] = AllocPooled(pool
, strlen((char *)val
) + 1);
473 if (DO(icon
)->do_ToolTypes
[ttnum
- 1])
475 strcpy(DO(icon
)->do_ToolTypes
[ttnum
- 1], (char *)val
);
487 } /* while(chunksize >= 4) */
489 PNG_FreeChunk(chunkpointer
[0]);
493 D(bug("=== Failure during icOn chunk parsing ===\n"));
494 FreeIconPNG(&icon
->dobj
, IconBase
);
499 } /* if (chunkpointer[0]) */
503 #warning "FIXME: Someone killed PNG Icon do_Type detection here which causes"
504 #warning " following lines to always free DrawerData even when it"
505 #warning " shouldn't be freed (only possible to know if do_Type is"
506 #warning " known). So for now following lines disabled and DrawerData"
507 #warning " is always kept (even when it shouldn't)."
510 if (icon
->dobj
.do_DrawerData
&&
511 (icon
->dobj
.do_Type
!= WBDISK
) &&
512 (icon
->dobj
.do_Type
!= WBDRAWER
) &&
513 (icon
->dobj
.do_Type
!= WBGARBAGE
))
515 FreePooled(pool
, icon
->dobj
.do_DrawerData
, sizeof(struct DrawerData
));
516 icon
->dobj
.do_DrawerData
= NULL
;
522 /* Look for a possible 2nd PNG image attached onto the first one */
524 UBYTE
*filepos
= icon
->iconPNG
.filebuffer
+ 8;
529 ULONG chunksize
= (filepos
[0] << 24) | (filepos
[1] << 16) |
530 (filepos
[2] << 8) | filepos
[3];
531 ULONG chunktype
= (filepos
[4] << 24) | (filepos
[5] << 16) |
532 (filepos
[6] << 8) | filepos
[7];
536 if (chunktype
== MAKE_ID('I', 'E', 'N', 'D'))
541 filepos
+= chunksize
;
544 if (filepos
+ 8 < icon
->iconPNG
.filebuffer
+ icon
->iconPNG
.filebuffersize
)
546 ULONG offset
= filepos
- icon
->iconPNG
.filebuffer
;
548 icon
->iconPNG
.handle2
= PNG_LoadImageMEM(filepos
, filesize
- offset
, 0, 0, TRUE
);
550 if (icon
->iconPNG
.handle2
)
554 PNG_GetImageInfo(icon
->iconPNG
.handle2
, &width
, &height
, NULL
, NULL
);
556 if ((width
== icon
->iconPNG
.width
) &&
557 (height
== icon
->iconPNG
.height
))
559 PNG_GetImageData(icon
->iconPNG
.handle2
, (APTR
*)&icon
->iconPNG
.img2
, NULL
);
563 PNG_FreeImage(icon
->iconPNG
.handle2
);
564 icon
->iconPNG
.handle2
= NULL
;
572 /* If there's no image for selected-state, generate one */
573 if (!icon
->iconPNG
.img2
)
575 ULONG size
= icon
->iconPNG
.width
* icon
->iconPNG
.height
;
577 if ((icon
->iconPNG
.img2
= AllocPooled(pool
, size
* sizeof(ULONG
))))
579 ULONG
*src
= (ULONG
*)icon
->iconPNG
.img1
;
580 ULONG
*dst
= (ULONG
*)icon
->iconPNG
.img2
;
584 ULONG pixel
= *src
++;
586 /* Effects like in changetoselectediconcolor.c */
588 #if EFFECT == EFFECT_LIGHTEN
590 pixel
= (pixel
& 0xFF000000) +
591 ((pixel
>> 1) & 0x007F7F7F) +
594 pixel
= (pixel
& 0x000000FF) +
595 ((pixel
>> 1) & 0x7F7F7F00) +
598 #elif EFFECT == EFFECT_TINT_BLUE
600 pixel
= (pixel
& 0xFF000000) +
601 ((pixel
>> 1) & 0x007F7F7F) +
604 pixel
= (pixel
& 0x000000FF) +
605 ((pixel
>> 1) & 0x7F7F7F00) +
609 #elif EFFECT == EFFECT_XOR
611 pixel
= (pixel
& 0xFF000000) +
612 ((pixel
& 0x00FFFFFF) ^ 0x00FFFFFF);
614 pixel
= (pixel
& 0x000000FF) +
615 ((pixel
& 0xFFFFFF00) ^ 0xFFFFFF00);
623 /* Make fallback planar images */
625 if (!MakePlanarImages(icon
, IconBase
))
627 D(bug("Planar image creation failed\n"));
628 FreeIconPNG(&icon
->dobj
, IconBase
);
638 /****************************************************************************************/
640 STATIC VOID
MakeCRCTable(struct IconBase
*IconBase
)
645 for (n
= 0; n
< 256; n
++)
647 c
= (unsigned long) n
;
648 for (k
= 0; k
< 8; k
++)
651 c
= 0xedb88320L
^ (c
>> 1);
655 IconBase
->ib_CRCTable
[n
] = c
;
658 IconBase
->ib_CRCTableComputed
= TRUE
;
662 /****************************************************************************************/
664 STATIC ULONG
UpdateCRC(ULONG crc
, UBYTE
*buf
, ULONG len
, struct IconBase
*IconBase
)
669 ObtainSemaphore(&IconBase
->iconlistlock
);
670 if (!IconBase
->ib_CRCTableComputed
)
672 MakeCRCTable(IconBase
);
674 ReleaseSemaphore(&IconBase
->iconlistlock
);
676 for (n
= 0; n
< len
; n
++)
678 c
= IconBase
->ib_CRCTable
[(c
^ buf
[n
]) & 0xff] ^ (c
>> 8);
685 /****************************************************************************************/
687 STATIC BOOL
WriteIconAttr(BPTR file
, ULONG id
, ULONG val
, ULONG
*chunksize
,
688 ULONG
*crc
, struct IconBase
*IconBase
)
701 if (Write(file
, buf
, 8) != 8) return FALSE
;
704 *crc
= UpdateCRC(*crc
, buf
, 8, IconBase
);
708 /****************************************************************************************/
710 STATIC BOOL
WriteIconStrAttr(BPTR file
, ULONG id
, char *val
, ULONG
*chunksize
,
711 ULONG
*crc
, struct IconBase
*IconBase
)
714 ULONG len
= strlen(val
) + 1;
721 if (Write(file
, buf
, 4) != 4) return FALSE
;
722 *crc
= UpdateCRC(*crc
, buf
, 4, IconBase
);
724 if (Write(file
, val
, len
) != len
) return FALSE
;
725 *crc
= UpdateCRC(*crc
, val
, len
, IconBase
);
727 *chunksize
+= 4 + len
;
732 /****************************************************************************************/
734 STATIC BOOL
WriteIconChunk(BPTR file
, struct DiskObject
*dobj
, struct IconBase
*IconBase
)
736 ULONG crc
= 0xFFFFFFFF;
738 ULONG sizeseek
= Seek(file
, 0, OFFSET_CURRENT
);
739 UBYTE buf
[] = {0x12, 0x34, 0x56, 0x78, 'i', 'c', 'O', 'n'};
741 if (sizeseek
< 0) return FALSE
;
743 /* Write Chunk size + chunk type */
744 if (Write(file
, buf
, 8) != 8) return FALSE
;
746 crc
= UpdateCRC(crc
, buf
+ 4, 4, IconBase
); /* chunksize is excluded from CRC */
748 /* Write Stack Size */
750 if (!WriteIconAttr(file
, ATTR_STACKSIZE
, dobj
->do_StackSize
, &chunksize
, &crc
, IconBase
))
755 /* Write Icon X Position */
756 if (dobj
->do_CurrentX
!= NO_ICON_POSITION
)
758 if (!WriteIconAttr(file
, ATTR_ICONX
, dobj
->do_CurrentX
, &chunksize
, &crc
, IconBase
))
764 /* Write Icon Y Position */
765 if (dobj
->do_CurrentY
!= NO_ICON_POSITION
)
767 if (!WriteIconAttr(file
, ATTR_ICONY
, dobj
->do_CurrentY
, &chunksize
, &crc
, IconBase
))
773 if (dobj
->do_DrawerData
)
775 if (!WriteIconAttr(file
, ATTR_DRAWERX
, dobj
->do_DrawerData
->dd_NewWindow
.LeftEdge
,
776 &chunksize
, &crc
, IconBase
))
781 if (!WriteIconAttr(file
, ATTR_DRAWERY
, dobj
->do_DrawerData
->dd_NewWindow
.TopEdge
,
782 &chunksize
, &crc
, IconBase
))
787 if (!WriteIconAttr(file
, ATTR_DRAWERWIDTH
, dobj
->do_DrawerData
->dd_NewWindow
.Width
,
788 &chunksize
, &crc
, IconBase
))
793 if (!WriteIconAttr(file
, ATTR_DRAWERHEIGHT
, dobj
->do_DrawerData
->dd_NewWindow
.Height
,
794 &chunksize
, &crc
, IconBase
))
799 if (!WriteIconAttr(file
, ATTR_DRAWERFLAGS
, dd_to_flags(dobj
),
800 &chunksize
, &crc
, IconBase
))
805 } /* if (dobj->do_DrawerData) */
807 if (dobj
->do_DefaultTool
)
809 if (!WriteIconStrAttr(file
, ATTR_DEFAULTTOOL
, dobj
->do_DefaultTool
,
810 &chunksize
, &crc
, IconBase
))
817 if (dobj
->do_ToolTypes
)
819 STRPTR
*tt
= (STRPTR
*)dobj
->do_ToolTypes
;
821 for(tt
= (STRPTR
*)dobj
->do_ToolTypes
; *tt
; tt
++)
823 if (!WriteIconStrAttr(file
, ATTR_TOOLTYPE
, *tt
, &chunksize
,
838 if (Write(file
, buf
, 4) != 4) return FALSE
;
840 /* Write chunk's size */
841 if (Seek(file
, sizeseek
, OFFSET_BEGINNING
) < 0) return FALSE
;
843 buf
[0] = chunksize
>> 24;
844 buf
[1] = chunksize
>> 16;
845 buf
[2] = chunksize
>> 8;
847 if (Write(file
, buf
, 4) != 4) return FALSE
;
849 if (Seek(file
, 0, OFFSET_END
) < 0) return FALSE
;
854 /****************************************************************************************/
856 BOOL
WriteIconPNG(BPTR file
, struct DiskObject
*dobj
, struct IconBase
*IconBase
)
858 struct NativeIcon
*nativeicon
= NATIVEICON(dobj
);
859 struct IconPNG
*iconpng
= &nativeicon
->iconPNG
;
860 UBYTE
*mempos
= iconpng
->filebuffer
;
863 /* Write PNG header */
864 if (Write(file
, iconpng
->filebuffer
, 8) != 8) return FALSE
;
870 ULONG chunksize
= (mempos
[0] << 24) | (mempos
[1] << 16) |
871 (mempos
[2] << 8) | mempos
[3];
872 ULONG chunktype
= (mempos
[4] << 24) | (mempos
[5] << 16) |
873 (mempos
[6] << 8) | mempos
[7];
877 if (chunktype
== MAKE_ID('I', 'E', 'N', 'D'))
879 if (!WriteIconChunk(file
, dobj
, IconBase
)) return FALSE
;
883 if (chunktype
!= MAKE_ID('i', 'c', 'O', 'n'))
885 if (Write(file
, mempos
, chunksize
) != chunksize
)
895 if (mempos
< iconpng
->filebuffer
+ iconpng
->filebuffersize
)
897 ULONG size
= iconpng
->filebuffer
+ iconpng
->filebuffersize
- mempos
;
899 /* 2nd PNG Image attached */
901 if (Write(file
, mempos
, size
) != size
) return FALSE
;
907 /****************************************************************************************/
909 VOID
FreeIconPNG(struct DiskObject
*dobj
, struct IconBase
*IconBase
)
913 struct NativeIcon
*nativeicon
= NATIVEICON(dobj
);
915 if (nativeicon
->iconPNG
.handle
)
917 PNG_FreeImage(nativeicon
->iconPNG
.handle
);
920 if (nativeicon
->iconPNG
.handle2
)
922 PNG_FreeImage(nativeicon
->iconPNG
.handle2
);
925 if (nativeicon
->pool
) DeletePool(nativeicon
->pool
);
929 /****************************************************************************************/