~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/gfx/src/mac/nsImageMac.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
4
 *
 
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/
 
9
 *
 
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
 
13
 * License.
 
14
 *
 
15
 * The Original Code is mozilla.org code.
 
16
 *
 
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.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 *
 
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.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
#include "nsImageMac.h"
 
39
#include "nsRenderingContextMac.h"
 
40
#include "nsDeviceContextMac.h"
 
41
#include "nsCarbonHelpers.h"
 
42
#include "nsRegionPool.h"
 
43
 
 
44
#include <MacTypes.h>
 
45
#include <Quickdraw.h>
 
46
 
 
47
#include "nsGfxUtils.h"
 
48
#include "imgScaler.h"
 
49
 
 
50
#if 0
 
51
#if TARGET_CARBON
 
52
// useful region debugging code.
 
53
static OSStatus PrintRgnRectProc(UInt16 message, RgnHandle rgn, const Rect *inRect, void *refCon)
 
54
{
 
55
  UInt32*   rectCount = (UInt32*)refCon;
 
56
  
 
57
  switch (message)
 
58
  {
 
59
    case kQDRegionToRectsMsgInit:
 
60
      printf("Dumping region 0x%X\n", rgn);
 
61
      break;
 
62
      
 
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);
 
65
      (*rectCount)++;
 
66
      break;
 
67
      
 
68
    case kQDRegionToRectsMsgTerminate:
 
69
      printf("\n");
 
70
      break;
 
71
  }
 
72
  
 
73
  return noErr;
 
74
}
 
75
 
 
76
static void PrintRegionOutline(RgnHandle inRgn)
 
77
{
 
78
  static RegionToRectsUPP sCountRectProc = nsnull;
 
79
  if (!sCountRectProc)
 
80
    sCountRectProc = NewRegionToRectsUPP(PrintRgnRectProc);
 
81
  
 
82
  UInt32    rectCount = 0;  
 
83
  ::QDRegionToRects(inRgn, kQDParseRegionFromTopLeft, sCountRectProc, &rectCount);
 
84
}
 
85
#endif // TARGET_CARBON
 
86
#endif
 
87
 
 
88
#pragma mark -
 
89
 
 
90
/** ---------------------------------------------------
 
91
 *  See documentation in nsImageMac.h
 
92
 *  @update 
 
93
 */
 
94
nsImageMac::nsImageMac()
 
95
: mImageGWorld(nsnull)
 
96
, mImageBits(nsnull)
 
97
, mWidth(0)
 
98
, mHeight(0)
 
99
, mRowBytes(0)
 
100
, mBytesPerPixel(0)   // this value is never initialized; the API that uses it is unused
 
101
, mMaskGWorld(nsnull)
 
102
, mMaskBits(nsnull)
 
103
, mAlphaDepth(0)
 
104
, mAlphaRowBytes(0)
 
105
, mDecodedX1(PR_INT32_MAX)
 
106
, mDecodedY1(PR_INT32_MAX)
 
107
, mDecodedX2(0)
 
108
, mDecodedY2(0)
 
109
{
 
110
}
 
111
 
 
112
/** ---------------------------------------------------
 
113
 *  See documentation in nsImageMac.h
 
114
 *  @update 
 
115
 */
 
116
nsImageMac::~nsImageMac()
 
117
{
 
118
  if (mImageGWorld)
 
119
    ::DisposeGWorld(mImageGWorld);
 
120
    
 
121
  if (mMaskGWorld)
 
122
    ::DisposeGWorld(mMaskGWorld);
 
123
  
 
124
  if (mImageBits)
 
125
    free(mImageBits);
 
126
 
 
127
  if (mMaskBits)
 
128
    free(mMaskBits);
 
129
}
 
130
 
 
131
NS_IMPL_ISUPPORTS2(nsImageMac, nsIImage, nsIImageMac)
 
132
 
 
133
/** ---------------------------------------------------
 
134
 *  See documentation in nsImageMac.h
 
135
 *  @update 
 
136
 */
 
137
PRUint8* 
 
138
nsImageMac::GetBits()
 
139
{
 
140
  NS_ASSERTION(mImageBits, "Getting bits for non-existent image");
 
141
  return (PRUint8 *)mImageBits;
 
142
}
 
143
 
 
144
 
 
145
/** ---------------------------------------------------
 
146
 *  See documentation in nsImageMac.h
 
147
 *  @update 
 
148
 */
 
149
PRUint8* 
 
150
nsImageMac::GetAlphaBits()
 
151
{
 
152
  NS_ASSERTION(mMaskBits, "Getting bits for non-existent image mask");
 
153
  return (PRUint8 *)mMaskBits;
 
154
}
 
155
 
 
156
 
 
157
/** ---------------------------------------------------
 
158
 *  See documentation in nsImageMac.h
 
159
 *  @update 08/03/99 -- cleared out the image pointer - dwc
 
160
 */
 
161
nsresult 
 
162
nsImageMac::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
 
163
{
 
164
  // Assumed: Init only runs once (due to gfxIImageFrame only allowing 1 Init)
 
165
  OSErr err = noErr;
 
166
  
 
167
  mWidth = aWidth;
 
168
  mHeight = aHeight;
 
169
 
 
170
  err = CreateGWorld(aWidth, aHeight, aDepth, &mImageGWorld, &mImageBits, &mRowBytes);
 
171
  if (err != noErr)
 
172
  {
 
173
    if (err == memFullErr)
 
174
      nsMemory::HeapMinimize(PR_FALSE);
 
175
    return NS_ERROR_FAILURE;
 
176
  }
 
177
  
 
178
  // this is unused
 
179
  //mBytesPerPixel = (mImagePixmap.pixelSize <= 8) ? 1 : mImagePixmap.pixelSize / 8;
 
180
        
 
181
  if (aMaskRequirements != nsMaskRequirements_kNoMask)
 
182
  {
 
183
    switch (aMaskRequirements)
 
184
    {
 
185
      case nsMaskRequirements_kNeeds1Bit:
 
186
        mAlphaDepth = 1;
 
187
        break;
 
188
        
 
189
      case nsMaskRequirements_kNeeds8Bit:
 
190
        mAlphaDepth = 8;              
 
191
        break;
 
192
 
 
193
      default:
 
194
        break; // avoid compiler warning
 
195
    }
 
196
    
 
197
    err = CreateGWorld(aWidth, aHeight, mAlphaDepth, &mMaskGWorld, &mMaskBits, &mAlphaRowBytes);
 
198
    if (err != noErr)
 
199
    {
 
200
      if (err == memFullErr)
 
201
        nsMemory::HeapMinimize(PR_FALSE);
 
202
      return NS_ERROR_FAILURE;
 
203
    }
 
204
  }
 
205
  
 
206
  return NS_OK;
 
207
}
 
208
 
 
209
/** ---------------------------------------------------
 
210
 *  See documentation in nsImageMac.h
 
211
 *  @update 
 
212
 */
 
213
void nsImageMac::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect)
 
214
{
 
215
  mDecodedX1 = PR_MIN(mDecodedX1, aUpdateRect->x);
 
216
  mDecodedY1 = PR_MIN(mDecodedY1, aUpdateRect->y);
 
217
 
 
218
  if (aUpdateRect->YMost() > mDecodedY2)
 
219
    mDecodedY2 = aUpdateRect->YMost();
 
220
 
 
221
  if (aUpdateRect->XMost() > mDecodedX2)
 
222
    mDecodedX2 = aUpdateRect->XMost();
 
223
}
 
224
 
 
225
 
 
226
/** ---------------------------------------------------
 
227
 *  See documentation in nsImageMac.h
 
228
 *  @update 
 
229
 */
 
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)
 
