1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
23
* Peter Hartshorn <peter@igelaus.com.au>
24
* Stuart Parmenter <pavlov@netscape.com>
25
* Tim Rowley <tor@cs.brown.edu> -- 8bit alpha compositing
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.
40
* ***** END LICENSE BLOCK ***** */
42
#include "nsImageXlib.h"
43
#include "nsDrawingSurfaceXlib.h"
44
#include "nsRenderingContextXlib.h"
49
#include "imgScaler.h"
51
#define IsFlagSet(a,b) ((a) & (b))
54
static PRLogModuleInfo *ImageXlibLM = PR_NewLogModule("ImageXlib");
55
#endif /* PR_LOGGING */
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
62
static GC s1bitGC = 0;
63
static GC sXbitGC = 0;
65
XlibRgbHandle *nsImageXlib::mXlibRgbHandle = nsnull;
66
Display *nsImageXlib::mDisplay = nsnull;
68
nsImageXlib::nsImageXlib()
77
, mImagePixmap(nsnull)
78
, mAlphaPixmap(nsnull)
81
, mAlphaValid(PR_FALSE)
84
, mPendingUpdate(PR_FALSE)
85
, mDecodedX1(PR_INT32_MAX)
86
, mDecodedY1(PR_INT32_MAX)
90
PR_LOG(ImageXlibLM, PR_LOG_DEBUG, ("nsImageXlib::nsImageXlib()\n"));
92
if (!mXlibRgbHandle) {
93
mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
94
mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
97
if (!mXlibRgbHandle || !mDisplay)
101
nsImageXlib::~nsImageXlib()
103
PR_LOG(ImageXlibLM, PR_LOG_DEBUG,("nsImageXlib::nsImageXlib()\n"));
104
if (nsnull != mImageBits) {
108
if (nsnull != mAlphaBits) {
112
if (mAlphaPixmap != nsnull)
114
// The display cant be null. It gets fetched from the drawing
115
// surface used to create the pixmap. It gets assigned once
117
NS_ASSERTION(nsnull != mDisplay,"display is null.");
119
#ifdef XLIB_PIXMAP_DEBUG
120
printf("XFreePixmap(display = %p)\n",mDisplay);
123
XFreePixmap(mDisplay, mAlphaPixmap);
128
if (mImagePixmap != 0)
130
NS_ASSERTION(nsnull != mDisplay,"display is null.");
132
#ifdef XLIB_PIXMAP_DEBUG
133
printf("XFreePixmap(display = %p)\n",mDisplay);
136
XFreePixmap(mDisplay, mImagePixmap);
141
XFreeGC(mDisplay, mGC);
144
if(sXbitGC && mDisplay) // Sometimes mDisplay is null, let orhers free
146
XFreeGC(mDisplay, sXbitGC);
149
if(s1bitGC && mDisplay) // Sometimes mDisplay is null, let orhers free
151
XFreeGC(mDisplay, s1bitGC);
157
NS_IMPL_ISUPPORTS1(nsImageXlib, nsIImage)
159
nsresult nsImageXlib::Init(PRInt32 aWidth, PRInt32 aHeight,
160
PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
162
// gfxImageFrame makes sure nsImageXlib::Init gets called only once
163
if ((aWidth == 0) || (aHeight == 0))
164
return NS_ERROR_FAILURE;
169
NS_ASSERTION(PR_FALSE, "unexpected image depth");
170
return NS_ERROR_UNEXPECTED;
177
// Create the memory for the image
180
mImageBits = (PRUint8*)new PRUint8[mSizeImage];
182
switch(aMaskRequirements) {
183
case nsMaskRequirements_kNeeds1Bit:
184
mAlphaRowBytes = (aWidth + 7) / 8;
187
// 32-bit align each row
188
mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
190
mAlphaBits = new unsigned char[mAlphaRowBytes * aHeight];
193
case nsMaskRequirements_kNeeds8Bit:
194
mAlphaRowBytes = aWidth;
197
// 32-bit align each row
198
mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
199
mAlphaBits = new unsigned char[mAlphaRowBytes * aHeight];
203
break; // avoid compiler warning
208
//---------------------------------------------------------------------
210
PRInt32 nsImageXlib::GetHeight()
215
PRInt32 nsImageXlib::GetWidth()
220
PRUint8 *nsImageXlib::GetBits()
225
void *nsImageXlib::GetBitInfo()
230
PRInt32 nsImageXlib::GetLineStride()
235
nsColorMap *nsImageXlib::GetColorMap()
240
PRUint8 *nsImageXlib::GetAlphaBits()
245
PRInt32 nsImageXlib::GetAlphaLineStride()
247
return mAlphaRowBytes;
250
//-----------------------------------------------------------------------
252
// Set up the palette to the passed in color array, RGB only in this array
253
void nsImageXlib::ImageUpdated(nsIDeviceContext *aContext,
257
mPendingUpdate = PR_TRUE;
258
mUpdateRegion.Or(mUpdateRegion, *aUpdateRect);
260
mDecodedX1 = PR_MIN(mDecodedX1, aUpdateRect->x);
261
mDecodedY1 = PR_MIN(mDecodedY1, aUpdateRect->y);
263
if (aUpdateRect->YMost() > mDecodedY2)
264
mDecodedY2 = aUpdateRect->YMost();
265
if (aUpdateRect->XMost() > mDecodedX2)
266
mDecodedX2 = aUpdateRect->XMost();
269
void nsImageXlib::UpdateCachedImage()
271
nsRegionRectIterator ri(mUpdateRegion);
274
while (rect = ri.Next()) {
276
// fprintf(stderr, "ImageUpdated %p x,y=(%d %d) width,height=(%d %d)\n",
277
// this, rect->x, rect->y, rect->width, rect->height);
279
unsigned bottom, left, right;
280
bottom = rect->y + rect->height;
282
right = left + rect->width;
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) {
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));
303
// byte where the first/last bits of the update region are located
304
PRUint32 leftindex = left >> 3;
305
PRUint32 rightindex = (right-1) >> 3;
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;
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;
323
// move to first full byte
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;
336
// move to last full byte
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++) {
346
mIsSpacer = PR_FALSE;
354
if (mAlphaValid && mImagePixmap) {
355
XFreePixmap(mDisplay, mImagePixmap);
360
CreateOffscreenPixmap(mWidth, mHeight);
364
memset(&gcv, 0, sizeof(XGCValues));
365
gcv.function = GXcopy;
366
sXbitGC = XCreateGC(mDisplay, mImagePixmap, GCFunction, &gcv);
368
xxlib_draw_rgb_image_dithalign(
370
mImagePixmap, sXbitGC,
372
rect->width, rect->height,
374
mImageBits + mRowBytes * rect->y + 3 * rect->x,
380
mUpdateRegion.SetEmpty();
381
mPendingUpdate = PR_FALSE;
382
mFlags = nsImageUpdateFlags_kBitsChanged; // this should be 0'd out by Draw()
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)
394
PRInt32 origSHeight = aSHeight, origDHeight = aDHeight;
395
PRInt32 origSWidth = aSWidth, origDWidth = aDWidth;
397
if (aSWidth < 0 || aDWidth < 0 || aSHeight < 0 || aDHeight < 0)
398
return NS_ERROR_FAILURE;
400
if (0 == aSWidth || 0 == aDWidth || 0 == aSHeight || 0 == aDHeight)
403
if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
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;
411
if (aSX < mDecodedX1) {
412
aDX += ((mDecodedX1 - aSX)*origDWidth)/origSWidth;
416
if (aSY + aSHeight > mDecodedY2) {
417
aDHeight -= ((aSY + aSHeight - mDecodedY2)*origDHeight)/origSHeight;
418
aSHeight -= (aSY + aSHeight) - mDecodedY2;
420
if (aSY < mDecodedY1) {
421
aDY += ((mDecodedY1 - aSY)*origDHeight)/origSHeight;
425
if ((aDWidth <= 0 || aDHeight <= 0) || (aSWidth <= 0 || aSHeight <= 0))
428
nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
430
if (mAlphaDepth == 1)
431
CreateAlphaBitmap(mWidth, mHeight);
433
if ((mAlphaDepth == 8) && mAlphaValid) {
434
DrawComposited(aContext, aSurface,
435
aSX, aSY, aSWidth, aSHeight,
436
aDX, aDY, aDWidth, aDHeight);
441
/* XIE seriosly loses scaling images with alpha */
444
PRBool succeeded = PR_FALSE;
446
xGC *xiegc = ((nsRenderingContextXlib&)aContext).GetGC();
447
Drawable drawable; drawing->GetDrawable(drawable);
448
succeeded = DrawScaledImageXIE(mDisplay, drawable,
462
/* the good scaling way, right from GTK */
466
if (mAlphaDepth==1) {
467
PRUint32 scaledRowBytes = (aDWidth+7)>>3; // round to next byte
468
PRUint8 *scaledAlpha = (PRUint8 *)nsMemory::Alloc(aDHeight*scaledRowBytes);
470
// code below attempts to draw the image without the mask if mask
471
// creation fails for some reason. thus no easy-out "return"
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);
478
pixmap = XCreatePixmap(mDisplay, DefaultRootWindow(mDisplay),
479
aDWidth, aDHeight, 1);
483
ximage = XCreateImage(mDisplay, xxlib_rgb_get_visual(mXlibRgbHandle),
484
1, XYPixmap, 0, (char *)scaledAlpha,
489
ximage->bits_per_pixel=1;
490
ximage->bitmap_bit_order=MSBFirst;
491
ximage->byte_order = MSBFirst;
495
memset(&gcv, 0, sizeof(XGCValues));
496
gcv.function = GXcopy;
497
tmpGC = XCreateGC(mDisplay, pixmap, GCFunction, &gcv);
499
XPutImage(mDisplay, pixmap, tmpGC, ximage,
500
0, 0, 0, 0, aDWidth, aDHeight);
501
XFreeGC(mDisplay, tmpGC);
503
// can't write into the clip mask - destroy so we don't use it
505
XFreePixmap(mDisplay, pixmap);
510
XDestroyImage(ximage);
512
nsMemory::Free(scaledAlpha);
516
xGC *imageGC = nsnull;
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,
530
imageGC = ((nsRenderingContextXlib&)aContext).GetGC();
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);
540
Drawable drawable; drawing->GetDrawable(drawable);
541
xxlib_draw_rgb_image(mXlibRgbHandle, drawable, gc,
542
aDX, aDY, aDWidth, aDHeight,
544
scaledRGB, 3*aDWidth);
545
nsMemory::Free(scaledRGB);
552
XFreeGC(mDisplay, gc);
554
XFreePixmap(mDisplay, pixmap);
561
// Draw the bitmap, this method has a source and destination coordinates
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)
567
if (aSurface == nsnull)
568
return NS_ERROR_FAILURE;
573
if ((mAlphaDepth == 1) && mIsSpacer)
576
if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
579
if (aSWidth != aDWidth || aSHeight != aDHeight) {
580
return DrawScaled(aContext, aSurface, aSX, aSY, aSWidth, aSHeight,
581
aDX, aDY, aDWidth, aDHeight);
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!");
590
// limit the size of the blit to the amount of the image read in
591
PRInt32 j = aSX + aSWidth;
593
if (j > mDecodedX2) {
598
if (aSX < mDecodedX1) {
599
aDX += mDecodedX1 - aSX;
604
if (j > mDecodedY2) {
609
if (aSY < mDecodedY1) {
610
aDY += mDecodedY1 - aSY;
614
if (aDWidth <= 0 || aDHeight <= 0 || aSWidth <= 0 || aSHeight <= 0)
617
if ((mAlphaDepth == 8) && mAlphaValid) {
618
DrawComposited(aContext, aSurface,
619
aSX, aSY, aSWidth, aSHeight,
620
aDX, aDY, aSWidth, aSHeight);
624
nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
626
if (mAlphaDepth == 1)
627
CreateAlphaBitmap(mWidth, mHeight);
630
xGC *gc = ((nsRenderingContextXlib&)aContext).GetGC();
633
if (mGC) { /* reuse GC */
635
SetupGCForAlpha(copyGC, aDX - aSX, aDY - aSY);
636
} else { /* make a new one */
637
/* this repeats things done in SetupGCForAlpha */
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;
647
Drawable drawable; drawing->GetDrawable(drawable);
648
mGC = XCreateGC(mDisplay, drawable, xvalues_mask , &xvalues);
651
} else { /* !mAlphaPixmap */
655
Drawable drawable; drawing->GetDrawable(drawable);
656
XCopyArea(mDisplay, mImagePixmap, drawable,
657
copyGC, aSX, aSY, aSWidth, aSHeight, aDX, aDY);
664
// -----------------------------------------------------------------
665
// 8-bit alpha composite drawing
668
findIndex32(unsigned mask)
684
findIndex24(unsigned mask)
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)
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);
712
redIndex = 3-redIndex;
713
greenIndex = 3-greenIndex;
714
blueIndex = 3-blueIndex;
717
for (unsigned y=0; y<height; y++)
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;
725
for (unsigned i=0; i<width;
726
i++, baseRow+=4, targetRow+=3, imageRow+=3, alphaRow++)
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);
736
// 24-bit (888) truecolor convert/composite function
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)
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);
749
if (flipBytes^isLSB) {
750
redIndex = 2-redIndex;
751
greenIndex = 2-greenIndex;
752
blueIndex = 2-blueIndex;
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;
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);
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
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
784
// 16-bit ([56][56][56]) truecolor convert/composite function
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)
792
Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
794
unsigned *redScale = (xxlib_get_prec_from_mask(visual->red_mask) == 5)
796
unsigned *greenScale = (xxlib_get_prec_from_mask(visual->green_mask) == 5)
798
unsigned *blueScale = (xxlib_get_prec_from_mask(visual->blue_mask) == 5)
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);
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++) {
815
unsigned char tmp[2];
818
pix = *((short *)tmp);
820
pix = *((short *)baseRow);
821
unsigned alpha = *alphaRow;
822
MOZ_BLEND(targetRow[0],
823
redScale[(pix&visual->red_mask) >> redShift],
825
MOZ_BLEND(targetRow[1],
826
greenScale[(pix&visual->green_mask) >> greenShift],
828
MOZ_BLEND(targetRow[2],
829
blueScale[(pix&visual->blue_mask) >> blueShift],
835
// Generic convert/composite function
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)
843
Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
845
unsigned char *target = readData;
848
if (flipBytes && (ximage->bits_per_pixel>=16)) {
849
for (int row=0; row<ximage->height; row++) {
851
(unsigned char*)ximage->data + row*ximage->bytes_per_line;
852
if (ximage->bits_per_pixel==24) { // Aurgh....
854
col<ximage->bytes_per_line;
855
col+=(ximage->bits_per_pixel/8)) {
866
col<ximage->bytes_per_line;
867
col+=(ximage->bits_per_pixel/8)) {
869
switch (ximage->bits_per_pixel) {
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);
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);
901
for (int row=0; row<ximage->height; row++) {
903
(unsigned char *)ximage->data + row*ximage->bytes_per_line;
904
for (int col=0; col<ximage->width; col++) {
906
switch (ximage->bits_per_pixel) {
908
pix = (*ptr>>(col%8))&1;
913
pix = (col&1)?(*ptr>>4):(*ptr&0xf);
921
pix = *((short *)ptr);
926
pix = (*(ptr+2)<<16) | (*(ptr+1)<<8) | *ptr;
928
pix = (*ptr<<16) | (*(ptr+1)<<8) | *(ptr+2);
932
pix = *((unsigned *)ptr);
938
redFill|((pix&visual->red_mask) >> redShift)<<redScale;
940
greenFill|((pix&visual->green_mask) >> greenShift)<<greenScale;
942
blueFill|((pix&visual->blue_mask) >> blueShift)<<blueScale;
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);
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)
968
if ((aDWidth==0) || (aDHeight==0))
971
nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
972
Drawable drawable; drawing->GetDrawable(drawable);
973
Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
975
// I hate clipping... too!
976
PRUint32 surfaceWidth, surfaceHeight;
977
drawing->GetDimensions(&surfaceWidth, &surfaceHeight);
980
unsigned readWidth, readHeight, destX, destY;
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...
991
readX = 0; readWidth = aDWidth + aDX; destX = aSX - aDX;
993
readX = aDX; readWidth = aDWidth; destX = aSX;
996
readY = 0; readHeight = aDHeight + aDY; destY = aSY - aDY;
998
readY = aDY; readHeight = aDHeight; destY = aSY;
1001
if (readX+readWidth > surfaceWidth)
1002
readWidth = surfaceWidth-readX;
1003
if (readY+readHeight > surfaceHeight)
1004
readHeight = surfaceHeight-readY;
1006
if ((readHeight <= 0) || (readWidth <= 0))
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);
1014
XImage *ximage = XGetImage(mDisplay, drawable,
1015
readX, readY, readWidth, readHeight,
1016
AllPlanes, ZPixmap);
1018
NS_ASSERTION((ximage != NULL), "XGetImage() failed");
1022
unsigned char *readData =
1023
(unsigned char *)nsMemory::Alloc(3*readWidth*readHeight);
1025
PRUint8 *scaledImage = 0;
1026
PRUint8 *scaledAlpha = 0;
1027
PRUint8 *imageOrigin, *alphaOrigin;
1028
PRUint32 imageStride, alphaStride;
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;
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);
1044
nsMemory::Free(scaledImage);
1046
nsMemory::Free(scaledAlpha);
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;
1060
imageOrigin = mImageBits + destY*mRowBytes + 3*destX;
1061
imageStride = mRowBytes;
1062
alphaOrigin = mAlphaBits + destY*mAlphaRowBytes + destX;
1063
alphaStride = mAlphaRowBytes;
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);
1075
( isLSB && ximage->byte_order != LSBFirst) ||
1076
(!isLSB && ximage->byte_order == LSBFirst);
1078
if ((ximage->bits_per_pixel==32) &&
1080
(green_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) &&
1088
(green_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);
1103
DrawCompositedGeneral(isLSB, flipBytes,
1104
imageOrigin, imageStride,
1105
alphaOrigin, alphaStride,
1106
readWidth, readHeight, ximage, readData);
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);
1115
nsMemory::Free(readData);
1117
nsMemory::Free(scaledImage);
1119
nsMemory::Free(scaledAlpha);
1123
void nsImageXlib::CreateAlphaBitmap(PRInt32 aWidth, PRInt32 aHeight)
1125
XImage *x_image = nsnull;
1128
/* Create gc clip-mask on demand */
1129
if (mAlphaBits && IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
1132
mAlphaPixmap = XCreatePixmap(mDisplay, DefaultRootWindow(mDisplay),
1133
aWidth, aHeight, 1);
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 */
1139
0, /* x offset, XXX fix this */
1140
(char *)mAlphaBits, /* cast away our sign. */
1143
32, /* bitmap pad */
1144
mAlphaRowBytes); /* bytes per line */
1146
x_image->bits_per_pixel=1;
1148
/* Image library always places pixels left-to-right MSB to LSB */
1149
x_image->bitmap_bit_order = MSBFirst;
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;
1162
#error ERROR! Endianness is unknown;
1165
/* Copy the XImage to mAlphaPixmap */
1167
memset(&gcv, 0, sizeof(XGCValues));
1168
gcv.function = GXcopy;
1169
s1bitGC = XCreateGC(mDisplay, mAlphaPixmap, GCFunction, &gcv);
1172
XPutImage(mDisplay, mAlphaPixmap, s1bitGC, x_image, 0, 0, 0, 0,
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);
1181
void nsImageXlib::CreateOffscreenPixmap(PRInt32 aWidth, PRInt32 aHeight)
1183
if (mImagePixmap == nsnull) {
1184
mImagePixmap = XCreatePixmap(mDisplay, XDefaultRootWindow(mDisplay),
1186
xxlib_rgb_get_depth(mXlibRgbHandle));
1190
void nsImageXlib::SetupGCForAlpha(GC aGC, PRInt32 aX, PRInt32 aY)
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;
1203
XChangeGC(mDisplay, aGC, xvalues_mask, &xvalues);
1207
// Draw the bitmap. This draw just has destination coordinates
1209
nsImageXlib::Draw(nsIRenderingContext &aContext,
1210
nsDrawingSurface aSurface,
1211
PRInt32 aX, PRInt32 aY,
1212
PRInt32 aWidth, PRInt32 aHeight)
1215
UpdateCachedImage();
1217
if ((mAlphaDepth == 1) && mIsSpacer)
1220
if (aSurface == nsnull)
1221
return NS_ERROR_FAILURE;
1223
if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
1226
if ((mAlphaDepth == 8) && mAlphaValid) {
1227
DrawComposited(aContext, aSurface,
1228
0, 0, aWidth, aHeight,
1229
aX, aY, aWidth, aHeight);
1233
// XXX it is said that this is temporary code
1234
if ((aWidth != mWidth) || (aHeight != mHeight)) {
1239
nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
1244
validWidth = aWidth,
1245
validHeight = aHeight;
1247
if ((mDecodedY2 < aHeight)) {
1248
validHeight = mDecodedY2 - mDecodedY1;
1250
if ((mDecodedX2 < aWidth)) {
1251
validWidth = mDecodedX2 - mDecodedX1;
1253
if ((mDecodedY1 > 0)) {
1254
validHeight -= mDecodedY1;
1255
validY = mDecodedY1;
1257
if ((mDecodedX1 > 0)) {
1258
validHeight -= mDecodedX1;
1259
validX = mDecodedX1;
1262
CreateAlphaBitmap(aWidth, aHeight);
1265
xGC *gc = ((nsRenderingContextXlib&)aContext).GetGC();
1268
if (mGC) { /* reuse GC */
1270
SetupGCForAlpha(copyGC, aX, aY);
1271
} else { /* make a new one */
1272
/* this repeats things done in SetupGCForAlpha */
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;
1282
Drawable drawable; drawing->GetDrawable(drawable);
1283
mGC = XCreateGC(mDisplay, drawable, xvalues_mask , &xvalues);
1286
} else { /* !mAlphaPixmap */
1290
Drawable drawable; drawing->GetDrawable(drawable);
1291
XCopyArea(mDisplay, mImagePixmap, drawable,
1292
copyGC, validX, validY,
1293
validWidth, validHeight,
1294
validX + aX, validY + aY);
1302
void nsImageXlib::TilePixmap(Pixmap src, Pixmap dest, PRInt32 aSXOffset,
1303
PRInt32 aSYOffset, const nsRect &destRect,
1304
const nsRect &clipRect, PRBool useClip)
1308
unsigned long valuesMask;
1309
memset(&values, 0, sizeof(XGCValues));
1310
values.fill_style = FillTiled;
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);
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);
1326
XFillRectangle(mDisplay, dest, gc, destRect.x, destRect.y,
1327
destRect.width, destRect.height);
1329
XFreeGC(mDisplay, gc);
1332
NS_IMETHODIMP nsImageXlib::DrawTile(nsIRenderingContext &aContext,
1333
nsDrawingSurface aSurface,
1334
PRInt32 aSXOffset, PRInt32 aSYOffset,
1335
PRInt32 aPadX, PRInt32 aPadY,
1336
const nsRect &aTileRect)
1339
UpdateCachedImage();
1341
if ((mAlphaDepth == 1) && mIsSpacer)
1344
if (aTileRect.width <= 0 || aTileRect.height <= 0) {
1348
if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
1351
nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
1353
PRBool partial = PR_FALSE;
1358
validWidth = mWidth,
1359
validHeight = mHeight;
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;
1367
if (mDecodedX2 < mWidth) {
1368
validWidth = mDecodedX2 - mDecodedX1;
1371
if (mDecodedY1 > 0) {
1372
validHeight -= mDecodedY1;
1373
validY = mDecodedY1;
1376
if (mDecodedX1 > 0) {
1377
validWidth -= mDecodedX1;
1378
validX = mDecodedX1;
1382
if (validWidth == 0 || validHeight == 0) {
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;
1392
// Set up clipping and call Draw().
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));
1404
aContext.PopState(clipState);
1409
CreateOffscreenPixmap(mWidth, mHeight);
1411
if (mAlphaDepth == 1) {
1415
CreateAlphaBitmap(validWidth, validHeight);
1417
nsRect tmpRect(0,0,aTileRect.width, aTileRect.height);
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,
1428
tileMask = XCreatePixmap(mDisplay, mAlphaPixmap,
1429
aTileRect.width, aTileRect.height, mAlphaDepth);
1430
TilePixmap(mAlphaPixmap, tileMask, aSXOffset, aSYOffset, tmpRect,
1435
unsigned long valuesMask;
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);
1445
XCopyArea(mDisplay, tileImg, drawable,
1447
aTileRect.width, aTileRect.height,
1448
aTileRect.x, aTileRect.y);
1450
XFreePixmap(mDisplay, tileImg);
1451
XFreePixmap(mDisplay, tileMask);
1452
XFreeGC(mDisplay, fgc);
1455
// In the non-alpha case, xlib can tile for us
1459
aContext.GetClipRect(clipRect, isValid);
1461
Drawable drawable; drawing->GetDrawable(drawable);
1462
TilePixmap(mImagePixmap, drawable, aSXOffset, aSYOffset,
1463
aTileRect, clipRect, PR_FALSE);
1471
//----------------------------------------------------------------------
1472
nsresult nsImageXlib::Optimize(nsIDeviceContext *aContext)
1477
//----------------------------------------------------------------------
1478
// Lock the image pixels.
1480
nsImageXlib::LockImagePixels(PRBool aMaskPixels)
1485
//---------------------------------------------------------------------
1486
// unlock the image pixels. Implement this if you need it.
1488
nsImageXlib::UnlockImagePixels(PRBool aMaskPixels)
1493
NS_IMETHODIMP nsImageXlib::DrawToImage(nsIImage* aDstImage,
1494
nscoord aDX, nscoord aDY,
1495
nscoord aDWidth, nscoord aDHeight)
1497
nsImageXlib *dest = NS_STATIC_CAST(nsImageXlib *, aDstImage);
1499
return NS_ERROR_FAILURE;
1501
if (aDX >= dest->mWidth || aDY >= dest->mHeight)
1505
UpdateCachedImage();
1507
if (!dest->mImagePixmap)
1508
dest->CreateOffscreenPixmap(dest->mWidth, dest->mHeight);
1510
if (!dest->mImagePixmap || !mImagePixmap)
1511
return NS_ERROR_FAILURE;
1513
GC gc = XCreateGC(mDisplay, dest->mImagePixmap, 0, NULL);
1515
if (mAlphaDepth == 1)
1516
CreateAlphaBitmap(mWidth, mHeight);
1519
SetupGCForAlpha(gc, aDX, aDY);
1521
XCopyArea(dest->mDisplay, mImagePixmap, dest->mImagePixmap, gc,
1522
0, 0, mWidth, mHeight, aDX, aDY);
1524
XFreeGC(mDisplay, gc);
1526
if (!mIsSpacer || !mAlphaDepth)
1527
dest->mIsSpacer = PR_FALSE;
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;
1534
if ((aDWidth != mWidth) || (aDHeight != mHeight)) {
1535
// scale factor in DrawTo... start scaling
1536
scaledImage = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
1538
return NS_ERROR_OUT_OF_MEMORY;
1540
RectStretch(mWidth, mHeight, aDWidth, aDHeight,
1541
0, 0, aDWidth-1, aDHeight-1,
1542
mImageBits, mRowBytes, scaledImage, 3*aDWidth, 24);
1546
alphaStride = (aDWidth+7)>>3; // round to next byte
1548
alphaStride = aDWidth;
1550
scaledAlpha = (PRUint8 *)nsMemory::Alloc(alphaStride*aDHeight);
1552
nsMemory::Free(scaledImage);
1553
return NS_ERROR_OUT_OF_MEMORY;
1556
RectStretch(mWidth, mHeight, aDWidth, aDHeight,
1557
0, 0, aDWidth-1, aDHeight-1,
1558
mAlphaBits, mAlphaRowBytes, scaledAlpha, alphaStride,
1561
rgbPtr = scaledImage;
1562
rgbStride = 3*aDWidth;
1563
alphaPtr = scaledAlpha;
1565
rgbPtr = mImageBits;
1566
rgbStride = mRowBytes;
1567
alphaPtr = mAlphaBits;
1568
alphaStride = mAlphaRowBytes;
1572
PRInt32 ValidWidth = ( aDWidth < ( dest->mWidth - aDX ) ) ? aDWidth : ( dest->mWidth - aDX );
1573
PRInt32 ValidHeight = ( aDHeight < ( dest->mHeight - aDY ) ) ? aDHeight : ( dest->mHeight - aDY );
1575
// now composite the two images together
1576
switch (mAlphaDepth) {
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
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
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
1602
dstAlpha[(aDX+x)>>3] |= alphaPixels; // the cheap aligned case
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;
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);
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?
1629
// dstAlpha bit already set
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;
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;
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++) {
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);
1666
for (y=0; y<ValidHeight; y++)
1667
memcpy(dest->mImageBits + (y+aDY)*dest->mRowBytes + 3*aDX,
1668
rgbPtr + y*rgbStride,
1672
nsMemory::Free(scaledAlpha);
1674
nsMemory::Free(scaledImage);