diff --git a/mozilla/gfx/src/cairo/nsCairoImage.cpp b/mozilla/gfx/src/cairo/nsCairoImage.cpp index 7ca174e3c1d..65d6202236c 100644 --- a/mozilla/gfx/src/cairo/nsCairoImage.cpp +++ b/mozilla/gfx/src/cairo/nsCairoImage.cpp @@ -62,8 +62,7 @@ static void ARGBToThreeChannel(PRUint32* aARGB, PRUint8* aData) { #endif } -static void ThreeChannelToARGB(PRUint8* aData, PRUint32* aARGB) { - PRUint32 v = *aARGB & 0xFF000000; +static PRUint32 ThreeChannelToARGB(PRUint8* aData, PRUint8 aAlpha) { PRUint8 r, g, b; #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON) // BGR format; assume little-endian system @@ -76,8 +75,7 @@ static void ThreeChannelToARGB(PRUint8* aData, PRUint32* aARGB) { // RGB, red byte first r = aData[0]; g = aData[1]; b = aData[2]; #endif - v |= (r << 16) | (g << 8) | b; - *aARGB = v; + return (aAlpha << 24) | (r << 16) | (g << 8) | b; } nsCairoImage::nsCairoImage() @@ -89,8 +87,7 @@ nsCairoImage::nsCairoImage() mImageSurfaceData(nsnull), mImageSurfaceAlpha(nsnull), mAlphaDepth(0), - mHadAnyAlphaValues(PR_FALSE), - mHadAnyPixelValues(PR_FALSE) + mHadAnyData(PR_FALSE) { } @@ -234,6 +231,54 @@ nsCairoImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface, return Draw(aContext, aSurface, 0, 0, mWidth, mHeight, aX, aY, aWidth, aHeight); } +void +nsCairoImage::UpdateFromImageData() +{ + if (!mImageSurfaceData) + return; + + NS_ASSERTION(mAlphaDepth == 0 || mAlphaDepth == 1 || mAlphaDepth == 8, + "Bad alpha depth"); + + PRInt32 alphaIndex = 0; + PRInt32 bufIndex = 0; + for (PRInt32 row = 0; row < mHeight; ++row) { + for (PRInt32 col = 0; col < mWidth; ++col) { + PRUint8 alpha = 0xFF; + if (mAlphaDepth == 1) { + PRUint8 mask = 1 << (7 - (col&7)); + if (!(mImageSurfaceAlpha[alphaIndex] & mask)) { + alpha = 0; + } + if (mask == 0x01) { + ++alphaIndex; + } + } else if (mAlphaDepth == 8) { + alpha = mImageSurfaceAlpha[bufIndex]; + } + mImageSurfaceBuf[bufIndex] = ThreeChannelToARGB(&mImageSurfaceData[bufIndex*3], alpha); + ++bufIndex; + } + if (mAlphaDepth == 1) { + if (mWidth & 7) { + ++alphaIndex; + } + } + } + + if (PR_FALSE) { // Enabling this saves memory but can lead to pathological + // behaviour + nsMemory::Free(mImageSurfaceData); + mImageSurfaceData = nsnull; + if (mImageSurfaceAlpha) { + nsMemory::Free(mImageSurfaceAlpha); + mImageSurfaceAlpha = nsnull; + } + + mHadAnyData = PR_TRUE; + } +} + NS_IMETHODIMP nsCairoImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface, PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight, @@ -244,12 +289,15 @@ nsCairoImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface, aSX, aSY, aSWidth, aSHeight, aDX, aDY, aDWidth, aDHeight); #endif + UpdateFromImageData(); nsCairoDrawingSurface *dstSurf = NS_STATIC_CAST(nsCairoDrawingSurface*, aSurface); nsCairoRenderingContext *cairoContext = NS_STATIC_CAST(nsCairoRenderingContext*, &aContext); cairo_t *dstCairo = cairoContext->GetCairo(); + cairo_translate(dstCairo, aDX, aDY); + cairo_pattern_t *pat = cairo_pattern_create_for_surface (mImageSurface); cairo_matrix_t* matrix = cairo_matrix_create(); if (matrix) { @@ -262,8 +310,9 @@ nsCairoImage::Draw(nsIRenderingContext &aContext, nsIDrawingSurface *aSurface, cairo_pattern_destroy (pat); cairo_new_path(dstCairo); - cairo_rectangle (dstCairo, aDX, aDY, aDWidth, aDHeight); + cairo_rectangle (dstCairo, 0, 0, aDWidth, aDHeight); cairo_fill (dstCairo); + cairo_translate(dstCairo, -aDX, -aDY); return NS_OK; } @@ -275,6 +324,8 @@ nsCairoImage::DrawTile(nsIRenderingContext &aContext, PRInt32 aPadX, PRInt32 aPadY, const nsRect &aTileRect) { + UpdateFromImageData(); + if (aPadX || aPadY) fprintf (stderr, "Warning: nsCairoImage::DrawTile given padX(%d)/padY(%d), ignoring\n", aPadX, aPadY); @@ -283,32 +334,26 @@ nsCairoImage::DrawTile(nsIRenderingContext &aContext, cairo_t *dstCairo = cairoContext->GetCairo(); - cairo_save(dstCairo); - - // just in case this needs setting - cairo_set_target_surface(dstCairo, dstSurf->GetCairoSurface()); - - // coords are absolute again - cairo_identity_matrix(dstCairo); + cairo_translate(dstCairo, aTileRect.x, aTileRect.y); cairo_pattern_t *pat = cairo_pattern_create_for_surface (mImageSurface); - cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT); - if (aSXOffset != 0 || aSYOffset != 0) { - cairo_matrix_t* matrix = cairo_matrix_create(); - if (matrix) { - cairo_matrix_set_affine(matrix, 1, 0, 0, 1, aSXOffset, aSYOffset); - cairo_pattern_set_matrix(pat, matrix); - cairo_matrix_destroy(matrix); - } + cairo_matrix_t* matrix = cairo_matrix_create(); + if (matrix) { + nsCOMPtr dc; + aContext.GetDeviceContext(*getter_AddRefs(dc)); + float app2dev = dc->AppUnitsToDevUnits(); + cairo_matrix_set_affine(matrix, app2dev, 0, 0, app2dev, aSXOffset, aSYOffset); + cairo_pattern_set_matrix(pat, matrix); + cairo_matrix_destroy(matrix); } + cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT); cairo_set_pattern (dstCairo, pat); cairo_pattern_destroy (pat); cairo_new_path(dstCairo); - cairo_rectangle (dstCairo, aTileRect.x, aTileRect.y, aTileRect.width, aTileRect.height); + cairo_rectangle (dstCairo, 0, 0, aTileRect.width, aTileRect.height); cairo_fill (dstCairo); - - cairo_restore(dstCairo); + cairo_translate(dstCairo, -aTileRect.x, -aTileRect.y); return NS_OK; } @@ -316,6 +361,8 @@ nsCairoImage::DrawTile(nsIRenderingContext &aContext, NS_IMETHODIMP nsCairoImage::DrawToImage(nsIImage* aDstImage, PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight) { + UpdateFromImageData(); + nsCairoImage *dstCairoImage = NS_STATIC_CAST(nsCairoImage*, aDstImage); cairo_t *dstCairo = cairo_create (); @@ -356,106 +403,71 @@ nsCairoImage::GetBitInfo() NS_IMETHODIMP nsCairoImage::LockImagePixels(PRBool aMaskPixels) { - PRInt32 count = mWidth*mHeight; - if (aMaskPixels) { - NS_ASSERTION(!mImageSurfaceAlpha, "already locked alphas"); + if (mImageSurfaceData) { + return NS_OK; + } + + if (mAlphaDepth > 0) { NS_ASSERTION(mAlphaDepth == 1 || mAlphaDepth == 8, "Bad alpha depth"); - PRInt32 size = mHeight*(mAlphaDepth == 1 ? ((mWidth+7)/8) : mWidth); + PRUint32 size = mHeight*(mAlphaDepth == 1 ? ((mWidth+7)/8) : mWidth); mImageSurfaceAlpha = (PRUint8*)nsMemory::Alloc(size); if (!mImageSurfaceAlpha) return NS_ERROR_OUT_OF_MEMORY; - if (mHadAnyAlphaValues) { - // fill from existing ARGB buffer - if (mAlphaDepth == 8) { - for (PRInt32 i = 0; i < count; ++i) { - mImageSurfaceAlpha[i] = (PRUint8)(mImageSurfaceBuf[i] >> 24); - } - } else { - PRInt32 i = 0; - for (PRInt32 row = 0; row < mHeight; ++row) { - PRUint8 alphaBits = 0; - for (PRInt32 col = 0; col < mWidth; ++col) { - PRUint8 mask = 1 << (7 - (col&7)); - if (mImageSurfaceBuf[row*mWidth + col] & 0xFF000000) { - alphaBits |= mask; - } - if (mask == 0x01) { - // This mask byte is complete, write it back - mImageSurfaceAlpha[i] = alphaBits; - alphaBits = 0; - ++i; - } + } + + PRUint32 size = mWidth * mHeight * 3; + mImageSurfaceData = (PRUint8*)nsMemory::Alloc(size); + if (!mImageSurfaceData) + return NS_ERROR_OUT_OF_MEMORY; + + PRInt32 count = mWidth*mHeight; + if (mAlphaDepth > 0 && mHadAnyData) { + PRInt32 size = mHeight*(mAlphaDepth == 1 ? ((mWidth+7)/8) : mWidth); + mImageSurfaceAlpha = (PRUint8*)nsMemory::Alloc(size); + + // fill from existing ARGB buffer + if (mAlphaDepth == 8) { + for (PRInt32 i = 0; i < count; ++i) { + mImageSurfaceAlpha[i] = (PRUint8)(mImageSurfaceBuf[i] >> 24); + } + } else { + PRInt32 i = 0; + for (PRInt32 row = 0; row < mHeight; ++row) { + PRUint8 alphaBits = 0; + for (PRInt32 col = 0; col < mWidth; ++col) { + PRUint8 mask = 1 << (7 - (col&7)); + if (mImageSurfaceBuf[row*mWidth + col] & 0xFF000000) { + alphaBits |= mask; } - if (mWidth & 7) { - // write back the incomplete alpha mask + if (mask == 0x01) { + // This mask byte is complete, write it back mImageSurfaceAlpha[i] = alphaBits; + alphaBits = 0; ++i; } } - } - } - } else { - NS_ASSERTION(!mImageSurfaceData, "already locked pixels"); - mImageSurfaceData = (PRUint8*)nsMemory::Alloc(mWidth * mHeight * 3); - if (!mImageSurfaceData) - return NS_ERROR_OUT_OF_MEMORY; - if (mHadAnyPixelValues) { - // fill from existing ARGB buffer - for (PRInt32 i = 0; i < count; ++i) { - ARGBToThreeChannel(&mImageSurfaceBuf[i], &mImageSurfaceData[i*3]); + if (mWidth & 7) { + // write back the incomplete alpha mask + mImageSurfaceAlpha[i] = alphaBits; + ++i; + } } } } + + if (mHadAnyData) { + // fill from existing ARGB buffer + for (PRInt32 i = 0; i < count; ++i) { + ARGBToThreeChannel(&mImageSurfaceBuf[i], &mImageSurfaceData[i*3]); + } + } + return NS_OK; } NS_IMETHODIMP nsCairoImage::UnlockImagePixels(PRBool aMaskPixels) { - PRInt32 count = mWidth*mHeight; - if (aMaskPixels) { - NS_ASSERTION(mImageSurfaceAlpha, "alpha values not locked"); - NS_ASSERTION(mAlphaDepth == 1 || mAlphaDepth == 8, - "Bad alpha depth"); - if (mAlphaDepth == 8) { - for (PRInt32 i = 0; i < count; ++i) { - PRInt32 v = mImageSurfaceBuf[i] & 0xFFFFFF; - v |= mImageSurfaceAlpha[i] << 24; - mImageSurfaceBuf[i] = v; - } - } else { - PRInt32 i = 0; - for (PRInt32 row = 0; row < mHeight; ++row) { - for (PRInt32 col = 0; col < mWidth; ++col) { - PRInt32 index = row*mWidth + col; - PRInt32 v = mImageSurfaceBuf[index] & 0xFFFFFF; - PRUint8 mask = 1 << (7 - (col&7)); - if (mImageSurfaceAlpha[i] & mask) { - v |= 0xFF000000; - } - mImageSurfaceBuf[index] = v; - if (mask == 0x01) { - ++i; - } - } - if (mWidth & 7) { - ++i; - } - } - } - - nsMemory::Free(mImageSurfaceAlpha); - mImageSurfaceAlpha = nsnull; - mHadAnyAlphaValues = PR_TRUE; - } else { - NS_ASSERTION(mImageSurfaceData, "had not locked pixels"); - for (PRInt32 i = 0; i < count; ++i) { - ThreeChannelToARGB(&mImageSurfaceData[i*3], &mImageSurfaceBuf[i]); - } - nsMemory::Free(mImageSurfaceData); - mImageSurfaceData = nsnull; - mHadAnyPixelValues = PR_TRUE; - } return NS_OK; } diff --git a/mozilla/gfx/src/cairo/nsCairoImage.h b/mozilla/gfx/src/cairo/nsCairoImage.h index f1c9656382e..9aab44079b4 100644 --- a/mozilla/gfx/src/cairo/nsCairoImage.h +++ b/mozilla/gfx/src/cairo/nsCairoImage.h @@ -88,6 +88,8 @@ public: NS_IMETHOD LockImagePixels(PRBool aMaskPixels); NS_IMETHOD UnlockImagePixels(PRBool aMaskPixels); + void UpdateFromImageData(); + protected: PRInt32 mWidth; PRInt32 mHeight; @@ -97,13 +99,13 @@ protected: cairo_format_t mCairoFormat; // Where the mImageSurface data lives (in the mCairoFormat) PRUint32* mImageSurfaceBuf; - // Where gfxIImageFrame data lives temporarily during LockImagePixels + // Where gfxIImageFrame data lives while the image data is dirty + // (from LockImagePixels(Alpha) to the next paint) PRUint8* mImageSurfaceData; PRUint8* mImageSurfaceAlpha; PRUint8 mAlphaDepth; - PRPackedBool mHadAnyAlphaValues; - PRPackedBool mHadAnyPixelValues; + PRPackedBool mHadAnyData; }; #endif // NSCAIROIMAGE__H__ diff --git a/mozilla/gfx/src/cairo/nsCairoRenderingContext.cpp b/mozilla/gfx/src/cairo/nsCairoRenderingContext.cpp index 0de919ecf0f..af62e0f8b40 100644 --- a/mozilla/gfx/src/cairo/nsCairoRenderingContext.cpp +++ b/mozilla/gfx/src/cairo/nsCairoRenderingContext.cpp @@ -205,6 +205,7 @@ nsCairoRenderingContext::PushTranslation(PushedTranslation* aState) { // XXX this is slow! PushState(); + return NS_OK; } NS_IMETHODIMP @@ -212,6 +213,7 @@ nsCairoRenderingContext::PopTranslation(PushedTranslation* aState) { // XXX this is slow! PopState(); + return NS_OK; } NS_IMETHODIMP @@ -896,18 +898,6 @@ nsCairoRenderingContext::DrawTile(imgIContainer *aImage, nscoord aXOffset, nscoord aYOffset, const nsRect * aTargetRect) { - // from nsRenderingContextImpl.cpp - - nsRect dr(*aTargetRect); - double x = dr.x, y = dr.y, w = dr.width, h = dr.height; - cairo_transform_point(mCairo, &x, &y); - cairo_transform_distance(mCairo, &w, &h); - dr.x = (int) x; dr.y = (int) y; dr.width = (int) w; dr.height = (int) h; - - x = aXOffset; y = aYOffset; - cairo_transform_point(mCairo, &x, &y); - aXOffset = (int) x; aYOffset = (int) y; - nscoord width, height; aImage->GetWidth(&width); aImage->GetHeight(&height); @@ -915,9 +905,6 @@ nsCairoRenderingContext::DrawTile(imgIContainer *aImage, if (width == 0 || height == 0) return PR_FALSE; - nscoord xOffset = (dr.x - aXOffset) % width; - nscoord yOffset = (dr.y - aYOffset) % height; - nsCOMPtr iframe; aImage->GetCurrentFrame(getter_AddRefs(iframe)); if (!iframe) return NS_ERROR_FAILURE; @@ -925,16 +912,24 @@ nsCairoRenderingContext::DrawTile(imgIContainer *aImage, nsCOMPtr img(do_GetInterface(iframe)); if (!img) return NS_ERROR_FAILURE; - /* bug 113561 - frame can be smaller than container */ + // For Bug 87819 + // iframe may want image to start at different position, so adjust nsRect iframeRect; iframe->GetRect(iframeRect); + + // offsets are always in appunits, they have + // nothing to do with the current transform + float app2dev; + app2dev = mDeviceContext->AppUnitsToDevUnits(); + nsPoint s; + s.x = NSToIntRound(app2dev*aXOffset); + s.y = NSToIntRound(app2dev*aYOffset); + PRInt32 padx = width - iframeRect.width; PRInt32 pady = height - iframeRect.height; - return img->DrawTile(*this, mDrawingSurface, - xOffset - iframeRect.x, yOffset - iframeRect.y, - padx, pady, - dr); + return img->DrawTile(*this, mDrawingSurface, s.x - iframeRect.x, s.y - iframeRect.y, + padx, pady, *aTargetRect); } //