232
{
 
233
  Rect                srcRect, dstRect, maskRect;
 
234
  nsresult rv = NS_OK;
 
235
 
 
236
  if (!mImageGWorld)
 
237
    return NS_ERROR_FAILURE;
 
238
 
 
239
  if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
 
240
    return NS_OK;
 
241
 
 
242
  PRInt32 srcWidth = aSWidth;
 
243
  PRInt32 srcHeight = aSHeight;
 
244
  PRInt32 dstWidth = aDWidth;
 
245
  PRInt32 dstHeight = aDHeight;
 
246
 
 
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
 
249
  // the dest rect.
 
250
 
 
251
  PRInt32 j = aSX + aSWidth;
 
252
  PRInt32 z;
 
253
  if (j > mDecodedX2) {
 
254
    z = j - mDecodedX2;
 
255
    aDWidth -= z*dstWidth/srcWidth;
 
256
    aSWidth -= z;
 
257
  }
 
258
  if (aSX < mDecodedX1) {
 
259
    aDX += (mDecodedX1 - aSX)*dstWidth/srcWidth;
 
260
    aSX = mDecodedX1;
 
261
  }
 
262
 
 
263
  j = aSY + aSHeight;
 
264
  if (j > mDecodedY2) {
 
265
    z = j - mDecodedY2;
 
266
    aDHeight -= z*dstHeight/srcHeight;
 
267
    aSHeight -= z;
 
268
  }
 
269
  if (aSY < mDecodedY1) {
 
270
    aDY += (mDecodedY1 - aSY)*dstHeight/srcHeight;
 
271
    aSY = mDecodedY1;
 
272
  }
 
273
 
 
274
  if (aDWidth <= 0 || aDHeight <= 0 || aSWidth <= 0 || aSHeight <= 0)
 
275
    return NS_OK;
 
276
 
 
277
  ::SetRect(&srcRect, aSX, aSY, aSX + aSWidth, aSY + aSHeight);
 
278
  maskRect = srcRect;
 
279
  ::SetRect(&dstRect, aDX, aDY, aDX + aDWidth, aDY + aDHeight);
 
280
 
 
281
  // get the destination pix map
 
282
  nsDrawingSurfaceMac* surface = static_cast<nsDrawingSurfaceMac*>(aSurface);
 
283
  CGrafPtr    destPort;
 
284
  rv = surface->GetGrafPtr(&destPort);
 
285
  if (NS_FAILED(rv)) return rv;
 
286
 
 
287
  StPortSetter    destSetter(destPort);
 
288
  ::ForeColor(blackColor);
 
289
  ::BackColor(whiteColor);
 
290
 
 
291
  if (RenderingToPrinter(aContext))
 
292
  {
 
293
    if (!mMaskGWorld)
 
294
    {
 
295
      ::CopyBits(::GetPortBitMapForCopyBits(mImageGWorld),
 
296
                 ::GetPortBitMapForCopyBits(destPort),
 
297
                 &srcRect, &dstRect, srcCopy, nsnull);
 
298
    }
 
299
    else
 
300
    {
 
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.
 
304
 
 
305
      GWorldPtr tempGWorld;
 
306
 
 
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.
 
310
 
 
311
      PRInt16 pixelDepth = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
 
312
      if (AllocateGWorld(pixelDepth, nsnull, srcRect, &tempGWorld) == noErr)
 
313
      {
 
314
        // erase it to white
 
315
        ClearGWorld(tempGWorld);
 
316
 
 
317
        PixMapHandle    tempPixMap = ::GetGWorldPixMap(tempGWorld);
 
318
        if (tempPixMap)
 
319
        {
 
320
          StPixelLocker   tempPixLocker(tempPixMap);      // locks the pixels
 
321
 
 
322
          // Copy everything into tempGWorld
 
323
          if (mAlphaDepth > 1)
 
324
            ::CopyDeepMask(::GetPortBitMapForCopyBits(mImageGWorld),
 
325
                           ::GetPortBitMapForCopyBits(mMaskGWorld),
 
326
                           ::GetPortBitMapForCopyBits(tempGWorld),
 
327
                           &srcRect, &maskRect, &srcRect, srcCopy, nsnull);
 
328
          else
 
329
            ::CopyMask(::GetPortBitMapForCopyBits(mImageGWorld),
 
330
                       ::GetPortBitMapForCopyBits(mMaskGWorld),
 
331
                       ::GetPortBitMapForCopyBits(tempGWorld),
 
332
                       &srcRect, &maskRect, &srcRect);
 
333
 
 
334
          // now copy tempGWorld bits to destination
 
335
          ::CopyBits(::GetPortBitMapForCopyBits(tempGWorld),
 
336
                     ::GetPortBitMapForCopyBits(destPort),
 
337
                     &srcRect, &dstRect, srcCopy, nsnull);
 
338
        }
 
339
        
 
340
        ::DisposeGWorld(tempGWorld);  // do this after dtor of tempPixLocker!
 
341
      }
 
342
    }
 
343
  }
 
344
  else
 
345
  {
 
346
    // not printing...
 
347
    if (mAlphaDepth == 1 && ((aSWidth != aDWidth) || (aSHeight != aDHeight)))
 
348
    {
 
349
      // If scaling an image that has a 1-bit mask...
 
350
 
 
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
 
355
      // image and mask.
 
356
 
 
357
      GWorldPtr tempSrcGWorld = nsnull, tempMaskGWorld = nsnull;
 
358
 
 
359
      // create temporary source GWorld
 
360
      char* scaledSrcBits;
 
361
      PRInt32 tmpSrcRowBytes;
 
362
      PRInt16 pixelDepthSrc = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
 
363
      OSErr err = CreateGWorld(aDWidth, aDHeight, pixelDepthSrc,
 
364
                               &tempSrcGWorld, &scaledSrcBits, &tmpSrcRowBytes);
 
365
 
 
366
      if (err != noErr)  return NS_ERROR_FAILURE;
 
367
 
 
368
      // create temporary mask GWorld
 
369
      char* scaledMaskBits;
 
370
      PRInt32 tmpMaskRowBytes;
 
371
      err = CreateGWorld(aDWidth, aDHeight, mAlphaDepth, &tempMaskGWorld,
 
372
                         &scaledMaskBits, &tmpMaskRowBytes);
 
373
 
 
374
      if (err == noErr)
 
375
      {
 
376
        PixMapHandle srcPixMap = ::GetGWorldPixMap(mImageGWorld);
 
377
        PixMapHandle maskPixMap = ::GetGWorldPixMap(mMaskGWorld);
 
378
        if (srcPixMap && maskPixMap)
 
379
        {
 
380
          StPixelLocker srcPixLocker(srcPixMap);      // locks the pixels
 
381
          StPixelLocker maskPixLocker(maskPixMap);
 
382
 
 
383
          // scale the source
 
384
          RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
 
385
                      0, 0, aDWidth - 1, aDHeight - 1,
 
386
                      mImageBits, mRowBytes, scaledSrcBits, tmpSrcRowBytes,
 
387
                      pixelDepthSrc);
 
388
 
 
389
          // scale the mask
 
390
          RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
 
391
                      0, 0, aDWidth - 1, aDHeight - 1,
 
392
                      mMaskBits, mAlphaRowBytes, scaledMaskBits,
 
393
                      tmpMaskRowBytes, mAlphaDepth);
 
394
 
 
395
          Rect tmpRect;
 
396
          ::SetRect(&tmpRect, 0, 0, aDWidth, aDHeight);
 
397
 
 
398
          // copy to screen
 
399
          CopyBitsWithMask(::GetPortBitMapForCopyBits(tempSrcGWorld),
 
400
                           ::GetPortBitMapForCopyBits(tempMaskGWorld),
 
401
                           mAlphaDepth, ::GetPortBitMapForCopyBits(destPort),
 
402
                           tmpRect, tmpRect, dstRect, PR_TRUE);
 
403
        }
 
404
 
 
405
        ::DisposeGWorld(tempMaskGWorld);
 
406
        free(scaledMaskBits);
 
407
      }
 
408
      else
 
409
      {
 
410
        rv = NS_ERROR_FAILURE;
 
411
      }
 
412
 
 
413
      ::DisposeGWorld(tempSrcGWorld);
 
414
      free(scaledSrcBits);
 
415
    }
 
416
    else
 
