--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -220,16 +220,24 @@ ThebesLayerBuffer::PaintState
ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
float aXResolution, float aYResolution,
PRUint32 aFlags)
{
PaintState result;
result.mDidSelfCopy = PR_FALSE;
float curXRes = aLayer->GetXResolution();
float curYRes = aLayer->GetYResolution();
+ // If we have non-identity resolution then mBufferRotation might not fall
+ // on a buffer pixel boundary, in which case that row of pixels will contain
+ // a mix of two completely different rows of the layer, which would be
+ // a catastrophe. So disable rotation in that case.
+ // We also need to disable rotation if we're going to be resampled when
+ // drawing, because we might sample across the rotation boundary.
+ PRBool canHaveRotation =
+ !(aFlags & PAINT_WILL_RESAMPLE) && aXResolution == 1.0 && aYResolution == 1.0;
nsIntRegion validRegion = aLayer->GetValidRegion();
ContentType contentType;
nsIntRegion neededRegion;
nsIntSize destBufferDims;
PRBool canReuseBuffer;
nsIntRect destBufferRect;
@@ -294,27 +302,20 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
NS_ASSERTION(destBufferRect.Contains(neededRegion.GetBounds()),
"Destination rect doesn't contain what we need to paint");
result.mRegionToDraw.Sub(neededRegion, validRegion);
if (result.mRegionToDraw.IsEmpty())
return result;
- // If we have non-identity resolution then mBufferRotation might not fall
- // on a buffer pixel boundary, in which case that row of pixels will contain
- // a mix of two completely different rows of the layer, which would be
- // a catastrophe. So disable rotation in that case.
- // We also need to disable rotation if we're going to be resampled when
- // drawing, because we might sample across the rotation boundary.
- PRBool canHaveRotation =
- !(aFlags & PAINT_WILL_RESAMPLE) && aXResolution == 1.0 && aYResolution == 1.0;
nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
nsRefPtr<gfxASurface> destBuffer;
PRBool bufferDimsChanged = PR_FALSE;
+ PRUint32 bufferFlags = canHaveRotation ? ALLOW_REPEAT : 0;
if (canReuseBuffer) {
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
"resolution changes must Clear()!");
nsIntRect keepArea;
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
// Set mBufferRotation so that the pixels currently in mBuffer
// will still be rendered in the right place when mBufferRect
@@ -339,38 +340,36 @@ ThebesLayerBuffer::BeginPaint(ThebesLaye
MovePixels(mBuffer, srcRect, dest, curXRes, curYRes);
result.mDidSelfCopy = PR_TRUE;
// Don't set destBuffer; we special-case self-copies, and
// just did the necessary work above.
mBufferRect = destBufferRect;
} else {
// We can't do a real self-copy because the buffer is rotated.
// So allocate a new buffer for the destination.
- destBufferRect = neededRegion.GetBounds();
bufferDimsChanged = PR_TRUE;
- destBuffer = CreateBuffer(contentType, destBufferDims);
+ destBuffer = CreateBuffer(contentType, destBufferDims, bufferFlags);
if (!destBuffer)
return result;
}
} else {
mBufferRect = destBufferRect;
mBufferRotation = newRotation;
}
} else {
// No pixels are going to be kept. The whole visible region
// will be redrawn, so we don't need to copy anything, so we don't
// set destBuffer.
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
}
} else {
// The buffer's not big enough, so allocate a new one
- destBufferRect = neededRegion.GetBounds();
bufferDimsChanged = PR_TRUE;
- destBuffer = CreateBuffer(contentType, destBufferDims);
+ destBuffer = CreateBuffer(contentType, destBufferDims, bufferFlags);
if (!destBuffer)
return result;
}
NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
"If we're resampling, we need to validate the entire buffer");
// If we have no buffered data already, then destBuffer will be a fresh buffer
// and we do not need to clear it below.
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -47,28 +47,34 @@
#include "gfxTeeSurface.h"
namespace mozilla {
namespace layers {
using gl::GLContext;
using gl::TextureImage;
+static const int ALLOW_REPEAT = ThebesLayerBuffer::ALLOW_REPEAT;
+
// BindAndDrawQuadWithTextureRect can work with either GL_REPEAT (preferred)
-// or GL_CLAMP_TO_EDGE textures. We select based on whether REPEAT is
-// valid for non-power-of-two textures -- if we have NPOT support we use it,
-// otherwise we stick with CLAMP_TO_EDGE and decompose.
+// or GL_CLAMP_TO_EDGE textures. If ALLOW_REPEAT is set in aFlags, we
+// select based on whether REPEAT is valid for non-power-of-two textures --
+// if we have NPOT support we use it, otherwise we stick with CLAMP_TO_EDGE and
+// decompose.
+// If ALLOW_REPEAT is not set, we always use GL_CLAMP_TO_EDGE.
static already_AddRefed<TextureImage>
CreateClampOrRepeatTextureImage(GLContext *aGl,
const nsIntSize& aSize,
- TextureImage::ContentType aContentType)
+ TextureImage::ContentType aContentType,
+ PRUint32 aFlags)
{
GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
- if (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
- aGl->IsExtensionSupported(GLContext::OES_texture_npot))
+ if ((aFlags & ALLOW_REPEAT) &&
+ (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
+ aGl->IsExtensionSupported(GLContext::OES_texture_npot)))
{
wrapMode = LOCAL_GL_REPEAT;
}
return aGl->CreateTextureImage(aSize, aContentType, wrapMode);
}
// |aTexCoordRect| is the rectangle from the texture that we want to
@@ -158,19 +164,21 @@ public:
typedef ThebesLayerBuffer::PaintState PaintState;
ThebesLayerBufferOGL(ThebesLayer* aLayer, LayerOGL* aOGLLayer)
: mLayer(aLayer)
, mOGLLayer(aOGLLayer)
{}
virtual ~ThebesLayerBufferOGL() {}
+ enum { PAINT_WILL_RESAMPLE = ThebesLayerBuffer::PAINT_WILL_RESAMPLE };
virtual PaintState BeginPaint(ContentType aContentType,
float aXResolution,
- float aYResolution) = 0;
+ float aYResolution,
+ PRUint32 aFlags) = 0;
void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager);
nsIntSize GetSize() {
if (mTexImage)
return mTexImage->GetSize();
return nsIntSize(0, 0);
}
@@ -235,17 +243,17 @@ ThebesLayerBufferOGL::RenderTo(const nsI
alphaProgram->Activate();
alphaProgram->SetBlackTextureUnit(0);
alphaProgram->SetWhiteTextureUnit(1);
program = alphaProgram;
} else {
// Note BGR: Cairo's image surfaces are always in what
// OpenGL and our shaders consider BGR format.
ColorTextureLayerProgram *basicProgram =
- aManager->GetBasicLayerProgram(mLayer->CanUseOpaqueSurface(),
+ aManager->GetBasicLayerProgram(mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR,
mTexImage->IsRGB());
basicProgram->Activate();
basicProgram->SetTextureUnit(0);
program = basicProgram;
}
program->SetLayerOpacity(mLayer->GetEffectiveOpacity());
@@ -293,33 +301,34 @@ public:
, ThebesLayerBuffer(SizedToVisibleBounds)
{
}
virtual ~SurfaceBufferOGL() {}
// ThebesLayerBufferOGL interface
virtual PaintState BeginPaint(ContentType aContentType,
float aXResolution,
- float aYResolution)
+ float aYResolution,
+ PRUint32 aFlags)
{
// Let ThebesLayerBuffer do all the hard work for us! :D
return ThebesLayerBuffer::BeginPaint(mLayer,
aContentType,
aXResolution,
aYResolution,
- 0);
+ aFlags);
}
// ThebesLayerBuffer interface
virtual already_AddRefed<gfxASurface>
- CreateBuffer(ContentType aType, const nsIntSize& aSize)
+ CreateBuffer(ContentType aType, const nsIntSize& aSize, PRUint32 aFlags)
{
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
- mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType);
+ mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType, aFlags);
return mTexImage ? mTexImage->GetBackingSurface() : nsnull;
}
protected:
virtual nsIntPoint GetOriginOffset() {
return BufferRect().TopLeft() - BufferRotation();
}
};
@@ -336,17 +345,18 @@ public:
: ThebesLayerBufferOGL(aLayer, aLayer)
, mBufferRect(0,0,0,0)
, mBufferRotation(0,0)
{}
virtual ~BasicBufferOGL() {}
virtual PaintState BeginPaint(ContentType aContentType,
float aXResolution,
- float aYResolution);
+ float aYResolution,
+ PRUint32 aFlags);
protected:
enum XSide {
LEFT, RIGHT
};
enum YSide {
TOP, BOTTOM
};
@@ -403,143 +413,196 @@ ScaledSize(const nsIntSize& aSize, float
nsIntRect rect(0, 0, aSize.width, aSize.height);
rect.ScaleRoundOut(aXScale, aYScale);
return rect.Size();
}
BasicBufferOGL::PaintState
BasicBufferOGL::BeginPaint(ContentType aContentType,
float aXResolution,
- float aYResolution)
+ float aYResolution,
+ PRUint32 aFlags)
{
PaintState result;
-
- result.mRegionToDraw.Sub(mLayer->GetVisibleRegion(), mLayer->GetValidRegion());
-
float curXRes = mLayer->GetXResolution();
float curYRes = mLayer->GetYResolution();
- Layer::SurfaceMode mode = mLayer->GetSurfaceMode();
+ // If we have non-identity resolution then mBufferRotation might not fall
+ // on a buffer pixel boundary, in which case that row of pixels will contain
+ // a mix of two completely different rows of the layer, which would be
+ // a catastrophe. So disable rotation in that case.
+ // We also need to disable rotation if we're going to be resampled when
+ // drawing, because we might sample across the rotation boundary.
+ PRBool canHaveRotation =
+ !(aFlags & PAINT_WILL_RESAMPLE) && aXResolution == 1.0 && aYResolution == 1.0;
+
+ nsIntRegion validRegion = mLayer->GetValidRegion();
+
+ Layer::SurfaceMode mode;
+ ContentType contentType;
+ nsIntRegion neededRegion;
+ nsIntSize destBufferDims;
+ PRBool canReuseBuffer;
+ nsIntRect destBufferRect;
- if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
+ while (PR_TRUE) {
+ mode = mLayer->GetSurfaceMode();
+ contentType = aContentType;
+ neededRegion = mLayer->GetVisibleRegion();
+ destBufferDims = ScaledSize(neededRegion.GetBounds().Size(),
+ aXResolution, aYResolution);
+ // If we're going to resample, we need a buffer that's in clamp mode.
+ canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() &&
+ mTexImage &&
+ (!(aFlags & PAINT_WILL_RESAMPLE) ||
+ mTexImage->GetWrapMode() == LOCAL_GL_CLAMP_TO_EDGE);
+
+ if (canReuseBuffer) {
+ if (mBufferRect.Contains(neededRegion.GetBounds())) {
+ // We don't need to adjust mBufferRect.
+ destBufferRect = mBufferRect;
+ } else {
+ // The buffer's big enough but doesn't contain everything that's
+ // going to be visible. We'll move it.
+ destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
+ }
+ } else {
+ destBufferRect = neededRegion.GetBounds();
+ }
+
+ if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
- mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
+ mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
#else
- if (!mLayer->GetParent() || !mLayer->GetParent()->SupportsComponentAlphaChildren()) {
- mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
- } else {
- aContentType = gfxASurface::CONTENT_COLOR;
+ if (!mLayer->GetParent() || !mLayer->GetParent()->SupportsComponentAlphaChildren()) {
+ mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
+ } else {
+ contentType = gfxASurface::CONTENT_COLOR;
+ }
+ #endif
+ }
+
+ if ((aFlags & PAINT_WILL_RESAMPLE) &&
+ (neededRegion.GetBounds() != destBufferRect ||
+ neededRegion.GetNumRects() > 1)) {
+ // The area we add to neededRegion might not be painted opaquely
+ if (mode == Layer::SURFACE_OPAQUE) {
+ contentType = gfxASurface::CONTENT_COLOR_ALPHA;
+ mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
+ }
+ // For component alpha layers, we leave contentType as CONTENT_COLOR.
+
+ // We need to validate the entire buffer, to make sure that only valid
+ // pixels are sampled
+ neededRegion = destBufferRect;
+ destBufferDims = ScaledSize(neededRegion.GetBounds().Size(),
+ aXResolution, aYResolution);
}
-#endif
+
+ if (mTexImage &&
+ (mTexImage->GetContentType() != contentType ||
+ aXResolution != curXRes || aYResolution != curYRes ||
+ (mode == Layer::SURFACE_COMPONENT_ALPHA) != (mTexImageOnWhite != nsnull))) {
+ // We're effectively clearing the valid region, so we need to draw
+ // the entire needed region now.
+ //
+ // XXX/cjones: a possibly worthwhile optimization to keep in mind
+ // is to re-use buffers when the resolution and visible region
+ // have changed in such a way that the buffer size stays the same.
+ // It might make even more sense to allocate buffers from a
+ // recyclable pool, so that we could keep this logic simple and
+ // still get back the same buffer.
+ result.mRegionToInvalidate = mLayer->GetValidRegion();
+ validRegion.SetEmpty();
+ mTexImage = nsnull;
+ mTexImageOnWhite = nsnull;
+ mBufferRect.SetRect(0, 0, 0, 0);
+ mBufferRotation.MoveTo(0, 0);
+ // Restart decision process with the cleared buffer. We can only go
+ // around the loop one more iteration, since mTexImage is null now.
+ continue;
+ }
+
+ break;
}
- if (!mTexImage || mTexImage->GetContentType() != aContentType ||
- aXResolution != curXRes || aYResolution != curYRes ||
- (mode == Layer::SURFACE_COMPONENT_ALPHA) != (mTexImageOnWhite != nsnull)) {
- // We're effectively clearing the valid region, so we need to draw
- // the entire visible region now.
- //
- // XXX/cjones: a possibly worthwhile optimization to keep in mind
- // is to re-use buffers when the resolution and visible region
- // have changed in such a way that the buffer size stays the same.
- // It might make even more sense to allocate buffers from a
- // recyclable pool, so that we could keep this logic simple and
- // still get back the same buffer.
- result.mRegionToDraw = mLayer->GetVisibleRegion();
- result.mRegionToInvalidate = mLayer->GetValidRegion();
- mTexImage = nsnull;
- mTexImageOnWhite = nsnull;
- mBufferRect.SetRect(0, 0, 0, 0);
- mBufferRotation.MoveTo(0, 0);
- }
-
+ result.mRegionToDraw.Sub(neededRegion, validRegion);
if (result.mRegionToDraw.IsEmpty())
return result;
- nsIntRect visibleBounds = mLayer->GetVisibleRegion().GetBounds();
- nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
- nsIntSize destBufferDims = ScaledSize(visibleBounds.Size(),
- aXResolution, aYResolution);
-
if (destBufferDims.width > gl()->GetMaxTextureSize() ||
destBufferDims.height > gl()->GetMaxTextureSize()) {
return result;
}
+ nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
nsRefPtr<TextureImage> destBuffer;
nsRefPtr<TextureImage> destBufferOnWhite;
- nsIntRect destBufferRect;
- if (visibleBounds.Size() <= mBufferRect.Size()) {
+ PRUint32 bufferFlags = canHaveRotation ? ALLOW_REPEAT : 0;
+ if (canReuseBuffer) {
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
"resolution changes must clear the buffer!");
- // The current buffer is big enough to hold the visible area.
- if (mBufferRect.Contains(visibleBounds)) {
- // We don't need to adjust mBufferRect.
- destBufferRect = mBufferRect;
- } else {
- // The buffer's big enough but doesn't contain everything that's
- // going to be visible. We'll move it.
- destBufferRect = nsIntRect(visibleBounds.TopLeft(), mBufferRect.Size());
- }
+
nsIntRect keepArea;
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
// Set mBufferRotation so that the pixels currently in mBuffer
// will still be rendered in the right place when mBufferRect
// changes to destBufferRect.
nsIntPoint newRotation = mBufferRotation +
(destBufferRect.TopLeft() - mBufferRect.TopLeft());
WrapRotationAxis(&newRotation.x, mBufferRect.width);
WrapRotationAxis(&newRotation.y, mBufferRect.height);
NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
"newRotation out of bounds");
PRInt32 xBoundary = destBufferRect.XMost() - newRotation.x;
PRInt32 yBoundary = destBufferRect.YMost() - newRotation.y;
if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
- (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost())) {
+ (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
+ (newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
// The stuff we need to redraw will wrap around an edge of the
// buffer, so we will need to do a self-copy
// If mBufferRotation == nsIntPoint(0,0) we could do a real
// self-copy but we're not going to do that in GL yet.
// We can't do a real self-copy because the buffer is rotated.
// So allocate a new buffer for the destination.
- destBufferRect = visibleBounds;
- destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType);
+ destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
if (!destBuffer)
return result;
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
destBufferOnWhite =
- CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType);
+ CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
if (!destBufferOnWhite)
return result;
}
} else {
mBufferRect = destBufferRect;
mBufferRotation = newRotation;
}
} else {
// No pixels are going to be kept. The whole visible region
// will be redrawn, so we don't need to copy anything, so we don't
// set destBuffer.
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
}
} else {
// The buffer's not big enough, so allocate a new one
- destBufferRect = visibleBounds;
- destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType);
+ destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
if (!destBuffer)
return result;
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
destBufferOnWhite =
- CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType);
+ CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
if (!destBufferOnWhite)
return result;
}
}
+ NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || destBufferRect == neededRegion.GetBounds(),
+ "If we're resampling, we need to validate the entire buffer");
if (!destBuffer && !mTexImage) {
return result;
}
if (destBuffer) {
if (mTexImage && (mode != Layer::SURFACE_COMPONENT_ALPHA || mTexImageOnWhite)) {
// BlitTextureImage depends on the FBO texture target being
@@ -561,32 +624,33 @@ BasicBufferOGL::BeginPaint(ContentType a
destBuffer, dstRect);
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
destBufferOnWhite->Resize(size);
gl()->BlitTextureImage(mTexImageOnWhite, srcRect,
destBufferOnWhite, dstRect);
}
} else {
// can't blit, just draw everything
- destBufferRect = visibleBounds;
- destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType);
+ destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
destBufferOnWhite =
- CreateClampOrRepeatTextureImage(gl(), destBufferDims, aContentType);
+ CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
}
}
}
mTexImage = destBuffer.forget();
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
mTexImageOnWhite = destBufferOnWhite.forget();
}
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
}
+ NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
+ "Rotation disabled, but we have nonzero rotation?");
nsIntRegion invalidate;
invalidate.Sub(mLayer->GetValidRegion(), destBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
// Figure out which quadrant to draw in
PRInt32 xBoundary = mBufferRect.XMost() - mBufferRotation.x;
PRInt32 yBoundary = mBufferRect.YMost() - mBufferRotation.y;
@@ -626,17 +690,17 @@ BasicBufferOGL::BeginPaint(ContentType a
// be incorrect.
surf->SetAllowUseAsSource(PR_FALSE);
result.mContext = new gfxContext(surf);
} else {
result.mContext = new gfxContext(mTexImage->BeginUpdate(result.mRegionToDraw));
if (mTexImage->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);
- result.mContext->Fill();
+ result.mContext->Paint();
result.mContext->SetOperator(gfxContext::OPERATOR_OVER);
}
}
if (!result.mContext) {
NS_WARNING("unable to get context for update");
return result;
}
result.mContext->Scale(aXResolution, aYResolution);
@@ -717,26 +781,35 @@ ThebesLayerOGL::RenderLayer(int aPreviou
mOGLManager->MakeCurrent();
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
TextureImage::ContentType contentType =
CanUseOpaqueSurface() ? gfxASurface::CONTENT_COLOR :
gfxASurface::CONTENT_COLOR_ALPHA;
- const gfx3DMatrix& transform = GetEffectiveTransform();
gfxMatrix transform2d;
gfxSize scale(1.0, 1.0);
- if (transform.Is2D(&transform2d)) {
+ float paintXRes = 1.0;
+ float paintYRes = 1.0;
+ PRUint32 flags = 0;
+ if (GetEffectiveTransform().Is2D(&transform2d)) {
scale = transform2d.ScaleFactors(PR_TRUE);
+ paintXRes = gfxUtils::ClampToScaleFactor(scale.width);
+ paintYRes = gfxUtils::ClampToScaleFactor(scale.height);
+ transform2d.Scale(1.0/paintXRes, 1.0/paintYRes);
+ if (transform2d.HasNonIntegerTranslation()) {
+ flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
+ }
+ } else {
+ flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
}
- float paintXRes = gfxUtils::ClampToScaleFactor(scale.width);
- float paintYRes = gfxUtils::ClampToScaleFactor(scale.height);
- Buffer::PaintState state = mBuffer->BeginPaint(contentType, paintXRes, paintYRes);
+ Buffer::PaintState state =
+ mBuffer->BeginPaint(contentType, paintXRes, paintYRes, flags);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
if (state.mContext) {
state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
mXResolution = paintXRes;
mYResolution = paintYRes;
LayerManager::DrawThebesLayerCallback callback =
@@ -782,29 +855,22 @@ ThebesLayerOGL::IsEmpty()
class ShadowBufferOGL : public ThebesLayerBufferOGL
{
public:
ShadowBufferOGL(ShadowThebesLayerOGL* aLayer)
: ThebesLayerBufferOGL(aLayer, aLayer)
{}
- virtual PaintState BeginPaint(ContentType aContentType, float, float) {
+ virtual PaintState BeginPaint(ContentType aContentType,
+ float, float, PRUint32) {
NS_RUNTIMEABORT("can't BeginPaint for a shadow layer");
return PaintState();
}
- void
- CreateTexture(ContentType aType, const nsIntSize& aSize)
- {
- NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");
-
- mTexImage = CreateClampOrRepeatTextureImage(gl(), aSize, aType);
- }
-
void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
const nsIntRect& aRect, const nsIntPoint& aRotation);
protected:
virtual nsIntPoint GetOriginOffset() {
return mBufferRect.TopLeft() - mBufferRotation;
}
@@ -814,18 +880,20 @@ private:
};
void
ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
const nsIntRect& aRect, const nsIntPoint& aRotation)
{
gfxIntSize size = aUpdate->GetSize();
if (GetSize() != nsIntSize(size.width, size.height)) {
- CreateTexture(aUpdate->GetContentType(),
- nsIntSize(size.width, size.height));
+ // XXX we should do something here to decide whether to use REPEAT or not,
+ // but I'm not sure what
+ mTexImage = CreateClampOrRepeatTextureImage(gl(),
+ nsIntSize(size.width, size.height), aUpdate->GetContentType(), ALLOW_REPEAT);
}
nsIntRegion destRegion(aUpdated);
// aUpdated is in screen coordinates. Move it so that the layer's
// top-left is 0,0
nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft();
destRegion.MoveBy(-visTopLeft);