mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 945655 - Make all filters deal with null inputs and empty output rects consistently: treat them as transparent. r=roc
This commit is contained in:
parent
a7bf924cb8
commit
80876b8581
@ -568,9 +568,13 @@ FilterNodeSoftware::Draw(DrawTarget* aDrawTarget,
|
|||||||
int32_t(renderRect.width), int32_t(renderRect.height));
|
int32_t(renderRect.width), int32_t(renderRect.height));
|
||||||
IntRect outputRect = renderIntRect.Intersect(GetOutputRectInRect(renderIntRect));
|
IntRect outputRect = renderIntRect.Intersect(GetOutputRectInRect(renderIntRect));
|
||||||
|
|
||||||
// Render.
|
RefPtr<DataSourceSurface> result;
|
||||||
RefPtr<DataSourceSurface> result = GetOutput(outputRect);
|
if (!outputRect.IsEmpty()) {
|
||||||
|
result = GetOutput(outputRect);
|
||||||
|
}
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
// Null results are allowed and treated as transparent. Don't draw anything.
|
||||||
#ifdef DEBUG_DUMP_SURFACES
|
#ifdef DEBUG_DUMP_SURFACES
|
||||||
printf("output returned null\n");
|
printf("output returned null\n");
|
||||||
printf("</pre>\n");
|
printf("</pre>\n");
|
||||||
@ -603,10 +607,6 @@ FilterNodeSoftware::Draw(DrawTarget* aDrawTarget,
|
|||||||
TemporaryRef<DataSourceSurface>
|
TemporaryRef<DataSourceSurface>
|
||||||
FilterNodeSoftware::GetOutput(const IntRect &aRect)
|
FilterNodeSoftware::GetOutput(const IntRect &aRect)
|
||||||
{
|
{
|
||||||
if (aRect.IsEmpty()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(GetOutputRectInRect(aRect).Contains(aRect));
|
MOZ_ASSERT(GetOutputRectInRect(aRect).Contains(aRect));
|
||||||
if (!mCachedRect.Contains(aRect)) {
|
if (!mCachedRect.Contains(aRect)) {
|
||||||
RequestRect(aRect);
|
RequestRect(aRect);
|
||||||
@ -673,6 +673,10 @@ FilterNodeSoftware::GetInputDataSourceSurface(uint32_t aInputEnumIndex,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aRect.IsEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<SourceSurface> surface;
|
RefPtr<SourceSurface> surface;
|
||||||
IntRect surfaceRect;
|
IntRect surfaceRect;
|
||||||
if (mInputSurfaces[inputIndex]) {
|
if (mInputSurfaces[inputIndex]) {
|
||||||
@ -887,11 +891,23 @@ FilterNodeBlendSoftware::Render(const IntRect& aRect)
|
|||||||
GetInputDataSourceSurface(IN_BLEND_IN, aRect, NEED_COLOR_CHANNELS);
|
GetInputDataSourceSurface(IN_BLEND_IN, aRect, NEED_COLOR_CHANNELS);
|
||||||
RefPtr<DataSourceSurface> input2 =
|
RefPtr<DataSourceSurface> input2 =
|
||||||
GetInputDataSourceSurface(IN_BLEND_IN2, aRect, NEED_COLOR_CHANNELS);
|
GetInputDataSourceSurface(IN_BLEND_IN2, aRect, NEED_COLOR_CHANNELS);
|
||||||
if (!input1 || !input2) {
|
|
||||||
|
// Null inputs need to be treated as transparent.
|
||||||
|
|
||||||
|
// First case: both are transparent.
|
||||||
|
if (!input1 && !input2) {
|
||||||
|
// Then the result is transparent, too.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FilterProcessing::ApplyBlending(input1, input2, mBlendMode);
|
// Second case: both are non-transparent.
|
||||||
|
if (input1 && input2) {
|
||||||
|
// Apply normal filtering.
|
||||||
|
return FilterProcessing::ApplyBlending(input1, input2, mBlendMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third case: one of them is transparent. Return the non-transparent one.
|
||||||
|
return input1 ? input1 : input2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -940,6 +956,10 @@ FilterNodeTransformSoftware::SetAttribute(uint32_t aIndex, const Matrix &aMatrix
|
|||||||
IntRect
|
IntRect
|
||||||
FilterNodeTransformSoftware::SourceRectForOutputRect(const IntRect &aRect)
|
FilterNodeTransformSoftware::SourceRectForOutputRect(const IntRect &aRect)
|
||||||
{
|
{
|
||||||
|
if (aRect.IsEmpty()) {
|
||||||
|
return IntRect();
|
||||||
|
}
|
||||||
|
|
||||||
Matrix inverted(mMatrix);
|
Matrix inverted(mMatrix);
|
||||||
if (!inverted.Invert()) {
|
if (!inverted.Invert()) {
|
||||||
return IntRect();
|
return IntRect();
|
||||||
@ -993,6 +1013,10 @@ IntRect
|
|||||||
FilterNodeTransformSoftware::GetOutputRectInRect(const IntRect& aRect)
|
FilterNodeTransformSoftware::GetOutputRectInRect(const IntRect& aRect)
|
||||||
{
|
{
|
||||||
IntRect srcRect = SourceRectForOutputRect(aRect);
|
IntRect srcRect = SourceRectForOutputRect(aRect);
|
||||||
|
if (srcRect.IsEmpty()) {
|
||||||
|
return IntRect();
|
||||||
|
}
|
||||||
|
|
||||||
Rect outRect = mMatrix.TransformBounds(Rect(srcRect));
|
Rect outRect = mMatrix.TransformBounds(Rect(srcRect));
|
||||||
outRect.RoundOut();
|
outRect.RoundOut();
|
||||||
return RoundedToInt(outRect).Intersect(aRect);
|
return RoundedToInt(outRect).Intersect(aRect);
|
||||||
@ -2244,6 +2268,10 @@ FilterNodeConvolveMatrixSoftware::RequestFromInputsForRect(const IntRect &aRect)
|
|||||||
IntRect
|
IntRect
|
||||||
FilterNodeConvolveMatrixSoftware::InflatedSourceRect(const IntRect &aDestRect)
|
FilterNodeConvolveMatrixSoftware::InflatedSourceRect(const IntRect &aDestRect)
|
||||||
{
|
{
|
||||||
|
if (aDestRect.IsEmpty()) {
|
||||||
|
return IntRect();
|
||||||
|
}
|
||||||
|
|
||||||
IntMargin margin;
|
IntMargin margin;
|
||||||
margin.left = ceil(mTarget.x * mKernelUnitLength.width);
|
margin.left = ceil(mTarget.x * mKernelUnitLength.width);
|
||||||
margin.top = ceil(mTarget.y * mKernelUnitLength.height);
|
margin.top = ceil(mTarget.y * mKernelUnitLength.height);
|
||||||
@ -2258,6 +2286,10 @@ FilterNodeConvolveMatrixSoftware::InflatedSourceRect(const IntRect &aDestRect)
|
|||||||
IntRect
|
IntRect
|
||||||
FilterNodeConvolveMatrixSoftware::InflatedDestRect(const IntRect &aSourceRect)
|
FilterNodeConvolveMatrixSoftware::InflatedDestRect(const IntRect &aSourceRect)
|
||||||
{
|
{
|
||||||
|
if (aSourceRect.IsEmpty()) {
|
||||||
|
return IntRect();
|
||||||
|
}
|
||||||
|
|
||||||
IntMargin margin;
|
IntMargin margin;
|
||||||
margin.left = ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width);
|
margin.left = ceil((mKernelSize.width - mTarget.x - 1) * mKernelUnitLength.width);
|
||||||
margin.top = ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height);
|
margin.top = ceil((mKernelSize.height - mTarget.y - 1) * mKernelUnitLength.height);
|
||||||
@ -2513,11 +2545,25 @@ FilterNodeArithmeticCombineSoftware::Render(const IntRect& aRect)
|
|||||||
GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN, aRect, NEED_COLOR_CHANNELS);
|
GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN, aRect, NEED_COLOR_CHANNELS);
|
||||||
RefPtr<DataSourceSurface> input2 =
|
RefPtr<DataSourceSurface> input2 =
|
||||||
GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN2, aRect, NEED_COLOR_CHANNELS);
|
GetInputDataSourceSurface(IN_ARITHMETIC_COMBINE_IN2, aRect, NEED_COLOR_CHANNELS);
|
||||||
if (!input1 || !input2) {
|
if (!input1 && !input2) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FilterProcessing::ApplyArithmeticCombine(input1, input2, mK1, mK2, mK3, mK4);
|
// If one input is null, treat it as transparent by adjusting the factors.
|
||||||
|
Float k1 = mK1, k2 = mK2, k3 = mK3, k4 = mK4;
|
||||||
|
if (!input1) {
|
||||||
|
k1 = 0.0f;
|
||||||
|
k2 = 0.0f;
|
||||||
|
input1 = input2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input2) {
|
||||||
|
k1 = 0.0f;
|
||||||
|
k3 = 0.0f;
|
||||||
|
input2 = input1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilterProcessing::ApplyArithmeticCombine(input1, input2, k1, k2, k3, k4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2559,17 +2605,41 @@ FilterNodeCompositeSoftware::Render(const IntRect& aRect)
|
|||||||
GetInputDataSourceSurface(IN_COMPOSITE_IN_START, aRect, NEED_COLOR_CHANNELS);
|
GetInputDataSourceSurface(IN_COMPOSITE_IN_START, aRect, NEED_COLOR_CHANNELS);
|
||||||
RefPtr<DataSourceSurface> dest =
|
RefPtr<DataSourceSurface> dest =
|
||||||
Factory::CreateDataSourceSurface(aRect.Size(), FORMAT_B8G8R8A8);
|
Factory::CreateDataSourceSurface(aRect.Size(), FORMAT_B8G8R8A8);
|
||||||
if (!start || !dest) {
|
if (!dest) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
CopyRect(start, dest, aRect - aRect.TopLeft(), IntPoint());
|
|
||||||
|
if (start) {
|
||||||
|
CopyRect(start, dest, aRect - aRect.TopLeft(), IntPoint());
|
||||||
|
} else {
|
||||||
|
ClearDataSourceSurface(dest);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t inputIndex = 1; inputIndex < NumberOfSetInputs(); inputIndex++) {
|
for (size_t inputIndex = 1; inputIndex < NumberOfSetInputs(); inputIndex++) {
|
||||||
RefPtr<DataSourceSurface> input =
|
RefPtr<DataSourceSurface> input =
|
||||||
GetInputDataSourceSurface(IN_COMPOSITE_IN_START + inputIndex, aRect, NEED_COLOR_CHANNELS);
|
GetInputDataSourceSurface(IN_COMPOSITE_IN_START + inputIndex, aRect, NEED_COLOR_CHANNELS);
|
||||||
if (!input) {
|
if (input) {
|
||||||
return nullptr;
|
FilterProcessing::ApplyComposition(input, dest, mOperator);
|
||||||
|
} else {
|
||||||
|
// We need to treat input as transparent. Depending on the composite
|
||||||
|
// operator, different things happen to dest.
|
||||||
|
switch (mOperator) {
|
||||||
|
case COMPOSITE_OPERATOR_OVER:
|
||||||
|
case COMPOSITE_OPERATOR_ATOP:
|
||||||
|
case COMPOSITE_OPERATOR_XOR:
|
||||||
|
// dest is unchanged.
|
||||||
|
break;
|
||||||
|
case COMPOSITE_OPERATOR_OUT:
|
||||||
|
// dest is now transparent, but it can become non-transparent again
|
||||||
|
// when compositing additional inputs.
|
||||||
|
ClearDataSourceSurface(dest);
|
||||||
|
break;
|
||||||
|
case COMPOSITE_OPERATOR_IN:
|
||||||
|
// Transparency always wins. We're completely transparent now and
|
||||||
|
// no additional input can get rid of that transparency.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FilterProcessing::ApplyComposition(input, dest, mOperator);
|
|
||||||
}
|
}
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@ -3122,13 +3192,17 @@ FilterNodeLightingSoftware<LightType, LightingType>::DoRender(const IntRect& aRe
|
|||||||
GetInputDataSourceSurface(IN_LIGHTING_IN, srcRect, CAN_HANDLE_A8,
|
GetInputDataSourceSurface(IN_LIGHTING_IN, srcRect, CAN_HANDLE_A8,
|
||||||
EDGE_MODE_DUPLICATE);
|
EDGE_MODE_DUPLICATE);
|
||||||
|
|
||||||
|
if (!input) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (input->GetFormat() != FORMAT_A8) {
|
if (input->GetFormat() != FORMAT_A8) {
|
||||||
input = FilterProcessing::ExtractAlpha(input);
|
input = FilterProcessing::ExtractAlpha(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<DataSourceSurface> target =
|
RefPtr<DataSourceSurface> target =
|
||||||
Factory::CreateDataSourceSurface(size, FORMAT_B8G8R8A8);
|
Factory::CreateDataSourceSurface(size, FORMAT_B8G8R8A8);
|
||||||
if (!input || !target) {
|
if (!target) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user