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();