Merge the last green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ehsan Akhgari 2011-06-22 15:50:44 -04:00
Родитель 0d9e4bf17a a512d28a8c
Коммит 39836938cc
62 изменённых файлов: 1052 добавлений и 831 удалений

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

@ -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