From b8e5671d5318e59ad4e36f047940521d18d1f5ed Mon Sep 17 00:00:00 2001 From: X512 Date: Sun, 7 Jun 2020 17:08:41 +0900 Subject: [PATCH] app_server: fix transformations in BPicture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #16122, #16147. Change-Id: I16a38919d25836546389aff6093415eda781668f Reviewed-on: https://review.haiku-os.org/c/haiku/+/2889 Reviewed-by: Stephan Aßmus --- src/servers/app/ServerPicture.cpp | 53 +++++++++++++++++++---- src/servers/app/ServerWindow.cpp | 24 ++++------ src/servers/app/drawing/DrawingEngine.cpp | 5 ++- src/servers/app/drawing/DrawingEngine.h | 3 +- src/servers/app/drawing/Painter/Painter.h | 3 +- 5 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 162f641a3b..9a5f8c3136 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -208,10 +208,18 @@ ShapePainter::Draw(BRect frame, bool filled) fPtStack.pop(); } - BPoint offset(fCanvas->CurrentState()->PenLocation()); - fCanvas->PenToScreenTransform().Apply(&offset); + // this might seem a bit weird, but under R5, the shapes + // are always offset by the current pen location + BPoint screenOffset + = fCanvas->CurrentState()->PenLocation(); + frame.OffsetBy(screenOffset); + + const SimpleTransform transform = fCanvas->PenToScreenTransform(); + transform.Apply(&screenOffset); + transform.Apply(&frame); + fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList, - ptCount, ptList, filled, offset, fCanvas->Scale()); + ptCount, ptList, filled, screenOffset, fCanvas->Scale()); delete[] opList; delete[] ptList; @@ -407,9 +415,18 @@ draw_string(void* _canvas, const char* string, size_t length, float deltaSpace, static void draw_string_locations(void* _canvas, const char* string, size_t length, - const BPoint* locations, size_t locationsCount) + const BPoint* _locations, size_t locationsCount) { Canvas* const canvas = reinterpret_cast(_canvas); + BStackOrHeapArray locations(locationsCount); + if (!locations.IsValid()) + return; + + const SimpleTransform transform = canvas->PenToScreenTransform(); + for (size_t i = 0; i < locationsCount; i++) { + locations[i] = _locations[i]; + transform.Apply(&locations[i]); + } BPoint location = canvas->GetDrawingEngine()->DrawString(string, length, locations); @@ -758,8 +775,13 @@ static void set_transform(void* _canvas, const BAffineTransform& transform) { Canvas* const canvas = reinterpret_cast(_canvas); + + BPoint leftTop(0, 0); + canvas->PenToScreenTransform().Apply(&leftTop); + canvas->CurrentState()->SetTransform(transform); - canvas->GetDrawingEngine()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform( + canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); } @@ -767,10 +789,15 @@ static void translate_by(void* _canvas, double x, double y) { Canvas* const canvas = reinterpret_cast(_canvas); + + BPoint leftTop(0, 0); + canvas->PenToScreenTransform().Apply(&leftTop); + BAffineTransform transform = canvas->CurrentState()->Transform(); transform.PreTranslateBy(x, y); canvas->CurrentState()->SetTransform(transform); - canvas->GetDrawingEngine()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform( + canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); } @@ -778,10 +805,15 @@ static void scale_by(void* _canvas, double x, double y) { Canvas* const canvas = reinterpret_cast(_canvas); + + BPoint leftTop(0, 0); + canvas->PenToScreenTransform().Apply(&leftTop); + BAffineTransform transform = canvas->CurrentState()->Transform(); transform.PreScaleBy(x, y); canvas->CurrentState()->SetTransform(transform); - canvas->GetDrawingEngine()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform( + canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); } @@ -789,10 +821,15 @@ static void rotate_by(void* _canvas, double angleRadians) { Canvas* const canvas = reinterpret_cast(_canvas); + + BPoint leftTop(0, 0); + canvas->PenToScreenTransform().Apply(&leftTop); + BAffineTransform transform = canvas->CurrentState()->Transform(); transform.PreRotateBy(angleRadians); canvas->CurrentState()->SetTransform(transform); - canvas->GetDrawingEngine()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform( + canvas->CurrentState()->CombinedTransform(), leftTop.x, leftTop.y); } diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index f236c10969..16a4ad7b6a 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -3671,24 +3671,16 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&opCount); link.Read(&ptCount); - uint32* opList = new(std::nothrow) uint32[opCount]; - BPoint* ptList = new(std::nothrow) BPoint[ptCount]; - if (opList != NULL && ptList != NULL - && link.Read(opList, opCount * sizeof(uint32)) >= B_OK - && link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) { - // This might seem a bit weird, but under BeOS, the shapes - // are always offset by the current pen location - BPoint penLocation - = fCurrentView->CurrentState()->PenLocation(); - for (int32 i = 0; i < ptCount; i++) { - ptList[i] += penLocation; - } - const bool fill = (code == AS_FILL_SHAPE); - picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill); + BStackOrHeapArray opList(opCount); + BStackOrHeapArray ptList(ptCount); + if (!opList.IsValid() || !ptList.IsValid() + || link.Read(opList, opCount * sizeof(uint32)) < B_OK + || link.Read(ptList, ptCount * sizeof(BPoint)) < B_OK) { + break; } + picture->WriteDrawShape(opCount, opList, ptCount, + ptList, code == AS_FILL_SHAPE); - delete[] opList; - delete[] ptList; break; } diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index c4e50f6da0..8d50de84a5 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -323,9 +323,10 @@ DrawingEngine::SetFont(const DrawState* state) void -DrawingEngine::SetTransform(const BAffineTransform& transform) +DrawingEngine::SetTransform(const BAffineTransform& transform, int32 xOffset, + int32 yOffset) { - fPainter->SetTransform(transform); + fPainter->SetTransform(transform, xOffset, yOffset); } diff --git a/src/servers/app/drawing/DrawingEngine.h b/src/servers/app/drawing/DrawingEngine.h index dc010bb925..763e8f995d 100644 --- a/src/servers/app/drawing/DrawingEngine.h +++ b/src/servers/app/drawing/DrawingEngine.h @@ -86,7 +86,8 @@ public: alpha_function alphaFunc); virtual void SetFont(const ServerFont& font); virtual void SetFont(const DrawState* state); - virtual void SetTransform(const BAffineTransform& transform); + virtual void SetTransform(const BAffineTransform& transform, + int32 xOffset, int32 yOffset); void SuspendAutoSync(); void Sync(); diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index fc22b08193..c997dfd00e 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -68,8 +68,7 @@ public: // object settings void SetTransform(BAffineTransform transform, - int32 xOffset = 0, - int32 yOffset = 0); + int32 xOffset, int32 yOffset); inline bool IsIdentityTransform() const { return fIdentityTransform; }