From 89f8b7a12d16a16388e45a4708c033cfb3993df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sat, 8 Feb 2014 11:36:13 +0100 Subject: [PATCH] app_server: Fix computing bounding boxes for transformed stuff. * In DrawingEngine, clipping is computed before drawing happens. This did not take into account when drawing primitives can now be transformed. Fixes drawing glitches in the Transformation test when the round rect is scrolled into view and it was previously prevented to draw. * Fixed clipping rect computation for the sanitized StrokeRoundRect() implementation which centers the stroke on the rect. --- src/servers/app/drawing/DrawingEngine.cpp | 48 +++++++++++------------ src/servers/app/drawing/Painter/Painter.h | 42 +++++++++++++++++++- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index 6ef0b85c73..3fdc48f4f4 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -583,6 +583,7 @@ DrawingEngine::InvertRect(BRect r) ASSERT_PARALLEL_LOCKED(); make_rect_valid(r); + // NOTE: Currently ignores view transformation, so no TransformAndClipRect() r = fPainter->ClipRect(r); if (!r.IsValid()) return; @@ -608,7 +609,7 @@ DrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& bitmapRect, { ASSERT_PARALLEL_LOCKED(); - BRect clipped = fPainter->ClipRect(viewRect); + BRect clipped = fPainter->TransformAndClipRect(viewRect); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -632,7 +633,7 @@ DrawingEngine::DrawArc(BRect r, const float& angle, const float& span, if (!filled) extend_by_stroke_width(clipped, fPainter->PenSize()); - clipped = fPainter->ClipRect(r); + clipped = fPainter->TransformAndClipRect(r); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -662,7 +663,7 @@ DrawingEngine::FillArc(BRect r, const float& angle, const float& span, fPainter->AlignEllipseRect(&r, true); BRect clipped(r); - clipped = fPainter->ClipRect(r); + clipped = fPainter->TransformAndClipRect(r); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -724,7 +725,7 @@ DrawingEngine::DrawEllipse(BRect r, bool filled) clipped.right = ceilf(clipped.right); clipped.bottom = ceilf(clipped.bottom); - clipped = fPainter->ClipRect(clipped); + clipped = fPainter->TransformAndClipRect(clipped); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -750,7 +751,7 @@ DrawingEngine::FillEllipse(BRect r, const BGradient& gradient) clipped.right = ceilf(clipped.right); clipped.bottom = ceilf(clipped.bottom); - clipped = fPainter->ClipRect(clipped); + clipped = fPainter->TransformAndClipRect(clipped); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -771,7 +772,7 @@ DrawingEngine::DrawPolygon(BPoint* ptlist, int32 numpts, BRect bounds, make_rect_valid(bounds); if (!filled) extend_by_stroke_width(bounds, fPainter->PenSize()); - bounds = fPainter->ClipRect(bounds); + bounds = fPainter->TransformAndClipRect(bounds); if (bounds.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, bounds); @@ -789,7 +790,7 @@ DrawingEngine::FillPolygon(BPoint* ptlist, int32 numpts, BRect bounds, ASSERT_PARALLEL_LOCKED(); make_rect_valid(bounds); - bounds = fPainter->ClipRect(bounds); + bounds = fPainter->TransformAndClipRect(bounds); if (bounds.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, bounds); @@ -938,7 +939,7 @@ DrawingEngine::StrokeRect(BRect r) make_rect_valid(r); BRect clipped(r); extend_by_stroke_width(clipped, fPainter->PenSize()); - clipped = fPainter->ClipRect(clipped); + clipped = fPainter->TransformAndClipRect(clipped); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -955,7 +956,7 @@ DrawingEngine::FillRect(BRect r) ASSERT_PARALLEL_LOCKED(); make_rect_valid(r); - r = fPainter->AlignAndClipRect(r); + r = fPainter->TransformAlignAndClipRect(r); if (!r.IsValid()) return; @@ -1007,7 +1008,7 @@ DrawingEngine::FillRect(BRect r, const BGradient& gradient) ASSERT_PARALLEL_LOCKED(); make_rect_valid(r); - r = fPainter->AlignAndClipRect(r); + r = fPainter->TransformAlignAndClipRect(r); if (!r.IsValid()) return; @@ -1024,7 +1025,7 @@ DrawingEngine::FillRegion(BRegion& r) { ASSERT_PARALLEL_LOCKED(); - BRect clipped = fPainter->ClipRect(r.Frame()); + BRect clipped = fPainter->TransformAndClipRect(r.Frame()); if (!clipped.IsValid()) return; @@ -1095,10 +1096,10 @@ DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, bool filled) { ASSERT_PARALLEL_LOCKED(); - // NOTE: the stroke does not extend past "r" in R5, - // though I consider this unexpected behaviour. make_rect_valid(r); - BRect clipped = fPainter->ClipRect(r); + if (!filled) + extend_by_stroke_width(r, fPainter->PenSize()); + BRect clipped = fPainter->TransformAndClipRect(r); clipped.left = floorf(clipped.left); clipped.top = floorf(clipped.top); @@ -1122,10 +1123,8 @@ DrawingEngine::FillRoundRect(BRect r, float xrad, float yrad, { ASSERT_PARALLEL_LOCKED(); - // NOTE: the stroke does not extend past "r" in R5, - // though I consider this unexpected behaviour. make_rect_valid(r); - BRect clipped = fPainter->ClipRect(r); + BRect clipped = fPainter->TransformAndClipRect(r); clipped.left = floorf(clipped.left); clipped.top = floorf(clipped.top); @@ -1210,7 +1209,7 @@ DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, bool filled) BRect clipped(bounds); if (!filled) extend_by_stroke_width(clipped, fPainter->PenSize()); - clipped = fPainter->ClipRect(clipped); + clipped = fPainter->TransformAndClipRect(clipped); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -1231,7 +1230,7 @@ DrawingEngine::FillTriangle(BPoint* pts, const BRect& bounds, ASSERT_PARALLEL_LOCKED(); BRect clipped(bounds); - clipped = fPainter->ClipRect(clipped); + clipped = fPainter->TransformAndClipRect(clipped); if (clipped.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, clipped); @@ -1250,7 +1249,7 @@ DrawingEngine::StrokeLine(const BPoint& start, const BPoint& end) BRect touched(start, end); make_rect_valid(touched); extend_by_stroke_width(touched, fPainter->PenSize()); - touched = fPainter->ClipRect(touched); + touched = fPainter->TransformAndClipRect(touched); if (touched.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, touched); @@ -1286,7 +1285,7 @@ DrawingEngine::StrokeLineArray(int32 numLines, touched = touched | box; } extend_by_stroke_width(touched, fPainter->PenSize()); - touched = fPainter->ClipRect(touched); + touched = fPainter->TransformAndClipRect(touched); if (touched.IsValid()) { AutoFloatingOverlaysHider _(fGraphicsCard, touched); @@ -1328,7 +1327,8 @@ DrawingEngine::DrawString(const char* string, int32 length, BPoint penLocation = pt; // try a fast clipping path - if (fPainter->ClippingRegion() && fPainter->Font().Rotation() == 0.0f) { + if (fPainter->ClippingRegion() && fPainter->Font().Rotation() == 0.0f + && fPainter->IsIdentityTransform()) { float fontSize = fPainter->Font().Size(); BRect clippingFrame = fPainter->ClippingRegion()->Frame(); if (pt.x - fontSize > clippingFrame.right @@ -1354,7 +1354,7 @@ DrawingEngine::DrawString(const char* string, int32 length, BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta, &cacheReference); // stop here if we're supposed to render outside of the clipping - b = fPainter->ClipRect(b); + b = fPainter->TransformAndClipRect(b); if (b.IsValid()) { //printf("bounding box '%s': %lld µs\n", string, system_time() - now); AutoFloatingOverlaysHider _(fGraphicsCard, b); @@ -1385,7 +1385,7 @@ DrawingEngine::DrawString(const char* string, int32 length, BRect b = fPainter->BoundingBox(string, length, offsets, &penLocation, &cacheReference); // stop here if we're supposed to render outside of the clipping - b = fPainter->ClipRect(b); + b = fPainter->TransformAndClipRect(b); if (b.IsValid()) { //printf("bounding box '%s': %lld µs\n", string, system_time() - now); AutoFloatingOverlaysHider _(fGraphicsCard, b); diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index 6e5a09ef3e..bb9f200399 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -15,6 +15,7 @@ #include "FontManager.h" #include "PatternHandler.h" #include "ServerFont.h" +#include "Transformable.h" #include "defines.h" @@ -39,7 +40,6 @@ class FontCacheReference; class RenderingBuffer; class ServerBitmap; class ServerFont; -class Transformable; class Painter { @@ -65,6 +65,9 @@ public: int32 xOffset = 0, int32 yOffset = 0); + inline bool IsIdentityTransform() const + { return fIdentityTransform; } + void SetHighColor(const rgb_color& color); inline rgb_color HighColor() const { return fPatternHandler.HighColor(); } @@ -233,7 +236,9 @@ public: BRect InvertRect(const BRect& r) const; + inline BRect TransformAndClipRect(BRect rect) const; inline BRect ClipRect(BRect rect) const; + inline BRect TransformAlignAndClipRect(BRect rect) const; inline BRect AlignAndClipRect(BRect rect) const; @@ -367,7 +372,7 @@ private: bool fAttached : 1; bool fIdentityTransform : 1; - agg::trans_affine fTransform; + Transformable fTransform; float fPenSize; const BRegion* fClippingRegion; drawing_mode fDrawingMode; @@ -386,6 +391,21 @@ private: }; +inline BRect +Painter::TransformAndClipRect(BRect rect) const +{ + rect.left = floorf(rect.left); + rect.top = floorf(rect.top); + rect.right = ceilf(rect.right); + rect.bottom = ceilf(rect.bottom); + + if (!fIdentityTransform) + rect = fTransform.TransformBounds(rect); + + return _Clipped(rect); +} + + inline BRect Painter::ClipRect(BRect rect) const { @@ -413,4 +433,22 @@ Painter::AlignAndClipRect(BRect rect) const } +inline BRect +Painter::TransformAlignAndClipRect(BRect rect) const +{ + rect.left = floorf(rect.left); + rect.top = floorf(rect.top); + if (fSubpixelPrecise) { + rect.right = ceilf(rect.right); + rect.bottom = ceilf(rect.bottom); + } else { + rect.right = floorf(rect.right); + rect.bottom = floorf(rect.bottom); + } + if (!fIdentityTransform) + rect = fTransform.TransformBounds(rect); + return _Clipped(rect); +} + + #endif // PAINTER_H