From 25dbf74b8e2aac1c64145408d19c933e7a3d3672 Mon Sep 17 00:00:00 2001 From: Julian Harnath Date: Tue, 10 Nov 2015 22:52:56 +0100 Subject: [PATCH] BView: add methods for affine translation/scaling/rotation * BView::TranslateBy(), BView::ScaleBy() and BView::RotateBy() allow to conveniently modify the current affine transformation. This makes it unnecessary to first read the current transform, modify it, and then set it again. Uses the new Pre...() methods of BAffineTransform. * Also, remove setting the transform "through" to the BView even while recording a BPicture, as this now results in transforms being applied more than once. --- headers/os/interface/View.h | 3 + headers/private/app/ServerProtocol.h | 4 ++ headers/private/interface/PictureDataWriter.h | 3 + headers/private/interface/PicturePlayer.h | 3 + headers/private/interface/PictureProtocol.h | 5 +- src/kits/interface/PictureDataWriter.cpp | 47 ++++++++++++ src/kits/interface/PicturePlayer.cpp | 36 ++++++++++ src/kits/interface/View.cpp | 50 +++++++++++++ src/servers/app/PictureBoundingBoxPlayer.cpp | 38 ++++++++++ src/servers/app/ServerPicture.cpp | 37 ++++++++++ src/servers/app/ServerWindow.cpp | 71 ++++++++++++++++++- src/servers/app/drawing/DrawingEngine.cpp | 7 ++ src/servers/app/drawing/DrawingEngine.h | 1 + 13 files changed, 301 insertions(+), 4 deletions(-) diff --git a/headers/os/interface/View.h b/headers/os/interface/View.h index 59c57c10f6..84079e1cb1 100644 --- a/headers/os/interface/View.h +++ b/headers/os/interface/View.h @@ -300,6 +300,9 @@ public: // more powerful alternative. void SetTransform(BAffineTransform transform); BAffineTransform Transform() const; + void TranslateBy(double x, double y); + void ScaleBy(double x, double y); + void RotateBy(double angleRadians); void PushState(); void PopState(); diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 0ad22a00e6..d5f42f0907 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -343,6 +343,10 @@ enum { AS_VIEW_SET_TRANSFORM, AS_VIEW_GET_TRANSFORM, + AS_VIEW_AFFINE_TRANSLATE, + AS_VIEW_AFFINE_SCALE, + AS_VIEW_AFFINE_ROTATE, + // Polygon filling rules AS_VIEW_SET_FILL_RULE, AS_VIEW_GET_FILL_RULE, diff --git a/headers/private/interface/PictureDataWriter.h b/headers/private/interface/PictureDataWriter.h index a2f33fd637..6018ed9f47 100644 --- a/headers/private/interface/PictureDataWriter.h +++ b/headers/private/interface/PictureDataWriter.h @@ -41,6 +41,9 @@ public: const float& miterLimit); status_t WriteSetScale(const float& scale); status_t WriteSetTransform(BAffineTransform transform); + status_t WriteTranslateBy(double x, double y); + status_t WriteScaleBy(double x, double y); + status_t WriteRotateBy(double angleRadians); status_t WriteSetPattern(const ::pattern& pattern); status_t WriteClipToPicture(int32 pictureToken, const BPoint& origin, bool inverse); diff --git a/headers/private/interface/PicturePlayer.h b/headers/private/interface/PicturePlayer.h index 86e71b26e0..1a2e92b272 100644 --- a/headers/private/interface/PicturePlayer.h +++ b/headers/private/interface/PicturePlayer.h @@ -84,6 +84,9 @@ struct picture_player_callbacks { void (*set_blending_mode)(void* userData, source_alpha alphaSourceMode, alpha_function alphaFunctionMode); void (*set_transform)(void* userData, const BAffineTransform& transform); + void (*translate_by)(void* userData, double x, double y); + void (*scale_by)(void* userData, double x, double y); + void (*rotate_by)(void* userData, double angleRadians); void (*blend_layer)(void* userData, Layer* layer); void (*clip_to_rect)(void* userData, const BRect& rect, bool inverse); void (*clip_to_shape)(void* userData, int32 opCount, const uint32 opList[], diff --git a/headers/private/interface/PictureProtocol.h b/headers/private/interface/PictureProtocol.h index 84c0f468b4..b226b52dfe 100644 --- a/headers/private/interface/PictureProtocol.h +++ b/headers/private/interface/PictureProtocol.h @@ -54,7 +54,10 @@ enum { B_PIC_SET_FONT_BPP = 0x0388, B_PIC_SET_FONT_FACE = 0x0389, B_PIC_SET_TRANSFORM = 0x0390, - B_PIC_BLEND_LAYER = 0x0391 + B_PIC_AFFINE_TRANSLATE = 0x0391, + B_PIC_AFFINE_SCALE = 0x0392, + B_PIC_AFFINE_ROTATE = 0x0393, + B_PIC_BLEND_LAYER = 0x0394 }; diff --git a/src/kits/interface/PictureDataWriter.cpp b/src/kits/interface/PictureDataWriter.cpp index c0c0f023d9..1d99c5e4bc 100644 --- a/src/kits/interface/PictureDataWriter.cpp +++ b/src/kits/interface/PictureDataWriter.cpp @@ -183,6 +183,53 @@ PictureDataWriter::WriteSetTransform(BAffineTransform transform) } +status_t +PictureDataWriter::WriteTranslateBy(double x, double y) +{ + try { + BeginOp(B_PIC_AFFINE_TRANSLATE); + Write(x); + Write(y); + EndOp(); + } catch (status_t& status) { + return status; + } + + return B_OK; +} + + +status_t +PictureDataWriter::WriteScaleBy(double x, double y) +{ + try { + BeginOp(B_PIC_AFFINE_SCALE); + Write(x); + Write(y); + EndOp(); + } catch (status_t& status) { + return status; + } + + return B_OK; +} + + +status_t +PictureDataWriter::WriteRotateBy(double angleRadians) +{ + try { + BeginOp(B_PIC_AFFINE_ROTATE); + Write(angleRadians); + EndOp(); + } catch (status_t& status) { + return status; + } + + return B_OK; +} + + status_t PictureDataWriter::WriteSetPattern(const ::pattern& pattern) { diff --git a/src/kits/interface/PicturePlayer.cpp b/src/kits/interface/PicturePlayer.cpp index 1b52179557..7d356e4b28 100644 --- a/src/kits/interface/PicturePlayer.cpp +++ b/src/kits/interface/PicturePlayer.cpp @@ -1213,6 +1213,42 @@ PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData, break; } + case B_PIC_AFFINE_TRANSLATE: + { + const double* x; + const double* y; + if (callbacks.translate_by == NULL || !reader.Get(x) + || !reader.Get(y)) { + break; + } + + callbacks.translate_by(userData, *x, *y); + break; + } + + case B_PIC_AFFINE_SCALE: + { + const double* x; + const double* y; + if (callbacks.scale_by == NULL || !reader.Get(x) + || !reader.Get(y)) { + break; + } + + callbacks.scale_by(userData, *x, *y); + break; + } + + case B_PIC_AFFINE_ROTATE: + { + const double* angleRadians; + if (callbacks.rotate_by == NULL || !reader.Get(angleRadians)) + break; + + callbacks.rotate_by(userData, *angleRadians); + break; + } + case B_PIC_BLEND_LAYER: { Layer* const* layer; diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index bb57d2b319..0a0f2b4e98 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -1924,6 +1924,56 @@ BView::Transform() const } +void +BView::TranslateBy(double x, double y) +{ + if (fOwner != NULL) { + _CheckLockAndSwitchCurrent(); + + fOwner->fLink->StartMessage(AS_VIEW_AFFINE_TRANSLATE); + fOwner->fLink->Attach(x); + fOwner->fLink->Attach(y); + + fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; + } + + fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; +} + + +void +BView::ScaleBy(double x, double y) +{ + if (fOwner != NULL) { + _CheckLockAndSwitchCurrent(); + + fOwner->fLink->StartMessage(AS_VIEW_AFFINE_SCALE); + fOwner->fLink->Attach(x); + fOwner->fLink->Attach(y); + + fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; + } + + fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; +} + + +void +BView::RotateBy(double angleRadians) +{ + if (fOwner != NULL) { + _CheckLockAndSwitchCurrent(); + + fOwner->fLink->StartMessage(AS_VIEW_AFFINE_ROTATE); + fOwner->fLink->Attach(angleRadians); + + fState->valid_flags &= ~B_VIEW_TRANSFORM_BIT; + } + + fState->archiving_flags |= B_VIEW_TRANSFORM_BIT; +} + + void BView::SetLineMode(cap_mode lineCap, join_mode lineJoin, float miterLimit) { diff --git a/src/servers/app/PictureBoundingBoxPlayer.cpp b/src/servers/app/PictureBoundingBoxPlayer.cpp index e4382b7a16..0e465b8190 100644 --- a/src/servers/app/PictureBoundingBoxPlayer.cpp +++ b/src/servers/app/PictureBoundingBoxPlayer.cpp @@ -730,7 +730,42 @@ set_transform(void* _state, const BAffineTransform& transform) TRACE_BB("%p transform\n", _state); BoundingBoxState* const state = reinterpret_cast(_state); + state->GetDrawState()->SetTransform(transform); +} + +static void +translate_by(void* _state, double x, double y) +{ + TRACE_BB("%p translate\n", _state); + BoundingBoxState* const state = + reinterpret_cast(_state); + BAffineTransform transform = state->GetDrawState()->Transform(); + transform.PreTranslateBy(x, y); + state->GetDrawState()->SetTransform(transform); +} + + +static void +scale_by(void* _state, double x, double y) +{ + TRACE_BB("%p scale\n", _state); + BoundingBoxState* const state = + reinterpret_cast(_state); + BAffineTransform transform = state->GetDrawState()->Transform(); + transform.PreScaleBy(x, y); + state->GetDrawState()->SetTransform(transform); +} + + +static void +rotate_by(void* _state, double angleRadians) +{ + TRACE_BB("%p rotate\n", _state); + BoundingBoxState* const state = + reinterpret_cast(_state); + BAffineTransform transform = state->GetDrawState()->Transform(); + transform.PreRotateBy(angleRadians); state->GetDrawState()->SetTransform(transform); } @@ -791,6 +826,9 @@ static const BPrivate::picture_player_callbacks set_font_face, set_blending_mode, set_transform, + translate_by, + scale_by, + rotate_by, determine_bounds_nested_layer }; diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 422cccb033..d265336b1c 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -749,6 +749,40 @@ set_transform(void* _canvas, const BAffineTransform& transform) { Canvas* const canvas = reinterpret_cast(_canvas); canvas->CurrentState()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform(transform); +} + + +static void +translate_by(void* _canvas, double x, double y) +{ + Canvas* const canvas = reinterpret_cast(_canvas); + BAffineTransform transform = canvas->CurrentState()->Transform(); + transform.PreTranslateBy(x, y); + canvas->CurrentState()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform(transform); +} + + +static void +scale_by(void* _canvas, double x, double y) +{ + Canvas* const canvas = reinterpret_cast(_canvas); + BAffineTransform transform = canvas->CurrentState()->Transform(); + transform.PreScaleBy(x, y); + canvas->CurrentState()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform(transform); +} + + +static void +rotate_by(void* _canvas, double angleRadians) +{ + Canvas* const canvas = reinterpret_cast(_canvas); + BAffineTransform transform = canvas->CurrentState()->Transform(); + transform.PreRotateBy(angleRadians); + canvas->CurrentState()->SetTransform(transform); + canvas->GetDrawingEngine()->SetTransform(transform); } @@ -838,6 +872,9 @@ static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = { set_font_face, set_blending_mode, set_transform, + translate_by, + scale_by, + rotate_by, blend_layer, clip_to_rect, clip_to_shape diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 934c198fb1..6539d64f22 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1635,6 +1635,44 @@ fDesktop->LockSingleWindow(); fLink.Flush(); break; } + case AS_VIEW_AFFINE_TRANSLATE: + { + double x, y; + link.Read(&x); + link.Read(&y); + BAffineTransform current = + fCurrentView->CurrentState()->Transform(); + current.PreTranslateBy(x, y); + fCurrentView->CurrentState()->SetTransform(current); + _UpdateDrawState(fCurrentView); + break; + } + + case AS_VIEW_AFFINE_SCALE: + { + double x, y; + link.Read(&x); + link.Read(&y); + BAffineTransform current = + fCurrentView->CurrentState()->Transform(); + current.PreScaleBy(x, y); + fCurrentView->CurrentState()->SetTransform(current); + _UpdateDrawState(fCurrentView); + break; + } + + case AS_VIEW_AFFINE_ROTATE: + { + double angleRadians; + link.Read(&angleRadians); + BAffineTransform current = + fCurrentView->CurrentState()->Transform(); + current.PreRotateBy(angleRadians); + fCurrentView->CurrentState()->SetTransform(current); + _UpdateDrawState(fCurrentView); + break; + } + case AS_VIEW_SET_PEN_LOC: { BPoint location; @@ -3133,12 +3171,39 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) break; picture->WriteSetTransform(transform); - - fCurrentView->CurrentState()->SetTransform(transform); - _UpdateDrawState(fCurrentView); break; } + case AS_VIEW_AFFINE_TRANSLATE: + { + double x, y; + link.Read(&x); + link.Read(&y); + + picture->WriteTranslateBy(x, y); + break; + } + + case AS_VIEW_AFFINE_SCALE: + { + double x, y; + link.Read(&x); + link.Read(&y); + + picture->WriteScaleBy(x, y); + break; + } + + case AS_VIEW_AFFINE_ROTATE: + { + double angleRadians; + link.Read(&angleRadians); + + picture->WriteRotateBy(angleRadians); + break; + } + + case AS_VIEW_SET_PATTERN: { pattern pat; diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index 147a359b18..eb323a1430 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -322,6 +322,13 @@ DrawingEngine::SetFont(const DrawState* state) } +void +DrawingEngine::SetTransform(const BAffineTransform& transform) +{ + fPainter->SetTransform(transform); +} + + // #pragma mark - diff --git a/src/servers/app/drawing/DrawingEngine.h b/src/servers/app/drawing/DrawingEngine.h index d9a0896614..0aafa63d50 100644 --- a/src/servers/app/drawing/DrawingEngine.h +++ b/src/servers/app/drawing/DrawingEngine.h @@ -86,6 +86,7 @@ public: alpha_function alphaFunc); virtual void SetFont(const ServerFont& font); virtual void SetFont(const DrawState* state); + virtual void SetTransform(const BAffineTransform& transform); void SuspendAutoSync(); void Sync();