417
    {
 
418
      // not scaling...
 
419
      CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
 
420
                       mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull,
 
421
                       mAlphaDepth, ::GetPortBitMapForCopyBits(destPort),
 
422
                       srcRect, maskRect, dstRect, PR_TRUE);
 
423
    }
 
424
  }
 
425
 
 
426
  return rv;
 
427
}
 
428
 
 
429
/** ---------------------------------------------------
 
430
 *  See documentation in nsImageMac.h
 
431
 *  @update 
 
432
 */
 
433
NS_IMETHODIMP nsImageMac::Draw(nsIRenderingContext &aContext, 
 
434
                 nsDrawingSurface aSurface,
 
435
                 PRInt32 aX, PRInt32 aY, 
 
436
                 PRInt32 aWidth, PRInt32 aHeight)
 
437
{
 
438
 
 
439
  return Draw(aContext, aSurface, 0, 0, mWidth, mHeight, aX, aY, aWidth, aHeight);
 
440
}
 
441
 
 
442
/** ---------------------------------------------------
 
443
 *  See documentation in nsImageMac.h
 
444
 *  @update 
 
445
 */
 
446
NS_IMETHODIMP nsImageMac::DrawToImage(nsIImage* aDstImage, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
 
447
{
 
448
  Rect srcRect, dstRect, maskRect;
 
449
 
 
450
  if (!mImageGWorld)
 
451
    return NS_ERROR_FAILURE;
 
452
 
 
453
#ifdef MOZ_WIDGET_COCOA
 
454
  nsGraphicsUtils::SetPortToKnownGoodPort();
 
455
#endif
 
456
 
 
457
  // lock and set up bits handles
 
458
  LockImagePixels(PR_FALSE);
 
459
  LockImagePixels(PR_TRUE);
 
460
 
 
461
  ::SetRect(&srcRect, 0, 0, mWidth, mHeight);
 
462
  maskRect = srcRect;
 
463
  ::SetRect(&dstRect, aDX, aDY, aDX + aDWidth, aDY + aDHeight);
 
464
 
 
465
  ::ForeColor(blackColor);
 
466
  ::BackColor(whiteColor);
 
467
  
 
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));
 
473
  
 
474
  GWorldPtr destGWorld;
 
475
  dstMacImage->GetGWorldPtr(&destGWorld);
 
476
  NS_ASSERTION(destGWorld, "No dest pixels!");
 
477
 
 
478
  CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
 
479
      mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull, mAlphaDepth,
 
480
      ::GetPortBitMapForCopyBits(destGWorld), srcRect, maskRect, dstRect, PR_FALSE);
 
481
  
 
482
  aDstImage->UnlockImagePixels(PR_FALSE);
 
483
  aDstImage->UnlockImagePixels(PR_TRUE);
 
484
  UnlockImagePixels(PR_FALSE);
 
485
  UnlockImagePixels(PR_TRUE);
 
486
  
 
487
  return NS_OK;
 
488
}
 
489
 
 
490
 
 
491
/** ---------------------------------------------------
 
492
 *  See documentation in nsImageMac.h
 
493
 *  @update 
 
494
 */
 
495
nsresult nsImageMac::Optimize(nsIDeviceContext* aContext)
 
496
{
 
497
  return NS_OK;
 
498
}
 
499
 
 
500
#pragma mark -
 
501
 
 
502
/** ---------------------------------------------------
 
503
 *  Lock down the image pixels
 
504
 */
 
505
NS_IMETHODIMP
 
506
nsImageMac::LockImagePixels(PRBool aMaskPixels)
 
507
{
 
508
  // nothing to do
 
509
  return NS_OK;
 
510
}
 
511
 
 
512
/** ---------------------------------------------------
 
513
 *  Unlock the pixels
 
514
 */
 
515
NS_IMETHODIMP
 
516
nsImageMac::UnlockImagePixels(PRBool aMaskPixels)
 
517
{
 
518
  // nothing to do
 
519
  return NS_OK;
 
520
}
 
521
 
 
522
#pragma mark -
 
523
 
 
524
/*
 
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.
 
528
  
 
529
  We only bother caching the device for 24-bit GWorlds. This method returns nsnull
 
530
  for other depths.
 
531
*/
 
532
GDHandle nsImageMac::GetCachedGDeviceForDepth(PRInt32 aDepth)
 
533
{
 
534
  if (aDepth == 24)
 
535
  {
 
536
    static GWorldPtr s24BitDeviceGWorld = nsnull;
 
537
    
 
538
    if (!s24BitDeviceGWorld)
 
539
    {
 
540
      Rect  bounds = { 0, 0, 16, 16 };
 
541
      ::NewGWorld(&s24BitDeviceGWorld, aDepth, &bounds, nsnull, nsnull, 0);
 
542
      if (!s24BitDeviceGWorld) return nsnull;
 
543
    }
 
544
    return ::GetGWorldDevice(s24BitDeviceGWorld);
 
545
  }
 
546
  
 
547
  return nsnull;
 
548
}
 
549
 
 
550
/** -----------------------------------------------------------------
 
551
 *  Create a PixMap, filling in ioPixMap
 
552
 */
 
553
OSErr nsImageMac::CreateGWorld( PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,
 
554
                GWorldPtr* outGWorld, char** outBits, PRInt32* outRowBytes)
 
555
{
 
556
    return CreateGWorldInternal(aWidth, aHeight, aDepth, outGWorld, outBits, outRowBytes, PR_FALSE);
 
557
}
 
558
 
 
559
 
 
560
/** -----------------------------------------------------------------
 
561
 *  Create a PixMap, filling in ioPixMap
 
562
 *  Call the CreatePixMap wrapper instead.
 
563
 */
 
564
OSErr nsImageMac::CreateGWorldInternal(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, 
 
565
                GWorldPtr* outGWorld, char** outBits, PRInt32* outRowBytes, PRBool aAllow2Bytes)
 
566
{
 
567
  OSErr   err = noErr;
 
568
  
 
569
  
 
570
  PRInt32 bitsPerPixel = 0;
 
571
  CTabHandle  colorTable;
 
572
  PRUint32 pixelFormat = GetPixelFormatForDepth(aDepth, bitsPerPixel, &colorTable);
 
573
 
 
574
  if (pixelFormat != 0)
 
575
  {
 
576
    PRInt32   rowBytes = CalculateRowBytesInternal(aWidth, bitsPerPixel, aAllow2Bytes);
 
577
    PRInt32   imageSize = rowBytes * aHeight;
 
578
 
 
579
    char*     imageBits = (char*)calloc(imageSize, 1);
 
580
    if (!imageBits)
 
581
      return memFullErr;
 
582
 
 
583
    Rect imageRect = {0, 0, 0, 0};
 
584
    imageRect.right = aWidth;
 
585
    imageRect.bottom = aHeight;
 
586
    
 
587
    GDHandle    deviceHandle = GetCachedGDeviceForDepth(aDepth);
 
588
    GWorldFlags flags = deviceHandle ? noNewDevice : 0;
 
589
    
 
590
    GWorldPtr imageGWorld;
 
591
    err = ::NewGWorldFromPtr(&imageGWorld, pixelFormat, &imageRect, colorTable, deviceHandle, flags, (Ptr)imageBits, rowBytes);
 
592
    if (err != noErr)
 
593
    {
 
594
      NS_ASSERTION(0, "NewGWorldFromPtr failed");
 
595
      return err;
 
596
    }
 
597
    
 
598
    *outGWorld = imageGWorld;
 
599
    *outBits = imageBits;
 
600
    *outRowBytes = rowBytes;
 
601
  } 
 
602
 
 
603
  return noErr;
 
604
}
 
605
 
 
606
 
 
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.
 
615
 *
 
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 
 
620
 *  wrapped.
 
621
 *
 
622
 *  See <http://developer.apple.com/technotes/qd/qd_15.html>
 
623
 */
 
624
PRInt32 nsImageMac::CalculateRowBytesInternal(PRUint32 aWidth, PRUint32 aDepth, PRBool aAllow2Bytes)
 
625
{
 
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;
 
631
}
 
