Bug 1220629 - Part 2: Prepare DrawTargetD2D1 for the possibilities of layers existing inside it. r=jrmuizel

This commit is contained in:
Bas Schouten 2016-01-05 09:03:08 +01:00
parent c2450768f8
commit 413175f223
2 changed files with 61 additions and 34 deletions

View File

@ -31,7 +31,7 @@ ID2D1Factory1 *D2DFactory1()
} }
DrawTargetD2D1::DrawTargetD2D1() DrawTargetD2D1::DrawTargetD2D1()
: mClipsArePushed(false) : mPushedLayers(1)
{ {
} }
@ -267,7 +267,7 @@ DrawTargetD2D1::ClearRect(const Rect &aRect)
mDC->FillGeometry(geom, brush); mDC->FillGeometry(geom, brush);
mDC->PopAxisAlignedClip(); mDC->PopAxisAlignedClip();
mDC->SetTarget(mBitmap); mDC->SetTarget(CurrentTarget());
list->Close(); list->Close();
mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT); mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT);
@ -515,7 +515,7 @@ DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
PrepareForDrawing(aOptions.mCompositionOp, aPattern); PrepareForDrawing(aOptions.mCompositionOp, aPattern);
bool forceClearType = false; bool forceClearType = false;
if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA && if (!CurrentLayer().mIsOpaque && mPermitSubpixelAA &&
aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) { aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) {
forceClearType = true; forceClearType = true;
} }
@ -538,7 +538,7 @@ DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
} }
if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE &&
mFormat != SurfaceFormat::B8G8R8X8 && !forceClearType) { !CurrentLayer().mIsOpaque && !forceClearType) {
d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
} }
@ -555,10 +555,10 @@ DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun); DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
bool needsRepushedLayers = false; bool needsRepushedLayers = false;
if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && mFormat != SurfaceFormat::B8G8R8X8) { if (forceClearType) {
D2D1_RECT_F rect; D2D1_RECT_F rect;
bool isAligned; bool isAligned;
needsRepushedLayers = mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned); needsRepushedLayers = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
// If we have a complex clip in our stack and we have a transparent // If we have a complex clip in our stack and we have a transparent
// background, and subpixel AA is permitted, we need to repush our layer // background, and subpixel AA is permitted, we need to repush our layer
@ -664,14 +664,14 @@ DrawTargetD2D1::PushClip(const Path *aPath)
pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds); pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds);
mPushedClips.push_back(clip); CurrentLayer().mPushedClips.push_back(clip);
// The transform of clips is relative to the world matrix, since we use the total // The transform of clips is relative to the world matrix, since we use the total
// transform for the clips, make the world matrix identity. // transform for the clips, make the world matrix identity.
mDC->SetTransform(D2D1::IdentityMatrix()); mDC->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true; mTransformDirty = true;
if (mClipsArePushed) { if (CurrentLayer().mClipsArePushed) {
PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform); PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform);
} }
} }
@ -704,12 +704,12 @@ DrawTargetD2D1::PushClipRect(const Rect &aRect)
// Do not store the transform, just store the device space rectangle directly. // Do not store the transform, just store the device space rectangle directly.
clip.mBounds = D2DRect(rect); clip.mBounds = D2DRect(rect);
mPushedClips.push_back(clip); CurrentLayer().mPushedClips.push_back(clip);
mDC->SetTransform(D2D1::IdentityMatrix()); mDC->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true; mTransformDirty = true;
if (mClipsArePushed) { if (CurrentLayer().mClipsArePushed) {
mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
} }
} }
@ -719,14 +719,14 @@ DrawTargetD2D1::PopClip()
{ {
mCurrentClippedGeometry = nullptr; mCurrentClippedGeometry = nullptr;
if (mClipsArePushed) { if (CurrentLayer().mClipsArePushed) {
if (mPushedClips.back().mPath) { if (CurrentLayer().mPushedClips.back().mPath) {
mDC->PopLayer(); mDC->PopLayer();
} else { } else {
mDC->PopAxisAlignedClip(); mDC->PopAxisAlignedClip();
} }
} }
mPushedClips.pop_back(); CurrentLayer().mPushedClips.pop_back();
} }
already_AddRefed<SourceSurface> already_AddRefed<SourceSurface>
@ -878,10 +878,12 @@ DrawTargetD2D1::Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat)
return false; return false;
} }
mDC->SetTarget(mBitmap); mDC->SetTarget(CurrentTarget());
mDC->BeginDraw(); mDC->BeginDraw();
CurrentLayer().mIsOpaque = aFormat == SurfaceFormat::B8G8R8X8;
return true; return true;
} }
@ -922,7 +924,7 @@ DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
return false; return false;
} }
mDC->SetTarget(mBitmap); mDC->SetTarget(CurrentTarget());
hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush)); hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush));
@ -933,6 +935,8 @@ DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
mDC->BeginDraw(); mDC->BeginDraw();
CurrentLayer().mIsOpaque = aFormat == SurfaceFormat::B8G8R8X8;
mDC->Clear(); mDC->Clear();
mFormat = aFormat; mFormat = aFormat;
@ -1048,7 +1052,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
PopAllClips(); PopAllClips();
mDC->SetTarget(mBitmap); mDC->SetTarget(CurrentTarget());
mCommandList->Close(); mCommandList->Close();
RefPtr<ID2D1CommandList> source = mCommandList; RefPtr<ID2D1CommandList> source = mCommandList;
@ -1062,7 +1066,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
D2D1_RECT_F rect; D2D1_RECT_F rect;
bool isAligned; bool isAligned;
RefPtr<ID2D1Bitmap> tmpBitmap; RefPtr<ID2D1Bitmap> tmpBitmap;
bool clipIsComplex = mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned); bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
if (clipIsComplex) { if (clipIsComplex) {
if (!IsOperatorBoundByMask(aOp)) { if (!IsOperatorBoundByMask(aOp)) {
@ -1184,12 +1188,12 @@ IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
bool bool
DrawTargetD2D1::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned) DrawTargetD2D1::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned)
{ {
if (!mPushedClips.size()) { if (!CurrentLayer().mPushedClips.size()) {
return false; return false;
} }
aClipRect = D2D1::RectF(0, 0, mSize.width, mSize.height); aClipRect = D2D1::RectF(0, 0, mSize.width, mSize.height);
for (auto iter = mPushedClips.begin();iter != mPushedClips.end(); iter++) { for (auto iter = CurrentLayer().mPushedClips.begin();iter != CurrentLayer().mPushedClips.end(); iter++) {
if (iter->mPath) { if (iter->mPath) {
return false; return false;
} }
@ -1210,7 +1214,7 @@ DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
return clippedGeometry.forget(); return clippedGeometry.forget();
} }
MOZ_ASSERT(mPushedClips.size()); MOZ_ASSERT(CurrentLayer().mPushedClips.size());
mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize); mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize);
@ -1218,7 +1222,7 @@ DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
RefPtr<ID2D1Geometry> pathGeom; RefPtr<ID2D1Geometry> pathGeom;
D2D1_RECT_F pathRect; D2D1_RECT_F pathRect;
bool pathRectIsAxisAligned = false; bool pathRectIsAxisAligned = false;
auto iter = mPushedClips.begin(); auto iter = CurrentLayer().mPushedClips.begin();
if (iter->mPath) { if (iter->mPath) {
pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform); pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
@ -1228,7 +1232,7 @@ DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
} }
iter++; iter++;
for (;iter != mPushedClips.end(); iter++) { for (;iter != CurrentLayer().mPushedClips.end(); iter++) {
// Do nothing but add it to the current clip bounds. // Do nothing but add it to the current clip bounds.
if (!iter->mPath && iter->mIsPixelAligned) { if (!iter->mPath && iter->mIsPixelAligned) {
mCurrentClipBounds.IntersectRect(mCurrentClipBounds, mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
@ -1313,20 +1317,20 @@ DrawTargetD2D1::GetInverseClippedGeometry()
void void
DrawTargetD2D1::PopAllClips() DrawTargetD2D1::PopAllClips()
{ {
if (mClipsArePushed) { if (CurrentLayer().mClipsArePushed) {
PopClipsFromDC(mDC); PopClipsFromDC(mDC);
mClipsArePushed = false; CurrentLayer().mClipsArePushed = false;
} }
} }
void void
DrawTargetD2D1::PushAllClips() DrawTargetD2D1::PushAllClips()
{ {
if (!mClipsArePushed) { if (!CurrentLayer().mClipsArePushed) {
PushClipsToDC(mDC); PushClipsToDC(mDC);
mClipsArePushed = true; CurrentLayer().mClipsArePushed = true;
} }
} }
@ -1336,8 +1340,7 @@ DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC, bool aForceIgnoreAlpha, c
mDC->SetTransform(D2D1::IdentityMatrix()); mDC->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true; mTransformDirty = true;
for (std::vector<PushedClip>::iterator iter = mPushedClips.begin(); for (auto iter = CurrentLayer().mPushedClips.begin(); iter != CurrentLayer().mPushedClips.end(); iter++) {
iter != mPushedClips.end(); iter++) {
if (iter->mPath) { if (iter->mPath) {
PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform, aForceIgnoreAlpha, aMaxRect); PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform, aForceIgnoreAlpha, aMaxRect);
} else { } else {
@ -1349,8 +1352,8 @@ DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC, bool aForceIgnoreAlpha, c
void void
DrawTargetD2D1::PopClipsFromDC(ID2D1DeviceContext *aDC) DrawTargetD2D1::PopClipsFromDC(ID2D1DeviceContext *aDC)
{ {
for (int i = mPushedClips.size() - 1; i >= 0; i--) { for (int i = CurrentLayer().mPushedClips.size() - 1; i >= 0; i--) {
if (mPushedClips[i].mPath) { if (CurrentLayer().mPushedClips[i].mPath) {
aDC->PopLayer(); aDC->PopLayer();
} else { } else {
aDC->PopAxisAlignedClip(); aDC->PopAxisAlignedClip();

View File

@ -167,14 +167,24 @@ private:
} }
void AddDependencyOnSource(SourceSurfaceD2D1* aSource); void AddDependencyOnSource(SourceSurfaceD2D1* aSource);
ID2D1Image* CurrentTarget()
{
if (CurrentLayer().mCurrentList) {
return CurrentLayer().mCurrentList;
}
return mBitmap;
}
// This returns the clipped geometry, in addition it returns aClipBounds which // This returns the clipped geometry, in addition it returns aClipBounds which
// represents the intersection of all pixel-aligned rectangular clips that // represents the intersection of all pixel-aligned rectangular clips that
// are currently set. The returned clipped geometry must be clipped by these // are currently set. The returned clipped geometry must be clipped by these
// bounds to correctly reflect the total clip. This is in device space. // bounds to correctly reflect the total clip. This is in device space and
// only for clips applied to the -current layer-.
already_AddRefed<ID2D1Geometry> GetClippedGeometry(IntRect *aClipBounds); already_AddRefed<ID2D1Geometry> GetClippedGeometry(IntRect *aClipBounds);
already_AddRefed<ID2D1Geometry> GetInverseClippedGeometry(); already_AddRefed<ID2D1Geometry> GetInverseClippedGeometry();
// This gives the device space clip rect applied to the -current layer-.
bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned); bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned);
void PopAllClips(); void PopAllClips();
@ -220,7 +230,23 @@ private:
}; };
RefPtr<PathD2D> mPath; RefPtr<PathD2D> mPath;
}; };
std::vector<PushedClip> mPushedClips;
// List of pushed layers.
struct PushedLayer
{
PushedLayer() : mClipsArePushed(false), mIsOpaque(false) {}
std::vector<PushedClip> mPushedClips;
RefPtr<ID2D1CommandList> mCurrentList;
// True if the current clip stack is pushed to the CurrentTarget().
bool mClipsArePushed;
bool mIsOpaque;
};
std::vector<PushedLayer> mPushedLayers;
PushedLayer& CurrentLayer()
{
return mPushedLayers.back();
}
// The latest snapshot of this surface. This needs to be told when this // The latest snapshot of this surface. This needs to be told when this
// target is modified. We keep it alive as a cache. // target is modified. We keep it alive as a cache.
@ -230,8 +256,6 @@ private:
// A list of targets which have this object in their mDependentTargets set // A list of targets which have this object in their mDependentTargets set
TargetSet mDependingOnTargets; TargetSet mDependingOnTargets;
// True of the current clip stack is pushed to the main RT.
bool mClipsArePushed;
static ID2D1Factory1 *mFactory; static ID2D1Factory1 *mFactory;
static IDWriteFactory *mDWriteFactory; static IDWriteFactory *mDWriteFactory;
}; };