Back to index

lightning-sunbird  0.9+nobinonly
nsBlender.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsBlender.h"
00040 #include "nsCRT.h"
00041 
00046 nsBlender :: nsBlender()
00047 {
00048 }
00049 
00054 nsBlender::~nsBlender() 
00055 {
00056 }
00057 
00058 NS_IMPL_ISUPPORTS1(nsBlender, nsIBlender)
00059 
00060 //------------------------------------------------------------
00061 
00062 // need to set up some masks for 16 bit blending
00063 // Use compile-time constants where possible for marginally smaller
00064 // footprint (don't need fields in nsBlender) but also for faster code
00065 #if defined(XP_MAC) || defined(XP_MACOSX)
00066 
00067 #define BLEND_RED_MASK        0x7c00
00068 #define BLEND_GREEN_MASK      0x03e0
00069 #define BLEND_BLUE_MASK       0x001f
00070 #define BLEND_RED_SET_MASK    0xf8
00071 #define BLEND_GREEN_SET_MASK  0xf8
00072 #define BLEND_BLUE_SET_MASK   0xf8
00073 #define BLEND_RED_SHIFT       7
00074 #define BLEND_GREEN_SHIFT     2
00075 #define BLEND_BLUE_SHIFT      3
00076 #define BLEND_GREEN_BITS      5
00077 
00078 #else  // XP_WIN, XP_UNIX, ???
00079 
00080 #define BLEND_RED_MASK        0xf800
00081 #define BLEND_GREEN_MASK      0x07e0
00082 #define BLEND_BLUE_MASK       0x001f
00083 #define BLEND_RED_SET_MASK    0xf8
00084 #define BLEND_GREEN_SET_MASK  0xfC
00085 #define BLEND_BLUE_SET_MASK   0xf8
00086 #define BLEND_RED_SHIFT       8
00087 #define BLEND_GREEN_SHIFT     3
00088 #define BLEND_BLUE_SHIFT      3
00089 #define BLEND_GREEN_BITS      6
00090 
00091 #endif
00092 
00097 NS_IMETHODIMP
00098 nsBlender::Init(nsIDeviceContext *aContext)
00099 {
00100   return NS_OK;
00101 }
00102 
00103 #define RED16(x)    (((x) & BLEND_RED_MASK) >> BLEND_RED_SHIFT)
00104 #define GREEN16(x)  (((x) & BLEND_GREEN_MASK) >> BLEND_GREEN_SHIFT)
00105 #define BLUE16(x)   (((x) & BLEND_BLUE_MASK) << BLEND_BLUE_SHIFT)
00106 
00107 static void rangeCheck(nsIDrawingSurface* surface, PRInt32& aX, PRInt32& aY, PRInt32& aWidth, PRInt32& aHeight)
00108 {
00109   PRUint32 width, height;
00110   surface->GetDimensions(&width, &height);
00111   
00112   // ensure that the origin is within bounds of the drawing surface.
00113   if (aX < 0)
00114     aX = 0;
00115   else if (aX > (PRInt32)width)
00116     aX = width;
00117   if (aY < 0)
00118     aY = 0;
00119   else if (aY > (PRInt32)height)
00120     aY = height;
00121   
00122   // ensure that the dimensions are within bounds.
00123   if (aX + aWidth > (PRInt32)width)
00124     aWidth = width - aX;
00125   if (aY + aHeight > (PRInt32)height)
00126     aHeight = height - aY;
00127 }
00128 
00133 NS_IMETHODIMP
00134 nsBlender::Blend(PRInt32 aSX, PRInt32 aSY, PRInt32 aWidth, PRInt32 aHeight, nsIDrawingSurface* aSrc,
00135                  nsIDrawingSurface* aDst, PRInt32 aDX, PRInt32 aDY, float aSrcOpacity,
00136                  nsIDrawingSurface* aSecondSrc, nscolor aSrcBackColor,
00137                  nscolor aSecondSrcBackColor)
00138 {
00139   NS_ASSERTION(aSrc, "nsBlender::Blend() called with nsnull aSrc");
00140   NS_ASSERTION(aDst, "nsBlender::Blend() called with nsnull aDst");
00141   NS_ENSURE_ARG_POINTER(aSrc);
00142   NS_ENSURE_ARG_POINTER(aDst);
00143 
00144   if (aSecondSrc) {
00145     // the background color options are obsolete and should be removed.
00146     NS_ASSERTION(aSrcBackColor == NS_RGB(0, 0, 0),
00147       "Background color for primary source must be black");
00148     NS_ASSERTION(aSecondSrcBackColor == NS_RGB(255, 255, 255),
00149       "Background color for secondary source must be white");
00150     if (aSrcBackColor != NS_RGB(0, 0, 0) ||
00151         aSecondSrcBackColor != NS_RGB(255, 255, 255)) {
00152       // disable multi-buffer blending; pretend the primary buffer
00153       // is all opaque pixels
00154       aSecondSrc = nsnull;
00155     }
00156   }
00157  
00158   nsresult result = NS_ERROR_FAILURE;
00159 
00160   // range check the coordinates in both the source and destination buffers.
00161   rangeCheck(aSrc, aSX, aSY, aWidth, aHeight);
00162   rangeCheck(aDst, aDX, aDY, aWidth, aHeight);
00163 
00164   if (aWidth <= 0 || aHeight <= 0)
00165     return NS_OK;
00166 
00167   PRUint8* srcBytes = nsnull;
00168   PRUint8* secondSrcBytes = nsnull;
00169   PRUint8* destBytes = nsnull;
00170   PRInt32 srcSpan, destSpan, secondSrcSpan;
00171   PRInt32 srcRowBytes, destRowBytes, secondSrcRowBytes;
00172 
00173   result = aSrc->Lock(aSX, aSY, aWidth, aHeight, (void**)&srcBytes, &srcSpan, &srcRowBytes, NS_LOCK_SURFACE_READ_ONLY);
00174   if (NS_SUCCEEDED(result)) {
00175 
00176     // Compute depth like this to make sure it's consistent with the memory layout.
00177     // For example on Win32 at least 24-bit bitmaps are used regardless of the device context depth. 
00178     // See bug 228399 for more information.
00179     PRUint32 depth = (srcRowBytes / aWidth) * 8;
00180 
00181     result = aDst->Lock(aDX, aDY, aWidth, aHeight, (void**)&destBytes, &destSpan, &destRowBytes, 0);
00182     if (NS_SUCCEEDED(result)) {
00183       NS_ASSERTION(srcRowBytes == destRowBytes, "Mismatched lock-bitmap sizes (src/dest) in Blender");
00184       if (srcRowBytes == destRowBytes) {
00185         if (aSecondSrc) {
00186           result = aSecondSrc->Lock(aSX, aSY, aWidth, aHeight, (void**)&secondSrcBytes, &secondSrcSpan, &secondSrcRowBytes, NS_LOCK_SURFACE_READ_ONLY);
00187           if (NS_SUCCEEDED(result)) {
00188             NS_ASSERTION(srcSpan == secondSrcSpan && srcRowBytes == secondSrcRowBytes,
00189                          "Mismatched bitmap formats (src/secondSrc) in Blender");                         
00190             if (srcSpan == secondSrcSpan && srcRowBytes == secondSrcRowBytes) {
00191               result = Blend(srcBytes, srcSpan,
00192                              destBytes, destSpan,
00193                              secondSrcBytes,
00194                              srcRowBytes, aHeight, aSrcOpacity, depth);
00195             }
00196             
00197             aSecondSrc->Unlock();
00198           }
00199         }
00200         else
00201         {
00202           result = Blend(srcBytes, srcSpan,
00203                          destBytes, destSpan,
00204                          secondSrcBytes,
00205                          srcRowBytes, aHeight, aSrcOpacity, depth);
00206         }
00207       }
00208 
00209       aDst->Unlock();
00210     }
00211 
00212     aSrc->Unlock();
00213   }
00214 
00215   return result;
00216 }
00217 
00222 NS_IMETHODIMP nsBlender::Blend(PRInt32 aSX, PRInt32 aSY, PRInt32 aWidth, PRInt32 aHeight, nsIRenderingContext *aSrc,
00223                                nsIRenderingContext *aDest, PRInt32 aDX, PRInt32 aDY, float aSrcOpacity,
00224                                nsIRenderingContext *aSecondSrc, nscolor aSrcBackColor,
00225                                nscolor aSecondSrcBackColor)
00226 {
00227   // just hand off to the drawing surface blender, to make code easier to maintain.
00228   nsIDrawingSurface* srcSurface, *destSurface, *secondSrcSurface = nsnull;
00229   aSrc->GetDrawingSurface(&srcSurface);
00230   aDest->GetDrawingSurface(&destSurface);
00231   if (aSecondSrc != nsnull)
00232     aSecondSrc->GetDrawingSurface(&secondSrcSurface);
00233   return Blend(aSX, aSY, aWidth, aHeight, srcSurface, destSurface,
00234                aDX, aDY, aSrcOpacity, secondSrcSurface, aSrcBackColor,
00235                aSecondSrcBackColor);
00236 }
00237 
00238 #ifndef MOZ_XUL
00239 NS_IMETHODIMP nsBlender::GetAlphas(const nsRect& aRect, nsIDrawingSurface* aBlack,
00240                                    nsIDrawingSurface* aWhite, PRUint8** aAlphas) {
00241   NS_ERROR("GetAlphas not implemented because XUL support not built");
00242   return NS_ERROR_NOT_IMPLEMENTED;
00243 }
00244 #else
00245 
00252 static void ComputeAlphasByByte(PRInt32 aNumLines, PRInt32 aBytesPerLine,
00253                                 PRInt32 aBytesPerPixel,
00254                                 PRUint8 *aOnBlackImage, PRUint8 *aOnWhiteImage,
00255                                 PRInt32 aBytesLineSpan, PRUint8 *aAlphas,
00256                                 PRUint32 aAlphasSize)
00257 {
00258   NS_ASSERTION(aBytesPerPixel == 3 || aBytesPerPixel == 4,
00259                "Only 24 or 32 bits per pixel supported here");
00260 
00261   PRIntn y;
00262   PRUint8* alphas = aAlphas;
00263   for (y = 0; y < aNumLines; y++) {
00264     // Look at component #1. It must be a real color no matter what
00265     // RGBA ordering is used.
00266     PRUint8 *s1 = aOnBlackImage + 1;
00267     PRUint8 *s2 = aOnWhiteImage + 1;
00268     
00269     PRIntn i;
00270     for (i = 1; i < aBytesPerLine; i += aBytesPerPixel) {
00271       *alphas++ = (PRUint8)(255 - (*s2 - *s1));
00272       s1 += aBytesPerPixel;
00273       s2 += aBytesPerPixel;
00274     }
00275   
00276     aOnBlackImage += aBytesLineSpan;
00277     aOnWhiteImage += aBytesLineSpan;
00278   }
00279 
00280   NS_ASSERTION(alphas - aAlphas == aAlphasSize, "alpha24/32 calculation error");
00281 }
00282 
00290 static void ComputeAlphas16(PRInt32 aNumLines, PRInt32 aBytesPerLine,
00291                             PRUint8 *aOnBlackImage, PRUint8 *aOnWhiteImage,
00292                             PRInt32 aBytesLineSpan, PRUint8 *aAlphas,
00293                             PRUint32 aAlphasSize)
00294 {
00295   PRIntn y;
00296   PRUint8* alphas = aAlphas;
00297   for (y = 0; y < aNumLines; y++) {
00298     PRUint16 *s1 = (PRUint16*)aOnBlackImage;
00299     PRUint16 *s2 = (PRUint16*)aOnWhiteImage;
00300     
00301       // GREEN16 returns a value between 0 and 255 representing the
00302       // green value of the pixel. It only has BLEND_GREEN_BITS of
00303       // precision (so the values are typically 0, 8, 16, ..., 248). 
00304       // If we just used the GREEN16 values
00305       // directly in the same equations that we use for the 24-bit case,
00306       // we'd lose because (e.g.) a completely transparent pixel would
00307       // have GREEN16(pix1) = 0, GREEN16(pix2) = 248, and the resulting 
00308       // alpha value would just be 248, but we need 255. So we need to
00309       // do some rescaling.
00310     const PRUint32 SCALE_DENOMINATOR =   // usually 248
00311       ((1 << BLEND_GREEN_BITS) - 1) << (8 - BLEND_GREEN_BITS);
00312 
00313     PRIntn i;
00314     for (i = 0; i < aBytesPerLine; i += 2) {
00315       PRUint32 pix1 = GREEN16(*s1);
00316       PRUint32 pix2 = GREEN16(*s2);
00317       *alphas++ = (PRUint8)(255 - ((pix2 - pix1)*255)/SCALE_DENOMINATOR);
00318       s1++;
00319       s2++;
00320     }
00321     
00322     aOnBlackImage += aBytesLineSpan;
00323     aOnWhiteImage += aBytesLineSpan;
00324   }
00325 
00326   NS_ASSERTION(alphas - aAlphas == aAlphasSize, "alpha16 calculation error");
00327 }
00328 
00329 static void ComputeAlphas(PRInt32 aNumLines, PRInt32 aBytesPerLine,
00330                           PRInt32 aDepth,
00331                           PRUint8 *aOnBlackImage, PRUint8 *aOnWhiteImage,
00332                           PRInt32 aBytesLineSpan, PRUint8 *aAlphas,
00333                           PRUint32 aAlphasSize)
00334 {
00335   switch (aDepth) {
00336     case 32:
00337     case 24:
00338       ComputeAlphasByByte(aNumLines, aBytesPerLine, aDepth/8,
00339                           aOnBlackImage, aOnWhiteImage,
00340                           aBytesLineSpan, aAlphas, aAlphasSize);
00341       break;
00342 
00343     case 16:
00344       ComputeAlphas16(aNumLines, aBytesPerLine, aOnBlackImage, aOnWhiteImage,
00345                       aBytesLineSpan, aAlphas, aAlphasSize);
00346       break;
00347     
00348     default:
00349       NS_ERROR("Unknown depth for alpha calculation");
00350       // make them all opaque
00351       memset(aAlphas, 255, aAlphasSize);
00352   }
00353 }
00354 
00355 NS_IMETHODIMP nsBlender::GetAlphas(const nsRect& aRect, nsIDrawingSurface* aBlack,
00356                                    nsIDrawingSurface* aWhite, PRUint8** aAlphas) {
00357   nsresult result;
00358 
00359   nsIDrawingSurface* blackSurface = (nsIDrawingSurface *)aBlack;
00360   nsIDrawingSurface* whiteSurface = (nsIDrawingSurface *)aWhite;
00361 
00362   nsRect r = aRect;
00363 
00364   rangeCheck(blackSurface, r.x, r.y, r.width, r.height);
00365   rangeCheck(whiteSurface, r.x, r.y, r.width, r.height);
00366 
00367   PRUint8* blackBytes = nsnull;
00368   PRUint8* whiteBytes = nsnull;
00369   PRInt32 blackSpan, whiteSpan;
00370   PRInt32 blackBytesPerLine, whiteBytesPerLine;
00371 
00372   result = blackSurface->Lock(r.x, r.y, r.width, r.height,
00373                               (void**)&blackBytes, &blackSpan,
00374                               &blackBytesPerLine, NS_LOCK_SURFACE_READ_ONLY);
00375   if (NS_SUCCEEDED(result)) {
00376     result = whiteSurface->Lock(r.x, r.y, r.width, r.height,
00377                                 (void**)&whiteBytes, &whiteSpan,
00378                                 &whiteBytesPerLine, NS_LOCK_SURFACE_READ_ONLY);
00379     if (NS_SUCCEEDED(result)) {
00380       NS_ASSERTION(blackSpan == whiteSpan &&
00381                    blackBytesPerLine == whiteBytesPerLine,
00382                    "Mismatched bitmap formats (black/white) in Blender");
00383       if (blackSpan == whiteSpan && blackBytesPerLine == whiteBytesPerLine) {
00384         *aAlphas = new PRUint8[r.width*r.height];
00385         if (*aAlphas) {
00386           // compute depth like this to make sure it's consistent with the memory layout
00387           // and work around some GTK bugs. If there are no gfx bugs, then this is correct,
00388           // if there are gfx bugs, this will prevent a crash.
00389           PRUint32 depth = (blackBytesPerLine/r.width)*8;
00390           ComputeAlphas(r.height, blackBytesPerLine, depth,
00391                         blackBytes, whiteBytes, blackSpan, 
00392                         *aAlphas, r.width*r.height);
00393         } else {
00394           result = NS_ERROR_FAILURE;
00395         }
00396       } else {
00397         result = NS_ERROR_FAILURE;
00398       }
00399 
00400       whiteSurface->Unlock();
00401     }
00402 
00403     blackSurface->Unlock();
00404   }
00405   
00406   return result;
00407 }
00408 #endif // MOZ_XUL
00409 
00413 static void Do8Blend(float aOpacity, PRInt32 aNumLines, PRInt32 aNumBytes,
00414                      PRUint8 *aSImage, PRUint8 *aS2Image, PRUint8 *aDImage,
00415                      PRInt32 aSLSpan, PRInt32 aDLSpan)
00416 {
00417   if (aOpacity <= 0.0) {
00418     return;
00419   }
00420 
00421   // OK, just do an opaque blend. Assume the rendered image had just
00422   // 1-bit alpha.
00423   PRIntn y;
00424   if (!aS2Image) {
00425     for (y = 0; y < aNumLines; y++) {
00426       memcpy(aDImage, aSImage, aNumBytes);
00427       aSImage += aSLSpan;
00428       aDImage += aDLSpan;
00429     }
00430   } else {
00431     for (y = 0; y < aNumLines; y++) {
00432       for (int i = 0; i < aNumBytes; i++) {
00433         if (aSImage[i] == aS2Image[i]) {
00434           aDImage[i] = aSImage[i];
00435         }
00436       }
00437       aSImage += aSLSpan;
00438       aS2Image += aSLSpan;
00439       aDImage += aDLSpan;
00440     }
00441   }
00442 }
00443 
00448 nsresult nsBlender::Blend(PRUint8 *aSrcBits, PRInt32 aSrcStride,
00449                           PRUint8 *aDestBits, PRInt32 aDestStride,
00450                           PRUint8 *aSecondSrcBits,
00451                           PRInt32 aSrcBytes, PRInt32 aLines, float aOpacity,
00452                           PRUint8 aDepth)
00453 {
00454   nsresult result = NS_OK;
00455   switch (aDepth) {
00456     case 32:
00457         Do32Blend(aOpacity, aLines, aSrcBytes, aSrcBits, aDestBits,
00458                   aSecondSrcBits, aSrcStride, aDestStride, nsHighQual);
00459         break;
00460 
00461     case 24:
00462         Do24Blend(aOpacity, aLines, aSrcBytes, aSrcBits, aDestBits,
00463                   aSecondSrcBits, aSrcStride, aDestStride, nsHighQual);
00464         break;
00465 
00466     case 16:
00467         Do16Blend(aOpacity, aLines, aSrcBytes, aSrcBits, aDestBits,
00468                   aSecondSrcBits, aSrcStride, aDestStride, nsHighQual);
00469         break;
00470 
00471     default:
00472         Do8Blend(aOpacity, aLines, aSrcBytes, aSrcBits, aSecondSrcBits,
00473                aDestBits, aSrcStride, aDestStride);
00474         break;
00475   }
00476 
00477   return result;
00478 }
00479 
00503 static void DoSingleImageBlend(PRUint32 aOpacity256, PRInt32 aNumLines, PRInt32 aNumBytes,
00504                                PRUint8 *aSImage, PRUint8 *aDImage,
00505                                PRInt32 aSLSpan, PRInt32 aDLSpan)
00506 {
00507   PRIntn y;
00508 
00509   for (y = 0; y < aNumLines; y++) {
00510     PRUint8 *s2 = aSImage;
00511     PRUint8 *d2 = aDImage;
00512     
00513     PRIntn i;
00514     for (i = 0; i < aNumBytes; i++) {
00515       PRUint32 destPix = *d2;
00516       
00517       *d2 = (PRUint8)(destPix + (((*s2 - destPix)*aOpacity256) >> 8));
00518       
00519       d2++;
00520       s2++;
00521     }
00522     
00523     aSImage += aSLSpan;
00524     aDImage += aDLSpan;
00525   }
00526 }
00527 
00566 void
00567 nsBlender::Do32Blend(float aOpacity, PRInt32 aNumLines, PRInt32 aNumBytes,
00568                      PRUint8 *aSImage, PRUint8 *aDImage, PRUint8 *aSecondSImage,
00569                      PRInt32 aSLSpan, PRInt32 aDLSpan, nsBlendQuality aBlendQuality)
00570 {
00571   /* Use alpha ranging from 0 to 256 inclusive. This means that we get accurate
00572      results when we divide by 256. */
00573   PRUint32 opacity256 = (PRUint32)(aOpacity*256);
00574 
00575   // Handle simpler cases
00576   if (opacity256 <= 0) {
00577     return;
00578   }
00579   if (nsnull == aSecondSImage) {
00580     DoSingleImageBlend(opacity256, aNumLines, aNumBytes, aSImage, aDImage, aSLSpan, aDLSpan);
00581     return;
00582   }
00583 
00584   PRIntn numPixels = aNumBytes/4;
00585 
00586   PRIntn y;
00587   for (y = 0; y < aNumLines; y++) {
00588     PRUint8 *s2 = aSImage;
00589     PRUint8 *d2 = aDImage;
00590     PRUint8 *ss2 = aSecondSImage;
00591 
00592     PRIntn x;
00593     for (x = 0; x < numPixels; x++) {
00594       PRUint32 pixSColor  = *((PRUint32*)(s2))&0xFFFFFF;
00595       PRUint32 pixSSColor = *((PRUint32*)(ss2))&0xFFFFFF;
00596       
00597       if ((pixSColor != 0x000000) || (pixSSColor != 0xFFFFFF)) {
00598         if (pixSColor != pixSSColor) {
00599           PRIntn i;
00600           // the original source pixel was alpha-blended into the background.
00601           // We have to extract the original alpha and color value.
00602           for (i = 0; i < 4; i++) {
00603             PRUint32 destPix = *d2;
00604             PRUint32 onBlack = *s2;
00605             PRUint32 imageAlphaTimesDestPix = (255 + onBlack - *ss2)*destPix;
00606             PRUint32 adjustedDestPix;
00607             FAST_DIVIDE_BY_255(adjustedDestPix, imageAlphaTimesDestPix);
00608             
00609             *d2 = (PRUint8)(destPix + (((onBlack - adjustedDestPix)*opacity256) >> 8));
00610             
00611             d2++;
00612             s2++;
00613             ss2++;
00614           }
00615         } else {
00616           PRIntn i;
00617           for (i = 0; i < 4; i++) {
00618             PRUint32 destPix = *d2;
00619             PRUint32 onBlack = *s2;
00620             
00621             *d2 = (PRUint8)(destPix + (((onBlack - destPix)*opacity256) >> 8));
00622             
00623             d2++;
00624             s2++;
00625           }
00626 
00627           ss2 += 4;
00628         }
00629       } else {
00630         d2 += 4;
00631         s2 += 4;
00632         ss2 += 4;
00633       }
00634     }
00635     
00636     aSImage += aSLSpan;
00637     aDImage += aDLSpan;
00638     aSecondSImage += aSLSpan;
00639   }
00640 }
00641 
00646 void
00647 nsBlender::Do24Blend(float aOpacity, PRInt32 aNumLines, PRInt32 aNumBytes,
00648                      PRUint8 *aSImage, PRUint8 *aDImage, PRUint8 *aSecondSImage,
00649                      PRInt32 aSLSpan, PRInt32 aDLSpan, nsBlendQuality aBlendQuality)
00650 {
00651   /* Use alpha ranging from 0 to 256 inclusive. This means that we get accurate
00652      results when we divide by 256. */
00653   PRUint32 opacity256 = (PRUint32)(aOpacity*256);
00654 
00655   // Handle simpler cases
00656   if (opacity256 <= 0) {
00657     return;
00658   }
00659   if (nsnull == aSecondSImage) {
00660     DoSingleImageBlend(opacity256, aNumLines, aNumBytes, aSImage, aDImage, aSLSpan, aDLSpan);
00661     return;
00662   }
00663 
00664   PRIntn numPixels = aNumBytes/3;
00665 
00666   PRIntn y;
00667   for (y = 0; y < aNumLines; y++) {
00668     PRUint8 *s2 = aSImage;
00669     PRUint8 *d2 = aDImage;
00670     PRUint8 *ss2 = aSecondSImage;
00671 
00672     PRIntn x;
00673     for (x = 0; x < numPixels; x++) {
00674       PRUint32 pixSColor  = s2[0] | (s2[1] << 8) | (s2[2] << 16);
00675       PRUint32 pixSSColor = ss2[0] | (ss2[1] << 8) | (ss2[2] << 16);
00676       
00677       if ((pixSColor != 0x000000) || (pixSSColor != 0xFFFFFF)) {
00678         if (pixSColor != pixSSColor) {
00679           PRIntn i;
00680           // the original source pixel was alpha-blended into the background.
00681           // We have to extract the original alpha and color value.
00682           for (i = 0; i < 3; i++) {
00683             PRUint32 destPix = *d2;
00684             PRUint32 onBlack = *s2;
00685             PRUint32 imageAlphaTimesDestPix = (255 + onBlack - *ss2)*destPix;
00686             PRUint32 adjustedDestPix;
00687             FAST_DIVIDE_BY_255(adjustedDestPix, imageAlphaTimesDestPix);
00688             
00689             *d2 = (PRUint8)(destPix + (((onBlack - adjustedDestPix)*opacity256) >> 8));
00690             
00691             d2++;
00692             s2++;
00693             ss2++;
00694           }
00695         } else {
00696           PRIntn i;
00697           for (i = 0; i < 3; i++) {
00698             PRUint32 destPix = *d2;
00699             PRUint32 onBlack = *s2;
00700             
00701             *d2 = (PRUint8)(destPix + (((onBlack - destPix)*opacity256) >> 8));
00702             
00703             d2++;
00704             s2++;
00705           }
00706 
00707           ss2 += 3;
00708         }
00709       } else {
00710         d2 += 3;
00711         s2 += 3;
00712         ss2 += 3;
00713       }
00714     }
00715     
00716     aSImage += aSLSpan;
00717     aDImage += aDLSpan;
00718     aSecondSImage += aSLSpan;
00719   }
00720 }
00721 
00722 //------------------------------------------------------------
00723 
00724 
00725 
00726 #define MAKE16(r, g, b)                                              \
00727         (PRUint16)(((r) & BLEND_RED_SET_MASK) << BLEND_RED_SHIFT)    \
00728           | (((g) & BLEND_GREEN_SET_MASK) << BLEND_GREEN_SHIFT)      \
00729           | (((b) & BLEND_BLUE_SET_MASK) >> BLEND_BLUE_SHIFT)
00730 
00735 void
00736 nsBlender::Do16Blend(float aOpacity, PRInt32 aNumLines, PRInt32 aNumBytes,
00737                      PRUint8 *aSImage, PRUint8 *aDImage, PRUint8 *aSecondSImage,
00738                      PRInt32 aSLSpan, PRInt32 aDLSpan, nsBlendQuality aBlendQuality)
00739 {
00740   PRUint32 opacity256 = (PRUint32)(aOpacity*256);
00741 
00742   // Handle simpler cases
00743   if (opacity256 <= 0) {
00744     return;
00745   }
00746 
00747   PRIntn numPixels = aNumBytes/2;
00748   
00749   if (nsnull == aSecondSImage) {
00750     PRIntn y;
00751     for (y = 0; y < aNumLines; y++) {
00752       PRUint16 *s2 = (PRUint16*)aSImage;
00753       PRUint16 *d2 = (PRUint16*)aDImage;
00754       
00755       PRIntn i;
00756       for (i = 0; i < numPixels; i++) {
00757         PRUint32 destPix = *d2;
00758         PRUint32 destPixR = RED16(destPix);
00759         PRUint32 destPixG = GREEN16(destPix);
00760         PRUint32 destPixB = BLUE16(destPix);
00761         PRUint32 srcPix = *s2;
00762         
00763         *d2 = MAKE16(destPixR + (((RED16(srcPix) - destPixR)*opacity256) >> 8),
00764                      destPixG + (((GREEN16(srcPix) - destPixG)*opacity256) >> 8),
00765                      destPixB + (((BLUE16(srcPix) - destPixB)*opacity256) >> 8));
00766         d2++;
00767         s2++;
00768       }
00769       
00770       aSImage += aSLSpan;
00771       aDImage += aDLSpan;
00772     }
00773     return;
00774   }
00775 
00776   PRUint32 srcBackgroundColor = MAKE16(0x00, 0x00, 0x00);
00777   PRUint32 src2BackgroundColor = MAKE16(0xFF, 0xFF, 0xFF);
00778 
00779   PRIntn y;
00780   for (y = 0; y < aNumLines; y++) {
00781     PRUint16 *s2 = (PRUint16*)aSImage;
00782     PRUint16 *d2 = (PRUint16*)aDImage;
00783     PRUint16 *ss2 = (PRUint16*)aSecondSImage;
00784 
00785     PRIntn x;
00786     for (x = 0; x < numPixels; x++) {
00787       PRUint32 srcPix = *s2;
00788       PRUint32 src2Pix = *ss2;
00789 
00790       if ((srcPix != srcBackgroundColor) || (src2Pix != src2BackgroundColor)) {
00791         PRUint32 destPix = *d2;
00792         PRUint32 destPixR = RED16(destPix);
00793         PRUint32 destPixG = GREEN16(destPix);
00794         PRUint32 destPixB = BLUE16(destPix);
00795         PRUint32 srcPixR = RED16(srcPix);
00796         PRUint32 srcPixG = GREEN16(srcPix);
00797         PRUint32 srcPixB = BLUE16(srcPix);
00798           
00799         if (srcPix != src2Pix) {
00800           PRUint32 imageAlphaTimesDestPixR = (255 + srcPixR - RED16(src2Pix))*destPixR;
00801           PRUint32 imageAlphaTimesDestPixG = (255 + srcPixG - GREEN16(src2Pix))*destPixG;
00802           PRUint32 imageAlphaTimesDestPixB = (255 + srcPixB - BLUE16(src2Pix))*destPixB;
00803           PRUint32 adjustedDestPixR;
00804           FAST_DIVIDE_BY_255(adjustedDestPixR, imageAlphaTimesDestPixR);
00805           PRUint32 adjustedDestPixG;
00806           FAST_DIVIDE_BY_255(adjustedDestPixG, imageAlphaTimesDestPixG);
00807           PRUint32 adjustedDestPixB;
00808           FAST_DIVIDE_BY_255(adjustedDestPixB, imageAlphaTimesDestPixB);
00809             
00810           *d2 = MAKE16(destPixR + (((srcPixR - adjustedDestPixR)*opacity256) >> 8),
00811             destPixG + (((srcPixG - adjustedDestPixG)*opacity256) >> 8),
00812             destPixB + (((srcPixB - adjustedDestPixB)*opacity256) >> 8));
00813         } else {
00814           *d2 = MAKE16(destPixR + (((srcPixR - destPixR)*opacity256) >> 8),
00815             destPixG + (((srcPixG - destPixG)*opacity256) >> 8),
00816             destPixB + (((srcPixB - destPixB)*opacity256) >> 8));
00817         }
00818       }
00819 
00820       d2++;
00821       s2++;
00822       ss2++;
00823     }
00824     
00825     aSImage += aSLSpan;
00826     aDImage += aDLSpan;
00827     aSecondSImage += aSLSpan;
00828   }
00829 }
00830 
00831 //------------------------------------------------------------