632
 
 
633
/** Protected CalculateRowBytes. Most functions should call this
 
634
    Requires rowBytes to be a multiple of 4
 
635
    @see CalculateRowBytesInternal
 
636
  */
 
637
PRInt32 nsImageMac::CalculateRowBytes(PRUint32 aWidth, PRUint32 aDepth)
 
638
{
 
639
    return CalculateRowBytesInternal(aWidth, aDepth, PR_FALSE);
 
640
}
 
641
 
 
642
 
 
643
PRUint32 nsImageMac::GetPixelFormatForDepth(PRInt32 inDepth, PRInt32& outBitsPerPixel, CTabHandle* outDefaultColorTable)
 
644
{
 
645
  PRUint32 pixelFormat = 0;
 
646
  PRInt32  bitsPerPixel;
 
647
  
 
648
  if (outDefaultColorTable)
 
649
      *outDefaultColorTable = nsnull;
 
650
 
 
651
  // See IM:QuickDraw pp 4-92 for GetCTable params
 
652
  switch (inDepth)
 
653
  {
 
654
    case 1:
 
655
      if (outDefaultColorTable)
 
656
        *outDefaultColorTable = ::GetCTable(32 + 1);
 
657
      bitsPerPixel = 1;
 
658
      pixelFormat = k1MonochromePixelFormat;
 
659
      break;
 
660
 
 
661
    case 2:
 
662
      if (outDefaultColorTable)
 
663
        *outDefaultColorTable = ::GetCTable(32 + 2);
 
664
      bitsPerPixel = 2;
 
665
      pixelFormat = k2IndexedPixelFormat;
 
666
      break;
 
667
      
 
668
    case 4:
 
669
      if (outDefaultColorTable)
 
670
        *outDefaultColorTable = ::GetCTable(32 + 4);
 
671
      bitsPerPixel = 4;
 
672
      pixelFormat = k4IndexedPixelFormat;
 
673
      break;
 
674
      
 
675
    case 8:
 
676
      if (outDefaultColorTable)
 
677
        *outDefaultColorTable = ::GetCTable(32 + 8);
 
678
      bitsPerPixel = 8;
 
679
      pixelFormat = k8IndexedPixelFormat;
 
680
      break;
 
681
      
 
682
    case 16:
 
683
      bitsPerPixel = 16;
 
684
      pixelFormat = k16BE555PixelFormat;
 
685
      break;
 
686
      
 
687
    case 24:
 
688
      // 24-bit images are 8 bits per component; the alpha component is ignored
 
689
      bitsPerPixel = 32;
 
690
      pixelFormat = k32ARGBPixelFormat;
 
691
      break;
 
692
 
 
693
    case 32:
 
694
      bitsPerPixel = 32;
 
695
      pixelFormat = k32ARGBPixelFormat;
 
696
      break;
 
697
      
 
698
    default:
 
699
      NS_ASSERTION(0, "Unhandled image depth");
 
700
  }
 
701
  
 
702
  outBitsPerPixel = bitsPerPixel;
 
703
  return pixelFormat;
 
704
}
 
705
 
 
706
#pragma mark -
 
707
 
 
708
/** ---------------------------------------------------
 
709
 *  Erase the GWorld contents
 
710
 */
 
711
void nsImageMac::ClearGWorld(GWorldPtr theGWorld)
 
712
{
 
713
  PixMapHandle  thePixels = ::GetGWorldPixMap(theGWorld);
 
714
 
 
715
  StPixelLocker pixelLocker(thePixels);
 
716
  StGWorldPortSetter  tilingWorldSetter(theGWorld); 
 
717
  
 
718
  // White the offscreen
 
719
  ::BackColor(whiteColor);
 
720
 
 
721
  Rect portRect;
 
722
  ::GetPortBounds(theGWorld, &portRect);
 
723
  ::EraseRect(&portRect);
 
724
}
 
725
 
 
726
/** -----------------------------------------------------------------
 
727
 *  Allocate a GWorld
 
728
 */
 
729
OSErr nsImageMac::AllocateGWorld(PRInt16 depth, CTabHandle colorTable,
 
730
                                 const Rect& bounds, GWorldPtr *outGWorld)
 
731
{
 
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);
 
735
  if (!newGWorld)
 
736
    return memFullErr;
 
737
 
 
738
  *outGWorld = newGWorld;
 
739
  return noErr;
 
740
}
 
741
 
 
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)
 
746
{
 
747
  if (maskBits)
 
748
  {
 
749
    StRegionFromPool    origClipRegion;
 
750
    
 
751
    if (inDrawingToPort)
 
752
    {
 
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);
 
756
      
 
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.
 
761
      
 
762
      StRegionFromPool newClip;
 
763
      ::RectRgn(newClip, &destRect);
 
764
      ::SectRgn(newClip, origClipRegion, newClip);
 
765
      ::SetClip(newClip);
 
766
    }
 
767
 
 
768
    ::CopyDeepMask(srcBits, maskBits, destBits, &srcRect, &maskRect,
 
769
                   &destRect, ditherCopy, nsnull);
 
770
 
 
771
    if (inDrawingToPort)
 
772
    {
 
773
      ::SetClip(origClipRegion);
 
774
    }    
 
775
  }
 
776
  else
 
777
  {
 
778
    ::CopyBits(srcBits, destBits, &srcRect, &destRect, ditherCopy, nsnull);
 
779
  }
 
780
}
 
781
 
 
782
 
 
783
PRBool nsImageMac::RenderingToPrinter(nsIRenderingContext &aContext)
 
784
{
 
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();
 
790
}
 
791
 
 
792
 
 
793
 
 
794
#pragma mark -
 
795
 
 
796
 
 
797
//
 
798
// ConvertToPICT
 
799
//
 
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.
 
804
//
 
805
NS_IMETHODIMP
 
806
nsImageMac::ConvertToPICT(PicHandle* outPicture)
 
807
{
 
808
  *outPicture = nsnull;
 
809
 
 
810
  Rect picFrame  = {0, 0, mHeight, mWidth};
 
811
  Rect maskFrame = {0, 0, mHeight, mWidth};
 
812
  GWorldPtr tempGWorld;
 
813
 
 
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;
 
818
 
 
819
  // erase it to white
 
820
  ClearGWorld(tempGWorld);
 
821
 
 
822
  PixMapHandle tempPixMap = ::GetGWorldPixMap(tempGWorld);
 
823
  if (tempPixMap)
 
824
  {
 
825
    StPixelLocker tempPixLocker(tempPixMap);      // locks the pixels
 
826
  
 
827
    // now copy into the picture
 
828
    GWorldPtr currPort;
 
829
    GDHandle currDev;
 
830
    ::GetGWorld(&currPort, &currDev);
 
831
    ::SetGWorld(tempGWorld, nsnull);
 
832
 
 
833
    ::SetOrigin(0, 0);
 
834
    ::ForeColor(blackColor);
 
835
    ::BackColor(whiteColor);
 
836
 
 
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);
 
841
 
 
842
    PicHandle thePicture = ::OpenPicture(&picFrame);
 
843
    OSErr err = noErr;
 
844
    if (thePicture)
 
845
    {
 
846
      ::CopyBits(::GetPortBitMapForCopyBits(tempGWorld), ::GetPortBitMapForCopyBits(tempGWorld),
 
847
                   &picFrame, &picFrame, ditherCopy, nsnull);
 
848
    
 
849
      ::ClosePicture();
 
850
      err = QDError();
 
851
    }
 
852
    
 
853
    ::SetGWorld(currPort, currDev);     // restore to the way things were
 
854
    
 
855
    if ( err == noErr )       
 
856
      *outPicture = thePicture;
 
857
  }
 
858
 
 
859
  ::DisposeGWorld(tempGWorld);        // do this after dtor of tempPixLocker!
 
860
  
 
861
  return NS_OK;
 
862
} // ConvertToPICT
 
863
 
 
864
 
 
865
NS_IMETHODIMP
 
866
nsImageMac::ConvertFromPICT(PicHandle inPicture)
 
867
{
 
868
  return NS_ERROR_FAILURE;
 
869
 
 
870
} // ConvertFromPICT
 
871
 
 
872
NS_IMETHODIMP
 
873
nsImageMac::GetGWorldPtr(GWorldPtr* aGWorld)
 
874
{
 
875
  *aGWorld = mImageGWorld;
 
876
  return NS_OK;
 
877
}
 
878
 
 
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. 
 
882
    See <Icons.h>
 
883
    The caller of the function owns the memory allocated for the resulting icon.
 
884
 
 
885
    The "type" of the icon is implicit in the size and depth and mask 
 
886
    parameters, 
 
887
    e.g.
 
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)
 
891
    
 
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.
 
894
 
 
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.
 
897
 
 
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.
 
907
*/
 
908
    
 
909
    
 
910
 
 
911
NS_IMETHODIMP
 
912
nsImageMac::ConvertToIcon(  const nsRect& aSrcRegion, 
 
913
                            const PRInt16 aIconDepth, 
 
914
                            const PRInt16 aIconSize,
 
915
                            Handle* aOutIcon,
 
916
                            OSType* aOutIconType) 
 
917
{
 
918
 
 
919
    NS_ENSURE_ARG_POINTER(aOutIcon);
 
920
    NS_ENSURE_ARG_POINTER(aOutIconType);    
 
921
    *aOutIcon = nsnull;
 
922
    *aOutIconType = nsnull;
 
923
    
 
924
    if (aIconDepth != 1 && aIconDepth != 2  && aIconDepth != 4 && 
 
925
        aIconDepth != 8 && aIconDepth != 24 && aIconDepth != 32)
 
926
      return NS_ERROR_INVALID_ARG;
 
927
    
 
928
    //returns null if there size specified isn't a valid size for an icon
 
929
    OSType iconType = MakeIconType(aIconSize, aIconDepth, PR_FALSE);
 
930
    if (iconType == nil)
 
931
        return NS_ERROR_INVALID_ARG;
 
932
 
 
933
    *aOutIconType = iconType;
 
934
    
 
935
    Rect   srcRect;
 
936
    srcRect.top = aSrcRegion.y;
 
937
    srcRect.left = aSrcRegion.x;
 
938
    srcRect.bottom = aSrcRegion.y + aSrcRegion.height;
 
939
    srcRect.right = aSrcRegion.x + aSrcRegion.width;
 
940
 
 
941
    Rect  iconRect = { 0, 0, aIconSize, aIconSize};
 
942
    return CopyPixMap(srcRect, iconRect, aIconDepth, 
 
943
                                  PR_FALSE, aOutIcon, PR_TRUE);     
 
944
} // ConvertToIcon
 
945
 
 
946
 
 
947
/** Create an Icon mask from a specified region of the the alpha channel 
 
948
    in this image.
 
949
    The caller owns the memory allocated for the mask.
 
950
    
 
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.
 
955
    
 
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)
 
959
    
 
960
    size 16 -> s8mk, size 32 -> l8mk, size 48 -> h8mk. 
 
961
    (no mini 8 bit masks exist)
 
962
    
 
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.
 
966
    
 
967
    'XXX#' resources (icm#, ics#, ICN# or ich#) contain a 1 bit icon of the 
 
968
    indicated
 
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.
 
972
    
 
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 
 
978
    <Icons.h>
 
979
    
 
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)
 
982
    
 
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.
 
993
    
 
994
    
 
995
*/    
 
996
NS_IMETHODIMP
 
997
nsImageMac::ConvertAlphaToIconMask(  const nsRect& aSrcRegion, 
 
998
                                     const PRInt16 aMaskDepth, 
 
999
                                     const PRInt16 aMaskSize,
 
1000
                                     Handle* aOutMask,
 
1001
                                     OSType* aOutIconType) 
 
1002
{                            
 
1003
    Handle          dstHandle = nsnull;
 
1004
    Rect            srcRect;
 
1005
    nsresult        result;      
 
1006
    Rect            maskRect = { 0, 0, aMaskSize, aMaskSize};
 
1007
    
 
1008
    srcRect.top = aSrcRegion.y;
 
1009
    srcRect.left = aSrcRegion.x;
 
1010
    srcRect.bottom = aSrcRegion.y + aSrcRegion.height;
 
1011
    srcRect.right = aSrcRegion.x + aSrcRegion.width;
 
1012
    
 
1013
    NS_ENSURE_ARG_POINTER(aOutMask);
 
1014
    NS_ENSURE_ARG_POINTER(aOutIconType);
 
1015
    *aOutMask = nsnull;
 
1016
    *aOutIconType = nsnull;
 
1017
    
 
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;
 
1022
    } 
 
1023
    *aOutIconType = iconType;
 
1024
    
 
1025
    if (mMaskGWorld)
 
1026
    {
 
1027
        //image has an alpha channel, copy into icon mask
 
1028
    
 
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)
 
1032
        {
 
1033
            //for 8 bit masks, this is sufficient
 
1034
            result = CopyPixMap(srcRect, maskRect, aMaskDepth, 
 
1035
                                        PR_TRUE, &dstHandle, PR_TRUE); 
 
1036
        }
 
1037
        else if (aMaskDepth == 1)
 
1038
        {
 
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);
 
1044
                                    
 
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);
 
1052
                }
 
1053
            }
 
1054
 
 
1055
            if (iconHandle) ::DisposeHandle(iconHandle);
 
1056
            if (maskHandle) ::DisposeHandle(maskHandle);    
 
1057
        }
 
1058
        else
 
1059
        {
 
1060
            NS_ASSERTION(aMaskDepth, "Unregonised icon mask depth");
 
1061
            result = NS_ERROR_INVALID_ARG;
 
1062
        }
 
1063
    }
 
1064
    else
 
1065
    {
 
1066
        //image has no alpha channel, make an entirely black mask with the appropriate depth
 
1067
        if (aMaskDepth == 8)
 
1068
        {
 
1069
            //simply make the mask
 
1070
            result = MakeOpaqueMask(aMaskSize, aMaskSize, aMaskDepth, &dstHandle);            
 
1071
        }
 
1072
        else if (aMaskDepth == 1)
 
1073
        {
 
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);
 
1083
                }
 
1084
            }
 
1085
 
 
1086
            if (iconHandle) ::DisposeHandle(iconHandle);
 
1087
            if (maskHandle) ::DisposeHandle(maskHandle); 
 
1088
        
 
1089
        }
 
1090
        else
 
1091
        {
 
1092
            NS_ASSERTION(aMaskDepth, "Unregonised icon mask depth");
 
1093
            result = NS_ERROR_INVALID_ARG;
 
1094
        }
 
1095
    }
 
1096
 
 
1097
    if (NS_SUCCEEDED(result)) *aOutMask = dstHandle;
 
1098
    return result;
 
1099
} // ConvertAlphaToIconMask
 
1100
 
 
1101
#pragma mark -
 
1102
 
 
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.
 
1109
    
 
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    
 
1119
*/
 
1120
 
 
1121
/** Call CopyPixMap instead*/
 
1122
nsresult 
 
1123
nsImageMac::CopyPixMap(const Rect& aSrcRegion,
 
1124
                       const Rect& aDestRegion,
 
1125
                       const PRInt32 aDestDepth,
 
1126
                       const PRBool aCopyMaskBits,
 
1127
                       Handle *aDestData,
 
1128
                       PRBool aAllow2Bytes /* = PR_FALSE */
 
1129
                      ) 
 
