From d7cbdea701768d6b89e0d6e26ef95aa2bc6a4ff1 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Thu, 27 Sep 2012 23:00:51 +0200 Subject: [PATCH] Bug 778367 - Part 1: Minimize intermediate surface size. r=jrmuizel --- gfx/thebes/gfxContext.cpp | 163 +++++++++++++++++++++++++------------- gfx/thebes/gfxContext.h | 5 ++ 2 files changed, 111 insertions(+), 57 deletions(-) diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index aac34788317c..cfaa9bc48f66 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -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(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(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(&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 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; } } @@ -1549,7 +1543,7 @@ gfxContext::PushGroupAndCopyBackground(gfxASurface::gfxContentType content) PushGroup(content); Rect surfRect(0, 0, Float(mDT->GetSize().width), Float(mDT->GetSize().height)); Matrix oldTransform = mDT->GetTransform(); - mDT->SetTransform(Matrix()); + mDT->SetTransform(GetDeviceTransform()); mDT->DrawSurface(source, surfRect, surfRect); mDT->SetTransform(oldTransform); mDT->SetOpaqueRect(oldDT->GetOpaqueRect()); @@ -1570,12 +1564,17 @@ gfxContext::PopGroup() return wrapper; } else { RefPtr src = mDT->Snapshot(); + Point deviceOffset = CurrentState().deviceOffset; Restore(); - Matrix mat = mDT->GetTransform(); + Matrix mat = mTransform; mat.Invert(); - nsRefPtr pat = new gfxPattern(src, mat); + + Matrix deviceOffsetTranslation; + deviceOffsetTranslation.Translate(deviceOffset.x, deviceOffset.y); + + nsRefPtr pat = new gfxPattern(src, deviceOffsetTranslation * mat); return pat.forget(); } @@ -1588,15 +1587,19 @@ gfxContext::PopGroupToSource() cairo_pop_group_to_source(mCairo); } else { RefPtr 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 +1925,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 +1973,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 +2031,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 +2083,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 +2092,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 +2114,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; +} \ No newline at end of file diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index f8e380df9a1d..d2bc8b39307c 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -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;