2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
6 #include <aros/debug.h>
8 #include <exec/types.h>
9 #include <workbench/icon.h>
10 #include <utility/tagitem.h>
11 #include <graphics/gfxmacros.h>
12 #include <proto/icon.h>
14 #include "icon_intern.h"
15 #include "support_builtin.h"
18 static BOOL
scaleToResolution(ULONG SrcWidth
, ULONG SrcHeight
,
19 UWORD SrcResX
, UWORD SrcResY
,
20 ULONG
*DstWidth
, ULONG
*DstHeight
,
21 UWORD DstResX
, UWORD DstResY
,
22 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
23 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
24 struct IconBase
*IconBase
);
26 static BOOL
scaleToBounds(ULONG SrcWidth
, ULONG SrcHeight
,
27 UWORD MaxWidth
, UWORD MaxHeight
,
28 ULONG
*DstWidth
, ULONG
*DstHeight
,
29 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
30 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
31 struct IconBase
*IconBase
);
33 /* ARGB image scaling */
34 static void ScaleRect(ULONG
*Target
, const ULONG
*Source
, int SrcWidth
, int SrcHeight
, int TgtWidth
, int TgtHeight
);
36 /*****************************************************************************
40 AROS_LH3(BOOL
, LayoutIconA
,
43 AROS_LHA(struct DiskObject
*, icon
, A0
),
44 AROS_LHA(struct Screen
*, screen
, A1
),
45 AROS_LHA(struct TagItem
*, tags
, A2
),
48 struct IconBase
*, IconBase
, 32, Icon
)
51 Adapt a palette-mapped icon for display.
68 *****************************************************************************/
72 /* Default source DPI is the Amiga PAL DPI */
74 ULONG scaleXsrc
= 1, scaleYsrc
= 1, scaleXdst
= 1, scaleYdst
= 1;
75 ULONG mutualexclude
= (ULONG
)icon
->do_Gadget
.MutualExclude
;
77 struct NativeIcon
*ni
;
83 const ULONG bflags
= BMF_CLEAR
;
84 ni
= GetNativeIcon(icon
, LB(IconBase
));
88 if (ni
->ni_Width
<= 0)
89 ni
->ni_Width
= ni
->ni_DiskObject
.do_Gadget
.Width
;
90 if (ni
->ni_Height
<= 0)
91 ni
->ni_Height
= ni
->ni_DiskObject
.do_Gadget
.Height
;
93 D(bug("[%s] Icon %p, Screen %p, %xx%x icon\n", __func__
, icon
, screen
, ni
->ni_Width
, ni
->ni_Height
));
95 /* Already mapped to this screen?
97 if (screen
== ni
->ni_Screen
)
100 for (i
= 0; i
< 2; i
++) {
101 struct NativeIconImage
*image
= &ni
->ni_Image
[i
];
104 FreeBitMap(image
->BitMap
);
105 image
->BitMap
= NULL
;
108 if (image
->ARGBMap
&& image
->ARGBMap
!= image
->ARGB
) {
109 FreeVec(image
->ARGBMap
);
113 for (j
= 0; j
< image
->Pens
; j
++) {
114 ReleasePen(ni
->ni_Screen
->ViewPort
.ColorMap
, image
->Pen
[j
]);
120 /* Remove the synthesized BitMask */
121 if (image
->BitMask
) {
122 FreeVec(image
->BitMask
);
123 image
->BitMask
= NULL
;
127 ni
->ni_Screen
= NULL
;
132 dri
= GetScreenDrawInfo(screen
);
136 /* Look up the DrawInfo Pens we will need for the
137 * layout of the border and frame.
139 for (i
= 0; i
< NUMDRIPENS
; i
++) {
140 if (i
< dri
->dri_NumPens
)
141 ni
->ni_Pens
[i
] = dri
->dri_Pens
[i
];
143 ni
->ni_Pens
[i
] = dri
->dri_Pens
[DETAILPEN
];
146 cm
= screen
->ViewPort
.ColorMap
;
148 /* NOTE: The ARGB data (if present) will not need
151 D(bug("%s: Screen %p, Depth %d, ColorMap %d\n", __func__
, screen
, dri
->dri_Depth
, cm
? cm
->Count
: -1));
155 /* Calculate the scaling factors
157 if (ni
->ni_Face
.Width
&& ni
->ni_Face
.Height
) {
158 width
= ni
->ni_Face
.Width
;
159 height
= ni
->ni_Face
.Height
;
161 width
= icon
->do_Gadget
.Width
;
162 height
= icon
->do_Gadget
.Height
;
165 if (ni
->ni_ScaleBox
== ICON_SCALEBOX_DEFAULT
)
166 scalebox
= LB(IconBase
)->ib_ScaleBox
;
168 scalebox
= ni
->ni_ScaleBox
;
170 ni
->ni_Width
= width
;
171 ni
->ni_Height
= height
;
173 /* Are we rescaling dynamically? */
174 if (scalebox
== ICON_SCALEBOX_AUTOSCALE
) {
175 UBYTE tpdX
= 0, tpdY
= 0;
177 /* Check for a magic MutualExlcude value
178 * that encodes Tick-Per-Dot information.
179 * MutalExclude of 0xffffffff is not valid.
181 if ((mutualexclude
!= 0xffffffff) && (mutualexclude
& (1 << 31))) {
182 /* tpd information is in the lower 16 bits */
183 tpdX
= (mutualexclude
>> 8) & 0xff;
184 tpdY
= (mutualexclude
>> 0) & 0xff;
188 scaleToResolution(width
, height
, tpdX
, tpdY
,
189 &ni
->ni_Width
, &ni
->ni_Height
, dri
->dri_Resolution
.X
, dri
->dri_Resolution
.Y
,
190 &scaleXsrc
, &scaleYsrc
, &scaleXdst
, &scaleYdst
,
193 D(bug("%s: Icon tpd (%d:%d), Screen tpd (%d:%d)\n", __func__
,
194 tpdX
, tpdY
, dri
->dri_Resolution
.X
, dri
->dri_Resolution
.Y
));
197 WORD MaxWidth
, MaxHeight
;
199 UNPACK_ICON_SCALEBOX(scalebox
, MaxWidth
, MaxHeight
);
201 scaleToBounds(width
, height
, MaxWidth
, MaxHeight
,
202 &ni
->ni_Width
, &ni
->ni_Height
,
203 &scaleXsrc
, &scaleYsrc
, &scaleXdst
, &scaleYdst
,
207 for (i
= 0; i
< 2; i
++) {
208 struct NativeIconImage
*image
= &ni
->ni_Image
[i
];
209 struct TagItem pentags
[] = {
210 { OBP_Precision
, IconBase
->ib_Precision
},
211 { OBP_FailIfBad
, FALSE
},
212 { TAG_MORE
, (IPTR
)tags
},
218 bmdepth
= GetBitMapAttr(screen
->RastPort
.BitMap
, BMA_DEPTH
);
220 /* If we can use ARGB data, then use it! */
221 D(bug("[%s] Screen depth is %d\n", __func__
, bmdepth
));
222 if ((bmdepth
> 8) && CyberGfxBase
) {
223 FetchIconARGB(icon
, i
);
225 if (width
!= ni
->ni_Width
|| height
!= ni
->ni_Height
) {
226 if ((image
->ARGBMap
= AllocVec(ni
->ni_Width
* ni
->ni_Height
* sizeof(ULONG
), MEMF_PUBLIC
))) {
227 D(bug("[%s] ARGB scaling\n"));
228 ScaleRect(image
->ARGBMap
, image
->ARGB
, width
, height
, ni
->ni_Width
, ni
->ni_Height
);
229 width
= ni
->ni_Width
;
230 height
= ni
->ni_Height
;
233 image
->ARGBMap
= (APTR
)image
->ARGB
;
236 if (image
->ARGBMap
) {
239 D(bug("[%s] No ARGB image\n"));
243 /* Allocate a bitmap, which is a 'friend' of the screen */
244 image
->BitMap
= AllocBitMap(width
, height
, dri
->dri_Depth
, bflags
, screen
->RastPort
.BitMap
);
245 if (image
->BitMap
== NULL
) {
246 SetIoErr(ERROR_NO_FREE_STORE
);
251 FetchIconImage(icon
, i
);
253 if (!image
->ImageData
) {
254 struct Image
*gi
= NULL
;
258 if (i
== 1 && (icon
->do_Gadget
.Flags
& GFLG_GADGHIMAGE
)) {
259 gi
= icon
->do_Gadget
.SelectRender
;
260 } else if (icon
->do_Gadget
.Flags
& GFLG_GADGIMAGE
) {
261 gi
= icon
->do_Gadget
.GadgetRender
;
267 if (i
== 1 && (icon
->do_Gadget
.Flags
& GFLG_GADGHCOMP
))
268 state
= IDS_SELECTED
;
272 if (i
== 1 && (icon
->do_Gadget
.Flags
& GFLG_GADGBACKFILL
)) {
273 state
= IDS_SELECTED
;
279 rp
.BitMap
= image
->BitMap
;
280 DrawImageState(&rp
, gi
, 0, 0, state
, dri
);
282 /* Create a bitmap with a 1 pixel border,
283 * fill it with the inverse color,
284 * draw the inverse image into it,
285 * then flood-fill the border with color 0.
287 * Finally, copy the final image to the
288 * destination bitmap.
291 if ((bm
= AllocBitMap(gi
->Width
+2, gi
->Height
+2, gi
->Depth
, BMF_CLEAR
, NULL
))) {
296 if ((trbuf
= AllocRaster(gi
->Width
+2, gi
->Height
+2))) {
298 InitTmpRas(&tr
, trbuf
, RASSIZE(gi
->Width
+2, gi
->Height
+2));
300 SetAPen(&rp
, (1 << gi
->Depth
)-1);
301 RectFill(&rp
, 0, 0, gi
->Width
+1, gi
->Height
+1);
302 DrawImageState(&rp
, gi
, 1, 1, state
, dri
);
305 BltBitMap(bm
, 1, 1, image
->BitMap
, 0, 0, gi
->Width
, gi
->Height
, 0xc0, ~0, NULL
);
306 FreeRaster(trbuf
, gi
->Width
+2, gi
->Height
+2);
315 /* Palettized image processing */
317 image
->Pen
= AllocVec(image
->Pens
* sizeof(image
->Pen
[0]), MEMF_PUBLIC
| MEMF_CLEAR
);
320 SetIoErr(ERROR_NO_FREE_STORE
);
325 /* Get the needed colormap entries. */
326 for (j
= 0; j
< image
->Pens
; j
++) {
329 /* CHECKME: So, uh, how does one accuarately
330 * convert 8 bit RGB to 32 bit RBG?
332 r
= image
->Palette
[j
].red
<< 24;
333 g
= image
->Palette
[j
].green
<< 24;
334 b
= image
->Palette
[j
].blue
<< 24;
335 pen
= ObtainBestPenA(cm
, r
, g
, b
, pentags
);
336 image
->Pen
[j
] = (UBYTE
)pen
;
339 /* Draw the selected state into the screen's pens
341 * We take the risk of yet another memory allocation
342 * so that we can use WriteChunkyPixels(), which is
343 * GOBS faster than WritePixel().
345 idata
= AllocVec(height
* width
, MEMF_ANY
);
347 FreeBitMap(image
->BitMap
);
348 image
->BitMap
= NULL
;
349 SetIoErr(ERROR_NO_FREE_STORE
);
353 CopyMem(image
->ImageData
, idata
, height
* width
);
354 for (x
= 0; x
< (height
* width
); x
++) {
355 idata
[x
] = image
->Pen
[image
->ImageData
[x
]];
358 rp
.BitMap
= image
->BitMap
;
359 WriteChunkyPixels(&rp
, 0, 0, width
- 1, height
- 1,
363 /* Synthesize a bitmask for transparentcolor icons */
364 D(bug("[%s] TransparentColor %d\n", __func__
, image
->TransparentColor
));
365 if (image
->TransparentColor
>= 0) {
369 UWORD bpr
= image
->BitMap
->BytesPerRow
;
370 image
->BitMask
= AllocVec(bpr
* height
+ 4, MEMF_PUBLIC
| MEMF_CHIP
| MEMF_CLEAR
);
371 if (!image
->BitMask
) {
372 SetIoErr(ERROR_NO_FREE_STORE
);
376 img
= image
->ImageData
;
377 row
= image
->BitMask
;
378 #ifdef __mc68000 /* AGA support */
379 row
= (APTR
)(((IPTR
)row
+ 7) & ~7);
381 for (y
= 0; y
< height
; y
++, row
+= bpr
) {
382 for (x
= 0; x
< width
; x
++, img
++) {
383 if ((*img
!= image
->TransparentColor
)) {
384 row
[x
>>3] |= 1 << (7 - (x
& 7));
391 if (width
!= ni
->ni_Width
|| height
!= ni
->ni_Height
) {
392 struct BitMap
*bm
= AllocBitMap(ni
->ni_Width
, ni
->ni_Height
, dri
->dri_Depth
, bflags
, image
->BitMap
);
394 D(bug("%s: Rescaling from %dx%d to %dx%d\n", __func__
,
395 width
, height
, ni
->ni_Width
, ni
->ni_Height
));
398 struct BitScaleArgs bsa
= {
399 .bsa_SrcBitMap
= image
->BitMap
,
402 .bsa_SrcWidth
= width
,
403 .bsa_SrcHeight
= height
,
404 .bsa_XSrcFactor
= scaleXsrc
,
405 .bsa_XDestFactor
= scaleXdst
,
406 .bsa_YSrcFactor
= scaleYsrc
,
407 .bsa_YDestFactor
= scaleYdst
,
408 .bsa_DestBitMap
= bm
,
412 if (image
->BitMask
) {
413 struct BitMap src
, dst
;
415 src
.BytesPerRow
= image
->BitMap
->BytesPerRow
;
419 src
.Planes
[0] = image
->BitMask
;
420 #ifdef __mc68000 /* AGA support */
421 src
.Planes
[0] = (APTR
)(((IPTR
)src
.Planes
[0] + 7) & ~7);
423 dst
.BytesPerRow
= bm
->BytesPerRow
;
424 dst
.Rows
= ni
->ni_Height
;
427 dst_mask
= AllocVec(dst
.BytesPerRow
* dst
.Rows
+ 4, MEMF_PUBLIC
| MEMF_CHIP
| MEMF_CLEAR
);
428 dst
.Planes
[0] = dst_mask
;
430 #ifdef __mc68000 /* AGA support */
431 dst
.Planes
[0] = (APTR
)(((IPTR
)dst
.Planes
[0] + 7) & ~7);
433 bsa
.bsa_SrcBitMap
= &src
;
434 bsa
.bsa_DestBitMap
= &dst
;
437 bsa
.bsa_SrcWidth
= width
,
438 bsa
.bsa_SrcHeight
= height
,
439 bsa
.bsa_XSrcFactor
= scaleXsrc
,
440 bsa
.bsa_XDestFactor
= scaleXdst
,
441 bsa
.bsa_YSrcFactor
= scaleYsrc
,
442 bsa
.bsa_YDestFactor
= scaleYdst
,
445 FreeVec(image
->BitMask
);
446 image
->BitMask
= dst_mask
;
454 FreeBitMap(image
->BitMap
);
460 /* Hack to support Directory Opus 4/5, which insists
461 * on drawing its own icon imagery instead of calling
464 if (!icon
->do_Gadget
.GadgetRender
) {
465 GetBuiltinImage(&ni
->ni_Image
[0].Render
, icon
->do_Type
, FALSE
);
466 icon
->do_Gadget
.GadgetRender
= &ni
->ni_Image
[0].Render
;
469 if (!icon
->do_Gadget
.SelectRender
) {
470 GetBuiltinImage(&ni
->ni_Image
[1].Render
, icon
->do_Type
, TRUE
);
471 icon
->do_Gadget
.SelectRender
= &ni
->ni_Image
[1].Render
;
474 ni
->ni_Screen
= screen
;
477 FreeScreenDrawInfo(screen
, dri
);
485 } /* LayoutIconA() */
488 static BOOL
scaleToBounds(ULONG SrcWidth
, ULONG SrcHeight
,
489 UWORD MaxWidth
, UWORD MaxHeight
,
490 ULONG
*DstWidth
, ULONG
*DstHeight
,
491 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
492 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
493 struct IconBase
*IconBase
)
495 ULONG scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
;
497 if (MaxWidth
<= 0 || MaxHeight
<= 0)
500 /* Scaling calculations
502 scaleXsrc
= SrcWidth
;
503 scaleYsrc
= SrcHeight
;
504 scaleXdst
= MaxWidth
;
505 scaleYdst
= SrcHeight
* MaxWidth
/ SrcWidth
;
507 if (scaleYdst
> MaxHeight
) {
508 LONG delta
= scaleYdst
- MaxHeight
;
509 scaleXdst
-= delta
* SrcWidth
/ SrcHeight
;
513 while (scaleXsrc
> 168383 || scaleXdst
> 168383) {
516 if (scaleXsrc
== 0 || scaleXdst
== 0) {
517 D(bug("\tCan't scale X from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
522 while (scaleYsrc
> 168383 || scaleYdst
> 168383) {
525 if (scaleYsrc
== 0 || scaleYdst
== 0) {
526 D(bug("\tCan't scale Y from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
531 *DstWidth
= ScalerDiv(SrcWidth
, scaleXdst
, scaleXsrc
);
532 *DstHeight
= ScalerDiv(SrcHeight
, scaleYdst
, scaleYsrc
);
534 *ScaleXSrc
= scaleXsrc
;
535 *ScaleYSrc
= scaleYsrc
;
537 *ScaleXDst
= scaleXdst
;
538 *ScaleYDst
= scaleYdst
;
540 D(bug("[%s] Scale icon %dx%d to box %dx%d => %dx%d\n", __func__
, SrcWidth
, SrcHeight
, MaxWidth
, MaxHeight
, *DstWidth
, *DstHeight
));
545 static BOOL
scaleToResolution(ULONG SrcWidth
, ULONG SrcHeight
,
546 UWORD SrcResX
, UWORD SrcResY
,
547 ULONG
*DstWidth
, ULONG
*DstHeight
,
548 UWORD DstResX
, UWORD DstResY
,
549 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
550 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
551 struct IconBase
*IconBase
)
553 ULONG scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
;
555 /* Scaling calculations
556 * Remember: 'res' is in 'ticks', which is inversely
557 * related to display DPI.
559 scaleXsrc
= SrcWidth
;
560 scaleYsrc
= SrcHeight
;
561 scaleXdst
= SrcWidth
* SrcResX
/ DstResX
;
562 scaleYdst
= SrcHeight
* SrcResY
/ DstResY
;
564 while (scaleXsrc
> 168383 || scaleXdst
> 168383) {
567 if (scaleXsrc
== 0 || scaleXdst
== 0) {
568 D(bug("\tCan't scale X from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
573 while (scaleYsrc
> 168383 || scaleYdst
> 168383) {
576 if (scaleYsrc
== 0 || scaleYdst
== 0) {
577 D(bug("\tCan't scale Y from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
582 *DstWidth
= ScalerDiv(SrcWidth
, scaleXdst
, scaleXsrc
);
583 *DstHeight
= ScalerDiv(SrcHeight
, scaleYdst
, scaleYsrc
);
585 *ScaleXSrc
= scaleXsrc
;
586 *ScaleYSrc
= scaleYsrc
;
588 *ScaleXDst
= scaleXdst
;
589 *ScaleYDst
= scaleYdst
;
591 D(bug("[%s] Scale icon %dx%d => %dx%d\n", __func__
, SrcWidth
, SrcHeight
, *DstWidth
, *DstHeight
));
596 /* From 'Image Scaling With Bresenham', Dr. Dobbs Journal, May 1, 2002
598 static inline void ScaleLine(ULONG
*Target
, const ULONG
*Source
, int SrcWidth
, int TgtWidth
)
600 int NumPixels
= TgtWidth
;
601 int IntPart
= SrcWidth
/ TgtWidth
;
602 int FracPart
= SrcWidth
% TgtWidth
;
604 while (NumPixels
-- > 0) {
605 *(Target
++) = *Source
;
615 static void ScaleRect(ULONG
*Target
, const ULONG
*Source
, int SrcWidth
, int SrcHeight
, int TgtWidth
, int TgtHeight
)
617 int NumPixels
= TgtHeight
;
618 int IntPart
= (SrcHeight
/ TgtHeight
) * SrcWidth
;
619 int FractPart
= SrcHeight
% TgtHeight
;
621 const ULONG
*PrevSource
= NULL
;
622 while (NumPixels
-- > 0) {
623 if (Source
== PrevSource
) {
624 CopyMem(&Target
[-TgtWidth
], Target
, TgtWidth
*sizeof(*Target
));
626 ScaleLine(Target
, Source
, SrcWidth
, TgtWidth
);
632 if (E
>= TgtHeight
) {