1130
{
 
1131
    NS_ENSURE_ARG_POINTER(aDestData);
 
1132
    *aDestData = nsnull;
 
1133
 
 
1134
    PRInt32     copyMode;
 
1135
    CTabHandle  destColorTable = nsnull;
 
1136
    GWorldPtr   srcGWorld = nsnull;
 
1137
 
 
1138
    //are we copying the image data or the mask
 
1139
    if (aCopyMaskBits)
 
1140
    {
 
1141
        if (!mMaskGWorld)
 
1142
            return NS_ERROR_INVALID_ARG;
 
1143
 
 
1144
        srcGWorld = mMaskGWorld;        
 
1145
        copyMode = srcCopy;
 
1146
        if (aDestDepth <= 8)
 
1147
            destColorTable = GetCTable(32 + aDestDepth);
 
1148
    }
 
1149
    else
 
1150
    {
 
1151
        if (!mImageGWorld)
 
1152
            return NS_ERROR_INVALID_ARG;
 
1153
 
 
1154
        srcGWorld = mImageGWorld;        
 
1155
        copyMode = ditherCopy;
 
1156
        if (aDestDepth <= 8)
 
1157
            destColorTable = GetCTable(64 + aDestDepth);
 
1158
    }
 
1159
 
 
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;
 
1163
    
 
1164
    Handle resultData = ::NewHandleClear(destSize);
 
1165
    if (!resultData) return NS_ERROR_OUT_OF_MEMORY;
 
1166
 
 
1167
    PRInt32  bitsPerPixel;
 
1168
    PRUint32 pixelFormat = GetPixelFormatForDepth(aDestDepth, bitsPerPixel);
 
1169
 
 
1170
    { // lock scope
 
1171
        StHandleLocker destBitsLocker(resultData);
 
1172
 
 
1173
        GWorldPtr destGWorld = nsnull;
 
1174
        OSErr err = ::NewGWorldFromPtr(&destGWorld, pixelFormat, &aDestRegion, destColorTable, nsnull, 0, *resultData, destRowBytes);
 
1175
        if (err != noErr)
 
1176
        {
 
1177
            NS_ASSERTION(0, "NewGWorldFromPtr failed in nsImageMac::CopyPixMap");
 
1178
            return NS_ERROR_FAILURE;
 
1179
        }
 
1180
        
 
1181
        ::CopyBits( ::GetPortBitMapForCopyBits(srcGWorld),
 
1182
                    ::GetPortBitMapForCopyBits(destGWorld),
 
1183
                    &aSrcRegion, &aDestRegion, 
 
1184
                    copyMode, nsnull);
 
1185
 
 
1186
        // do I need to free the color table explicitly?
 
1187
        ::DisposeGWorld(destGWorld);
 
1188
    }
 
1189
    
 
1190
    *aDestData = resultData;
 
1191
    return NS_OK;
 
1192
 
 
1193
} //CopyPixMap
 
1194
 
 
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
 
1202
        a copy of aSrcData2
 
1203
    @return nsresult an error code
 
1204
*/
 
1205
nsresult 
 
1206
nsImageMac::ConcatBitsHandles( Handle aSrcData1, 
 
1207
                               Handle aSrcData2,
 
1208
                               Handle *aDstData)
 
1209
{
 
1210
    NS_ENSURE_ARG_POINTER(aDstData);
 
1211
    *aDstData = nsnull;
 
1212
 
 
1213
    Handle result = aSrcData1;    
 
1214
 
 
1215
    // clone the first handle
 
1216
    OSErr err = ::HandToHand(&result);
 
1217
    if (err != noErr) return NS_ERROR_OUT_OF_MEMORY;
 
1218
    
 
1219
    // then append the second
 
1220
    err = ::HandAndHand(result, aSrcData2);
 
1221
    if (err != noErr)
 
1222
    {
 
1223
      ::DisposeHandle(result);
 
1224
      return NS_ERROR_OUT_OF_MEMORY;
 
1225
    }
 
1226
    
 
1227
    *aDstData = result;
 
1228
    return NS_OK;
 
1229
} // ConcatBitsHandles
 
1230
 
 
1231
 
 
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
 
1238
*/
 
1239
nsresult 
 
1240
nsImageMac::MakeOpaqueMask(    const PRInt32 aWidth,
 
1241
                               const PRInt32 aHeight,
 
1242
                               const PRInt32 aDepth,
 
1243
                               Handle *aMask)
 
1244
{
 
1245
    NS_ENSURE_ARG_POINTER(aMask);
 
1246
    aMask = nsnull;    
 
1247
 
 
1248
    //mask size =  (width * height * depth)
 
1249
    PRInt32 size = aHeight * CalculateRowBytesInternal(aWidth, aDepth, PR_TRUE);
 
1250
    
 
1251
    Handle resultData = ::NewHandle(size);
 
1252
    if (!resultData)
 
1253
        return NS_ERROR_OUT_OF_MEMORY;
 
1254
 
 
1255
    StHandleLocker dstLocker(resultData);
 
1256
    memset(*resultData, 0xFF, size);
 
1257
    *aMask = resultData;
 
1258
    return NS_OK;
 
1259
} // MakeOpaqueMask
 
1260
 
 
1261
 
 
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)
 
1267
      16x16 - small 
 
1268
      32x32 - large
 
1269
      48x48 - huge
 
1270
      128x128 - thumbnail
 
1271
    
 
1272
    Exact mapping table (see note above about 1 bit masks being generally inseperable from 1 bit icons)
 
1273
    
 
1274
    Icon
 
1275
        depth height  width   type
 
1276
        1     32      32      ICON    (one bit icon without mask)
 
1277
        4     12      16      icm4      
 
1278
        4     16      16      ics4
 
1279
        4     32      32      icl4
 
1280
        4     48      48      ich4
 
1281
        8     12      16      icm8
 
1282
        8     16      16      ics8  
 
1283
        8     32      32      icl8
 
1284
        8     48      48      ich8
 
1285
        32    16      16      is32
 
1286
        32    32      32      il32
 
1287
        32    48      48      ih32
 
1288
        32    128     128     it32
 
1289
    Mask
 
1290
        1     16      12      icm#
 
1291
        1     16      16      ics#
 
1292
        1     32      32      ICN#    (one bit icon and mask - you probably want one of these, not an 'ICON')
 
1293
        1     48      48      ich#
 
1294
        8     16      16      s8mk
 
1295
        8     32      32      l8mk
 
1296
        8     48      48      h8mk
 
1297
        8     16      12      t8mk
 
1298
    
 
1299
    16 and 24 bit depths will be promoted to 32 bit.
 
1300
    Any other combination not in the above table gives nil
 
1301
          
 
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
 
1306
  */      
 
1307
OSType
 
1308
nsImageMac::MakeIconType(PRInt32 aHeight, PRInt32 aDepth, PRBool aMask) 
 
1309
{
 
1310
    switch(aHeight) {
 
1311
      case 12:
 
1312
        switch(aDepth) {
 
1313
          case 1:
 
1314
            return 'icm#';
 
1315
          case 4:
 
1316
            return 'icm4';
 
1317
          case 8:
 
1318
            return 'icm8';
 
1319
          default:
 
1320
            return nil;          
 
1321
        }
 
1322
      case 16:
 
1323
        switch(aDepth) {
 
1324
          case 1:
 
1325
            return 'ics#';
 
1326
          case 4:
 
1327
            return 'ics4';
 
1328
          case 8:
 
1329
            if(aMask)
 
1330
              return 's8mk';
 
1331
            else
 
1332
              return 'ics8';
 
1333
          case 16:
 
1334
          case 24:
 
1335
          case 32:
 
1336
            return 'is32';
 
1337
          default:
 
1338
            return nil;           
 
1339
        }
 
1340
      case 32:
 
1341
        switch(aDepth) {
 
1342
          case 1:
 
1343
            if(aMask)
 
1344
              return 'ICN#';
 
1345
            else
 
1346
              return 'ICON';
 
1347
          case 4:
 
1348
            return 'icl4';
 
1349
          case 8:
 
1350
            if(aMask)
 
1351
              return 'l8mk';
 
1352
            else
 
1353
              return 'icl8';
 
1354
          case 16:
 
1355
          case 24:
 
1356
          case 32:
 
1357
            return 'il32'; 
 
1358
          default:
 
1359
            return nil;           
 
1360
        }
 
1361
      case 48:
 
1362
        switch(aDepth) {
 
1363
          case 1:
 
1364
            return 'ich#';
 
1365
          case 4:
 
1366
            return 'ich4';
 
1367
          case 8:
 
1368
            if(aMask)
 
1369
              return 'h8mk';
 
1370
            else
 
1371
              return 'ich8';
 
1372
          case 16:
 
1373
          case 24:
 
1374
          case 32:
 
1375
            return 'ih32';            
 
1376
          default:
 
1377
            return nil;
 
1378
        }
 
1379
      case 128:
 
1380
        if(aMask)
 
1381
          return 't8mk';
 
1382
        else
 
1383
          switch (aDepth) {
 
1384
            case 16:
 
1385
            case 24:
 
1386
            case 32:
 
1387
              return 'it32';
 
1388
            default:
 
1389
              return nil;
 
1390
          }                  
 
1391
      default:
 
1392
        return nil;
 
1393
    } //switch(aHeight)
 
1394
}
 
