зеркало из https://github.com/mozilla/gecko-dev.git
Bug 590294, part 8: Implement resolution-scaled drawing for basic layers. r=roc
This commit is contained in:
Родитель
f502883ffc
Коммит
a2c93af9b1
|
@ -44,6 +44,19 @@
|
|||
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.size.width, rect.size.height);
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
ThebesLayerBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide)
|
||||
{
|
||||
|
@ -67,7 +80,9 @@ ThebesLayerBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide)
|
|||
*/
|
||||
void
|
||||
ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
||||
XSide aXSide, YSide aYSide, float aOpacity)
|
||||
XSide aXSide, YSide aYSide,
|
||||
float aOpacity,
|
||||
float aXRes, float aYRes)
|
||||
{
|
||||
// The rectangle that we're going to fill. Basically we're going to
|
||||
// render the buffer at mBufferRect + quadrantTranslation to get the
|
||||
|
@ -79,9 +94,21 @@ ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
|||
return;
|
||||
|
||||
aTarget->NewPath();
|
||||
aTarget->Rectangle(gfxRect(fillRect.x, fillRect.y, fillRect.width, fillRect.height),
|
||||
aTarget->Rectangle(gfxRect(fillRect.x, fillRect.y,
|
||||
fillRect.width, fillRect.height),
|
||||
PR_TRUE);
|
||||
aTarget->SetSource(mBuffer, gfxPoint(quadrantRect.x, quadrantRect.y));
|
||||
|
||||
gfxPoint quadrantTranslation(quadrantRect.x, quadrantRect.y);
|
||||
nsRefPtr<gfxPattern> pattern = new gfxPattern(mBuffer);
|
||||
|
||||
// Transform from user -> buffer space.
|
||||
gfxMatrix transform;
|
||||
transform.Scale(aXRes, aYRes);
|
||||
transform.Translate(-quadrantTranslation);
|
||||
|
||||
pattern->SetMatrix(transform);
|
||||
aTarget->SetPattern(pattern);
|
||||
|
||||
if (aOpacity != 1.0) {
|
||||
aTarget->Save();
|
||||
aTarget->Clip();
|
||||
|
@ -93,14 +120,15 @@ ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
|
|||
}
|
||||
|
||||
void
|
||||
ThebesLayerBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity)
|
||||
ThebesLayerBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
|
||||
float aXRes, float aYRes)
|
||||
{
|
||||
// Draw four quadrants. We could use REPEAT_, but it's probably better
|
||||
// not to, to be performance-safe.
|
||||
DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity);
|
||||
DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity);
|
||||
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity);
|
||||
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity);
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -114,15 +142,27 @@ WrapRotationAxis(PRInt32* aRotationPoint, PRInt32 aSize)
|
|||
}
|
||||
|
||||
ThebesLayerBuffer::PaintState
|
||||
ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType)
|
||||
ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
float aXResolution, float aYResolution)
|
||||
{
|
||||
PaintState result;
|
||||
|
||||
result.mRegionToDraw.Sub(aLayer->GetVisibleRegion(), aLayer->GetValidRegion());
|
||||
|
||||
if (mBuffer && aContentType != mBuffer->GetContentType()) {
|
||||
float curXRes = aLayer->GetXResolution();
|
||||
float curYRes = aLayer->GetYResolution();
|
||||
if (mBuffer &&
|
||||
(aContentType != mBuffer->GetContentType() ||
|
||||
aXResolution != curXRes || aYResolution != curYRes)) {
|
||||
// We're effectively clearing the valid region, so we need to draw
|
||||
// the entire visible region now.
|
||||
//
|
||||
// XXX/cjones: a possibly worthwhile optimization to keep in mind
|
||||
// is to re-use buffers when the resolution and visible region
|
||||
// have changed in such a way that the buffer size stays the same.
|
||||
// It might make even more sense to allocate buffers from a
|
||||
// recyclable pool, so that we could keep this logic simple and
|
||||
// still get back the same buffer.
|
||||
result.mRegionToDraw = aLayer->GetVisibleRegion();
|
||||
result.mRegionToInvalidate = aLayer->GetValidRegion();
|
||||
Clear();
|
||||
|
@ -133,10 +173,15 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType)
|
|||
nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
|
||||
|
||||
nsIntRect visibleBounds = aLayer->GetVisibleRegion().GetBounds();
|
||||
nsIntSize scaledBufferSize = ScaledSize(visibleBounds.Size(),
|
||||
aXResolution, aYResolution);
|
||||
nsRefPtr<gfxASurface> destBuffer;
|
||||
nsIntRect destBufferRect;
|
||||
|
||||
if (BufferSizeOkFor(visibleBounds.Size())) {
|
||||
if (BufferSizeOkFor(scaledBufferSize)) {
|
||||
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
|
||||
"resolution changes must Clear()!");
|
||||
|
||||
// The current buffer is big enough to hold the visible area.
|
||||
if (mBufferRect.Contains(visibleBounds)) {
|
||||
// We don't need to adjust mBufferRect.
|
||||
|
@ -169,7 +214,9 @@ 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 = visibleBounds;
|
||||
destBuffer = CreateBuffer(aContentType, destBufferRect.Size());
|
||||
destBuffer = CreateBuffer(aContentType,
|
||||
ScaledSize(destBufferRect.Size(),
|
||||
aXResolution, aYResolution));
|
||||
if (!destBuffer)
|
||||
return result;
|
||||
}
|
||||
|
@ -187,7 +234,9 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType)
|
|||
} else {
|
||||
// The buffer's not big enough, so allocate a new one
|
||||
destBufferRect = visibleBounds;
|
||||
destBuffer = CreateBuffer(aContentType, destBufferRect.Size());
|
||||
destBuffer = CreateBuffer(aContentType,
|
||||
ScaledSize(destBufferRect.Size(),
|
||||
aXResolution, aYResolution));
|
||||
if (!destBuffer)
|
||||
return result;
|
||||
}
|
||||
|
@ -202,8 +251,11 @@ 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));
|
||||
DrawBufferWithRotation(tmpCtx, 1.0);
|
||||
NS_ASSERTION(curXRes == aXResolution && curYRes == aYResolution,
|
||||
"resolution changes must Clear()!");
|
||||
DrawBufferWithRotation(tmpCtx, 1.0, aXResolution, aYResolution);
|
||||
}
|
||||
|
||||
mBuffer = destBuffer.forget();
|
||||
|
@ -224,6 +276,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType)
|
|||
YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
|
||||
nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
|
||||
NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
|
||||
result.mContext->Scale(aXResolution, aYResolution);
|
||||
result.mContext->Translate(-gfxPoint(quadrantRect.x, quadrantRect.y));
|
||||
|
||||
gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw);
|
||||
|
|
|
@ -124,7 +124,8 @@ public:
|
|||
* Otherwise it must not be null.
|
||||
* mRegionToInvalidate will contain mRegionToDraw.
|
||||
*/
|
||||
PaintState BeginPaint(ThebesLayer* aLayer, ContentType aContentType);
|
||||
PaintState BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
|
||||
float aXResolution, float aYResolution);
|
||||
|
||||
/**
|
||||
* Return a new surface of |aSize| and |aType|.
|
||||
|
@ -147,8 +148,10 @@ protected:
|
|||
TOP, BOTTOM
|
||||
};
|
||||
nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide);
|
||||
void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide, float aOpacity);
|
||||
void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity);
|
||||
void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
|
||||
float aOpacity, float aXRes, float aYRes);
|
||||
void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
|
||||
float aXRes, float aYRes);
|
||||
|
||||
const nsIntRect& BufferRect() const { return mBufferRect; }
|
||||
const nsIntPoint& BufferRotation() const { return mBufferRotation; }
|
||||
|
|
|
@ -424,7 +424,10 @@ BasicThebesLayer::Paint(gfxContext* aContext,
|
|||
}
|
||||
|
||||
{
|
||||
Buffer::PaintState state = mBuffer.BeginPaint(this, contentType);
|
||||
float paintXRes = BasicManager()->XResolution();
|
||||
float paintYRes = BasicManager()->YResolution();
|
||||
Buffer::PaintState state =
|
||||
mBuffer.BeginPaint(this, contentType, paintXRes, paintYRes);
|
||||
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
|
||||
|
||||
if (state.mContext) {
|
||||
|
@ -437,6 +440,10 @@ BasicThebesLayer::Paint(gfxContext* aContext,
|
|||
PaintBuffer(state.mContext,
|
||||
state.mRegionToDraw, state.mRegionToInvalidate,
|
||||
aCallback, aCallbackData);
|
||||
|
||||
mXResolution = paintXRes;
|
||||
mYResolution = paintYRes;
|
||||
Mutated();
|
||||
} else {
|
||||
// It's possible that state.mRegionToInvalidate is nonempty here,
|
||||
// if we are shrinking the valid region to nothing.
|
||||
|
@ -459,7 +466,8 @@ BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
|
|||
if (aIsOpaqueContent) {
|
||||
aTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
}
|
||||
DrawBufferWithRotation(aTarget, aOpacity);
|
||||
DrawBufferWithRotation(aTarget, aOpacity,
|
||||
aLayer->GetXResolution(), aLayer->GetYResolution());
|
||||
aTarget->Restore();
|
||||
}
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ public:
|
|||
virtual PaintState BeginPaint(ContentType aContentType)
|
||||
{
|
||||
// Let ThebesLayerBuffer do all the hard work for us! :D
|
||||
return ThebesLayerBuffer::BeginPaint(mLayer, aContentType);
|
||||
return ThebesLayerBuffer::BeginPaint(mLayer, aContentType, 1.0, 1.0);
|
||||
}
|
||||
|
||||
// ThebesLayerBuffer interface
|
||||
|
|
|
@ -189,12 +189,12 @@ nsMargin nsRect::operator-(const nsRect& aRect) const
|
|||
}
|
||||
|
||||
// scale the rect but round to smallest containing rect
|
||||
nsRect& nsRect::ScaleRoundOut(float aScale)
|
||||
nsRect& nsRect::ScaleRoundOut(float aXScale, float aYScale)
|
||||
{
|
||||
nscoord right = NSToCoordCeil(float(XMost()) * aScale);
|
||||
nscoord bottom = NSToCoordCeil(float(YMost()) * aScale);
|
||||
x = NSToCoordFloor(float(x) * aScale);
|
||||
y = NSToCoordFloor(float(y) * aScale);
|
||||
nscoord right = NSToCoordCeil(float(XMost()) * aXScale);
|
||||
nscoord bottom = NSToCoordCeil(float(YMost()) * aYScale);
|
||||
x = NSToCoordFloor(float(x) * aXScale);
|
||||
y = NSToCoordFloor(float(y) * aYScale);
|
||||
width = (right - x);
|
||||
height = (bottom - y);
|
||||
return *this;
|
||||
|
|
|
@ -180,7 +180,8 @@ struct NS_GFX nsRect {
|
|||
|
||||
// Scale by aScale, converting coordinates to integers so that the result is
|
||||
// the smallest integer-coordinate rectangle containing the unrounded result.
|
||||
nsRect& ScaleRoundOut(float aScale);
|
||||
nsRect& ScaleRoundOut(float aScale) { return ScaleRoundOut(aScale, aScale); }
|
||||
nsRect& ScaleRoundOut(float aXScale, float aYScale);
|
||||
|
||||
// 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
|
||||
|
|
|
@ -434,6 +434,16 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
root->SetFrameMetrics(metrics);
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
layerManager->SetRoot(root);
|
||||
aBuilder->LayerBuilder()->WillEndTransaction(layerManager);
|
||||
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
|
||||
|
|
Загрузка…
Ссылка в новой задаче