зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1151821: Make globalCompositeOperator work correctly when a complex clip is pushed. r=jrmuizel
This commit is contained in:
Родитель
a5e91c3f1c
Коммит
d1703bc5b7
|
@ -925,21 +925,22 @@ DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|||
{
|
||||
MarkChanged();
|
||||
|
||||
// It's important to do this before FlushTransformToDC! As this will cause
|
||||
// the transform to become dirty.
|
||||
if (!mClipsArePushed) {
|
||||
mClipsArePushed = true;
|
||||
PushClipsToDC(mDC);
|
||||
}
|
||||
|
||||
FlushTransformToDC();
|
||||
|
||||
if (aOp == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
|
||||
// It's important to do this before FlushTransformToDC! As this will cause
|
||||
// the transform to become dirty.
|
||||
PushAllClips();
|
||||
|
||||
FlushTransformToDC();
|
||||
return;
|
||||
}
|
||||
|
||||
PopAllClips();
|
||||
|
||||
mDC->SetTarget(mTempBitmap);
|
||||
mDC->Clear(D2D1::ColorF(0, 0));
|
||||
|
||||
PushAllClips();
|
||||
FlushTransformToDC();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -951,6 +952,8 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|||
return;
|
||||
}
|
||||
|
||||
PopAllClips();
|
||||
|
||||
RefPtr<ID2D1Image> image;
|
||||
mDC->GetTarget(byRef(image));
|
||||
|
||||
|
@ -961,7 +964,38 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|||
|
||||
if (patternSupported) {
|
||||
if (D2DSupportsCompositeMode(aOp)) {
|
||||
D2D1_RECT_F rect;
|
||||
bool isAligned;
|
||||
RefPtr<ID2D1Bitmap> tmpBitmap;
|
||||
bool clipIsComplex = mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
|
||||
|
||||
if (clipIsComplex) {
|
||||
if (!IsOperatorBoundByMask(aOp)) {
|
||||
HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(tmpBitmap));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 6CreateBitmap failure " << mSize << " Code: " << hexa(hr);
|
||||
// For now, crash in this scenario; this should happen because tmpBitmap is
|
||||
// null and CopyFromBitmap call below dereferences it.
|
||||
// return;
|
||||
}
|
||||
mDC->Flush();
|
||||
|
||||
tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
|
||||
}
|
||||
} else {
|
||||
PushAllClips();
|
||||
}
|
||||
mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
|
||||
|
||||
if (tmpBitmap) {
|
||||
RefPtr<ID2D1BitmapBrush> brush;
|
||||
RefPtr<ID2D1Geometry> inverseGeom = GetInverseClippedGeometry();
|
||||
mDC->CreateBitmapBrush(tmpBitmap, byRef(brush));
|
||||
|
||||
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
|
||||
mDC->FillGeometry(inverseGeom, brush);
|
||||
mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -985,7 +1019,6 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|||
|
||||
// This flush is important since the copy method will not know about the context drawing to the surface.
|
||||
// We also need to pop all the clips to make sure any drawn content will have made it to the final bitmap.
|
||||
PopAllClips();
|
||||
mDC->Flush();
|
||||
|
||||
// We need to use a copy here because affects don't accept a surface on
|
||||
|
@ -996,8 +1029,7 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|||
mBlendEffect->SetInput(1, mTempBitmap);
|
||||
mBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
|
||||
|
||||
PushClipsToDC(mDC);
|
||||
mClipsArePushed = true;
|
||||
PushAllClips();
|
||||
|
||||
mDC->DrawImage(mBlendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
|
||||
return;
|
||||
|
@ -1009,6 +1041,8 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
|||
return;
|
||||
}
|
||||
|
||||
PushAllClips();
|
||||
|
||||
RefPtr<ID2D1Effect> radialGradientEffect;
|
||||
|
||||
mDC->CreateEffect(CLSID_RadialGradientEffect, byRef(radialGradientEffect));
|
||||
|
@ -1078,6 +1112,8 @@ DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
|
|||
return mCurrentClippedGeometry;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPushedClips.size());
|
||||
|
||||
mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize);
|
||||
|
||||
// if pathGeom is null then pathRect represents the path.
|
||||
|
@ -1157,6 +1193,24 @@ DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
|
|||
return mCurrentClippedGeometry;
|
||||
}
|
||||
|
||||
TemporaryRef<ID2D1Geometry>
|
||||
DrawTargetD2D1::GetInverseClippedGeometry()
|
||||
{
|
||||
IntRect bounds;
|
||||
RefPtr<ID2D1Geometry> geom = GetClippedGeometry(&bounds);
|
||||
RefPtr<ID2D1RectangleGeometry> rectGeom;
|
||||
RefPtr<ID2D1PathGeometry> inverseGeom;
|
||||
|
||||
factory()->CreateRectangleGeometry(D2D1::RectF(0, 0, mSize.width, mSize.height), byRef(rectGeom));
|
||||
factory()->CreatePathGeometry(byRef(inverseGeom));
|
||||
RefPtr<ID2D1GeometrySink> sink;
|
||||
inverseGeom->Open(byRef(sink));
|
||||
rectGeom->CombineWithGeometry(geom, D2D1_COMBINE_MODE_EXCLUDE, D2D1::IdentityMatrix(), sink);
|
||||
sink->Close();
|
||||
|
||||
return inverseGeom;
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::PopAllClips()
|
||||
{
|
||||
|
@ -1167,6 +1221,16 @@ DrawTargetD2D1::PopAllClips()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::PushAllClips()
|
||||
{
|
||||
if (!mClipsArePushed) {
|
||||
PushClipsToDC(mDC);
|
||||
|
||||
mClipsArePushed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC)
|
||||
{
|
||||
|
|
|
@ -173,9 +173,12 @@ private:
|
|||
// bounds to correctly reflect the total clip. This is in device space.
|
||||
TemporaryRef<ID2D1Geometry> GetClippedGeometry(IntRect *aClipBounds);
|
||||
|
||||
TemporaryRef<ID2D1Geometry> GetInverseClippedGeometry();
|
||||
|
||||
bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned);
|
||||
|
||||
void PopAllClips();
|
||||
void PushAllClips();
|
||||
void PushClipsToDC(ID2D1DeviceContext *aDC);
|
||||
void PopClipsFromDC(ID2D1DeviceContext *aDC);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче