зеркало из https://github.com/mozilla/pjs.git
Merge the last green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
39836938cc
|
@ -621,7 +621,7 @@ nsHTMLCanvasElement::InvalidateCanvasContent(const gfxRect* damageRect)
|
|||
if (!frame)
|
||||
return;
|
||||
|
||||
frame->MarkLayersActive();
|
||||
frame->MarkLayersActive(nsChangeHint(0));
|
||||
|
||||
nsRect invalRect;
|
||||
nsRect contentArea = frame->GetContentRect();
|
||||
|
|
|
@ -571,9 +571,6 @@ ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
|
|||
if (!mValidRegion.IsEmpty()) {
|
||||
AppendToString(aTo, mValidRegion, " [valid=", "]");
|
||||
}
|
||||
if (mXResolution != 1.0 || mYResolution != 1.0) {
|
||||
aTo.AppendPrintf(" [xres=%g yres=%g]", mXResolution, mYResolution);
|
||||
}
|
||||
return aTo;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ public:
|
|||
return mScrollId != NULL_SCROLL_ID;
|
||||
}
|
||||
|
||||
// These are all in layer coordinate space.
|
||||
nsIntRect mViewport;
|
||||
nsIntSize mContentSize;
|
||||
nsIntPoint mViewportScrollOffset;
|
||||
|
@ -943,13 +944,24 @@ public:
|
|||
* region.
|
||||
*/
|
||||
virtual void InvalidateRegion(const nsIntRegion& aRegion) = 0;
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* Set whether ComputeEffectiveTransforms should compute the
|
||||
* "residual translation" --- the translation that should be applied *before*
|
||||
* mEffectiveTransform to get the ideal transform for this ThebesLayer.
|
||||
* When this is true, ComputeEffectiveTransforms will compute the residual
|
||||
* and ensure that the layer is invalidated whenever the residual changes.
|
||||
* When it's false, a change in the residual will not trigger invalidation
|
||||
* and GetResidualTranslation will return 0,0.
|
||||
* So when the residual is to be ignored, set this to false for better
|
||||
* performance.
|
||||
*/
|
||||
void SetAllowResidualTranslation(bool aAllow) { mAllowResidualTranslation = aAllow; }
|
||||
|
||||
/**
|
||||
* Can be used anytime
|
||||
*/
|
||||
const nsIntRegion& GetValidRegion() const { return mValidRegion; }
|
||||
float GetXResolution() const { return mXResolution; }
|
||||
float GetYResolution() const { return mYResolution; }
|
||||
|
||||
virtual ThebesLayer* AsThebesLayer() { return this; }
|
||||
|
||||
|
@ -959,46 +971,63 @@ public:
|
|||
{
|
||||
// The default implementation just snaps 0,0 to pixels.
|
||||
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
|
||||
mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
|
||||
gfxMatrix residual;
|
||||
mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0),
|
||||
mAllowResidualTranslation ? &residual : nsnull);
|
||||
// The residual can only be a translation because ThebesLayer snapping
|
||||
// only aligns a single point with the pixel grid; scale factors are always
|
||||
// preserved exactly
|
||||
NS_ASSERTION(!residual.HasNonTranslation(),
|
||||
"Residual transform can only be a translation");
|
||||
if (residual.GetTranslation() != mResidualTranslation) {
|
||||
mResidualTranslation = residual.GetTranslation();
|
||||
NS_ASSERTION(-0.5 <= mResidualTranslation.x && mResidualTranslation.x < 0.5 &&
|
||||
-0.5 <= mResidualTranslation.y && mResidualTranslation.y < 0.5,
|
||||
"Residual translation out of range");
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
bool UsedForReadback() { return mUsedForReadback; }
|
||||
void SetUsedForReadback(bool aUsed) { mUsedForReadback = aUsed; }
|
||||
/**
|
||||
* Returns the residual translation. Apply this translation when drawing
|
||||
* into the ThebesLayer so that when mEffectiveTransform is applied afterwards
|
||||
* by layer compositing, the results exactly match the "ideal transform"
|
||||
* (the product of the transform of this layer and its ancestors).
|
||||
* Returns 0,0 unless SetAllowResidualTranslation(true) has been called.
|
||||
* The residual translation components are always in the range [-0.5, 0.5).
|
||||
*/
|
||||
gfxPoint GetResidualTranslation() const { return mResidualTranslation; }
|
||||
|
||||
protected:
|
||||
ThebesLayer(LayerManager* aManager, void* aImplData)
|
||||
: Layer(aManager, aImplData)
|
||||
, mValidRegion()
|
||||
, mXResolution(1.0)
|
||||
, mYResolution(1.0)
|
||||
, mUsedForReadback(false)
|
||||
, mAllowResidualTranslation(false)
|
||||
{
|
||||
mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT
|
||||
}
|
||||
|
||||
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
|
||||
|
||||
/**
|
||||
* ComputeEffectiveTransforms snaps the ideal transform to get mEffectiveTransform.
|
||||
* mResidualTranslation is the translation that should be applied *before*
|
||||
* mEffectiveTransform to get the ideal transform.
|
||||
*/
|
||||
gfxPoint mResidualTranslation;
|
||||
nsIntRegion mValidRegion;
|
||||
// Resolution values tell this to paint its content scaled by
|
||||
// <aXResolution, aYResolution>, into a backing buffer with
|
||||
// dimensions scaled the same. A non-1.0 resolution also tells this
|
||||
// to set scaling factors that compensate for the re-paint
|
||||
// resolution when rendering itself to render targets
|
||||
//
|
||||
// Resolution doesn't affect the visible region, valid region, or
|
||||
// re-painted regions at all. It only affects how scalable thebes
|
||||
// content is rasterized to device pixels.
|
||||
//
|
||||
// Setting the resolution isn't part of the public ThebesLayer API
|
||||
// because it's backend-specific, and it doesn't necessarily make
|
||||
// sense for all backends to fully support it.
|
||||
float mXResolution;
|
||||
float mYResolution;
|
||||
/**
|
||||
* Set when this ThebesLayer is participating in readback, i.e. some
|
||||
* ReadbackLayer (may) be getting its background from this layer.
|
||||
*/
|
||||
bool mUsedForReadback;
|
||||
/**
|
||||
* True when
|
||||
*/
|
||||
bool mAllowResidualTranslation;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,19 +45,6 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
static nsIntSize
|
||||
ScaledSize(const nsIntSize& aSize, float aXScale, float aYScale)
|
||||
{
|
||||
if (aXScale == 1.0 && aYScale == 1.0) {
|
||||
return aSize;
|
||||
}
|
||||
|
||||
gfxRect rect(0, 0, aSize.width, aSize.height);
|
||||
rect.Scale(aXScale, aYScale);
|
||||
rect.RoundOut();
|
||||
return nsIntSize(rect.Width(), rect.Height());
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
ThebesLayerBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide)
|
||||
{
|
||||
|
@ -82,8 +69,7 @@ ThebesLayerBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide)
|
|||
void
|
||||
ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
||||
XSide aXSide, YSide aYSide,
|
||||
float aOpacity,
|
||||
float aXRes, float aYRes)
|
||||
float aOpacity)
|
||||
{
|
||||
// The rectangle that we're going to fill. Basically we're going to
|
||||
// render the buffer at mBufferRect + quadrantTranslation to get the
|
||||
|
@ -111,19 +97,8 @@ ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
|||
|
||||
// Transform from user -> buffer space.
|
||||
gfxMatrix transform;
|
||||
transform.Scale(aXRes, aYRes);
|
||||
transform.Translate(-quadrantTranslation);
|
||||
|
||||
// in common cases the matrix after scaling by 1/aRes is close to 1.0,
|
||||
// so we want to make it 1.0 in both cases
|
||||
transform.Scale(1.0 / aXRes, 1.0 / aYRes);
|
||||
transform.NudgeToIntegers();
|
||||
|
||||
gfxMatrix ctxMatrix = aTarget->CurrentMatrix();
|
||||
ctxMatrix.Scale(1.0 / aXRes, 1.0 / aYRes);
|
||||
ctxMatrix.NudgeToIntegers();
|
||||
aTarget->SetMatrix(ctxMatrix);
|
||||
|
||||
pattern->SetMatrix(transform);
|
||||
aTarget->SetPattern(pattern);
|
||||
|
||||
|
@ -138,21 +113,18 @@ ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
|||
}
|
||||
|
||||
void
|
||||
ThebesLayerBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
|
||||
float aXRes, float aYRes)
|
||||
ThebesLayerBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity)
|
||||
{
|
||||
// Draw four quadrants. We could use REPEAT_, but it's probably better
|
||||
// not to, to be performance-safe.
|
||||
DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity, aXRes, aYRes);
|
||||
DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity, aXRes, aYRes);
|
||||
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity, aXRes, aYRes);
|
||||
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity, aXRes, aYRes);
|
||||
DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity);
|
||||
DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity);
|
||||
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity);
|
||||
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxContext>
|
||||
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds,
|
||||
float aXResolution,
|
||||
float aYResolution)
|
||||
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(mBuffer);
|
||||
|
||||
|
@ -163,49 +135,11 @@ ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds,
|
|||
YSide sideY = aBounds.YMost() <= yBoundary ? BOTTOM : TOP;
|
||||
nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
|
||||
NS_ASSERTION(quadrantRect.Contains(aBounds), "Messed up quadrants");
|
||||
ctx->Scale(aXResolution, aYResolution);
|
||||
ctx->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y));
|
||||
|
||||
return ctx.forget();
|
||||
}
|
||||
|
||||
// Move the pixels in aBuffer specified by |aSourceRect| to |aDest|.
|
||||
// |aSourceRect| and |aDest| are in the space of |aBuffer|, but
|
||||
// unscaled by the resolution. This helper does the scaling.
|
||||
static void
|
||||
MovePixels(gfxASurface* aBuffer,
|
||||
const nsIntRect& aSourceRect, const nsIntPoint& aDest,
|
||||
float aXResolution, float aYResolution)
|
||||
{
|
||||
gfxRect src(aSourceRect.x, aSourceRect.y, aSourceRect.width, aSourceRect.height);
|
||||
gfxRect dest(aDest.x, aDest.y, aSourceRect.width, aSourceRect.height);
|
||||
src.Scale(aXResolution, aYResolution);
|
||||
dest.Scale(aXResolution, aYResolution);
|
||||
|
||||
#ifdef DEBUG
|
||||
// If we're doing a self-copy, enforce that the rects we're copying
|
||||
// were computed in order to round to device pixels. If the rects
|
||||
// we're moving *weren't* computed to round, then glitches like
|
||||
// seaming are likely. Assume that the precision of these
|
||||
// computations is 1 app unit, and toss in a fudge factor of 2.0.
|
||||
static const gfxFloat kPrecision =
|
||||
1.0 / gfxFloat(nsDeviceContext::AppUnitsPerCSSPixel());
|
||||
// FIXME/bug 637852: we've decided to live with transient glitches
|
||||
// during fast-panning for the time being.
|
||||
NS_WARN_IF_FALSE(
|
||||
src.WithinEpsilonOfIntegerPixels(2.0 * kPrecision * aXResolution) &&
|
||||
dest.WithinEpsilonOfIntegerPixels(2.0 * kPrecision * aXResolution),
|
||||
"Rects don't round to device pixels within precision; glitches likely to follow");
|
||||
#endif
|
||||
|
||||
src.Round();
|
||||
dest.Round();
|
||||
|
||||
aBuffer->MovePixels(nsIntRect(src.X(), src.Y(),
|
||||
src.Width(), src.Height()),
|
||||
nsIntPoint(dest.X(), dest.Y()));
|
||||
}
|
||||
|
||||
static void
|
||||
WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize)
|
||||
{
|
||||
|
@ -218,36 +152,24 @@ WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize)
|
|||
|
||||
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
|
||||
// We 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;
|
||||
PRBool canHaveRotation = !(aFlags & PAINT_WILL_RESAMPLE);
|
||||
|
||||
nsIntRegion validRegion = aLayer->GetValidRegion();
|
||||
|
||||
ContentType contentType;
|
||||
nsIntRegion neededRegion;
|
||||
nsIntSize destBufferDims;
|
||||
PRBool canReuseBuffer;
|
||||
nsIntRect destBufferRect;
|
||||
|
||||
while (PR_TRUE) {
|
||||
contentType = aContentType;
|
||||
neededRegion = aLayer->GetVisibleRegion();
|
||||
destBufferDims = ScaledSize(neededRegion.GetBounds().Size(),
|
||||
aXResolution, aYResolution);
|
||||
canReuseBuffer = mBuffer && BufferSizeOkFor(destBufferDims);
|
||||
canReuseBuffer = mBuffer && BufferSizeOkFor(neededRegion.GetBounds().Size());
|
||||
|
||||
if (canReuseBuffer) {
|
||||
if (mBufferRect.Contains(neededRegion.GetBounds())) {
|
||||
|
@ -273,22 +195,11 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
// 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);
|
||||
}
|
||||
|
||||
if (mBuffer &&
|
||||
(contentType != mBuffer->GetContentType() ||
|
||||
aXResolution != curXRes || aYResolution != curYRes)) {
|
||||
if (mBuffer && contentType != mBuffer->GetContentType()) {
|
||||
// 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 = aLayer->GetValidRegion();
|
||||
validRegion.SetEmpty();
|
||||
Clear();
|
||||
|
@ -309,12 +220,8 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
|
||||
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
|
||||
|
@ -337,7 +244,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
if (mBufferRotation == nsIntPoint(0,0)) {
|
||||
nsIntRect srcRect(nsIntPoint(0, 0), mBufferRect.Size());
|
||||
nsIntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft();
|
||||
MovePixels(mBuffer, srcRect, dest, curXRes, curYRes);
|
||||
mBuffer->MovePixels(srcRect, dest);
|
||||
result.mDidSelfCopy = PR_TRUE;
|
||||
// Don't set destBuffer; we special-case self-copies, and
|
||||
// just did the necessary work above.
|
||||
|
@ -346,8 +253,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
// 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, bufferFlags);
|
||||
destBuffer = CreateBuffer(contentType, destBufferRect.Size(), bufferFlags);
|
||||
if (!destBuffer)
|
||||
return result;
|
||||
}
|
||||
|
@ -364,8 +270,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
}
|
||||
} else {
|
||||
// The buffer's not big enough, so allocate a new one
|
||||
bufferDimsChanged = PR_TRUE;
|
||||
destBuffer = CreateBuffer(contentType, destBufferDims, bufferFlags);
|
||||
destBuffer = CreateBuffer(contentType, destBufferRect.Size(), bufferFlags);
|
||||
if (!destBuffer)
|
||||
return result;
|
||||
}
|
||||
|
@ -382,20 +287,14 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBuffer);
|
||||
nsIntPoint offset = -destBufferRect.TopLeft();
|
||||
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
tmpCtx->Scale(aXResolution, aYResolution);
|
||||
tmpCtx->Translate(gfxPoint(offset.x, offset.y));
|
||||
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
|
||||
"resolution changes must Clear()!");
|
||||
DrawBufferWithRotation(tmpCtx, 1.0, aXResolution, aYResolution);
|
||||
DrawBufferWithRotation(tmpCtx, 1.0);
|
||||
}
|
||||
|
||||
mBuffer = destBuffer.forget();
|
||||
mBufferRect = destBufferRect;
|
||||
mBufferRotation = nsIntPoint(0,0);
|
||||
}
|
||||
if (bufferDimsChanged) {
|
||||
mBufferDims = destBufferDims;
|
||||
}
|
||||
NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
|
||||
"Rotation disabled, but we have nonzero rotation?");
|
||||
|
||||
|
@ -403,8 +302,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
|||
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
|
||||
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
|
||||
|
||||
result.mContext = GetContextForQuadrantUpdate(drawBounds,
|
||||
aXResolution, aYResolution);
|
||||
result.mContext = GetContextForQuadrantUpdate(drawBounds);
|
||||
|
||||
gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
|
||||
if (contentType == gfxASurface::CONTENT_COLOR_ALPHA && !isClear) {
|
||||
|
|
|
@ -82,8 +82,7 @@ public:
|
|||
};
|
||||
|
||||
ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
|
||||
: mBufferDims(0,0)
|
||||
, mBufferRotation(0,0)
|
||||
: mBufferRotation(0,0)
|
||||
, mBufferSizePolicy(aBufferSizePolicy)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ThebesLayerBuffer);
|
||||
|
@ -100,7 +99,6 @@ public:
|
|||
void Clear()
|
||||
{
|
||||
mBuffer = nsnull;
|
||||
mBufferDims.SizeTo(0, 0);
|
||||
mBufferRect.SetEmpty();
|
||||
}
|
||||
|
||||
|
@ -140,7 +138,6 @@ public:
|
|||
* fill the buffer bounds).
|
||||
*/
|
||||
PaintState BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
float aXResolution, float aYResolution,
|
||||
PRUint32 aFlags);
|
||||
|
||||
enum {
|
||||
|
@ -170,32 +167,23 @@ protected:
|
|||
};
|
||||
nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide);
|
||||
void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
|
||||
float aOpacity, float aXRes, float aYRes);
|
||||
void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
|
||||
float aXRes, float aYRes);
|
||||
float aOpacity);
|
||||
void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity);
|
||||
|
||||
/**
|
||||
* |BufferRect()| is the rect of device pixels that this
|
||||
* ThebesLayerBuffer covers. That is what DrawBufferWithRotation()
|
||||
* will paint when it's called.
|
||||
*
|
||||
* |BufferDims()| is the actual dimensions of the underlying surface
|
||||
* maintained by this, also in device pixels. It is *not*
|
||||
* necessarily true that |BufferRect().Size() == BufferDims()|.
|
||||
* They may differ if a ThebesLayer is drawn at a non-1.0
|
||||
* resolution.
|
||||
*/
|
||||
const nsIntSize& BufferDims() const { return mBufferDims; }
|
||||
const nsIntRect& BufferRect() const { return mBufferRect; }
|
||||
const nsIntPoint& BufferRotation() const { return mBufferRotation; }
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
SetBuffer(gfxASurface* aBuffer, const nsIntSize& aBufferDims,
|
||||
SetBuffer(gfxASurface* aBuffer,
|
||||
const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation)
|
||||
{
|
||||
nsRefPtr<gfxASurface> tmp = mBuffer.forget();
|
||||
mBuffer = aBuffer;
|
||||
mBufferDims = aBufferDims;
|
||||
mBufferRect = aBufferRect;
|
||||
mBufferRotation = aBufferRotation;
|
||||
return tmp.forget();
|
||||
|
@ -206,24 +194,17 @@ protected:
|
|||
* which must be contained within a single quadrant.
|
||||
*/
|
||||
already_AddRefed<gfxContext>
|
||||
GetContextForQuadrantUpdate(const nsIntRect& aBounds,
|
||||
float aXResolution, float aYResolution);
|
||||
GetContextForQuadrantUpdate(const nsIntRect& aBounds);
|
||||
|
||||
private:
|
||||
PRBool BufferSizeOkFor(const nsIntSize& aSize)
|
||||
{
|
||||
return (aSize == mBufferDims ||
|
||||
return (aSize == mBufferRect.Size() ||
|
||||
(SizedToVisibleBounds != mBufferSizePolicy &&
|
||||
aSize < mBufferDims));
|
||||
aSize < mBufferRect.Size()));
|
||||
}
|
||||
|
||||
nsRefPtr<gfxASurface> mBuffer;
|
||||
/**
|
||||
* The actual dimensions of mBuffer. For the ContainsVisibleBounds
|
||||
* policy or with resolution-scaled drawing, mBufferDims might be
|
||||
* different than mBufferRect.Size().
|
||||
*/
|
||||
nsIntSize mBufferDims;
|
||||
/** The area of the ThebesLayer that is covered by the buffer as a whole */
|
||||
nsIntRect mBufferRect;
|
||||
/**
|
||||
|
|
|
@ -416,19 +416,18 @@ public:
|
|||
void SetBackingBuffer(gfxASurface* aBuffer,
|
||||
const nsIntRect& aRect, const nsIntPoint& aRotation)
|
||||
{
|
||||
gfxIntSize prevSize = gfxIntSize(BufferDims().width, BufferDims().height);
|
||||
gfxIntSize prevSize = gfxIntSize(BufferRect().width, BufferRect().height);
|
||||
gfxIntSize newSize = aBuffer->GetSize();
|
||||
NS_ABORT_IF_FALSE(newSize == prevSize,
|
||||
"Swapped-in buffer size doesn't match old buffer's!");
|
||||
nsRefPtr<gfxASurface> oldBuffer;
|
||||
oldBuffer = SetBuffer(aBuffer, nsIntSize(newSize.width, newSize.height),
|
||||
aRect, aRotation);
|
||||
oldBuffer = SetBuffer(aBuffer, aRect, aRotation);
|
||||
}
|
||||
|
||||
void SetBackingBufferAndUpdateFrom(
|
||||
gfxASurface* aBuffer,
|
||||
gfxASurface* aSource, const nsIntRect& aRect, const nsIntPoint& aRotation,
|
||||
const nsIntRegion& aUpdateRegion, float aXResolution, float aYResolution);
|
||||
const nsIntRegion& aUpdateRegion);
|
||||
|
||||
private:
|
||||
BasicThebesLayerBuffer(gfxASurface* aBuffer,
|
||||
|
@ -437,8 +436,7 @@ private:
|
|||
// intended to be used for creating temporaries
|
||||
: ThebesLayerBuffer(ContainsVisibleBounds)
|
||||
{
|
||||
gfxIntSize sz = aBuffer->GetSize();
|
||||
SetBuffer(aBuffer, nsIntSize(sz.width, sz.height), aRect, aRotation);
|
||||
SetBuffer(aBuffer, aRect, aRotation);
|
||||
}
|
||||
|
||||
BasicThebesLayer* mLayer;
|
||||
|
@ -500,6 +498,21 @@ public:
|
|||
aType, gfxIntSize(aSize.width, aSize.height));
|
||||
}
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
{
|
||||
if (!BasicManager()->IsRetained()) {
|
||||
// Don't do any snapping of our transform, since we're just going to
|
||||
// draw straight through without intermediate buffers.
|
||||
mEffectiveTransform = GetLocalTransform()*aTransformToSurface;
|
||||
if (gfxPoint(0,0) != mResidualTranslation) {
|
||||
mResidualTranslation = gfxPoint(0,0);
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
return;
|
||||
}
|
||||
ThebesLayer::ComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
||||
protected:
|
||||
BasicLayerManager* BasicManager()
|
||||
{
|
||||
|
@ -680,9 +693,6 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
|||
}
|
||||
|
||||
{
|
||||
gfxSize scale = aContext->CurrentMatrix().ScaleFactors(PR_TRUE);
|
||||
float paintXRes = BasicManager()->XResolution() * gfxUtils::ClampToScaleFactor(scale.width);
|
||||
float paintYRes = BasicManager()->YResolution() * gfxUtils::ClampToScaleFactor(scale.height);
|
||||
PRUint32 flags = 0;
|
||||
gfxMatrix transform;
|
||||
if (!GetEffectiveTransform().Is2D(&transform) ||
|
||||
|
@ -691,7 +701,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
|||
flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE;
|
||||
}
|
||||
Buffer::PaintState state =
|
||||
mBuffer.BeginPaint(this, contentType, paintXRes, paintYRes, flags);
|
||||
mBuffer.BeginPaint(this, contentType, flags);
|
||||
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
|
||||
|
||||
if (state.mContext) {
|
||||
|
@ -702,9 +712,6 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
|||
state.mRegionToInvalidate.And(state.mRegionToInvalidate,
|
||||
GetEffectiveVisibleRegion());
|
||||
nsIntRegion extendedDrawRegion = state.mRegionToDraw;
|
||||
extendedDrawRegion.ExtendForScaling(paintXRes, paintYRes);
|
||||
mXResolution = paintXRes;
|
||||
mYResolution = paintYRes;
|
||||
SetAntialiasingFlags(this, state.mContext);
|
||||
PaintBuffer(state.mContext,
|
||||
state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate,
|
||||
|
@ -766,8 +773,7 @@ BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
|
|||
// and may cause gray lines.
|
||||
gfxUtils::ClipToRegionSnapped(aTarget, aLayer->GetEffectiveVisibleRegion());
|
||||
}
|
||||
DrawBufferWithRotation(aTarget, aOpacity,
|
||||
aLayer->GetXResolution(), aLayer->GetYResolution());
|
||||
DrawBufferWithRotation(aTarget, aOpacity);
|
||||
aTarget->Restore();
|
||||
}
|
||||
|
||||
|
@ -782,19 +788,18 @@ void
|
|||
BasicThebesLayerBuffer::SetBackingBufferAndUpdateFrom(
|
||||
gfxASurface* aBuffer,
|
||||
gfxASurface* aSource, const nsIntRect& aRect, const nsIntPoint& aRotation,
|
||||
const nsIntRegion& aUpdateRegion, float aXResolution, float aYResolution)
|
||||
const nsIntRegion& aUpdateRegion)
|
||||
{
|
||||
SetBackingBuffer(aBuffer, aRect, aRotation);
|
||||
nsRefPtr<gfxContext> destCtx =
|
||||
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(),
|
||||
aXResolution, aYResolution);
|
||||
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds());
|
||||
destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
if (IsClippingCheap(destCtx, aUpdateRegion)) {
|
||||
gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
|
||||
}
|
||||
|
||||
BasicThebesLayerBuffer srcBuffer(aSource, aRect, aRotation);
|
||||
srcBuffer.DrawBufferWithRotation(destCtx, 1.0, aXResolution, aYResolution);
|
||||
srcBuffer.DrawBufferWithRotation(destCtx, 1.0);
|
||||
}
|
||||
|
||||
class BasicImageLayer : public ImageLayer, public BasicImplData {
|
||||
|
@ -1205,9 +1210,7 @@ BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
|
|||
#ifdef DEBUG
|
||||
mPhase(PHASE_NONE),
|
||||
#endif
|
||||
mXResolution(1.0)
|
||||
, mYResolution(1.0)
|
||||
, mWidget(aWidget)
|
||||
mWidget(aWidget)
|
||||
, mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(PR_FALSE)
|
||||
, mCachedSurfaceInUse(PR_FALSE)
|
||||
, mTransactionIncomplete(false)
|
||||
|
@ -1921,8 +1924,7 @@ public:
|
|||
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
||||
{
|
||||
aAttrs = ThebesLayerAttributes(GetValidRegion(),
|
||||
mXResolution, mYResolution);
|
||||
aAttrs = ThebesLayerAttributes(GetValidRegion());
|
||||
}
|
||||
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
|
@ -1931,7 +1933,6 @@ public:
|
|||
|
||||
void SetBackBufferAndAttrs(const ThebesBuffer& aBuffer,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution, float aYResolution,
|
||||
const OptionalThebesBuffer& aReadOnlyFrontBuffer,
|
||||
const nsIntRegion& aFrontUpdatedRegion);
|
||||
|
||||
|
@ -1972,8 +1973,6 @@ private:
|
|||
void
|
||||
BasicShadowableThebesLayer::SetBackBufferAndAttrs(const ThebesBuffer& aBuffer,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution,
|
||||
float aYResolution,
|
||||
const OptionalThebesBuffer& aReadOnlyFrontBuffer,
|
||||
const nsIntRegion& aFrontUpdatedRegion)
|
||||
{
|
||||
|
@ -1986,8 +1985,6 @@ BasicShadowableThebesLayer::SetBackBufferAndAttrs(const ThebesBuffer& aBuffer,
|
|||
// to a texture it owns, then we probably got back the same buffer
|
||||
// we pushed in the update and all is well. If not, ...
|
||||
mValidRegion = aValidRegion;
|
||||
mXResolution = aXResolution;
|
||||
mYResolution = aYResolution;
|
||||
mBuffer.SetBackingBuffer(backBuffer, aBuffer.rect(), aBuffer.rotation());
|
||||
return;
|
||||
}
|
||||
|
@ -2004,7 +2001,7 @@ BasicShadowableThebesLayer::SetBackBufferAndAttrs(const ThebesBuffer& aBuffer,
|
|||
mBuffer.SetBackingBufferAndUpdateFrom(
|
||||
backBuffer,
|
||||
roFrontBuffer, roFront.rect(), roFront.rotation(),
|
||||
aFrontUpdatedRegion, mXResolution, mYResolution);
|
||||
aFrontUpdatedRegion);
|
||||
// Now the new back buffer has the same (interesting) pixels as the
|
||||
// new front buffer, and mValidRegion et al. are correct wrt the new
|
||||
// back buffer (i.e. as they were for the old back buffer)
|
||||
|
@ -2094,7 +2091,6 @@ BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType,
|
|||
|
||||
BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
|
||||
nsIntRegion(),
|
||||
1.0, 1.0,
|
||||
nsIntRect(),
|
||||
tmpFront);
|
||||
return BasicManager()->OpenDescriptor(mBackBuffer);
|
||||
|
@ -2429,10 +2425,8 @@ public:
|
|||
*aOldRect = BufferRect();
|
||||
*aOldRotation = BufferRotation();
|
||||
|
||||
gfxIntSize newSize = aNewBuffer->GetSize();
|
||||
nsRefPtr<gfxASurface> oldBuffer;
|
||||
oldBuffer = SetBuffer(aNewBuffer,
|
||||
nsIntSize(newSize.width, newSize.height),
|
||||
aNewRect, aNewRotation);
|
||||
oldBuffer.forget(aOldBuffer);
|
||||
}
|
||||
|
@ -2451,8 +2445,6 @@ class BasicShadowThebesLayer : public ShadowThebesLayer, public BasicImplData {
|
|||
public:
|
||||
BasicShadowThebesLayer(BasicShadowLayerManager* aLayerManager)
|
||||
: ShadowThebesLayer(aLayerManager, static_cast<BasicImplData*>(this))
|
||||
, mOldXResolution(1.0)
|
||||
, mOldYResolution(1.0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicShadowThebesLayer);
|
||||
}
|
||||
|
@ -2465,8 +2457,7 @@ public:
|
|||
}
|
||||
|
||||
virtual void SetFrontBuffer(const OptionalThebesBuffer& aNewFront,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution, float aYResolution);
|
||||
const nsIntRegion& aValidRegion);
|
||||
|
||||
virtual void SetValidRegion(const nsIntRegion& aRegion)
|
||||
{
|
||||
|
@ -2474,13 +2465,6 @@ public:
|
|||
ShadowThebesLayer::SetValidRegion(aRegion);
|
||||
}
|
||||
|
||||
virtual void SetResolution(float aXResolution, float aYResolution)
|
||||
{
|
||||
mOldXResolution = mXResolution;
|
||||
mOldYResolution = mYResolution;
|
||||
ShadowThebesLayer::SetResolution(aXResolution, aYResolution);
|
||||
}
|
||||
|
||||
virtual void Disconnect()
|
||||
{
|
||||
DestroyFrontBuffer();
|
||||
|
@ -2490,7 +2474,6 @@ public:
|
|||
virtual void
|
||||
Swap(const ThebesBuffer& aNewFront, const nsIntRegion& aUpdatedRegion,
|
||||
ThebesBuffer* aNewBack, nsIntRegion* aNewBackValidRegion,
|
||||
float* aNewXResolution, float* aNewYResolution,
|
||||
OptionalThebesBuffer* aReadOnlyFront, nsIntRegion* aFrontUpdatedRegion);
|
||||
|
||||
virtual void DestroyFrontBuffer()
|
||||
|
@ -2498,8 +2481,6 @@ public:
|
|||
mFrontBuffer.Clear();
|
||||
mValidRegion.SetEmpty();
|
||||
mOldValidRegion.SetEmpty();
|
||||
mOldXResolution = 1.0;
|
||||
mOldYResolution = 1.0;
|
||||
|
||||
if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
|
||||
BasicManager()->ShadowLayerManager::DestroySharedSurface(&mFrontBufferDescriptor, mAllocator);
|
||||
|
@ -2525,18 +2506,13 @@ private:
|
|||
// Then when we Swap() back/front buffers, we can return these
|
||||
// parameters to our partner (adjusted as needed).
|
||||
nsIntRegion mOldValidRegion;
|
||||
float mOldXResolution;
|
||||
float mOldYResolution;
|
||||
};
|
||||
|
||||
void
|
||||
BasicShadowThebesLayer::SetFrontBuffer(const OptionalThebesBuffer& aNewFront,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution, float aYResolution)
|
||||
const nsIntRegion& aValidRegion)
|
||||
{
|
||||
mValidRegion = mOldValidRegion = aValidRegion;
|
||||
mXResolution = mOldXResolution = aXResolution;
|
||||
mYResolution = mOldYResolution = aYResolution;
|
||||
|
||||
NS_ABORT_IF_FALSE(OptionalThebesBuffer::Tnull_t != aNewFront.type(),
|
||||
"aNewFront must be valid here!");
|
||||
|
@ -2558,7 +2534,6 @@ BasicShadowThebesLayer::Swap(const ThebesBuffer& aNewFront,
|
|||
const nsIntRegion& aUpdatedRegion,
|
||||
ThebesBuffer* aNewBack,
|
||||
nsIntRegion* aNewBackValidRegion,
|
||||
float* aNewXResolution, float* aNewYResolution,
|
||||
OptionalThebesBuffer* aReadOnlyFront,
|
||||
nsIntRegion* aFrontUpdatedRegion)
|
||||
{
|
||||
|
@ -2566,25 +2541,7 @@ BasicShadowThebesLayer::Swap(const ThebesBuffer& aNewFront,
|
|||
aNewBack->buffer() = mFrontBufferDescriptor;
|
||||
// We have to invalidate the pixels painted into the new buffer.
|
||||
// They might overlap with our old pixels.
|
||||
if (mOldXResolution == mXResolution && mOldYResolution == mYResolution) {
|
||||
aNewBackValidRegion->Sub(mOldValidRegion, aUpdatedRegion);
|
||||
} else {
|
||||
// On resolution changes, pretend that our buffer has the new
|
||||
// resolution, but just has no valid content. This can avoid
|
||||
// unnecessary buffer reallocs.
|
||||
//
|
||||
// FIXME/bug 598866: when we start re-using buffers after
|
||||
// resolution changes, we're going to need to implement
|
||||
// front->back copies to avoid thrashing our valid region by
|
||||
// always nullifying it.
|
||||
aNewBackValidRegion->SetEmpty();
|
||||
mOldXResolution = mXResolution;
|
||||
mOldYResolution = mYResolution;
|
||||
}
|
||||
NS_ASSERTION(mXResolution == mOldXResolution && mYResolution == mOldYResolution,
|
||||
"Uh-oh, buffer allocation thrash forthcoming!");
|
||||
*aNewXResolution = mXResolution;
|
||||
*aNewYResolution = mYResolution;
|
||||
aNewBackValidRegion->Sub(mOldValidRegion, aUpdatedRegion);
|
||||
|
||||
nsRefPtr<gfxASurface> newFrontBuffer =
|
||||
BasicManager()->OpenDescriptor(aNewFront.buffer());
|
||||
|
@ -3077,8 +3034,7 @@ BasicShadowLayerManager::ForwardTransaction()
|
|||
const OpThebesBufferSwap& obs = reply.get_OpThebesBufferSwap();
|
||||
BasicShadowableThebesLayer* thebes = GetBasicShadowable(obs)->AsThebes();
|
||||
thebes->SetBackBufferAndAttrs(
|
||||
obs.newBackBuffer(),
|
||||
obs.newValidRegion(), obs.newXResolution(), obs.newYResolution(),
|
||||
obs.newBackBuffer(), obs.newValidRegion(),
|
||||
obs.readOnlyFrontBuffer(), obs.frontUpdatedRegion());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -115,21 +115,6 @@ public:
|
|||
void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering);
|
||||
gfxContext* GetDefaultTarget() { return mDefaultTarget; }
|
||||
|
||||
/**
|
||||
* Set a target resolution for managed layers that are scalable. It
|
||||
* might make sense to call this outside of a transaction, but
|
||||
* currently it's only allowed during the construction phase of
|
||||
* transactions.
|
||||
*/
|
||||
void SetResolution(float aXResolution, float aYResolution)
|
||||
{
|
||||
NS_ASSERTION(InConstruction(), "resolution must be set before drawing");
|
||||
mXResolution = aXResolution;
|
||||
mYResolution = aYResolution;
|
||||
}
|
||||
float XResolution() const { return mXResolution; }
|
||||
float YResolution() const { return mYResolution; }
|
||||
|
||||
nsIWidget* GetRetainerWidget() { return mWidget; }
|
||||
void ClearRetainerWidget() { mWidget = nsnull; }
|
||||
|
||||
|
@ -212,10 +197,6 @@ protected:
|
|||
bool EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
// Target resolution for scalable content.
|
||||
float mXResolution;
|
||||
float mYResolution;
|
||||
|
||||
// Widget whose surface should be used as the basis for ThebesLayer
|
||||
// buffers.
|
||||
nsIWidget* mWidget;
|
||||
|
|
|
@ -79,8 +79,7 @@ ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
|
|||
|
||||
void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset,
|
||||
ID3D10Texture2D* aDest, const nsIntPoint &aDestOffset,
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion,
|
||||
float aXRes, float aYRes)
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
|
||||
{
|
||||
nsIntRegion retainedRegion;
|
||||
nsIntRegionRectIterator iter(aCopyRegion);
|
||||
|
@ -88,19 +87,18 @@ void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcO
|
|||
while ((r = iter.Next())) {
|
||||
if (r->width * r->height > RETENTION_THRESHOLD) {
|
||||
// Calculate the retained rectangle's position on the old and the new
|
||||
// surface. We need to scale these rectangles since the visible
|
||||
// region is in unscaled units, and the texture size has been scaled.
|
||||
// surface.
|
||||
D3D10_BOX box;
|
||||
box.left = UINT(floor((r->x - aSrcOffset.x) * aXRes));
|
||||
box.top = UINT(floor((r->y - aSrcOffset.y) * aYRes));
|
||||
box.right = box.left + UINT(ceil(r->width * aXRes));
|
||||
box.bottom = box.top + UINT(ceil(r->height * aYRes));
|
||||
box.left = r->x - aSrcOffset.x;
|
||||
box.top = r->y - aSrcOffset.y;
|
||||
box.right = box.left + r->width;
|
||||
box.bottom = box.top + r->height;
|
||||
box.back = 1;
|
||||
box.front = 0;
|
||||
|
||||
device()->CopySubresourceRegion(aDest, 0,
|
||||
UINT(floor((r->x - aDestOffset.x) * aXRes)),
|
||||
UINT(floor((r->y - aDestOffset.y) * aYRes)),
|
||||
r->x - aDestOffset.x,
|
||||
r->y - aDestOffset.y,
|
||||
0,
|
||||
aSrc, 0,
|
||||
&box);
|
||||
|
@ -212,15 +210,6 @@ ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
|
|||
|
||||
VerifyContentType(mode);
|
||||
|
||||
float xres, yres;
|
||||
GetDesiredResolutions(xres, yres);
|
||||
|
||||
// If our resolution changed, we need new sized textures, delete the old ones.
|
||||
if (ResolutionChanged(xres, yres)) {
|
||||
mTexture = nsnull;
|
||||
mTextureOnWhite = nsnull;
|
||||
}
|
||||
|
||||
nsTArray<ReadbackProcessor::Update> readbackUpdates;
|
||||
nsIntRegion readbackRegion;
|
||||
if (aReadback && UsedForReadback()) {
|
||||
|
@ -245,27 +234,23 @@ ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
|
|||
|
||||
nsIntRect largeRect = retainRegion.GetLargestRectangle();
|
||||
|
||||
// If we had no hardware texture before, have no retained area larger than
|
||||
// the retention threshold or the requested resolution has changed,
|
||||
// we're not retaining and are done here. If our texture creation failed
|
||||
// this can mean a device reset is pending and we should silently ignore the
|
||||
// failure. In the future when device failures are properly handled we
|
||||
// should test for the type of failure and gracefully handle different
|
||||
// failures. See bug 569081.
|
||||
// If we had no hardware texture before, or have no retained area larger than
|
||||
// the retention threshold, we're not retaining and are done here.
|
||||
// If our texture creation failed this can mean a device reset is pending
|
||||
// and we should silently ignore the failure. In the future when device
|
||||
// failures are properly handled we should test for the type of failure
|
||||
// and gracefully handle different failures. See bug 569081.
|
||||
if (!oldTexture || !mTexture ||
|
||||
largeRect.width * largeRect.height < RETENTION_THRESHOLD ||
|
||||
ResolutionChanged(xres, yres)) {
|
||||
largeRect.width * largeRect.height < RETENTION_THRESHOLD) {
|
||||
mValidRegion.SetEmpty();
|
||||
} else {
|
||||
CopyRegion(oldTexture, mTextureRect.TopLeft(),
|
||||
mTexture, newTextureRect.TopLeft(),
|
||||
retainRegion, &mValidRegion,
|
||||
xres, yres);
|
||||
retainRegion, &mValidRegion);
|
||||
if (oldTextureOnWhite) {
|
||||
CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(),
|
||||
mTextureOnWhite, newTextureRect.TopLeft(),
|
||||
retainRegion, &mValidRegion,
|
||||
xres, yres);
|
||||
retainRegion, &mValidRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,11 +338,9 @@ ThebesLayerD3D10::VerifyContentType(SurfaceMode aMode)
|
|||
|
||||
static void
|
||||
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
||||
const nsIntPoint& aOffset, const gfxRGBA& aColor,
|
||||
float aXRes, float aYRes)
|
||||
const nsIntPoint& aOffset, const gfxRGBA& aColor)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
|
||||
ctx->Scale(aXRes, aYRes);
|
||||
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
|
||||
gfxUtils::PathFromRegion(ctx, aRegion);
|
||||
ctx->SetColor(aColor);
|
||||
|
@ -373,15 +356,11 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
|
|||
return;
|
||||
}
|
||||
|
||||
float xres, yres;
|
||||
GetDesiredResolutions(xres, yres);
|
||||
aRegion.ExtendForScaling(xres, yres);
|
||||
|
||||
nsRefPtr<gfxASurface> destinationSurface;
|
||||
|
||||
if (aMode == SURFACE_COMPONENT_ALPHA) {
|
||||
FillSurface(mD2DSurface, aRegion, visibleRect.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0), xres, yres);
|
||||
FillSurface(mD2DSurfaceOnWhite, aRegion, visibleRect.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0), xres, yres);
|
||||
FillSurface(mD2DSurface, aRegion, visibleRect.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
FillSurface(mD2DSurfaceOnWhite, aRegion, visibleRect.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0));
|
||||
gfxASurface* surfaces[2] = { mD2DSurface.get(), mD2DSurfaceOnWhite.get() };
|
||||
destinationSurface = new gfxTeeSurface(surfaces, NS_ARRAY_LENGTH(surfaces));
|
||||
// Using this surface as a source will likely go horribly wrong, since
|
||||
|
@ -393,8 +372,6 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
|
|||
}
|
||||
|
||||
nsRefPtr<gfxContext> context = new gfxContext(destinationSurface);
|
||||
// Draw content scaled at our current resolution.
|
||||
context->Scale(xres, yres);
|
||||
|
||||
nsIntRegionRectIterator iter(aRegion);
|
||||
context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y));
|
||||
|
@ -425,15 +402,7 @@ ThebesLayerD3D10::CreateNewTextures(const gfxIntSize &aSize, SurfaceMode aMode)
|
|||
return;
|
||||
}
|
||||
|
||||
// Scale the requested size (in unscaled units) to the actual
|
||||
// texture size we require.
|
||||
gfxIntSize scaledSize;
|
||||
float xres, yres;
|
||||
GetDesiredResolutions(xres, yres);
|
||||
scaledSize.width = PRInt32(ceil(aSize.width * xres));
|
||||
scaledSize.height = PRInt32(ceil(aSize.height * yres));
|
||||
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, scaledSize.width, scaledSize.height, 1, 1);
|
||||
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
|
||||
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
|
||||
HRESULT hr;
|
||||
|
@ -485,32 +454,6 @@ ThebesLayerD3D10::CreateNewTextures(const gfxIntSize &aSize, SurfaceMode aMode)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mXResolution = xres;
|
||||
mYResolution = yres;
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D10::GetDesiredResolutions(float& aXRes, float& aYRes)
|
||||
{
|
||||
const gfx3DMatrix& transform = GetLayer()->GetEffectiveTransform();
|
||||
gfxMatrix transform2d;
|
||||
if (transform.Is2D(&transform2d)) {
|
||||
gfxSize scale = transform2d.ScaleFactors(PR_TRUE);
|
||||
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
|
||||
aXRes = gfxUtils::ClampToScaleFactor(scale.width);
|
||||
aYRes = gfxUtils::ClampToScaleFactor(scale.height);
|
||||
} else {
|
||||
aXRes = 1.0;
|
||||
aYRes = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ThebesLayerD3D10::ResolutionChanged(float aXRes, float aYRes)
|
||||
{
|
||||
return aXRes != mXResolution ||
|
||||
aYRes != mYResolution;
|
||||
}
|
||||
|
||||
} /* namespace layers */
|
||||
|
|
|
@ -99,18 +99,7 @@ private:
|
|||
/* Copy a texture region */
|
||||
void CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset,
|
||||
ID3D10Texture2D* aDest, const nsIntPoint &aDestOffset,
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion,
|
||||
float aXRes, float aYRes);
|
||||
|
||||
/**
|
||||
* Calculate the desired texture resolution based on
|
||||
* the layer managers resolution, and the current
|
||||
* transforms scale factor.
|
||||
*/
|
||||
void GetDesiredResolutions(float& aXRes, float& aYRes);
|
||||
|
||||
/* Check if the current texture resolution matches the stored resolution. */
|
||||
bool ResolutionChanged(float aXRes, float aYRes);
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion);
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
|
|
|
@ -77,8 +77,7 @@ ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
|
|||
void
|
||||
ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
|
||||
IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion,
|
||||
float aXRes, float aYRes)
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
|
||||
{
|
||||
nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface;
|
||||
aSrc->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
|
||||
|
@ -92,17 +91,16 @@ ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffse
|
|||
RECT oldRect, newRect;
|
||||
|
||||
// Calculate the retained rectangle's position on the old and the new
|
||||
// surface. We need to scale these rectangles since the visible
|
||||
// region is in unscaled units, and the texture size has been scaled.
|
||||
oldRect.left = UINT(floor((r->x - aSrcOffset.x) * aXRes));
|
||||
oldRect.top = UINT(floor((r->y - aSrcOffset.y) * aYRes));
|
||||
oldRect.right = oldRect.left + UINT(ceil(r->width * aXRes));
|
||||
oldRect.bottom = oldRect.top + UINT(ceil(r->height * aYRes));
|
||||
// surface.
|
||||
oldRect.left = r->x - aSrcOffset.x;
|
||||
oldRect.top = r->y - aSrcOffset.y;
|
||||
oldRect.right = oldRect.left + r->width;
|
||||
oldRect.bottom = oldRect.top + r->height;
|
||||
|
||||
newRect.left = UINT(floor((r->x - aDestOffset.x) * aXRes));
|
||||
newRect.top = UINT(floor((r->y - aDestOffset.y) * aYRes));
|
||||
newRect.right = newRect.left + UINT(ceil(r->width * aXRes));
|
||||
newRect.bottom = newRect.top + UINT(ceil(r->height * aYRes));
|
||||
newRect.left = r->x - aDestOffset.x;
|
||||
newRect.top = r->y - aDestOffset.y;
|
||||
newRect.right = newRect.left + r->width;
|
||||
newRect.bottom = newRect.top + r->height;
|
||||
|
||||
// Copy data from our old texture to the new one
|
||||
HRESULT hr = device()->
|
||||
|
@ -128,15 +126,6 @@ ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode)
|
|||
{
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
|
||||
float xres, yres;
|
||||
GetDesiredResolutions(xres, yres);
|
||||
|
||||
// If our resolution changed, we need new sized textures, delete the old ones.
|
||||
if (ResolutionChanged(xres, yres)) {
|
||||
mTexture = nsnull;
|
||||
mTextureOnWhite = nsnull;
|
||||
}
|
||||
|
||||
if (HaveTextures(aMode)) {
|
||||
if (!mTextureRect.IsEqualInterior(visibleRect)) {
|
||||
nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
|
||||
|
@ -159,10 +148,10 @@ ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode)
|
|||
mValidRegion.SetEmpty();
|
||||
} else {
|
||||
CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, visibleRect.TopLeft(),
|
||||
retainRegion, &mValidRegion, xres, yres);
|
||||
retainRegion, &mValidRegion);
|
||||
if (aMode == SURFACE_COMPONENT_ALPHA) {
|
||||
CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, visibleRect.TopLeft(),
|
||||
retainRegion, &mValidRegion, xres, yres);
|
||||
retainRegion, &mValidRegion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +358,7 @@ public:
|
|||
OpaqueRenderer(const nsIntRegion& aUpdateRegion) :
|
||||
mUpdateRegion(aUpdateRegion), mDC(NULL) {}
|
||||
~OpaqueRenderer() { End(); }
|
||||
already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer, float aXRes, float aYRes);
|
||||
already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer);
|
||||
void End();
|
||||
IDirect3DTexture9* GetTexture() { return mTmpTexture; }
|
||||
|
||||
|
@ -381,15 +370,12 @@ private:
|
|||
};
|
||||
|
||||
already_AddRefed<gfxWindowsSurface>
|
||||
OpaqueRenderer::Begin(LayerD3D9* aLayer, float aXRes, float aYRes)
|
||||
OpaqueRenderer::Begin(LayerD3D9* aLayer)
|
||||
{
|
||||
nsIntRect bounds = mUpdateRegion.GetBounds();
|
||||
gfxIntSize scaledSize;
|
||||
scaledSize.width = PRInt32(ceil(bounds.width * aXRes));
|
||||
scaledSize.height = PRInt32(ceil(bounds.height * aYRes));
|
||||
|
||||
HRESULT hr = aLayer->device()->
|
||||
CreateTexture(scaledSize.width, scaledSize.height, 1, 0, D3DFMT_X8R8G8B8,
|
||||
CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_X8R8G8B8,
|
||||
D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), NULL);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
|
@ -427,11 +413,9 @@ OpaqueRenderer::End()
|
|||
|
||||
static void
|
||||
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
||||
const nsIntPoint& aOffset, const gfxRGBA& aColor,
|
||||
float aXRes, float aYRes)
|
||||
const nsIntPoint& aOffset, const gfxRGBA& aColor)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
|
||||
ctx->Scale(aXRes, aYRes);
|
||||
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
|
||||
gfxUtils::ClipToRegion(ctx, aRegion);
|
||||
ctx->SetColor(aColor);
|
||||
|
@ -444,14 +428,9 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
{
|
||||
HRESULT hr;
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
float xres, yres;
|
||||
GetDesiredResolutions(xres, yres);
|
||||
|
||||
nsRefPtr<gfxASurface> destinationSurface;
|
||||
nsIntRect bounds = aRegion.GetBounds();
|
||||
gfxIntSize scaledSize;
|
||||
scaledSize.width = PRInt32(ceil(bounds.width * xres));
|
||||
scaledSize.height = PRInt32(ceil(bounds.height * yres));
|
||||
nsRefPtr<IDirect3DTexture9> tmpTexture;
|
||||
OpaqueRenderer opaqueRenderer(aRegion);
|
||||
OpaqueRenderer opaqueRendererOnWhite(aRegion);
|
||||
|
@ -459,11 +438,11 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
switch (aMode)
|
||||
{
|
||||
case SURFACE_OPAQUE:
|
||||
destinationSurface = opaqueRenderer.Begin(this, xres, yres);
|
||||
destinationSurface = opaqueRenderer.Begin(this);
|
||||
break;
|
||||
|
||||
case SURFACE_SINGLE_CHANNEL_ALPHA: {
|
||||
hr = device()->CreateTexture(scaledSize.width, scaledSize.height, 1,
|
||||
hr = device()->CreateTexture(bounds.width, bounds.height, 1,
|
||||
0, D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
|
||||
|
||||
|
@ -476,7 +455,7 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
// of our DEFAULT texture and then use UpdateTexture and add dirty rects
|
||||
// to update in a single call.
|
||||
nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface(
|
||||
gfxIntSize(scaledSize.width, scaledSize.height), gfxASurface::ImageFormatARGB32);
|
||||
gfxIntSize(bounds.width, bounds.height), gfxASurface::ImageFormatARGB32);
|
||||
// If the contents of this layer don't require component alpha in the
|
||||
// end of rendering, it's safe to enable Cleartype since all the Cleartype
|
||||
// glyphs must be over (or under) opaque pixels.
|
||||
|
@ -486,11 +465,11 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
}
|
||||
|
||||
case SURFACE_COMPONENT_ALPHA: {
|
||||
nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this, xres, yres);
|
||||
nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this, xres, yres);
|
||||
nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this);
|
||||
nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this);
|
||||
if (onBlack && onWhite) {
|
||||
FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0), xres, yres);
|
||||
FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0), xres, yres);
|
||||
FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0));
|
||||
FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0));
|
||||
gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() };
|
||||
destinationSurface = new gfxTeeSurface(surfaces, NS_ARRAY_LENGTH(surfaces));
|
||||
// Using this surface as a source will likely go horribly wrong, since
|
||||
|
@ -506,10 +485,7 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
return;
|
||||
|
||||
nsRefPtr<gfxContext> context = new gfxContext(destinationSurface);
|
||||
// Draw content scaled at our current resolution.
|
||||
context->Scale(xres, yres);
|
||||
context->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||
aRegion.ExtendForScaling(xres, yres);
|
||||
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||
cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
|
||||
|
||||
|
@ -545,7 +521,7 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface((unsigned char *)r.pBits,
|
||||
scaledSize,
|
||||
bounds.Size(),
|
||||
r.Pitch,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
|
||||
|
@ -577,8 +553,7 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
}
|
||||
NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths");
|
||||
|
||||
// Copy to the texture. We need to scale these rectangles since the visible
|
||||
// region is in unscaled units, and the texture sizes have been scaled.
|
||||
// Copy to the texture.
|
||||
for (PRUint32 i = 0; i < srcTextures.Length(); ++i) {
|
||||
nsRefPtr<IDirect3DSurface9> srcSurface;
|
||||
nsRefPtr<IDirect3DSurface9> dstSurface;
|
||||
|
@ -590,16 +565,14 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
const nsIntRect *iterRect;
|
||||
while ((iterRect = iter.Next())) {
|
||||
RECT rect;
|
||||
rect.left = NS_MAX<LONG>(0, LONG(floor((iterRect->x - bounds.x) * xres)));
|
||||
rect.top = NS_MAX<LONG>(0, LONG(floor((iterRect->y - bounds.y) * yres)));
|
||||
rect.right = NS_MIN<LONG>(scaledSize.width,
|
||||
LONG(ceil((iterRect->XMost() - bounds.x) * xres)));
|
||||
rect.bottom = NS_MIN<LONG>(scaledSize.height,
|
||||
LONG(ceil((iterRect->YMost() - bounds.y) * yres)));
|
||||
rect.left = iterRect->x - bounds.x;
|
||||
rect.top = iterRect->y - bounds.y;
|
||||
rect.right = iterRect->XMost() - bounds.x;
|
||||
rect.bottom = iterRect->YMost() - bounds.y;
|
||||
|
||||
POINT point;
|
||||
point.x = NS_MAX<LONG>(0, LONG(floor((iterRect->x - visibleRect.x) * xres)));
|
||||
point.y = NS_MAX<LONG>(0, LONG(floor((iterRect->y - visibleRect.y) * yres)));
|
||||
point.x = iterRect->x - visibleRect.x;
|
||||
point.y = iterRect->y - visibleRect.y;
|
||||
device()->UpdateSurface(srcSurface, &rect, dstSurface, &point);
|
||||
}
|
||||
}
|
||||
|
@ -614,52 +587,18 @@ ThebesLayerD3D9::CreateNewTextures(const gfxIntSize &aSize,
|
|||
return;
|
||||
}
|
||||
|
||||
// Scale the requested size (in unscaled units) to the actual
|
||||
// texture size we require.
|
||||
gfxIntSize scaledSize;
|
||||
float xres, yres;
|
||||
GetDesiredResolutions(xres, yres);
|
||||
scaledSize.width = PRInt32(ceil(aSize.width * xres));
|
||||
scaledSize.height = PRInt32(ceil(aSize.height * yres));
|
||||
|
||||
mTexture = nsnull;
|
||||
mTextureOnWhite = nsnull;
|
||||
device()->CreateTexture(scaledSize.width, scaledSize.height, 1,
|
||||
device()->CreateTexture(aSize.width, aSize.height, 1,
|
||||
D3DUSAGE_RENDERTARGET,
|
||||
aMode != SURFACE_SINGLE_CHANNEL_ALPHA ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
|
||||
if (aMode == SURFACE_COMPONENT_ALPHA) {
|
||||
device()->CreateTexture(scaledSize.width, scaledSize.height, 1,
|
||||
device()->CreateTexture(aSize.width, aSize.height, 1,
|
||||
D3DUSAGE_RENDERTARGET,
|
||||
D3DFMT_X8R8G8B8,
|
||||
D3DPOOL_DEFAULT, getter_AddRefs(mTextureOnWhite), NULL);
|
||||
}
|
||||
|
||||
mXResolution = xres;
|
||||
mYResolution = yres;
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D9::GetDesiredResolutions(float& aXRes, float& aYRes)
|
||||
{
|
||||
const gfx3DMatrix& transform = GetLayer()->GetEffectiveTransform();
|
||||
gfxMatrix transform2d;
|
||||
if (transform.Is2D(&transform2d)) {
|
||||
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
|
||||
gfxSize scale = transform2d.ScaleFactors(PR_TRUE);
|
||||
aXRes = gfxUtils::ClampToScaleFactor(scale.width);
|
||||
aYRes = gfxUtils::ClampToScaleFactor(scale.height);
|
||||
} else {
|
||||
aXRes = 1.0;
|
||||
aYRes = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ThebesLayerD3D9::ResolutionChanged(float aXRes, float aYRes)
|
||||
{
|
||||
return aXRes != mXResolution ||
|
||||
aYRes != mYResolution;
|
||||
}
|
||||
|
||||
} /* namespace layers */
|
||||
|
|
|
@ -109,18 +109,7 @@ private:
|
|||
|
||||
void CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
|
||||
IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion,
|
||||
float aXRes, float aYRes);
|
||||
|
||||
/**
|
||||
* Calculate the desired texture resolution based on
|
||||
* the layer managers resolution, and the current
|
||||
* transforms scale factor.
|
||||
*/
|
||||
void GetDesiredResolutions(float& aXRes, float& aYRes);
|
||||
|
||||
/* Check if the current texture resolution matches */
|
||||
bool ResolutionChanged(float aXRes, float aYRes);
|
||||
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion);
|
||||
};
|
||||
|
||||
} /* layers */
|
||||
|
|
|
@ -105,8 +105,6 @@ struct OpCreateThebesBuffer {
|
|||
PLayer layer;
|
||||
OptionalThebesBuffer initialFront;
|
||||
nsIntRegion frontValidRegion;
|
||||
float xResolution;
|
||||
float yResolution;
|
||||
};
|
||||
struct OpDestroyThebesFrontBuffer { PLayer layer; };
|
||||
|
||||
|
@ -141,8 +139,6 @@ struct CommonLayerAttributes {
|
|||
|
||||
struct ThebesLayerAttributes {
|
||||
nsIntRegion validRegion;
|
||||
float xResolution;
|
||||
float yResolution;
|
||||
};
|
||||
struct ContainerLayerAttributes{ FrameMetrics metrics; };
|
||||
struct ColorLayerAttributes { gfxRGBA color; };
|
||||
|
@ -230,8 +226,6 @@ struct OpThebesBufferSwap {
|
|||
PLayer layer;
|
||||
ThebesBuffer newBackBuffer;
|
||||
nsIntRegion newValidRegion;
|
||||
float newXResolution;
|
||||
float newYResolution;
|
||||
// If the parent took the child's old back buffer and returned its
|
||||
// old front buffer, |readOnlyFrontBuffer| may (if non-null) contain
|
||||
// the child's old back buffer (parent's new front buffer). This
|
||||
|
|
|
@ -186,8 +186,6 @@ ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas)
|
|||
void
|
||||
ShadowLayerForwarder::CreatedThebesBuffer(ShadowableLayer* aThebes,
|
||||
const nsIntRegion& aFrontValidRegion,
|
||||
float aXResolution,
|
||||
float aYResolution,
|
||||
const nsIntRect& aBufferRect,
|
||||
const SurfaceDescriptor& aTempFrontBuffer)
|
||||
{
|
||||
|
@ -199,9 +197,7 @@ ShadowLayerForwarder::CreatedThebesBuffer(ShadowableLayer* aThebes,
|
|||
}
|
||||
mTxn->AddEdit(OpCreateThebesBuffer(NULL, Shadow(aThebes),
|
||||
buffer,
|
||||
aFrontValidRegion,
|
||||
aXResolution,
|
||||
aYResolution));
|
||||
aFrontValidRegion));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -157,7 +157,6 @@ public:
|
|||
*/
|
||||
void CreatedThebesBuffer(ShadowableLayer* aThebes,
|
||||
const nsIntRegion& aFrontValidRegion,
|
||||
float aXResolution, float aYResolution,
|
||||
const nsIntRect& aBufferRect,
|
||||
const SurfaceDescriptor& aInitialFrontBuffer);
|
||||
/**
|
||||
|
@ -494,8 +493,7 @@ public:
|
|||
* values. This is called when a new buffer has been created.
|
||||
*/
|
||||
virtual void SetFrontBuffer(const OptionalThebesBuffer& aNewFront,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution, float aYResolution) = 0;
|
||||
const nsIntRegion& aValidRegion) = 0;
|
||||
|
||||
virtual void InvalidateRegion(const nsIntRegion& aRegion)
|
||||
{
|
||||
|
@ -511,16 +509,6 @@ public:
|
|||
Mutated();
|
||||
}
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
*/
|
||||
virtual void SetResolution(float aXResolution, float aYResolution)
|
||||
{
|
||||
mXResolution = aXResolution;
|
||||
mYResolution = aYResolution;
|
||||
Mutated();
|
||||
}
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
*
|
||||
|
@ -531,7 +519,6 @@ public:
|
|||
virtual void
|
||||
Swap(const ThebesBuffer& aNewFront, const nsIntRegion& aUpdatedRegion,
|
||||
ThebesBuffer* aNewBack, nsIntRegion* aNewBackValidRegion,
|
||||
float* aNewXResolution, float* aNewYResolution,
|
||||
OptionalThebesBuffer* aReadOnlyFront, nsIntRegion* aFrontUpdatedRegion) = 0;
|
||||
|
||||
/**
|
||||
|
|
|
@ -211,8 +211,7 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
|||
ShadowThebesLayer* thebes = static_cast<ShadowThebesLayer*>(
|
||||
AsShadowLayer(otb)->AsLayer());
|
||||
|
||||
thebes->SetFrontBuffer(otb.initialFront(), otb.frontValidRegion(),
|
||||
otb.xResolution(), otb.yResolution());
|
||||
thebes->SetFrontBuffer(otb.initialFront(), otb.frontValidRegion());
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -310,7 +309,6 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
|||
specific.get_ThebesLayerAttributes();
|
||||
|
||||
thebesLayer->SetValidRegion(attrs.validRegion());
|
||||
thebesLayer->SetResolution(attrs.xResolution(), attrs.yResolution());
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -391,16 +389,15 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
|||
|
||||
ThebesBuffer newBack;
|
||||
nsIntRegion newValidRegion;
|
||||
float newXResolution, newYResolution;
|
||||
OptionalThebesBuffer readonlyFront;
|
||||
nsIntRegion frontUpdatedRegion;
|
||||
thebes->Swap(newFront, op.updatedRegion(),
|
||||
&newBack, &newValidRegion, &newXResolution, &newYResolution,
|
||||
&newBack, &newValidRegion,
|
||||
&readonlyFront, &frontUpdatedRegion);
|
||||
replyv.push_back(
|
||||
OpThebesBufferSwap(
|
||||
shadow, NULL,
|
||||
newBack, newValidRegion, newXResolution, newYResolution,
|
||||
newBack, newValidRegion,
|
||||
readonlyFront, frontUpdatedRegion));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -171,8 +171,6 @@ public:
|
|||
|
||||
enum { PAINT_WILL_RESAMPLE = ThebesLayerBuffer::PAINT_WILL_RESAMPLE };
|
||||
virtual PaintState BeginPaint(ContentType aContentType,
|
||||
float aXResolution,
|
||||
float aYResolution,
|
||||
PRUint32 aFlags) = 0;
|
||||
|
||||
void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
|
||||
|
@ -215,9 +213,6 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
|
|||
TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
|
||||
TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
|
||||
|
||||
float xres = mLayer->GetXResolution();
|
||||
float yres = mLayer->GetYResolution();
|
||||
|
||||
PRInt32 passes = mTexImageOnWhite ? 2 : 1;
|
||||
for (PRInt32 pass = 1; pass <= passes; ++pass) {
|
||||
LayerProgram *program;
|
||||
|
@ -274,12 +269,6 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
|
|||
|
||||
quadRect.MoveBy(-GetOriginOffset());
|
||||
|
||||
// The buffer rect and rotation are resolution-neutral; with a
|
||||
// non-1.0 resolution, only the texture size is scaled by the
|
||||
// resolution. So map the quadrent rect into the space scaled to
|
||||
// the texture size and let GL do the rest.
|
||||
quadRect.ScaleRoundOut(xres, yres);
|
||||
|
||||
BindAndDrawQuadWithTextureRect(gl(), program, quadRect,
|
||||
mTexImage->GetSize(),
|
||||
mTexImage->GetWrapMode());
|
||||
|
@ -312,15 +301,11 @@ public:
|
|||
|
||||
// ThebesLayerBufferOGL interface
|
||||
virtual PaintState BeginPaint(ContentType aContentType,
|
||||
float aXResolution,
|
||||
float aYResolution,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
// Let ThebesLayerBuffer do all the hard work for us! :D
|
||||
return ThebesLayerBuffer::BeginPaint(mLayer,
|
||||
aContentType,
|
||||
aXResolution,
|
||||
aYResolution,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
|
@ -356,8 +341,6 @@ public:
|
|||
virtual ~BasicBufferOGL() {}
|
||||
|
||||
virtual PaintState BeginPaint(ContentType aContentType,
|
||||
float aXResolution,
|
||||
float aYResolution,
|
||||
PRUint32 aFlags);
|
||||
|
||||
protected:
|
||||
|
@ -410,42 +393,20 @@ FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
|||
ctx->Paint();
|
||||
}
|
||||
|
||||
static nsIntSize
|
||||
ScaledSize(const nsIntSize& aSize, float aXScale, float aYScale)
|
||||
{
|
||||
if (aXScale == 1.0 && aYScale == 1.0) {
|
||||
return aSize;
|
||||
}
|
||||
|
||||
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,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
PaintState result;
|
||||
float curXRes = mLayer->GetXResolution();
|
||||
float curYRes = mLayer->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
|
||||
// We 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;
|
||||
PRBool canHaveRotation = !(aFlags & PAINT_WILL_RESAMPLE);
|
||||
|
||||
nsIntRegion validRegion = mLayer->GetValidRegion();
|
||||
|
||||
Layer::SurfaceMode mode;
|
||||
ContentType contentType;
|
||||
nsIntRegion neededRegion;
|
||||
nsIntSize destBufferDims;
|
||||
PRBool canReuseBuffer;
|
||||
nsIntRect destBufferRect;
|
||||
|
||||
|
@ -453,8 +414,6 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
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 &&
|
||||
|
@ -499,23 +458,13 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -534,8 +483,8 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
if (result.mRegionToDraw.IsEmpty())
|
||||
return result;
|
||||
|
||||
if (destBufferDims.width > gl()->GetMaxTextureSize() ||
|
||||
destBufferDims.height > gl()->GetMaxTextureSize()) {
|
||||
if (destBufferRect.width > gl()->GetMaxTextureSize() ||
|
||||
destBufferRect.height > gl()->GetMaxTextureSize()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -545,9 +494,6 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
|
||||
PRUint32 bufferFlags = canHaveRotation ? ALLOW_REPEAT : 0;
|
||||
if (canReuseBuffer) {
|
||||
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
|
||||
"resolution changes must clear the buffer!");
|
||||
|
||||
nsIntRect keepArea;
|
||||
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
|
||||
// Set mBufferRotation so that the pixels currently in mBuffer
|
||||
|
@ -571,12 +517,12 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
// We can't do a real self-copy because the buffer is rotated.
|
||||
// So allocate a new buffer for the destination.
|
||||
destBufferRect = neededRegion.GetBounds();
|
||||
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
|
||||
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
|
||||
if (!destBuffer)
|
||||
return result;
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
destBufferOnWhite =
|
||||
CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
|
||||
CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
|
||||
if (!destBufferOnWhite)
|
||||
return result;
|
||||
}
|
||||
|
@ -593,13 +539,13 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
}
|
||||
} else {
|
||||
// The buffer's not big enough, so allocate a new one
|
||||
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
|
||||
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
|
||||
if (!destBuffer)
|
||||
return result;
|
||||
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
destBufferOnWhite =
|
||||
CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
|
||||
CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
|
||||
if (!destBufferOnWhite)
|
||||
return result;
|
||||
}
|
||||
|
@ -623,24 +569,21 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
srcRect.MoveBy(- mBufferRect.TopLeft() + mBufferRotation);
|
||||
dstRect.MoveBy(- destBufferRect.TopLeft());
|
||||
|
||||
nsIntSize size = ScaledSize(destBufferRect.Size(), aXResolution, aYResolution);
|
||||
destBuffer->Resize(size);
|
||||
srcRect.ScaleRoundOut(aXResolution, aYResolution);
|
||||
dstRect.ScaleRoundOut(aXResolution, aYResolution);
|
||||
destBuffer->Resize(destBufferRect.Size());
|
||||
|
||||
gl()->BlitTextureImage(mTexImage, srcRect,
|
||||
destBuffer, dstRect);
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
destBufferOnWhite->Resize(size);
|
||||
destBufferOnWhite->Resize(destBufferRect.Size());
|
||||
gl()->BlitTextureImage(mTexImageOnWhite, srcRect,
|
||||
destBufferOnWhite, dstRect);
|
||||
}
|
||||
} else {
|
||||
// can't blit, just draw everything
|
||||
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
|
||||
destBuffer = CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
destBufferOnWhite =
|
||||
CreateClampOrRepeatTextureImage(gl(), destBufferDims, contentType, bufferFlags);
|
||||
CreateClampOrRepeatTextureImage(gl(), destBufferRect.Size(), contentType, bufferFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -672,7 +615,6 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
// Make the region to draw relative to the buffer, before
|
||||
// passing to BeginUpdate.
|
||||
result.mRegionToDraw.MoveBy(offset);
|
||||
result.mRegionToDraw.ScaleRoundOut(aXResolution, aYResolution);
|
||||
// BeginUpdate is allowed to modify the given region,
|
||||
// if it wants more to be repainted than we request.
|
||||
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
|
||||
|
@ -711,15 +653,10 @@ BasicBufferOGL::BeginPaint(ContentType aContentType,
|
|||
NS_WARNING("unable to get context for update");
|
||||
return result;
|
||||
}
|
||||
result.mContext->Scale(aXResolution, aYResolution);
|
||||
result.mContext->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y));
|
||||
// Move rgnToPaint back into position so that the thebes callback
|
||||
// gets the right coordintes.
|
||||
result.mRegionToDraw.ScaleRoundOut(1/aXResolution, 1/aYResolution);
|
||||
result.mRegionToDraw.MoveBy(-offset);
|
||||
// Round our region out to values that will scale cleanly by the given
|
||||
// resolution.
|
||||
result.mRegionToDraw.ExtendForScaling(aXResolution, aYResolution);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -795,15 +732,8 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
|
|||
gfxASurface::CONTENT_COLOR_ALPHA;
|
||||
|
||||
gfxMatrix transform2d;
|
||||
gfxSize scale(1.0, 1.0);
|
||||
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;
|
||||
}
|
||||
|
@ -811,14 +741,11 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
|
|||
flags |= ThebesLayerBufferOGL::PAINT_WILL_RESAMPLE;
|
||||
}
|
||||
|
||||
Buffer::PaintState state =
|
||||
mBuffer->BeginPaint(contentType, paintXRes, paintYRes, flags);
|
||||
Buffer::PaintState state = mBuffer->BeginPaint(contentType, flags);
|
||||
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
|
||||
|
||||
if (state.mContext) {
|
||||
state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
|
||||
mXResolution = paintXRes;
|
||||
mYResolution = paintYRes;
|
||||
|
||||
LayerManager::DrawThebesLayerCallback callback =
|
||||
mOGLManager->GetThebesLayerCallback();
|
||||
|
@ -866,8 +793,7 @@ public:
|
|||
: ThebesLayerBufferOGL(aLayer, aLayer)
|
||||
{}
|
||||
|
||||
virtual PaintState BeginPaint(ContentType aContentType,
|
||||
float, float, PRUint32) {
|
||||
virtual PaintState BeginPaint(ContentType aContentType, PRUint32) {
|
||||
NS_RUNTIMEABORT("can't BeginPaint for a shadow layer");
|
||||
return PaintState();
|
||||
}
|
||||
|
@ -903,26 +829,8 @@ ShadowBufferOGL::Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
|
|||
nsIntPoint visTopLeft = mLayer->GetVisibleRegion().GetBounds().TopLeft();
|
||||
destRegion.MoveBy(-visTopLeft);
|
||||
|
||||
// |aUpdated|, |aRect|, and |aRotation| are in thebes-layer space,
|
||||
// unadjusted for resolution. The texture is in device space, so
|
||||
// first we need to map the update params to device space.
|
||||
//
|
||||
// XXX this prematurely commits us to updating rects instead of
|
||||
// regions here. This will be a perf penalty on platforms that
|
||||
// support region updates. This is OK for now because the
|
||||
// TextureImage backends we care about need to update contiguous
|
||||
// rects anyway, and would do this conversion internally. To fix
|
||||
// this, we would need to scale the region instead of its bounds
|
||||
// here.
|
||||
nsIntRect destBounds = destRegion.GetBounds();
|
||||
gfxRect destRect(destBounds.x, destBounds.y, destBounds.width, destBounds.height);
|
||||
destRect.Scale(mLayer->GetXResolution(), mLayer->GetYResolution());
|
||||
destRect.RoundOut();
|
||||
|
||||
// NB: this gfxContext must not escape EndUpdate() below
|
||||
nsIntRegion scaledDestRegion(nsIntRect(destRect.X(), destRect.Y(),
|
||||
destRect.Width(), destRect.Height()));
|
||||
mTexImage->DirectUpdate(aUpdate, scaledDestRegion);
|
||||
mTexImage->DirectUpdate(aUpdate, destRegion);
|
||||
|
||||
mBufferRect = aRect;
|
||||
mBufferRotation = aRotation;
|
||||
|
@ -940,8 +848,7 @@ ShadowThebesLayerOGL::~ShadowThebesLayerOGL()
|
|||
|
||||
void
|
||||
ShadowThebesLayerOGL::SetFrontBuffer(const OptionalThebesBuffer& aNewFront,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution, float aYResolution)
|
||||
const nsIntRegion& aValidRegion)
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
|
@ -960,7 +867,6 @@ ShadowThebesLayerOGL::Swap(const ThebesBuffer& aNewFront,
|
|||
const nsIntRegion& aUpdatedRegion,
|
||||
ThebesBuffer* aNewBack,
|
||||
nsIntRegion* aNewBackValidRegion,
|
||||
float* aNewXResolution, float* aNewYResolution,
|
||||
OptionalThebesBuffer* aReadOnlyFront,
|
||||
nsIntRegion* aFrontUpdatedRegion)
|
||||
{
|
||||
|
@ -971,8 +877,6 @@ ShadowThebesLayerOGL::Swap(const ThebesBuffer& aNewFront,
|
|||
|
||||
*aNewBack = aNewFront;
|
||||
*aNewBackValidRegion = mValidRegion;
|
||||
*aNewXResolution = mXResolution;
|
||||
*aNewYResolution = mYResolution;
|
||||
*aReadOnlyFront = null_t();
|
||||
aFrontUpdatedRegion->SetEmpty();
|
||||
}
|
||||
|
|
|
@ -93,12 +93,10 @@ public:
|
|||
|
||||
// ShadowThebesLayer impl
|
||||
virtual void SetFrontBuffer(const OptionalThebesBuffer& aNewFront,
|
||||
const nsIntRegion& aValidRegion,
|
||||
float aXResolution, float aYResolution);
|
||||
const nsIntRegion& aValidRegion);
|
||||
virtual void
|
||||
Swap(const ThebesBuffer& aNewFront, const nsIntRegion& aUpdatedRegion,
|
||||
ThebesBuffer* aNewBack, nsIntRegion* aNewBackValidRegion,
|
||||
float* aNewXResolution, float* aNewYResolution,
|
||||
OptionalThebesBuffer* aReadOnlyFront, nsIntRegion* aFrontUpdatedRegion);
|
||||
virtual void DestroyFrontBuffer();
|
||||
|
||||
|
|
|
@ -295,7 +295,12 @@ struct BaseRect {
|
|||
|
||||
// Scale 'this' by aScale, converting coordinates to integers so that the result is
|
||||
// the smallest integer-coordinate rectangle containing the unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
|
||||
// Scale 'this' by aXScale and aYScale, converting coordinates to integers so
|
||||
// that the result is the smallest integer-coordinate rectangle containing the
|
||||
// unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleRoundOut(double aXScale, double aYScale)
|
||||
{
|
||||
T right = static_cast<T>(NS_ceil(double(XMost()) * aXScale));
|
||||
|
@ -305,6 +310,38 @@ struct BaseRect {
|
|||
width = right - x;
|
||||
height = bottom - y;
|
||||
}
|
||||
// Scale 'this' by aScale, converting coordinates to integers so that the result is
|
||||
// the largest integer-coordinate rectangle contained by the unrounded result.
|
||||
void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); }
|
||||
// Scale 'this' by aXScale and aYScale, converting coordinates to integers so
|
||||
// that the result is the largest integer-coordinate rectangle contained by the
|
||||
// unrounded result.
|
||||
void ScaleRoundIn(double aXScale, double aYScale)
|
||||
{
|
||||
T right = static_cast<T>(NS_floor(double(XMost()) * aXScale));
|
||||
T bottom = static_cast<T>(NS_floor(double(YMost()) * aYScale));
|
||||
x = static_cast<T>(NS_ceil(double(x) * aXScale));
|
||||
y = static_cast<T>(NS_ceil(double(y) * aYScale));
|
||||
width = NS_MAX<T>(0, right - x);
|
||||
height = NS_MAX<T>(0, bottom - y);
|
||||
}
|
||||
// Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
|
||||
// the smallest integer-coordinate rectangle containing the unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleInverseRoundOut(double aScale) { ScaleInverseRoundOut(aScale, aScale); }
|
||||
// Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
|
||||
// that the result is the smallest integer-coordinate rectangle containing the
|
||||
// unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleInverseRoundOut(double aXScale, double aYScale)
|
||||
{
|
||||
T right = static_cast<T>(ceil(double(XMost()) / aXScale));
|
||||
T bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
|
||||
x = static_cast<T>(floor(double(x) / aXScale));
|
||||
y = static_cast<T>(floor(double(y) / aYScale));
|
||||
width = right - x;
|
||||
height = bottom - y;
|
||||
}
|
||||
|
||||
private:
|
||||
// Do not use the default operator== or operator!= !
|
||||
|
|
|
@ -52,6 +52,8 @@ struct nsPoint : public mozilla::BasePoint<nscoord, nsPoint> {
|
|||
nsPoint(const nsPoint& aPoint) : Super(aPoint) {}
|
||||
nsPoint(nscoord aX, nscoord aY) : Super(aX, aY) {}
|
||||
|
||||
inline nsIntPoint ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
inline nsIntPoint ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
// Converts this point from aFromAPP, an appunits per pixel ratio, to aToAPP.
|
||||
|
@ -67,14 +69,23 @@ struct nsIntPoint : public mozilla::BasePoint<PRInt32, nsIntPoint> {
|
|||
};
|
||||
|
||||
inline nsIntPoint
|
||||
nsPoint::ToNearestPixels(nscoord aAppUnitsPerPixel) const {
|
||||
nsPoint::ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return nsIntPoint(
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel)),
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel)));
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale),
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale));
|
||||
}
|
||||
|
||||
inline nsIntPoint
|
||||
nsPoint::ToNearestPixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nsPoint
|
||||
nsPoint::ConvertAppUnits(PRInt32 aFromAPP, PRInt32 aToAPP) const {
|
||||
nsPoint::ConvertAppUnits(PRInt32 aFromAPP, PRInt32 aToAPP) const
|
||||
{
|
||||
if (aFromAPP != aToAPP) {
|
||||
nsPoint point;
|
||||
point.x = NSToCoordRound(NSCoordScale(x, aFromAPP, aToAPP));
|
||||
|
|
|
@ -54,27 +54,6 @@ static bool IsFloatInteger(float aFloat)
|
|||
}
|
||||
#endif
|
||||
|
||||
nsRect& nsRect::ExtendForScaling(float aXMult, float aYMult)
|
||||
{
|
||||
NS_ASSERTION((IsFloatInteger(aXMult) || IsFloatInteger(1/aXMult)) &&
|
||||
(IsFloatInteger(aYMult) || IsFloatInteger(1/aYMult)),
|
||||
"Multiplication factors must be integers or 1/integer");
|
||||
|
||||
// Scale rect by multiplier, snap outwards to integers and then unscale.
|
||||
// We round the results to the nearest integer to prevent floating point errors.
|
||||
if (aXMult < 1) {
|
||||
nscoord right = NSToCoordRound(ceil(float(XMost()) * aXMult) / aXMult);
|
||||
x = NSToCoordRound(floor(float(x) * aXMult) / aXMult);
|
||||
width = right - x;
|
||||
}
|
||||
if (aYMult < 1) {
|
||||
nscoord bottom = NSToCoordRound(ceil(float(YMost()) * aYMult) / aYMult);
|
||||
y = NSToCoordRound(floor(float(y) * aYMult) / aYMult);
|
||||
height = bottom - y;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Diagnostics
|
||||
|
||||
|
|
|
@ -81,20 +81,24 @@ struct NS_GFX nsRect :
|
|||
}
|
||||
#endif
|
||||
|
||||
// Extend the rect outwards such that the edges are on integer boundaries
|
||||
// and the edges scaled by aXMult/aYMult are also on integer boundaries.
|
||||
// aXMult/aYMult must be N or 1/N for integer N.
|
||||
nsRect& ExtendForScaling(float aXMult, float aYMult);
|
||||
|
||||
// Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
|
||||
// In the RoundOut version we make the rect the smallest rect containing the
|
||||
// unrounded result. In the RoundIn version we make the rect the largest rect
|
||||
// contained in the unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
inline nsRect ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const;
|
||||
inline nsRect ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const;
|
||||
|
||||
inline nsIntRect ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const;
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
inline nsIntRect ScaleToOutsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
|
||||
inline nsIntRect ScaleToInsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const;
|
||||
};
|
||||
|
||||
|
@ -175,46 +179,67 @@ nsRect::ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const
|
|||
|
||||
// scale the rect but round to preserve centers
|
||||
inline nsIntRect
|
||||
nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
|
||||
nsRect::ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsIntRect rect;
|
||||
rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel));
|
||||
rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel));
|
||||
rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale);
|
||||
rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale);
|
||||
rect.width = NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(),
|
||||
aAppUnitsPerPixel)) - rect.x;
|
||||
aAppUnitsPerPixel) * aXScale) - rect.x;
|
||||
rect.height = NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(),
|
||||
aAppUnitsPerPixel)) - rect.y;
|
||||
aAppUnitsPerPixel) * aYScale) - rect.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
// scale the rect but round to smallest containing rect
|
||||
inline nsIntRect
|
||||
nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
|
||||
nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsIntRect rect;
|
||||
rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)));
|
||||
rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)));
|
||||
rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
|
||||
rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
|
||||
rect.width = NSToIntCeil(NSAppUnitsToFloatPixels(XMost(),
|
||||
float(aAppUnitsPerPixel))) - rect.x;
|
||||
float(aAppUnitsPerPixel)) * aXScale) - rect.x;
|
||||
rect.height = NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
|
||||
float(aAppUnitsPerPixel))) - rect.y;
|
||||
float(aAppUnitsPerPixel)) * aYScale) - rect.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
// scale the rect but round to largest contained rect
|
||||
inline nsIntRect
|
||||
nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
|
||||
nsRect::ScaleToInsidePixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsIntRect rect;
|
||||
rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)));
|
||||
rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)));
|
||||
rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
|
||||
rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
|
||||
rect.width = NSToIntFloor(NSAppUnitsToFloatPixels(XMost(),
|
||||
float(aAppUnitsPerPixel))) - rect.x;
|
||||
float(aAppUnitsPerPixel)) * aXScale) - rect.x;
|
||||
rect.height = NSToIntFloor(NSAppUnitsToFloatPixels(YMost(),
|
||||
float(aAppUnitsPerPixel))) - rect.y;
|
||||
float(aAppUnitsPerPixel)) * aYScale) - rect.y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
inline nsIntRect
|
||||
nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nsIntRect
|
||||
nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline nsIntRect
|
||||
nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
// app units are integer multiples of pixels, so no rounding needed
|
||||
inline nsRect
|
||||
nsIntRect::ToAppUnits(nscoord aAppUnitsPerPixel) const
|
||||
|
|
|
@ -1293,22 +1293,6 @@ void nsRegion::MoveBy (nsPoint aPt)
|
|||
}
|
||||
}
|
||||
|
||||
nsRegion& nsRegion::ExtendForScaling (float aXMult, float aYMult)
|
||||
{
|
||||
nsRegion region;
|
||||
nsRegionRectIterator iter(*this);
|
||||
for (;;) {
|
||||
const nsRect* r = iter.Next();
|
||||
if (!r)
|
||||
break;
|
||||
nsRect rect = *r;
|
||||
rect.ExtendForScaling(aXMult, aYMult);
|
||||
region.Or(region, rect);
|
||||
}
|
||||
*this = region;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRegion& nsRegion::ScaleRoundOut (float aXScale, float aYScale)
|
||||
{
|
||||
nsRegion region;
|
||||
|
@ -1325,6 +1309,22 @@ nsRegion& nsRegion::ScaleRoundOut (float aXScale, float aYScale)
|
|||
return *this;
|
||||
}
|
||||
|
||||
nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
|
||||
{
|
||||
nsRegion region;
|
||||
nsRegionRectIterator iter(*this);
|
||||
for (;;) {
|
||||
const nsRect* r = iter.Next();
|
||||
if (!r)
|
||||
break;
|
||||
nsRect rect = *r;
|
||||
rect.ScaleInverseRoundOut(aXScale, aYScale);
|
||||
region.Or(region, rect);
|
||||
}
|
||||
*this = region;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRegion nsRegion::ConvertAppUnitsRoundOut (PRInt32 aFromAPP, PRInt32 aToAPP) const
|
||||
{
|
||||
if (aFromAPP == aToAPP) {
|
||||
|
@ -1389,6 +1389,20 @@ nsIntRegion nsRegion::ToNearestPixels (nscoord aAppUnitsPerPixel) const
|
|||
return ToPixels(aAppUnitsPerPixel, false);
|
||||
}
|
||||
|
||||
nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsIntRegion result;
|
||||
nsRegionRectIterator rgnIter(*this);
|
||||
const nsRect* currentRect;
|
||||
while ((currentRect = rgnIter.Next())) {
|
||||
nsIntRect deviceRect =
|
||||
currentRect->ScaleToOutsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
result.Or(result, deviceRect);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// A cell's "value" is a pair consisting of
|
||||
// a) the area of the subrectangle it corresponds to, if it's in
|
||||
// aContainingRect and in the region, 0 otherwise
|
||||
|
|
|
@ -185,9 +185,10 @@ public:
|
|||
nsRegion ConvertAppUnitsRoundOut (PRInt32 aFromAPP, PRInt32 aToAPP) const;
|
||||
nsRegion ConvertAppUnitsRoundIn (PRInt32 aFromAPP, PRInt32 aToAPP) const;
|
||||
nsRegion& ScaleRoundOut(float aXScale, float aYScale);
|
||||
nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
|
||||
nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
|
||||
nsRegion& ExtendForScaling (float aXMult, float aYMult);
|
||||
|
||||
/**
|
||||
* Gets the largest rectangle contained in the region.
|
||||
|
@ -448,12 +449,6 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
nsIntRegion& ExtendForScaling (float aXMult, float aYMult)
|
||||
{
|
||||
mImpl.ExtendForScaling(aXMult, aYMult);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by adding area to it
|
||||
* if necessary. The simplified region will be a superset of the
|
||||
|
|
|
@ -44,12 +44,17 @@
|
|||
// Maximum allowable size
|
||||
#define NS_MAXSIZE nscoord_MAX
|
||||
|
||||
struct nsIntSize;
|
||||
|
||||
struct nsSize : public mozilla::BaseSize<nscoord, nsSize> {
|
||||
typedef mozilla::BaseSize<nscoord, nsSize> Super;
|
||||
|
||||
nsSize() : Super() {}
|
||||
nsSize(nscoord aWidth, nscoord aHeight) : Super(aWidth, aHeight) {}
|
||||
|
||||
inline nsIntSize ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
// Converts this size from aFromAPP, an appunits per pixel ratio, to aToAPP.
|
||||
inline nsSize ConvertAppUnits(PRInt32 aFromAPP, PRInt32 aToAPP) const;
|
||||
};
|
||||
|
@ -61,6 +66,15 @@ struct nsIntSize : public mozilla::BaseSize<PRInt32, nsIntSize> {
|
|||
nsIntSize(PRInt32 aWidth, PRInt32 aHeight) : Super(aWidth, aHeight) {}
|
||||
};
|
||||
|
||||
inline nsIntSize
|
||||
nsSize::ScaleToNearestPixels(float aXScale, float aYScale,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
return nsIntSize(
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(width, aAppUnitsPerPixel) * aXScale),
|
||||
NSToIntRoundUp(NSAppUnitsToDoublePixels(height, aAppUnitsPerPixel) * aYScale));
|
||||
}
|
||||
|
||||
inline nsSize
|
||||
nsSize::ConvertAppUnits(PRInt32 aFromAPP, PRInt32 aToAPP) const {
|
||||
if (aFromAPP != aToAPP) {
|
||||
|
|
|
@ -119,7 +119,8 @@ public:
|
|||
static PRBool GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut);
|
||||
|
||||
/**
|
||||
* Clamp aVal to a power of kScaleResolution.
|
||||
* Return the smallest power of kScaleResolution (2) greater than or equal to
|
||||
* aVal.
|
||||
*/
|
||||
static gfxFloat ClampToScaleFactor(gfxFloat aVal);
|
||||
};
|
||||
|
|
|
@ -134,9 +134,11 @@ public:
|
|||
ContainerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
nsIFrame* aContainerFrame,
|
||||
ContainerLayer* aContainerLayer) :
|
||||
ContainerLayer* aContainerLayer,
|
||||
const FrameLayerBuilder::ContainerParameters& aParameters) :
|
||||
mBuilder(aBuilder), mManager(aManager),
|
||||
mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer),
|
||||
mParameters(aParameters),
|
||||
mNextFreeRecycledThebesLayer(0), mNextFreeRecycledColorLayer(0),
|
||||
mNextFreeRecycledImageLayer(0), mInvalidateAllThebesContent(PR_FALSE)
|
||||
{
|
||||
|
@ -202,7 +204,7 @@ protected:
|
|||
* @param aSolidColor if non-null, the visible area of the item is
|
||||
* a constant color given by *aSolidColor
|
||||
*/
|
||||
void Accumulate(nsDisplayListBuilder* aBuilder,
|
||||
void Accumulate(ContainerState* aState,
|
||||
nsDisplayItem* aItem,
|
||||
const nsIntRect& aVisibleRect,
|
||||
const nsIntRect& aDrawRect,
|
||||
|
@ -288,6 +290,7 @@ protected:
|
|||
*/
|
||||
FrameLayerBuilder::Clip mImageClip;
|
||||
};
|
||||
friend class ThebesLayerData;
|
||||
|
||||
/**
|
||||
* Grab the next recyclable ThebesLayer, or create one if there are no
|
||||
|
@ -362,6 +365,7 @@ protected:
|
|||
LayerManager* mManager;
|
||||
nsIFrame* mContainerFrame;
|
||||
ContainerLayer* mContainerLayer;
|
||||
FrameLayerBuilder::ContainerParameters mParameters;
|
||||
/**
|
||||
* The region of ThebesLayers that should be invalidated every time
|
||||
* we recycle one.
|
||||
|
@ -389,13 +393,30 @@ class ThebesDisplayItemLayerUserData : public LayerUserData
|
|||
{
|
||||
public:
|
||||
ThebesDisplayItemLayerUserData() :
|
||||
mForcedBackgroundColor(NS_RGBA(0,0,0,0)) {}
|
||||
mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
|
||||
mXScale(1.f), mYScale(1.f),
|
||||
mActiveScrolledRootPosition(0, 0) {}
|
||||
|
||||
/**
|
||||
* A color that should be painted over the bounds of the layer's visible
|
||||
* region before any other content is painted.
|
||||
*/
|
||||
nscolor mForcedBackgroundColor;
|
||||
/**
|
||||
* The resolution scale used.
|
||||
*/
|
||||
float mXScale, mYScale;
|
||||
/**
|
||||
* We try to make 0,0 of the ThebesLayer be the top-left of the
|
||||
* border-box of the "active scrolled root" frame (i.e. the nearest ancestor
|
||||
* frame for the display items that is being actively scrolled). But
|
||||
* we force the ThebesLayer transform to be an integer translation, and we may
|
||||
* have a resolution scale, so we have to snap the ThebesLayer transform, so
|
||||
* 0,0 may not be exactly the top-left of the active scrolled root. Here we
|
||||
* store the coordinates in ThebesLayer space of the top-left of the
|
||||
* active scrolled root.
|
||||
*/
|
||||
gfxPoint mActiveScrolledRootPosition;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -792,6 +813,7 @@ ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot)
|
|||
{
|
||||
// We need a new thebes layer
|
||||
nsRefPtr<ThebesLayer> layer;
|
||||
ThebesDisplayItemLayerUserData* data;
|
||||
if (mNextFreeRecycledThebesLayer < mRecycledThebesLayers.Length()) {
|
||||
// Recycle a layer
|
||||
layer = mRecycledThebesLayers[mNextFreeRecycledThebesLayer];
|
||||
|
@ -800,6 +822,10 @@ ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot)
|
|||
// reapply any necessary clipping.
|
||||
layer->SetClipRect(nsnull);
|
||||
|
||||
data = static_cast<ThebesDisplayItemLayerUserData*>
|
||||
(layer->GetUserData(&gThebesDisplayItemLayerUserData));
|
||||
NS_ASSERTION(data, "Recycled ThebesLayers must have user data");
|
||||
|
||||
// This gets called on recycled ThebesLayers that are going to be in the
|
||||
// final layer tree, so it's a convenient time to invalidate the
|
||||
// content that changed where we don't know what ThebesLayer it belonged
|
||||
|
@ -808,7 +834,9 @@ ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot)
|
|||
// transform. See nsGfxScrollFrame::InvalidateInternal, where
|
||||
// we ensure that mInvalidThebesContent is updated according to the
|
||||
// scroll position as of the most recent paint.
|
||||
if (mInvalidateAllThebesContent) {
|
||||
if (mInvalidateAllThebesContent ||
|
||||
data->mXScale != mParameters.mXScale ||
|
||||
data->mYScale != mParameters.mYScale) {
|
||||
nsIntRect invalidate = layer->GetValidRegion().GetBounds();
|
||||
layer->InvalidateRegion(invalidate);
|
||||
} else {
|
||||
|
@ -824,21 +852,43 @@ ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot)
|
|||
if (!layer)
|
||||
return nsnull;
|
||||
// Mark this layer as being used for Thebes-painting display items
|
||||
layer->SetUserData(&gThebesDisplayItemLayerUserData,
|
||||
new ThebesDisplayItemLayerUserData());
|
||||
data = new ThebesDisplayItemLayerUserData();
|
||||
layer->SetUserData(&gThebesDisplayItemLayerUserData, data);
|
||||
}
|
||||
data->mXScale = mParameters.mXScale;
|
||||
data->mYScale = mParameters.mYScale;
|
||||
// If we're in a transformed subtree, but no ancestor transform is actively
|
||||
// changing, we'll use the residual translation when drawing into the
|
||||
// ThebesLayer to ensure that snapping exactly matches the ideal transform.
|
||||
layer->SetAllowResidualTranslation(
|
||||
mParameters.mInTransformedSubtree && !mParameters.mInActiveTransformedSubtree);
|
||||
|
||||
mBuilder->LayerBuilder()->SaveLastPaintOffset(layer);
|
||||
|
||||
// Set up transform so that 0,0 in the Thebes layer corresponds to the
|
||||
// (pixel-snapped) top-left of the aActiveScrolledRoot.
|
||||
nsPoint offset = mBuilder->ToReferenceFrame(aActiveScrolledRoot);
|
||||
nsIntPoint pixOffset = offset.ToNearestPixels(
|
||||
aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel());
|
||||
nscoord appUnitsPerDevPixel = aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel();
|
||||
gfxPoint scaledOffset(
|
||||
NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale,
|
||||
NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale);
|
||||
nsIntPoint pixOffset(NSToIntRoundUp(scaledOffset.x), NSToIntRoundUp(scaledOffset.y));
|
||||
gfxMatrix matrix;
|
||||
matrix.Translate(gfxPoint(pixOffset.x, pixOffset.y));
|
||||
layer->SetTransform(gfx3DMatrix::From2D(matrix));
|
||||
|
||||
// Calculate exact position of the top-left of the active scrolled root.
|
||||
// This might not be 0,0 due to the snapping in ScaleToNearestPixels.
|
||||
gfxPoint activeScrolledRootTopLeft = scaledOffset - matrix.GetTranslation();
|
||||
// If it has changed, then we need to invalidate the entire layer since the
|
||||
// pixels in the layer buffer have the content at a (subpixel) offset
|
||||
// from what we need.
|
||||
if (activeScrolledRootTopLeft != data->mActiveScrolledRootPosition) {
|
||||
data->mActiveScrolledRootPosition = activeScrolledRootTopLeft;
|
||||
nsIntRect invalidate = layer->GetValidRegion().GetBounds();
|
||||
layer->InvalidateRegion(invalidate);
|
||||
}
|
||||
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
|
@ -914,13 +964,14 @@ ContainerState::FindOpaqueBackgroundColorFor(PRInt32 aThebesLayerIndex)
|
|||
// The layer doesn't intersect our target, ignore it and move on
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// The candidate intersects our target. If any layer has a solid-color
|
||||
// area behind our target, this must be it. Scan its display items.
|
||||
nsPresContext* presContext = mContainerFrame->PresContext();
|
||||
nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
nsRect rect =
|
||||
target->mVisibleRegion.GetBounds().ToAppUnits(appUnitsPerDevPixel);
|
||||
rect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
|
||||
return mBuilder->LayerBuilder()->
|
||||
FindOpaqueColorCovering(mBuilder, candidate->mLayer, rect);
|
||||
}
|
||||
|
@ -960,9 +1011,9 @@ ContainerState::PopThebesLayerData()
|
|||
if (data->mImageClip.mHaveClipRect) {
|
||||
nsPresContext* presContext = mContainerFrame->PresContext();
|
||||
nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
nsIntRect clip = data->mImageClip.mClipRect.ToNearestPixels(appUnitsPerDevPixel);
|
||||
imageLayer->IntersectClipRect(
|
||||
data->mImageClip.mClipRect.ToNearestPixels(appUnitsPerDevPixel));
|
||||
nsIntRect clip = data->mImageClip.mClipRect.ScaleToNearestPixels(
|
||||
mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
|
||||
imageLayer->IntersectClipRect(clip);
|
||||
}
|
||||
layer = imageLayer;
|
||||
} else {
|
||||
|
@ -1101,20 +1152,22 @@ WindowHasTransparency(nsDisplayListBuilder* aBuilder)
|
|||
}
|
||||
|
||||
void
|
||||
ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
|
||||
ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
|
||||
nsDisplayItem* aItem,
|
||||
const nsIntRect& aVisibleRect,
|
||||
const nsIntRect& aDrawRect,
|
||||
const FrameLayerBuilder::Clip& aClip)
|
||||
{
|
||||
nscolor uniformColor;
|
||||
PRBool isUniform = aItem->IsUniform(aBuilder, &uniformColor);
|
||||
PRBool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor);
|
||||
// Some display items have to exist (so they can set forceTransparentSurface
|
||||
// below) but don't draw anything. They'll return true for isUniform but
|
||||
// a color with opacity 0.
|
||||
if (!isUniform || NS_GET_A(uniformColor) > 0) {
|
||||
if (isUniform &&
|
||||
aItem->GetBounds(aBuilder).ToInsidePixels(AppUnitsPerDevPixel(aItem)).Contains(aVisibleRect)) {
|
||||
aItem->GetBounds(aState->mBuilder).ScaleToInsidePixels(
|
||||
aState->mParameters.mXScale, aState->mParameters.mYScale,
|
||||
AppUnitsPerDevPixel(aItem)).Contains(aVisibleRect)) {
|
||||
if (mVisibleRegion.IsEmpty()) {
|
||||
// This color is all we have
|
||||
mSolidColor = uniformColor;
|
||||
|
@ -1147,7 +1200,7 @@ ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
|
||||
PRBool forceTransparentSurface = PR_FALSE;
|
||||
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &forceTransparentSurface);
|
||||
nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &forceTransparentSurface);
|
||||
if (!opaque.IsEmpty()) {
|
||||
nsRegionRectIterator iter(opaque);
|
||||
nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
|
||||
|
@ -1157,25 +1210,28 @@ ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
|
|||
// is a large opaque background at the bottom of z-order (e.g.,
|
||||
// a canvas background), so we need to make sure that the first rect
|
||||
// we see doesn't get discarded.
|
||||
nsIntRect rect = aClip.ApproximateIntersect(*r).ToInsidePixels(appUnitsPerDevPixel);
|
||||
nsIntRect rect = aClip.ApproximateIntersect(*r).ScaleToInsidePixels(
|
||||
aState->mParameters.mXScale, aState->mParameters.mYScale,
|
||||
appUnitsPerDevPixel);
|
||||
nsIntRegion tmp;
|
||||
tmp.Or(mOpaqueRegion, rect);
|
||||
// Opaque display items in chrome documents whose window is partially
|
||||
// transparent are always added to the opaque region. This helps ensure
|
||||
// that we get as much subpixel-AA as possible in the chrome.
|
||||
if (tmp.GetNumRects() <= 4 ||
|
||||
(WindowHasTransparency(aBuilder) &&
|
||||
(WindowHasTransparency(aState->mBuilder) &&
|
||||
aItem->GetUnderlyingFrame()->PresContext()->IsChrome())) {
|
||||
mOpaqueRegion = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
nsRect componentAlpha = aItem->GetComponentAlphaBounds(aBuilder);
|
||||
nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
|
||||
componentAlpha.IntersectRect(componentAlpha, aItem->GetVisibleRect());
|
||||
if (!componentAlpha.IsEmpty()) {
|
||||
nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
|
||||
if (!mOpaqueRegion.Contains(componentAlpha.ToOutsidePixels(appUnitsPerDevPixel))) {
|
||||
if (SuppressComponentAlpha(aBuilder, aItem, componentAlpha)) {
|
||||
if (!mOpaqueRegion.Contains(componentAlpha.ScaleToOutsidePixels(
|
||||
aState->mParameters.mXScale, aState->mParameters.mYScale, appUnitsPerDevPixel))) {
|
||||
if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) {
|
||||
aItem->DisableComponentAlpha();
|
||||
} else {
|
||||
mNeedComponentAlpha = PR_TRUE;
|
||||
|
@ -1244,7 +1300,7 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
|
|||
layer = thebesLayerData->mLayer;
|
||||
}
|
||||
|
||||
thebesLayerData->Accumulate(mBuilder, aItem, aVisibleRect, aDrawRect, aClip);
|
||||
thebesLayerData->Accumulate(this, aItem, aVisibleRect, aDrawRect, aClip);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
|
@ -1257,7 +1313,8 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
|
|||
// using a temporary BasicLayerManager.
|
||||
nsRefPtr<BasicLayerManager> tempManager = new BasicLayerManager();
|
||||
tempManager->BeginTransactionWithTarget(aContext);
|
||||
nsRefPtr<Layer> layer = aItem->BuildLayer(aBuilder, tempManager);
|
||||
nsRefPtr<Layer> layer =
|
||||
aItem->BuildLayer(aBuilder, tempManager, FrameLayerBuilder::ContainerParameters());
|
||||
if (!layer) {
|
||||
tempManager->EndTransaction(nsnull, nsnull);
|
||||
return;
|
||||
|
@ -1308,13 +1365,15 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
|||
"items in a container layer should all have the same app units per dev pixel");
|
||||
|
||||
nsIntRect itemVisibleRect =
|
||||
item->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel);
|
||||
item->GetVisibleRect().ScaleToOutsidePixels(
|
||||
mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
|
||||
nsRect itemContent = item->GetBounds(mBuilder);
|
||||
if (aClip.mHaveClipRect) {
|
||||
itemContent.IntersectRect(aClip.mClipRect, itemContent);
|
||||
}
|
||||
mBounds.UnionRect(mBounds, itemContent);
|
||||
nsIntRect itemDrawRect = itemContent.ToOutsidePixels(appUnitsPerDevPixel);
|
||||
nsIntRect itemDrawRect = itemContent.ScaleToOutsidePixels(
|
||||
mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
|
||||
LayerState layerState = item->GetLayerState(mBuilder, mManager);
|
||||
|
||||
nsIFrame* activeScrolledRoot =
|
||||
|
@ -1346,12 +1405,21 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
|||
aClip.RemoveRoundedCorners();
|
||||
|
||||
// Just use its layer.
|
||||
nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager);
|
||||
nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
|
||||
if (!ownLayer) {
|
||||
InvalidateForLayerChange(item, ownLayer);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's not a ContainerLayer, we need to apply the scale transform
|
||||
// ourselves.
|
||||
if (!ownLayer->AsContainerLayer()) {
|
||||
// The layer's current transform is applied first, then the result is scaled.
|
||||
gfx3DMatrix transform = ownLayer->GetTransform()*
|
||||
gfx3DMatrix::Scale(mParameters.mXScale, mParameters.mYScale, 1.0f);
|
||||
ownLayer->SetTransform(transform);
|
||||
}
|
||||
|
||||
ownLayer->SetIsFixedPosition(!nsLayoutUtils::ScrolledByViewportScrolling(
|
||||
activeScrolledRoot, mBuilder));
|
||||
|
||||
|
@ -1362,7 +1430,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
|||
// It has its own layer. Update that layer's clip and visible rects.
|
||||
if (aClip.mHaveClipRect) {
|
||||
ownLayer->IntersectClipRect(
|
||||
aClip.mClipRect.ToNearestPixels(appUnitsPerDevPixel));
|
||||
aClip.mClipRect.ScaleToNearestPixels(
|
||||
mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel));
|
||||
}
|
||||
ThebesLayerData* data = GetTopThebesLayerData();
|
||||
if (data) {
|
||||
|
@ -1422,17 +1491,25 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer)
|
|||
// in the container via regular frame invalidation.
|
||||
nsRect bounds = aItem->GetBounds(mBuilder);
|
||||
PRInt32 appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
|
||||
nsIntRect r = bounds.ToOutsidePixels(appUnitsPerDevPixel);
|
||||
|
||||
ThebesLayer* t = oldLayer->AsThebesLayer();
|
||||
if (t) {
|
||||
InvalidatePostTransformRegion(t, r,
|
||||
ThebesDisplayItemLayerUserData* data =
|
||||
static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
|
||||
// Note that whenever the layer's scale changes, we invalidate the whole thing,
|
||||
// so it doesn't matter whether we are using the old scale at last paint
|
||||
// or a new scale here
|
||||
InvalidatePostTransformRegion(t,
|
||||
bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, appUnitsPerDevPixel),
|
||||
mBuilder->LayerBuilder()->GetLastPaintOffset(t));
|
||||
}
|
||||
if (aNewLayer) {
|
||||
ThebesLayer* newLayer = aNewLayer->AsThebesLayer();
|
||||
if (newLayer) {
|
||||
InvalidatePostTransformRegion(newLayer, r,
|
||||
ThebesDisplayItemLayerUserData* data =
|
||||
static_cast<ThebesDisplayItemLayerUserData*>(newLayer->GetUserData(&gThebesDisplayItemLayerUserData));
|
||||
InvalidatePostTransformRegion(newLayer,
|
||||
bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, appUnitsPerDevPixel),
|
||||
GetTranslationForThebesLayer(newLayer));
|
||||
}
|
||||
}
|
||||
|
@ -1596,12 +1673,75 @@ ContainerState::Finish(PRUint32* aTextContentFlags)
|
|||
*aTextContentFlags = textContentFlags;
|
||||
}
|
||||
|
||||
static FrameLayerBuilder::ContainerParameters
|
||||
ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
|
||||
nsIFrame* aContainerFrame,
|
||||
const gfx3DMatrix* aTransform,
|
||||
const FrameLayerBuilder::ContainerParameters& aIncomingScale,
|
||||
ContainerLayer* aLayer)
|
||||
{
|
||||
gfx3DMatrix transform =
|
||||
gfx3DMatrix::Scale(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
|
||||
if (aTransform) {
|
||||
// aTransform is applied first, then the scale is applied to the result
|
||||
transform = (*aTransform)*transform;
|
||||
}
|
||||
|
||||
gfxMatrix transform2d;
|
||||
gfxSize scale;
|
||||
// Only fiddle with scale factors for the retaining layer manager, since
|
||||
// it only matters for retained layers
|
||||
if (aLayerBuilder->GetRetainingLayerManager() == aLayer->Manager() &&
|
||||
transform.Is2D(&transform2d)) {
|
||||
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
|
||||
scale = transform2d.ScaleFactors(PR_TRUE);
|
||||
// For frames with a changing transform that's not just a translation,
|
||||
// round scale factors up to nearest power-of-2 boundary so that we don't
|
||||
// keep having to redraw the content as it scales up and down. Rounding up to nearest
|
||||
// power-of-2 boundary ensures we never scale up, only down --- avoiding
|
||||
// jaggies. It also ensures we never scale down by more than a factor of 2,
|
||||
// avoiding bad downscaling quality.
|
||||
gfxMatrix frameTransform;
|
||||
if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
|
||||
aTransform &&
|
||||
(!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
|
||||
scale.width = gfxUtils::ClampToScaleFactor(scale.width);
|
||||
scale.height = gfxUtils::ClampToScaleFactor(scale.height);
|
||||
} else {
|
||||
// XXX Do we need to move nearly-integer values to integers here?
|
||||
}
|
||||
// If the scale factors are too small, just use 1.0. The content is being
|
||||
// scaled out of sight anyway.
|
||||
if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
|
||||
scale.width = scale.height = 1.0;
|
||||
}
|
||||
} else {
|
||||
scale = gfxSize(1.0, 1.0);
|
||||
}
|
||||
|
||||
// Apply the inverse of our resolution-scale before the rest of our transform
|
||||
transform = gfx3DMatrix::Scale(1.0/scale.width, 1.0/scale.height, 1.0)*transform;
|
||||
aLayer->SetTransform(transform);
|
||||
|
||||
FrameLayerBuilder::ContainerParameters
|
||||
result(scale.width, scale.height, aIncomingScale);
|
||||
if (aTransform) {
|
||||
result.mInTransformedSubtree = true;
|
||||
if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
|
||||
result.mInActiveTransformedSubtree = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
already_AddRefed<ContainerLayer>
|
||||
FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
nsIFrame* aContainerFrame,
|
||||
nsDisplayItem* aContainerItem,
|
||||
const nsDisplayList& aChildren)
|
||||
const nsDisplayList& aChildren,
|
||||
const ContainerParameters& aParameters,
|
||||
const gfx3DMatrix* aTransform)
|
||||
{
|
||||
FrameProperties props = aContainerFrame->Properties();
|
||||
PRUint32 containerDisplayItemKey =
|
||||
|
@ -1646,7 +1786,11 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
|||
return containerLayer.forget();
|
||||
}
|
||||
|
||||
ContainerState state(aBuilder, aManager, aContainerFrame, containerLayer);
|
||||
ContainerParameters scaleParameters =
|
||||
ChooseScaleAndSetTransform(this, aContainerFrame, aTransform, aParameters,
|
||||
containerLayer);
|
||||
ContainerState state(aBuilder, aManager, aContainerFrame, containerLayer,
|
||||
scaleParameters);
|
||||
nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
if (aManager == mRetainingManager) {
|
||||
|
@ -1666,7 +1810,8 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
|||
nsPoint offset = offsetAtLastPaint ? *offsetAtLastPaint : currentOffset;
|
||||
invalidThebesContent->MoveBy(offset);
|
||||
state.SetInvalidThebesContent(invalidThebesContent->
|
||||
ToOutsidePixels(appUnitsPerDevPixel));
|
||||
ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
|
||||
appUnitsPerDevPixel));
|
||||
// We have to preserve the current contents of invalidThebesContent
|
||||
// because there might be multiple container layers for the same
|
||||
// frame and we need to invalidate the ThebesLayer children of all
|
||||
|
@ -1691,14 +1836,18 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
nsRect bounds = state.GetChildrenBounds();
|
||||
NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
|
||||
nsIntRect pixBounds = bounds.ToOutsidePixels(appUnitsPerDevPixel);
|
||||
nsIntRect pixBounds =
|
||||
bounds.ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
|
||||
appUnitsPerDevPixel);
|
||||
containerLayer->SetVisibleRegion(pixBounds);
|
||||
// Make sure that rounding the visible region out didn't add any area
|
||||
// we won't paint
|
||||
if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface() &&
|
||||
bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
|
||||
// Clear CONTENT_COMPONENT_ALPHA
|
||||
flags = Layer::CONTENT_OPAQUE;
|
||||
if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
|
||||
bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
|
||||
if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
|
||||
// Clear CONTENT_COMPONENT_ALPHA
|
||||
flags = Layer::CONTENT_OPAQUE;
|
||||
}
|
||||
}
|
||||
containerLayer->SetContentFlags(flags);
|
||||
|
||||
|
@ -1822,6 +1971,34 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
/*
|
||||
* A note on residual transforms:
|
||||
*
|
||||
* In a transformed subtree we sometimes apply the ThebesLayer's
|
||||
* "residual transform" when drawing content into the ThebesLayer.
|
||||
* This is a translation by components in the range [-0.5,0.5) provided
|
||||
* by the layer system; applying the residual transform followed by the
|
||||
* transforms used by layer compositing ensures that the subpixel alignment
|
||||
* of the content of the ThebesLayer exactly matches what it would be if
|
||||
* we used cairo/Thebes to draw directly to the screen without going through
|
||||
* retained layer buffers.
|
||||
*
|
||||
* The visible and valid regions of the ThebesLayer are computed without
|
||||
* knowing the residual transform (because we don't know what the residual
|
||||
* transform is going to be until we've built the layer tree!). So we have to
|
||||
* consider whether content painted in the range [x, xmost) might be painted
|
||||
* outside the visible region we computed for that content. The visible region
|
||||
* would be [floor(x), ceil(xmost)). The content would be rendered at
|
||||
* [x + r, xmost + r), where -0.5 <= r < 0.5. So some half-rendered pixels could
|
||||
* indeed fall outside the computed visible region, which is not a big deal;
|
||||
* similar issues already arise when we snap cliprects to nearest pixels.
|
||||
* Note that if the rendering of the content is snapped to nearest pixels ---
|
||||
* which it often is --- then the content is actually rendered at
|
||||
* [snap(x + r), snap(xmost + r)). It turns out that floor(x) <= snap(x + r)
|
||||
* and ceil(xmost) >= snap(xmost + r), so the rendering of snapped content
|
||||
* always falls within the visible region we computed.
|
||||
*/
|
||||
|
||||
/* static */ void
|
||||
FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
gfxContext* aContext,
|
||||
|
@ -1864,15 +2041,22 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
|||
// ThebesLayer
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
|
||||
nsIntPoint offset = GetTranslationForThebesLayer(aLayer);
|
||||
aContext->Translate(-gfxPoint(offset.x, offset.y));
|
||||
// Apply the residual transform if it has been enabled, to ensure that
|
||||
// snapping when we draw into aContext exactly matches the ideal transform.
|
||||
// See above for why this is OK.
|
||||
aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y));
|
||||
aContext->Scale(userData->mXScale, userData->mYScale);
|
||||
|
||||
nsPresContext* presContext = containerLayerFrame->PresContext();
|
||||
PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
nsRect r = (aRegionToInvalidate.GetBounds() + offset).
|
||||
ToAppUnits(appUnitsPerDevPixel);
|
||||
containerLayerFrame->InvalidateWithFlags(r,
|
||||
nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
|
||||
nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
|
||||
if (!aRegionToInvalidate.IsEmpty()) {
|
||||
nsRect r = (aRegionToInvalidate.GetBounds() + offset).
|
||||
ToAppUnits(appUnitsPerDevPixel);
|
||||
r.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
|
||||
containerLayerFrame->InvalidateWithFlags(r,
|
||||
nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
|
||||
nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
|
||||
}
|
||||
|
||||
PRUint32 i;
|
||||
// Update visible regions. We need perform visibility analysis again
|
||||
|
@ -1883,6 +2067,7 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
|||
nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
|
||||
visible.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
|
||||
NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
|
||||
visible.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
|
||||
|
||||
for (i = items.Length(); i > 0; --i) {
|
||||
ClippedDisplayItem* cdi = &items[i - 1];
|
||||
|
@ -1989,7 +2174,7 @@ void
|
|||
FrameLayerBuilder::DumpRetainedLayerTree()
|
||||
{
|
||||
if (mRetainingManager) {
|
||||
mRetainingManager->Dump(stderr);
|
||||
mRetainingManager->Dump(stdout);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -93,6 +93,15 @@ enum LayerState {
|
|||
* corresponds to the (pixel-snapped) top-left of the aActiveScrolledRoot.
|
||||
* It sets up ContainerLayers so that 0,0 in the container layer
|
||||
* corresponds to the snapped top-left of the display list reference frame.
|
||||
*
|
||||
* When we construct a container layer, we know the transform that will be
|
||||
* applied to the layer. If the transform scales the content, we can get
|
||||
* better results when intermediate buffers are used by pushing some scale
|
||||
* from the container's transform down to the children. For ThebesLayer
|
||||
* children, the scaling can be achieved by changing the size of the layer
|
||||
* and drawing into it with increased or decreased resolution. By convention,
|
||||
* integer types (nsIntPoint/nsIntSize/nsIntRect/nsIntRegion) are all in layer
|
||||
* coordinates, post-scaling, whereas appunit types are all pre-scaling.
|
||||
*/
|
||||
class FrameLayerBuilder {
|
||||
public:
|
||||
|
@ -132,6 +141,22 @@ public:
|
|||
*/
|
||||
void DidEndTransaction(LayerManager* aManager);
|
||||
|
||||
struct ContainerParameters {
|
||||
ContainerParameters() :
|
||||
mXScale(1), mYScale(1),
|
||||
mInTransformedSubtree(false), mInActiveTransformedSubtree(false) {}
|
||||
ContainerParameters(float aXScale, float aYScale) :
|
||||
mXScale(aXScale), mYScale(aYScale),
|
||||
mInTransformedSubtree(false), mInActiveTransformedSubtree(false) {}
|
||||
ContainerParameters(float aXScale, float aYScale,
|
||||
const ContainerParameters& aParent) :
|
||||
mXScale(aXScale), mYScale(aYScale),
|
||||
mInTransformedSubtree(aParent.mInTransformedSubtree),
|
||||
mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree) {}
|
||||
float mXScale, mYScale;
|
||||
bool mInTransformedSubtree;
|
||||
bool mInActiveTransformedSubtree;
|
||||
};
|
||||
/**
|
||||
* Build a container layer for a display item that contains a child
|
||||
* list, either reusing an existing one or creating a new one. It
|
||||
|
@ -146,13 +171,17 @@ public:
|
|||
* Returns a layer with clip rect cleared; it is the
|
||||
* caller's responsibility to add any clip rect. The visible region
|
||||
* is set based on what's in the layer.
|
||||
* The container layer is transformed by aTransform (if non-null), and
|
||||
* the result is transformed by the scale factors in aContainerParameters.
|
||||
*/
|
||||
already_AddRefed<ContainerLayer>
|
||||
BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
nsIFrame* aContainerFrame,
|
||||
nsDisplayItem* aContainerItem,
|
||||
const nsDisplayList& aChildren);
|
||||
const nsDisplayList& aChildren,
|
||||
const ContainerParameters& aContainerParameters,
|
||||
const gfx3DMatrix* aTransform);
|
||||
|
||||
/**
|
||||
* Get a retained layer for a display item that needs to create its own
|
||||
|
|
|
@ -7689,13 +7689,13 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
|
|||
}
|
||||
}
|
||||
if (aChange & nsChangeHint_UpdateOpacityLayer) {
|
||||
aFrame->MarkLayersActive();
|
||||
aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
|
||||
aFrame->InvalidateLayer(aFrame->GetVisualOverflowRectRelativeToSelf(),
|
||||
nsDisplayItem::TYPE_OPACITY);
|
||||
}
|
||||
|
||||
if (aChange & nsChangeHint_UpdateTransformLayer) {
|
||||
aFrame->MarkLayersActive();
|
||||
aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
|
||||
// Invalidate the old transformed area. The new transformed area
|
||||
// will be invalidated by nsFrame::FinishAndStoreOverflowArea.
|
||||
aFrame->InvalidateTransformLayer();
|
||||
|
|
|
@ -197,6 +197,7 @@ nsCSSBorderRenderer::nsCSSBorderRenderer(PRInt32 aAppUnitsPerPixel,
|
|||
|
||||
mOneUnitBorder = CheckFourFloatsEqual(mBorderWidths, 1.0);
|
||||
mNoBorderRadius = AllCornersZeroSize(mBorderRadii);
|
||||
mAvoidStroke = PR_FALSE;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
@ -560,7 +561,8 @@ nsCSSBorderRenderer::FillSolidBorder(const gfxRect& aOuterRect,
|
|||
// common border styles, such as inset and outset, that are
|
||||
// top-left/bottom-right split.
|
||||
if (aSides == SIDE_BITS_ALL &&
|
||||
CheckFourFloatsEqual(aBorderSizes, aBorderSizes[0]))
|
||||
CheckFourFloatsEqual(aBorderSizes, aBorderSizes[0]) &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
gfxRect r(aOuterRect);
|
||||
r.Deflate(aBorderSizes[0] / 2.0);
|
||||
|
@ -635,7 +637,7 @@ nsCSSBorderRenderer::FillSolidBorder(const gfxRect& aOuterRect,
|
|||
for (PRUint32 i = 0; i < 4; i++) {
|
||||
if (aSides & (1 << i)) {
|
||||
mContext->NewPath();
|
||||
mContext->Rectangle(r[i]);
|
||||
mContext->Rectangle(r[i], PR_TRUE);
|
||||
mContext->Fill();
|
||||
}
|
||||
}
|
||||
|
@ -1379,22 +1381,29 @@ nsCSSBorderRenderer::DrawBorders()
|
|||
return;
|
||||
}
|
||||
|
||||
// round mOuterRect and mInnerRect; they're already an integer
|
||||
// number of pixels apart and should stay that way after
|
||||
// rounding.
|
||||
mOuterRect.Round();
|
||||
mInnerRect.Round();
|
||||
|
||||
gfxMatrix mat = mContext->CurrentMatrix();
|
||||
|
||||
// Clamp the CTM to be pixel-aligned; we do this only
|
||||
// for translation-only matrices now, but we could do it
|
||||
// if the matrix has just a scale as well. We should not
|
||||
// do it if there's a rotation.
|
||||
if (!mat.HasNonTranslation()) {
|
||||
if (mat.HasNonTranslation()) {
|
||||
if (!mat.HasNonAxisAlignedTransform()) {
|
||||
// Scale + transform. Avoid stroke fast-paths so that we have a chance
|
||||
// of snapping to pixel boundaries.
|
||||
mAvoidStroke = PR_TRUE;
|
||||
}
|
||||
} else {
|
||||
mat.x0 = floor(mat.x0 + 0.5);
|
||||
mat.y0 = floor(mat.y0 + 0.5);
|
||||
mContext->SetMatrix(mat);
|
||||
|
||||
// round mOuterRect and mInnerRect; they're already an integer
|
||||
// number of pixels apart and should stay that way after
|
||||
// rounding. We don't do this if there's a scale in the current transform
|
||||
// since this loses information that might be relevant when we're scaling.
|
||||
mOuterRect.Round();
|
||||
mInnerRect.Round();
|
||||
}
|
||||
|
||||
PRBool allBordersSameWidth = AllBordersSameWidth();
|
||||
|
@ -1415,7 +1424,8 @@ nsCSSBorderRenderer::DrawBorders()
|
|||
mCompositeColors[0] == NULL &&
|
||||
allBordersSameWidth &&
|
||||
mBorderStyles[0] == NS_STYLE_BORDER_STYLE_SOLID &&
|
||||
mNoBorderRadius)
|
||||
mNoBorderRadius &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
// Very simple case.
|
||||
SetupStrokeStyle(NS_SIDE_TOP);
|
||||
|
@ -1432,7 +1442,8 @@ nsCSSBorderRenderer::DrawBorders()
|
|||
allBordersSameWidth &&
|
||||
mBorderStyles[0] == NS_STYLE_BORDER_STYLE_DOTTED &&
|
||||
mBorderWidths[0] < 3 &&
|
||||
mNoBorderRadius)
|
||||
mNoBorderRadius &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
// Very simple case. We draw this rectangular dotted borner without
|
||||
// antialiasing. The dots should be pixel aligned.
|
||||
|
@ -1453,7 +1464,8 @@ nsCSSBorderRenderer::DrawBorders()
|
|||
if (allBordersSame &&
|
||||
allBordersSameWidth &&
|
||||
mCompositeColors[0] == NULL &&
|
||||
mBorderStyles[0] == NS_STYLE_BORDER_STYLE_SOLID)
|
||||
mBorderStyles[0] == NS_STYLE_BORDER_STYLE_SOLID &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
NS_FOR_CSS_CORNERS(i) {
|
||||
if (mBorderRadii[i].width <= mBorderWidths[0]) {
|
||||
|
@ -1495,13 +1507,15 @@ nsCSSBorderRenderer::DrawBorders()
|
|||
allBordersSameWidth &&
|
||||
mCompositeColors[0] == NULL &&
|
||||
mBorderWidths[0] == 1 &&
|
||||
mNoBorderRadius)
|
||||
mNoBorderRadius &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
DrawSingleWidthSolidBorder();
|
||||
return;
|
||||
}
|
||||
|
||||
if (allBordersSolid && !hasCompositeColors)
|
||||
if (allBordersSolid && !hasCompositeColors &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
DrawNoCompositeColorSolidBorder();
|
||||
return;
|
||||
|
@ -1509,7 +1523,8 @@ nsCSSBorderRenderer::DrawBorders()
|
|||
|
||||
if (allBordersSolid &&
|
||||
allBordersSameWidth &&
|
||||
mNoBorderRadius)
|
||||
mNoBorderRadius &&
|
||||
!mAvoidStroke)
|
||||
{
|
||||
// Easy enough to deal with.
|
||||
DrawRectangularCompositeColors();
|
||||
|
|
|
@ -137,6 +137,7 @@ struct nsCSSBorderRenderer {
|
|||
// calculated values
|
||||
PRPackedBool mOneUnitBorder;
|
||||
PRPackedBool mNoBorderRadius;
|
||||
PRPackedBool mAvoidStroke;
|
||||
|
||||
// For all the sides in the bitmask, would they be rendered
|
||||
// in an identical color and style?
|
||||
|
|
|
@ -200,21 +200,26 @@ static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
|
|||
static void RecordFrameMetrics(nsIFrame* aForFrame,
|
||||
nsIFrame* aScrollFrame,
|
||||
ContainerLayer* aRoot,
|
||||
nsRect aVisibleRect,
|
||||
nsRect aViewport,
|
||||
const nsRect& aVisibleRect,
|
||||
const nsRect& aViewport,
|
||||
nsRect* aDisplayPort,
|
||||
ViewID aScrollId) {
|
||||
ViewID aScrollId,
|
||||
const nsDisplayItem::ContainerParameters& aContainerParameters) {
|
||||
nsPresContext* presContext = aForFrame->PresContext();
|
||||
PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
||||
nsIntRect visible = aVisibleRect.ToNearestPixels(presContext->AppUnitsPerDevPixel());
|
||||
nsIntRect visible = aVisibleRect.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
aRoot->SetVisibleRegion(nsIntRegion(visible));
|
||||
|
||||
FrameMetrics metrics;
|
||||
|
||||
PRInt32 auPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
metrics.mViewport = aViewport.ToNearestPixels(auPerDevPixel);
|
||||
metrics.mViewport = aViewport.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
|
||||
if (aDisplayPort) {
|
||||
metrics.mDisplayPort = aDisplayPort->ToNearestPixels(auPerDevPixel);
|
||||
metrics.mDisplayPort = aDisplayPort->ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
}
|
||||
|
||||
nsIScrollableFrame* scrollableFrame = nsnull;
|
||||
|
@ -225,16 +230,15 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
|
|||
nsSize contentSize =
|
||||
scrollableFrame->GetScrollRange().Size() +
|
||||
scrollableFrame->GetScrollPortRect().Size();
|
||||
metrics.mContentSize = nsIntSize(NSAppUnitsToIntPixels(contentSize.width, auPerDevPixel),
|
||||
NSAppUnitsToIntPixels(contentSize.height, auPerDevPixel));
|
||||
|
||||
metrics.mViewportScrollOffset =
|
||||
scrollableFrame->GetScrollPosition().ToNearestPixels(auPerDevPixel);
|
||||
metrics.mContentSize = contentSize.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
metrics.mViewportScrollOffset = scrollableFrame->GetScrollPosition().ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
}
|
||||
else {
|
||||
nsSize contentSize = aForFrame->GetSize();
|
||||
metrics.mContentSize = nsIntSize(NSAppUnitsToIntPixels(contentSize.width, auPerDevPixel),
|
||||
NSAppUnitsToIntPixels(contentSize.height, auPerDevPixel));
|
||||
metrics.mContentSize = contentSize.ScaleToNearestPixels(
|
||||
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
|
||||
}
|
||||
|
||||
metrics.mScrollId = aScrollId;
|
||||
|
@ -589,14 +593,22 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||
aBuilder->LayerBuilder()->DidBeginRetainedLayerTransaction(layerManager);
|
||||
}
|
||||
|
||||
nsRefPtr<ContainerLayer> root = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nsnull, *this);
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
nsPresContext* presContext = aForFrame->PresContext();
|
||||
nsIPresShell* presShell = presContext->GetPresShell();
|
||||
|
||||
nsDisplayItem::ContainerParameters containerParameters
|
||||
(presShell->GetXResolution(), presShell->GetYResolution());
|
||||
nsRefPtr<ContainerLayer> root = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nsnull, *this,
|
||||
containerParameters, nsnull);
|
||||
if (!root)
|
||||
return;
|
||||
// Root is being scaled up by the X/Y resolution. Scale it back down.
|
||||
gfx3DMatrix rootTransform = root->GetTransform()*
|
||||
gfx3DMatrix::Scale(1.0f/containerParameters.mXScale,
|
||||
1.0f/containerParameters.mYScale, 1.0f);
|
||||
root->SetTransform(rootTransform);
|
||||
|
||||
ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID
|
||||
: FrameMetrics::NULL_SCROLL_ID;
|
||||
|
||||
|
@ -611,17 +623,8 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
RecordFrameMetrics(aForFrame, rootScrollFrame,
|
||||
root, mVisibleRect, mVisibleRect,
|
||||
(usingDisplayport ? &displayport : nsnull), id);
|
||||
|
||||
// If the layer manager supports resolution scaling, set that up
|
||||
if (LayerManager::LAYERS_BASIC == layerManager->GetBackendType()) {
|
||||
BasicLayerManager* basicManager =
|
||||
static_cast<BasicLayerManager*>(layerManager.get());
|
||||
// This is free if both resolutions are 1.0, or neither resolution
|
||||
// has changed since the last transaction
|
||||
basicManager->SetResolution(presShell->GetXResolution(),
|
||||
presShell->GetYResolution());
|
||||
}
|
||||
(usingDisplayport ? &displayport : nsnull), id,
|
||||
containerParameters);
|
||||
|
||||
layerManager->SetRoot(root);
|
||||
aBuilder->LayerBuilder()->WillEndTransaction(layerManager);
|
||||
|
@ -1701,9 +1704,11 @@ nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
|||
// nsDisplayOpacity uses layers for rendering
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager) {
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList);
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
|
||||
aContainerParameters, nsnull);
|
||||
if (!layer)
|
||||
return nsnull;
|
||||
|
||||
|
@ -1714,7 +1719,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
nsDisplayItem::LayerState
|
||||
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager) {
|
||||
if (mFrame->AreLayersMarkedActive())
|
||||
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer))
|
||||
return LAYER_ACTIVE;
|
||||
nsIFrame* activeScrolledRoot =
|
||||
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
|
||||
|
@ -1768,9 +1773,11 @@ nsDisplayOwnLayer::~nsDisplayOwnLayer() {
|
|||
// nsDisplayOpacity uses layers for rendering
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager) {
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList);
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
|
||||
aContainerParameters, nsnull);
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
|
@ -1833,9 +1840,11 @@ nsDisplayScrollLayer::~nsDisplayScrollLayer()
|
|||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager) {
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<ContainerLayer> layer = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList);
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
|
||||
aContainerParameters, nsnull);
|
||||
|
||||
// Get the already set unique ID for scrolling this content remotely.
|
||||
// Or, if not set, generate a new ID.
|
||||
|
@ -1852,7 +1861,8 @@ nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport);
|
||||
}
|
||||
RecordFrameMetrics(mScrolledFrame, mScrollFrame, layer, mVisibleRect, viewport,
|
||||
(usingDisplayport ? &displayport : nsnull), scrollId);
|
||||
(usingDisplayport ? &displayport : nsnull), scrollId,
|
||||
aContainerParameters);
|
||||
|
||||
return layer.forget();
|
||||
}
|
||||
|
@ -2375,7 +2385,8 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
|
|||
}
|
||||
|
||||
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
|
||||
LayerManager *aManager)
|
||||
LayerManager *aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{
|
||||
gfxMatrix newTransformMatrix =
|
||||
GetResultingTransformMatrix(mFrame, ToReferenceFrame(),
|
||||
|
@ -2384,19 +2395,16 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
|
|||
if (newTransformMatrix.IsSingular())
|
||||
return nsnull;
|
||||
|
||||
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList());
|
||||
if (!layer)
|
||||
return nsnull;
|
||||
|
||||
layer->SetTransform(gfx3DMatrix::From2D(newTransformMatrix));
|
||||
return layer.forget();
|
||||
gfx3DMatrix matrix = gfx3DMatrix::From2D(newTransformMatrix);
|
||||
return aBuilder->LayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList(),
|
||||
aContainerParameters, &matrix);
|
||||
}
|
||||
|
||||
nsDisplayItem::LayerState
|
||||
nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager) {
|
||||
if (mFrame->AreLayersMarkedActive())
|
||||
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer))
|
||||
return LAYER_ACTIVE;
|
||||
nsIFrame* activeScrolledRoot =
|
||||
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
|
||||
|
|
|
@ -721,9 +721,15 @@ public:
|
|||
*
|
||||
* The caller (nsDisplayList) is responsible for setting the visible
|
||||
* region of the layer.
|
||||
*
|
||||
* @param aContainerParameters should be passed to
|
||||
* FrameLayerBuilder::BuildContainerLayerFor if a ContainerLayer is
|
||||
* constructed.
|
||||
*/
|
||||
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{ return nsnull; }
|
||||
|
||||
/**
|
||||
|
@ -1753,7 +1759,8 @@ public:
|
|||
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
PRBool* aForceTransparentSurface = nsnull);
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
|
@ -1776,7 +1783,8 @@ public:
|
|||
#endif
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
{
|
||||
|
@ -1837,7 +1845,8 @@ public:
|
|||
#endif
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
|
||||
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion,
|
||||
|
@ -2098,7 +2107,8 @@ public:
|
|||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager);
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
virtual PRBool ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
||||
nsRegion *aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion);
|
||||
|
|
|
@ -213,7 +213,7 @@ void
|
|||
nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayList& aList)
|
||||
{
|
||||
PrintDisplayListTo(aBuilder, aList, 0, stderr);
|
||||
PrintDisplayListTo(aBuilder, aList, 0, stdout);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1292,7 +1292,7 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
|
|||
|
||||
#ifdef DEBUG
|
||||
if (gDumpEventList) {
|
||||
fprintf(stderr, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
|
||||
fprintf(stdout, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
|
||||
nsFrame::PrintDisplayList(&builder, list);
|
||||
}
|
||||
#endif
|
||||
|
@ -1601,7 +1601,7 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
|
||||
#ifdef DEBUG
|
||||
if (gDumpPaintList) {
|
||||
fprintf(stderr, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
|
||||
fprintf(stdout, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
|
||||
dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
nsFrame::PrintDisplayList(&builder, list);
|
||||
}
|
||||
|
@ -1653,10 +1653,10 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
|
||||
#ifdef DEBUG
|
||||
if (gDumpPaintList) {
|
||||
fprintf(stderr, "Painting --- after optimization:\n");
|
||||
fprintf(stdout, "Painting --- after optimization:\n");
|
||||
nsFrame::PrintDisplayList(&builder, list);
|
||||
|
||||
fprintf(stderr, "Painting --- retained layer tree:\n");
|
||||
fprintf(stdout, "Painting --- retained layer tree:\n");
|
||||
builder.LayerBuilder()->DumpRetainedLayerTree();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -118,6 +118,7 @@
|
|||
#include "nsExpirationTracker.h"
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "nsChangeHint.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "CSSCalc.h"
|
||||
|
@ -4099,12 +4100,17 @@ nsIFrame::InvalidateTransformLayer()
|
|||
|
||||
class LayerActivity {
|
||||
public:
|
||||
LayerActivity(nsIFrame* aFrame) : mFrame(aFrame) {}
|
||||
LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
|
||||
~LayerActivity();
|
||||
nsExpirationState* GetExpirationState() { return &mState; }
|
||||
|
||||
nsIFrame* mFrame;
|
||||
nsExpirationState mState;
|
||||
// mChangeHint can be some combination of nsChangeHint_UpdateOpacityLayer and
|
||||
// nsChangeHint_UpdateTransformLayer (or neither)
|
||||
// The presence of those bits indicates whether opacity or transform
|
||||
// changes have been detected.
|
||||
nsChangeHint mChangeHint;
|
||||
};
|
||||
|
||||
class LayerActivityTracker : public nsExpirationTracker<LayerActivity,4> {
|
||||
|
@ -4149,7 +4155,7 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
|
|||
}
|
||||
|
||||
void
|
||||
nsIFrame::MarkLayersActive()
|
||||
nsIFrame::MarkLayersActive(nsChangeHint aChangeHint)
|
||||
{
|
||||
FrameProperties properties = Properties();
|
||||
LayerActivity* layerActivity =
|
||||
|
@ -4164,6 +4170,7 @@ nsIFrame::MarkLayersActive()
|
|||
gLayerActivityTracker->AddObject(layerActivity);
|
||||
properties.Set(LayerActivityProperty(), layerActivity);
|
||||
}
|
||||
NS_UpdateHint(layerActivity->mChangeHint, aChangeHint);
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -4172,6 +4179,14 @@ nsIFrame::AreLayersMarkedActive()
|
|||
return Properties().Get(LayerActivityProperty()) != nsnull;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
|
||||
{
|
||||
LayerActivity* layerActivity =
|
||||
static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
|
||||
return layerActivity && (layerActivity->mChangeHint & aChangeHint);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsFrame::ShutdownLayerActivityTimer()
|
||||
{
|
||||
|
|
|
@ -1634,9 +1634,6 @@ CanScrollWithBlitting(nsIFrame* aFrame)
|
|||
{
|
||||
for (nsIFrame* f = aFrame; f;
|
||||
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
|
||||
if (f->GetStyleDisplay()->HasTransform()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
|
||||
f->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
return PR_FALSE;
|
||||
|
|
|
@ -97,7 +97,8 @@ public:
|
|||
}
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{
|
||||
return static_cast<nsHTMLCanvasFrame*>(mFrame)->
|
||||
BuildLayer(aBuilder, aManager, this);
|
||||
|
@ -132,7 +133,7 @@ nsHTMLCanvasFrame::Init(nsIContent* aContent,
|
|||
// We can fill in the canvas before the canvas frame is created, in
|
||||
// which case we never get around to marking the layer active. Therefore,
|
||||
// we mark it active here when we create the frame.
|
||||
MarkLayersActive();
|
||||
MarkLayersActive(nsChangeHint(0));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -1997,14 +1997,25 @@ public:
|
|||
* after a short period. This call does no immediate invalidation,
|
||||
* but when the mark times out, we'll invalidate the frame's overflow
|
||||
* area.
|
||||
* @param aChangeHint nsChangeHint_UpdateTransformLayer or
|
||||
* nsChangeHint_UpdateOpacityLayer or 0, depending on whether the change
|
||||
* triggering the activity is a changing transform, changing opacity, or
|
||||
* something else.
|
||||
*/
|
||||
void MarkLayersActive();
|
||||
|
||||
void MarkLayersActive(nsChangeHint aHint);
|
||||
/**
|
||||
* Return true if this frame is marked as needing active layers.
|
||||
*/
|
||||
PRBool AreLayersMarkedActive();
|
||||
|
||||
/**
|
||||
* Return true if this frame is marked as needing active layers.
|
||||
* @param aChangeHint nsChangeHint_UpdateTransformLayer or
|
||||
* nsChangeHint_UpdateOpacityLayer. We return true only if
|
||||
* a change in the transform or opacity has been recorded while layers have
|
||||
* been marked active for this frame.
|
||||
*/
|
||||
PRBool AreLayersMarkedActive(nsChangeHint aChangeHint);
|
||||
|
||||
/**
|
||||
* @param aFlags see InvalidateInternal below
|
||||
*/
|
||||
|
|
|
@ -956,7 +956,8 @@ public:
|
|||
NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{
|
||||
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
|
||||
}
|
||||
|
|
|
@ -348,7 +348,8 @@ public:
|
|||
nsTArray<nsIWidget::Configuration>* aConfigurations);
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{
|
||||
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder,
|
||||
aManager,
|
||||
|
|
|
@ -5131,7 +5131,7 @@ nsTextFrame::GetSnappedBaselineY(gfxContext* aContext, gfxFloat aY)
|
|||
gfxFloat appUnitsPerDevUnit = mTextRun->GetAppUnitsPerDevUnit();
|
||||
gfxFloat baseline = aY + mAscent;
|
||||
gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
|
||||
if (!aContext->UserToDevicePixelSnapped(putativeRect))
|
||||
if (!aContext->UserToDevicePixelSnapped(putativeRect, PR_TRUE))
|
||||
return baseline;
|
||||
return aContext->DeviceToUser(putativeRect.TopLeft()).y*appUnitsPerDevUnit;
|
||||
}
|
||||
|
|
|
@ -403,7 +403,8 @@ public:
|
|||
}
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{
|
||||
return static_cast<nsVideoFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
|
||||
}
|
||||
|
|
|
@ -204,6 +204,7 @@ ComputeShadowTreeTransform(nsIFrame* aContainerFrame,
|
|||
nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsIntPoint scrollOffset =
|
||||
aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
|
||||
// metricsScrollOffset is in layer coordinates.
|
||||
nsIntPoint metricsScrollOffset = aMetrics->mViewportScrollOffset;
|
||||
|
||||
if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) {
|
||||
|
@ -225,7 +226,7 @@ ComputeShadowTreeTransform(nsIFrame* aContainerFrame,
|
|||
static void
|
||||
BuildListForLayer(Layer* aLayer,
|
||||
nsFrameLoader* aRootFrameLoader,
|
||||
gfx3DMatrix aTransform,
|
||||
const gfx3DMatrix& aTransform,
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList& aShadowTree,
|
||||
nsIFrame* aSubdocFrame)
|
||||
|
@ -245,6 +246,8 @@ BuildListForLayer(Layer* aLayer,
|
|||
// Calculate transform for this layer.
|
||||
nsContentView* view =
|
||||
aRootFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
|
||||
// XXX why don't we include aLayer->GetTransform() in the inverse-scale here?
|
||||
// This seems wrong, but it doesn't seem to cause bugs!
|
||||
gfx3DMatrix applyTransform = ComputeShadowTreeTransform(
|
||||
aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(),
|
||||
1 / GetXScale(aTransform), 1 / GetYScale(aTransform));
|
||||
|
@ -252,14 +255,15 @@ BuildListForLayer(Layer* aLayer,
|
|||
|
||||
// As mentioned above, bounds calculation also depends on the scale
|
||||
// of this layer.
|
||||
Scale(aTransform, GetXScale(applyTransform), GetYScale(applyTransform));
|
||||
gfx3DMatrix tmpTransform = aTransform;
|
||||
Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform));
|
||||
|
||||
// Calculate rect for this layer based on aTransform.
|
||||
nsRect bounds;
|
||||
{
|
||||
nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
bounds = metrics->mViewport.ToAppUnits(auPerDevPixel);
|
||||
ApplyTransform(bounds, aTransform, auPerDevPixel);
|
||||
ApplyTransform(bounds, tmpTransform, auPerDevPixel);
|
||||
|
||||
}
|
||||
|
||||
|
@ -281,7 +285,7 @@ BuildListForLayer(Layer* aLayer,
|
|||
static void
|
||||
TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
|
||||
nsIFrame* aFrame, Layer* aLayer,
|
||||
ViewTransform& aTransform)
|
||||
const ViewTransform& aTransform)
|
||||
{
|
||||
ShadowLayer* shadow = aLayer->AsShadowLayer();
|
||||
shadow->SetShadowClipRect(aLayer->GetClipRect());
|
||||
|
@ -290,32 +294,38 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
|
|||
const FrameMetrics* metrics = GetFrameMetrics(aLayer);
|
||||
|
||||
gfx3DMatrix shadowTransform;
|
||||
ViewTransform layerTransform = aTransform;
|
||||
|
||||
if (metrics && metrics->IsScrollable()) {
|
||||
const ViewID scrollId = metrics->mScrollId;
|
||||
const nsContentView* view =
|
||||
aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
|
||||
NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree");
|
||||
const gfx3DMatrix& currentTransform = aLayer->GetTransform();
|
||||
|
||||
ViewTransform viewTransform = ComputeShadowTreeTransform(
|
||||
aFrame, aFrameLoader, metrics, view->GetViewConfig(),
|
||||
1 / aTransform.mXScale, 1 / aTransform.mYScale
|
||||
1 / (GetXScale(currentTransform)*layerTransform.mXScale),
|
||||
1 / (GetYScale(currentTransform)*layerTransform.mYScale)
|
||||
);
|
||||
|
||||
// Apply the layer's own transform *before* the view transform
|
||||
shadowTransform = gfx3DMatrix(viewTransform) * currentTransform;
|
||||
|
||||
if (metrics->IsRootScrollable()) {
|
||||
aTransform.mTranslation = viewTransform.mTranslation;
|
||||
viewTransform.mTranslation += GetRootFrameOffset(aFrame, aBuilder);
|
||||
layerTransform.mTranslation = viewTransform.mTranslation;
|
||||
// Apply the root frame translation *before* we do the rest of the transforms.
|
||||
nsIntPoint rootFrameOffset = GetRootFrameOffset(aFrame, aBuilder);
|
||||
shadowTransform = shadowTransform *
|
||||
gfx3DMatrix::Translation(float(rootFrameOffset.x), float(rootFrameOffset.y), 0.0);
|
||||
}
|
||||
|
||||
shadowTransform = gfx3DMatrix(viewTransform) * aLayer->GetTransform();
|
||||
|
||||
} else {
|
||||
shadowTransform = aLayer->GetTransform();
|
||||
}
|
||||
|
||||
if (aLayer->GetIsFixedPosition() &&
|
||||
!aLayer->GetParent()->GetIsFixedPosition()) {
|
||||
ReverseTranslate(shadowTransform, aTransform);
|
||||
ReverseTranslate(shadowTransform, layerTransform);
|
||||
const nsIntRect* clipRect = shadow->GetShadowClipRect();
|
||||
if (clipRect) {
|
||||
nsIntRect transformedClipRect(*clipRect);
|
||||
|
@ -325,12 +335,12 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
|
|||
}
|
||||
|
||||
shadow->SetShadowTransform(shadowTransform);
|
||||
aTransform.mXScale *= GetXScale(shadowTransform);
|
||||
aTransform.mYScale *= GetYScale(shadowTransform);
|
||||
layerTransform.mXScale *= GetXScale(shadowTransform);
|
||||
layerTransform.mYScale *= GetYScale(shadowTransform);
|
||||
|
||||
for (Layer* child = aLayer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, aTransform);
|
||||
TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -819,7 +829,8 @@ RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager)
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
{
|
||||
PRInt32 appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel);
|
||||
|
|
|
@ -143,7 +143,8 @@ public:
|
|||
|
||||
NS_OVERRIDE
|
||||
virtual already_AddRefed<Layer>
|
||||
BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager);
|
||||
BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
|
||||
NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.outer {
|
||||
background:yellow;
|
||||
position:absolute;
|
||||
left:100px;
|
||||
top:100px;
|
||||
width:420px;
|
||||
height:140px;
|
||||
line-height:28px;
|
||||
}
|
||||
.inner {
|
||||
float:left;
|
||||
width:140px;
|
||||
height:15.4px;
|
||||
background:black;
|
||||
}
|
||||
canvas {
|
||||
display:block;
|
||||
float:left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="outer"><div class="inner"></div><canvas id="c" width="10" height="10" style="width:14px; height:14px;"></canvas></div>
|
||||
<script>
|
||||
var ctx = document.getElementById("c").getContext("2d");
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(2, 2, 6, 6);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.outer {
|
||||
background:yellow;
|
||||
position:absolute;
|
||||
left:100px;
|
||||
top:100px;
|
||||
width:300px;
|
||||
height:100px;
|
||||
-moz-transform:scale(1.4);
|
||||
-moz-transform-origin:top left;
|
||||
transform:scale(1.4);
|
||||
transform-origin:top left;
|
||||
}
|
||||
.inner {
|
||||
float:left;
|
||||
width:100px;
|
||||
height:11px;
|
||||
background:black;
|
||||
}
|
||||
canvas {
|
||||
display:block;
|
||||
float:left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="outer"><div class="inner"></div><canvas id="c" width="10" height="10"></canvas></div>
|
||||
<script>
|
||||
var ctx = document.getElementById("c").getContext("2d");
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(2, 2, 6, 6);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
#parent {
|
||||
position: absolute;
|
||||
top: 100.8px;
|
||||
-moz-transform: scale(1.1232,1.1232);
|
||||
transform: scale(1.1232,1.1232);
|
||||
}
|
||||
#b1 {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 109px;
|
||||
background: #c00;
|
||||
-moz-transform: translate(100px,100px);
|
||||
transform: translate(100px,100px);
|
||||
}
|
||||
#b2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: white;
|
||||
-moz-transform: translate(400px,0);
|
||||
transform: translate(400px,0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="parent">
|
||||
<div id="b1"></div>
|
||||
<div id="b2"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<style>
|
||||
html { background:white; }
|
||||
#parent {
|
||||
position: absolute;
|
||||
top: 100.8px;
|
||||
-moz-transform: scale(1.1232,1.1232);
|
||||
transform: scale(1.1232,1.1232);
|
||||
}
|
||||
#b1 {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 109px;
|
||||
background: #c00;
|
||||
-moz-transform: translate(100px,100px);
|
||||
transform: translate(100px,100px);
|
||||
}
|
||||
#b2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: white;
|
||||
-moz-transform: translate(400px,200px);
|
||||
transform: translate(400px,200px);
|
||||
}
|
||||
#b2.done {
|
||||
-moz-transform: translate(400px,0);
|
||||
transform: translate(400px,0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="parent">
|
||||
<div id="b1"></div>
|
||||
<div id="b2"></div>
|
||||
</div>
|
||||
<script>
|
||||
function doTest() {
|
||||
document.getElementById('b2').setAttribute("class", "done");
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
window.addEventListener("MozReftestInvalidate", doTest, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { margin-top:101px; }
|
||||
.outer {
|
||||
-moz-transform:scale(1.4);
|
||||
-moz-transform-origin:top left;
|
||||
line-height:40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="outer"><div class="inner">Hello Kitty</div></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { margin-top:100.9px; }
|
||||
.outer {
|
||||
-moz-transform:scale(1.4);
|
||||
-moz-transform-origin:top left;
|
||||
line-height:40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="outer"><div class="inner">Hello Kitty</div></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="-moz-transform:scale(0.5); -moz-transform-origin:top left; border:10px solid black; border-radius:20px;">
|
||||
<div style="width:100px; height:100px; background:yellow"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="-moz-transform:scale(0.5); -moz-transform-origin:top left; border:10px solid black; border-radius:20px;">
|
||||
<canvas width="100" height="100" id="c" style="display:block"></canvas>
|
||||
<script>
|
||||
var c = document.getElementById("c");
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.fillStyle = "yellow";
|
||||
ctx.fillRect(0, 0, c.width, c.height);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div id="d" style="border:20px solid black; height:200px; width:200px;">
|
||||
<div style="width:200px; height:50px; background:yellow"></div>
|
||||
<div style="height:100px; background:blue;"></div>
|
||||
<div style="height:50px; background:orange;"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div id="d" style="-moz-transform:scale(2); -moz-transform-origin:top left; border:10px solid black; height:100px; width:100px; overflow:hidden">
|
||||
<canvas width="100" height="100" id="c" style="display:block"></canvas>
|
||||
<div style="height:50px; background:blue;"></div>
|
||||
<div style="height:50px; background:orange;"></div>
|
||||
</div>
|
||||
<script>
|
||||
var c = document.getElementById("c");
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.fillStyle = "yellow";
|
||||
ctx.fillRect(0, 0, c.width, c.height);
|
||||
var d = document.getElementById("d");
|
||||
d.scrollTop = 75;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1561,7 +1561,7 @@ asserts(0-1) == 582146-1.html about:blank
|
|||
== 584699-1.html 584699-1-ref.html
|
||||
== 585598-2.xhtml 585598-2-ref.xhtml
|
||||
== 586400-1.html 586400-1-ref.html
|
||||
fails-if(Android) fails-if(cocoaWidget) == 586683-1.html 586683-1-ref.html
|
||||
fails-if(Android) == 586683-1.html 586683-1-ref.html
|
||||
== 589615-1a.xhtml 589615-1-ref.html
|
||||
== 589615-1b.html 589615-1-ref.html
|
||||
== 589672-1.html 589672-1-ref.html
|
||||
|
@ -1622,6 +1622,7 @@ fails-if(Android) == 625409-1.html 625409-1-ref.html
|
|||
fails-if(Android) == 632423-1.html 632423-1-ref.html
|
||||
skip-if(Android) fails-if(winWidget) == 632781-verybig.html 632781-ref.html # large canvas elements are not drawn on Windows, see bug 633936
|
||||
== 632781-normalsize.html 632781-ref.html
|
||||
== 633344-1.html 633344-1-ref.html
|
||||
fails-if(Android) == 634232-1.html 634232-1-ref.html
|
||||
fails-if(Android) == 635302-1.html 635302-1-ref.html
|
||||
== 635373-1.html 635373-1-ref.html
|
||||
|
@ -1629,6 +1630,10 @@ fails-if(Android) == 635302-1.html 635302-1-ref.html
|
|||
fails-if(http.platform=="X11"&&!layersGPUAccelerated) == 635373-3.html 635373-3-ref.html
|
||||
HTTP(..) == 635639-1.html 635639-1-ref.html
|
||||
HTTP(..) == 635639-2.html 635639-2-ref.html
|
||||
== 637597-1.html 637597-1-ref.html
|
||||
== 637852-1.html 637852-1-ref.html
|
||||
== 637852-2.html 637852-2-ref.html
|
||||
== 637852-3.html 637852-3-ref.html
|
||||
== 641770-1.html 641770-1-ref.html
|
||||
== 641856-1.html 641856-1-ref.html
|
||||
== 645491-1.html 645491-1-ref.html
|
||||
|
|
|
@ -20,10 +20,10 @@ fails-if(Android) == element-paint-native-widget.html element-paint-native-widge
|
|||
== element-paint-subimage-sampling-restriction.html about:blank
|
||||
== element-paint-clippath.html element-paint-clippath-ref.html
|
||||
== element-paint-sharpness-01a.html element-paint-sharpness-01b.html
|
||||
fails-if(Android) == element-paint-sharpness-01b.html element-paint-sharpness-01c.html
|
||||
== element-paint-sharpness-01b.html element-paint-sharpness-01c.html
|
||||
== element-paint-sharpness-01c.html element-paint-sharpness-01d.html
|
||||
== element-paint-sharpness-02a.html element-paint-sharpness-02b.html
|
||||
fails-if(Android) == element-paint-sharpness-02b.html element-paint-sharpness-02c.html
|
||||
== element-paint-sharpness-02b.html element-paint-sharpness-02c.html
|
||||
== element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01-ref.html
|
||||
== element-paint-paintserversize-rounding-02.html element-paint-paintserversize-rounding-02-ref.html
|
||||
== element-paint-multiple-backgrounds-01a.html element-paint-multiple-backgrounds-01-ref.html
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fails-if(Android) == background-image-zoom-1.html background-image-zoom-1-ref.html
|
||||
== background-image-zoom-1.html background-image-zoom-1-ref.html
|
||||
== background-image-zoom-2.html about:blank
|
||||
fails-if(Android) == image-zoom-1.html image-zoom-1-ref.html
|
||||
== image-zoom-1.html image-zoom-1-ref.html
|
||||
== invalid-url-image-1.html invalid-url-image-1-ref.html
|
||||
|
|
|
@ -7,5 +7,7 @@ HTTP == opacity-mixed-scrolling-1.html opacity-mixed-scrolling-1.html?ref
|
|||
random-if(cocoaWidget) HTTP == opacity-mixed-scrolling-2.html opacity-mixed-scrolling-2.html?ref # see bug 625357
|
||||
HTTP == simple-1.html simple-1.html?ref
|
||||
HTTP == text-1.html text-1.html?ref
|
||||
HTTP == transformed-1.html transformed-1.html?ref
|
||||
HTTP == transformed-1.html?up transformed-1.html?ref
|
||||
== uncovering-1.html uncovering-1-ref.html
|
||||
== uncovering-2.html uncovering-2-ref.html
|
||||
|
|
|
@ -24,6 +24,13 @@ function doScroll(d)
|
|||
|
||||
if (document.location.search == '?ref') {
|
||||
doScroll(20);
|
||||
} else if (document.location.search == '?up') {
|
||||
doScroll(40);
|
||||
document.documentElement.setAttribute("class", "reftest-wait");
|
||||
window.addEventListener("MozReftestInvalidate", function() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
doScroll(20);
|
||||
}, false);
|
||||
} else {
|
||||
doScroll(1);
|
||||
document.documentElement.setAttribute("class", "reftest-wait");
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div class="scrollTop" style="height:100px; width:100px; overflow:hidden;
|
||||
-moz-transform:scale(2.7); transform:scale(2.7); -moz-transform-origin:top left; transform-origin:top left;">
|
||||
<div style="background:yellow;">
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>document.body.getBoundingClientRect();</script>
|
||||
<script src="scrolling.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -15,7 +15,7 @@ fails == xbl-grad-ref--grad-in-resources-02.svg pass.svg
|
|||
== xbl-grad-ref--grad-in-bound-04.svg pass.svg
|
||||
|
||||
# Tests for zooming with the full page zoom UI
|
||||
fails-if(Android) == feImage-zoom-01a.svg feImage-zoom-01-ref.svg
|
||||
fails-if(Android) == feImage-zoom-01b.svg feImage-zoom-01-ref.svg
|
||||
== feImage-zoom-01a.svg feImage-zoom-01-ref.svg
|
||||
== feImage-zoom-01b.svg feImage-zoom-01-ref.svg
|
||||
== foreignObject-zoom-01.svg pass.svg
|
||||
skip == zoomed-svg-with-viewBox-01.svg zoomed-svg-with-viewBox-01-ref.svg
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
== mask-html-01.xhtml mask-html-01-ref.svg
|
||||
== mask-html-01-extref-01.xhtml mask-html-01-ref.svg
|
||||
== mask-html-01-extref-02.xhtml mask-html-01-ref.svg
|
||||
fails-if(Android) == mask-html-zoomed-01.xhtml mask-html-01-ref.svg
|
||||
== mask-html-zoomed-01.xhtml mask-html-01-ref.svg
|
||||
== mask-html-xbl-bound-01.html mask-html-01-ref.svg
|
||||
|
|
Загрузка…
Ссылка в новой задаче