Fix handling of filled rectangles with transforms.

The DrawingEngine didn't properly make a distinction between the
rectangle being filled and the damaged region on screen. This led to
unexpected results when using BAffineTransform.
This commit is contained in:
Adrien Destugues
2014-05-19 14:18:56 +02:00
parent 66bce8233a
commit 79eb23a82d
+52 -34
View File
@@ -963,49 +963,62 @@ DrawingEngine::FillRect(BRect r)
ASSERT_PARALLEL_LOCKED(); ASSERT_PARALLEL_LOCKED();
make_rect_valid(r); make_rect_valid(r);
r = fPainter->TransformAlignAndClipRect(r); r.left = floorf(r.left);
if (!r.IsValid()) r.top = floorf(r.top);
r.right = ceilf(r.right);
r.bottom = ceilf(r.bottom);
BRect dirty = fPainter->TransformAndClipRect(r);
if (!dirty.IsValid())
return; return;
AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r); AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r);
bool doInSoftware = true; bool doInSoftware = true;
if ((r.Width() + 1) * (r.Height() + 1) > 100.0) {
// try hardware optimized version first if (fPainter->IsIdentityTransform())
// if the rect is large enough {
if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) { // TODO the accelerated code path may also be used for transforms that
if (fPainter->Pattern() == B_SOLID_HIGH // only scale and translate (but don't shear or rotate).
&& (fPainter->DrawingMode() == B_OP_COPY
|| fPainter->DrawingMode() == B_OP_OVER)) { if ((r.Width() + 1) * (r.Height() + 1) > 100.0) {
BRegion region(r); // try hardware optimized version first
region.IntersectWith(fPainter->ClippingRegion()); // if the rect is large enough
fGraphicsCard->FillRegion(region, fPainter->HighColor(), if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) {
fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); if (fPainter->Pattern() == B_SOLID_HIGH
doInSoftware = false; && (fPainter->DrawingMode() == B_OP_COPY
} else if (fPainter->Pattern() == B_SOLID_LOW || fPainter->DrawingMode() == B_OP_OVER)) {
&& fPainter->DrawingMode() == B_OP_COPY) { BRegion region(r);
BRegion region(r); region.IntersectWith(fPainter->ClippingRegion());
region.IntersectWith(fPainter->ClippingRegion()); fGraphicsCard->FillRegion(region, fPainter->HighColor(),
fGraphicsCard->FillRegion(region, fPainter->LowColor(), fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
fSuspendSyncLevel == 0 || overlaysHider.WasHidden()); doInSoftware = false;
doInSoftware = false; } else if (fPainter->Pattern() == B_SOLID_LOW
&& fPainter->DrawingMode() == B_OP_COPY) {
BRegion region(r);
region.IntersectWith(fPainter->ClippingRegion());
fGraphicsCard->FillRegion(region, fPainter->LowColor(),
fSuspendSyncLevel == 0 || overlaysHider.WasHidden());
doInSoftware = false;
}
} }
} }
}
if (doInSoftware && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0 if (doInSoftware
&& fPainter->Pattern() == B_SOLID_HIGH && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0
&& fPainter->DrawingMode() == B_OP_INVERT) { && fPainter->Pattern() == B_SOLID_HIGH
BRegion region(r); && fPainter->DrawingMode() == B_OP_INVERT) {
region.IntersectWith(fPainter->ClippingRegion()); BRegion region(r);
fGraphicsCard->InvertRegion(region); region.IntersectWith(fPainter->ClippingRegion());
doInSoftware = false; fGraphicsCard->InvertRegion(region);
doInSoftware = false;
}
} }
if (doInSoftware) if (doInSoftware)
fPainter->FillRect(r); fPainter->FillRect(r);
_CopyToFront(r); _CopyToFront(dirty);
} }
@@ -1015,15 +1028,20 @@ DrawingEngine::FillRect(BRect r, const BGradient& gradient)
ASSERT_PARALLEL_LOCKED(); ASSERT_PARALLEL_LOCKED();
make_rect_valid(r); make_rect_valid(r);
r = fPainter->TransformAlignAndClipRect(r); r.left = floorf(r.left);
if (!r.IsValid()) r.top = floorf(r.top);
r.right = ceilf(r.right);
r.bottom = ceilf(r.bottom);
BRect dirty = fPainter->TransformAndClipRect(r);
if (!dirty.IsValid())
return; return;
AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, r); AutoFloatingOverlaysHider overlaysHider(fGraphicsCard, dirty);
fPainter->FillRect(r, gradient); fPainter->FillRect(r, gradient);
_CopyToFront(r); _CopyToFront(dirty);
} }