From 3c6147ff53a04a00592da689869f462be130f041 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Tue, 8 May 2012 04:31:30 +0200 Subject: [PATCH] Bug 732985 - Part 2: Use ImageScaler for large images. r=jrmuizel --- gfx/2d/DrawTargetD2D.cpp | 61 +++++++++++++++++++++++++++++++------ gfx/2d/SourceSurfaceD2D.cpp | 8 +++-- gfx/2d/SourceSurfaceD2D.h | 2 +- gfx/2d/Tools.h | 15 +++++++++ 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/gfx/2d/DrawTargetD2D.cpp b/gfx/2d/DrawTargetD2D.cpp index a0e8f45f5ce..3ccc97d1ca3 100644 --- a/gfx/2d/DrawTargetD2D.cpp +++ b/gfx/2d/DrawTargetD2D.cpp @@ -42,6 +42,7 @@ #include "PathD2D.h" #include "GradientStopsD2D.h" #include "ScaledFontDWrite.h" +#include "ImageScaling.h" #include "Logging.h" #include "Tools.h" #include @@ -289,7 +290,7 @@ DrawTargetD2D::DrawSurface(SourceSurface *aSurface, int stride = srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()); - unsigned char *data = &srcSurf->mRawData.front() + + unsigned char *data = srcSurf->mRawData + (uint32_t)aSource.y * stride + (uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat()); @@ -1982,8 +1983,8 @@ DrawTargetD2D::CreatePartialBitmapForSurface(SourceSurfaceD2D *aSurface, Matrix // or downsample in software. Matrix transform = mTransform; - transform = aMatrix * transform; - if (!transform.Invert()) { + Matrix invTransform = transform = aMatrix * transform; + if (!invTransform.Invert()) { // Singular transform, nothing to be drawn. return NULL; } @@ -1991,7 +1992,7 @@ DrawTargetD2D::CreatePartialBitmapForSurface(SourceSurfaceD2D *aSurface, Matrix Rect rect(0, 0, mSize.width, mSize.height); // Calculate the rectangle of the source mapped to our surface. - rect = transform.TransformBounds(rect); + rect = invTransform.TransformBounds(rect); rect.RoundOut(); Rect uploadRect(0, 0, aSurface->mSize.width, aSurface->mSize.height); @@ -2014,19 +2015,59 @@ DrawTargetD2D::CreatePartialBitmapForSurface(SourceSurfaceD2D *aSurface, Matrix // A partial upload will suffice. mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)), - &aSurface->mRawData.front() + int(uploadRect.x) + int(uploadRect.y) * stride, + aSurface->mRawData + int(uploadRect.x) * 4 + int(uploadRect.y) * stride, stride, D2D1::BitmapProperties(D2DPixelFormat(aSurface->mFormat)), byRef(bitmap)); - aMatrix.Translate(-uploadRect.x, -uploadRect.y); + aMatrix.Translate(uploadRect.x, uploadRect.y); return bitmap; } else { - // XXX - FIX ME!! - MOZ_ASSERT(false); - gfxDebug() << "Source surface used for pattern too large!"; - return NULL; + int Bpp = BytesPerPixel(aSurface->mFormat); + + if (Bpp != 4) { + // This shouldn't actually happen in practice! + MOZ_ASSERT(false); + return NULL; + } + + int stride = Bpp * aSurface->mSize.width; + + ImageHalfScaler scaler(aSurface->mRawData, stride, IntSize(aSurface->mSize)); + + // Calculate the maximum width/height of the image post transform. + Point topRight = transform * Point(aSurface->mSize.width, 0); + Point topLeft = transform * Point(0, 0); + Point bottomRight = transform * Point(aSurface->mSize.width, aSurface->mSize.height); + Point bottomLeft = transform * Point(0, aSurface->mSize.height); + + IntSize scaleSize; + + scaleSize.width = max(Distance(topRight, topLeft), Distance(bottomRight, bottomLeft)); + scaleSize.height = max(Distance(topRight, bottomRight), Distance(topLeft, bottomLeft)); + + if (scaleSize.width > mRT->GetMaximumBitmapSize()) { + // Ok, in this case we'd really want a downscale of a part of the bitmap, + // perhaps we can do this later but for simplicity let's do something + // different here and assume it's good enough, this should be rare! + scaleSize.width = 4095; + } + if (scaleSize.height > mRT->GetMaximumBitmapSize()) { + scaleSize.height = 4095; + } + + scaler.ScaleForSize(scaleSize); + + IntSize newSize = scaler.GetSize(); + + mRT->CreateBitmap(D2D1::SizeU(newSize.width, newSize.height), + scaler.GetScaledData(), scaler.GetStride(), + D2D1::BitmapProperties(D2DPixelFormat(aSurface->mFormat)), + byRef(bitmap)); + + aMatrix.Scale(aSurface->mSize.width / newSize.width, aSurface->mSize.height / newSize.height); + return bitmap; } } diff --git a/gfx/2d/SourceSurfaceD2D.cpp b/gfx/2d/SourceSurfaceD2D.cpp index 977de8bd53d..2ff4c4e5cc7 100644 --- a/gfx/2d/SourceSurfaceD2D.cpp +++ b/gfx/2d/SourceSurfaceD2D.cpp @@ -42,11 +42,13 @@ namespace mozilla { namespace gfx { SourceSurfaceD2D::SourceSurfaceD2D() + : mRawData(NULL) { } SourceSurfaceD2D::~SourceSurfaceD2D() { + delete [] mRawData; } IntSize @@ -82,9 +84,11 @@ SourceSurfaceD2D::InitFromData(unsigned char *aData, if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() || (uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) { int newStride = BytesPerPixel(aFormat) * aSize.width; - mRawData.resize(aSize.height * newStride); + // This should only be called once! + MOZ_ASSERT(!mRawData); + mRawData = new uint8_t[aSize.height * newStride]; for (int y = 0; y < aSize.height; y++) { - memcpy(&mRawData.front() + y * newStride, aData + y * aStride, newStride); + memcpy(mRawData + y * newStride, aData + y * aStride, newStride); } gfxDebug() << "Bitmap does not fit in texture, saving raw data."; return true; diff --git a/gfx/2d/SourceSurfaceD2D.h b/gfx/2d/SourceSurfaceD2D.h index d322bb07a91..06cb5d70e44 100644 --- a/gfx/2d/SourceSurfaceD2D.h +++ b/gfx/2d/SourceSurfaceD2D.h @@ -71,7 +71,7 @@ private: friend class DrawTargetD2D; RefPtr mBitmap; - std::vector mRawData; + uint8_t *mRawData; SurfaceFormat mFormat; IntSize mSize; }; diff --git a/gfx/2d/Tools.h b/gfx/2d/Tools.h index 576bb2df6a3..77a830df6b3 100644 --- a/gfx/2d/Tools.h +++ b/gfx/2d/Tools.h @@ -66,6 +66,21 @@ struct ClassStorage T *addr() { return (T *)(void *)bytes; } }; +static inline bool +FuzzyEqual(Float aA, Float aB, Float aErr) +{ + if ((aA + aErr > aB) && (aA - aErr < aB)) { + return true; + } + return false; +} + +static inline Float +Distance(Point aA, Point aB) +{ + return hypotf(aB.x - aA.x, aB.y - aA.y); +} + } }