Files
Mozilla/mozilla/gfx/src/nsBlender.cpp
beard%netscape.com af0519c458 bug #33091, added range check to prevent memory corruption, r=kmcclusk
git-svn-id: svn://10.0.0.236/trunk@64050 18797224-902f-48f8-a5cc-f745e15eee43
2000-03-24 21:32:10 +00:00

968 lines
25 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "nsBlender.h"
#include "nsIDeviceContext.h"
#include "il_util.h"
static NS_DEFINE_IID(kIBlenderIID, NS_IBLENDER_IID);
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
nsBlender :: nsBlender()
{
NS_INIT_REFCNT();
mContext = nsnull;
mSrcBytes = nsnull;
mSecondSrcBytes = nsnull;
mDestBytes = nsnull;
mSrcRowBytes = 0;
mDestRowBytes = 0;
mSecondSrcRowBytes = 0;
mSrcSpan = 0;
mDestSpan = 0;
mSecondSrcSpan = 0;
}
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
nsBlender::~nsBlender()
{
NS_IF_RELEASE(mContext);
}
NS_IMPL_ISUPPORTS(nsBlender, kIBlenderIID);
//------------------------------------------------------------
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
NS_IMETHODIMP
nsBlender::Init(nsIDeviceContext *aContext)
{
mContext = aContext;
NS_IF_ADDREF(mContext);
// need to set up some masks for 16 bit Mac or Unix
#ifdef XP_MAC
mRedMask = 0x7c00;
mGreenMask = 0x03e0;
mBlueMask = 0x001f;
mRedSetMask = 0xf8;
mGreenSetMask = 0xf8;
mBlueSetMask = 0xf8;
mRedShift = 7;
mGreenShift = 2;
mBlueShift = 3;
#endif
#ifdef XP_WIN
mRedMask = 0xf800;
mGreenMask = 0x07e0;
mBlueMask = 0x001f;
mRedSetMask = 0xf8;
mGreenSetMask = 0xfC;
mBlueSetMask = 0xf8;
mRedShift = 8;
mGreenShift = 3;
mBlueShift = 3;
#endif
#ifdef XP_UNIX
mRedMask = 0xf800;
mGreenMask = 0x07e0;
mBlueMask = 0x001f;
mRedSetMask = 0xf8;
mGreenSetMask = 0xfC;
mBlueSetMask = 0xf8;
mRedShift = 8;
mGreenShift = 3;
mBlueShift = 3;
#endif
return NS_OK;
}
static void rangeCheck(nsIDrawingSurface* surface, PRInt32& aX, PRInt32& aY, PRInt32& aWidth, PRInt32& aHeight)
{
PRUint32 width, height;
surface->GetDimensions(&width, &height);
// ensure that the origin is within bounds of the drawing surface.
if (aX < 0)
aX = 0;
else if (aX > (PRInt32)width)
aX = width;
if (aY < 0)
aY = 0;
else if (aY > (PRInt32)height)
aY = height;
// ensure that the dimensions are within bounds.
if (aX + aWidth > (PRInt32)width)
aWidth = width - aX;
if (aY + aHeight > (PRInt32)height)
aHeight = height - aY;
}
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
NS_IMETHODIMP
nsBlender::Blend(PRInt32 aSX, PRInt32 aSY, PRInt32 aWidth, PRInt32 aHeight, nsDrawingSurface aSrc,
nsDrawingSurface aDst, PRInt32 aDX, PRInt32 aDY, float aSrcOpacity,
nsDrawingSurface aSecondSrc, nscolor aSrcBackColor, nscolor aSecondSrcBackColor)
{
nsresult result = NS_ERROR_FAILURE;
nsIDrawingSurface* srcSurface = (nsIDrawingSurface *)aSrc;
nsIDrawingSurface* destSurface = (nsIDrawingSurface *)aDst;
nsIDrawingSurface* secondSrcSurface = (nsIDrawingSurface *)aSecondSrc;
// range check the coordinates in both the source and destination buffers.
rangeCheck(srcSurface, aSX, aSY, aWidth, aHeight);
rangeCheck(destSurface, aDX, aDY, aWidth, aHeight);
mSrcBytes = mSecondSrcBytes = mDestBytes = nsnull;
if (NS_OK == srcSurface->Lock(aSX, aSY, aWidth, aHeight, (void **)&mSrcBytes, &mSrcRowBytes, &mSrcSpan, NS_LOCK_SURFACE_READ_ONLY)) {
if (NS_OK == destSurface->Lock(aDX, aDY, aWidth, aHeight, (void **)&mDestBytes, &mDestRowBytes, &mDestSpan, 0)) {
if (secondSrcSurface)
secondSrcSurface->Lock(aSX, aSY, aWidth, aHeight, (void **)&mSecondSrcBytes, &mSecondSrcRowBytes, &mSecondSrcSpan, NS_LOCK_SURFACE_READ_ONLY);
nsPixelFormat pixformat;
srcSurface->GetPixelFormat(&pixformat);
result = Blend(mSrcBytes, mSrcRowBytes, mSrcSpan,
mDestBytes, mDestRowBytes, mDestSpan,
mSecondSrcBytes, mSecondSrcRowBytes, mSecondSrcSpan,
aHeight, (PRInt32)(aSrcOpacity * 100), pixformat,
aSrcBackColor, aSecondSrcBackColor);
destSurface->Unlock();
if (secondSrcSurface)
secondSrcSurface->Unlock();
}
srcSurface->Unlock();
}
return result;
}
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
NS_IMETHODIMP nsBlender::Blend(PRInt32 aSX, PRInt32 aSY, PRInt32 aWidth, PRInt32 aHeight, nsIRenderingContext *aSrc,
nsIRenderingContext *aDest, PRInt32 aDX, PRInt32 aDY, float aSrcOpacity,
nsIRenderingContext *aSecondSrc, nscolor aSrcBackColor, nscolor aSecondSrcBackColor)
{
// just hand off to the drawing surface blender, to make code easier to maintain.
nsDrawingSurface srcSurface, destSurface, secondSrcSurface = nsnull;
aSrc->GetDrawingSurface(&srcSurface);
aDest->GetDrawingSurface(&destSurface);
if (aSecondSrc != nsnull)
aSecondSrc->GetDrawingSurface(&secondSrcSurface);
return Blend(aSX, aSY, aWidth, aHeight, srcSurface, destSurface,
aDX, aDY, aSrcOpacity, secondSrcSurface,
aSrcBackColor, aSecondSrcBackColor);
}
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
nsresult nsBlender::Blend(PRUint8 *aSrcBits, PRInt32 aSrcStride, PRInt32 aSrcBytes,
PRUint8 *aDestBits, PRInt32 aDestStride, PRInt32 aDestBytes,
PRUint8 *aSecondSrcBits, PRInt32 aSecondSrcStride, PRInt32 aSecondSrcBytes,
PRInt32 aLines, PRInt32 aAlpha, nsPixelFormat &aPixFormat,
nscolor aSrcBackColor, nscolor aSecondSrcBackColor)
{
nsresult result = NS_OK;
PRUint32 depth;
mContext->GetDepth(depth);
// now do the blend
switch (depth){
case 32:
Do32Blend(aAlpha, aLines, aSrcBytes, aSrcBits, aDestBits,
aSecondSrcBits, aSrcStride, aDestStride, nsHighQual,
aSrcBackColor, aSecondSrcBackColor, aPixFormat);
result = NS_OK;
break;
case 24:
Do24Blend(aAlpha, aLines, aSrcBytes, aSrcBits, aDestBits,
aSecondSrcBits, aSrcStride, aDestStride, nsHighQual,
aSrcBackColor, aSecondSrcBackColor, aPixFormat);
break;
case 16:
Do16Blend(aAlpha, aLines, aSrcBytes, aSrcBits, aDestBits,
aSecondSrcBits, aSrcStride, aDestStride, nsHighQual,
aSrcBackColor, aSecondSrcBackColor, aPixFormat);
break;
case 8:
{
IL_ColorSpace *thespace = nsnull;
if ((result = mContext->GetILColorSpace(thespace)) == NS_OK){
Do8Blend(aAlpha, aLines, aSrcBytes, aSrcBits, aDestBits,
aSecondSrcBits, aSrcStride, aDestStride, thespace,
nsHighQual, aSrcBackColor, aSecondSrcBackColor);
IL_ReleaseColorSpace(thespace);
}
break;
}
}
return result;
}
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
void
nsBlender::Do32Blend(PRUint8 aBlendVal,PRInt32 aNumlines,PRInt32 aNumbytes,PRUint8 *aSImage,PRUint8 *aDImage,PRUint8 *aSecondSImage,PRInt32 aSLSpan,PRInt32 aDLSpan,nsBlendQuality aBlendQuality,nscolor aSrcBackColor, nscolor aSecondSrcBackColor, nsPixelFormat &aPixFormat)
{
PRUint8 *d1,*d2,*s1,*s2,*ss1,*ss2;
PRUint32 val1,val2;
PRInt32 x,y,temp1,numlines,numPixels,xinc,yinc;
PRUint32 srccolor,secsrccolor,i;
PRUint32 pixSColor,pixSSColor;
aBlendVal = (aBlendVal*255)/100;
val2 = aBlendVal;
val1 = 255-val2;
// now go thru the image and blend (remember, its bottom upwards)
s1 = aSImage;
d1 = aDImage;
numlines = aNumlines;
xinc = 1;
yinc = 1;
if (nsnull != aSecondSImage){
ss1 = (PRUint8 *)aSecondSImage;
srccolor = ((NS_GET_R(aSrcBackColor)<<16)) | ((NS_GET_G(aSrcBackColor) <<8)) | ((NS_GET_B(aSrcBackColor)));
secsrccolor = ((NS_GET_R(aSecondSrcBackColor)<<16)) | ((NS_GET_G(aSecondSrcBackColor) <<8)) | ((NS_GET_B(aSecondSrcBackColor)));
}else {
ss1 = nsnull;
}
if(nsnull == ss1){
for(y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
for(x = 0; x < aNumbytes; x++){
temp1 = (((*d2)*val1)+((*s2)*val2))>>8;
if(temp1>255){
temp1 = 255;
}
*d2 = (PRUint8)temp1;
d2++;
s2++;
}
s1 += aSLSpan;
d1 += aDLSpan;
}
} else {
numPixels = aNumbytes/4;
for(y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
ss2=ss1;
for(x=0;x<numPixels;x++){
pixSColor = *((PRUint32*)(s2))&0xFFFFFF;
pixSSColor = *((PRUint32*)(ss2))&0xFFFFFF ;
if((pixSColor!=srccolor) || (pixSSColor!=secsrccolor)) {
for(i=0;i<4;i++){
temp1 = (((*d2)*val1)+((*s2)*val2))>>8;
if(temp1>255){
temp1 = 255;
}
*d2 = (PRUint8)temp1;
d2++;
s2++;
ss2++;
}
} else {
d2+=4;
s2+=4;
ss2+=4;
}
}
s1 += aSLSpan;
d1 += aDLSpan;
ss1+= aDLSpan;
}
}
}
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
void
nsBlender::Do24Blend(PRUint8 aBlendVal,PRInt32 aNumlines,PRInt32 aNumbytes,PRUint8 *aSImage,PRUint8 *aDImage,PRUint8 *aSecondSImage,PRInt32 aSLSpan,PRInt32 aDLSpan,nsBlendQuality aBlendQuality,nscolor aSrcBackColor, nscolor aSecondSrcBackColor, nsPixelFormat &aPixFormat)
{
PRUint8 *d1,*d2,*s1,*s2,*ss1,*ss2;
PRUint32 val1,val2;
PRInt32 x,y,temp1,numlines,numPixels,xinc,yinc;
PRUint32 srccolor,secsrccolor,i;
PRUint32 pixSColor,pixSSColor;
aBlendVal = (aBlendVal*255)/100;
val2 = aBlendVal;
val1 = 255-val2;
// now go thru the image and blend (remember, its bottom upwards)
s1 = aSImage;
d1 = aDImage;
numlines = aNumlines;
xinc = 1;
yinc = 1;
if (nsnull != aSecondSImage){
ss1 = (PRUint8 *)aSecondSImage;
srccolor = ((NS_GET_R(aSrcBackColor)<<16)) | ((NS_GET_G(aSrcBackColor) <<8)) | ((NS_GET_B(aSrcBackColor)));
secsrccolor = ((NS_GET_R(aSecondSrcBackColor)<<16)) | ((NS_GET_G(aSecondSrcBackColor) <<8)) | ((NS_GET_B(aSecondSrcBackColor)));
}else {
ss1 = nsnull;
}
if(nsnull == ss1){
for(y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
for(x = 0; x < aNumbytes; x++){
temp1 = (((*d2)*val1)+((*s2)*val2))>>8;
if(temp1>255){
temp1 = 255;
}
*d2 = (PRUint8)temp1;
d2++;
s2++;
}
s1 += aSLSpan;
d1 += aDLSpan;
}
} else {
numPixels = aNumbytes/3;
for(y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
ss2=ss1;
for(x=0;x<numPixels;x++){
pixSColor = *((PRUint32*)(s2))&0xFFFFFF;
pixSSColor = *((PRUint32*)(ss2))&0xFFFFFF ;
if((pixSColor!=srccolor) || (pixSSColor!=secsrccolor)) {
for(i=0;i<3;i++){
temp1 = (((*d2)*val1)+((*s2)*val2))>>8;
if(temp1>255){
temp1 = 255;
}
*d2 = (PRUint8)temp1;
d2++;
s2++;
ss2++;
}
} else {
d2+=3;
s2+=3;
ss2+=3;
}
}
s1 += aSLSpan;
d1 += aDLSpan;
ss1+= aDLSpan;
}
}
}
//------------------------------------------------------------
#define RED16(x) (((x) & mRedMask) >> mRedShift)
#define GREEN16(x) (((x) & mGreenMask) >> mGreenShift)
#define BLUE16(x) (((x) & mBlueMask) << mBlueShift)
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
void
nsBlender::Do16Blend(PRUint8 aBlendVal,PRInt32 aNumlines,PRInt32 aNumbytes,PRUint8 *aSImage,PRUint8 *aDImage,PRUint8 *aSecondSImage,PRInt32 aSLSpan,PRInt32 aDLSpan,nsBlendQuality aBlendQuality,nscolor aSrcBackColor, nscolor aSecondSrcBackColor, nsPixelFormat &aPixFormat)
{
PRUint16 *d1,*d2,*s1,*s2,*ss1,*ss2;
PRUint32 val1,val2,red,green,blue,stemp,dtemp,sstemp;
PRInt32 x,y,numlines,xinc,yinc;
PRUint16 srccolor,secsrccolor;
PRInt16 dspan,sspan,span;
// since we are using 16 bit pointers, the num bytes need to be cut by 2
aBlendVal = (aBlendVal * 255) / 100;
val2 = aBlendVal;
val1 = 255-val2;
// now go thru the image and blend (remember, its bottom upwards)
s1 = (PRUint16*)aSImage;
d1 = (PRUint16*)aDImage;
dspan = aDLSpan >> 1;
sspan = aSLSpan >> 1;
span = aNumbytes >> 1;
numlines = aNumlines;
xinc = 1;
yinc = 1;
if (nsnull != aSecondSImage) {
ss1 = (PRUint16 *)aSecondSImage;
srccolor = ((NS_GET_R(aSrcBackColor) & mRedSetMask) << mRedShift) |
((NS_GET_G(aSrcBackColor) & mGreenSetMask) << mGreenShift) |
((NS_GET_B(aSrcBackColor) & mBlueSetMask) >> mBlueShift);
secsrccolor = ((NS_GET_R(aSecondSrcBackColor) & mRedSetMask) << mRedShift) |
((NS_GET_G(aSecondSrcBackColor) & mGreenSetMask) << mGreenShift) |
((NS_GET_B(aSecondSrcBackColor) & mBlueSetMask) >> mBlueShift);
} else {
ss1 = nsnull;
}
if (nsnull != ss1){
for (y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
ss2 = ss1;
for (x = 0; x < span; x++){
stemp = *s2;
sstemp = *ss2;
if ((stemp != srccolor) || (sstemp != secsrccolor)) {
dtemp = *d2;
red = (RED16(dtemp) * val1 + RED16(stemp) * val2) >> 8;
if (red > 255)
red = 255;
green = (GREEN16(dtemp) * val1 + GREEN16(stemp) * val2) >> 8;
if (green > 255)
green = 255;
blue = (BLUE16(dtemp) * val1 + BLUE16(stemp) * val2) >> 8;
if (blue > 255)
blue = 255;
*d2 = (PRUint16)((red & mRedSetMask) << mRedShift) | ((green & mGreenSetMask) << mGreenShift) | ((blue & mBlueSetMask) >> mBlueShift);
}
d2++;
s2++;
ss2++;
}
s1 += sspan;
d1 += dspan;
ss1 += sspan;
}
} else {
for (y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
for (x = 0; x < span; x++){
stemp = *s2;
dtemp = *d2;
red = (RED16(dtemp) * val1 + RED16(stemp) * val2) >> 8;
if (red > 255)
red = 255;
green = (GREEN16(dtemp) * val1 + GREEN16(stemp) * val2) >> 8;
if (green > 255)
green = 255;
blue = (BLUE16(dtemp) * val1 + BLUE16(stemp) * val2) >> 8;
if (blue > 255)
blue = 255;
*d2 = (PRUint16)((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >> 3);
d2++;
s2++;
}
s1 += sspan;
d1 += dspan;
}
}
}
//------------------------------------------------------------
extern void inv_colormap(PRInt16 colors,PRUint8 *aCMap,PRInt16 bits,PRUint32 *dist_buf,PRUint8 *aRGBMap );
/** ---------------------------------------------------
* See documentation in nsBlender.h
* @update 2/25/00 dwc
*/
void
nsBlender::Do8Blend(PRUint8 aBlendVal,PRInt32 aNumlines,PRInt32 aNumbytes,PRUint8 *aSImage,PRUint8 *aDImage,PRUint8 *aSecondSImage,PRInt32 aSLSpan,PRInt32 aDLSpan,IL_ColorSpace *aColorMap,nsBlendQuality aBlendQuality,nscolor aSrcBackColor, nscolor aSecondSrcBackColor)
{
PRUint32 r,g,b,r1,g1,b1,i;
PRUint8 *d1,*d2,*s1,*s2;
PRInt32 x,y,val1,val2,numlines,xinc,yinc;;
PRUint8 *mapptr,*invermap;
PRUint32 *distbuffer;
PRUint32 quantlevel,tnum,num,shiftnum;
NI_RGB *map;
aBlendVal = (aBlendVal*255)/100;
val2 = aBlendVal;
val1 = 255-val2;
// build a colormap we can use to get an inverse map
map = aColorMap->cmap.map+10;
mapptr = new PRUint8[256*3];
invermap = mapptr;
for(i=0;i<216;i++){
*invermap=map->blue;
invermap++;
*invermap=map->green;
invermap++;
*invermap=map->red;
invermap++;
map++;
}
for(i=216;i<256;i++){
*invermap=0;
invermap++;
*invermap=0;
invermap++;
*invermap=0;
invermap++;
}
quantlevel = aBlendQuality+2;
quantlevel = 4; // 4 5
shiftnum = (8-quantlevel)+8; // 12 11
tnum = 2; // 2 2
for(i=1;i<=quantlevel;i++)
tnum = 2*tnum; // 2, 4, 8, tnum = 16 32
num = tnum; // num = 16 32
for(i=1;i<3;i++)
num = num*tnum; // 256, 4096 32768
distbuffer = new PRUint32[num]; // new PRUint[4096] 32768
invermap = new PRUint8[num];
inv_colormap(216,mapptr,quantlevel,distbuffer,invermap ); // 216,mapptr[],4,distbuffer[4096],invermap[12288])
// now go thru the image and blend (remember, its bottom upwards)
s1 = aSImage;
d1 = aDImage;
numlines = aNumlines;
xinc = 1;
yinc = 1;
for(y = 0; y < aNumlines; y++){
s2 = s1;
d2 = d1;
for(x = 0; x < aNumbytes; x++){
i = (*d2);
i-=10;
r = mapptr[(3 * i) + 2];
g = mapptr[(3 * i) + 1];
b = mapptr[(3 * i)];
i =(*s2);
i-=10;
r1 = mapptr[(3 * i) + 2];
g1 = mapptr[(3 * i) + 1];
b1 = mapptr[(3 * i)];
r = ((r*val1)+(r1*val2))>>shiftnum;
//r=r>>quantlevel;
if(r>tnum)
r = tnum;
g = ((g*val1)+(g1*val2))>>shiftnum;
//g=g>>quantlevel;
if(g>tnum)
g = tnum;
b = ((b*val1)+(b1*val2))>>shiftnum;
//b=b>>quantlevel;
if(b>tnum)
b = tnum;
r = (r<<(2*quantlevel))+(g<<quantlevel)+b;
r = (invermap[r]+10);
(*d2)=r;
d2++;
s2++;
}
s1 += aSLSpan;
d1 += aDLSpan;
}
delete[] distbuffer;
delete[] invermap;
}
//------------------------------------------------------------
static PRInt32 bcenter, gcenter, rcenter;
static PRUint32 gdist, rdist, cdist;
static PRInt32 cbinc, cginc, crinc;
static PRUint32 *gdp, *rdp, *cdp;
static PRUint8 *grgbp, *rrgbp, *crgbp;
static PRInt32 gstride, rstride;
static PRInt32 x, xsqr, colormax;
static PRInt32 cindex;
static void maxfill(PRUint32 *buffer,PRInt32 side );
static PRInt32 redloop( void );
static PRInt32 greenloop( PRInt32 );
static PRInt32 blueloop( PRInt32 );
/** --------------------------------------------------------------------------
* Create an inverse colormap for a given color table
* @param colors -- Number of colors
* @param aCMap -- The color map
* @param aBits -- Resolution in bits for the inverse map
* @param dist_buf -- a buffer to hold the temporary colors in while we calculate the map
* @param aRGBMap -- the map to put the inverse colors into for the color table
* @return VOID
*/
void
inv_colormap(PRInt16 aNumColors,PRUint8 *aCMap,PRInt16 aBits,PRUint32 *dist_buf,PRUint8 *aRGBMap )
{
PRInt32 nbits = 8 - aBits; // 3
PRUint32 r,g,b;
colormax = 1 << aBits; // 32
x = 1 << nbits; // 8
xsqr = 1 << (2 * nbits); // 64
// Compute "strides" for accessing the arrays
gstride = colormax; // 32
rstride = colormax * colormax; // 1024
maxfill( dist_buf, colormax );
for (cindex = 0;cindex < aNumColors;cindex++ ){
r = aCMap[(3 * cindex) + 2];
g = aCMap[(3 * cindex) + 1];
b = aCMap[(3 * cindex)];
rcenter = r >> nbits;
gcenter = g >> nbits;
bcenter = b >> nbits;
rdist = r - (rcenter * x + x/2);
gdist = g - (gcenter * x + x/2);
cdist = b - (bcenter * x + x/2);
cdist = rdist*rdist + gdist*gdist + cdist*cdist;
crinc = 2 * ((rcenter + 1) * xsqr - (r * x));
cginc = 2 * ((gcenter + 1) * xsqr - (g * x));
cbinc = 2 * ((bcenter + 1) * xsqr - (b * x));
// Array starting points.
cdp = dist_buf + rcenter * rstride + gcenter * gstride + bcenter; // dist 01533120 ..
crgbp = aRGBMap + rcenter * rstride + gcenter * gstride + bcenter; // aRGBMap 01553168
(void)redloop();
}
}
/** --------------------------------------------------------------------------
* find a red max or min value in a color cube
* @return a red component in a certain span
*/
static PRInt32
redloop()
{
PRInt32 detect,r,first;
PRInt32 txsqr = xsqr + xsqr;
static PRInt32 rxx;
detect = 0;
rdist = cdist; // 48
rxx = crinc; // 128
rdp = cdp;
rrgbp = crgbp; // 01553168
first = 1;
for (r=rcenter;r<colormax;r++,rdp+=rstride,rrgbp+=rstride,rdist+=rxx,rxx+=txsqr,first=0){
if ( greenloop( first ) )
detect = 1;
else
if ( detect )
break;
}
rxx=crinc-txsqr;
rdist = cdist-rxx;
rdp=cdp-rstride;
rrgbp=crgbp-rstride;
first=1;
for (r=rcenter-1;r>=0;r--,rdp-=rstride,rrgbp-=rstride,rxx-=txsqr,rdist-=rxx,first=0){
if ( greenloop( first ) )
detect = 1;
else
if ( detect )
break;
}
return detect;
}
/** --------------------------------------------------------------------------
* find a green max or min value in a color cube
* @return a red component in a certain span
*/
static PRInt32
greenloop(PRInt32 aRestart)
{
PRInt32 detect,g,first;
PRInt32 txsqr = xsqr + xsqr;
static PRInt32 here, min, max;
static PRInt32 ginc, gxx, gcdist;
static PRUint32 *gcdp;
static PRUint8 *gcrgbp;
if(aRestart){
here = gcenter;
min = 0;
max = colormax - 1;
ginc = cginc;
}
detect = 0;
gcdp=rdp;
gdp=rdp;
gcrgbp=rrgbp;
grgbp=rrgbp;
gcdist=rdist;
gdist=rdist;
// loop up.
for(g=here,gxx=ginc,first=1;g<=max;
g++,gdp+=gstride,gcdp+=gstride,grgbp+=gstride,gcrgbp+=gstride,
gdist+=gxx,gcdist+=gxx,gxx+=txsqr,first=0){
if(blueloop(first)){
if (!detect){
if (g>here){
here = g;
rdp = gcdp;
rrgbp = gcrgbp;
rdist = gcdist;
ginc = gxx;
}
detect=1;
}
}else
if (detect){
break;
}
}
// loop down
gcdist = rdist-gxx;
gdist = gcdist;
gdp=rdp-gstride;
gcdp=gdp;
grgbp=rrgbp-gstride;
gcrgbp = grgbp;
for (g=here-1,gxx=ginc-txsqr,
first=1;g>=min;g--,gdp-=gstride,gcdp-=gstride,grgbp-=gstride,gcrgbp-=gstride,
gxx-=txsqr,gdist-=gxx,gcdist-=gxx,first=0){
if (blueloop(first)){
if (!detect){
here = g;
rdp = gcdp;
rrgbp = gcrgbp;
rdist = gcdist;
ginc = gxx;
detect = 1;
}
} else
if ( detect ){
break;
}
}
return detect;
}
/** --------------------------------------------------------------------------
* find a blue max or min value in a color cube
* @return a red component in a certain span
*/
static PRInt32
blueloop(PRInt32 aRestart )
{
PRInt32 detect,b,i=cindex;
register PRUint32 *dp;
register PRUint8 *rgbp;
register PRInt32 bxx;
PRUint32 bdist;
register PRInt32 txsqr = xsqr + xsqr;
register PRInt32 lim;
static PRInt32 here, min, max;
static PRInt32 binc;
if (aRestart){
here = bcenter;
min = 0;
max = colormax - 1;
binc = cbinc;
}
detect = 0;
bdist = gdist;
// Basic loop, finds first applicable cell.
for (b=here,bxx=binc,dp=gdp,rgbp=grgbp,lim=max;b<=lim;
b++,dp++,rgbp++,bdist+=bxx,bxx+=txsqr){
if(*dp>bdist){
if(b>here){
here = b;
gdp = dp;
grgbp = rgbp;
gdist = bdist;
binc = bxx;
}
detect = 1;
break;
}
}
// Second loop fills in a run of closer cells.
for (;b<=lim;b++,dp++,rgbp++,bdist+=bxx,bxx+=txsqr){
if (*dp>bdist){
*dp = bdist;
*rgbp = i;
}
else{
break;
}
}
// Basic loop down, do initializations here
lim = min;
b = here - 1;
bxx = binc - txsqr;
bdist = gdist - bxx;
dp = gdp - 1;
rgbp = grgbp - 1;
// The 'find' loop is executed only if we didn't already find something.
if (!detect)
for (;b>=lim;b--,dp--,rgbp--,bxx-=txsqr,bdist-=bxx){
if (*dp>bdist){
here = b;
gdp = dp;
grgbp = rgbp;
gdist = bdist;
binc = bxx;
detect = 1;
break;
}
}
// Update loop.
for (;b>=lim;b--,dp--,rgbp--,bxx-=txsqr,bdist-=bxx){
if (*dp>bdist){
*dp = bdist;
*rgbp = i;
} else{
break;
}
}
// If we saw something, update the edge trackers.
return detect;
}
/** --------------------------------------------------------------------------
* fill in a span with a max value
* @return VOID
*/
static void
maxfill(PRUint32 *buffer,PRInt32 side )
{
register PRInt32 maxv = ~0L;
register PRInt32 i;
register PRUint32 *bp;
for (i=side*side*side,bp=buffer;i>0;i--,bp++) // side*side*side = 32768
*bp = maxv;
}
//------------------------------------------------------------