Bug 778367: Minimize intermediate surface size. r=jrmuizel

This commit is contained in:
Bas Schouten 2012-09-27 23:00:51 +02:00
Родитель b33e2f4875
Коммит 7d8475a743
2 изменённых файлов: 118 добавлений и 57 удалений

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

@ -44,10 +44,10 @@ public:
Matrix transform = state.surfTransform;
if (state.patternTransformChanged) {
Matrix mat = mContext->mDT->GetTransform();
Matrix mat = mContext->mTransform;
mat.Invert();
transform = mat * state.patternTransform * transform;
transform = transform * state.patternTransform * mat;
}
mPattern = new (mSurfacePattern.addr())
@ -183,7 +183,7 @@ gfxContext::Save()
if (mCairo) {
cairo_save(mCairo);
} else {
CurrentState().transform = mDT->GetTransform();
CurrentState().transform = mTransform;
mStateStack.AppendElement(AzureState(CurrentState()));
CurrentState().clipWasReset = false;
CurrentState().pushedClips.Clear();
@ -212,11 +212,13 @@ gfxContext::Restore()
// the restore. We don't currently have users that do this and we should
// make sure there will not be any. Sadly we can't assert this easily.
mTransformChanged = true;
mPathTransform = mDT->GetTransform();
mPathTransform = mTransform;
}
mDT = CurrentState().drawTarget;
mDT->SetTransform(CurrentState().transform);
mTransform = CurrentState().transform;
mDT->SetTransform(GetDTTransform());
}
}
@ -460,7 +462,7 @@ gfxContext::Rectangle(const gfxRect& rect, bool snapToPixels)
if (snapToPixels) {
gfxRect newRect(rect);
if (UserToDevicePixelSnapped(newRect, true)) {
gfxMatrix mat = ThebesMatrix(mDT->GetTransform());
gfxMatrix mat = ThebesMatrix(mTransform);
mat.Invert();
// We need the user space rect.
@ -552,7 +554,7 @@ gfxContext::Translate(const gfxPoint& pt)
if (mCairo) {
cairo_translate(mCairo, pt.x, pt.y);
} else {
Matrix newMatrix = mDT->GetTransform();
Matrix newMatrix = mTransform;
ChangeTransform(newMatrix.Translate(Float(pt.x), Float(pt.y)));
}
@ -564,7 +566,7 @@ gfxContext::Scale(gfxFloat x, gfxFloat y)
if (mCairo) {
cairo_scale(mCairo, x, y);
} else {
Matrix newMatrix = mDT->GetTransform();
Matrix newMatrix = mTransform;
ChangeTransform(newMatrix.Scale(Float(x), Float(y)));
}
@ -577,7 +579,7 @@ gfxContext::Rotate(gfxFloat angle)
cairo_rotate(mCairo, angle);
} else {
Matrix rotation = Matrix::Rotation(Float(angle));
ChangeTransform(rotation * mDT->GetTransform());
ChangeTransform(rotation * mTransform);
}
}
@ -588,7 +590,7 @@ gfxContext::Multiply(const gfxMatrix& matrix)
const cairo_matrix_t& mat = reinterpret_cast<const cairo_matrix_t&>(matrix);
cairo_transform(mCairo, &mat);
} else {
ChangeTransform(ToMatrix(matrix) * mDT->GetTransform());
ChangeTransform(ToMatrix(matrix) * mTransform);
}
}
@ -600,7 +602,7 @@ gfxContext::MultiplyAndNudgeToIntegers(const gfxMatrix& matrix)
cairo_transform(mCairo, &mat);
// XXX nudging to integers not currently supported for Thebes
} else {
Matrix transform = ToMatrix(matrix) * mDT->GetTransform();
Matrix transform = ToMatrix(matrix) * mTransform;
transform.NudgeToIntegers();
ChangeTransform(transform);
}
@ -613,6 +615,8 @@ gfxContext::SetMatrix(const gfxMatrix& matrix)
const cairo_matrix_t& mat = reinterpret_cast<const cairo_matrix_t&>(matrix);
cairo_set_matrix(mCairo, &mat);
} else {
Matrix mat;
mat.Translate(-CurrentState().deviceOffset.x, -CurrentState().deviceOffset.y);
ChangeTransform(ToMatrix(matrix));
}
}
@ -635,7 +639,7 @@ gfxContext::CurrentMatrix() const
cairo_get_matrix(mCairo, &mat);
return gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat));
} else {
return ThebesMatrix(mDT->GetTransform());
return ThebesMatrix(mTransform);
}
}
@ -650,7 +654,7 @@ gfxContext::NudgeCurrentMatrixToIntegers()
} else {
gfxMatrix matrix = ThebesMatrix(mTransform);
matrix.NudgeToIntegers();
mTransform = ToMatrix(matrix);
ChangeTransform(ToMatrix(matrix));
}
}
@ -662,7 +666,7 @@ gfxContext::DeviceToUser(const gfxPoint& point) const
cairo_device_to_user(mCairo, &ret.x, &ret.y);
return ret;
} else {
Matrix matrix = mDT->GetTransform();
Matrix matrix = mTransform;
matrix.Invert();
@ -678,7 +682,7 @@ gfxContext::DeviceToUser(const gfxSize& size) const
cairo_device_to_user_distance(mCairo, &ret.width, &ret.height);
return ret;
} else {
Matrix matrix = mDT->GetTransform();
Matrix matrix = mTransform;
matrix.Invert();
@ -695,7 +699,7 @@ gfxContext::DeviceToUser(const gfxRect& rect) const
cairo_device_to_user_distance(mCairo, &ret.width, &ret.height);
return ret;
} else {
Matrix matrix = mDT->GetTransform();
Matrix matrix = mTransform;
matrix.Invert();
@ -711,7 +715,7 @@ gfxContext::UserToDevice(const gfxPoint& point) const
cairo_user_to_device(mCairo, &ret.x, &ret.y);
return ret;
} else {
return ThebesPoint(mDT->GetTransform() * ToPoint(point));
return ThebesPoint(mTransform * ToPoint(point));
}
}
@ -723,7 +727,7 @@ gfxContext::UserToDevice(const gfxSize& size) const
cairo_user_to_device_distance(mCairo, &ret.width, &ret.height);
return ret;
} else {
const Matrix &matrix = mDT->GetTransform();
const Matrix &matrix = mTransform;
gfxSize newSize = size;
newSize.width = newSize.width * matrix._11 + newSize.height * matrix._12;
@ -756,7 +760,7 @@ gfxContext::UserToDevice(const gfxRect& rect) const
return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
} else {
const Matrix &matrix = mDT->GetTransform();
const Matrix &matrix = mTransform;
return ThebesRect(matrix.TransformBounds(ToRect(rect)));
}
}
@ -780,7 +784,7 @@ gfxContext::UserToDevicePixelSnapped(gfxRect& rect, bool ignoreScale) const
!WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0)))
return false;
} else {
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
if (!ignoreScale &&
(!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) ||
!WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0)))
@ -830,7 +834,7 @@ gfxContext::UserToDevicePixelSnapped(gfxPoint& pt, bool ignoreScale) const
!WITHIN_E(mat.xy,0.0) || !WITHIN_E(mat.yx,0.0)))
return false;
} else {
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
if (!ignoreScale &&
(!WITHIN_E(mat._11,1.0) || !WITHIN_E(mat._22,1.0) ||
!WITHIN_E(mat._12,0.0) || !WITHIN_E(mat._21,0.0)))
@ -1121,7 +1125,7 @@ gfxContext::Clip(const gfxRect& rect)
cairo_rectangle(mCairo, rect.X(), rect.Y(), rect.Width(), rect.Height());
cairo_clip(mCairo);
} else {
AzureState::PushedClip clip = { NULL, ToRect(rect), mDT->GetTransform() };
AzureState::PushedClip clip = { NULL, ToRect(rect), mTransform };
CurrentState().pushedClips.AppendElement(clip);
mDT->PushClipRect(ToRect(rect));
NewPath();
@ -1135,13 +1139,13 @@ gfxContext::Clip()
cairo_clip_preserve(mCairo);
} else {
if (mPathIsRect && !mTransformChanged) {
AzureState::PushedClip clip = { NULL, mRect, mDT->GetTransform() };
AzureState::PushedClip clip = { NULL, mRect, mTransform };
CurrentState().pushedClips.AppendElement(clip);
mDT->PushClipRect(mRect);
} else {
EnsurePath();
mDT->PushClip(mPath);
AzureState::PushedClip clip = { mPath, Rect(), mDT->GetTransform() };
AzureState::PushedClip clip = { mPath, Rect(), mTransform };
CurrentState().pushedClips.AppendElement(clip);
}
}
@ -1188,31 +1192,13 @@ gfxContext::GetClipExtents()
cairo_clip_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
} else {
unsigned int lastReset = 0;
for (int i = mStateStack.Length() - 1; i > 0; i--) {
if (mStateStack[i].clipWasReset) {
lastReset = i;
}
}
Rect rect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
for (unsigned int i = lastReset; i < mStateStack.Length(); i++) {
for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
if (clip.path) {
Rect bounds = clip.path->GetBounds(clip.transform);
rect.IntersectRect(rect, bounds);
} else {
rect.IntersectRect(rect, clip.transform.TransformBounds(clip.rect));
}
}
}
Rect rect = GetAzureDeviceSpaceClipBounds();
if (rect.width == 0 || rect.height == 0) {
return gfxRect(0, 0, 0, 0);
}
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
mat.Invert();
rect = mat.TransformBounds(rect);
@ -1469,15 +1455,23 @@ gfxContext::PushGroup(gfxASurface::gfxContentType content)
if (mCairo) {
cairo_push_group_with_content(mCairo, (cairo_content_t) content);
} else {
Rect clipBounds = GetAzureDeviceSpaceClipBounds();
clipBounds.RoundOut();
clipBounds.width = NS_MAX(1.0f, clipBounds.width);
clipBounds.height = NS_MAX(1.0f, clipBounds.height);
RefPtr<DrawTarget> newDT =
mDT->CreateSimilarDrawTarget(mDT->GetSize(), gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content));
mDT->CreateSimilarDrawTarget(IntSize(int32_t(clipBounds.width), int32_t(clipBounds.height)),
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content));
Save();
CurrentState().drawTarget = newDT;
CurrentState().deviceOffset = clipBounds.TopLeft();
PushClipsToDT(newDT);
newDT->SetTransform(mDT->GetTransform());
newDT->SetTransform(GetDTTransform());
mDT = newDT;
}
}
@ -1546,11 +1540,18 @@ gfxContext::PushGroupAndCopyBackground(gfxASurface::gfxContentType content)
mDT->GetOpaqueRect().Contains(clipExtents)) {
DrawTarget *oldDT = mDT;
RefPtr<SourceSurface> source = mDT->Snapshot();
Point oldDeviceOffset = CurrentState().deviceOffset;
PushGroup(content);
Point offset = CurrentState().deviceOffset - oldDeviceOffset;
PushGroup(gfxASurface::CONTENT_COLOR);
Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height));
Rect sourceRect = surfRect;
sourceRect.x += offset.x;
sourceRect.y += offset.y;
Matrix oldTransform = mDT->GetTransform();
mDT->SetTransform(Matrix());
mDT->DrawSurface(source, surfRect, surfRect);
mDT->DrawSurface(source, surfRect, sourceRect);
mDT->SetTransform(oldTransform);
mDT->SetOpaqueRect(oldDT->GetOpaqueRect());
return;
@ -1570,12 +1571,17 @@ gfxContext::PopGroup()
return wrapper;
} else {
RefPtr<SourceSurface> src = mDT->Snapshot();
Point deviceOffset = CurrentState().deviceOffset;
Restore();
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
mat.Invert();
nsRefPtr<gfxPattern> pat = new gfxPattern(src, mat);
Matrix deviceOffsetTranslation;
deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
nsRefPtr<gfxPattern> pat = new gfxPattern(src, deviceOffsetTranslation * mat);
return pat.forget();
}
@ -1588,15 +1594,19 @@ gfxContext::PopGroupToSource()
cairo_pop_group_to_source(mCairo);
} else {
RefPtr<SourceSurface> src = mDT->Snapshot();
Point deviceOffset = CurrentState().deviceOffset;
Restore();
CurrentState().sourceSurfCairo = NULL;
CurrentState().sourceSurface = src;
CurrentState().pattern = NULL;
CurrentState().patternTransformChanged = false;
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
mat.Invert();
CurrentState().surfTransform = mat;
Matrix deviceOffsetTranslation;
deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y);
CurrentState().surfTransform = deviceOffsetTranslation * mat;
}
}
@ -1922,7 +1932,7 @@ gfxContext::EnsurePath()
if (mPath) {
if (mTransformChanged) {
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
mat.Invert();
mat = mPathTransform * mat;
mPathBuilder = mPath->TransformedCopyToBuilder(mat, CurrentState().fillRule);
@ -1970,7 +1980,7 @@ gfxContext::EnsurePathBuilder()
mPathBuilder->Close();
} else if (mPathIsRect) {
mTransformChanged = false;
Matrix mat = mDT->GetTransform();
Matrix mat = mTransform;
mat.Invert();
mat = mPathTransform * mat;
mPathBuilder->MoveTo(mat * mRect.TopLeft());
@ -2028,7 +2038,7 @@ gfxContext::PushClipsToDT(DrawTarget *aDT)
// reset to the clip before ours.
for (unsigned int i = lastReset; i < mStateStack.Length() - 1; i++) {
for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
aDT->SetTransform(mStateStack[i].pushedClips[c].transform);
aDT->SetTransform(mStateStack[i].pushedClips[c].transform * GetDeviceTransform());
if (mStateStack[i].pushedClips[c].path) {
aDT->PushClip(mStateStack[i].pushedClips[c].path);
} else {
@ -2080,7 +2090,7 @@ gfxContext::ChangeTransform(const Matrix &aNewMatrix)
if ((state.pattern || state.sourceSurface)
&& !state.patternTransformChanged) {
state.patternTransform = mDT->GetTransform();
state.patternTransform = mTransform;
state.patternTransformChanged = true;
}
@ -2089,7 +2099,7 @@ gfxContext::ChangeTransform(const Matrix &aNewMatrix)
invMatrix.Invert();
Matrix toNewUS = mDT->GetTransform() * invMatrix;
Matrix toNewUS = mTransform * invMatrix;
if (toNewUS.IsRectilinear() && mPathIsRect) {
mRect = toNewUS.TransformBounds(mRect);
@ -2111,5 +2121,51 @@ gfxContext::ChangeTransform(const Matrix &aNewMatrix)
mTransformChanged = false;
}
mDT->SetTransform(aNewMatrix);
mTransform = aNewMatrix;
mDT->SetTransform(GetDTTransform());
}
Rect
gfxContext::GetAzureDeviceSpaceClipBounds()
{
unsigned int lastReset = 0;
for (int i = mStateStack.Length() - 1; i > 0; i--) {
if (mStateStack[i].clipWasReset) {
lastReset = i;
}
}
Rect rect(CurrentState().deviceOffset.x, CurrentState().deviceOffset.y,
Float(mDT->GetSize().width), Float(mDT->GetSize().height));
for (unsigned int i = lastReset; i < mStateStack.Length(); i++) {
for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) {
AzureState::PushedClip &clip = mStateStack[i].pushedClips[c];
if (clip.path) {
Rect bounds = clip.path->GetBounds(clip.transform);
rect.IntersectRect(rect, bounds);
} else {
rect.IntersectRect(rect, clip.transform.TransformBounds(clip.rect));
}
}
}
return rect;
}
Matrix
gfxContext::GetDeviceTransform() const
{
Matrix mat;
mat.Translate(-CurrentState().deviceOffset.x, -CurrentState().deviceOffset.y);
return mat;
}
Matrix
gfxContext::GetDTTransform() const
{
Matrix mat = mTransform;
mat._31 -= CurrentState().deviceOffset.x;
mat._32 -= CurrentState().deviceOffset.y;
return mat;
}

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

@ -738,6 +738,8 @@ private:
mozilla::gfx::AntialiasMode aaMode;
bool patternTransformChanged;
Matrix patternTransform;
// This is used solely for using minimal intermediate surface size.
mozilla::gfx::Point deviceOffset;
};
// This ensures mPath contains a valid path (in user space!)
@ -748,6 +750,9 @@ private:
void PushClipsToDT(mozilla::gfx::DrawTarget *aDT);
CompositionOp GetOp();
void ChangeTransform(const mozilla::gfx::Matrix &aNewMatrix);
Rect GetAzureDeviceSpaceClipBounds();
Matrix GetDeviceTransform() const;
Matrix GetDTTransform() const;
bool mPathIsRect;
bool mTransformChanged;