Bug 195022 - Workaround fix for scaling images with a 1-bit mask. r=sfraser,sr=tor

This commit is contained in:
pedemont%us.ibm.com 2004-06-02 16:00:29 +00:00
Родитель fdf3d8ae6f
Коммит e95b7feb8b
5 изменённых файлов: 131 добавлений и 307 удалений

Просмотреть файл

@ -126,7 +126,7 @@ CPPSRCS += \
$(NULL)
endif
ifneq (,$(filter gtk gtk2 xlib beos windows os2,$(MOZ_WIDGET_TOOLKIT)))
ifneq (,$(filter gtk gtk2 xlib beos windows os2 mac,$(MOZ_WIDGET_TOOLKIT)))
CPPSRCS += imgScaler.cpp
endif

Просмотреть файл

@ -1,264 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla 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/MPL/
*
* 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
* Tomas Mšller.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Tomas Mšller
* Tim Rowley <tor@cs.brown.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <stdio.h>
#include "imgScaler.h"
// Scaling code from Graphics Gems book III
// http://www.acm.org/pubs/tog/GraphicsGems/gemsiii/fastBitmap.c
//
// License states - "All code here can be used without restrictions."
// http://www.acm.org/pubs/tog/GraphicsGems/
/*
Fast Bitmap Stretching
Tomas Mšller
*/
static void
Stretch24(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn, unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride);
static void
Stretch8(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn, unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride);
static void
Stretch1(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn, unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride);
/**********************************************************
RectStretch enlarges or diminishes a source rectangle of a bitmap to
a destination rectangle. The source rectangle is selected by the two
points (xs1,ys1) and (xs2,ys2), and the destination rectangle by
(xd1,yd1) and (xd2,yd2). Since readability of source-code is wanted,
some optimizations have been left out for the reader: It's possible
to read one line at a time, by first stretching in x-direction and
then stretching that bitmap in y-direction.
Entry:
aSrcWidth, aSrcHeight - size of entire original image
aDstWidth, aDstHeight - size of entire scaled image
aStartColumn, aStartRow - upper corner of desired area (inclusive)
aEndColumn, aEndRow - bottom corner of desired area (inclusive)
unsigned char *aSrcImage, aSrcStride - start of original image data
unsigned char *aDstStride, aDstStride - start of desired area image data
unsigned aDepth - bit depth of image (24, 8, or 1)
**********************************************************/
NS_GFX_(void)
RectStretch(unsigned aSrcWidth, unsigned aSrcHeight,
unsigned aDstWidth, unsigned aDstHeight,
unsigned aStartColumn, unsigned aStartRow,
unsigned aEndColumn, unsigned aEndRow,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride,
unsigned aDepth)
{
int e;
unsigned dx, dy;
void (*Stretch)(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn,
unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride);
unsigned xs1, ys1, xs2, ys2, xd1, yd1, xd2, yd2;
xs1 = ys1 = xd1 = yd1 = 0;
xs2 = aSrcWidth - 1;
ys2 = aSrcHeight - 1;
xd2 = aDstWidth - 1;
yd2 = aDstHeight - 1;
// fprintf(stderr, "RS (%d %d)-(%d %d) (%d %d)-(%d %d) %d %d %d\n",
// xs1, ys1, xs2, ys2, xd1, yd1, xd2, yd2,
// aSrcStride, aDstStride, aDepth);
switch (aDepth) {
case 24:
Stretch = Stretch24;
break;
case 8:
Stretch = Stretch8;
break;
case 1:
Stretch = Stretch1;
break;
default:
return;
}
dx = yd2 - yd1;
dy = ys2 - ys1;
e = dy - dx;
dy += 1;
if (!dx)
dx = 1;
for (yd1 = 0; yd1 <= aEndRow; yd1++) {
if (yd1 >= aStartRow)
Stretch(xd1, xd2, xs1, xs2, ys1, yd1,
aStartRow, aStartColumn, aEndColumn,
aSrcImage, aSrcStride, aDstImage, aDstStride);
while (e >= 0) {
ys1++;
e -= dx;
}
e += dy;
}
}
/**********************************************************
Stretches a horizontal source line onto a horizontal destination
line. Used by RectStretch.
Entry:
x1,x2 - x-coordinates of the destination line
y1,y2 - x-coordinates of the source line
yr - y-coordinate of source line
yw - y-coordinate of destination line
**********************************************************/
static void
Stretch24(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn, unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride)
{
int e;
unsigned dx, dy, d;
unsigned char *src, *dst;
dx = x2 - x1;
dy = y2 - y1;
e = dy - dx;
dy += 1;
src = aSrcImage + yr * aSrcStride + 3 * y1;
dst = aDstImage + (yw - aStartRow) * aDstStride;
if (!dx)
dx = 1;
for (d = 0; d <= aEndColumn; d++) {
if (d >= aStartColumn) {
*dst++ = src[0];
*dst++ = src[1];
*dst++ = src[2];
}
while (e >= 0) {
src += 3;
e -= dx;
}
e += dy;
}
}
static void
Stretch8(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn, unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride)
{
int e;
unsigned dx, dy, d;
unsigned char *src, *dst;
dx = x2 - x1;
dy = y2 - y1;
e = dy - dx;
dy += 1;
src = aSrcImage + yr * aSrcStride + y1;
dst = aDstImage + (yw - aStartRow) * aDstStride;
if (!dx)
dx = 1;
for (d = 0; d <= aEndColumn; d++) {
if (d >= aStartColumn) {
*dst = *src;
dst++;
}
while (e >= 0) {
src++;
e -= dx;
}
e += dy;
}
}
static void
Stretch1(unsigned x1, unsigned x2, unsigned y1, unsigned y2,
unsigned yr, unsigned yw,
unsigned aStartRow, unsigned aStartColumn, unsigned aEndColumn,
unsigned char *aSrcImage, unsigned aSrcStride,
unsigned char *aDstImage, unsigned aDstStride)
{
int e;
unsigned dx, dy, d;
dx = x2 - x1;
dy = y2 - y1;
e = dy - dx;
dy += 1;
if (!dx)
dx = 1;
for (d = 0; d <= aEndColumn; d++) {
if ((d >= aStartColumn) &&
(*(aSrcImage + yr * aSrcStride + (y1 >> 3)) & 1 << (7 - y1 & 0x7)))
*(aDstImage +
(yw - aStartRow) * aDstStride +
((x1 - aStartColumn) >> 3))
|= 1 << (7 - x1 & 0x7);
while (e >= 0) {
y1++;
e -= dx;
}
x1++;
e += dy;
}
}