1395
 
 
1396
nsresult nsImageMac::SlowTile(nsIRenderingContext &aContext,
 
1397
                                   nsDrawingSurface aSurface,
 
1398
                                   PRInt32 aSXOffset, PRInt32 aSYOffset,
 
1399
                                   PRInt32 aPadX, PRInt32 aPadY,
 
1400
                                   const nsRect &aTileRect)
 
1401
{
 
1402
  if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
 
1403
    return NS_OK;
 
1404
 
 
1405
  PRInt32
 
1406
    validX = 0,
 
1407
    validY = 0,
 
1408
    validWidth  = mWidth,
 
1409
    validHeight = mHeight;
 
1410
  
 
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;
 
1415
  }
 
1416
  if (mDecodedX2 < mWidth) {
 
1417
    validWidth = mDecodedX2 - mDecodedX1;
 
1418
  }
 
1419
  if (mDecodedY1 > 0) {   
 
1420
    validHeight -= mDecodedY1;
 
1421
    validY = mDecodedY1;
 
1422
  }
 
1423
  if (mDecodedX1 > 0) {
 
1424
    validWidth -= mDecodedX1;
 
1425
    validX = mDecodedX1; 
 
1426
  }
 
1427
 
 
1428
  PRInt32 aY0 = aTileRect.y - aSYOffset,
 
1429
          aX0 = aTileRect.x - aSXOffset,
 
1430
          aY1 = aTileRect.y + aTileRect.height,
 
1431
          aX1 = aTileRect.x + aTileRect.width;
 
1432
 
 
1433
  for (PRInt32 y = aY0; y < aY1; y += mHeight + aPadY)
 
1434
    for (PRInt32 x = aX0; x < aX1; x += mWidth + aPadX)
 
1435
    {
 
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
 
1439
    }
 
1440
 
 
1441
  return NS_OK;
 
1442
}
 
1443
 
 
1444
 
 
1445
 
 
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.
 
1451
//
 
1452
// This code is not called for printing (because all the CopyDeepMask stuff doesn't
 
1453
// work when printing).
 
1454
 
 
1455
nsresult nsImageMac::DrawTileQuickly(nsIRenderingContext &aContext,
 
1456
                                   nsDrawingSurface aSurface,
 
1457
                                   PRInt32 aSXOffset, PRInt32 aSYOffset,
 
1458
                                   const nsRect &aTileRect)
 
1459
{
 
1460
  if (!mImageGWorld)
 
1461
    return NS_ERROR_FAILURE;
 
1462
 
 
1463
  // lock and set up bits handles
 
1464
  Rect  imageRect;
 
1465
  imageRect.left = 0;
 
1466
  imageRect.top = 0;
 
1467
  imageRect.right = mWidth;
 
1468
  imageRect.bottom = mHeight;
 
1469
 
 
1470
  // get the destination pix map
 
1471
  nsDrawingSurfaceMac* destSurface = static_cast<nsDrawingSurfaceMac*>(aSurface);
 
1472
  
 
1473
  CGrafPtr    destPort;
 
1474
  nsresult    rv = destSurface->GetGrafPtr(&destPort);
 
1475
  if (NS_FAILED(rv)) return rv;
 
1476
  
 
1477
  StPortSetter    destSetter(destPort);
 
1478
  ::ForeColor(blackColor);
 
1479
  ::BackColor(whiteColor);
 
1480
  
 
1481
  PixMapHandle    destPixels = ::GetGWorldPixMap(destPort);
 
1482
  StPixelLocker   destPixLocker(destPixels);
 
1483
  
 
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;
 
1487
  
 
1488
  PRInt32 tilingBoundsWidth   = aSXOffset + aTileRect.width;
 
1489
  PRInt32 tilingBoundsHeight  = aSYOffset + aTileRect.height;
 
1490
 
 
1491
  PRInt32 tiledRows = (tilingBoundsHeight + mHeight - 1) / mHeight;   // round up
 
1492
  PRInt32 tiledCols = (tilingBoundsWidth + mWidth - 1) / mWidth;      // round up
 
1493
 
 
1494
  PRInt32 numTiles = tiledRows * tiledCols;
 
1495
  if (numTiles <= kTilingCopyThreshold)
 
1496
  {
 
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;
 
1502
 
 
1503
    for (PRInt32 y = topY; y < bottomY; y += mHeight)
 
1504
    {
 
1505
      for (PRInt32 x = leftX; x < rightX; x += mWidth)
 
1506
      {
 
1507
        Rect    imageDestRect = imageRect;
 
1508
        Rect    imageSrcRect  = imageRect;
 
1509
        ::OffsetRect(&imageDestRect, x, y);
 
1510
 
 
1511
        if (x > rightX - mWidth) {
 
1512
          imageDestRect.right = PR_MIN(imageDestRect.right, rightX);
 
1513
          imageSrcRect.right = imageRect.left + (imageDestRect.right - imageDestRect.left);
 
1514
        }
 
1515
        
 
1516
        if (y > bottomY - mHeight) {
 
1517
          imageDestRect.bottom = PR_MIN(imageDestRect.bottom, bottomY);
 
1518
          imageSrcRect.bottom = imageRect.top + (imageDestRect.bottom - imageDestRect.top);
 
1519
        }
 
1520
        
 
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);
 
1525
      }
 
1526
    }
 
1527
  
 
1528
    return NS_OK;
 
1529
  }
 
1530
 
 
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;
 
1536
 
 
1537
  Rect  tileRect = tileDestRect;
 
1538
  ::OffsetRect(&tileRect, -tileRect.left, -tileRect.top);   // offset to {0, 0}
 
1539
 
 
1540
  PRInt16 pixelDepth = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
 
1541
 
 
1542
  GWorldPtr   tilingGWorld = nsnull;
 
1543
  OSErr err = AllocateGWorld(pixelDepth, nsnull, tileRect, &tilingGWorld);
 
1544
  if (err != noErr) return NS_ERROR_OUT_OF_MEMORY;
 
1545
  
 
1546
  GWorldPtr   maskingGWorld = nsnull;
 
1547
  if (mMaskGWorld)
 
1548
  {
 
1549
    err = AllocateGWorld(pixelDepth, nsnull, tileRect, &maskingGWorld);
 
1550
    if (err != noErr) {
 
1551
      ::DisposeGWorld(tilingGWorld);
 
1552
      return NS_ERROR_OUT_OF_MEMORY;
 
1553
    }
 
1554
    
 
1555
    ClearGWorld(maskingGWorld);
 
1556
  }  
 
1557
  
 
1558
  PixMapHandle    tilingPixels = ::GetGWorldPixMap(tilingGWorld);
 
1559
  PixMapHandle    maskingPixels = (maskingGWorld) ? ::GetGWorldPixMap(maskingGWorld) : nsnull;
 
