1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the NPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the NPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
38
#include "nsImageMac.h"
39
#include "nsRenderingContextMac.h"
40
#include "nsDeviceContextMac.h"
41
#include "nsCarbonHelpers.h"
42
#include "nsRegionPool.h"
45
#include <Quickdraw.h>
47
#include "nsGfxUtils.h"
48
#include "imgScaler.h"
52
// useful region debugging code.
53
static OSStatus PrintRgnRectProc(UInt16 message, RgnHandle rgn, const Rect *inRect, void *refCon)
55
UInt32* rectCount = (UInt32*)refCon;
59
case kQDRegionToRectsMsgInit:
60
printf("Dumping region 0x%X\n", rgn);
63
case kQDRegionToRectsMsgParse:
64
printf("Rect %d t,l,r,b: %ld, %ld, %ld, %ld\n", *rectCount, inRect->top, inRect->left, inRect->right, inRect->bottom);
68
case kQDRegionToRectsMsgTerminate:
76
static void PrintRegionOutline(RgnHandle inRgn)
78
static RegionToRectsUPP sCountRectProc = nsnull;
80
sCountRectProc = NewRegionToRectsUPP(PrintRgnRectProc);
83
::QDRegionToRects(inRgn, kQDParseRegionFromTopLeft, sCountRectProc, &rectCount);
85
#endif // TARGET_CARBON
90
/** ---------------------------------------------------
91
* See documentation in nsImageMac.h
94
nsImageMac::nsImageMac()
95
: mImageGWorld(nsnull)
100
, mBytesPerPixel(0) // this value is never initialized; the API that uses it is unused
101
, mMaskGWorld(nsnull)
105
, mDecodedX1(PR_INT32_MAX)
106
, mDecodedY1(PR_INT32_MAX)
112
/** ---------------------------------------------------
113
* See documentation in nsImageMac.h
116
nsImageMac::~nsImageMac()
119
::DisposeGWorld(mImageGWorld);
122
::DisposeGWorld(mMaskGWorld);
131
NS_IMPL_ISUPPORTS2(nsImageMac, nsIImage, nsIImageMac)
133
/** ---------------------------------------------------
134
* See documentation in nsImageMac.h
138
nsImageMac::GetBits()
140
NS_ASSERTION(mImageBits, "Getting bits for non-existent image");
141
return (PRUint8 *)mImageBits;
145
/** ---------------------------------------------------
146
* See documentation in nsImageMac.h
150
nsImageMac::GetAlphaBits()
152
NS_ASSERTION(mMaskBits, "Getting bits for non-existent image mask");
153
return (PRUint8 *)mMaskBits;
157
/** ---------------------------------------------------
158
* See documentation in nsImageMac.h
159
* @update 08/03/99 -- cleared out the image pointer - dwc
162
nsImageMac::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
164
// Assumed: Init only runs once (due to gfxIImageFrame only allowing 1 Init)
170
err = CreateGWorld(aWidth, aHeight, aDepth, &mImageGWorld, &mImageBits, &mRowBytes);
173
if (err == memFullErr)
174
nsMemory::HeapMinimize(PR_FALSE);
175
return NS_ERROR_FAILURE;
179
//mBytesPerPixel = (mImagePixmap.pixelSize <= 8) ? 1 : mImagePixmap.pixelSize / 8;
181
if (aMaskRequirements != nsMaskRequirements_kNoMask)
183
switch (aMaskRequirements)
185
case nsMaskRequirements_kNeeds1Bit:
189
case nsMaskRequirements_kNeeds8Bit:
194
break; // avoid compiler warning
197
err = CreateGWorld(aWidth, aHeight, mAlphaDepth, &mMaskGWorld, &mMaskBits, &mAlphaRowBytes);
200
if (err == memFullErr)
201
nsMemory::HeapMinimize(PR_FALSE);
202
return NS_ERROR_FAILURE;
209
/** ---------------------------------------------------
210
* See documentation in nsImageMac.h
213
void nsImageMac::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect)
215
mDecodedX1 = PR_MIN(mDecodedX1, aUpdateRect->x);
216
mDecodedY1 = PR_MIN(mDecodedY1, aUpdateRect->y);
218
if (aUpdateRect->YMost() > mDecodedY2)
219
mDecodedY2 = aUpdateRect->YMost();
221
if (aUpdateRect->XMost() > mDecodedX2)
222
mDecodedX2 = aUpdateRect->XMost();
226
/** ---------------------------------------------------
227
* See documentation in nsImageMac.h
230
NS_IMETHODIMP nsImageMac::Draw(nsIRenderingContext &aContext, nsDrawingSurface aSurface, PRInt32 aSX, PRInt32 aSY,
231
PRInt32 aSWidth, PRInt32 aSHeight, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
233
Rect srcRect, dstRect, maskRect;
237
return NS_ERROR_FAILURE;
239
if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
242
PRInt32 srcWidth = aSWidth;
243
PRInt32 srcHeight = aSHeight;
244
PRInt32 dstWidth = aDWidth;
245
PRInt32 dstHeight = aDHeight;
247
// Ensure that the source rect is no larger than our decoded rect.
248
// If it is, clip the source rect, and scale the difference to adjust
251
PRInt32 j = aSX + aSWidth;
253
if (j > mDecodedX2) {
255
aDWidth -= z*dstWidth/srcWidth;
258
if (aSX < mDecodedX1) {
259
aDX += (mDecodedX1 - aSX)*dstWidth/srcWidth;
264
if (j > mDecodedY2) {
266
aDHeight -= z*dstHeight/srcHeight;
269
if (aSY < mDecodedY1) {
270
aDY += (mDecodedY1 - aSY)*dstHeight/srcHeight;
274
if (aDWidth <= 0 || aDHeight <= 0 || aSWidth <= 0 || aSHeight <= 0)
277
::SetRect(&srcRect, aSX, aSY, aSX + aSWidth, aSY + aSHeight);
279
::SetRect(&dstRect, aDX, aDY, aDX + aDWidth, aDY + aDHeight);
281
// get the destination pix map
282
nsDrawingSurfaceMac* surface = static_cast<nsDrawingSurfaceMac*>(aSurface);
284
rv = surface->GetGrafPtr(&destPort);
285
if (NS_FAILED(rv)) return rv;
287
StPortSetter destSetter(destPort);
288
::ForeColor(blackColor);
289
::BackColor(whiteColor);
291
if (RenderingToPrinter(aContext))
295
::CopyBits(::GetPortBitMapForCopyBits(mImageGWorld),
296
::GetPortBitMapForCopyBits(destPort),
297
&srcRect, &dstRect, srcCopy, nsnull);
301
// If we are printing, then we need to render everything into a temp
302
// GWorld, and then blit that out to the destination. We do this
303
// since Copy{Deep}Mask are not supported for printing.
305
GWorldPtr tempGWorld;
307
// if we have a mask, blit the transparent image into a new GWorld which is
308
// just white, and print that. This is marginally better than printing the
309
// image directly, since the transparent pixels come out black.
311
PRInt16 pixelDepth = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
312
if (AllocateGWorld(pixelDepth, nsnull, srcRect, &tempGWorld) == noErr)
315
ClearGWorld(tempGWorld);
317
PixMapHandle tempPixMap = ::GetGWorldPixMap(tempGWorld);
320
StPixelLocker tempPixLocker(tempPixMap); // locks the pixels
322
// Copy everything into tempGWorld
324
::CopyDeepMask(::GetPortBitMapForCopyBits(mImageGWorld),
325
::GetPortBitMapForCopyBits(mMaskGWorld),
326
::GetPortBitMapForCopyBits(tempGWorld),
327
&srcRect, &maskRect, &srcRect, srcCopy, nsnull);
329
::CopyMask(::GetPortBitMapForCopyBits(mImageGWorld),
330
::GetPortBitMapForCopyBits(mMaskGWorld),
331
::GetPortBitMapForCopyBits(tempGWorld),
332
&srcRect, &maskRect, &srcRect);
334
// now copy tempGWorld bits to destination
335
::CopyBits(::GetPortBitMapForCopyBits(tempGWorld),
336
::GetPortBitMapForCopyBits(destPort),
337
&srcRect, &dstRect, srcCopy, nsnull);
340
::DisposeGWorld(tempGWorld); // do this after dtor of tempPixLocker!
347
if (mAlphaDepth == 1 && ((aSWidth != aDWidth) || (aSHeight != aDHeight)))
349
// If scaling an image that has a 1-bit mask...
351
// Bug 195022 - Seems there is a bug in the Copy{Deep}Mask functions
352
// where scaling an image that has a 1-bit mask can cause some ugly
353
// artifacts to appear on screen. To work around this issue, we use the
354
// functions in imgScaler.cpp to do the actual scaling of the source
357
GWorldPtr tempSrcGWorld = nsnull, tempMaskGWorld = nsnull;
359
// create temporary source GWorld
361
PRInt32 tmpSrcRowBytes;
362
PRInt16 pixelDepthSrc = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
363
OSErr err = CreateGWorld(aDWidth, aDHeight, pixelDepthSrc,
364
&tempSrcGWorld, &scaledSrcBits, &tmpSrcRowBytes);
366
if (err != noErr) return NS_ERROR_FAILURE;
368
// create temporary mask GWorld
369
char* scaledMaskBits;
370
PRInt32 tmpMaskRowBytes;
371
err = CreateGWorld(aDWidth, aDHeight, mAlphaDepth, &tempMaskGWorld,
372
&scaledMaskBits, &tmpMaskRowBytes);
376
PixMapHandle srcPixMap = ::GetGWorldPixMap(mImageGWorld);
377
PixMapHandle maskPixMap = ::GetGWorldPixMap(mMaskGWorld);
378
if (srcPixMap && maskPixMap)
380
StPixelLocker srcPixLocker(srcPixMap); // locks the pixels
381
StPixelLocker maskPixLocker(maskPixMap);
384
RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
385
0, 0, aDWidth - 1, aDHeight - 1,
386
mImageBits, mRowBytes, scaledSrcBits, tmpSrcRowBytes,
390
RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
391
0, 0, aDWidth - 1, aDHeight - 1,
392
mMaskBits, mAlphaRowBytes, scaledMaskBits,
393
tmpMaskRowBytes, mAlphaDepth);
396
::SetRect(&tmpRect, 0, 0, aDWidth, aDHeight);
399
CopyBitsWithMask(::GetPortBitMapForCopyBits(tempSrcGWorld),
400
::GetPortBitMapForCopyBits(tempMaskGWorld),
401
mAlphaDepth, ::GetPortBitMapForCopyBits(destPort),
402
tmpRect, tmpRect, dstRect, PR_TRUE);
405
::DisposeGWorld(tempMaskGWorld);
406
free(scaledMaskBits);
410
rv = NS_ERROR_FAILURE;
413
::DisposeGWorld(tempSrcGWorld);
419
CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
420
mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull,
421
mAlphaDepth, ::GetPortBitMapForCopyBits(destPort),
422
srcRect, maskRect, dstRect, PR_TRUE);
429
/** ---------------------------------------------------
430
* See documentation in nsImageMac.h
433
NS_IMETHODIMP nsImageMac::Draw(nsIRenderingContext &aContext,
434
nsDrawingSurface aSurface,
435
PRInt32 aX, PRInt32 aY,
436
PRInt32 aWidth, PRInt32 aHeight)
439
return Draw(aContext, aSurface, 0, 0, mWidth, mHeight, aX, aY, aWidth, aHeight);
442
/** ---------------------------------------------------
443
* See documentation in nsImageMac.h
446
NS_IMETHODIMP nsImageMac::DrawToImage(nsIImage* aDstImage, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
448
Rect srcRect, dstRect, maskRect;
451
return NS_ERROR_FAILURE;
453
#ifdef MOZ_WIDGET_COCOA
454
nsGraphicsUtils::SetPortToKnownGoodPort();
457
// lock and set up bits handles
458
LockImagePixels(PR_FALSE);
459
LockImagePixels(PR_TRUE);
461
::SetRect(&srcRect, 0, 0, mWidth, mHeight);
463
::SetRect(&dstRect, aDX, aDY, aDX + aDWidth, aDY + aDHeight);
465
::ForeColor(blackColor);
466
::BackColor(whiteColor);
468
// get the destination pix map
469
aDstImage->LockImagePixels(PR_FALSE);
470
aDstImage->LockImagePixels(PR_TRUE);
471
//nsImageMac* dstMacImage = static_cast<nsImageMac*>(aDstImage);
472
nsCOMPtr<nsIImageMac> dstMacImage( do_QueryInterface(aDstImage));
474
GWorldPtr destGWorld;
475
dstMacImage->GetGWorldPtr(&destGWorld);
476
NS_ASSERTION(destGWorld, "No dest pixels!");
478
CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
479
mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull, mAlphaDepth,
480
::GetPortBitMapForCopyBits(destGWorld), srcRect, maskRect, dstRect, PR_FALSE);
482
aDstImage->UnlockImagePixels(PR_FALSE);
483
aDstImage->UnlockImagePixels(PR_TRUE);
484
UnlockImagePixels(PR_FALSE);
485
UnlockImagePixels(PR_TRUE);
491
/** ---------------------------------------------------
492
* See documentation in nsImageMac.h
495
nsresult nsImageMac::Optimize(nsIDeviceContext* aContext)
502
/** ---------------------------------------------------
503
* Lock down the image pixels
506
nsImageMac::LockImagePixels(PRBool aMaskPixels)
512
/** ---------------------------------------------------
516
nsImageMac::UnlockImagePixels(PRBool aMaskPixels)
525
Because almost all the images we create are 24-bit images, we can share the same GDevice between
526
all of them. So we make a tiny GWorld, and then will use its GDevice for all subsequent
527
24-bit GWorlds. This GWorld is never freed.
529
We only bother caching the device for 24-bit GWorlds. This method returns nsnull
532
GDHandle nsImageMac::GetCachedGDeviceForDepth(PRInt32 aDepth)
536
static GWorldPtr s24BitDeviceGWorld = nsnull;
538
if (!s24BitDeviceGWorld)
540
Rect bounds = { 0, 0, 16, 16 };
541
::NewGWorld(&s24BitDeviceGWorld, aDepth, &bounds, nsnull, nsnull, 0);
542
if (!s24BitDeviceGWorld) return nsnull;
544
return ::GetGWorldDevice(s24BitDeviceGWorld);
550
/** -----------------------------------------------------------------
551
* Create a PixMap, filling in ioPixMap
553
OSErr nsImageMac::CreateGWorld( PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,
554
GWorldPtr* outGWorld, char** outBits, PRInt32* outRowBytes)
556
return CreateGWorldInternal(aWidth, aHeight, aDepth, outGWorld, outBits, outRowBytes, PR_FALSE);
560
/** -----------------------------------------------------------------
561
* Create a PixMap, filling in ioPixMap
562
* Call the CreatePixMap wrapper instead.
564
OSErr nsImageMac::CreateGWorldInternal(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,
565
GWorldPtr* outGWorld, char** outBits, PRInt32* outRowBytes, PRBool aAllow2Bytes)
570
PRInt32 bitsPerPixel = 0;
571
CTabHandle colorTable;
572
PRUint32 pixelFormat = GetPixelFormatForDepth(aDepth, bitsPerPixel, &colorTable);
574
if (pixelFormat != 0)
576
PRInt32 rowBytes = CalculateRowBytesInternal(aWidth, bitsPerPixel, aAllow2Bytes);
577
PRInt32 imageSize = rowBytes * aHeight;
579
char* imageBits = (char*)calloc(imageSize, 1);
583
Rect imageRect = {0, 0, 0, 0};
584
imageRect.right = aWidth;
585
imageRect.bottom = aHeight;
587
GDHandle deviceHandle = GetCachedGDeviceForDepth(aDepth);
588
GWorldFlags flags = deviceHandle ? noNewDevice : 0;
590
GWorldPtr imageGWorld;
591
err = ::NewGWorldFromPtr(&imageGWorld, pixelFormat, &imageRect, colorTable, deviceHandle, flags, (Ptr)imageBits, rowBytes);
594
NS_ASSERTION(0, "NewGWorldFromPtr failed");
598
*outGWorld = imageGWorld;
599
*outBits = imageBits;
600
*outRowBytes = rowBytes;
607
/** ---------------------------------------------------
608
* Calculate rowBytes, making sure that it comes out as
609
* a multiple of 4. ( 32 / 4 == 8). If you pass true for
610
* aAllow2Bytes then, for small images (aWidth * aDepth =< 24), you
611
* get a result which can be a multiple of 2 instead.
612
* Some parts of the toolbox require this, notably the native icon creation
613
* code. This is worth experimenting with if you deal with masks of 16x16 icons
614
* which are frequently 1 bit and thus are considered "small" by this function.
616
* CAUTION: MacOS X is extremely intolerant of divisible by 2 widths. You should never
617
* pass a PixMap to the OS for drawing with PixMap.rowBytes set to anything other than
618
* a multiple of 4 on Mac OS X. (CopyBits seems to be OK with divisible by 2 rowbytes,
619
* at least for the icon code in this class). That's why this function is private and
622
* See <http://developer.apple.com/technotes/qd/qd_15.html>
624
PRInt32 nsImageMac::CalculateRowBytesInternal(PRUint32 aWidth, PRUint32 aDepth, PRBool aAllow2Bytes)
626
PRInt32 rowBits = aWidth * aDepth;
627
//if bits per row is 24 or less, may need 3 bytes or less
628
return (rowBits > 24 || !aAllow2Bytes) ?
629
((aWidth * aDepth + 31) / 32) * 4 :
630
((aWidth * aDepth + 15) / 16) * 2;
633
/** Protected CalculateRowBytes. Most functions should call this
634
Requires rowBytes to be a multiple of 4
635
@see CalculateRowBytesInternal
637
PRInt32 nsImageMac::CalculateRowBytes(PRUint32 aWidth, PRUint32 aDepth)
639
return CalculateRowBytesInternal(aWidth, aDepth, PR_FALSE);
643
PRUint32 nsImageMac::GetPixelFormatForDepth(PRInt32 inDepth, PRInt32& outBitsPerPixel, CTabHandle* outDefaultColorTable)
645
PRUint32 pixelFormat = 0;
646
PRInt32 bitsPerPixel;
648
if (outDefaultColorTable)
649
*outDefaultColorTable = nsnull;
651
// See IM:QuickDraw pp 4-92 for GetCTable params
655
if (outDefaultColorTable)
656
*outDefaultColorTable = ::GetCTable(32 + 1);
658
pixelFormat = k1MonochromePixelFormat;
662
if (outDefaultColorTable)
663
*outDefaultColorTable = ::GetCTable(32 + 2);
665
pixelFormat = k2IndexedPixelFormat;
669
if (outDefaultColorTable)
670
*outDefaultColorTable = ::GetCTable(32 + 4);
672
pixelFormat = k4IndexedPixelFormat;
676
if (outDefaultColorTable)
677
*outDefaultColorTable = ::GetCTable(32 + 8);
679
pixelFormat = k8IndexedPixelFormat;
684
pixelFormat = k16BE555PixelFormat;
688
// 24-bit images are 8 bits per component; the alpha component is ignored
690
pixelFormat = k32ARGBPixelFormat;
695
pixelFormat = k32ARGBPixelFormat;
699
NS_ASSERTION(0, "Unhandled image depth");
702
outBitsPerPixel = bitsPerPixel;
708
/** ---------------------------------------------------
709
* Erase the GWorld contents
711
void nsImageMac::ClearGWorld(GWorldPtr theGWorld)
713
PixMapHandle thePixels = ::GetGWorldPixMap(theGWorld);
715
StPixelLocker pixelLocker(thePixels);
716
StGWorldPortSetter tilingWorldSetter(theGWorld);
718
// White the offscreen
719
::BackColor(whiteColor);
722
::GetPortBounds(theGWorld, &portRect);
723
::EraseRect(&portRect);
726
/** -----------------------------------------------------------------
729
OSErr nsImageMac::AllocateGWorld(PRInt16 depth, CTabHandle colorTable,
730
const Rect& bounds, GWorldPtr *outGWorld)
732
GWorldPtr newGWorld = NULL;
733
// on Mac OS X, there's no reason to use the temp mem flag
734
::NewGWorld(&newGWorld, depth, &bounds, colorTable, nsnull, 0);
738
*outGWorld = newGWorld;
742
void nsImageMac::CopyBitsWithMask(const BitMap* srcBits, const BitMap* maskBits,
743
PRInt16 maskDepth, const BitMap* destBits,
744
const Rect& srcRect, const Rect& maskRect,
745
const Rect& destRect, PRBool inDrawingToPort)
749
StRegionFromPool origClipRegion;
753
// We need to pass in the clip region, even if it doesn't intersect the image, to avoid a bug
754
// on Mac OS X that causes bad image drawing (see bug 137295).
755
::GetClip(origClipRegion);
757
// There is a bug in the OS that causes bad image drawing if the clip region in
758
// the destination port is complex (has holes in??), which hits us on pages with iframes.
759
// To work around this, temporarily set the clip to the intersection of the clip
760
// and this image (which, most of the time, will be rectangular). See bug 137295.
762
StRegionFromPool newClip;
763
::RectRgn(newClip, &destRect);
764
::SectRgn(newClip, origClipRegion, newClip);
768
::CopyDeepMask(srcBits, maskBits, destBits, &srcRect, &maskRect,
769
&destRect, ditherCopy, nsnull);
773
::SetClip(origClipRegion);
778
::CopyBits(srcBits, destBits, &srcRect, &destRect, ditherCopy, nsnull);
783
PRBool nsImageMac::RenderingToPrinter(nsIRenderingContext &aContext)
785
nsCOMPtr<nsIDeviceContext> dc; // (this screams for a private interface, sigh!)
786
aContext.GetDeviceContext(*getter_AddRefs(dc));
787
// a weird and wonderful world of scanky casts and oddly-named intefaces.
788
nsDeviceContextMac* theDevContext = NS_REINTERPRET_CAST(nsDeviceContextMac*, dc.get());
789
return theDevContext && theDevContext->IsPrinter();
800
// Convert from image bits to a PICT, probably for placement on the clipboard.
801
// Blit the transparent image into a new GWorld which is just white, and
802
// then blit that into the picture. We can't just blit directly into
803
// the picture because CopyDeepMask isn't supported on PICTs.
806
nsImageMac::ConvertToPICT(PicHandle* outPicture)
808
*outPicture = nsnull;
810
Rect picFrame = {0, 0, mHeight, mWidth};
811
Rect maskFrame = {0, 0, mHeight, mWidth};
812
GWorldPtr tempGWorld;
814
PRInt16 pixelDepth = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
815
// allocate a "normal" GWorld (which owns its own pixels)
816
if (AllocateGWorld(pixelDepth, nsnull, picFrame, &tempGWorld) != noErr)
817
return NS_ERROR_FAILURE;
820
ClearGWorld(tempGWorld);
822
PixMapHandle tempPixMap = ::GetGWorldPixMap(tempGWorld);
825
StPixelLocker tempPixLocker(tempPixMap); // locks the pixels
827
// now copy into the picture
830
::GetGWorld(&currPort, &currDev);
831
::SetGWorld(tempGWorld, nsnull);
834
::ForeColor(blackColor);
835
::BackColor(whiteColor);
837
// copy from the destination into our temp GWorld, to get the background
838
CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
839
mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull, mAlphaDepth,
840
::GetPortBitMapForCopyBits(tempGWorld), picFrame, maskFrame, picFrame, PR_FALSE);
842
PicHandle thePicture = ::OpenPicture(&picFrame);
846
::CopyBits(::GetPortBitMapForCopyBits(tempGWorld), ::GetPortBitMapForCopyBits(tempGWorld),
847
&picFrame, &picFrame, ditherCopy, nsnull);
853
::SetGWorld(currPort, currDev); // restore to the way things were
856
*outPicture = thePicture;
859
::DisposeGWorld(tempGWorld); // do this after dtor of tempPixLocker!
866
nsImageMac::ConvertFromPICT(PicHandle inPicture)
868
return NS_ERROR_FAILURE;
873
nsImageMac::GetGWorldPtr(GWorldPtr* aGWorld)
875
*aGWorld = mImageGWorld;
879
/** Create a Macintosh native icon from a region of this image.
880
After creating an Icon, you probably want to add it to either
881
an IconSuite, an IconFamily or perhaps just write it as a resource.
883
The caller of the function owns the memory allocated for the resulting icon.
885
The "type" of the icon is implicit in the size and depth and mask
888
size 32, depth 1 -> 'ICON' resource
889
size 16, depth 4 -> 'ics4' resource
890
size 48, depth 32 -> 'ih32' valid only inside an 'icns' resource (IconFamily)
892
n.b. you cannout create any of the 'XXX#' (icm#, ics#, ICN# or ich#) resources
893
using this method. Use ConvertAlphaToIconMask for this task.
895
CopyBits is used to scale and dither, so the bit depth and size of the requested
896
icon do not have to match those of this image.
898
@param the region of this image to make into an icon.
899
@param aIconDepth the depth of the icon, must be one of 1, 4, 8 or 32
900
@param aIconSize the size of the icon. Traditionally 12, 16, 32 or 48
901
@param aOutIcon a handle the icon, caller owns the memory
902
@param aOutIconType the type code for the icon requested (see MakeIconType)
903
@return error an error code -
904
NS_OK if the data was produced,
905
NS_ERROR_INVALID_ARG if the depth is wrong,
906
NS_ERROR_FAILURE if a general error occurs.
912
nsImageMac::ConvertToIcon( const nsRect& aSrcRegion,
913
const PRInt16 aIconDepth,
914
const PRInt16 aIconSize,
916
OSType* aOutIconType)
919
NS_ENSURE_ARG_POINTER(aOutIcon);
920
NS_ENSURE_ARG_POINTER(aOutIconType);
922
*aOutIconType = nsnull;
924
if (aIconDepth != 1 && aIconDepth != 2 && aIconDepth != 4 &&
925
aIconDepth != 8 && aIconDepth != 24 && aIconDepth != 32)
926
return NS_ERROR_INVALID_ARG;
928
//returns null if there size specified isn't a valid size for an icon
929
OSType iconType = MakeIconType(aIconSize, aIconDepth, PR_FALSE);
931
return NS_ERROR_INVALID_ARG;
933
*aOutIconType = iconType;
936
srcRect.top = aSrcRegion.y;
937
srcRect.left = aSrcRegion.x;
938
srcRect.bottom = aSrcRegion.y + aSrcRegion.height;
939
srcRect.right = aSrcRegion.x + aSrcRegion.width;
941
Rect iconRect = { 0, 0, aIconSize, aIconSize};
942
return CopyPixMap(srcRect, iconRect, aIconDepth,
943
PR_FALSE, aOutIcon, PR_TRUE);
947
/** Create an Icon mask from a specified region of the the alpha channel
949
The caller owns the memory allocated for the mask.
951
If the image has no alpha channel, a fully opaque mask of the
952
requested size and depth is generated and returned.
953
If the image has an alpha channel which is at a different depth
954
from the requested mask, the channel is converted.
956
If an 8 bit masks is requested, one is simply returned.
957
As with icons, the size and determines the exact type, however
958
8 bit masks are ONLY valid inside an IconFamily ('icns' resource)
960
size 16 -> s8mk, size 32 -> l8mk, size 48 -> h8mk.
961
(no mini 8 bit masks exist)
963
1 bit masks are trickier. These are older and work for both IconFamilies and
964
IconSuites. Actually, a 1 bit masks is required for every size that you set
965
in an IconFamily or Icon Suite.
967
'XXX#' resources (icm#, ics#, ICN# or ich#) contain a 1 bit icon of the
969
size, followed immediate by a 1 bit mask of the same size.
970
That's how it works, you can't have the mask separately.
971
This mask is used for all icons of that size in a suite or family.
973
So if you want to use a 256 colour 32x32 icon you will typically call
974
CreateToIcon to make an icl8 resource then this function to make an ICN#
975
resource. Then you store the result in an suite or a family.
976
Repeat for other sizes and depths as desired.
977
For more details, see Inside Macintosh: Icon Utilities, Icon Services and
980
size 12 -> icm#, size 16 -> ics#, size 32-> ICN#, size 48-> ich#
981
(constrast ICON above with ICN#, the later has both the icon and the mask)
983
@param the region of this image's alpha channel to make into an icon.
984
@param aIconDepth the depth of the icon, must be 1 or 8
985
@param aIconSize the size of the icon. Traditionally 12, 16, 32 or 48
986
See above for restictions.
987
@param aOutIcon a handle the mask, caller owns the memory
988
@param aOutIconType the type code for the icon mask requested (see MakeIconType)
989
@return error an error code -
990
NS_OK if the data was produced,
991
NS_ERROR_INVALID_ARG if the depth is wrong,
992
NS_ERROR_FAILURE if a general error occurs.
997
nsImageMac::ConvertAlphaToIconMask( const nsRect& aSrcRegion,
998
const PRInt16 aMaskDepth,
999
const PRInt16 aMaskSize,
1001
OSType* aOutIconType)
1003
Handle dstHandle = nsnull;
1006
Rect maskRect = { 0, 0, aMaskSize, aMaskSize};
1008
srcRect.top = aSrcRegion.y;
1009
srcRect.left = aSrcRegion.x;
1010
srcRect.bottom = aSrcRegion.y + aSrcRegion.height;
1011
srcRect.right = aSrcRegion.x + aSrcRegion.width;
1013
NS_ENSURE_ARG_POINTER(aOutMask);
1014
NS_ENSURE_ARG_POINTER(aOutIconType);
1016
*aOutIconType = nsnull;
1018
//returns null if there size specified isn't a valid size for an icon
1019
OSType iconType = MakeIconType(aMaskSize, aMaskDepth, PR_TRUE);
1020
if (iconType == nil) {
1021
return NS_ERROR_INVALID_ARG;
1023
*aOutIconType = iconType;
1027
//image has an alpha channel, copy into icon mask
1029
//if the image has an 8 bit mask, but the caller asks for a 1 bit
1030
//mask, or vice versa, it'll simply be converted by CopyPixMap
1031
if (aMaskDepth == 8)
1033
//for 8 bit masks, this is sufficient
1034
result = CopyPixMap(srcRect, maskRect, aMaskDepth,
1035
PR_TRUE, &dstHandle, PR_TRUE);
1037
else if (aMaskDepth == 1)
1039
//1 bit masks are tricker, we must create an '#' resource
1040
//which inclues both the 1-bit icon and a mask for it (icm#, ics#, ICN# or ich#)
1041
Handle iconHandle = nsnull, maskHandle = nsnull;
1042
result = CopyPixMap(srcRect, maskRect, aMaskDepth,
1043
PR_FALSE, &iconHandle, PR_TRUE);
1045
if (NS_SUCCEEDED(result)) {
1046
result = CopyPixMap(srcRect, maskRect, aMaskDepth,
1047
PR_TRUE, &maskHandle, PR_TRUE);
1048
if (NS_SUCCEEDED(result)) {
1049
//a '#' resource's data is simply the mask appended to the icon
1050
//these icons and masks are small - 128 bytes each
1051
result = ConcatBitsHandles(iconHandle, maskHandle, &dstHandle);
1055
if (iconHandle) ::DisposeHandle(iconHandle);
1056
if (maskHandle) ::DisposeHandle(maskHandle);
1060
NS_ASSERTION(aMaskDepth, "Unregonised icon mask depth");
1061
result = NS_ERROR_INVALID_ARG;
1066
//image has no alpha channel, make an entirely black mask with the appropriate depth
1067
if (aMaskDepth == 8)
1069
//simply make the mask
1070
result = MakeOpaqueMask(aMaskSize, aMaskSize, aMaskDepth, &dstHandle);
1072
else if (aMaskDepth == 1)
1074
//make 1 bit icon and mask as above
1075
Handle iconHandle = nsnull, maskHandle = nsnull;
1076
result = CopyPixMap(srcRect, maskRect, aMaskDepth, PR_FALSE, &iconHandle, PR_TRUE);
1077
if (NS_SUCCEEDED(result)) {
1078
result = MakeOpaqueMask(aMaskSize, aMaskSize, aMaskDepth, &maskHandle);
1079
if (NS_SUCCEEDED(result)) {
1080
//a '#' resource's data is simply the mask appended to the icon
1081
//these icons and masks are small - 128 bytes each
1082
result = ConcatBitsHandles(iconHandle, maskHandle, &dstHandle);
1086
if (iconHandle) ::DisposeHandle(iconHandle);
1087
if (maskHandle) ::DisposeHandle(maskHandle);
1092
NS_ASSERTION(aMaskDepth, "Unregonised icon mask depth");
1093
result = NS_ERROR_INVALID_ARG;
1097
if (NS_SUCCEEDED(result)) *aOutMask = dstHandle;
1099
} // ConvertAlphaToIconMask
1103
/** Create a new PixMap with the specified size and depth,
1104
then copy either the image bits or the mask bits from this
1105
image into a handle. CopyBits is used to dither and scale
1106
the indicated source region from this image into the resulting
1107
handle. For indexed colour image depths, a standard Mac colour table
1108
is used. For masks, a standard Mac greyscale table is used.
1110
@param aSrcregion the part of the image to copy
1111
@param aDestRegion the size of the destination image bits to create
1112
@param aDestDepth the depth of the destination image bits
1113
@param aCopyMaskBits if true, the alpha bits are copied, otherwise the
1114
image bits are copied. You must check that the
1115
image has an alpha channel before calling with this
1116
parameter set to true.
1117
@param aDestData the result bits are copied into this handle, the caller
1118
is responsible for disposing of them
1121
/** Call CopyPixMap instead*/
1123
nsImageMac::CopyPixMap(const Rect& aSrcRegion,
1124
const Rect& aDestRegion,
1125
const PRInt32 aDestDepth,
1126
const PRBool aCopyMaskBits,
1128
PRBool aAllow2Bytes /* = PR_FALSE */
1131
NS_ENSURE_ARG_POINTER(aDestData);
1132
*aDestData = nsnull;
1135
CTabHandle destColorTable = nsnull;
1136
GWorldPtr srcGWorld = nsnull;
1138
//are we copying the image data or the mask
1142
return NS_ERROR_INVALID_ARG;
1144
srcGWorld = mMaskGWorld;
1146
if (aDestDepth <= 8)
1147
destColorTable = GetCTable(32 + aDestDepth);
1152
return NS_ERROR_INVALID_ARG;
1154
srcGWorld = mImageGWorld;
1155
copyMode = ditherCopy;
1156
if (aDestDepth <= 8)
1157
destColorTable = GetCTable(64 + aDestDepth);
1160
// create a handle for the bits, and then wrap a GWorld around it
1161
PRInt32 destRowBytes = CalculateRowBytesInternal(aDestRegion.right - aDestRegion.left, aDestDepth, aAllow2Bytes);
1162
PRInt32 destSize = (aDestRegion.bottom - aDestRegion.top) * destRowBytes;
1164
Handle resultData = ::NewHandleClear(destSize);
1165
if (!resultData) return NS_ERROR_OUT_OF_MEMORY;
1167
PRInt32 bitsPerPixel;
1168
PRUint32 pixelFormat = GetPixelFormatForDepth(aDestDepth, bitsPerPixel);
1171
StHandleLocker destBitsLocker(resultData);
1173
GWorldPtr destGWorld = nsnull;
1174
OSErr err = ::NewGWorldFromPtr(&destGWorld, pixelFormat, &aDestRegion, destColorTable, nsnull, 0, *resultData, destRowBytes);
1177
NS_ASSERTION(0, "NewGWorldFromPtr failed in nsImageMac::CopyPixMap");
1178
return NS_ERROR_FAILURE;
1181
::CopyBits( ::GetPortBitMapForCopyBits(srcGWorld),
1182
::GetPortBitMapForCopyBits(destGWorld),
1183
&aSrcRegion, &aDestRegion,
1186
// do I need to free the color table explicitly?
1187
::DisposeGWorld(destGWorld);
1190
*aDestData = resultData;
1195
/** Concantenate the data supplied in the given handles,
1196
the caller is responsible for disposing the result.
1197
This uses AllocateBitsHandle to allocate the new handle, to take
1198
advantage of spillover allocation into TempMemory
1199
@param aSrcData1 first piece of source data
1200
@param aSrcData2 second piece of src data
1201
@param astData on exit, contains a copy of aSrcData1 followed by
1203
@return nsresult an error code
1206
nsImageMac::ConcatBitsHandles( Handle aSrcData1,
1210
NS_ENSURE_ARG_POINTER(aDstData);
1213
Handle result = aSrcData1;
1215
// clone the first handle
1216
OSErr err = ::HandToHand(&result);
1217
if (err != noErr) return NS_ERROR_OUT_OF_MEMORY;
1219
// then append the second
1220
err = ::HandAndHand(result, aSrcData2);
1223
::DisposeHandle(result);
1224
return NS_ERROR_OUT_OF_MEMORY;
1229
} // ConcatBitsHandles
1232
/** Make a completely opaque mask for an Icon of the specified size and depth.
1233
@param aWidth the width of the desired mask
1234
@param aHeight the height of the desired mask
1235
@param aDepth the bit depth of the desired mask
1236
@param aMask the mask
1237
@return nsresult an error code
1240
nsImageMac::MakeOpaqueMask( const PRInt32 aWidth,
1241
const PRInt32 aHeight,
1242
const PRInt32 aDepth,
1245
NS_ENSURE_ARG_POINTER(aMask);
1248
//mask size = (width * height * depth)
1249
PRInt32 size = aHeight * CalculateRowBytesInternal(aWidth, aDepth, PR_TRUE);
1251
Handle resultData = ::NewHandle(size);
1253
return NS_ERROR_OUT_OF_MEMORY;
1255
StHandleLocker dstLocker(resultData);
1256
memset(*resultData, 0xFF, size);
1257
*aMask = resultData;
1262
/** Make icon types (OSTypes) from depth and size arguments
1263
Valid depths for icons: 1, 4, 8 and then 16, 24 or 32 are treat as 32.
1264
Valid masks for icons: 1 and 8.
1265
Valid sizes for icons:
1266
16x12 - mini (pretty obsolete)
1272
Exact mapping table (see note above about 1 bit masks being generally inseperable from 1 bit icons)
1275
depth height width type
1276
1 32 32 ICON (one bit icon without mask)
1292
1 32 32 ICN# (one bit icon and mask - you probably want one of these, not an 'ICON')
1299
16 and 24 bit depths will be promoted to 32 bit.
1300
Any other combination not in the above table gives nil
1302
@param aHeight the height of the icon or mask
1303
@param aDepth the depth of the icon or mask
1304
@param aMask pass true for masks, false for icons
1305
@return the correct OSType as defined above
1308
nsImageMac::MakeIconType(PRInt32 aHeight, PRInt32 aDepth, PRBool aMask)
1396
nsresult nsImageMac::SlowTile(nsIRenderingContext &aContext,
1397
nsDrawingSurface aSurface,
1398
PRInt32 aSXOffset, PRInt32 aSYOffset,
1399
PRInt32 aPadX, PRInt32 aPadY,
1400
const nsRect &aTileRect)
1402
if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
1408
validWidth = mWidth,
1409
validHeight = mHeight;
1411
// limit the image rectangle to the size of the image data which
1412
// has been validated.
1413
if (mDecodedY2 < mHeight) {
1414
validHeight = mDecodedY2 - mDecodedY1;
1416
if (mDecodedX2 < mWidth) {
1417
validWidth = mDecodedX2 - mDecodedX1;
1419
if (mDecodedY1 > 0) {
1420
validHeight -= mDecodedY1;
1421
validY = mDecodedY1;
1423
if (mDecodedX1 > 0) {
1424
validWidth -= mDecodedX1;
1425
validX = mDecodedX1;
1428
PRInt32 aY0 = aTileRect.y - aSYOffset,
1429
aX0 = aTileRect.x - aSXOffset,
1430
aY1 = aTileRect.y + aTileRect.height,
1431
aX1 = aTileRect.x + aTileRect.width;
1433
for (PRInt32 y = aY0; y < aY1; y += mHeight + aPadY)
1434
for (PRInt32 x = aX0; x < aX1; x += mWidth + aPadX)
1436
Draw(aContext, aSurface,
1437
0, 0, PR_MIN(validWidth, aX1-x), PR_MIN(validHeight, aY1-y), // src coords
1438
x, y, PR_MIN(validWidth, aX1-x), PR_MIN(validHeight, aY1-y)); // dest coords
1446
// Fast tiling algorithm that uses successive doubling of the tile in a GWorld
1447
// to scale it up. This code does not deal with images whose masks are a different
1448
// size to the image (currently never happens), nor does it deal with partially
1449
// decoded images. Because we allocate our image bits handles zero'd out, I don't
1450
// think this matters.
1452
// This code is not called for printing (because all the CopyDeepMask stuff doesn't
1453
// work when printing).
1455
nsresult nsImageMac::DrawTileQuickly(nsIRenderingContext &aContext,
1456
nsDrawingSurface aSurface,
1457
PRInt32 aSXOffset, PRInt32 aSYOffset,
1458
const nsRect &aTileRect)
1461
return NS_ERROR_FAILURE;
1463
// lock and set up bits handles
1467
imageRect.right = mWidth;
1468
imageRect.bottom = mHeight;
1470
// get the destination pix map
1471
nsDrawingSurfaceMac* destSurface = static_cast<nsDrawingSurfaceMac*>(aSurface);
1474
nsresult rv = destSurface->GetGrafPtr(&destPort);
1475
if (NS_FAILED(rv)) return rv;
1477
StPortSetter destSetter(destPort);
1478
::ForeColor(blackColor);
1479
::BackColor(whiteColor);
1481
PixMapHandle destPixels = ::GetGWorldPixMap(destPort);
1482
StPixelLocker destPixLocker(destPixels);
1484
// How many tiles will we need? Allocating GWorlds is expensive,
1485
// so if only a few tilings are required, the old way is preferable.
1486
const PRInt32 kTilingCopyThreshold = 64;
1488
PRInt32 tilingBoundsWidth = aSXOffset + aTileRect.width;
1489
PRInt32 tilingBoundsHeight = aSYOffset + aTileRect.height;
1491
PRInt32 tiledRows = (tilingBoundsHeight + mHeight - 1) / mHeight; // round up
1492
PRInt32 tiledCols = (tilingBoundsWidth + mWidth - 1) / mWidth; // round up
1494
PRInt32 numTiles = tiledRows * tiledCols;
1495
if (numTiles <= kTilingCopyThreshold)
1497
// the outside bounds of the tiled area
1498
PRInt32 topY = aTileRect.y - aSYOffset,
1499
bottomY = aTileRect.y + aTileRect.height,
1500
leftX = aTileRect.x - aSXOffset,
1501
rightX = aTileRect.x + aTileRect.width;
1503
for (PRInt32 y = topY; y < bottomY; y += mHeight)
1505
for (PRInt32 x = leftX; x < rightX; x += mWidth)
1507
Rect imageDestRect = imageRect;
1508
Rect imageSrcRect = imageRect;
1509
::OffsetRect(&imageDestRect, x, y);
1511
if (x > rightX - mWidth) {
1512
imageDestRect.right = PR_MIN(imageDestRect.right, rightX);
1513
imageSrcRect.right = imageRect.left + (imageDestRect.right - imageDestRect.left);
1516
if (y > bottomY - mHeight) {
1517
imageDestRect.bottom = PR_MIN(imageDestRect.bottom, bottomY);
1518
imageSrcRect.bottom = imageRect.top + (imageDestRect.bottom - imageDestRect.top);
1521
// CopyBits will do the truncation for us at the edges
1522
CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
1523
mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull, mAlphaDepth,
1524
::GetPortBitMapForCopyBits(destPort), imageSrcRect, imageSrcRect, imageDestRect, PR_TRUE);
1531
Rect tileDestRect; // aTileRect as a Mac rect
1532
tileDestRect.left = aTileRect.x;
1533
tileDestRect.top = aTileRect.y;
1534
tileDestRect.bottom = tileDestRect.top + aTileRect.height;
1535
tileDestRect.right = tileDestRect.left + aTileRect.width;
1537
Rect tileRect = tileDestRect;
1538
::OffsetRect(&tileRect, -tileRect.left, -tileRect.top); // offset to {0, 0}
1540
PRInt16 pixelDepth = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
1542
GWorldPtr tilingGWorld = nsnull;
1543
OSErr err = AllocateGWorld(pixelDepth, nsnull, tileRect, &tilingGWorld);
1544
if (err != noErr) return NS_ERROR_OUT_OF_MEMORY;
1546
GWorldPtr maskingGWorld = nsnull;
1549
err = AllocateGWorld(pixelDepth, nsnull, tileRect, &maskingGWorld);
1551
::DisposeGWorld(tilingGWorld);
1552
return NS_ERROR_OUT_OF_MEMORY;
1555
ClearGWorld(maskingGWorld);
1558
PixMapHandle tilingPixels = ::GetGWorldPixMap(tilingGWorld);
1559
PixMapHandle maskingPixels = (maskingGWorld) ? ::GetGWorldPixMap(maskingGWorld) : nsnull;
1561
{ // scope for locks
1562
StPixelLocker tempPixLocker(tilingPixels);
1563
StPixelLocker tempMaskLocker(maskingPixels); // OK will null pixels
1565
const BitMap* destBitMap = ::GetPortBitMapForCopyBits(destPort);
1567
const BitMap* imageBitmap = ::GetPortBitMapForCopyBits(mImageGWorld);
1568
const BitMap* maskBitMap = mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull;
1570
const BitMap* tilingBitMap = ::GetPortBitMapForCopyBits(tilingGWorld);
1571
const BitMap* maskingBitMap = maskingGWorld ? ::GetPortBitMapForCopyBits(maskingGWorld) : nsnull;
1574
// our strategy here is to avoid allocating a GWorld which is bigger than the destination
1575
// area, by creating a tileable area in the top left of the GWorld by taking parts of
1576
// our tiled image. If aXOffset and aYOffset are 0, this tile is simply the image. If not, it
1577
// is a composite of 2 or 4 segments of the image.
1578
// Then we double up that tile as necessary.
1586
| - +-------------------------+
1592
|---------+ - - - - + 3 |
1598
| - - - - - - - - - + - - |
1602
+-------------------------+
1606
Rect tilePartRect = imageRect;
1608
// top left of offset tile (W)
1609
Rect offsetTileSrc = tilePartRect;
1610
offsetTileSrc.left = aSXOffset;
1611
offsetTileSrc.top = aSYOffset;
1613
Rect offsetTileDest = {0};
1614
offsetTileDest.right = tilePartRect.right - aSXOffset;
1615
offsetTileDest.bottom = tilePartRect.bottom - aSYOffset;
1617
::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1619
::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1621
// top right of offset tile (Z)
1624
offsetTileSrc = tilePartRect;
1625
offsetTileSrc.right = aSXOffset;
1626
offsetTileSrc.top = aSYOffset;
1628
offsetTileDest = tilePartRect;
1629
offsetTileDest.left = tilePartRect.right - aSXOffset;
1630
offsetTileDest.bottom = tilePartRect.bottom - aSYOffset;
1632
::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1634
::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1639
// bottom left of offset tile (Y)
1640
offsetTileSrc = tilePartRect;
1641
offsetTileSrc.left = aSXOffset;
1642
offsetTileSrc.bottom = aSYOffset;
1644
offsetTileDest = tilePartRect;
1645
offsetTileDest.right = tilePartRect.right - aSXOffset;
1646
offsetTileDest.top = tilePartRect.bottom - aSYOffset;
1648
::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1650
::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1653
if (aSXOffset > 0 && aSYOffset > 0)
1655
// bottom right of offset tile (X)
1656
offsetTileSrc = tilePartRect;
1657
offsetTileSrc.right = aSXOffset;
1658
offsetTileSrc.bottom = aSYOffset;
1660
offsetTileDest = tilePartRect;
1661
offsetTileDest.left = tilePartRect.right - aSXOffset;
1662
offsetTileDest.top = tilePartRect.bottom - aSYOffset;
1664
::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1666
::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
1669
// now double up this tile to cover the area
1670
PRBool doneWidth = PR_FALSE, doneHeight = PR_FALSE;
1672
Rect srcRect, dstRect;
1673
PRInt32 tileWidth = mWidth;
1674
PRInt32 tileHeight = mHeight;
1675
while (!doneWidth || !doneHeight)
1677
if (tileWidth < tileRect.right)
1679
srcRect.left = 0; srcRect.top = 0;
1680
srcRect.bottom = tileHeight; srcRect.right = tileWidth;
1682
dstRect.left = tileWidth; dstRect.top = 0;
1683
dstRect.bottom = tileHeight; dstRect.right = tileWidth + tileWidth;
1685
::CopyBits(tilingBitMap, tilingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
1687
::CopyBits(maskingBitMap, maskingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
1692
doneWidth = PR_TRUE;
1694
if (tileHeight < tileRect.bottom)
1696
srcRect.left = 0; srcRect.top = 0;
1697
srcRect.bottom = tileHeight; srcRect.right = tileWidth;
1699
dstRect.left = 0; dstRect.top = tileHeight;
1700
dstRect.bottom = tileHeight + tileHeight; dstRect.right = tileWidth;
1702
::CopyBits(tilingBitMap, tilingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
1704
::CopyBits(maskingBitMap, maskingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
1709
doneHeight = PR_TRUE;
1712
// We could optimize this a little more by making the temp GWorld 1/4 the size of the dest,
1713
// and doing 4 final blits directly to the destination.
1715
// finally, copy to the destination
1716
CopyBitsWithMask(tilingBitMap,
1717
maskingBitMap ? maskingBitMap : nsnull, mAlphaDepth,
1718
destBitMap, tileRect, tileRect, tileDestRect, PR_TRUE);
1720
} // scope for locks
1723
::DisposeGWorld(tilingGWorld);
1725
::DisposeGWorld(maskingGWorld);
1731
NS_IMETHODIMP nsImageMac::DrawTile(nsIRenderingContext &aContext,
1732
nsDrawingSurface aSurface,
1733
PRInt32 aSXOffset, PRInt32 aSYOffset,
1734
PRInt32 aPadX, PRInt32 aPadY,
1735
const nsRect &aTileRect)
1737
nsresult rv = NS_ERROR_FAILURE;
1738
PRBool padded = (aPadX || aPadY);
1740
if (!RenderingToPrinter(aContext) && !padded)
1741
rv = DrawTileQuickly(aContext, aSurface, aSXOffset, aSYOffset, aTileRect);
1744
rv = SlowTile(aContext, aSurface, aSXOffset, aSYOffset, aPadX, aPadY, aTileRect);