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"
17 static BOOL
scaleToResolution(ULONG SrcWidth
, ULONG SrcHeight
,
18 UWORD SrcResX
, UWORD SrcResY
,
19 ULONG
*DstWidth
, ULONG
*DstHeight
,
20 UWORD DstResX
, UWORD DstResY
,
21 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
22 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
23 struct IconBase
*IconBase
);
25 static BOOL
scaleToBounds(ULONG SrcWidth
, ULONG SrcHeight
,
26 UWORD MaxWidth
, UWORD MaxHeight
,
27 ULONG
*DstWidth
, ULONG
*DstHeight
,
28 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
29 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
30 struct IconBase
*IconBase
);
32 /* ARGB image scaling */
33 static void ScaleRect(ULONG
*Target
, const ULONG
*Source
, int SrcWidth
, int SrcHeight
, int TgtWidth
, int TgtHeight
);
35 /*****************************************************************************
39 AROS_LH3(BOOL
, LayoutIconA
,
42 AROS_LHA(struct DiskObject
*, icon
, A0
),
43 AROS_LHA(struct Screen
*, screen
, A1
),
44 AROS_LHA(struct TagItem
*, tags
, A2
),
47 struct IconBase
*, IconBase
, 32, Icon
)
50 Adapt a palette-mapped icon for display.
67 *****************************************************************************/
71 /* Default source DPI is the Amiga PAL DPI */
73 ULONG scaleXsrc
= 1, scaleYsrc
= 1, scaleXdst
= 1, scaleYdst
= 1;
74 ULONG mutualexclude
= (ULONG
)icon
->do_Gadget
.MutualExclude
;
76 struct NativeIcon
*ni
;
82 const ULONG bflags
= BMF_CLEAR
;
83 ni
= GetNativeIcon(icon
, LB(IconBase
));
87 if (ni
->ni_Width
<= 0)
88 ni
->ni_Width
= ni
->ni_DiskObject
.do_Gadget
.Width
;
89 if (ni
->ni_Height
<= 0)
90 ni
->ni_Height
= ni
->ni_DiskObject
.do_Gadget
.Height
;
92 D(bug("[%s] Icon %p, Screen %p, %xx%x icon\n", __func__
, icon
, screen
, ni
->ni_Width
, ni
->ni_Height
));
94 /* Already mapped to this screen?
96 if (screen
== ni
->ni_Screen
)
99 for (i
= 0; i
< 2; i
++) {
100 struct NativeIconImage
*image
= &ni
->ni_Image
[i
];
103 FreeBitMap(image
->BitMap
);
104 image
->BitMap
= NULL
;
107 if (image
->ARGBMap
&& image
->ARGBMap
!= image
->ARGB
) {
108 FreeVec(image
->ARGBMap
);
112 for (j
= 0; j
< image
->Pens
; j
++) {
113 ReleasePen(ni
->ni_Screen
->ViewPort
.ColorMap
, image
->Pen
[j
]);
119 /* Remove the synthesized BitMask */
120 if (image
->BitMask
) {
121 FreeVec(image
->BitMask
);
122 image
->BitMask
= NULL
;
126 ni
->ni_Screen
= NULL
;
131 dri
= GetScreenDrawInfo(screen
);
135 /* Look up the DrawInfo Pens we will need for the
136 * layout of the border and frame.
138 for (i
= 0; i
< NUMDRIPENS
; i
++) {
139 if (i
< dri
->dri_NumPens
)
140 ni
->ni_Pens
[i
] = dri
->dri_Pens
[i
];
142 ni
->ni_Pens
[i
] = dri
->dri_Pens
[DETAILPEN
];
145 cm
= screen
->ViewPort
.ColorMap
;
147 /* NOTE: The ARGB data (if present) will not need
150 D(bug("%s: Screen %p, Depth %d, ColorMap %d\n", __func__
, screen
, dri
->dri_Depth
, cm
? cm
->Count
: -1));
154 /* Calculate the scaling factors
156 if (ni
->ni_Face
.Width
&& ni
->ni_Face
.Height
) {
157 width
= ni
->ni_Face
.Width
;
158 height
= ni
->ni_Face
.Height
;
160 width
= icon
->do_Gadget
.Width
;
161 height
= icon
->do_Gadget
.Height
;
164 if (ni
->ni_ScaleBox
== ICON_SCALEBOX_DEFAULT
)
165 scalebox
= LB(IconBase
)->ib_ScaleBox
;
167 scalebox
= ni
->ni_ScaleBox
;
169 ni
->ni_Width
= width
;
170 ni
->ni_Height
= height
;
172 /* Are we rescaling dynamically? */
173 if (scalebox
== ICON_SCALEBOX_AUTOSCALE
) {
174 UBYTE tpdX
= 0, tpdY
= 0;
176 /* Check for a magic MutualExlcude value
177 * that encodes Tick-Per-Dot information.
178 * MutalExclude of 0xffffffff is not valid.
180 if ((mutualexclude
!= 0xffffffff) && (mutualexclude
& (1 << 31))) {
181 /* tpd information is in the lower 16 bits */
182 tpdX
= (mutualexclude
>> 8) & 0xff;
183 tpdY
= (mutualexclude
>> 0) & 0xff;
187 scaleToResolution(width
, height
, tpdX
, tpdY
,
188 &ni
->ni_Width
, &ni
->ni_Height
, dri
->dri_Resolution
.X
, dri
->dri_Resolution
.Y
,
189 &scaleXsrc
, &scaleYsrc
, &scaleXdst
, &scaleYdst
,
192 D(bug("%s: Icon tpd (%d:%d), Screen tpd (%d:%d)\n", __func__
,
193 tpdX
, tpdY
, dri
->dri_Resolution
.X
, dri
->dri_Resolution
.Y
));
196 WORD MaxWidth
, MaxHeight
;
198 UNPACK_ICON_SCALEBOX(scalebox
, MaxWidth
, MaxHeight
);
200 scaleToBounds(width
, height
, MaxWidth
, MaxHeight
,
201 &ni
->ni_Width
, &ni
->ni_Height
,
202 &scaleXsrc
, &scaleYsrc
, &scaleXdst
, &scaleYdst
,
206 for (i
= 0; i
< 2; i
++) {
207 struct NativeIconImage
*image
= &ni
->ni_Image
[i
];
208 struct TagItem pentags
[] = {
209 { OBP_Precision
, IconBase
->ib_Precision
},
210 { OBP_FailIfBad
, FALSE
},
211 { TAG_MORE
, (IPTR
)tags
},
217 bmdepth
= GetBitMapAttr(screen
->RastPort
.BitMap
, BMA_DEPTH
);
219 /* If we can use ARGB data, then use it! */
220 D(bug("[%s] Screen depth is %d\n", __func__
, bmdepth
));
221 if ((bmdepth
> 8) && CyberGfxBase
) {
222 FetchIconARGB(icon
, i
);
224 if (width
!= ni
->ni_Width
|| height
!= ni
->ni_Height
) {
225 if ((image
->ARGBMap
= AllocVec(ni
->ni_Width
* ni
->ni_Height
* sizeof(ULONG
), MEMF_PUBLIC
))) {
226 D(bug("[%s] ARGB scaling\n"));
227 ScaleRect(image
->ARGBMap
, image
->ARGB
, width
, height
, ni
->ni_Width
, ni
->ni_Height
);
231 image
->ARGBMap
= (APTR
)image
->ARGB
;
234 if (!image
->ARGBMap
) {
235 D(bug("[%s] No ARGB image\n"));
239 /* Allocate a bitmap, which is a 'friend' of the screen */
240 image
->BitMap
= AllocBitMap(width
, height
, dri
->dri_Depth
, bflags
, screen
->RastPort
.BitMap
);
241 if (image
->BitMap
== NULL
) {
242 SetIoErr(ERROR_NO_FREE_STORE
);
247 FetchIconImage(icon
, i
);
249 if (!image
->ImageData
) {
250 struct Image
*gi
= NULL
;
254 if (i
== 1 && (icon
->do_Gadget
.Flags
& GFLG_GADGHIMAGE
)) {
255 gi
= icon
->do_Gadget
.SelectRender
;
256 } else if (icon
->do_Gadget
.Flags
& GFLG_GADGIMAGE
) {
257 gi
= icon
->do_Gadget
.GadgetRender
;
263 if (i
== 1 && (icon
->do_Gadget
.Flags
& GFLG_GADGHCOMP
))
264 state
= IDS_SELECTED
;
268 if (i
== 1 && (icon
->do_Gadget
.Flags
& GFLG_GADGBACKFILL
)) {
269 state
= IDS_SELECTED
;
275 rp
.BitMap
= image
->BitMap
;
276 DrawImageState(&rp
, gi
, 0, 0, state
, dri
);
278 /* Create a bitmap with a 1 pixel border,
279 * fill it with the inverse color,
280 * draw the inverse image into it,
281 * then flood-fill the border with color 0.
283 * Finally, copy the final image to the
284 * destination bitmap.
287 if ((bm
= AllocBitMap(gi
->Width
+2, gi
->Height
+2, gi
->Depth
, BMF_CLEAR
, NULL
))) {
292 if ((trbuf
= AllocRaster(gi
->Width
+2, gi
->Height
+2))) {
294 InitTmpRas(&tr
, trbuf
, RASSIZE(gi
->Width
+2, gi
->Height
+2));
296 SetAPen(&rp
, (1 << gi
->Depth
)-1);
297 RectFill(&rp
, 0, 0, gi
->Width
+1, gi
->Height
+1);
298 DrawImageState(&rp
, gi
, 1, 1, state
, dri
);
301 BltBitMap(bm
, 1, 1, image
->BitMap
, 0, 0, gi
->Width
, gi
->Height
, 0xc0, ~0, NULL
);
302 FreeRaster(trbuf
, gi
->Width
+2, gi
->Height
+2);
311 /* Palettized image processing */
313 image
->Pen
= AllocVec(image
->Pens
* sizeof(image
->Pen
[0]), MEMF_PUBLIC
| MEMF_CLEAR
);
316 SetIoErr(ERROR_NO_FREE_STORE
);
321 /* Get the needed colormap entries. */
322 for (j
= 0; j
< image
->Pens
; j
++) {
325 /* CHECKME: So, uh, how does one accuarately
326 * convert 8 bit RGB to 32 bit RBG?
328 r
= image
->Palette
[j
].red
<< 24;
329 g
= image
->Palette
[j
].green
<< 24;
330 b
= image
->Palette
[j
].blue
<< 24;
331 pen
= ObtainBestPenA(cm
, r
, g
, b
, pentags
);
332 image
->Pen
[j
] = (UBYTE
)pen
;
335 /* Draw the selected state into the screen's pens
337 * We take the risk of yet another memory allocation
338 * so that we can use WriteChunkyPixels(), which is
339 * GOBS faster than WritePixel().
341 idata
= AllocVec(height
* width
, MEMF_ANY
);
343 FreeBitMap(image
->BitMap
);
344 image
->BitMap
= NULL
;
345 SetIoErr(ERROR_NO_FREE_STORE
);
349 CopyMem(image
->ImageData
, idata
, height
* width
);
350 for (x
= 0; x
< (height
* width
); x
++) {
351 idata
[x
] = image
->Pen
[image
->ImageData
[x
]];
354 rp
.BitMap
= image
->BitMap
;
355 WriteChunkyPixels(&rp
, 0, 0, width
- 1, height
- 1,
359 /* Synthesize a bitmask for transparentcolor icons */
360 D(bug("[%s] TransparentColor %d\n", __func__
, image
->TransparentColor
));
361 if (image
->TransparentColor
>= 0) {
365 UWORD bpr
= image
->BitMap
->BytesPerRow
;
366 image
->BitMask
= AllocVec(bpr
* height
+ 4, MEMF_PUBLIC
| MEMF_CHIP
| MEMF_CLEAR
);
367 if (!image
->BitMask
) {
368 SetIoErr(ERROR_NO_FREE_STORE
);
372 img
= image
->ImageData
;
373 row
= image
->BitMask
;
374 #ifdef __mc68000 /* AGA support */
375 row
= (APTR
)(((IPTR
)row
+ 7) & ~7);
377 for (y
= 0; y
< height
; y
++, row
+= bpr
) {
378 for (x
= 0; x
< width
; x
++, img
++) {
379 if ((*img
!= image
->TransparentColor
)) {
380 row
[x
>>3] |= 1 << (7 - (x
& 7));
387 if (width
!= ni
->ni_Width
|| height
!= ni
->ni_Height
) {
388 struct BitMap
*bm
= AllocBitMap(ni
->ni_Width
, ni
->ni_Height
, dri
->dri_Depth
, bflags
, image
->BitMap
);
390 D(bug("%s: Rescaling from %dx%d to %dx%d\n", __func__
,
391 width
, height
, ni
->ni_Width
, ni
->ni_Height
));
394 struct BitScaleArgs bsa
= {
395 .bsa_SrcBitMap
= image
->BitMap
,
398 .bsa_SrcWidth
= width
,
399 .bsa_SrcHeight
= height
,
400 .bsa_XSrcFactor
= scaleXsrc
,
401 .bsa_XDestFactor
= scaleXdst
,
402 .bsa_YSrcFactor
= scaleYsrc
,
403 .bsa_YDestFactor
= scaleYdst
,
404 .bsa_DestBitMap
= bm
,
408 if (image
->BitMask
) {
409 struct BitMap src
, dst
;
411 src
.BytesPerRow
= image
->BitMap
->BytesPerRow
;
415 src
.Planes
[0] = image
->BitMask
;
416 #ifdef __mc68000 /* AGA support */
417 src
.Planes
[0] = (APTR
)(((IPTR
)src
.Planes
[0] + 7) & ~7);
419 dst
.BytesPerRow
= bm
->BytesPerRow
;
420 dst
.Rows
= ni
->ni_Height
;
423 dst_mask
= AllocVec(dst
.BytesPerRow
* dst
.Rows
+ 4, MEMF_PUBLIC
| MEMF_CHIP
| MEMF_CLEAR
);
424 dst
.Planes
[0] = dst_mask
;
426 #ifdef __mc68000 /* AGA support */
427 dst
.Planes
[0] = (APTR
)(((IPTR
)dst
.Planes
[0] + 7) & ~7);
429 bsa
.bsa_SrcBitMap
= &src
;
430 bsa
.bsa_DestBitMap
= &dst
;
433 bsa
.bsa_SrcWidth
= width
,
434 bsa
.bsa_SrcHeight
= height
,
435 bsa
.bsa_XSrcFactor
= scaleXsrc
,
436 bsa
.bsa_XDestFactor
= scaleXdst
,
437 bsa
.bsa_YSrcFactor
= scaleYsrc
,
438 bsa
.bsa_YDestFactor
= scaleYdst
,
441 FreeVec(image
->BitMask
);
442 image
->BitMask
= dst_mask
;
450 FreeBitMap(image
->BitMap
);
456 ni
->ni_Screen
= screen
;
459 FreeScreenDrawInfo(screen
, dri
);
467 } /* LayoutIconA() */
470 static BOOL
scaleToBounds(ULONG SrcWidth
, ULONG SrcHeight
,
471 UWORD MaxWidth
, UWORD MaxHeight
,
472 ULONG
*DstWidth
, ULONG
*DstHeight
,
473 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
474 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
475 struct IconBase
*IconBase
)
477 ULONG scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
;
479 if (MaxWidth
<= 0 || MaxHeight
<= 0)
482 /* Scaling calculations
484 scaleXsrc
= SrcWidth
;
485 scaleYsrc
= SrcHeight
;
486 scaleXdst
= MaxWidth
;
487 scaleYdst
= SrcHeight
* MaxWidth
/ SrcWidth
;
489 if (scaleYdst
> MaxHeight
) {
490 LONG delta
= scaleYdst
- MaxHeight
;
491 scaleXdst
-= delta
* SrcWidth
/ SrcHeight
;
495 while (scaleXsrc
> 168383 || scaleXdst
> 168383) {
498 if (scaleXsrc
== 0 || scaleXdst
== 0) {
499 D(bug("\tCan't scale X from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
504 while (scaleYsrc
> 168383 || scaleYdst
> 168383) {
507 if (scaleYsrc
== 0 || scaleYdst
== 0) {
508 D(bug("\tCan't scale Y from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
513 *DstWidth
= ScalerDiv(SrcWidth
, scaleXdst
, scaleXsrc
);
514 *DstHeight
= ScalerDiv(SrcHeight
, scaleYdst
, scaleYsrc
);
516 *ScaleXSrc
= scaleXsrc
;
517 *ScaleYSrc
= scaleYsrc
;
519 *ScaleXDst
= scaleXdst
;
520 *ScaleYDst
= scaleYdst
;
522 D(bug("[%s] Scale icon %dx%d to box %dx%d => %dx%d\n", __func__
, SrcWidth
, SrcHeight
, MaxWidth
, MaxHeight
, *DstWidth
, *DstHeight
));
527 static BOOL
scaleToResolution(ULONG SrcWidth
, ULONG SrcHeight
,
528 UWORD SrcResX
, UWORD SrcResY
,
529 ULONG
*DstWidth
, ULONG
*DstHeight
,
530 UWORD DstResX
, UWORD DstResY
,
531 ULONG
*ScaleXSrc
, ULONG
*ScaleYSrc
,
532 ULONG
*ScaleXDst
, ULONG
*ScaleYDst
,
533 struct IconBase
*IconBase
)
535 ULONG scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
;
537 /* Scaling calculations
538 * Remember: 'res' is in 'ticks', which is inversely
539 * related to display DPI.
541 scaleXsrc
= SrcWidth
;
542 scaleYsrc
= SrcHeight
;
543 scaleXdst
= SrcWidth
* SrcResX
/ DstResX
;
544 scaleYdst
= SrcHeight
* SrcResY
/ DstResY
;
546 while (scaleXsrc
> 168383 || scaleXdst
> 168383) {
549 if (scaleXsrc
== 0 || scaleXdst
== 0) {
550 D(bug("\tCan't scale X from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
555 while (scaleYsrc
> 168383 || scaleYdst
> 168383) {
558 if (scaleYsrc
== 0 || scaleYdst
== 0) {
559 D(bug("\tCan't scale Y from %dx%d to %dx%d\n", scaleXsrc
, scaleYsrc
, scaleXdst
, scaleYdst
));
564 *DstWidth
= ScalerDiv(SrcWidth
, scaleXdst
, scaleXsrc
);
565 *DstHeight
= ScalerDiv(SrcHeight
, scaleYdst
, scaleYsrc
);
567 *ScaleXSrc
= scaleXsrc
;
568 *ScaleYSrc
= scaleYsrc
;
570 *ScaleXDst
= scaleXdst
;
571 *ScaleYDst
= scaleYdst
;
573 D(bug("[%s] Scale icon %dx%d => %dx%d\n", __func__
, SrcWidth
, SrcHeight
, *DstWidth
, *DstHeight
));
578 /* From 'Image Scaling With Bresenham', Dr. Dobbs Journal, May 1, 2002
580 static inline void ScaleLine(ULONG
*Target
, const ULONG
*Source
, int SrcWidth
, int TgtWidth
)
582 int NumPixels
= TgtWidth
;
583 int IntPart
= SrcWidth
/ TgtWidth
;
584 int FracPart
= SrcWidth
% TgtWidth
;
586 while (NumPixels
-- > 0) {
587 *(Target
++) = *Source
;
597 static void ScaleRect(ULONG
*Target
, const ULONG
*Source
, int SrcWidth
, int SrcHeight
, int TgtWidth
, int TgtHeight
)
599 int NumPixels
= TgtHeight
;
600 int IntPart
= (SrcHeight
/ TgtHeight
) * SrcWidth
;
601 int FractPart
= SrcHeight
% TgtHeight
;
603 const ULONG
*PrevSource
= NULL
;
604 while (NumPixels
-- > 0) {
605 if (Source
== PrevSource
) {
606 CopyMem(&Target
[-TgtWidth
], Target
, TgtWidth
*sizeof(*Target
));
608 ScaleLine(Target
, Source
, SrcWidth
, TgtWidth
);
614 if (E
>= TgtHeight
) {