1560
 
 
1561
  {   // scope for locks
 
1562
    StPixelLocker   tempPixLocker(tilingPixels);
 
1563
    StPixelLocker   tempMaskLocker(maskingPixels);   // OK will null pixels
 
1564
 
 
1565
    const BitMap* destBitMap    = ::GetPortBitMapForCopyBits(destPort);
 
1566
 
 
1567
    const BitMap* imageBitmap   = ::GetPortBitMapForCopyBits(mImageGWorld);
 
1568
    const BitMap* maskBitMap    = mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull;
 
1569
 
 
1570
    const BitMap* tilingBitMap  = ::GetPortBitMapForCopyBits(tilingGWorld);
 
1571
    const BitMap* maskingBitMap = maskingGWorld ? ::GetPortBitMapForCopyBits(maskingGWorld) : nsnull;
 
1572
 
 
1573
    
 
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.
 
1579
 
 
1580
/*
 
1581
 
 
1582
     +---------+
 
1583
     |         |
 
1584
     | X |  Y  |
 
1585
     |         |
 
1586
     | - +-------------------------+
 
1587
     | Z |  W  | Z |               |
 
1588
     +---|-----+---          |     |
 
1589
         |     |   |    1          |
 
1590
         |  Y  | X |         |     |
 
1591
         |     |   |               |
 
1592
         |---------+ - - - - +   3 |
 
1593
         |                         |
 
1594
         |                   |     |
 
1595
         |         2               |
 
1596
         |                   |     |
 
1597
         |                         |
 
1598
         | - - - - - - - - - + - - |
 
1599
         |                         |
 
1600
         |            4            |
 
1601
         |                         |
 
1602
         +-------------------------+
 
1603
 
 
1604
*/
 
1605
    
 
1606
    Rect    tilePartRect = imageRect;
 
1607
 
 
1608
    // top left of offset tile (W)
 
1609
    Rect    offsetTileSrc = tilePartRect;
 
1610
    offsetTileSrc.left  = aSXOffset;
 
1611
    offsetTileSrc.top   = aSYOffset;
 
1612
 
 
1613
    Rect    offsetTileDest = {0};
 
1614
    offsetTileDest.right  = tilePartRect.right - aSXOffset;
 
1615
    offsetTileDest.bottom = tilePartRect.bottom - aSYOffset;
 
1616
    
 
1617
    ::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
 
1618
    if (maskBitMap)
 
1619
      ::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
 
1620
 
 
1621
    // top right of offset tile (Z)
 
1622
    if (aSXOffset > 0)
 
1623
    {
 
1624
      offsetTileSrc = tilePartRect;
 
1625
      offsetTileSrc.right = aSXOffset;
 
1626
      offsetTileSrc.top   = aSYOffset;
 
1627
      
 
1628
      offsetTileDest = tilePartRect;
 
1629
      offsetTileDest.left   = tilePartRect.right - aSXOffset;
 
1630
      offsetTileDest.bottom = tilePartRect.bottom - aSYOffset;
 
1631
 
 
1632
      ::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
 
1633
      if (maskBitMap)
 
1634
        ::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);    
 
1635
    }
 
1636
    
 
1637
    if (aSYOffset > 0)
 
1638
    {
 
1639
      // bottom left of offset tile (Y)
 
1640
      offsetTileSrc = tilePartRect;
 
1641
      offsetTileSrc.left    = aSXOffset;
 
1642
      offsetTileSrc.bottom  = aSYOffset;
 
1643
      
 
1644
      offsetTileDest = tilePartRect;
 
1645
      offsetTileDest.right  = tilePartRect.right - aSXOffset;
 
1646
      offsetTileDest.top    = tilePartRect.bottom - aSYOffset;
 
1647
 
 
1648
      ::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
 
1649
      if (maskBitMap)
 
1650
        ::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);      
 
1651
    }
 
1652
    
 
1653
    if (aSXOffset > 0 && aSYOffset > 0)
 
1654
    {
 
1655
      // bottom right of offset tile (X)
 
1656
      offsetTileSrc = tilePartRect;
 
1657
      offsetTileSrc.right   = aSXOffset;
 
1658
      offsetTileSrc.bottom  = aSYOffset;
 
1659
      
 
1660
      offsetTileDest = tilePartRect;
 
1661
      offsetTileDest.left   = tilePartRect.right - aSXOffset;
 
1662
      offsetTileDest.top    = tilePartRect.bottom - aSYOffset;
 
1663
 
 
1664
      ::CopyBits(imageBitmap, tilingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
 
1665
      if (maskBitMap)
 
1666
        ::CopyBits(maskBitMap, maskingBitMap, &offsetTileSrc, &offsetTileDest, srcCopy, nsnull);
 
1667
    }
 
1668
 
 
1669
    // now double up this tile to cover the area
 
1670
    PRBool doneWidth = PR_FALSE, doneHeight = PR_FALSE;
 
1671
    
 
1672
    Rect srcRect, dstRect;
 
1673
    PRInt32 tileWidth  = mWidth;
 
1674
    PRInt32 tileHeight = mHeight;
 
1675
    while (!doneWidth || !doneHeight)
 
1676
    {
 
1677
      if (tileWidth < tileRect.right)
 
1678
      {
 
1679
        srcRect.left = 0; srcRect.top = 0;
 
1680
        srcRect.bottom = tileHeight; srcRect.right = tileWidth;
 
1681
 
 
1682
        dstRect.left = tileWidth; dstRect.top = 0;
 
1683
        dstRect.bottom = tileHeight; dstRect.right = tileWidth + tileWidth;
 
1684
        
 
1685
        ::CopyBits(tilingBitMap, tilingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
 
1686
        if (maskingPixels)
 
1687
          ::CopyBits(maskingBitMap, maskingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
 
1688
 
 
1689
        tileWidth *= 2;
 
1690
      }
 
1691
      else
 
1692
        doneWidth = PR_TRUE;
 
1693
    
 
1694
      if (tileHeight < tileRect.bottom)
 
1695
      {
 
1696
        srcRect.left = 0; srcRect.top = 0;
 
1697
        srcRect.bottom = tileHeight; srcRect.right = tileWidth;
 
1698
 
 
1699
        dstRect.left = 0; dstRect.top = tileHeight;
 
1700
        dstRect.bottom = tileHeight + tileHeight; dstRect.right = tileWidth;
 
1701
        
 
1702
        ::CopyBits(tilingBitMap, tilingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
 
1703
        if (maskingPixels)
 
1704
          ::CopyBits(maskingBitMap, maskingBitMap, &srcRect, &dstRect, srcCopy, nsnull);
 
1705
      
 
1706
        tileHeight *= 2;
 
1707
      }
 
1708
      else
 
1709
        doneHeight = PR_TRUE;
 
1710
    }
 
1711
    
 
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.
 
1714
    
 
1715
    // finally, copy to the destination
 
1716
    CopyBitsWithMask(tilingBitMap,
 
1717
        maskingBitMap ? maskingBitMap : nsnull, mAlphaDepth,
 
1718
        destBitMap, tileRect, tileRect, tileDestRect, PR_TRUE);
 
1719
 
 
1720
  } // scope for locks
 
1721
 
 
1722
  // clean up  
 
1723
  ::DisposeGWorld(tilingGWorld);
 
1724
  if (maskingGWorld)
 
1725
    ::DisposeGWorld(maskingGWorld);
 
1726
 
 
1727
  return NS_OK;
 
1728
}
 
1729
 
 
1730
 
 
1731
NS_IMETHODIMP nsImageMac::DrawTile(nsIRenderingContext &aContext,
 
1732
                                   nsDrawingSurface aSurface,
 
1733
                                   PRInt32 aSXOffset, PRInt32 aSYOffset,
 
1734
                                   PRInt32 aPadX, PRInt32 aPadY,
 
1735
                                   const nsRect &aTileRect)
 
1736
{
 
1737
  nsresult rv = NS_ERROR_FAILURE;
 
1738
  PRBool padded = (aPadX || aPadY);
 
1739
  
 
1740
  if (!RenderingToPrinter(aContext) && !padded)
 
1741
    rv = DrawTileQuickly(aContext, aSurface, aSXOffset, aSYOffset, aTileRect);
 
1742
 
 
1743
  if (NS_FAILED(rv))
 
1744
    rv = SlowTile(aContext, aSurface, aSXOffset, aSYOffset, aPadX, aPadY, aTileRect);
 
1745
    
 
1746
  return rv;
 
1747
}