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

« back to all changes in this revision

Viewing changes to mozilla/gfx/src/xlib/nsImageXlib.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
 *   Peter Hartshorn <peter@igelaus.com.au>
 
24
 *   Stuart Parmenter <pavlov@netscape.com>
 
25
 *   Tim Rowley <tor@cs.brown.edu> -- 8bit alpha compositing
 
26
 *
 
27
 *
 
28
 * Alternatively, the contents of this file may be used under the terms of
 
29
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
30
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
31
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
32
 * of those above. If you wish to allow use of your version of this file only
 
33
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
34
 * use your version of this file under the terms of the NPL, indicate your
 
35
 * decision by deleting the provisions above and replace them with the notice
 
36
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
37
 * the provisions above, a recipient may use your version of this file under
 
38
 * the terms of any one of the NPL, the GPL or the LGPL.
 
39
 *
 
40
 * ***** END LICENSE BLOCK ***** */
 
41
 
 
42
#include "nsImageXlib.h"
 
43
#include "nsDrawingSurfaceXlib.h"
 
44
#include "nsRenderingContextXlib.h"
 
45
#include "xlibrgb.h"
 
46
#include "prlog.h"
 
47
#include "nsRect.h"
 
48
#include "drawers.h"
 
49
#include "imgScaler.h"
 
50
 
 
51
#define IsFlagSet(a,b) ((a) & (b))
 
52
 
 
53
#ifdef PR_LOGGING 
 
54
static PRLogModuleInfo *ImageXlibLM = PR_NewLogModule("ImageXlib");
 
55
#endif /* PR_LOGGING */ 
 
56
 
 
57
/* XXX we are simply creating a GC and setting its function to Copy.
 
58
   we shouldn't be doing this every time this method is called.  this creates
 
59
   way more trips to the server than we should be doing so we are creating a
 
60
   static one.
 
61
*/
 
62
static GC s1bitGC = 0;
 
63
static GC sXbitGC = 0;
 
64
 
 
65
XlibRgbHandle *nsImageXlib::mXlibRgbHandle = nsnull;
 
66
Display       *nsImageXlib::mDisplay       = nsnull;
 
67
 
 
68
nsImageXlib::nsImageXlib()
 
69
: mImageBits(nsnull)
 
70
, mAlphaBits(nsnull)
 
71
, mWidth(0)
 
72
, mHeight(0)
 
73
, mDepth(0)
 
74
, mRowBytes(0)
 
75
, mSizeImage(0)
 
76
, mNumBytesPixel(0)
 
77
, mImagePixmap(nsnull)
 
78
, mAlphaPixmap(nsnull)
 
79
, mAlphaDepth(0)
 
80
, mAlphaRowBytes(0)
 
81
, mAlphaValid(PR_FALSE)
 
82
, mIsSpacer(PR_TRUE)
 
83
, mGC(nsnull)
 
84
, mPendingUpdate(PR_FALSE)
 
85
, mDecodedX1(PR_INT32_MAX)
 
86
, mDecodedY1(PR_INT32_MAX)
 
87
, mDecodedX2(0)
 
88
, mDecodedY2(0)
 
89
{
 
90
  PR_LOG(ImageXlibLM, PR_LOG_DEBUG, ("nsImageXlib::nsImageXlib()\n"));
 
91
 
 
92
  if (!mXlibRgbHandle) {
 
93
    mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
 
94
    mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
 
95
  }  
 
96
  
 
97
  if (!mXlibRgbHandle || !mDisplay)
 
98
    abort();
 
99
}
 
100
 
 
101
nsImageXlib::~nsImageXlib()
 
102
{
 
103
  PR_LOG(ImageXlibLM, PR_LOG_DEBUG,("nsImageXlib::nsImageXlib()\n"));
 
104
  if (nsnull != mImageBits) {
 
105
    delete[] mImageBits;
 
106
    mImageBits = nsnull;
 
107
  }
 
108
  if (nsnull != mAlphaBits) {
 
109
    delete[] mAlphaBits;
 
110
    mAlphaBits = nsnull;
 
111
 
 
112
    if (mAlphaPixmap != nsnull) 
 
113
    {
 
114
      // The display cant be null.  It gets fetched from the drawing 
 
115
      // surface used to create the pixmap.  It gets assigned once
 
116
      // in Draw()
 
117
      NS_ASSERTION(nsnull != mDisplay,"display is null.");
 
118
 
 
119
#ifdef XLIB_PIXMAP_DEBUG
 
120
      printf("XFreePixmap(display = %p)\n",mDisplay);
 
121
#endif
 
122
 
 
123
      XFreePixmap(mDisplay, mAlphaPixmap);
 
124
 
 
125
    }
 
126
  }
 
127
 
 
128
  if (mImagePixmap != 0) 
 
129
  {
 
130
    NS_ASSERTION(nsnull != mDisplay,"display is null.");
 
131
 
 
132
#ifdef XLIB_PIXMAP_DEBUG
 
133
    printf("XFreePixmap(display = %p)\n",mDisplay);
 
134
#endif
 
135
 
 
136
    XFreePixmap(mDisplay, mImagePixmap);
 
137
  }
 
138
 
 
139
  if(mGC)
 
140
  {
 
141
    XFreeGC(mDisplay, mGC);
 
142
    mGC=nsnull;
 
143
  }
 
144
  if(sXbitGC && mDisplay) // Sometimes mDisplay is null, let orhers free
 
145
  {
 
146
    XFreeGC(mDisplay, sXbitGC);
 
147
    sXbitGC=nsnull;
 
148
  }
 
149
  if(s1bitGC && mDisplay) // Sometimes mDisplay is null, let orhers free
 
150
  {
 
151
    XFreeGC(mDisplay, s1bitGC);
 
152
    s1bitGC=nsnull;
 
153
  }
 
154
  
 
155
}
 
156
 
 
157
NS_IMPL_ISUPPORTS1(nsImageXlib, nsIImage)
 