Просмотреть файл

@ -105,6 +105,7 @@ EXTRA_DSO_LDOPTS = \
LOCAL_INCLUDES = \
-I$(srcdir)/../shared \
-I$(srcdir)/.. \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -58,6 +58,9 @@ public:
NS_IMETHOD Init(nsNativeWidget aNativeWidget);
/* The following line tells the compiler that we are using the parent class'
functions, unless explicitly overridden. Avoids an ugly warning */
using DeviceContextImpl::CreateRenderingContext;
NS_IMETHOD CreateRenderingContext(nsIRenderingContext *&aContext);
NS_IMETHOD SupportsNativeWidgets(PRBool &aSupportsWidgets);

Просмотреть файл

@ -44,6 +44,7 @@
#include <Quickdraw.h>
#include "nsGfxUtils.h"
#include "imgScaler.h"
#if 0
#if TARGET_CARBON
@ -229,6 +230,7 @@ NS_IMETHODIMP nsImageMac::Draw(nsIRenderingContext &aContext, nsDrawingSurface a
PRInt32 aSWidth, PRInt32 aSHeight, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
{
Rect srcRect, dstRect, maskRect;
nsresult rv = NS_OK;
if (!mImageGWorld)
return NS_ERROR_FAILURE;
@ -278,29 +280,33 @@ NS_IMETHODIMP nsImageMac::Draw(nsIRenderingContext &aContext, nsDrawingSurface a
// get the destination pix map
nsDrawingSurfaceMac* surface = static_cast<nsDrawingSurfaceMac*>(aSurface);
CGrafPtr destPort;
nsresult rv = surface->GetGrafPtr(&destPort);
rv = surface->GetGrafPtr(&destPort);
if (NS_FAILED(rv)) return rv;
StPortSetter destSetter(destPort);
::ForeColor(blackColor);
::BackColor(whiteColor);
// can only do this if we are NOT printing
if (RenderingToPrinter(aContext)) // we are printing
if (!mMaskGWorld)
{
if (!mMaskGWorld)
{
::CopyBits(::GetPortBitMapForCopyBits(mImageGWorld), ::GetPortBitMapForCopyBits(destPort), &srcRect, &dstRect, srcCopy, nsnull);
}
else
::CopyBits(::GetPortBitMapForCopyBits(mImageGWorld),
::GetPortBitMapForCopyBits(destPort),
&srcRect, &dstRect, srcCopy, nsnull);
}
else
{
if (RenderingToPrinter(aContext))
{
// If we are printing, then we need to render everything into a temp
// GWorld, and then blit that out to the destination. We do this
// since Copy{Deep}Mask are not supported for printing.
GWorldPtr tempGWorld;
// if we have a mask, blit the transparent image into a new GWorld which is
// just white, and print that. This is marginally better than printing the
// image directly, since the transparent pixels come out black.
// We do all this because Copy{Deep}Mask is not supported when printing
PRInt16 pixelDepth = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
if (AllocateGWorld(pixelDepth, nsnull, srcRect, &tempGWorld) == noErr)
{
@ -311,35 +317,110 @@ NS_IMETHODIMP nsImageMac::Draw(nsIRenderingContext &aContext, nsDrawingSurface a
if (tempPixMap)
{
StPixelLocker tempPixLocker(tempPixMap); // locks the pixels
// copy from the destination into our temp GWorld, to get the background
// for some reason this copies garbage, so we erase to white above instead.
// ::CopyBits((BitMap*)*destPixels, (BitMap*)*tempPixMap, &dstRect, &srcRect, srcCopy, nsnull);
if (mAlphaDepth > 1)
::CopyDeepMask(::GetPortBitMapForCopyBits(mImageGWorld), ::GetPortBitMapForCopyBits(mMaskGWorld),
::GetPortBitMapForCopyBits(tempGWorld), &srcRect, &maskRect, &srcRect, srcCopy, nsnull);
else
::CopyMask(::GetPortBitMapForCopyBits(mImageGWorld), ::GetPortBitMapForCopyBits(mMaskGWorld),
::GetPortBitMapForCopyBits(tempGWorld), &srcRect, &maskRect, &srcRect);
// now copy to the screen
::CopyBits(::GetPortBitMapForCopyBits(tempGWorld), ::GetPortBitMapForCopyBits(destPort), &srcRect, &dstRect, srcCopy, nsnull);
// Copy everything into tempGWorld
if (mAlphaDepth > 1)
::CopyDeepMask(::GetPortBitMapForCopyBits(mImageGWorld),
::GetPortBitMapForCopyBits(mMaskGWorld),
::GetPortBitMapForCopyBits(tempGWorld),
&srcRect, &maskRect, &srcRect, srcCopy, nsnull);
else
::CopyMask(::GetPortBitMapForCopyBits(mImageGWorld),
::GetPortBitMapForCopyBits(mMaskGWorld),
::GetPortBitMapForCopyBits(tempGWorld),
&srcRect, &maskRect, &srcRect);
// now copy tempGWorld bits to destination
::CopyBits(::GetPortBitMapForCopyBits(tempGWorld),
::GetPortBitMapForCopyBits(destPort),
&srcRect, &dstRect, srcCopy, nsnull);
}
::DisposeGWorld(tempGWorld); // do this after dtor of tempPixLocker!
}
}
else
{
// not printing...
if (mAlphaDepth == 1 && ((aSWidth != aDWidth) || (aSHeight != aDHeight)))
{
// If scaling an image that has a 1-bit mask...
// Bug 195022 - Seems there is a bug in the Copy{Deep}Mask functions
// where scaling an image that has a 1-bit mask can cause some ugly
// artifacts to appear on screen. To work around this issue, we use the
// functions in imgScaler.cpp to do the actual scaling of the source
// image and mask.
GWorldPtr tempSrcGWorld = nsnull, tempMaskGWorld = nsnull;
// create temporary source GWorld
char* scaledSrcBits;
PRInt32 tmpSrcRowBytes;
PRInt16 pixelDepthSrc = ::GetPixDepth(::GetGWorldPixMap(mImageGWorld));
OSErr err = CreateGWorld(aDWidth, aDHeight, pixelDepthSrc,
&tempSrcGWorld, &scaledSrcBits, &tmpSrcRowBytes);
if (err != noErr) return NS_ERROR_FAILURE;
// create temporary mask GWorld
char* scaledMaskBits;
PRInt32 tmpMaskRowBytes;
err = CreateGWorld(aDWidth, aDHeight, mAlphaDepth, &tempMaskGWorld,
&scaledMaskBits, &tmpMaskRowBytes);
if (err == noErr)
{
PixMapHandle srcPixMap = ::GetGWorldPixMap(mImageGWorld);
PixMapHandle maskPixMap = ::GetGWorldPixMap(mMaskGWorld);
if (srcPixMap && maskPixMap)
{
StPixelLocker srcPixLocker(srcPixMap); // locks the pixels
StPixelLocker maskPixLocker(maskPixMap);
// scale the source
RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
0, 0, aDWidth - 1, aDHeight - 1,
mImageBits, mRowBytes, scaledSrcBits, tmpSrcRowBytes,
pixelDepthSrc);
// scale the mask
RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
0, 0, aDWidth - 1, aDHeight - 1,
mMaskBits, mAlphaRowBytes, scaledMaskBits,
tmpMaskRowBytes, mAlphaDepth);
Rect tmpRect;
::SetRect(&tmpRect, 0, 0, aDWidth, aDHeight);
// copy to screen
CopyBitsWithMask(::GetPortBitMapForCopyBits(tempSrcGWorld),
::GetPortBitMapForCopyBits(tempMaskGWorld),
mAlphaDepth, ::GetPortBitMapForCopyBits(destPort),
tmpRect, tmpRect, dstRect, PR_TRUE);
}
::DisposeGWorld(tempMaskGWorld);
}
else
{
rv = NS_ERROR_FAILURE;
}
::DisposeGWorld(tempSrcGWorld);
}
else
{
// not scaling...
CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
::GetPortBitMapForCopyBits(mMaskGWorld),
mAlphaDepth, ::GetPortBitMapForCopyBits(destPort),
srcRect, maskRect, dstRect, PR_TRUE);
}
}
}
else // not printing
{
CopyBitsWithMask(::GetPortBitMapForCopyBits(mImageGWorld),
mMaskGWorld ? ::GetPortBitMapForCopyBits(mMaskGWorld) : nsnull, mAlphaDepth,
::GetPortBitMapForCopyBits(destPort),
srcRect, maskRect, dstRect, PR_TRUE);
}
return NS_OK;
return rv;
}
/** ---------------------------------------------------
@ -642,7 +723,8 @@ void nsImageMac::ClearGWorld(GWorldPtr theGWorld)
/** -----------------------------------------------------------------
* Allocate a GWorld
*/
OSErr nsImageMac::AllocateGWorld(PRInt16 depth, CTabHandle colorTable, const Rect& bounds, GWorldPtr *outGWorld)
OSErr nsImageMac::AllocateGWorld(PRInt16 depth, CTabHandle colorTable,
const Rect& bounds, GWorldPtr *outGWorld)
{
GWorldPtr newGWorld = NULL;
// on Mac OS X, there's no reason to use the temp mem flag
@ -654,8 +736,10 @@ OSErr nsImageMac::AllocateGWorld(PRInt16 depth, CTabHandle colorTable, const Rec
return noErr;
}
void nsImageMac::CopyBitsWithMask(const BitMap* srcBits, const BitMap* maskBits, PRInt16 maskDepth, const BitMap* destBits,
const Rect& srcRect, const Rect& maskRect, const Rect& destRect, PRBool inDrawingToPort)
void nsImageMac::CopyBitsWithMask(const BitMap* srcBits, const BitMap* maskBits,
PRInt16 maskDepth, const BitMap* destBits,
const Rect& srcRect, const Rect& maskRect,
const Rect& destRect, PRBool inDrawingToPort)
{
if (maskBits)
{
@ -678,11 +762,11 @@ void nsImageMac::CopyBitsWithMask(const BitMap* srcBits, const BitMap* maskBits,
::SetClip(newClip);
}
if (maskDepth > 1) {
::CopyDeepMask(srcBits, maskBits, destBits, &srcRect, &maskRect, &destRect, ditherCopy, nsnull);
} else {
if (maskDepth > 1)
::CopyDeepMask(srcBits, maskBits, destBits, &srcRect, &maskRect,
&destRect, ditherCopy, nsnull);
else
::CopyMask(srcBits, maskBits, destBits, &srcRect, &maskRect, &destRect);
}
if (inDrawingToPort)
{