158
 
 
159
nsresult nsImageXlib::Init(PRInt32 aWidth, PRInt32 aHeight,
 
160
                           PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
 
161
{
 
162
  // gfxImageFrame makes sure nsImageXlib::Init gets called only once
 
163
  if ((aWidth == 0) || (aHeight == 0))
 
164
    return NS_ERROR_FAILURE;
 
165
 
 
166
  if (24 == aDepth) {
 
167
    mNumBytesPixel = 3;
 
168
  } else {
 
169
    NS_ASSERTION(PR_FALSE, "unexpected image depth");
 
170
    return NS_ERROR_UNEXPECTED;
 
171
  }
 
172
 
 
173
  mWidth = aWidth;
 
174
  mHeight = aHeight;
 
175
  mDepth = aDepth;
 
176
 
 
177
  // Create the memory for the image
 
178
  ComputeMetrics();
 
179
 
 
180
  mImageBits = (PRUint8*)new PRUint8[mSizeImage];
 
181
 
 
182
  switch(aMaskRequirements) {
 
183
    case nsMaskRequirements_kNeeds1Bit:
 
184
      mAlphaRowBytes = (aWidth  + 7) / 8;
 
185
      mAlphaDepth = 1;
 
186
 
 
187
      // 32-bit align each row
 
188
      mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
 
189
 
 
190
      mAlphaBits = new unsigned char[mAlphaRowBytes * aHeight];
 
191
      break;
 
192
 
 
193
    case nsMaskRequirements_kNeeds8Bit:
 
194
      mAlphaRowBytes = aWidth;
 
195
      mAlphaDepth = 8;
 
196
 
 
197
      // 32-bit align each row
 
198
      mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
 
199
      mAlphaBits = new unsigned char[mAlphaRowBytes * aHeight];
 
200
      break;
 
201
 
 
202
    default:
 
203
      break; // avoid compiler warning
 
204
  }
 
205
  return NS_OK;
 
206
}
 
207
 
 
208
//---------------------------------------------------------------------
 
209
 
 
210
PRInt32 nsImageXlib::GetHeight()
 
211
{
 
212
  return mHeight;
 
213
}
 
214
 
 
215
PRInt32 nsImageXlib::GetWidth()
 
216
{
 
217
  return mWidth;
 
218
}
 
219
 
 
220
PRUint8 *nsImageXlib::GetBits()
 
221
{
 
222
  return mImageBits;
 
223
}
 
224
 
 
225
void *nsImageXlib::GetBitInfo()
 
226
{
 
227
  return nsnull;
 
228
}
 
229
 
 
230
PRInt32 nsImageXlib::GetLineStride()
 
231
{
 
232
  return mRowBytes;
 
233
}
 
234
 
 
235
nsColorMap *nsImageXlib::GetColorMap()
 
236
{
 
237
  return nsnull;
 
238
}
 
239
 
 
240
PRUint8 *nsImageXlib::GetAlphaBits()
 
241
{
 
242
  return mAlphaBits;
 
243
}
 
244
 
 
245
PRInt32 nsImageXlib::GetAlphaLineStride()
 
246
{
 
247
  return mAlphaRowBytes;
 
248
}
 
249
 
 
250
//-----------------------------------------------------------------------
 
251
 
 
252
// Set up the palette to the passed in color array, RGB only in this array
 
253
void nsImageXlib::ImageUpdated(nsIDeviceContext *aContext,
 
254
                               PRUint8 aFlags,
 
255
                               nsRect *aUpdateRect)
 
256
{
 
257
  mPendingUpdate = PR_TRUE;
 
258
  mUpdateRegion.Or(mUpdateRegion, *aUpdateRect);
 
259
 
 
260
  mDecodedX1 = PR_MIN(mDecodedX1, aUpdateRect->x);
 
261
  mDecodedY1 = PR_MIN(mDecodedY1, aUpdateRect->y);
 
262
 
 
263
  if (aUpdateRect->YMost() > mDecodedY2)
 
264
    mDecodedY2 = aUpdateRect->YMost();
 
265
  if (aUpdateRect->XMost() > mDecodedX2)
 
266
    mDecodedX2 = aUpdateRect->XMost();
 
267
}
 
268
 
 
269
void nsImageXlib::UpdateCachedImage()
 
270
{
 
271
  nsRegionRectIterator ri(mUpdateRegion);
 
272
  const nsRect *rect;
 
273
 
 
274
  while (rect = ri.Next()) {
 
275
 
 
276
//  fprintf(stderr, "ImageUpdated %p x,y=(%d %d) width,height=(%d %d)\n",
 
277
//          this, rect->x, rect->y, rect->width, rect->height);
 
278
 
 
279
    unsigned bottom, left, right;
 
280
    bottom = rect->y + rect->height;
 
281
    left   = rect->x;
 
282
    right  = left + rect->width;
 
283
 
 
284
    // check if the image has an all-opaque 8-bit alpha mask
 
285
    if ((mAlphaDepth==8) && !mAlphaValid) {
 
286
      for (unsigned y=rect->y; (y<bottom) && !mAlphaValid; y++) {
 
287
        unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + left;
 
288
        for (unsigned x=left; x<right; x++) {
 
289
          if (*(alpha++)!=255) {
 
290
            mAlphaValid=PR_TRUE;
 
291
            break;
 
292
          }
 
293
        }
 
294
      }
 
295
    }
 
296
 
 
297
    // check if the image is a spacer
 
298
    if ((mAlphaDepth==1) && mIsSpacer) {
 
299
      // mask of the leading/trailing bits in the update region
 
300
      PRUint8  leftmask   = 0xff  >> (left & 0x7);
 
301
      PRUint8  rightmask  = 0xff  << (7 - ((right-1) & 0x7));
 
302
 
 
303
      // byte where the first/last bits of the update region are located
 
304
      PRUint32 leftindex  = left      >> 3;
 
305
      PRUint32 rightindex = (right-1) >> 3;
 
306
 
 
307
      // first/last bits in the same byte - combine mask into leftmask
 
308
      // and fill rightmask so we don't try using it
 
309
      if (leftindex == rightindex) {
 
310
        leftmask &= rightmask;
 
311
        rightmask = 0xff;
 
312
      }
 
313
 
 
314
      // check the leading bits
 
315
      if (leftmask != 0xff) {
 
316
        PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + leftindex;
 
317
        for (unsigned y=rect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
 
318
          if (*ptr & leftmask) {
 
319
            mIsSpacer = PR_FALSE;
 
320
            break;
 
321
          }
 
322
        }
 
323
        // move to first full byte
 
324
        leftindex++;
 
325
      }
 
326
 
 
327
      // check the trailing bits
 
328
      if (mIsSpacer && (rightmask != 0xff)) {
 
329
        PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + rightindex;
 
330
        for (unsigned y=rect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
 
331
          if (*ptr & rightmask) {
 
332
            mIsSpacer = PR_FALSE;
 
333
            break;
 
334
          }
 
335
        }
 
336
        // move to last full byte
 
337
        rightindex--;
 
338
      }
 
339
    
 
340
      // check the middle bytes
 
341
      if (mIsSpacer && (leftindex <= rightindex)) {
 
342
        for (unsigned y=rect->y; (y<bottom) && mIsSpacer; y++) {
 
343
          unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + leftindex;
 
344
          for (unsigned x=left; x<right; x++) {
 
345
            if (*(alpha++)!=0) {
 
346
              mIsSpacer = PR_FALSE;
 
347
              break;
 
348
            }
 
349
          }
 
350
        }
 
351
      }
 
352
    }
 
353
 
 
354
    if (mAlphaValid && mImagePixmap) {
 
355
      XFreePixmap(mDisplay, mImagePixmap);
 
356
      mImagePixmap = 0;
 
357
    }
 
358
    
 
359
    if (!mAlphaValid) {
 
360
      CreateOffscreenPixmap(mWidth, mHeight);
 
361
 
 
362
      if (!sXbitGC) {
 
363
        XGCValues gcv;
 
364
        memset(&gcv, 0, sizeof(XGCValues));
 
365
        gcv.function = GXcopy;
 
366
        sXbitGC  = XCreateGC(mDisplay, mImagePixmap, GCFunction, &gcv);
 
367
      }
 
368
      xxlib_draw_rgb_image_dithalign(
 
369
                     mXlibRgbHandle,
 
370
                     mImagePixmap, sXbitGC,
 
371
                     rect->x, rect->y,
 
372
                     rect->width, rect->height,
 
373
                     XLIB_RGB_DITHER_MAX,
 
374
                     mImageBits + mRowBytes * rect->y + 3 * rect->x,
 
375
                     mRowBytes,
 
376
                     rect->x, rect->y);
 
377
    }
 
378
  }
 
379
 
 
380
  mUpdateRegion.SetEmpty();
 
381
  mPendingUpdate = PR_FALSE;
 
382
  mFlags = nsImageUpdateFlags_kBitsChanged; // this should be 0'd out by Draw()
 
383
}
 
384
 
 
385
NS_IMETHODIMP
 
386
nsImageXlib::DrawScaled(nsIRenderingContext &aContext,
 
387
                        nsDrawingSurface aSurface,
 
388
                        PRInt32 aSX, PRInt32 aSY,
 
389
                        PRInt32 aSWidth, PRInt32 aSHeight,
 
390
                        PRInt32 aDX, PRInt32 aDY,
 
391
                        PRInt32 aDWidth, PRInt32 aDHeight)
 
392
{
 
393
 
 
394
  PRInt32 origSHeight = aSHeight, origDHeight = aDHeight;
 
395
  PRInt32 origSWidth = aSWidth, origDWidth = aDWidth;
 
396
 
 
397
  if (aSWidth < 0 || aDWidth < 0 || aSHeight < 0 || aDHeight < 0)
 
398
    return NS_ERROR_FAILURE;
 
399
 
 
400
  if (0 == aSWidth || 0 == aDWidth || 0 == aSHeight || 0 == aDHeight)
 
401
    return NS_OK;
 
402
 
 
403
  if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
 
404
    return NS_OK;
 
405
 
 
406
  // limit the size of the blit to the amount of the image read in
 
407
  if (aSX + aSWidth > mDecodedX2) {
 
408
    aDWidth -= ((aSX + aSWidth - mDecodedX2)*origDWidth)/origSWidth;
 
409
    aSWidth -= (aSX + aSWidth) - mDecodedX2;
 
410
  }
 
411
  if (aSX < mDecodedX1) {
 
412
    aDX += ((mDecodedX1 - aSX)*origDWidth)/origSWidth;
 
413
    aSX = mDecodedX1;
 
414
  }
 
415
 
 
416
  if (aSY + aSHeight > mDecodedY2) {
 
417
    aDHeight -= ((aSY + aSHeight - mDecodedY2)*origDHeight)/origSHeight;
 
418
    aSHeight -= (aSY + aSHeight) - mDecodedY2;
 
419
    }
 
420
  if (aSY < mDecodedY1) {
 
421
    aDY += ((mDecodedY1 - aSY)*origDHeight)/origSHeight;
 
422
    aSY = mDecodedY1;
 
423
  }
 
424
 
 
425
  if ((aDWidth <= 0 || aDHeight <= 0) || (aSWidth <= 0 || aSHeight <= 0))
 
426
    return NS_OK;
 
427
 
 
428
  nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
 
429
 
 
430
  if (mAlphaDepth == 1)
 
431
    CreateAlphaBitmap(mWidth, mHeight);
 
432
 
 
433
  if ((mAlphaDepth == 8) && mAlphaValid) {
 
434
    DrawComposited(aContext, aSurface,
 
435
        aSX, aSY, aSWidth, aSHeight,
 
436
        aDX, aDY, aDWidth, aDHeight);
 
437
    return NS_OK;
 
438
  }
 
439
 
 
440
#ifdef HAVE_XIE
 
441
  /* XIE seriosly loses scaling images with alpha */
 
442
  if (!mAlphaDepth) {
 
443
    /* Draw with XIE */
 
444
    PRBool succeeded = PR_FALSE;
 
445
 
 
446
    xGC *xiegc = ((nsRenderingContextXlib&)aContext).GetGC();
 
447
    Drawable drawable; drawing->GetDrawable(drawable);
 
448
    succeeded = DrawScaledImageXIE(mDisplay, drawable,
 
449
                                   *xiegc,
 
450
                                   mImagePixmap,
 
451
                                   mWidth, mHeight,
 
452
                                   aSX, aSY,
 
453
                                   aSWidth, aSHeight,
 
454
                                   aDX, aDY,
 
455
                                   aDWidth, aDHeight);
 
456
    xiegc->Release();
 
457
    if (succeeded)
 
458
      return NS_OK;
 
459
  }
 
460
#endif
 
461
 
 
462
  /* the good scaling way, right from GTK */
 
463
  GC gc = 0;
 
464
  Pixmap pixmap = 0;
 
465
 
 
466
  if (mAlphaDepth==1) {
 
467
    PRUint32 scaledRowBytes = (aDWidth+7)>>3;   // round to next byte
 
468
    PRUint8 *scaledAlpha = (PRUint8 *)nsMemory::Alloc(aDHeight*scaledRowBytes);
 
469
    
 
470
    // code below attempts to draw the image without the mask if mask
 
471
    // creation fails for some reason.  thus no easy-out "return"
 
472
    if (scaledAlpha) {
 
473
      memset(scaledAlpha, 0, aDHeight*scaledRowBytes);
 
474
      RectStretch(mWidth, mHeight, origDWidth, origDHeight,
 
475
                  aDX, aDY, aDX + aDWidth - 1, aDY + aDHeight - 1,
 
476
                  mAlphaBits, mAlphaRowBytes, scaledAlpha, scaledRowBytes, 1);
 
477
 
 
478
      pixmap = XCreatePixmap(mDisplay, DefaultRootWindow(mDisplay),
 
479
                             aDWidth, aDHeight, 1);
 
480
      XImage *ximage = 0;
 
481
      
 
482
      if (pixmap) {
 
483
        ximage = XCreateImage(mDisplay, xxlib_rgb_get_visual(mXlibRgbHandle),
 
484
                              1, XYPixmap, 0, (char *)scaledAlpha,
 
485
                              aDWidth, aDHeight,
 
486
                              8, scaledRowBytes);
 
487
      }
 
488
      if (ximage) {
 
489
        ximage->bits_per_pixel=1;
 
490
        ximage->bitmap_bit_order=MSBFirst;
 
491
        ximage->byte_order = MSBFirst;
 
492
 
 
493
        GC tmpGC;
 
494
        XGCValues gcv;
 
495
        memset(&gcv, 0, sizeof(XGCValues));
 
496
        gcv.function = GXcopy;
 
497
        tmpGC = XCreateGC(mDisplay, pixmap, GCFunction, &gcv);
 
498
        if (tmpGC) {
 
499
          XPutImage(mDisplay, pixmap, tmpGC, ximage,
 
500
                    0, 0, 0, 0, aDWidth, aDHeight);
 
501
          XFreeGC(mDisplay, tmpGC);
 
502
        } else {
 
503
          // can't write into the clip mask - destroy so we don't use it
 
504
          if (pixmap)
 
505
             XFreePixmap(mDisplay, pixmap);
 
506
          pixmap = 0;
 
507
        }
 
508
 
 
509
        ximage->data = 0;
 
510
        XDestroyImage(ximage);
 
511
      }
 
512
      nsMemory::Free(scaledAlpha);
 
513
    }
 
514
  }
 
515
 
 
516
  xGC *imageGC = nsnull;
 
517
 
 
518
  if (pixmap) {
 
519
    XGCValues values;
 
520
 
 
521
    memset(&values, 0, sizeof(XGCValues));
 
522
    values.clip_x_origin = aDX;
 
523
    values.clip_y_origin = aDY;
 
524
    values.clip_mask = pixmap;
 
525
    Drawable drawable; drawing->GetDrawable(drawable);
 
526
    gc = XCreateGC(mDisplay, drawable,
 
527
                   GCClipXOrigin | GCClipYOrigin | GCClipMask,
 
528
                   &values);
 
529
  } else {
 
530
    imageGC = ((nsRenderingContextXlib&)aContext).GetGC();
 
531
    gc = *imageGC;
 
532
  }
 
533
 
 
534
  PRUint8 *scaledRGB = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
 
535
  if (scaledRGB && gc) {
 
536
    RectStretch(mWidth, mHeight, origDWidth, origDHeight,
 
537
                aDX, aDY, aDX + aDWidth - 1, aDY + aDHeight - 1,
 
538
                mImageBits, mRowBytes, scaledRGB, 3*aDWidth, 24);
 
539
 
 
540
    Drawable drawable; drawing->GetDrawable(drawable);
 
541
    xxlib_draw_rgb_image(mXlibRgbHandle, drawable, gc,
 
542
                         aDX, aDY, aDWidth, aDHeight,
 
543
                         XLIB_RGB_DITHER_MAX,
 
544
                         scaledRGB, 3*aDWidth);
 
545
    nsMemory::Free(scaledRGB);
 
546
  }
 
547
 
 
548
  if (imageGC)
 
549
    imageGC->Release();
 
550
  else
 
551
    if (gc)
 
552
      XFreeGC(mDisplay, gc);
 
553
  if (pixmap)
 
554
    XFreePixmap(mDisplay, pixmap);
 
555
 
 
556
  mFlags = 0;
 
557
 
 
558
  return NS_OK;
 
559
}
 
560
 
 
561
// Draw the bitmap, this method has a source and destination coordinates
 
562
NS_IMETHODIMP
 
563
nsImageXlib::Draw(nsIRenderingContext &aContext, nsDrawingSurface aSurface,
 
564
                  PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
 
565
                  PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
 
566
{
 
567
  if (aSurface == nsnull)
 
568
    return NS_ERROR_FAILURE;
 
569
 
 
570
  if (mPendingUpdate)
 
571
    UpdateCachedImage();
 
572
 
 
573
  if ((mAlphaDepth == 1) && mIsSpacer)
 
574
    return NS_OK;
 
575
 
 
576
  if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
 
577
    return NS_OK;
 
578
 
 
579
  if (aSWidth != aDWidth || aSHeight != aDHeight) {
 
580
    return DrawScaled(aContext, aSurface, aSX, aSY, aSWidth, aSHeight,
 
581
                      aDX, aDY, aDWidth, aDHeight);
 
582
  }
 
583
 
 
584
  if (aSWidth <= 0 || aDWidth <= 0 || aSHeight <= 0 || aDHeight <= 0) {
 
585
    NS_ASSERTION(aSWidth > 0 && aDWidth > 0 && aSHeight > 0 && aDHeight > 0,
 
586
                 "You can't draw an image with a 0 width or height!");
 
587
    return NS_OK;
 
588
  }
 
589
 
 
590
  // limit the size of the blit to the amount of the image read in
 
591
  PRInt32 j = aSX + aSWidth;
 
592
  PRInt32 z;
 
593
  if (j > mDecodedX2) {
 
594
    z = j - mDecodedX2;
 
595
    aDWidth -= z;
 
596
    aSWidth -= z;
 
597
  }
 
598
  if (aSX < mDecodedX1) {
 
599
    aDX += mDecodedX1 - aSX;
 
600
    aSX = mDecodedX1;
 
601
  }
 
602
 
 
603
  j = aSY + aSHeight;
 
604
  if (j > mDecodedY2) {
 
605
    z = j - mDecodedY2;
 
606
    aDHeight -= z;
 
607
    aSHeight -= z;
 
608
  }
 
609
  if (aSY < mDecodedY1) {
 
610
    aDY += mDecodedY1 - aSY;
 
611
    aSY = mDecodedY1;
 
612
  }
 
613
 
 
614
  if (aDWidth <= 0 || aDHeight <= 0 || aSWidth <= 0 || aSHeight <= 0)
 
615
    return NS_OK;
 
616
 
 
617
  if ((mAlphaDepth == 8) && mAlphaValid) {
 
618
    DrawComposited(aContext, aSurface,
 
619
        aSX, aSY, aSWidth, aSHeight,
 
620
        aDX, aDY, aSWidth, aSHeight);
 
621
    return NS_OK;
 
622
  }
 
623
 
 
624
  nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
 
625
 
 
626
  if (mAlphaDepth == 1)
 
627
    CreateAlphaBitmap(mWidth, mHeight);
 
628
 
 
629
  GC copyGC;
 
630
  xGC *gc = ((nsRenderingContextXlib&)aContext).GetGC();
 
631
 
 
632
  if (mAlphaPixmap) {
 
633
    if (mGC) {                /* reuse GC */
 
634
      copyGC = mGC;
 
635
      SetupGCForAlpha(copyGC, aDX - aSX, aDY - aSY);
 
636
    } else {                  /* make a new one */
 
637
      /* this repeats things done in SetupGCForAlpha */
 
638
      XGCValues xvalues;
 
639
      memset(&xvalues, 0, sizeof(XGCValues));
 
640
      unsigned long xvalues_mask = 0;
 
641
      xvalues.clip_x_origin = aDX - aSX;
 
642
      xvalues.clip_y_origin = aDY - aSY;
 
643
      if (IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
 
644
        xvalues_mask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
 
645
        xvalues.clip_mask = mAlphaPixmap;
 
646
      }
 
647
      Drawable drawable; drawing->GetDrawable(drawable);
 
648
      mGC = XCreateGC(mDisplay, drawable, xvalues_mask , &xvalues);
 
649
      copyGC = mGC;
 
650
    }
 
651
  } else {  /* !mAlphaPixmap */
 
652
    copyGC = *gc;
 
653
  }
 
654
 
 
655
  Drawable drawable; drawing->GetDrawable(drawable);
 
656
  XCopyArea(mDisplay, mImagePixmap, drawable,
 
657
        copyGC, aSX, aSY, aSWidth, aSHeight, aDX, aDY);
 
658
 
 
659
  gc->Release();
 
660
  mFlags = 0;
 
661
  return NS_OK;
 
662
}
 
663
 
 
664
// -----------------------------------------------------------------
 
665
// 8-bit alpha composite drawing
 
666
 
 
667
static unsigned
 
668
findIndex32(unsigned mask)
 
669
{
 
670
  switch (mask)
 
671
  {
 
672
    case 0xff:
 
673
      return 3;
 
674
    case 0xff00:
 
675
      return 2;
 
676
    case 0xff0000:
 
677
      return 1;
 
678
    default:
 
679
      return 0;
 
680
  }
 
681
}
 
682
 
 
683
static unsigned
 
684
findIndex24(unsigned mask)
 
685
{
 
686
  switch(mask)
 
687
  {
 
688
    case 0xff:
 
689
      return 2;
 
690
    case 0xff00:
 
691
      return 1;
 
692
    default:
 
693
      return 0;
 
694
  }
 
695
}
 
696
 
 
697
 
 
698
// 32-bit (888) truecolor convert/composite function
 
699
void nsImageXlib::DrawComposited32(PRBool isLSB, PRBool flipBytes,
 
700
                                   PRUint8 *imageOrigin, PRUint32 imageStride,
 
701
                                   PRUint8 *alphaOrigin, PRUint32 alphaStride,
 
702
                                   unsigned width, unsigned height,
 
703
                                   XImage *ximage, unsigned char *readData)
 
704
{
 
705
  Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
 
706
  unsigned redIndex   = findIndex32(visual->red_mask);
 
707
  unsigned greenIndex = findIndex32(visual->green_mask);
 
708
  unsigned blueIndex  = findIndex32(visual->blue_mask);
 
709
 
 
710
  if (flipBytes^isLSB)
 
711
  {
 
712
    redIndex   = 3-redIndex;
 
713
    greenIndex = 3-greenIndex;
 
714
    blueIndex  = 3-blueIndex;
 
715
  }
 
716
 
 
717
  for (unsigned y=0; y<height; y++)
 
718
  {
 
719
    unsigned char *baseRow   = (unsigned char *)ximage->data
 
720
                                            +y*ximage->bytes_per_line;
 
721
    unsigned char *targetRow = readData     +3*(y*ximage->width);
 
722
    unsigned char *imageRow  = imageOrigin  +y*imageStride;
 
723
    unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
 
724
 
 
725
    for (unsigned i=0; i<width;
 
726
         i++, baseRow+=4, targetRow+=3, imageRow+=3, alphaRow++)
 
727
    {
 
728
      unsigned alpha = *alphaRow;
 
729
      MOZ_BLEND(targetRow[0], baseRow[redIndex],   imageRow[0], alpha);
 
730
      MOZ_BLEND(targetRow[1], baseRow[greenIndex], imageRow[1], alpha);
 
731
      MOZ_BLEND(targetRow[2], baseRow[blueIndex],  imageRow[2], alpha);
 
732
    }
 
733
  }
 
734
}
 
735
 
 
736
// 24-bit (888) truecolor convert/composite function
 
737
void
 
738
nsImageXlib::DrawComposited24(PRBool isLSB, PRBool flipBytes,
 
739
                             PRUint8 *imageOrigin, PRUint32 imageStride,
 
740
                             PRUint8 *alphaOrigin, PRUint32 alphaStride,
 
741
                             unsigned width, unsigned height,
 
742
                             XImage *ximage, unsigned char *readData)
 
743
{
 
744
  Visual *visual      = xxlib_rgb_get_visual(mXlibRgbHandle);
 
745
  unsigned redIndex   = findIndex24(visual->red_mask);
 
746
  unsigned greenIndex = findIndex24(visual->green_mask);
 
747
  unsigned blueIndex  = findIndex24(visual->blue_mask);
 
748
 
 
749
  if (flipBytes^isLSB) {
 
750
    redIndex   = 2-redIndex;
 
751
    greenIndex = 2-greenIndex;
 
752
    blueIndex  = 2-blueIndex;
 
753
  }
 
754
 
 
755
  for (unsigned y=0; y<height; y++) {
 
756
    unsigned char *baseRow   = (unsigned char *)ximage->data
 
757
                                            +y*ximage->bytes_per_line;
 
758
    unsigned char *targetRow = readData     +3*(y*ximage->width);
 
759
    unsigned char *imageRow  = imageOrigin  +y*imageStride;
 
760
    unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
 
761
 
 
762
    for (unsigned i=0; i<width;
 
763
         i++, baseRow+=3, targetRow+=3, imageRow+=3, alphaRow++) {
 
764
      unsigned alpha = *alphaRow;
 
765
      MOZ_BLEND(targetRow[0], baseRow[redIndex],   imageRow[0], alpha);
 
766
      MOZ_BLEND(targetRow[1], baseRow[greenIndex], imageRow[1], alpha);
 
767
      MOZ_BLEND(targetRow[2], baseRow[blueIndex],  imageRow[2], alpha);
 
768
    }
 
769
  }
 
770
}
 
771
 
 
772
unsigned nsImageXlib::scaled6[1<<6] = {
 
773
  3,   7,  11,  15,  19,  23,  27,  31,  35,  39,  43,  47,  51,  55,  59,  63,
 
774
 67,  71,  75,  79,  83,  87,  91,  95,  99, 103, 107, 111, 115, 119, 123, 127,
 
775
131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187, 191,
 
776
195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255
 
777
};
 
778
 
 
779
unsigned nsImageXlib::scaled5[1<<5] = {
 
780
  7,  15,  23,  31,  39,  47,  55,  63,  71,  79,  87,  95, 103, 111, 119, 127,
 
781
135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247, 255
 
782
};
 
783
 
 
784
// 16-bit ([56][56][56]) truecolor convert/composite function
 
785
void
 
786
nsImageXlib::DrawComposited16(PRBool isLSB, PRBool flipBytes,
 
787
                             PRUint8 *imageOrigin, PRUint32 imageStride,
 
788
                             PRUint8 *alphaOrigin, PRUint32 alphaStride,
 
789
                             unsigned width, unsigned height,
 
790
                             XImage *ximage, unsigned char *readData)
 
791
{
 
792
  Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
 
793
 
 
794
  unsigned *redScale   = (xxlib_get_prec_from_mask(visual->red_mask)   == 5)
 
795
                          ? scaled5 : scaled6;
 
796
  unsigned *greenScale = (xxlib_get_prec_from_mask(visual->green_mask) == 5)
 
797
                          ? scaled5 : scaled6;
 
798
  unsigned *blueScale  = (xxlib_get_prec_from_mask(visual->blue_mask)  == 5)
 
799
                          ? scaled5 : scaled6;
 
800
 
 
801
  unsigned long redShift   = xxlib_get_shift_from_mask(visual->red_mask);
 
802
  unsigned long greenShift = xxlib_get_shift_from_mask(visual->green_mask);
 
803
  unsigned long blueShift  = xxlib_get_shift_from_mask(visual->blue_mask);
 
804
 
 
805
  for (unsigned y=0; y<height; y++) {
 
806
    unsigned char *baseRow   = (unsigned char *)ximage->data
 
807
                                            +y*ximage->bytes_per_line;
 
808
    unsigned char *targetRow = readData     +3*(y*ximage->width);
 
809
    unsigned char *imageRow  = imageOrigin  +y*imageStride;
 
810
    unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
 
811
    for (unsigned i=0; i<width;
 
812
         i++, baseRow+=2, targetRow+=3, imageRow+=3, alphaRow++) {
 
813
      unsigned pix;
 
814
      if (flipBytes) {
 
815
        unsigned char tmp[2];
 
816
        tmp[0] = baseRow[1];
 
817
        tmp[1] = baseRow[0];
 
818
        pix = *((short *)tmp);
 
819
      } else
 
820
        pix = *((short *)baseRow);
 
821
      unsigned alpha = *alphaRow;
 
822
      MOZ_BLEND(targetRow[0],
 
823
                redScale[(pix&visual->red_mask) >> redShift], 
 
824
                imageRow[0], alpha);
 
825
      MOZ_BLEND(targetRow[1],
 
826
                greenScale[(pix&visual->green_mask) >> greenShift], 
 
827
                imageRow[1], alpha);
 
828
      MOZ_BLEND(targetRow[2],
 
829
                blueScale[(pix&visual->blue_mask) >> blueShift], 
 
830
                imageRow[2], alpha);
 
831
    }
 
832
  }
 
833
}
 
834
 
 
835
// Generic convert/composite function
 
836
void
 
837
nsImageXlib::DrawCompositedGeneral(PRBool isLSB, PRBool flipBytes,
 
838
                                  PRUint8 *imageOrigin, PRUint32 imageStride,
 
839
                                  PRUint8 *alphaOrigin, PRUint32 alphaStride,
 
840
                                  unsigned width, unsigned height,
 
841
                                  XImage *ximage, unsigned char *readData)
 
842
{
 
843
  Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
 
844
 
 
845
  unsigned char *target = readData;
 
846
 
 
847
  // flip bytes
 
848
  if (flipBytes && (ximage->bits_per_pixel>=16)) {
 
849
    for (int row=0; row<ximage->height; row++) {
 
850
      unsigned char *ptr =
 
851
        (unsigned char*)ximage->data + row*ximage->bytes_per_line;
 
852
      if (ximage->bits_per_pixel==24) {  // Aurgh....
 
853
        for (int col=0;
 
854
             col<ximage->bytes_per_line;
 
855
             col+=(ximage->bits_per_pixel/8)) {
 
856
          unsigned char tmp;
 
857
          tmp = *ptr;
 
858
          *ptr = *(ptr+2);
 
859
          *(ptr+2) = tmp;
 
860
          ptr+=3;
 
861
        }
 
862
        continue;
 
863
      }
 
864
 
 
865
      for (int col=0;
 
866
               col<ximage->bytes_per_line;
 
867
               col+=(ximage->bits_per_pixel/8)) {
 
868
        unsigned char tmp;
 
869
        switch (ximage->bits_per_pixel) {
 
870
        case 16:
 
871
          tmp = *ptr;
 
872
          *ptr = *(ptr+1);
 
873
          *(ptr+1) = tmp;
 
874
          ptr+=2;
 
875
          break;
 
876
        case 32:
 
877
          tmp = *ptr;
 
878
          *ptr = *(ptr+3);
 
879
          *(ptr+3) = tmp;
 
880
          tmp = *(ptr+1);
 
881
          *(ptr+1) = *(ptr+2);
 
882
          *(ptr+2) = tmp;
 
883
          ptr+=4;
 
884
          break;
 
885
        }
 
886
      }
 
887
    }
 
888
  }
 
889
 
 
890
  unsigned redScale   = 8 - xxlib_get_prec_from_mask(visual->red_mask);
 
891
  unsigned greenScale = 8 - xxlib_get_prec_from_mask(visual->green_mask);
 
892
  unsigned blueScale  = 8 - xxlib_get_prec_from_mask(visual->blue_mask);
 
893
  unsigned redFill    = 0xff >> xxlib_get_prec_from_mask(visual->red_mask);
 
894
  unsigned greenFill  = 0xff >> xxlib_get_prec_from_mask(visual->green_mask);
 
895
  unsigned blueFill   = 0xff >> xxlib_get_prec_from_mask(visual->blue_mask);
 
896
 
 
897
  unsigned long redShift   = xxlib_get_shift_from_mask(visual->red_mask);
 
898
  unsigned long greenShift = xxlib_get_shift_from_mask(visual->green_mask);
 
899
  unsigned long blueShift  = xxlib_get_shift_from_mask(visual->blue_mask);
 
900
 
 
901
  for (int row=0; row<ximage->height; row++) {
 
902
    unsigned char *ptr =
 
903
      (unsigned char *)ximage->data + row*ximage->bytes_per_line;
 
904
    for (int col=0; col<ximage->width; col++) {
 
905
      unsigned pix = 0;
 
906
      switch (ximage->bits_per_pixel) {
 
907
      case 1:
 
908
        pix = (*ptr>>(col%8))&1;
 
909
        if ((col%8)==7)
 
910
          ptr++;
 
911
        break;
 
912
      case 4:
 
913
        pix = (col&1)?(*ptr>>4):(*ptr&0xf);
 
914
        if (col&1)
 
915
          ptr++;
 
916
        break;
 
917
      case 8:
 
918
        pix = *ptr++;
 
919
        break;
 
920
      case 16:
 
921
        pix = *((short *)ptr);
 
922
        ptr+=2;
 
923
        break;
 
924
      case 24:
 
925
        if (isLSB)
 
926
          pix = (*(ptr+2)<<16) | (*(ptr+1)<<8) | *ptr;
 
927
        else
 
928
          pix = (*ptr<<16) | (*(ptr+1)<<8) | *(ptr+2);
 
929
        ptr+=3;
 
930
        break;
 
931
      case 32:
 
932
        pix = *((unsigned *)ptr);
 
933
        ptr+=4;
 
934
        break;
 
935
      }
 
936
 
 
937
      *target++ =
 
938
        redFill|((pix&visual->red_mask) >> redShift)<<redScale;
 
939
      *target++ =
 
940
        greenFill|((pix&visual->green_mask) >> greenShift)<<greenScale;
 
941
      *target++ =
 
942
        blueFill|((pix&visual->blue_mask) >> blueShift)<<blueScale;
 
943
    }
 
944
  }
 
945
 
 
946
  // now composite
 
947
  for (unsigned y=0; y<height; y++) {
 
948
    unsigned char *targetRow = readData+3*y*width;
 
949
    unsigned char *imageRow  = imageOrigin  +y*imageStride;
 
950
    unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
 
951
    for (unsigned i=0; i<width; i++) {
 
952
      unsigned alpha = alphaRow[i];
 
953
      MOZ_BLEND(targetRow[3*i],   targetRow[3*i],   imageRow[3*i],   alpha);
 
954
      MOZ_BLEND(targetRow[3*i+1], targetRow[3*i+1], imageRow[3*i+1], alpha);
 
955
      MOZ_BLEND(targetRow[3*i+2], targetRow[3*i+2], imageRow[3*i+2], alpha);
 
956
    }
 
957
  }
 
958
}
 
959
 
 
960
void
 
961
nsImageXlib::DrawComposited(nsIRenderingContext &aContext,
 
962
                            nsDrawingSurface aSurface,
 
963
                            PRInt32 aSX, PRInt32 aSY,
 
964
                            PRInt32 aSWidth, PRInt32 aSHeight,
 
965
                            PRInt32 aDX, PRInt32 aDY,
 
966
                            PRInt32 aDWidth, PRInt32 aDHeight)
 
967
{
 
968
  if ((aDWidth==0) || (aDHeight==0))
 
969
    return;
 
970
 
 
971
  nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
 
972
  Drawable drawable; drawing->GetDrawable(drawable);
 
973
  Visual  *visual   = xxlib_rgb_get_visual(mXlibRgbHandle);
 
974
 
 
975
  // I hate clipping... too!
 
976
  PRUint32 surfaceWidth, surfaceHeight;
 
977
  drawing->GetDimensions(&surfaceWidth, &surfaceHeight);
 
978
 
 
979
  int readX, readY;
 
980
  unsigned readWidth, readHeight, destX, destY;
 
981
 
 
982
  if ((aDY >= (int)surfaceHeight) || (aDX >= (int)surfaceWidth) ||
 
983
      (aDY + aDHeight <= 0) || (aDX + aDWidth <= 0)) {
 
984
    // This should never happen if the layout engine is sane,
 
985
    // as it means we're trying to draw an image which is outside
 
986
    // the drawing surface.  Bulletproof gfx for now...
 
987
    return;
 
988
  }
 
989
 
 
990
  if (aDX < 0) {
 
991
    readX = 0;   readWidth = aDWidth + aDX;    destX = aSX - aDX;
 
992
  } else {
 
993
    readX = aDX;  readWidth = aDWidth;       destX = aSX;
 
994
  }
 
995
  if (aDY < 0) {
 
996
    readY = 0;   readHeight = aDHeight + aDY;  destY = aSY - aDY;
 
997
  } else { 
 
998
    readY = aDY;  readHeight = aDHeight;     destY = aSY;
 
999
  }
 
1000
 
 
1001
  if (readX+readWidth > surfaceWidth)
 
1002
  readWidth = surfaceWidth-readX;                                             
 
1003
  if (readY+readHeight > surfaceHeight)
 
1004
    readHeight = surfaceHeight-readY;
 
1005
 
 
1006
  if ((readHeight <= 0) || (readWidth <= 0))
 
1007
    return;
 
1008
 
 
1009
  //  fprintf(stderr, "aX=%d aY=%d, aWidth=%u aHeight=%u\n", aX, aY, aWidth, aHeight);
 
1010
  //  fprintf(stderr, "surfaceWidth=%u surfaceHeight=%u\n", surfaceWidth, surfaceHeight);
 
1011
  //  fprintf(stderr, "readX=%u readY=%u readWidth=%u readHeight=%u destX=%u destY=%u\n\n",
 
1012
  //          readX, readY, readWidth, readHeight, destX, destY);
 
1013
 
 
1014
  XImage *ximage = XGetImage(mDisplay, drawable,
 
1015
                             readX, readY, readWidth, readHeight,
 
1016
                             AllPlanes, ZPixmap);
 
1017
 
 
1018
  NS_ASSERTION((ximage != NULL), "XGetImage() failed");
 
1019
  if (!ximage)
 
1020
    return;
 
1021
 
 
1022
  unsigned char *readData = 
 
1023
    (unsigned char *)nsMemory::Alloc(3*readWidth*readHeight);
 
1024
 
 
1025
  PRUint8 *scaledImage = 0;
 
1026
  PRUint8 *scaledAlpha = 0;
 
1027
  PRUint8 *imageOrigin, *alphaOrigin;
 
1028
  PRUint32 imageStride, alphaStride;
 
1029
 
 
1030
  /* image needs to be scaled */
 
1031
  if ((aSWidth!=aDWidth) || (aSHeight!=aDHeight)) {
 
1032
    PRUint32 x1, y1, x2, y2;
 
1033
    x1 = (destX*aSWidth)/aDWidth;
 
1034
    y1 = (destY*aSHeight)/aDHeight;
 
1035
    x2 = ((destX+readWidth)*aSWidth)/aDWidth;
 
1036
    y2 = ((destY+readHeight)*aSHeight)/aDHeight;
 
1037
 
 
1038
    scaledImage = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
 
1039
    scaledAlpha = (PRUint8 *)nsMemory::Alloc(aDWidth*aDHeight);
 
1040
    if (!scaledImage || !scaledAlpha) {
 
1041
      XDestroyImage(ximage);
 
1042
      nsMemory::Free(readData);
 
1043
      if (scaledImage)
 
1044
        nsMemory::Free(scaledImage);
 
1045
      if (scaledAlpha)
 
1046
        nsMemory::Free(scaledAlpha);
 
1047
      return;
 
1048
    }
 
1049
    RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
 
1050
                0, 0, aDWidth-1, aDHeight-1,
 
1051
                mImageBits, mRowBytes, scaledImage, 3*readWidth, 24);
 
1052
    RectStretch(x1, y1, x2-1, y2-1,
 
1053
                0, 0, aDWidth-1, aDHeight-1,
 
1054
                mAlphaBits, mAlphaRowBytes, scaledAlpha, readWidth, 8);
 
1055
    imageOrigin = scaledImage;
 
1056
    imageStride = 3*readWidth;
 
1057
    alphaOrigin = scaledAlpha;
 
1058
    alphaStride = readWidth;
 
1059
  } else {
 
1060
    imageOrigin = mImageBits + destY*mRowBytes + 3*destX;
 
1061
    imageStride = mRowBytes;
 
1062
    alphaOrigin = mAlphaBits + destY*mAlphaRowBytes + destX;
 
1063
    alphaStride = mAlphaRowBytes;
 
1064
  }
 
1065
 
 
1066
  PRBool isLSB;
 
1067
  unsigned int test = 1;
 
1068
  isLSB = (((char *)&test)[0]) ? 1 : 0;
 
1069
  int red_prec   = xxlib_get_prec_from_mask(visual->red_mask);
 
1070
  int green_prec = xxlib_get_prec_from_mask(visual->green_mask);
 
1071
  int blue_prec  = xxlib_get_prec_from_mask(visual->blue_mask);
 
1072
  
 
1073
 
 
1074
  PRBool flipBytes =
 
1075
    ( isLSB && ximage->byte_order != LSBFirst) ||
 
1076
    (!isLSB && ximage->byte_order == LSBFirst);
 
1077
 
 
1078
  if ((ximage->bits_per_pixel==32) &&
 
1079
      (red_prec == 8) &&
 
1080
      (green_prec == 8) &&
 
1081
      (blue_prec == 8))
 
1082
    DrawComposited32(isLSB, flipBytes, 
 
1083
                     imageOrigin, imageStride,
 
1084
                     alphaOrigin, alphaStride, 
 
1085
                     readWidth, readHeight, ximage, readData);
 
1086
  else if ((ximage->bits_per_pixel==24) &&
 
1087
      (red_prec == 8) &&
 
1088
      (green_prec == 8) &&
 
1089
      (blue_prec == 8))
 
1090
    DrawComposited24(isLSB, flipBytes, 
 
1091
                     imageOrigin, imageStride,
 
1092
                     alphaOrigin, alphaStride, 
 
1093
                     readWidth, readHeight, ximage, readData);
 
1094
  else if ((ximage->bits_per_pixel==16) &&
 
1095
           ((red_prec == 5)   || (red_prec == 6)) &&
 
1096
           ((green_prec == 5) || (green_prec == 6)) &&
 
1097
           ((blue_prec == 5)  || (blue_prec == 6)))
 
1098
    DrawComposited16(isLSB, flipBytes,
 
1099
                     imageOrigin, imageStride,
 
1100
                     alphaOrigin, alphaStride, 
 
1101
                     readWidth, readHeight, ximage, readData);
 
1102
  else
 
1103
    DrawCompositedGeneral(isLSB, flipBytes,
 
1104
                     imageOrigin, imageStride,
 
1105
                     alphaOrigin, alphaStride, 
 
1106
                     readWidth, readHeight, ximage, readData);
 
1107
 
 
1108
  xGC *imageGC = ((nsRenderingContextXlib&)aContext).GetGC();
 
1109
  xxlib_draw_rgb_image(mXlibRgbHandle, drawable, *imageGC,
 
1110
                       readX, readY, readWidth, readHeight,
 
1111
                       XLIB_RGB_DITHER_MAX,
 
1112
                       readData, 3*readWidth);
 
1113
  XDestroyImage(ximage);
 
1114
  imageGC->Release();
 
1115
  nsMemory::Free(readData);
 
1116
  if (scaledImage)
 
1117
    nsMemory::Free(scaledImage);
 
1118
  if (scaledAlpha)
 
1119
    nsMemory::Free(scaledAlpha);
 
1120
  mFlags = 0;
 
1121
}
 
1122
 
 
1123
void nsImageXlib::CreateAlphaBitmap(PRInt32 aWidth, PRInt32 aHeight)
 
1124
{
 
1125
  XImage *x_image = nsnull;
 
1126
  XGCValues gcv;
 
1127
 
 
1128
  /* Create gc clip-mask on demand */
 
1129
  if (mAlphaBits && IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
 
1130
 
 
1131
    if (!mAlphaPixmap)
 
1132
      mAlphaPixmap = XCreatePixmap(mDisplay, DefaultRootWindow(mDisplay),
 
1133
                                   aWidth, aHeight, 1);
 
1134
 
 
1135
    // Make an image out of the alpha-bits created by the image library
 
1136
    x_image = XCreateImage(mDisplay, xxlib_rgb_get_visual(mXlibRgbHandle),
 
1137
                           1, /* visual depth...1 for bitmaps */
 
1138
                           XYPixmap,
 
1139
                           0, /* x offset, XXX fix this */
 
1140
                           (char *)mAlphaBits,  /* cast away our sign. */
 
1141
                           aWidth,
 
1142
                           aHeight,
 
1143
                           32, /* bitmap pad */
 
1144
                           mAlphaRowBytes); /* bytes per line */
 
1145
 
 
1146
    x_image->bits_per_pixel=1;
 
1147
 
 
1148
    /* Image library always places pixels left-to-right MSB to LSB */
 
1149
    x_image->bitmap_bit_order = MSBFirst;
 
1150
 
 
1151
    /* This definition doesn't depend on client byte ordering
 
1152
       because the image library ensures that the bytes in
 
1153
       bitmask data are arranged left to right on the screen,
 
1154
       low to high address in memory. */
 
1155
    x_image->byte_order = MSBFirst;
 
1156
#if defined(IS_LITTLE_ENDIAN)
 
1157
    // no, it's still MSB XXX check on this!!
 
1158
    //      x_image->byte_order = LSBFirst;
 
1159
#elif defined (IS_BIG_ENDIAN)
 
1160
    x_image->byte_order = MSBFirst;
 
1161
#else
 
1162
#error ERROR! Endianness is unknown;
 
1163
#endif
 
1164
 
 
1165
    /* Copy the XImage to mAlphaPixmap */
 
1166
    if (!s1bitGC) {
 
1167
      memset(&gcv, 0, sizeof(XGCValues));
 
1168
      gcv.function = GXcopy;
 
1169
      s1bitGC = XCreateGC(mDisplay, mAlphaPixmap, GCFunction, &gcv);
 
1170
    }
 
1171
 
 
1172
    XPutImage(mDisplay, mAlphaPixmap, s1bitGC, x_image, 0, 0, 0, 0,
 
1173
              aWidth, aHeight);
 
1174
 
 
1175
    /* Now we are done with the temporary image */
 
1176
    x_image->data = 0;          /* Don't free the IL_Pixmap's bits. */
 
1177
    XDestroyImage(x_image);
 
1178
  }
 
1179
}
 
1180
 
 
1181
void nsImageXlib::CreateOffscreenPixmap(PRInt32 aWidth, PRInt32 aHeight)
 
1182
{
 
1183
  if (mImagePixmap == nsnull) {
 
1184
    mImagePixmap = XCreatePixmap(mDisplay, XDefaultRootWindow(mDisplay),
 
1185
                                 aWidth, aHeight,
 
1186
                                 xxlib_rgb_get_depth(mXlibRgbHandle));
 
1187
  }
 
1188
}
 
1189
 
 
1190
void nsImageXlib::SetupGCForAlpha(GC aGC, PRInt32 aX, PRInt32 aY)
 
1191
{
 
1192
  if (mAlphaPixmap)
 
1193
  {
 
1194
    XGCValues xvalues;
 
1195
    memset(&xvalues, 0, sizeof(XGCValues));
 
1196
    unsigned long xvalues_mask = 0;
 
1197
    xvalues.clip_x_origin = aX;
 
1198
    xvalues.clip_y_origin = aY;
 
1199
    xvalues_mask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
 
1200
    xvalues.function = GXcopy;
 
1201
    xvalues.clip_mask = mAlphaPixmap;
 
1202
 
 
1203
    XChangeGC(mDisplay, aGC, xvalues_mask, &xvalues);
 
1204
  }
 
1205
}
 
1206
 
 
1207
// Draw the bitmap. This draw just has destination coordinates
 
1208
NS_IMETHODIMP
 
1209
nsImageXlib::Draw(nsIRenderingContext &aContext,
 
1210
                  nsDrawingSurface aSurface,
 
1211
                  PRInt32 aX, PRInt32 aY,
 
1212
                  PRInt32 aWidth, PRInt32 aHeight)
 
1213
{
 
1214
  if (mPendingUpdate)
 
1215
    UpdateCachedImage();
 
1216
 
 
1217
  if ((mAlphaDepth == 1) && mIsSpacer)
 
1218
    return NS_OK;
 
1219
 
 
1220
  if (aSurface == nsnull)
 
1221
    return NS_ERROR_FAILURE;
 
1222
 
 
1223
  if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
 
1224
    return NS_OK;
 
1225
 
 
1226
  if ((mAlphaDepth == 8) && mAlphaValid) {
 
1227
    DrawComposited(aContext, aSurface,
 
1228
        0, 0, aWidth, aHeight,
 
1229
        aX, aY, aWidth, aHeight);
 
1230
    return NS_OK;
 
1231
  }
 
1232
 
 
1233
  // XXX it is said that this is temporary code
 
1234
  if ((aWidth != mWidth) || (aHeight != mHeight)) {
 
1235
    aWidth = mWidth;
 
1236
    aHeight = mHeight;
 
1237
  }
 
1238
 
 
1239
  nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
 
1240
  
 
1241
  PRInt32
 
1242
    validX = 0,
 
1243
    validY = 0,
 
1244
    validWidth = aWidth,
 
1245
    validHeight = aHeight;
 
1246
 
 
1247
  if ((mDecodedY2 < aHeight)) {
 
1248
    validHeight = mDecodedY2 - mDecodedY1;
 
1249
  }
 
1250
  if ((mDecodedX2 < aWidth)) {
 
1251
    validWidth = mDecodedX2 - mDecodedX1;
 
1252
  }
 
1253
  if ((mDecodedY1 > 0)) {
 
1254
    validHeight -= mDecodedY1;
 
1255
    validY = mDecodedY1;
 
1256
  }
 
1257
  if ((mDecodedX1 > 0)) {
 
1258
    validHeight -= mDecodedX1;
 
1259
    validX = mDecodedX1;
 
1260
  }
 
1261
 
 
1262
  CreateAlphaBitmap(aWidth, aHeight);
 
1263
 
 
1264
  GC copyGC;
 
1265
  xGC *gc = ((nsRenderingContextXlib&)aContext).GetGC();
 
1266
 
 
1267
  if (mAlphaPixmap) {
 
1268
    if (mGC) {                /* reuse GC */
 
1269
      copyGC = mGC;
 
1270
    SetupGCForAlpha(copyGC, aX, aY);
 
1271
    } else {                  /* make a new one */
 
1272
      /* this repeats things done in SetupGCForAlpha */
 
1273
      XGCValues xvalues;
 
1274
      memset(&xvalues, 0, sizeof(XGCValues));
 
1275
      unsigned long xvalues_mask = 0;
 
1276
      xvalues.clip_x_origin = aX;
 
1277
      xvalues.clip_y_origin = aY;
 
1278
      if (IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
 
1279
        xvalues_mask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
 
1280
        xvalues.clip_mask = mAlphaPixmap;
 
1281
      }
 
1282
      Drawable drawable; drawing->GetDrawable(drawable);
 
1283
      mGC = XCreateGC(mDisplay, drawable, xvalues_mask , &xvalues);
 
1284
      copyGC = mGC;
 
1285
    }
 
1286
  } else {  /* !mAlphaPixmap */
 
1287
    copyGC = *gc;
 
1288
  }
 
1289
 
 
1290
  Drawable drawable; drawing->GetDrawable(drawable);
 
1291
  XCopyArea(mDisplay, mImagePixmap, drawable,
 
1292
            copyGC, validX, validY,
 
1293
            validWidth, validHeight,
 
1294
            validX + aX, validY + aY);
 
1295
 
 
1296
  gc->Release();
 
1297
 
 
1298
  mFlags = 0;
 
1299
  return NS_OK;
 
1300
}
 
1301
 
 
1302
void nsImageXlib::TilePixmap(Pixmap src, Pixmap dest, PRInt32 aSXOffset,
 
1303
                             PRInt32 aSYOffset, const nsRect &destRect,
 
1304
                             const nsRect &clipRect, PRBool useClip)
 
1305
{
 
1306
  GC gc;
 
1307
  XGCValues values;
 
1308
  unsigned long valuesMask;
 
1309
  memset(&values, 0, sizeof(XGCValues));
 
1310
  values.fill_style = FillTiled;
 
1311
  values.tile = src;
 
1312
  values.ts_x_origin = destRect.x - aSXOffset;
 
1313
  values.ts_y_origin = destRect.y - aSYOffset;
 
1314
  valuesMask = GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle;
 
1315
  gc = XCreateGC(mDisplay, src, valuesMask, &values);
 
1316
 
 
1317
  if (useClip) {
 
1318
    XRectangle xrectangle;
 
1319
    xrectangle.x = clipRect.x;
 
1320
    xrectangle.y = clipRect.y;
 
1321
    xrectangle.width = clipRect.width;
 
1322
    xrectangle.height = clipRect.height;
 
1323
    XSetClipRectangles(mDisplay, gc, 0, 0, &xrectangle, 1, Unsorted);
 
1324
  }
 
1325
 
 
1326
  XFillRectangle(mDisplay, dest, gc, destRect.x, destRect.y,
 
1327
                 destRect.width, destRect.height);
 
1328
 
 
1329
  XFreeGC(mDisplay, gc);
 
1330
}
 
1331
 
 
1332
NS_IMETHODIMP nsImageXlib::DrawTile(nsIRenderingContext &aContext,
 
1333
                                    nsDrawingSurface aSurface,
 
1334
                                    PRInt32 aSXOffset, PRInt32 aSYOffset,
 
1335
                                    PRInt32 aPadX, PRInt32 aPadY,
 
1336
                                    const nsRect &aTileRect)
 
1337
{
 
1338
  if (mPendingUpdate)
 
1339
    UpdateCachedImage();
 
1340
 
 
1341
  if ((mAlphaDepth == 1) && mIsSpacer)
 
1342
    return NS_OK;
 
1343
 
 
1344
  if (aTileRect.width <= 0 || aTileRect.height <= 0) {
 
1345
    return NS_OK;
 
1346
  }
 
1347
 
 
1348
  if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
 
1349
    return NS_OK;
 
1350
 
 
1351
  nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
 
1352
 
 
1353
  PRBool partial = PR_FALSE;
 
1354
 
 
1355
  PRInt32
 
1356
    validX = 0,
 
1357
    validY = 0,
 
1358
    validWidth = mWidth,
 
1359
    validHeight = mHeight;
 
1360
 
 
1361
  // limit the image rectangle to the size of the image data which
 
1362
  // has been validated.
 
1363
  if (mDecodedY2 < mHeight) {
 
1364
    validHeight = mDecodedY2 - mDecodedY1;
 
1365
    partial = PR_TRUE;
 
1366
  }
 
1367
  if (mDecodedX2 < mWidth) {
 
1368
    validWidth = mDecodedX2 - mDecodedX1;
 
1369
    partial = PR_TRUE;
 
1370
  }
 
1371
  if (mDecodedY1 > 0) {   
 
1372
    validHeight -= mDecodedY1;
 
1373
    validY = mDecodedY1;
 
1374
    partial = PR_TRUE;
 
1375
  }
 
1376
  if (mDecodedX1 > 0) {
 
1377
    validWidth -= mDecodedX1;
 
1378
    validX = mDecodedX1;
 
1379
    partial = PR_TRUE;
 
1380
  }
 
1381
  
 
1382
  if (validWidth == 0 || validHeight == 0) {
 
1383
    return NS_OK;
 
1384
  }
 
1385
   
 
1386
  if (partial || ((mAlphaDepth == 8) && mAlphaValid) || (aPadX || aPadY)) {
 
1387
    PRInt32 aY0 = aTileRect.y - aSYOffset,
 
1388
            aX0 = aTileRect.x - aSXOffset,
 
1389
            aY1 = aTileRect.y + aTileRect.height,
 
1390
            aX1 = aTileRect.x + aTileRect.width;
 
1391
 
 
1392
    // Set up clipping and call Draw().
 
1393
    PRBool clipState;
 
1394
    aContext.PushState();
 
1395
    ((nsRenderingContextXlib&)aContext).SetClipRectInPixels(
 
1396
      aTileRect, nsClipCombine_kIntersect, clipState);
 
1397
    ((nsRenderingContextXlib&)aContext).UpdateGC();
 
1398
    for (PRInt32 y = aY0; y < aY1; y += mHeight + aPadY)
 
1399
      for (PRInt32 x = aX0; x < aX1; x += mWidth + aPadX)
 
1400
        Draw(aContext,aSurface, x, y,
 
1401
             PR_MIN(validWidth, aX1 - x),
 
1402
             PR_MIN(validHeight, aY1 - y));
 
1403
 
 
1404
    aContext.PopState(clipState);
 
1405
 
 
1406
    return NS_OK;
 
1407
  }
 
1408
 
 
1409
  CreateOffscreenPixmap(mWidth, mHeight);
 
1410
 
 
1411
  if (mAlphaDepth == 1) {
 
1412
    Pixmap tileImg;
 
1413
    Pixmap tileMask;
 
1414
 
 
1415
    CreateAlphaBitmap(validWidth, validHeight);
 
1416
 
 
1417
    nsRect tmpRect(0,0,aTileRect.width, aTileRect.height);
 
1418
 
 
1419
    XlibRgbHandle *drawingXHandle; 
 
1420
    drawing->GetXlibRgbHandle(drawingXHandle);
 
1421
    tileImg = XCreatePixmap(mDisplay, mImagePixmap,
 
1422
                            aTileRect.width, aTileRect.height,
 
1423
                            xxlib_rgb_get_depth(drawingXHandle));
 
1424
    TilePixmap(mImagePixmap, tileImg, aSXOffset, aSYOffset, tmpRect,
 
1425
               tmpRect, PR_FALSE);
 
1426
 
 
1427
    // tile alpha mask
 
1428
    tileMask = XCreatePixmap(mDisplay, mAlphaPixmap,
 
1429
                             aTileRect.width, aTileRect.height, mAlphaDepth);
 
1430
    TilePixmap(mAlphaPixmap, tileMask, aSXOffset, aSYOffset, tmpRect,
 
1431
               tmpRect, PR_FALSE);
 
1432
 
 
1433
    GC fgc;
 
1434
    XGCValues values;
 
1435
    unsigned long valuesMask;
 
1436
 
 
1437
    Drawable drawable; drawing->GetDrawable(drawable);
 
1438
    memset(&values, 0, sizeof(XGCValues));
 
1439
    values.clip_mask = tileMask;
 
1440
    values.clip_x_origin = aTileRect.x;
 
1441
    values.clip_y_origin = aTileRect.y;
 
1442
    valuesMask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
 
1443
    fgc = XCreateGC(mDisplay, drawable, valuesMask, &values);
 
1444
 
 
1445
    XCopyArea(mDisplay, tileImg, drawable,
 
1446
              fgc, 0,0,
 
1447
              aTileRect.width, aTileRect.height,
 
1448
              aTileRect.x, aTileRect.y);
 
1449
 
 
1450
    XFreePixmap(mDisplay, tileImg);
 
1451
    XFreePixmap(mDisplay, tileMask);
 
1452
    XFreeGC(mDisplay, fgc);
 
1453
 
 
1454
  } else {
 
1455
    // In the non-alpha case, xlib can tile for us
 
1456
    nsRect clipRect;
 
1457
    PRBool isValid;
 
1458
 
 
1459
    aContext.GetClipRect(clipRect, isValid);
 
1460
 
 
1461
    Drawable drawable; drawing->GetDrawable(drawable);
 
1462
    TilePixmap(mImagePixmap, drawable, aSXOffset, aSYOffset,
 
1463
               aTileRect, clipRect, PR_FALSE);
 
1464
  }
 
1465
 
 
1466
  mFlags = 0;
 
1467
  return NS_OK;
 
1468
}
 
1469
 
 
1470
 
 
1471
//----------------------------------------------------------------------
 
1472
nsresult nsImageXlib::Optimize(nsIDeviceContext *aContext)
 
1473
{
 
1474
  return NS_OK;
 
1475
}
 
1476
 
 
1477
//----------------------------------------------------------------------
 
1478
// Lock the image pixels.
 
1479
NS_IMETHODIMP
 
1480
nsImageXlib::LockImagePixels(PRBool aMaskPixels)
 
1481
{
 
1482
  return NS_OK;
 
1483
}
 
1484
 
 
1485
//---------------------------------------------------------------------
 
1486
// unlock the image pixels. Implement this if you need it.
 
1487
NS_IMETHODIMP
 
1488
nsImageXlib::UnlockImagePixels(PRBool aMaskPixels)
 
1489
{
 
1490
  return NS_OK;
 
1491
}
 
1492
 
 
1493
NS_IMETHODIMP nsImageXlib::DrawToImage(nsIImage* aDstImage,
 
1494
                                       nscoord aDX, nscoord aDY,
 
1495
                                       nscoord aDWidth, nscoord aDHeight)
 
1496
{
 
1497
  nsImageXlib *dest = NS_STATIC_CAST(nsImageXlib *, aDstImage);
 
1498
  if (!dest)
 
1499
    return NS_ERROR_FAILURE;
 
1500
 
 
1501
  if (aDX >= dest->mWidth || aDY >= dest->mHeight)
 
1502
    return NS_OK;
 
1503
 
 
1504
  if (mPendingUpdate)
 
1505
    UpdateCachedImage();
 
1506
 
 
1507
  if (!dest->mImagePixmap)
 
1508
    dest->CreateOffscreenPixmap(dest->mWidth, dest->mHeight);
 
1509
  
 
1510
  if (!dest->mImagePixmap || !mImagePixmap)
 
1511
    return NS_ERROR_FAILURE;
 
1512
 
 
1513
  GC gc = XCreateGC(mDisplay, dest->mImagePixmap, 0, NULL);
 
1514
 
 
1515
  if (mAlphaDepth == 1)
 
1516
    CreateAlphaBitmap(mWidth, mHeight);
 
1517
  
 
1518
  if (mAlphaPixmap)
 
1519
    SetupGCForAlpha(gc, aDX, aDY);
 
1520
 
 
1521
  XCopyArea(dest->mDisplay, mImagePixmap, dest->mImagePixmap, gc,
 
1522
            0, 0, mWidth, mHeight, aDX, aDY);
 
1523
 
 
1524
  XFreeGC(mDisplay, gc);
 
1525
 
 
1526
  if (!mIsSpacer || !mAlphaDepth)
 
1527
    dest->mIsSpacer = PR_FALSE;
 
1528
 
 
1529
  // need to copy the mImageBits in case we're rendered scaled
 
1530
  PRUint8 *scaledImage = 0, *scaledAlpha = 0;
 
1531
  PRUint8 *rgbPtr=0, *alphaPtr=0;
 
1532
  PRUint32 rgbStride, alphaStride = 0;
 
1533
 
 
1534
  if ((aDWidth != mWidth) || (aDHeight != mHeight)) {
 
1535
    // scale factor in DrawTo... start scaling
 
1536
    scaledImage = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
 
1537
    if (!scaledImage)
 
1538
      return NS_ERROR_OUT_OF_MEMORY;
 
1539
 
 
1540
    RectStretch(mWidth, mHeight, aDWidth, aDHeight,
 
1541
                0, 0, aDWidth-1, aDHeight-1,
 
1542
                mImageBits, mRowBytes, scaledImage, 3*aDWidth, 24);
 
1543
 
 
1544
    if (mAlphaDepth) {
 
1545
      if (mAlphaDepth==1)
 
1546
        alphaStride = (aDWidth+7)>>3;    // round to next byte
 
1547
      else
 
1548
        alphaStride = aDWidth;
 
1549
 
 
1550
      scaledAlpha = (PRUint8 *)nsMemory::Alloc(alphaStride*aDHeight);
 
1551
      if (!scaledAlpha) {
 
1552
        nsMemory::Free(scaledImage);
 
1553
        return NS_ERROR_OUT_OF_MEMORY;
 
1554
      }
 
1555
 
 
1556
      RectStretch(mWidth, mHeight, aDWidth, aDHeight,
 
1557
                  0, 0, aDWidth-1, aDHeight-1,
 
1558
                  mAlphaBits, mAlphaRowBytes, scaledAlpha, alphaStride,
 
1559
                  mAlphaDepth);
 
1560
    }
 
1561
    rgbPtr = scaledImage;
 
1562
    rgbStride = 3*aDWidth;
 
1563
    alphaPtr = scaledAlpha;
 
1564
  } else {
 
1565
    rgbPtr = mImageBits;
 
1566
    rgbStride = mRowBytes;
 
1567
    alphaPtr = mAlphaBits;
 
1568
    alphaStride = mAlphaRowBytes;
 
1569
  }
 
1570
 
 
1571
  PRInt32 y;
 
1572
  PRInt32 ValidWidth = ( aDWidth < ( dest->mWidth - aDX ) ) ? aDWidth : ( dest->mWidth - aDX ); 
 
1573
  PRInt32 ValidHeight = ( aDHeight < ( dest->mHeight - aDY ) ) ? aDHeight : ( dest->mHeight - aDY );
 
1574
 
 
1575
  // now composite the two images together
 
1576
  switch (mAlphaDepth) {
 
1577
  case 1:
 
1578
    {
 
1579
      PRUint8 *dst = dest->mImageBits + aDY*dest->mRowBytes + 3*aDX;
 
1580
      PRUint8 *dstAlpha = dest->mAlphaBits + aDY*dest->mAlphaRowBytes;
 
1581
      PRUint8 *src = rgbPtr;
 
1582
      PRUint8 *alpha = alphaPtr;
 
1583
      PRUint8 offset = aDX & 0x7; // x starts at 0
 
1584
      int iterations = (ValidWidth+7)/8; // round up
 
1585
 
 
1586
      for (y=0; y<aDHeight; y++) {
 
1587
        for (int x=0; x<ValidWidth; x += 8, dst += 3*8, src += 3*8) {
 
1588
          PRUint8 alphaPixels = *alpha++;
 
1589
          if (alphaPixels == 0) {
 
1590
            // all 8 transparent; jump forward
 
1591
            continue;
 
1592
          }
 
1593
 
 
1594
          // 1 or more bits are set, handle dstAlpha now - may not be aligned.
 
1595
          // Are all 8 of these alpha pixels used?
 
1596
          if (x+7 >= ValidWidth) {
 
1597
            alphaPixels &= 0xff << (8 - (ValidWidth-x)); // no, mask off unused
 
1598
            if (alphaPixels == 0)
 
1599
              continue;  // no 1 alpha pixels left
 
1600
          }
 
1601
          if (offset == 0) {
 
1602
            dstAlpha[(aDX+x)>>3] |= alphaPixels; // the cheap aligned case
 
1603
          }
 
1604
          else {
 
1605
            dstAlpha[(aDX+x)>>3]       |= alphaPixels >> offset;
 
1606
            // avoid write if no 1's to write - also avoids going past end of array
 
1607
            PRUint8 alphaTemp = alphaPixels << (8U - offset);
 
1608
            if (alphaTemp & 0xff)
 
1609
              dstAlpha[((aDX+x)>>3) + 1] |= alphaTemp;
 
1610
          }
 
1611
 
 
1612
          if (alphaPixels == 0xff) {
 
1613
            // fix - could speed up by gathering a run of 0xff's and doing 1 memcpy
 
1614
            // all 8 pixels set; copy and jump forward
 
1615
            memcpy(dst,src,8*3);
 
1616
            continue;
 
1617
          }
 
1618
          else {
 
1619
            // else mix of 1's and 0's in alphaPixels, do 1 bit at a time
 
1620
            // Don't go past end of line!
 
1621
            PRUint8 *d = dst, *s = src;
 
1622
            for (PRUint8 aMask = 1<<7, j = 0; aMask && j < ValidWidth-x; aMask >>= 1, j++) {
 
1623
              // if this pixel is opaque then copy into the destination image
 
1624
              if (alphaPixels & aMask) {
 
1625
                // might be faster with *d++ = *s++ 3 times?
 
1626
                d[0] = s[0];
 
1627
                d[1] = s[1];
 
1628
                d[2] = s[2];
 
1629
                // dstAlpha bit already set
 
1630
              }
 
1631
              d += 3;
 
1632
              s += 3;
 
1633
            }
 
1634
          }
 
1635
        }
 
1636
        // at end of each line, bump pointers.  Use wordy code because of
 
1637
        // bug 127455 to avoid possibility of unsigned underflow
 
1638
        dst = (dst - 3*8*iterations) + dest->mRowBytes;
 
1639
        src = (src - 3*8*iterations) + rgbStride;
 
1640
        alpha = (alpha - iterations) + alphaStride;
 
1641
        dstAlpha += dest->mAlphaRowBytes;
 
1642
      }
 
1643
    }
 
1644
    break;
 
1645
  case 8:
 
1646
    // fix? Does this matter?  GTK doesn't support this.  Others?
 
1647
    for (y=0; y<ValidHeight; y++) {
 
1648
      PRUint8 *dst = dest->mImageBits + (y+aDY)*dest->mRowBytes + 3*aDX;
 
1649
      PRUint8 *dstAlpha = 
 
1650
        dest->mAlphaBits + (y+aDY)*dest->mAlphaRowBytes + aDX;
 
1651
      PRUint8 *src = rgbPtr + y*rgbStride; 
 
1652
      PRUint8 *alpha = alphaPtr + y*alphaStride;
 
1653
      for (int x=0; x<ValidWidth; x++, dst+=3, dstAlpha++, src+=3, alpha++) {
 
1654
 
 
1655
        // blend this pixel over the destination image
 
1656
        unsigned val = *alpha;
 
1657
        MOZ_BLEND(dst[0], dst[0], src[0], val);
 
1658
        MOZ_BLEND(dst[1], dst[1], src[1], val);
 
1659
        MOZ_BLEND(dst[2], dst[2], src[2], val);
 
1660
        MOZ_BLEND(*dstAlpha, *dstAlpha, val, val);
 
1661
      }
 
1662
    }
 
1663
    break;
 
1664
  case 0:
 
1665
  default:
 
1666
    for (y=0; y<ValidHeight; y++)
 
1667
      memcpy(dest->mImageBits + (y+aDY)*dest->mRowBytes + 3*aDX, 
 
1668
             rgbPtr + y*rgbStride,
 
1669
             3*ValidWidth);
 
1670
  }
 
1671
  if (scaledAlpha)
 
1672
    nsMemory::Free(scaledAlpha);
 
1673
  if (scaledImage)
 
1674
    nsMemory::Free(scaledImage);
 
1675
 
 
1676
  return NS_OK;
 
1677
}