diff --git a/headers/os/interface/View.h b/headers/os/interface/View.h index e744375fee..29a3fefc12 100644 --- a/headers/os/interface/View.h +++ b/headers/os/interface/View.h @@ -505,6 +505,9 @@ public: void DrawPictureAsync(const char* filename, long offset, BPoint where); + void BeginLayer(uint8 opacity); + void EndLayer(); + status_t SetEventMask(uint32 mask, uint32 options = 0); uint32 EventMask(); status_t SetMouseEventMask(uint32 mask, diff --git a/headers/private/app/RegistrarDefs.h b/headers/private/app/RegistrarDefs.h index 736edbf361..e58216951b 100644 --- a/headers/private/app/RegistrarDefs.h +++ b/headers/private/app/RegistrarDefs.h @@ -23,7 +23,14 @@ namespace BPrivate { extern const char* kRAppLooperPortName; -#define B_REGISTRAR_SIGNATURE "application/x-vnd.haiku-registrar" +#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST +# define B_REGISTRAR_SIGNATURE "application/x-vnd.haiku-registrar" +# define B_REGISTRAR_PORT_NAME "system:roster" +#else +# define B_REGISTRAR_SIGNATURE "application/x-vnd.test-registrar" +# define B_REGISTRAR_PORT_NAME "haiku-test:roster" +#endif + #define B_REGISTRAR_AUTHENTICATION_PORT_NAME "auth" diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 952a6111dd..8e6bc00f4f 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -7,6 +7,7 @@ * Jérôme Duval, jerome.duval@free.fr * Axel Dörfler, axeld@pinc-software.de * Andrej Spielmann, + * Julian Harnath, */ #ifndef APP_SERVER_PROTOCOL_H #define APP_SERVER_PROTOCOL_H @@ -15,6 +16,10 @@ #include +#ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST +# define SERVER_PORT_NAME "haiku-test:app_server" +#endif + #if TEST_MODE # define SERVER_INPUT_PORT "haiku-test:input port" #endif @@ -319,6 +324,8 @@ enum { AS_VIEW_SET_VIEW_BITMAP, AS_VIEW_SET_PATTERN, AS_SET_CURRENT_VIEW, + AS_VIEW_BEGIN_LAYER, + AS_VIEW_END_LAYER, // BDirectWindow/BWindowScreen codes AS_DIRECT_WINDOW_GET_SYNC_DATA, diff --git a/headers/private/interface/PictureDataWriter.h b/headers/private/interface/PictureDataWriter.h index ea3fe9e7c8..805b3ea6f7 100644 --- a/headers/private/interface/PictureDataWriter.h +++ b/headers/private/interface/PictureDataWriter.h @@ -1,9 +1,10 @@ /* - * Copyright 2006-2007 Haiku, Inc. All rights reserved. + * Copyright 2006-2015 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini, burton666@libero.it + * Julian Harnath, */ #ifndef _PICTURE_DATA_WRITER_H #define _PICTURE_DATA_WRITER_H @@ -17,6 +18,7 @@ #include +class Layer; class BPositionIO; class BRegion; @@ -93,6 +95,8 @@ public: status_t WriteDrawPicture(const BPoint& where, const int32& token); + status_t WriteBlendLayer(Layer* layer); + protected: // throw a status_t on error void BeginOp(const int16& op); diff --git a/headers/private/interface/PicturePlayer.h b/headers/private/interface/PicturePlayer.h index f21b3ff4c5..09ea7b6a6e 100644 --- a/headers/private/interface/PicturePlayer.h +++ b/headers/private/interface/PicturePlayer.h @@ -23,6 +23,7 @@ class BAffineTransform; class BList; class BPicture; class BShape; +class Layer; namespace BPrivate { @@ -83,6 +84,7 @@ 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 (*blend_layer)(void* userData, Layer* layer); }; diff --git a/headers/private/interface/PictureProtocol.h b/headers/private/interface/PictureProtocol.h index f83b53d86c..f33abddaa6 100644 --- a/headers/private/interface/PictureProtocol.h +++ b/headers/private/interface/PictureProtocol.h @@ -52,10 +52,11 @@ enum { B_PIC_SET_FONT_BPP = 0x0388, B_PIC_SET_FONT_FACE = 0x0389, B_PIC_SET_TRANSFORM = 0x0390, + B_PIC_BLEND_LAYER = 0x0391 }; -const static uint32 kOpsTableSize = 49; +const static uint32 kOpsTableSize = 50; #endif diff --git a/src/kits/app/AppMisc.cpp b/src/kits/app/AppMisc.cpp index 1a607f785f..e996190ab8 100644 --- a/src/kits/app/AppMisc.cpp +++ b/src/kits/app/AppMisc.cpp @@ -176,6 +176,9 @@ is_app_showing_modal_window(team_id team) } +#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST + + /*! Creates a connection with the desktop. */ status_t @@ -208,4 +211,61 @@ create_desktop_connection(ServerLink* link, const char* name, int32 capacity) } +#else // HAIKU_TARGET_PLATFORM_LIBBE_TEST + + +static port_id sServerPort = -1; + + +port_id +get_app_server_port() +{ + if (sServerPort < 0) { + // No need for synchronization - in the worst case, we'll call + // find_port() twice. + sServerPort = find_port(SERVER_PORT_NAME); + } + + return sServerPort; +} + + +/*! Creates a connection with the desktop. +*/ +status_t +create_desktop_connection(ServerLink* link, const char* name, int32 capacity) +{ + port_id serverPort = get_app_server_port(); + if (serverPort < 0) + return serverPort; + + // Create the port so that the app_server knows where to send messages + port_id clientPort = create_port(capacity, name); + if (clientPort < 0) + return clientPort; + + link->SetTo(serverPort, clientPort); + + link->StartMessage(AS_GET_DESKTOP); + link->Attach(clientPort); + link->Attach(getuid()); + link->AttachString(getenv("TARGET_SCREEN")); + link->Attach(AS_PROTOCOL_VERSION); + + int32 code; + if (link->FlushWithReply(code) != B_OK || code != B_OK) { + link->SetSenderPort(-1); + return B_ERROR; + } + + link->Read(&serverPort); + link->SetSenderPort(serverPort); + + return B_OK; +} + + +#endif // HAIKU_TARGET_PLATFORM_LIBBE_TEST + + } // namespace BPrivate diff --git a/src/kits/app/Roster.cpp b/src/kits/app/Roster.cpp index df8ec689d1..a268796126 100644 --- a/src/kits/app/Roster.cpp +++ b/src/kits/app/Roster.cpp @@ -2620,10 +2620,10 @@ BRoster::_InitMessenger() DBG(OUT("BRoster::InitMessengers()\n")); // find the registrar port - BMessage data; - if (BLaunchRoster().GetData("application/x-vnd.Haiku-registrar", data) - == B_OK) { +#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST + BMessage data; + if (BLaunchRoster().GetData(B_REGISTRAR_SIGNATURE, data) == B_OK) { port_id port = data.GetInt32("port", -1); team_id team = data.GetInt32("team", -1); @@ -2636,6 +2636,16 @@ BRoster::_InitMessenger() B_PREFERRED_TOKEN); } } +#else + port_id rosterPort = find_port(B_REGISTRAR_PORT_NAME); + port_info info; + if (rosterPort >= 0 && get_port_info(rosterPort, &info) == B_OK) { + DBG(OUT(" found roster port\n")); + + BMessenger::Private(fMessenger).SetTo(info.team, rosterPort, + B_PREFERRED_TOKEN); + } +#endif DBG(OUT("BRoster::InitMessengers() done\n")); } diff --git a/src/kits/interface/PictureDataWriter.cpp b/src/kits/interface/PictureDataWriter.cpp index 8dabc494fe..4d059c2f3c 100644 --- a/src/kits/interface/PictureDataWriter.cpp +++ b/src/kits/interface/PictureDataWriter.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2006-2009 Haiku, Inc. All rights reserved. + * Copyright 2006-2015 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stefano Ceccherini, stefano.ceccherini@gmail.com + * Julian Harnath, */ #include @@ -660,6 +661,21 @@ PictureDataWriter::WritePopState() } +status_t +PictureDataWriter::WriteBlendLayer(Layer* layer) +{ + try { + BeginOp(B_PIC_BLEND_LAYER); + Write(layer); + EndOp(); + } catch (status_t& status) { + return status; + } + + return B_OK; +} + + // private void PictureDataWriter::BeginOp(const int16& op) diff --git a/src/kits/interface/PicturePlayer.cpp b/src/kits/interface/PicturePlayer.cpp index 980810bd59..5ccd6acc3b 100644 --- a/src/kits/interface/PicturePlayer.cpp +++ b/src/kits/interface/PicturePlayer.cpp @@ -1213,6 +1213,16 @@ PicturePlayer::_Play(const picture_player_callbacks& callbacks, void* userData, break; } + case B_PIC_BLEND_LAYER: + { + Layer* const* layer; + if (callbacks.blend_layer == NULL || !reader.Get(layer)) + break; + + callbacks.blend_layer(userData, *layer); + break; + } + default: break; } diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index eb07f0f64b..703320cdb8 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -7,6 +7,7 @@ * Axel Dörfler, axeld@pinc-software.de * Adrian Oanca, adioanca@cotty.iren.ro * Ingo Weinhold. ingo_weinhold@gmx.de + * Julian Harnath, julian.harnath@rwth-aachen.de */ @@ -3933,6 +3934,27 @@ BView::DrawPictureAsync(const char* filename, long offset, BPoint where) } +void +BView::BeginLayer(uint8 opacity) +{ + if (_CheckOwnerLockAndSwitchCurrent()) { + fOwner->fLink->StartMessage(AS_VIEW_BEGIN_LAYER); + fOwner->fLink->Attach(opacity); + _FlushIfNotInTransaction(); + } +} + + +void +BView::EndLayer() +{ + if (_CheckOwnerLockAndSwitchCurrent()) { + fOwner->fLink->StartMessage(AS_VIEW_END_LAYER); + _FlushIfNotInTransaction(); + } +} + + void BView::Invalidate(BRect invalRect) { @@ -5225,7 +5247,7 @@ BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) if (picture == NULL) { fOwner->fLink->StartMessage(AS_VIEW_CLIP_TO_PICTURE); fOwner->fLink->Attach(-1); - + // NOTE: No need to sync here, since the -1 token cannot // become invalid on the server. } else { @@ -5240,7 +5262,7 @@ BView::_ClipToPicture(BPicture* picture, BPoint where, bool invert, bool sync) // the client creates BPictures on the stack, these BPictures may // have issued a AS_DELETE_PICTURE command to the ServerApp when Draw() // goes out of scope, and the command is processed earlier in the - // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the + // ServerApp thread than the AS_VIEW_CLIP_TO_PICTURE command in the // ServerWindow thread, which will then have the result that no // ServerPicture is found of the token. if (sync) diff --git a/src/servers/app/AppServer.cpp b/src/servers/app/AppServer.cpp index 710d61c79a..9090086e72 100644 --- a/src/servers/app/AppServer.cpp +++ b/src/servers/app/AppServer.cpp @@ -48,7 +48,8 @@ uint32 gAppServerSIMDFlags = 0; */ AppServer::AppServer(status_t* status) : - BServer("application/x-vnd.Haiku-app_server", "picasso", -1, false, status), + SERVER_BASE("application/x-vnd.Haiku-app_server", "picasso", -1, false, + status), fDesktopLock("AppServerDesktopLock") { openlog("app_server", 0, LOG_DAEMON); @@ -153,7 +154,10 @@ AppServer::QuitRequested() wait_for_thread(thread, &status); } - return BServer::QuitRequested(); + delete this; + exit(0); + + return SERVER_BASE::QuitRequested(); #else return false; #endif diff --git a/src/servers/app/AppServer.h b/src/servers/app/AppServer.h index 9320edb9d1..e25beaad58 100644 --- a/src/servers/app/AppServer.h +++ b/src/servers/app/AppServer.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -23,12 +22,21 @@ #include "ServerConfig.h" +#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST +# include +# define SERVER_BASE BServer +#else +# include "TestServerLoopAdapter.h" +# define SERVER_BASE TestServerLoopAdapter +#endif + + class ServerApp; class BitmapManager; class Desktop; -class AppServer : public BServer { +class AppServer : public SERVER_BASE { public: AppServer(status_t* status); virtual ~AppServer(); @@ -39,7 +47,7 @@ public: private: Desktop* _CreateDesktop(uid_t userID, const char* targetScreen); - Desktop* _FindDesktop(uid_t userID, + virtual Desktop* _FindDesktop(uid_t userID, const char* targetScreen); void _LaunchInputServer(); diff --git a/src/servers/app/Canvas.cpp b/src/servers/app/Canvas.cpp new file mode 100644 index 0000000000..66e28ed770 --- /dev/null +++ b/src/servers/app/Canvas.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2001-2015, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm + * Adi Oanca + * Axel Dörfler, axeld@pinc-software.de + * Stephan Aßmus + * Marcus Overhagen + * Adrien Destugues + */ + + +#include "Canvas.h" + +#include + +#include + +#include "AlphaMask.h" +#include "DrawingEngine.h" +#include "DrawState.h" +#include "Layer.h" + + +#if __GNUC__ >= 3 +# define GCC_2_NRV(x) + // GCC >= 3.1 doesn't need it anymore +#else +# define GCC_2_NRV(x) return x; + // GCC 2 named return value syntax + // see http://gcc.gnu.org/onlinedocs/gcc-2.95.2/gcc_5.html#SEC106 +#endif + + +Canvas::Canvas() + : + fDrawState(new(std::nothrow) DrawState()) +{ +} + + +Canvas::Canvas(const DrawState& state) + : + fDrawState(new(std::nothrow) DrawState(state)) +{ +} + + +Canvas::~Canvas() +{ +} + + +status_t +Canvas::InitCheck() const +{ + if (fDrawState == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +void +Canvas::PushState() +{ + DrawState* newState = fDrawState->PushState(); + if (newState) + fDrawState = newState; +} + + +void +Canvas::PopState() +{ + if (fDrawState->PreviousState() == NULL) + return; + + bool rebuildClipping = fDrawState->HasAdditionalClipping(); + + fDrawState = fDrawState->PopState(); + + // rebuild clipping + // (the clipping from the popped state is not effective anymore) + if (rebuildClipping) + RebuildClipping(false); +} + + +void +Canvas::SetDrawState(DrawState* newState) +{ + fDrawState = newState; +} + + +void +Canvas::SetDrawingOrigin(BPoint origin) +{ + fDrawState->SetOrigin(origin); + + // rebuild clipping + if (fDrawState->HasClipping()) + RebuildClipping(false); +} + + +BPoint +Canvas::DrawingOrigin() const +{ + BPoint origin(fDrawState->Origin()); + float scale = Scale(); + + origin.x *= scale; + origin.y *= scale; + + return origin; +} + + +void +Canvas::SetScale(float scale) +{ + fDrawState->SetScale(scale); + + // rebuild clipping + if (fDrawState->HasClipping()) + RebuildClipping(false); +} + + +float +Canvas::Scale() const +{ + return fDrawState->Scale(); +} + + +void +Canvas::SetUserClipping(const BRegion* region) +{ + fDrawState->SetClippingRegion(region); + + // rebuild clipping (for just this canvas) + RebuildClipping(false); +} + + +void +Canvas::SetAlphaMask(AlphaMask* mask) +{ + fDrawState->SetAlphaMask(mask); +} + + +AlphaMask* +Canvas::GetAlphaMask() const +{ + return fDrawState->GetAlphaMask(); +} + + +SimpleTransform +Canvas::LocalToScreenTransform() const GCC_2_NRV(transform) +{ +#if __GNUC__ >= 3 + SimpleTransform transform; +#endif + _LocalToScreenTransform(transform); + return transform; +} + + +SimpleTransform +Canvas::ScreenToLocalTransform() const GCC_2_NRV(transform) +{ +#if __GNUC__ >= 3 + SimpleTransform transform; +#endif + _ScreenToLocalTransform(transform); + return transform; +} + + +SimpleTransform +Canvas::PenToScreenTransform() const GCC_2_NRV(transform) +{ +#if __GNUC__ >= 3 + SimpleTransform transform; +#endif + fDrawState->Transform(transform); + _LocalToScreenTransform(transform); + return transform; +} + + +SimpleTransform +Canvas::PenToLocalTransform() const GCC_2_NRV(transform) +{ +#if __GNUC__ >= 3 + SimpleTransform transform; +#endif + fDrawState->Transform(transform); + return transform; +} + + +SimpleTransform +Canvas::ScreenToPenTransform() const GCC_2_NRV(transform) +{ +#if __GNUC__ >= 3 + SimpleTransform transform; +#endif + _ScreenToLocalTransform(transform); + fDrawState->InverseTransform(transform); + return transform; +} + + +void +Canvas::BlendLayer(Layer* layer) +{ + if (layer->Opacity() == 255) { + layer->Play(this); + layer->ReleaseReference(); + return; + } else if (layer->Opacity() == 0) { + layer->ReleaseReference(); + return; + } + + UtilityBitmap* layerBitmap = layer->RenderToBitmap(this); + if (layerBitmap == NULL) + return; + + BRect destination = layerBitmap->Bounds(); + destination.OffsetBy(layer->LeftTopOffset()); + LocalToScreenTransform().Apply(&destination); + + PushState(); + + fDrawState->SetDrawingMode(B_OP_ALPHA); + fDrawState->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + fDrawState->SetTransformEnabled(false); + + AlphaMask* mask = new UniformAlphaMask(layer->Opacity()); + if (mask == NULL) { + layerBitmap->ReleaseReference(); + return; + } + + SetAlphaMask(mask); + mask->ReleaseReference(); + ResyncDrawState(); + + GetDrawingEngine()->DrawBitmap(layerBitmap, layerBitmap->Bounds(), + destination, 0); + + fDrawState->SetTransformEnabled(true); + + PopState(); + ResyncDrawState(); + + layerBitmap->ReleaseReference(); + layer->ReleaseReference(); +} + + +// #pragma mark - OffscreenCanvas + + +OffscreenCanvas::OffscreenCanvas(DrawingEngine* engine, + const DrawState& state) + : + Canvas(state), + fDrawingEngine(engine) +{ + ResyncDrawState(); +} + + +void +OffscreenCanvas::ResyncDrawState() +{ + fDrawingEngine->SetDrawState(fDrawState); +} diff --git a/src/servers/app/Canvas.h b/src/servers/app/Canvas.h new file mode 100644 index 0000000000..aaad41b9c6 --- /dev/null +++ b/src/servers/app/Canvas.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001-2015, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm + * Adi Oanca + * Axel Dörfler, axeld@pinc-software.de + * Stephan Aßmus + * Marcus Overhagen + * Adrien Destugues + * Julian Harnath + */ +#ifndef CANVAS_H +#define CANVAS_H + + +#include + +#include "SimpleTransform.h" + + +class AlphaMask; +class BGradient; +class BRegion; +class DrawingEngine; +class DrawState; +class IntPoint; +class IntRect; +class Layer; +class ServerPicture; + + +class Canvas { +public: + Canvas(); + Canvas(const DrawState& state); + virtual ~Canvas(); + + status_t InitCheck() const; + + virtual void PushState(); + virtual void PopState(); + DrawState* CurrentState() const { return fDrawState; } + void SetDrawState(DrawState* newState); + + void SetDrawingOrigin(BPoint origin); + BPoint DrawingOrigin() const; + + void SetScale(float scale); + float Scale() const; + + void SetUserClipping(const BRegion* region); + // region is expected in view coordinates + + void SetAlphaMask(AlphaMask* mask); + AlphaMask* GetAlphaMask() const; + + SimpleTransform LocalToScreenTransform() const; + SimpleTransform ScreenToLocalTransform() const; + SimpleTransform PenToScreenTransform() const; + SimpleTransform PenToLocalTransform() const; + SimpleTransform ScreenToPenTransform() const; + + void BlendLayer(Layer* layer); + + virtual DrawingEngine* GetDrawingEngine() const = 0; + virtual ServerPicture* GetPicture(int32 token) const = 0; + virtual void RebuildClipping(bool deep) = 0; + virtual void ResyncDrawState() {}; + virtual void UpdateCurrentDrawingRegion() {}; + +protected: + virtual void _LocalToScreenTransform( + SimpleTransform& transform) const = 0; + virtual void _ScreenToLocalTransform( + SimpleTransform& transform) const = 0; + +protected: + DrawState* fDrawState; +}; + + +class OffscreenCanvas : public Canvas { +public: + OffscreenCanvas(DrawingEngine* engine, + const DrawState& state); + + virtual DrawingEngine* GetDrawingEngine() const { return fDrawingEngine; } + + virtual void RebuildClipping(bool deep) { /* TODO */ } + virtual void ResyncDrawState(); + virtual ServerPicture* GetPicture(int32 token) const + { /* TODO */ return NULL; } + +protected: + virtual void _LocalToScreenTransform(SimpleTransform&) const {} + virtual void _ScreenToLocalTransform(SimpleTransform&) const {} + +private: + DrawingEngine* fDrawingEngine; +}; + + +#endif // CANVAS_H diff --git a/src/servers/app/DrawState.cpp b/src/servers/app/DrawState.cpp index 23c358fe6e..8bae0e1ebb 100644 --- a/src/servers/app/DrawState.cpp +++ b/src/servers/app/DrawState.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -8,6 +8,7 @@ * Stephan Aßmus * Axel Dörfler, axeld@pinc-software.de * Michael Pfeiffer + * Julian Harnath */ //! Data classes for working with BView states and draw parameters @@ -46,6 +47,7 @@ DrawState::DrawState() fDrawingMode(B_OP_COPY), fAlphaSrcMode(B_PIXEL_ALPHA), fAlphaFncMode(B_ALPHA_OVERLAY), + fDrawingModeLocked(false), fPenLocation(0.0f, 0.0f), fPenSize(1.0f), @@ -80,6 +82,7 @@ DrawState::DrawState(const DrawState& other) fDrawingMode(other.fDrawingMode), fAlphaSrcMode(other.fAlphaSrcMode), fAlphaFncMode(other.fAlphaFncMode), + fDrawingModeLocked(other.fDrawingModeLocked), fPenLocation(other.fPenLocation), fPenSize(other.fPenSize), @@ -107,8 +110,6 @@ DrawState::~DrawState() { delete fClippingRegion; delete fPreviousState; - if (fAlphaMask != NULL) - fAlphaMask->ReleaseReference(); } @@ -211,7 +212,7 @@ DrawState::ReadFromLink(BPrivate::LinkReceiver& link) ViewSetStateInfo info; link.Read(&info); - + fPenLocation = info.penLocation; fPenSize = info.penSize; fHighColor = info.highColor; @@ -369,6 +370,30 @@ DrawState::SetTransform(BAffineTransform transform) } +/* Can be used to temporarily disable all BAffineTransforms in the state + stack, and later reenable them. +*/ +void +DrawState::SetTransformEnabled(bool enabled) +{ + if (enabled) { + BAffineTransform temp = fTransform; + SetTransform(BAffineTransform()); + SetTransform(temp); + } + else + fCombinedTransform = BAffineTransform(); +} + + +DrawState* +DrawState::Squash() const +{ + DrawState* const squashedState = new DrawState(*this); + return squashedState->PushState(); +} + + void DrawState::SetClippingRegion(const BRegion* region) { @@ -407,8 +432,9 @@ DrawState::GetCombinedClippingRegion(BRegion* region) const { if (fClippingRegion != NULL) { BRegion localTransformedClipping(*fClippingRegion); - Transform(&localTransformedClipping); - + SimpleTransform penTransform; + Transform(penTransform); + penTransform.Apply(&localTransformedClipping); if (fPreviousState != NULL && fPreviousState->GetCombinedClippingRegion(region)) { localTransformedClipping.IntersectWith(region); @@ -428,24 +454,14 @@ DrawState::SetAlphaMask(AlphaMask* mask) { // NOTE: In BeOS, it wasn't possible to clip to a BPicture and keep // regular custom clipping to a BRegion at the same time. - if (fAlphaMask == mask) - return; - - if (mask != NULL) - mask->AcquireReference(); - if (fAlphaMask != NULL) - fAlphaMask->ReleaseReference(); - fAlphaMask = mask; - if (fAlphaMask != NULL && fPreviousState != NULL) - fAlphaMask->SetPrevious(fPreviousState->fAlphaMask); - + fAlphaMask.SetTo(mask); } AlphaMask* DrawState::GetAlphaMask() const { - return fAlphaMask; + return fAlphaMask.Get(); } @@ -453,83 +469,19 @@ DrawState::GetAlphaMask() const void -DrawState::Transform(float* x, float* y) const +DrawState::Transform(SimpleTransform& transform) const { - // scale relative to origin, therefore - // scale first then translate to - // origin - *x *= fCombinedScale; - *y *= fCombinedScale; - *x += fCombinedOrigin.x; - *y += fCombinedOrigin.y; + transform.AddOffset(fCombinedOrigin.x, fCombinedOrigin.y); + transform.SetScale(fCombinedScale); } void -DrawState::InverseTransform(float* x, float* y) const +DrawState::InverseTransform(SimpleTransform& transform) const { - *x -= fCombinedOrigin.x; - *y -= fCombinedOrigin.y; - if (fCombinedScale != 0.0) { - *x /= fCombinedScale; - *y /= fCombinedScale; - } -} - - -void -DrawState::Transform(BPoint* point) const -{ - Transform(&(point->x), &(point->y)); -} - - -void -DrawState::Transform(BRect* rect) const -{ - Transform(&(rect->left), &(rect->top)); - Transform(&(rect->right), &(rect->bottom)); -} - - -void -DrawState::Transform(BRegion* region) const -{ - if (fCombinedScale == 1.0) { - region->OffsetBy(fCombinedOrigin.x, fCombinedOrigin.y); - } else { - // TODO: optimize some more - BRegion converted; - int32 count = region->CountRects(); - for (int32 i = 0; i < count; i++) { - BRect r = region->RectAt(i); - BPoint lt(r.LeftTop()); - BPoint rb(r.RightBottom()); - // offset to bottom right corner of pixel before transformation - rb.x++; - rb.y++; - // apply transformation - Transform(<.x, <.y); - Transform(&rb.x, &rb.y); - // reset bottom right to pixel "index" - rb.x--; - rb.y--; - // add rect to converted region - // NOTE/TODO: the rect would not have to go - // through the whole intersection test process, - // it is guaranteed not to overlap with any rect - // already contained in the region - converted.Include(BRect(lt, rb)); - } - *region = converted; - } -} - - -void -DrawState::InverseTransform(BPoint* point) const -{ - InverseTransform(&(point->x), &(point->y)); + transform.AddOffset(-fCombinedOrigin.x, -fCombinedOrigin.y); + if (fCombinedScale != 0.0) + transform.SetScale(1.0 / fCombinedScale); } @@ -557,21 +509,37 @@ DrawState::SetPattern(const Pattern& pattern) } -void +bool DrawState::SetDrawingMode(drawing_mode mode) { - fDrawingMode = mode; + if (!fDrawingModeLocked) { + fDrawingMode = mode; + return true; + } + return false; +} + + +bool +DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode) +{ + if (!fDrawingModeLocked) { + fAlphaSrcMode = srcMode; + fAlphaFncMode = fncMode; + return true; + } + return false; } void -DrawState::SetBlendingMode(source_alpha srcMode, alpha_function fncMode) +DrawState::SetDrawingModeLocked(bool locked) { - fAlphaSrcMode = srcMode; - fAlphaFncMode = fncMode; + fDrawingModeLocked = locked; } + void DrawState::SetPenLocation(BPoint location) { diff --git a/src/servers/app/DrawState.h b/src/servers/app/DrawState.h index 48508ed6cf..3572874b7a 100644 --- a/src/servers/app/DrawState.h +++ b/src/servers/app/DrawState.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -7,6 +7,7 @@ * Adi Oanca * Stephan Aßmus * Axel Dörfler, axeld@pinc-software.de + * Julian Harnath */ #ifndef _DRAW_STATE_H_ #define _DRAW_STATE_H_ @@ -16,10 +17,12 @@ #include #include #include +#include #include #include "ServerFont.h" #include "PatternHandler.h" +#include "SimpleTransform.h" class AlphaMask; class BRegion; @@ -66,6 +69,9 @@ public: { return fTransform; } BAffineTransform CombinedTransform() const { return fCombinedTransform; } + void SetTransformEnabled(bool enabled); + + DrawState* Squash() const; // additional clipping as requested by client void SetClippingRegion(const BRegion* region); @@ -78,14 +84,8 @@ public: AlphaMask* GetAlphaMask() const; // coordinate transformations - void Transform(float* x, float* y) const; - void InverseTransform(float* x, float* y) const; - - void Transform(BPoint* point) const; - void Transform(BRect* rect) const; - void Transform(BRegion* region) const; - - void InverseTransform(BPoint* point) const; + void Transform(SimpleTransform& transform) const; + void InverseTransform(SimpleTransform& transform) const; // color void SetHighColor(rgb_color color); @@ -101,17 +101,19 @@ public: { return fPattern; } // drawing/blending mode - void SetDrawingMode(drawing_mode mode); + bool SetDrawingMode(drawing_mode mode); drawing_mode GetDrawingMode() const { return fDrawingMode; } - void SetBlendingMode(source_alpha srcMode, + bool SetBlendingMode(source_alpha srcMode, alpha_function fncMode); source_alpha AlphaSrcMode() const { return fAlphaSrcMode; } alpha_function AlphaFncMode() const { return fAlphaFncMode; } + void SetDrawingModeLocked(bool locked); + // pen void SetPenLocation(BPoint location); BPoint PenLocation() const; @@ -165,7 +167,7 @@ protected: BRegion* fClippingRegion; - AlphaMask* fAlphaMask; + BReference fAlphaMask; rgb_color fHighColor; rgb_color fLowColor; @@ -174,6 +176,7 @@ protected: drawing_mode fDrawingMode; source_alpha fAlphaSrcMode; alpha_function fAlphaFncMode; + bool fDrawingModeLocked; BPoint fPenLocation; float fPenSize; diff --git a/src/servers/app/DrawingContext.cpp b/src/servers/app/DrawingContext.cpp deleted file mode 100644 index 8a61f9b00a..0000000000 --- a/src/servers/app/DrawingContext.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c) 2001-2014, Haiku, Inc. - * Distributed under the terms of the MIT license. - * - * Authors: - * DarkWyrm - * Adi Oanca - * Axel Dörfler, axeld@pinc-software.de - * Stephan Aßmus - * Marcus Overhagen - * Adrien Destugues - -#include -#include -#include -#include -#include -#include - -#include "DrawingEngine.h" -#include "DrawState.h" - - -DrawingContext::DrawingContext() - : - fDrawState(new(std::nothrow) DrawState()) -{ -} - - -DrawingContext::DrawingContext(const DrawState& state) - : - fDrawState(new(std::nothrow) DrawState(state)) -{ -} - - -DrawingContext::~DrawingContext() -{ -} - - -status_t -DrawingContext::InitCheck() const -{ - if (fDrawState == NULL) - return B_NO_MEMORY; - - return B_OK; -} - - -void -DrawingContext::PushState() -{ - DrawState* newState = fDrawState->PushState(); - if (newState) - fDrawState = newState; -} - - -void -DrawingContext::PopState() -{ - if (fDrawState->PreviousState() == NULL) - return; - - bool rebuildClipping = fDrawState->HasAdditionalClipping(); - - fDrawState = fDrawState->PopState(); - - // rebuild clipping - // (the clipping from the popped state is not effective anymore) - if (rebuildClipping) - RebuildClipping(false); -} - - -void -DrawingContext::SetDrawingOrigin(BPoint origin) -{ - fDrawState->SetOrigin(origin); - - // rebuild clipping - if (fDrawState->HasClipping()) - RebuildClipping(false); -} - - -BPoint -DrawingContext::DrawingOrigin() const -{ - BPoint origin(fDrawState->Origin()); - float scale = Scale(); - - origin.x *= scale; - origin.y *= scale; - - return origin; -} - - -void -DrawingContext::SetScale(float scale) -{ - fDrawState->SetScale(scale); - - // rebuild clipping - if (fDrawState->HasClipping()) - RebuildClipping(false); -} - - -float -DrawingContext::Scale() const -{ - return fDrawState->Scale(); -} - - -void -DrawingContext::SetUserClipping(const BRegion* region) -{ - fDrawState->SetClippingRegion(region); - - // rebuild clipping (for just this context) - RebuildClipping(false); -} - - -void -DrawingContext::SetAlphaMask(AlphaMask* mask) -{ - fDrawState->SetAlphaMask(mask); -} - - -AlphaMask* -DrawingContext::GetAlphaMask() const -{ - return fDrawState->GetAlphaMask(); -} - - -//! converts a point from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BPoint* point) const -{ - fDrawState->Transform(point); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(point); -} - - -//! converts a rect from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BRect* rect) const -{ - fDrawState->Transform(rect); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(rect); -} - - -//! converts a region from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BRegion* region) const -{ - fDrawState->Transform(region); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(region); -} - - -//! converts a gradient from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BGradient* gradient) const -{ - switch (gradient->GetType()) { - case BGradient::TYPE_LINEAR: - { - BGradientLinear* linear = (BGradientLinear*) gradient; - BPoint start = linear->Start(); - BPoint end = linear->End(); - fDrawState->Transform(&start); - ConvertToScreen(&start); - fDrawState->Transform(&end); - ConvertToScreen(&end); - linear->SetStart(start); - linear->SetEnd(end); - break; - } - case BGradient::TYPE_RADIAL: - { - BGradientRadial* radial = (BGradientRadial*) gradient; - BPoint center = radial->Center(); - fDrawState->Transform(¢er); - ConvertToScreen(¢er); - radial->SetCenter(center); - break; - } - case BGradient::TYPE_RADIAL_FOCUS: - { - BGradientRadialFocus* radialFocus = (BGradientRadialFocus*) gradient; - BPoint center = radialFocus->Center(); - BPoint focal = radialFocus->Focal(); - fDrawState->Transform(¢er); - ConvertToScreen(¢er); - fDrawState->Transform(&focal); - ConvertToScreen(&focal); - radialFocus->SetCenter(center); - radialFocus->SetFocal(focal); - break; - } - case BGradient::TYPE_DIAMOND: - { - BGradientDiamond* diamond = (BGradientDiamond*) gradient; - BPoint center = diamond->Center(); - fDrawState->Transform(¢er); - ConvertToScreen(¢er); - diamond->SetCenter(center); - break; - } - case BGradient::TYPE_CONIC: - { - BGradientConic* conic = (BGradientConic*) gradient; - BPoint center = conic->Center(); - fDrawState->Transform(¢er); - ConvertToScreen(¢er); - conic->SetCenter(center); - break; - } - case BGradient::TYPE_NONE: - { - break; - } - } - - // Make sure the gradient is fully padded so that out of bounds access - // get the correct colors - gradient->SortColorStopsByOffset(); - - BGradient::ColorStop* end = gradient->ColorStopAtFast( - gradient->CountColorStops() - 1); - - if (end->offset != 255) - gradient->AddColor(end->color, 255); - - BGradient::ColorStop* start = gradient->ColorStopAtFast(0); - - if (start->offset != 0) - gradient->AddColor(start->color, 0); - - gradient->SortColorStopsByOffset(); -} - - -//! converts points from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BPoint* dst, const BPoint* src, int32 num) const -{ - // TODO: optimize this, it should be smarter - while (num--) { - *dst = *src; - fDrawState->Transform(dst); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(dst); - src++; - dst++; - } -} - - -//! converts rects from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BRect* dst, const BRect* src, int32 num) const -{ - // TODO: optimize this, it should be smarter - while (num--) { - *dst = *src; - fDrawState->Transform(dst); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(dst); - src++; - dst++; - } -} - - -//! converts regions from local *drawing* to screen coordinate system -void -DrawingContext::ConvertToScreenForDrawing(BRegion* dst, const BRegion* src, int32 num) const -{ - // TODO: optimize this, it should be smarter - while (num--) { - *dst = *src; - fDrawState->Transform(dst); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(dst); - src++; - dst++; - } -} - - -//! converts a point from screen to local coordinate system -void -DrawingContext::ConvertFromScreenForDrawing(BPoint* point) const -{ - ConvertFromScreen(point); - fDrawState->InverseTransform(point); -} - - -// #pragma mark - OffscreenContext - - -OffscreenContext::OffscreenContext(DrawingEngine* engine, - const DrawState& state) - : - DrawingContext(state), - fDrawingEngine(engine) -{ - ResyncDrawState(); -} - - -void -OffscreenContext::ResyncDrawState() -{ - fDrawingEngine->SetDrawState(fDrawState); -} - diff --git a/src/servers/app/DrawingContext.h b/src/servers/app/DrawingContext.h deleted file mode 100644 index 621ed0a920..0000000000 --- a/src/servers/app/DrawingContext.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2001-2014, Haiku, Inc. - * Distributed under the terms of the MIT license. - * - * Authors: - * DarkWyrm - * Adi Oanca - * Axel Dörfler, axeld@pinc-software.de - * Stephan Aßmus - * Marcus Overhagen - * Adrien Destugues - */ -#ifndef DRAWING_CONTEXT_H -#define DRAWING_CONTEXT_H - - -#include - - -class AlphaMask; -class BGradient; -class BRegion; -class DrawingEngine; -class DrawState; -class IntPoint; -class IntRect; -class ServerPicture; - - -class DrawingContext { -public: - DrawingContext(); - DrawingContext(const DrawState& state); - virtual ~DrawingContext(); - - status_t InitCheck() const; - - virtual void PushState(); - virtual void PopState(); - DrawState* CurrentState() const { return fDrawState; } - - void SetDrawingOrigin(BPoint origin); - BPoint DrawingOrigin() const; - - void SetScale(float scale); - float Scale() const; - - void SetUserClipping(const BRegion* region); - // region is expected in view coordinates - - void SetAlphaMask(AlphaMask* mask); - AlphaMask* GetAlphaMask() const; - - void ConvertToScreenForDrawing(BPoint* point) const; - void ConvertToScreenForDrawing(BRect* rect) const; - void ConvertToScreenForDrawing(BRegion* region) const; - void ConvertToScreenForDrawing(BGradient* gradient) const; - - void ConvertToScreenForDrawing(BPoint* dst, const BPoint* src, int32 num) const; - void ConvertToScreenForDrawing(BRect* dst, const BRect* src, int32 num) const; - void ConvertToScreenForDrawing(BRegion* dst, const BRegion* src, int32 num) const; - - void ConvertFromScreenForDrawing(BPoint* point) const; - // used when updating the pen position - - virtual void ConvertToScreen(BPoint* point) const = 0; - virtual void ConvertToScreen(IntPoint* point) const = 0; - virtual void ConvertToScreen(BRect* rect) const = 0; - virtual void ConvertToScreen(IntRect* rect) const = 0; - virtual void ConvertToScreen(BRegion* region) const = 0; - - virtual void ConvertFromScreen(BPoint* point) const = 0; - - virtual DrawingEngine* GetDrawingEngine() const = 0; - virtual ServerPicture* GetPicture(int32 token) const = 0; - virtual void RebuildClipping(bool deep) = 0; - virtual void ResyncDrawState() {}; - virtual void UpdateCurrentDrawingRegion() {}; - -protected: - DrawState* fDrawState; -}; - - -class OffscreenContext: public DrawingContext { -public: - OffscreenContext(DrawingEngine* engine, - const DrawState& state); - - // Screen and View coordinates are the same for us. - // DrawState already takes care of World<>View - // conversions. - virtual void ConvertToScreen(BPoint*) const {} - virtual void ConvertToScreen(IntPoint*) const {} - virtual void ConvertToScreen(BRect*) const {} - virtual void ConvertToScreen(IntRect*) const {} - virtual void ConvertToScreen(BRegion*) const {} - virtual void ConvertFromScreen(BPoint*) const {} - - virtual DrawingEngine* GetDrawingEngine() const { return fDrawingEngine; } - - virtual void RebuildClipping(bool deep) { /* TODO */ } - virtual void ResyncDrawState(); - virtual ServerPicture* GetPicture(int32 token) const - { /* TODO */ return NULL; } -private: - DrawingEngine* fDrawingEngine; -}; - - -#endif diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index 024088b061..7c96133439 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -32,10 +32,10 @@ local font_src = ; UseBuildFeatureHeaders freetype ; -Includes [ FGristFiles AppServer.cpp BitmapManager.cpp +Includes [ FGristFiles AppServer.cpp BitmapManager.cpp Canvas.cpp ClientMemoryAllocator.cpp Desktop.cpp DesktopSettings.cpp - DrawState.cpp DrawingContext.cpp DrawingEngine.cpp ServerApp.cpp - ServerBitmap.cpp ServerCursor.cpp ServerFont.cpp ServerPicture.cpp + DrawState.cpp DrawingEngine.cpp ServerApp.cpp + ServerBitmap.cpp ServerCursor.cpp ServerFont.cpp ServerPicture.cpp ServerWindow.cpp View.cpp Window.cpp WorkspacesView.cpp $(decorator_src) $(font_src) ] : [ BuildFeatureAttribute freetype : headers ] ; @@ -51,6 +51,7 @@ Server app_server : AppServer.cpp #BitfieldRegion.cpp BitmapManager.cpp + Canvas.cpp ClientMemoryAllocator.cpp CursorData.cpp CursorManager.cpp @@ -59,7 +60,6 @@ Server app_server : DesktopListener.cpp DesktopSettings.cpp DirectWindowInfo.cpp - DrawingContext.cpp DrawState.cpp EventDispatcher.cpp EventStream.cpp @@ -67,10 +67,12 @@ Server app_server : InputManager.cpp IntPoint.cpp IntRect.cpp + Layer.cpp MessageLooper.cpp MultiLocker.cpp OffscreenServerWindow.cpp OffscreenWindow.cpp + PictureBoundingBoxPlayer.cpp ProfileMessageSupport.cpp RGBColor.cpp RegionPool.cpp @@ -97,7 +99,7 @@ Server app_server : # libraries : libtranslation.so libbe.so libbnetapi.so - libaslocal.a $(BROKEN_64)libasremote.a $(BROKEN_64)libashtml5.a + libaslocal.a $(BROKEN_64)libasremote.a $(BROKEN_64)libashtml5.a libasdrawing.a libpainter.a libagg.a [ BuildFeatureAttribute freetype : library ] libstackandtile.a liblinprog.a libtextencoding.so libshared.a diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp new file mode 100644 index 0000000000..96bf38eafd --- /dev/null +++ b/src/servers/app/Layer.cpp @@ -0,0 +1,216 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ +#include "Layer.h" + +#include "AlphaMask.h" +#include "BitmapHWInterface.h" +#include "DrawingEngine.h" +#include "DrawState.h" +#include "IntRect.h" +#include "PictureBoundingBoxPlayer.h" +#include "ServerBitmap.h" +#include "View.h" + + +class LayerCanvas : public Canvas { +public: + LayerCanvas(DrawingEngine* drawingEngine, DrawState* drawState) + : + Canvas(), + fDrawingEngine(drawingEngine) + { + delete fDrawState; + fDrawState = drawState; + } + + virtual DrawingEngine* GetDrawingEngine() const + { + return fDrawingEngine; + } + + virtual ServerPicture* GetPicture(int32 token) const + { + return NULL; + } + + virtual void RebuildClipping(bool) + { + } + + virtual void ResyncDrawState() + { + fDrawingEngine->SetDrawState(fDrawState); + } + +protected: + virtual void _LocalToScreenTransform(SimpleTransform&) const + { + } + + virtual void _ScreenToLocalTransform(SimpleTransform&) const + { + } + +private: + DrawingEngine* fDrawingEngine; +}; + + +Layer::Layer(uint8 opacity) + : + fOpacity(opacity), + fLeftTopOffset(0, 0) +{ +} + + +Layer::~Layer() +{ +} + + +void +Layer::PushLayer(Layer* layer) +{ + PushPicture(layer); +} + + +Layer* +Layer::PopLayer() +{ + Layer* const previousLayer = static_cast(PopPicture()); + if (previousLayer != NULL) + previousLayer->ReleaseReference(); + return previousLayer; +} + + +UtilityBitmap* +Layer::RenderToBitmap(Canvas* canvas) +{ + BRect boundingBox = _DetermineBoundingBox(canvas); + if (!boundingBox.IsValid()) + return NULL; + + fLeftTopOffset = boundingBox.LeftTop(); + + UtilityBitmap* const layerBitmap = _AllocateBitmap(boundingBox); + if (layerBitmap == NULL) + return NULL; + + BitmapHWInterface layerInterface(layerBitmap); + DrawingEngine* const layerEngine = layerInterface.CreateDrawingEngine(); + if (layerEngine == NULL) { + layerBitmap->ReleaseReference(); + return NULL; + } + layerEngine->SetRendererOffset(boundingBox.left, boundingBox.top); + // Drawing commands of the layer's picture use coordinates in the + // coordinate space of the underlying canvas. The coordinate origin + // of the layer bitmap is at boundingBox.LeftTop(). So all the drawing + // from the picture needs to be offset to be moved into the bitmap. + // We use a low-level offsetting via the AGG renderer here because the + // offset needs to be processed independently, after all other + // transforms, even after the BAffineTransforms (which are processed in + // Painter), to prevent this origin from being further transformed by + // e.g. scaling. + + LayerCanvas layerCanvas(layerEngine, canvas->CurrentState()); + + AlphaMask* const mask = layerCanvas.GetAlphaMask(); + IntPoint oldOffset; + if (mask != NULL) { + // Move alpha mask to bitmap origin + oldOffset = mask->SetViewOrigin(IntPoint(0, 0)); + } + + canvas->CurrentState()->SetDrawingMode(B_OP_ALPHA); + canvas->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + + layerCanvas.ResyncDrawState(); + // Apply state to the new drawing engine of the layer canvas + + if (layerEngine->LockParallelAccess()) { + const BRegion region(boundingBox); + layerEngine->ConstrainClippingRegion(®ion); + + // Draw recorded picture into bitmap + Play(&layerCanvas); + layerEngine->UnlockParallelAccess(); + } + + if (mask != NULL) { + // Move alpha mask back to its old position + // Note: this needs to be adapted if setting alpha masks is + // implemented as BPicture command (the mask now might be a different + // one than before). + mask->SetViewOrigin(oldOffset); + layerCanvas.ResyncDrawState(); + } + + canvas->SetDrawState(layerCanvas.CurrentState()); + // Update state in canvas (the top-of-stack state could be a different + // state instance now, if the picture commands contained push/pop + // commands) + + delete layerEngine; + + return layerBitmap; +} + + +IntPoint +Layer::LeftTopOffset() const +{ + return fLeftTopOffset; +} + + +uint8 +Layer::Opacity() const +{ + return fOpacity; +} + + +BRect +Layer::_DetermineBoundingBox(Canvas* canvas) +{ + BRect boundingBox; + PictureBoundingBoxPlayer::Play(this, canvas->CurrentState(), &boundingBox); + + if (!boundingBox.IsValid()) + return boundingBox; + + // Round up and add an additional 2 pixels on the bottom/right to + // compensate for the various types of rounding used in Painter. + boundingBox.left = floorf(boundingBox.left); + boundingBox.right = ceilf(boundingBox.right) + 2; + boundingBox.top = floorf(boundingBox.top); + boundingBox.bottom = ceilf(boundingBox.bottom) + 2; + + // TODO: for optimization, crop the bounding box to the underlying + // view bounds here + + return boundingBox; +} + + +UtilityBitmap* +Layer::_AllocateBitmap(const BRect& bounds) +{ + UtilityBitmap* const layerBitmap = new(std::nothrow) UtilityBitmap(bounds, + B_RGBA32, 0); + if (layerBitmap == NULL) + return NULL; + if (!layerBitmap->IsValid()) { + delete layerBitmap; + return NULL; + } + memset(layerBitmap->Bits(), 0, layerBitmap->BitsLength()); + + return layerBitmap; +} diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h new file mode 100644 index 0000000000..7a9f969cd4 --- /dev/null +++ b/src/servers/app/Layer.h @@ -0,0 +1,42 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef LAYER_H +#define LAYER_H + + +#include "ServerPicture.h" + +#include "IntPoint.h" + + +class AlphaMask; +class Canvas; +class UtilityBitmap; + + +class Layer : public ServerPicture { +public: + Layer(uint8 opacity); + virtual ~Layer(); + + void PushLayer(Layer* layer); + Layer* PopLayer(); + + UtilityBitmap* RenderToBitmap(Canvas* canvas); + + IntPoint LeftTopOffset() const; + uint8 Opacity() const; + +private: + BRect _DetermineBoundingBox(Canvas* canvas); + UtilityBitmap* _AllocateBitmap(const BRect& bounds); + +private: + uint8 fOpacity; + IntPoint fLeftTopOffset; +}; + + +#endif // LAYER_H diff --git a/src/servers/app/MessageLooper.cpp b/src/servers/app/MessageLooper.cpp index e801712eed..2828b8ef4d 100644 --- a/src/servers/app/MessageLooper.cpp +++ b/src/servers/app/MessageLooper.cpp @@ -154,9 +154,9 @@ MessageLooper::_MessageLooper() Lock(); - if (code == kMsgQuitLooper) { + if (code == kMsgQuitLooper) Quit(); - } else + else _DispatchMessage(code, receiver); Unlock(); diff --git a/src/servers/app/PictureBoundingBoxPlayer.cpp b/src/servers/app/PictureBoundingBoxPlayer.cpp new file mode 100644 index 0000000000..e4382b7a16 --- /dev/null +++ b/src/servers/app/PictureBoundingBoxPlayer.cpp @@ -0,0 +1,816 @@ +/* + * Copyright 2001-2015, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Marc Flerackers (mflerackers@androme.be) + * Stefano Ceccherini (stefano.ceccherini@gmail.com) + * Marcus Overhagen + * Julian Harnath + */ + +#include "PictureBoundingBoxPlayer.h" + +#include +#include + +#include "DrawState.h" +#include "FontManager.h" +#include "Layer.h" +#include "ServerApp.h" +#include "ServerBitmap.h" +#include "ServerFont.h" +#include "ServerPicture.h" +#include "ServerTokenSpace.h" +#include "View.h" +#include "Window.h" + +#include +#include +#include +#include +#include +#include +#include + + +//#define DEBUG_TRACE_BB +#ifdef DEBUG_TRACE_BB +# define TRACE_BB(text, ...) debug_printf("PBBP: " text, ##__VA_ARGS__) +#else +# define TRACE_BB(text, ...) +#endif + + +typedef PictureBoundingBoxPlayer::State BoundingBoxState; + + +// #pragma mark - PictureBoundingBoxPlayer::State + + +class PictureBoundingBoxPlayer::State { +public: + State(const DrawState* drawState, BRect* boundingBox) + : + fDrawState(drawState->Squash()), + fBoundingBox(boundingBox) + { + fBoundingBox->Set(INT_MAX, INT_MAX, INT_MIN, INT_MIN); + } + + ~State() + { + delete fDrawState; + } + + DrawState* GetDrawState() + { + return fDrawState; + } + + void PushDrawState() + { + DrawState* nextState = fDrawState->PushState(); + if (nextState != NULL) + fDrawState = nextState; + } + + void PopDrawState() + { + if (fDrawState->PreviousState() != NULL) + fDrawState = fDrawState->PopState(); + } + + SimpleTransform PenToLocalTransform() const + { + SimpleTransform transform; + fDrawState->Transform(transform); + return transform; + } + + void IncludeRect(BRect& rect) + { + _AffineTransformRect(rect); + *fBoundingBox = (*fBoundingBox) | rect; + } + +private: + void _AffineTransformRect(BRect& rect) + { + BAffineTransform transform = fDrawState->CombinedTransform(); + if (transform.IsIdentity()) + return; + + BPoint transformedShape[4]; + transformedShape[0] = rect.LeftTop(); + transformedShape[1] = rect.LeftBottom(); + transformedShape[2] = rect.RightTop(); + transformedShape[3] = rect.RightBottom(); + + transform.Apply(&transformedShape[0], 4); + + float minX = INT_MAX; + float minY = INT_MAX; + float maxX = INT_MIN; + float maxY = INT_MIN; + + for (uint32 i = 0; i < 4; i++) { + if (transformedShape[i].x < minX) + minX = transformedShape[i].x; + else if (transformedShape[i].x > maxX) + maxX = transformedShape[i].x; + if (transformedShape[i].y < minY) + minY = transformedShape[i].y; + else if (transformedShape[i].y > maxY) + maxY = transformedShape[i].y; + } + + rect.Set(minX, minY, maxX, maxY); + } + + +private: + DrawState* fDrawState; + BRect* fBoundingBox; +}; + + +// #pragma mark - Picture playback hooks + + +static void +get_polygon_frame(const BPoint* points, int32 numPoints, BRect* frame) +{ + ASSERT(numPoints > 0); + + float left = points->x; + float top = points->y; + float right = left; + float bottom = top; + + points++; + numPoints--; + + while (numPoints--) { + if (points->x < left) + left = points->x; + if (points->x > right) + right = points->x; + if (points->y < top) + top = points->y; + if (points->y > bottom) + bottom = points->y; + points++; + } + + frame->Set(left, top, right, bottom); +} + + +template +static void +expand_rect_for_pen_size(BoundingBoxState* state, RectType& rect) +{ + float penInset = -((state->GetDrawState()->PenSize() / 2.0f) + 1.0f); + rect.InsetBy(penInset, penInset); +} + + +static void +move_pen_by(void* _state, const BPoint& delta) +{ + TRACE_BB("%p move pen by %.2f %.2f\n", _state, delta.x, delta.y); + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->GetDrawState()->SetPenLocation( + state->GetDrawState()->PenLocation() + delta); +} + + +static void +determine_bounds_stroke_line(void* _state, const BPoint& _start, + const BPoint& _end) +{ + TRACE_BB("%p stroke line %.2f %.2f -> %.2f %.2f\n", _state, + _start.x, _start.y, _end.x, _end.y); + BoundingBoxState* const state = + reinterpret_cast(_state); + + BPoint start = _start; + BPoint end = _end; + + const SimpleTransform transform = state->PenToLocalTransform(); + transform.Apply(&start); + transform.Apply(&end); + + BRect rect; + if (start.x <= end.x) { + rect.left = start.x; + rect.right = end.x; + } else { + rect.left = end.x; + rect.right = start.x; + } + if (start.y <= end.y) { + rect.top = start.y; + rect.bottom = end.y; + } else { + rect.top = end.y; + rect.bottom = start.y; + } + + expand_rect_for_pen_size(state, rect); + state->IncludeRect(rect); + + state->GetDrawState()->SetPenLocation(_end); +} + + +static void +determine_bounds_draw_rect(void* _state, const BRect& _rect, bool fill) +{ + TRACE_BB("%p draw rect fill=%d %.2f %.2f %.2f %.2f\n", _state, fill, + _rect.left, _rect.top, _rect.right, _rect.bottom); + BoundingBoxState* const state = + reinterpret_cast(_state); + + BRect rect = _rect; + state->PenToLocalTransform().Apply(&rect); + if (!fill) + expand_rect_for_pen_size(state, rect); + state->IncludeRect(rect); +} + + +static void +determine_bounds_draw_round_rect(void* _state, const BRect& _rect, + const BPoint&, bool fill) +{ + determine_bounds_draw_rect(_state, _rect, fill); +} + + +static void +determine_bounds_bezier(BoundingBoxState* state, const BPoint* viewPoints, + BRect& outRect) +{ + // Note: this is an approximation which results in a rectangle which + // encloses all four control points. That will always enclose the curve, + // although not necessarily tightly, but it's good enough for the purpose. + // The exact bounding box of a bezier curve is not trivial to determine, + // (need to calculate derivative of the curve) and we're going for + // performance here. + BPoint points[4]; + state->PenToLocalTransform().Apply(points, viewPoints, 4); + BPoint topLeft = points[0]; + BPoint bottomRight = points[0]; + for (uint32 index = 1; index < 4; index++) { + if (points[index].x < topLeft.x || points[index].y < topLeft.y) + topLeft = points[index]; + if (points[index].x > topLeft.x || points[index].y > topLeft.y) + bottomRight = points[index]; + } + outRect.SetLeftTop(topLeft); + outRect.SetRightBottom(bottomRight); +} + + +static void +determine_bounds_draw_bezier(void* _state, size_t numPoints, + const BPoint viewPoints[], bool fill) +{ + TRACE_BB("%p draw bezier fill=%d (%.2f %.2f) (%.2f %.2f) " + "(%.2f %.2f) (%.2f %.2f)\n", + _state, + fill, + viewPoints[0].x, viewPoints[0].y, + viewPoints[1].x, viewPoints[1].y, + viewPoints[2].x, viewPoints[2].y, + viewPoints[3].x, viewPoints[3].y); + BoundingBoxState* const state = + reinterpret_cast(_state); + + const size_t kSupportedPoints = 4; + if (numPoints != kSupportedPoints) + return; + + BRect rect; + determine_bounds_bezier(state, viewPoints, rect); + if (!fill) + expand_rect_for_pen_size(state, rect); + state->IncludeRect(rect); +} + + +static void +determine_bounds_draw_ellipse(void* _state, const BRect& _rect, bool fill) +{ + TRACE_BB("%p draw ellipse fill=%d (%.2f %.2f) (%.2f %.2f)\n", _state, fill, + _rect.left, _rect.top, _rect.right, _rect.bottom); + BoundingBoxState* const state = + reinterpret_cast(_state); + + BRect rect = _rect; + state->PenToLocalTransform().Apply(&rect); + if (!fill) + expand_rect_for_pen_size(state, rect); + state->IncludeRect(rect); +} + + +static void +determine_bounds_draw_arc(void* _state, const BPoint& center, + const BPoint& radii, float, float, bool fill) +{ + BRect rect(center.x - radii.x, center.y - radii.y, + center.x + radii.x - 1, center.y + radii.y - 1); + determine_bounds_draw_ellipse(_state, rect, fill); +} + + +static void +determine_bounds_polygon(BoundingBoxState* state, int32 numPoints, + const BPoint* viewPoints, BRect& outRect) +{ + if (numPoints <= 0) + return; + + if (numPoints <= 200) { + // fast path: no malloc/free, also avoid + // constructor/destructor calls + char data[200 * sizeof(BPoint)]; + BPoint* points = (BPoint*)data; + + state->PenToLocalTransform().Apply(points, viewPoints, numPoints); + get_polygon_frame(points, numPoints, &outRect); + + } else { + // avoid constructor/destructor calls by + // using malloc instead of new [] + BPoint* points = (BPoint*)malloc(numPoints * sizeof(BPoint)); + if (points == NULL) + return; + + state->PenToLocalTransform().Apply(points, viewPoints, numPoints); + get_polygon_frame(points, numPoints, &outRect); + + free(points); + } +} + + +void +determine_bounds_draw_polygon(void* _state, size_t numPoints, + const BPoint viewPoints[], bool, bool fill) +{ + TRACE_BB("%p draw polygon fill=%d (%ld points)\n", _state, fill, numPoints); + BoundingBoxState* const state = + reinterpret_cast(_state); + + BRect rect; + determine_bounds_polygon(state, numPoints, viewPoints, rect); + if (!fill) + expand_rect_for_pen_size(state, rect); + state->IncludeRect(rect); +} + + +static void +determine_bounds_draw_shape(void* _state, const BShape& shape, bool fill) +{ + BRect rect = shape.Bounds(); + + TRACE_BB("%p stroke shape (bounds %.2f %.2f %.2f %.2f)\n", _state, + rect.left, rect.top, rect.right, rect.bottom); + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->PenToLocalTransform().Apply(&rect); + if (!fill) + expand_rect_for_pen_size(state, rect); + state->IncludeRect(rect); +} + + +static void +determine_bounds_draw_string(void* _state, const char* string, size_t _length, + float deltaSpace, float deltaNonSpace) +{ + TRACE_BB("%p string '%s'\n", _state, string); + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font = state->GetDrawState()->Font(); + + escapement_delta delta = { deltaSpace, deltaNonSpace }; + BRect rect; + int32 length = _length; + font.GetBoundingBoxesForStrings((char**)&string, &length, 1, &rect, + B_SCREEN_METRIC, &delta); + + BPoint location = state->GetDrawState()->PenLocation(); + + state->PenToLocalTransform().Apply(&location); + rect.OffsetBy(location); + state->IncludeRect(rect); + + state->PenToLocalTransform().Apply(&location); + state->GetDrawState()->SetPenLocation(location); +} + + +static void +determine_bounds_draw_pixels(void* _state, const BRect&, const BRect& _dest, + uint32, uint32, size_t, color_space, uint32, const void*, size_t) +{ + TRACE_BB("%p pixels (dest %.2f %.2f %.2f %.2f)\n", _state, + _dest.left, _dest.top, _dest.right, _dest.bottom); + BoundingBoxState* const state = + reinterpret_cast(_state); + + BRect dest = _dest; + state->PenToLocalTransform().Apply(&dest); + state->IncludeRect(dest); +} + + +static void +draw_picture(void* _state, const BPoint& where, int32 token) +{ + TRACE_BB("%p picture (unimplemented)\n", _state); + + // TODO + (void)_state; + (void)where; + (void)token; +} + + +static void +set_clipping_rects(void* _state, size_t numRects, const BRect rects[]) +{ + TRACE_BB("%p cliping rects (%ld rects)\n", _state, numRects); + + // TODO + (void)_state; + (void)rects; + (void)numRects; +} + + +static void +clip_to_picture(void* _state, int32 pictureToken, const BPoint& where, + bool clipToInverse) +{ + TRACE_BB("%p clip to picture (unimplemented)\n", _state); + + // TODO +} + + +static void +push_state(void* _state) +{ + TRACE_BB("%p push state\n", _state); + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->PushDrawState(); +} + + +static void +pop_state(void* _state) +{ + TRACE_BB("%p pop state\n", _state); + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->PopDrawState(); +} + + +static void +enter_state_change(void*) +{ +} + + +static void +exit_state_change(void*) +{ +} + + +static void +enter_font_state(void*) +{ +} + + +static void +exit_font_state(void*) +{ +} + + +static void +set_origin(void* _state, const BPoint& pt) +{ + TRACE_BB("%p set origin %.2f %.2f\n", _state, pt.x, pt.y); + BoundingBoxState* const state = + reinterpret_cast(_state); + state->GetDrawState()->SetOrigin(pt); +} + + +static void +set_pen_location(void* _state, const BPoint& pt) +{ + TRACE_BB("%p set pen location %.2f %.2f\n", _state, pt.x, pt.y); + BoundingBoxState* const state = + reinterpret_cast(_state); + state->GetDrawState()->SetPenLocation(pt); +} + + +static void +set_drawing_mode(void*, drawing_mode) +{ +} + + +static void +set_line_mode(void* _state, cap_mode capMode, join_mode joinMode, + float miterLimit) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + DrawState* drawState = state->GetDrawState(); + drawState->SetLineCapMode(capMode); + drawState->SetLineJoinMode(joinMode); + drawState->SetMiterLimit(miterLimit); +} + + +static void +set_pen_size(void* _state, float size) +{ + TRACE_BB("%p set pen size %.2f\n", _state, size); + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->GetDrawState()->SetPenSize(size); +} + + +static void +set_fore_color(void* _state, const rgb_color& color) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->GetDrawState()->SetHighColor(color); +} + + +static void +set_back_color(void* _state, const rgb_color& color) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->GetDrawState()->SetLowColor(color); +} + + +static void +set_stipple_pattern(void* _state, const pattern& _pattern) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->GetDrawState()->SetPattern(Pattern(_pattern)); +} + + +static void +set_scale(void* _state, float scale) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + state->GetDrawState()->SetScale(scale); +} + + +static void +set_font_family(void* _state, const char* _family, size_t length) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + BString family(_family, length); + FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0); + ServerFont font; + font.SetStyle(fontStyle); + state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); +} + + +static void +set_font_style(void* _state, const char* _style, size_t length) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + BString style(_style, length); + ServerFont font(state->GetDrawState()->Font()); + FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style); + font.SetStyle(fontStyle); + state->GetDrawState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); +} + + +static void +set_font_spacing(void* _state, uint8 spacing) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetSpacing(spacing); + state->GetDrawState()->SetFont(font, B_FONT_SPACING); +} + + +static void +set_font_size(void* _state, float size) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetSize(size); + state->GetDrawState()->SetFont(font, B_FONT_SIZE); +} + + +static void +set_font_rotate(void* _state, float rotation) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetRotation(rotation); + state->GetDrawState()->SetFont(font, B_FONT_ROTATION); +} + + +static void +set_font_encoding(void* _state, uint8 encoding) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetEncoding(encoding); + state->GetDrawState()->SetFont(font, B_FONT_ENCODING); +} + + +static void +set_font_flags(void* _state, uint32 flags) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetFlags(flags); + state->GetDrawState()->SetFont(font, B_FONT_FLAGS); +} + + +static void +set_font_shear(void* _state, float shear) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetShear(shear); + state->GetDrawState()->SetFont(font, B_FONT_SHEAR); +} + + +static void +set_font_face(void* _state, uint16 face) +{ + BoundingBoxState* const state = + reinterpret_cast(_state); + + ServerFont font; + font.SetFace(face); + state->GetDrawState()->SetFont(font, B_FONT_FACE); +} + + +static void +set_blending_mode(void*, source_alpha, alpha_function) +{ +} + + +static void +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 +determine_bounds_nested_layer(void* _state, Layer* layer) +{ + TRACE_BB("%p nested layer\n", _state); + BoundingBoxState* const state = + reinterpret_cast(_state); + + BRect boundingBox; + PictureBoundingBoxPlayer::Play(layer, state->GetDrawState(), &boundingBox); + if (boundingBox.IsValid()) + state->IncludeRect(boundingBox); +} + + +static const BPrivate::picture_player_callbacks + kPictureBoundingBoxPlayerCallbacks = { + move_pen_by, + determine_bounds_stroke_line, + determine_bounds_draw_rect, + determine_bounds_draw_round_rect, + determine_bounds_draw_bezier, + determine_bounds_draw_arc, + determine_bounds_draw_ellipse, + determine_bounds_draw_polygon, + determine_bounds_draw_shape, + determine_bounds_draw_string, + determine_bounds_draw_pixels, + draw_picture, + set_clipping_rects, + clip_to_picture, + push_state, + pop_state, + enter_state_change, + exit_state_change, + enter_font_state, + exit_font_state, + set_origin, + set_pen_location, + set_drawing_mode, + set_line_mode, + set_pen_size, + set_fore_color, + set_back_color, + set_stipple_pattern, + set_scale, + set_font_family, + set_font_style, + set_font_spacing, + set_font_size, + set_font_rotate, + set_font_encoding, + set_font_flags, + set_font_shear, + set_font_face, + set_blending_mode, + set_transform, + determine_bounds_nested_layer +}; + + +// #pragma mark - PictureBoundingBoxPlayer + + +/* static */ void +PictureBoundingBoxPlayer::Play(ServerPicture* picture, + const DrawState* drawState, BRect* outBoundingBox) +{ + State state(drawState, outBoundingBox); + + BMallocIO* mallocIO = dynamic_cast(picture->fData); + if (mallocIO == NULL) + return; + + BPrivate::PicturePlayer player(mallocIO->Buffer(), + mallocIO->BufferLength(), ServerPicture::PictureList::Private( + picture->fPictures).AsBList()); + player.Play(kPictureBoundingBoxPlayerCallbacks, + sizeof(kPictureBoundingBoxPlayerCallbacks), &state); +} diff --git a/src/servers/app/PictureBoundingBoxPlayer.h b/src/servers/app/PictureBoundingBoxPlayer.h new file mode 100644 index 0000000000..115f1acbfb --- /dev/null +++ b/src/servers/app/PictureBoundingBoxPlayer.h @@ -0,0 +1,28 @@ +/* + * Copyright 2015, Haiku. + * Distributed under the terms of the MIT license. + * + * Authors: + * Julian Harnath + */ +#ifndef PICTURE_BOUNDING_BOX_H +#define PICTURE_BOUNDING_BOX_H + + +class BRect; +class DrawState; +class ServerPicture; + + +class PictureBoundingBoxPlayer { +public: + class State; + +public: + static void Play(ServerPicture* picture, + const DrawState* drawState, + BRect* outBoundingBox); +}; + + +#endif // PICTURE_BOUNDING_BOX_H diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 8df669b09b..98d8774186 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2001-2010, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Marc Flerackers (mflerackers@androme.be) * Stefano Ceccherini (stefano.ceccherini@gmail.com) * Marcus Overhagen + * Julian Harnath */ #include "ServerPicture.h" @@ -18,6 +19,7 @@ #include "DrawingEngine.h" #include "DrawState.h" #include "FontManager.h" +#include "Layer.h" #include "ServerApp.h" #include "ServerBitmap.h" #include "ServerFont.h" @@ -45,7 +47,7 @@ using std::stack; class ShapePainter : public BShapeIterator { public: - ShapePainter(DrawingContext* context); + ShapePainter(Canvas* canvas); virtual ~ShapePainter(); status_t Iterate(const BShape* shape); @@ -60,15 +62,15 @@ public: void Draw(BRect frame, bool filled); private: - DrawingContext* fContext; + Canvas* fCanvas; stack fOpStack; stack fPtStack; }; -ShapePainter::ShapePainter(DrawingContext* context) +ShapePainter::ShapePainter(Canvas* canvas) : - fContext(context) + fCanvas(canvas) { } @@ -204,10 +206,10 @@ ShapePainter::Draw(BRect frame, bool filled) fPtStack.pop(); } - BPoint offset(fContext->CurrentState()->PenLocation()); - fContext->ConvertToScreenForDrawing(&offset); - fContext->GetDrawingEngine()->DrawShape(frame, opCount, opList, - ptCount, ptList, filled, offset, fContext->Scale()); + BPoint offset(fCanvas->CurrentState()->PenLocation()); + fCanvas->PenToScreenTransform().Apply(&offset); + fCanvas->GetDrawingEngine()->DrawShape(frame, opCount, opList, + ptCount, ptList, filled, offset, fCanvas->Scale()); delete[] opList; delete[] ptList; @@ -248,26 +250,27 @@ get_polygon_frame(const BPoint* points, uint32 numPoints, BRect* _frame) static void -move_pen_by(void* _context, const BPoint& delta) +move_pen_by(void* _canvas, const BPoint& delta) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetPenLocation( - context->CurrentState()->PenLocation() + delta); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetPenLocation( + canvas->CurrentState()->PenLocation() + delta); } static void -stroke_line(void* _context, const BPoint& _start, const BPoint& _end) +stroke_line(void* _canvas, const BPoint& _start, const BPoint& _end) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BPoint start = _start; BPoint end = _end; - context->ConvertToScreenForDrawing(&start); - context->ConvertToScreenForDrawing(&end); - context->GetDrawingEngine()->StrokeLine(start, end); + const SimpleTransform transform = canvas->PenToScreenTransform(); + transform.Apply(&start); + transform.Apply(&end); + canvas->GetDrawingEngine()->StrokeLine(start, end); - context->CurrentState()->SetPenLocation(_end); + canvas->CurrentState()->SetPenLocation(_end); // the DrawingEngine/Painter does not need to be updated, since this // effects only the view->screen coord conversion, which is handled // by the view only @@ -275,79 +278,78 @@ stroke_line(void* _context, const BPoint& _start, const BPoint& _end) static void -draw_rect(void* _context, const BRect& _rect, bool fill) +draw_rect(void* _canvas, const BRect& _rect, bool fill) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BRect rect = _rect; - context->ConvertToScreenForDrawing(&rect); + canvas->PenToScreenTransform().Apply(&rect); if (fill) - context->GetDrawingEngine()->FillRect(rect); + canvas->GetDrawingEngine()->FillRect(rect); else - context->GetDrawingEngine()->StrokeRect(rect); + canvas->GetDrawingEngine()->StrokeRect(rect); } static void -draw_round_rect(void* _context, const BRect& _rect, const BPoint& radii, +draw_round_rect(void* _canvas, const BRect& _rect, const BPoint& radii, bool fill) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BRect rect = _rect; - context->ConvertToScreenForDrawing(&rect); - float scale = context->CurrentState()->CombinedScale(); - context->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale, + canvas->PenToScreenTransform().Apply(&rect); + float scale = canvas->CurrentState()->CombinedScale(); + canvas->GetDrawingEngine()->DrawRoundRect(rect, radii.x * scale, radii.y * scale, fill); } static void -draw_bezier(void* _context, size_t numPoints, const BPoint viewPoints[], +draw_bezier(void* _canvas, size_t numPoints, const BPoint viewPoints[], bool fill) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); const size_t kSupportedPoints = 4; if (numPoints != kSupportedPoints) return; BPoint points[kSupportedPoints]; - context->ConvertToScreenForDrawing(points, viewPoints, kSupportedPoints); - - context->GetDrawingEngine()->DrawBezier(points, fill); + canvas->PenToScreenTransform().Apply(points, viewPoints, kSupportedPoints); + canvas->GetDrawingEngine()->DrawBezier(points, fill); } static void -draw_arc(void* _context, const BPoint& center, const BPoint& radii, +draw_arc(void* _canvas, const BPoint& center, const BPoint& radii, float startTheta, float arcTheta, bool fill) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BRect rect(center.x - radii.x, center.y - radii.y, center.x + radii.x - 1, center.y + radii.y - 1); - context->ConvertToScreenForDrawing(&rect); - context->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill); + canvas->PenToScreenTransform().Apply(&rect); + canvas->GetDrawingEngine()->DrawArc(rect, startTheta, arcTheta, fill); } static void -draw_ellipse(void* _context, const BRect& _rect, bool fill) +draw_ellipse(void* _canvas, const BRect& _rect, bool fill) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BRect rect = _rect; - context->ConvertToScreenForDrawing(&rect); - context->GetDrawingEngine()->DrawEllipse(rect, fill); + canvas->PenToScreenTransform().Apply(&rect); + canvas->GetDrawingEngine()->DrawEllipse(rect, fill); } static void -draw_polygon(void* _context, size_t numPoints, const BPoint viewPoints[], +draw_polygon(void* _canvas, size_t numPoints, const BPoint viewPoints[], bool isClosed, bool fill) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); if (numPoints == 0) return; @@ -361,12 +363,12 @@ draw_polygon(void* _context, size_t numPoints, const BPoint viewPoints[], return; } - context->ConvertToScreenForDrawing(points, viewPoints, numPoints); + canvas->PenToScreenTransform().Apply(points, viewPoints, numPoints); BRect polyFrame; get_polygon_frame(points, numPoints, &polyFrame); - context->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, + canvas->GetDrawingEngine()->DrawPolygon(points, numPoints, polyFrame, fill, isClosed && numPoints > 2); if (numPoints > kMaxStackCount) @@ -375,10 +377,10 @@ draw_polygon(void* _context, size_t numPoints, const BPoint viewPoints[], static void -draw_shape(void* _context, const BShape& shape, bool fill) +draw_shape(void* _canvas, const BShape& shape, bool fill) { - DrawingContext* context = reinterpret_cast(_context); - ShapePainter drawShape(context); + Canvas* const canvas = reinterpret_cast(_canvas); + ShapePainter drawShape(canvas); drawShape.Iterate(&shape); drawShape.Draw(shape.Bounds(), fill); @@ -386,23 +388,23 @@ draw_shape(void* _context, const BShape& shape, bool fill) static void -draw_string(void* _context, const char* string, size_t length, float deltaSpace, +draw_string(void* _canvas, const char* string, size_t length, float deltaSpace, float deltaNonSpace) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); // NOTE: the picture data was recorded with a "set pen location" // command inserted before the "draw string" command, so we can // use PenLocation() - BPoint location = context->CurrentState()->PenLocation(); + BPoint location = canvas->CurrentState()->PenLocation(); escapement_delta delta = { deltaSpace, deltaNonSpace }; - context->ConvertToScreenForDrawing(&location); - location = context->GetDrawingEngine()->DrawString(string, length, + canvas->PenToScreenTransform().Apply(&location); + location = canvas->GetDrawingEngine()->DrawString(string, length, location, &delta); - context->ConvertFromScreenForDrawing(&location); - context->CurrentState()->SetPenLocation(location); + canvas->PenToScreenTransform().Apply(&location); + canvas->CurrentState()->SetPenLocation(location); // the DrawingEngine/Painter does not need to be updated, since this // effects only the view->screen coord conversion, which is handled // by the view only @@ -410,11 +412,11 @@ draw_string(void* _context, const char* string, size_t length, float deltaSpace, static void -draw_pixels(void* _context, const BRect& src, const BRect& _dest, uint32 width, +draw_pixels(void* _canvas, const BRect& src, const BRect& _dest, uint32 width, uint32 height, size_t bytesPerRow, color_space pixelFormat, uint32 options, const void* data, size_t length) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); UtilityBitmap bitmap(BRect(0, 0, width - 1, height - 1), (color_space)pixelFormat, 0, bytesPerRow); @@ -425,85 +427,90 @@ draw_pixels(void* _context, const BRect& src, const BRect& _dest, uint32 width, memcpy(bitmap.Bits(), data, std::min(height * bytesPerRow, length)); BRect dest = _dest; - context->ConvertToScreenForDrawing(&dest); - context->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options); + canvas->PenToScreenTransform().Apply(&dest); + canvas->GetDrawingEngine()->DrawBitmap(&bitmap, src, dest, options); } static void -draw_picture(void* _context, const BPoint& where, int32 token) +draw_picture(void* _canvas, const BPoint& where, int32 token) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); - ServerPicture* picture = context->GetPicture(token); + ServerPicture* picture = canvas->GetPicture(token); if (picture != NULL) { - context->PushState(); - context->SetDrawingOrigin(where); + canvas->PushState(); + canvas->SetDrawingOrigin(where); - context->PushState(); - picture->Play(context); - context->PopState(); + canvas->PushState(); + picture->Play(canvas); + canvas->PopState(); - context->PopState(); + canvas->PopState(); picture->ReleaseReference(); } } static void -set_clipping_rects(void* _context, size_t numRects, const BRect rects[]) +set_clipping_rects(void* _canvas, size_t numRects, const BRect rects[]) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); - // TODO: This might be too slow, we should copy the rects - // directly to BRegion's internal data - BRegion region; - for (uint32 c = 0; c < numRects; c++) - region.Include(rects[c]); - - context->SetUserClipping(®ion); - context->UpdateCurrentDrawingRegion(); + if (numRects == 0) + canvas->SetUserClipping(NULL); + else { + // TODO: This might be too slow, we should copy the rects + // directly to BRegion's internal data + BRegion region; + for (uint32 c = 0; c < numRects; c++) + region.Include(rects[c]); + canvas->SetUserClipping(®ion); + } + canvas->UpdateCurrentDrawingRegion(); } static void -clip_to_picture(void* _context, int32 pictureToken, const BPoint& where, +clip_to_picture(void* _canvas, int32 pictureToken, const BPoint& where, bool clipToInverse) { - DrawingContext* context = reinterpret_cast(_context); +/* TODO + Canvas* const canvas = reinterpret_cast(_canvas); - ServerPicture* picture = context->GetPicture(pictureToken); + ServerPicture* picture = canvas->GetPicture(pictureToken); if (picture == NULL) return; AlphaMask* mask = new(std::nothrow) AlphaMask( - picture, clipToInverse, where, *context->CurrentState()); - context->SetAlphaMask(mask); - context->UpdateCurrentDrawingRegion(); + picture, clipToInverse, where, *canvas->CurrentState()); + canvas->SetAlphaMask(mask); + canvas->UpdateCurrentDrawingRegion(); if (mask != NULL) mask->ReleaseReference(); picture->ReleaseReference(); +*/ } static void -push_state(void* _context) +push_state(void* _canvas) { - DrawingContext* context = reinterpret_cast(_context); - context->PushState(); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->PushState(); } static void -pop_state(void* _context) +pop_state(void* _canvas) { - DrawingContext* context = reinterpret_cast(_context); - context->PopState(); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->PopState(); BPoint p(0, 0); - context->ConvertToScreenForDrawing(&p); - context->GetDrawingEngine()->SetDrawState(context->CurrentState(), + canvas->PenToScreenTransform().Apply(&p); + canvas->GetDrawingEngine()->SetDrawState(canvas->CurrentState(), (int32)p.x, (int32)p.y); } @@ -511,46 +518,46 @@ pop_state(void* _context) // TODO: Be smart and actually take advantage of these methods: // only apply state changes when they are called static void -enter_state_change(void* context) +enter_state_change(void* _canvas) { } static void -exit_state_change(void* _context) +exit_state_change(void* _canvas) { - DrawingContext* context = reinterpret_cast(_context); - context->ResyncDrawState(); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->ResyncDrawState(); } static void -enter_font_state(void* context) +enter_font_state(void* _canvas) { } static void -exit_font_state(void* _context) +exit_font_state(void* _canvas) { - DrawingContext* context = reinterpret_cast(_context); - context->GetDrawingEngine()->SetFont(context->CurrentState()->Font()); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->GetDrawingEngine()->SetFont(canvas->CurrentState()->Font()); } static void -set_origin(void* _context, const BPoint& pt) +set_origin(void* _canvas, const BPoint& pt) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetOrigin(pt); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetOrigin(pt); } static void -set_pen_location(void* _context, const BPoint& pt) +set_pen_location(void* _canvas, const BPoint& pt) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetPenLocation(pt); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetPenLocation(pt); // the DrawingEngine/Painter does not need to be updated, since this // effects only the view->screen coord conversion, which is handled // by the view only @@ -558,72 +565,72 @@ set_pen_location(void* _context, const BPoint& pt) static void -set_drawing_mode(void* _context, drawing_mode mode) +set_drawing_mode(void* _canvas, drawing_mode mode) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetDrawingMode(mode); - context->GetDrawingEngine()->SetDrawingMode(mode); + Canvas* const canvas = reinterpret_cast(_canvas); + if (canvas->CurrentState()->SetDrawingMode(mode)) + canvas->GetDrawingEngine()->SetDrawingMode(mode); } static void -set_line_mode(void* _context, cap_mode capMode, join_mode joinMode, +set_line_mode(void* _canvas, cap_mode capMode, join_mode joinMode, float miterLimit) { - DrawingContext* context = reinterpret_cast(_context); - DrawState* state = context->CurrentState(); + Canvas* const canvas = reinterpret_cast(_canvas); + DrawState* state = canvas->CurrentState(); state->SetLineCapMode(capMode); state->SetLineJoinMode(joinMode); state->SetMiterLimit(miterLimit); - context->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit); + canvas->GetDrawingEngine()->SetStrokeMode(capMode, joinMode, miterLimit); } static void -set_pen_size(void* _context, float size) +set_pen_size(void* _canvas, float size) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetPenSize(size); - context->GetDrawingEngine()->SetPenSize( - context->CurrentState()->PenSize()); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetPenSize(size); + canvas->GetDrawingEngine()->SetPenSize( + canvas->CurrentState()->PenSize()); // DrawState::PenSize() returns the scaled pen size, so we // need to use that value to set the drawing engine pen size. } static void -set_fore_color(void* _context, const rgb_color& color) +set_fore_color(void* _canvas, const rgb_color& color) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetHighColor(color); - context->GetDrawingEngine()->SetHighColor(color); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetHighColor(color); + canvas->GetDrawingEngine()->SetHighColor(color); } static void -set_back_color(void* _context, const rgb_color& color) +set_back_color(void* _canvas, const rgb_color& color) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetLowColor(color); - context->GetDrawingEngine()->SetLowColor(color); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetLowColor(color); + canvas->GetDrawingEngine()->SetLowColor(color); } static void -set_stipple_pattern(void* _context, const pattern& pattern) +set_stipple_pattern(void* _canvas, const pattern& pattern) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetPattern(Pattern(pattern)); - context->GetDrawingEngine()->SetPattern(pattern); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetPattern(Pattern(pattern)); + canvas->GetDrawingEngine()->SetPattern(pattern); } static void -set_scale(void* _context, float scale) +set_scale(void* _canvas, float scale) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetScale(scale); - context->ResyncDrawState(); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetScale(scale); + canvas->ResyncDrawState(); // Update the drawing engine draw state, since some stuff // (for example the pen size) needs to be recalculated. @@ -631,109 +638,125 @@ set_scale(void* _context, float scale) static void -set_font_family(void* _context, const char* _family, size_t length) +set_font_family(void* _canvas, const char* _family, size_t length) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BString family(_family, length); FontStyle* fontStyle = gFontManager->GetStyleByIndex(family, 0); ServerFont font; font.SetStyle(fontStyle); - context->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); + canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); } static void -set_font_style(void* _context, const char* _style, size_t length) +set_font_style(void* _canvas, const char* _style, size_t length) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); BString style(_style, length); - ServerFont font(context->CurrentState()->Font()); + ServerFont font(canvas->CurrentState()->Font()); FontStyle* fontStyle = gFontManager->GetStyle(font.Family(), style); font.SetStyle(fontStyle); - context->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); + canvas->CurrentState()->SetFont(font, B_FONT_FAMILY_AND_STYLE); } static void -set_font_spacing(void* _context, uint8 spacing) +set_font_spacing(void* _canvas, uint8 spacing) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetSpacing(spacing); - context->CurrentState()->SetFont(font, B_FONT_SPACING); + canvas->CurrentState()->SetFont(font, B_FONT_SPACING); } static void -set_font_size(void* _context, float size) +set_font_size(void* _canvas, float size) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetSize(size); - context->CurrentState()->SetFont(font, B_FONT_SIZE); + canvas->CurrentState()->SetFont(font, B_FONT_SIZE); } static void -set_font_rotation(void* _context, float rotation) +set_font_rotation(void* _canvas, float rotation) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetRotation(rotation); - context->CurrentState()->SetFont(font, B_FONT_ROTATION); + canvas->CurrentState()->SetFont(font, B_FONT_ROTATION); } static void -set_font_encoding(void* _context, uint8 encoding) +set_font_encoding(void* _canvas, uint8 encoding) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetEncoding(encoding); - context->CurrentState()->SetFont(font, B_FONT_ENCODING); + canvas->CurrentState()->SetFont(font, B_FONT_ENCODING); } static void -set_font_flags(void* _context, uint32 flags) +set_font_flags(void* _canvas, uint32 flags) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetFlags(flags); - context->CurrentState()->SetFont(font, B_FONT_FLAGS); + canvas->CurrentState()->SetFont(font, B_FONT_FLAGS); } static void -set_font_shear(void* _context, float shear) +set_font_shear(void* _canvas, float shear) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetShear(shear); - context->CurrentState()->SetFont(font, B_FONT_SHEAR); + canvas->CurrentState()->SetFont(font, B_FONT_SHEAR); } static void -set_font_face(void* _context, uint16 face) +set_font_face(void* _canvas, uint16 face) { - DrawingContext* context = reinterpret_cast(_context); + Canvas* const canvas = reinterpret_cast(_canvas); ServerFont font; font.SetFace(face); - context->CurrentState()->SetFont(font, B_FONT_FACE); + canvas->CurrentState()->SetFont(font, B_FONT_FACE); } static void -set_blending_mode(void* _context, source_alpha alphaSrcMode, +set_blending_mode(void* _canvas, source_alpha alphaSrcMode, alpha_function alphaFncMode) { - DrawingContext* context = reinterpret_cast(_context); - context->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode); + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode); +} + + +static void +set_transform(void* _canvas, const BAffineTransform& transform) +{ + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->CurrentState()->SetTransform(transform); +} + + +static void +blend_layer(void* _canvas, Layer* layer) +{ + Canvas* const canvas = reinterpret_cast(_canvas); + canvas->BlendLayer(layer); } @@ -776,7 +799,9 @@ static const BPrivate::picture_player_callbacks kPicturePlayerCallbacks = { set_font_flags, set_font_shear, set_font_face, - set_blending_mode + set_blending_mode, + set_transform, + blend_layer }; @@ -925,7 +950,7 @@ ServerPicture::SyncState(View* view) WriteSetOrigin(view->CurrentState()->Origin()); WriteSetPenLocation(view->CurrentState()->PenLocation()); - WriteSetPenSize(view->CurrentState()->PenSize()); + WriteSetPenSize(view->CurrentState()->UnscaledPenSize()); WriteSetScale(view->CurrentState()->Scale()); WriteSetLineMode(view->CurrentState()->LineCapMode(), view->CurrentState()->LineJoinMode(), @@ -1010,7 +1035,7 @@ ServerPicture::SetFontFromLink(BPrivate::LinkReceiver& link) void -ServerPicture::Play(DrawingContext* target) +ServerPicture::Play(Canvas* target) { // TODO: for now: then change PicturePlayer // to accept a BPositionIO object diff --git a/src/servers/app/ServerPicture.h b/src/servers/app/ServerPicture.h index 6f27d38c2a..d44d2a5282 100644 --- a/src/servers/app/ServerPicture.h +++ b/src/servers/app/ServerPicture.h @@ -1,10 +1,11 @@ /* - * Copyright 2001-2010, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm * Stefano Ceccherini + * Julian Harnath */ #ifndef SERVER_PICTURE_H #define SERVER_PICTURE_H @@ -18,7 +19,7 @@ class BFile; -class DrawingContext; +class Canvas; class ServerApp; class View; @@ -35,7 +36,7 @@ public: ServerPicture(const ServerPicture& other); ServerPicture(const char* fileName, int32 offset); - ~ServerPicture(); + virtual ~ServerPicture(); int32 Token() { return fToken; } bool SetOwner(ServerApp* owner); @@ -49,7 +50,7 @@ public: void SyncState(View* view); void SetFontFromLink(BPrivate::LinkReceiver& link); - void Play(DrawingContext* target); + void Play(Canvas* target); void PushPicture(ServerPicture* picture); ServerPicture* PopPicture(); @@ -63,6 +64,8 @@ public: status_t ExportData(BPrivate::PortLink& link); private: + friend class PictureBoundingBoxPlayer; + typedef BObjectList PictureList; int32 fToken; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 2ec9d90c7c..2a7df4c944 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Haiku. + * Copyright 2001-2015, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -11,6 +11,7 @@ * Artur Wyszynski * Philippe Saint-Pierre * Brecht Machiels + * Julian Harnath */ @@ -61,6 +62,7 @@ #include "DrawingEngine.h" #include "DrawState.h" #include "HWInterface.h" +#include "Layer.h" #include "Overlay.h" #include "ProfileMessageSupport.h" #include "RenderingBuffer.h" @@ -351,7 +353,7 @@ ServerWindow::_Show() fDesktop->ShowWindow(fWindow); if (fDirectWindowInfo && fDirectWindowInfo->IsFullScreen()) _ResizeToFullScreen(); - + fDesktop->LockSingleWindow(); } @@ -1940,11 +1942,13 @@ fDesktop->LockSingleWindow(); if (picture == NULL) break; - AlphaMask* mask = new(std::nothrow) AlphaMask( - picture, inverse, where, *fCurrentView->CurrentState()); + AlphaMask* const mask = new PictureAlphaMask( + fCurrentView->GetAlphaMask(), picture, + *fCurrentView->CurrentState(), where, inverse); fCurrentView->SetAlphaMask(mask); if (mask != NULL) mask->ReleaseReference(); + _UpdateDrawState(fCurrentView); picture->ReleaseReference(); @@ -1964,7 +1968,7 @@ fDesktop->LockSingleWindow(); } else { _UpdateCurrentDrawingRegion(); BRegion region(fCurrentDrawingRegion); - fCurrentView->ConvertFromScreen(®ion); + fCurrentView->ScreenToLocalTransform().Apply(®ion); fLink.AttachRegion(region); } fLink.Flush(); @@ -2185,6 +2189,29 @@ fDesktop->LockSingleWindow(); break; } + case AS_VIEW_BEGIN_LAYER: + { + DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n", + Title())); + + uint8 opacity; + link.Read(&opacity); + + Layer* layer = new(std::nothrow) Layer(opacity); + if (layer == NULL) + break; + + if (opacity != 255) { + fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA); + fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA, + B_ALPHA_COMPOSITE); + fCurrentView->CurrentState()->SetDrawingModeLocked(true); + } + + fCurrentView->SetPicture(layer); + break; + } + default: _DispatchViewDrawingMessage(code, link); break; @@ -2255,8 +2282,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, info.endPoint.x, info.endPoint.y)); BPoint penPos = info.endPoint; - fCurrentView->ConvertToScreenForDrawing(&info.startPoint); - fCurrentView->ConvertToScreenForDrawing(&info.endPoint); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&info.startPoint); + transform.Apply(&info.endPoint); drawingEngine->StrokeLine(info.startPoint, info.endPoint); // We update the pen here because many DrawingEngine calls which @@ -2280,7 +2309,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, fCurrentView->Name(), rect.left, rect.top, rect.right, rect.bottom)); - fCurrentView->ConvertToScreenForDrawing(&rect); + fCurrentView->PenToScreenTransform().Apply(&rect); drawingEngine->InvertRect(rect); break; } @@ -2295,7 +2324,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, fCurrentView->Name(), rect.left, rect.top, rect.right, rect.bottom)); - fCurrentView->ConvertToScreenForDrawing(&rect); + fCurrentView->PenToScreenTransform().Apply(&rect); drawingEngine->StrokeRect(rect); break; } @@ -2310,7 +2339,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, fCurrentView->Name(), rect.left, rect.top, rect.right, rect.bottom)); - fCurrentView->ConvertToScreenForDrawing(&rect); + fCurrentView->PenToScreenTransform().Apply(&rect); drawingEngine->FillRect(rect); break; } @@ -2327,8 +2356,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, fCurrentView->Name(), rect.left, rect.top, rect.right, rect.bottom)); - fCurrentView->ConvertToScreenForDrawing(&rect); - fCurrentView->ConvertToScreenForDrawing(gradient); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&rect); + transform.Apply(gradient); drawingEngine->FillRect(rect, *gradient); delete gradient; break; @@ -2357,7 +2388,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, info.viewRect.left, info.viewRect.top, info.viewRect.right, info.viewRect.bottom)); - fCurrentView->ConvertToScreenForDrawing(&info.viewRect); + fCurrentView->PenToScreenTransform().Apply(&info.viewRect); // TODO: Unbreak... // if ((info.options & B_WAIT_FOR_RETRACE) != 0) @@ -2383,7 +2414,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, if (link.Read(&span) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&r); + fCurrentView->PenToScreenTransform().Apply(&r); drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC); break; } @@ -2400,8 +2431,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, BGradient* gradient; if (link.ReadGradient(&gradient) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&r); - fCurrentView->ConvertToScreenForDrawing(gradient); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&r); + transform.Apply(gradient); drawingEngine->FillArc(r, angle, span, *gradient); delete gradient; break; @@ -2412,11 +2445,13 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title())); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); BPoint pts[4]; status_t status; for (int32 i = 0; i < 4; i++) { status = link.Read(&(pts[i])); - fCurrentView->ConvertToScreenForDrawing(&pts[i]); + transform.Apply(&pts[i]); } if (status != B_OK) break; @@ -2429,15 +2464,17 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n", Title())); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); BPoint pts[4]; for (int32 i = 0; i < 4; i++) { link.Read(&(pts[i])); - fCurrentView->ConvertToScreenForDrawing(&pts[i]); + transform.Apply(&pts[i]); } BGradient* gradient; if (link.ReadGradient(&gradient) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(gradient); + transform.Apply(gradient); drawingEngine->FillBezier(pts, *gradient); delete gradient; break; @@ -2452,7 +2489,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, if (link.Read(&rect) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&rect); + fCurrentView->PenToScreenTransform().Apply(&rect); drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE); break; } @@ -2466,8 +2503,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, BGradient* gradient; if (link.ReadGradient(&gradient) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&rect); - fCurrentView->ConvertToScreenForDrawing(gradient); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&rect); + transform.Apply(gradient); drawingEngine->FillEllipse(rect, *gradient); delete gradient; break; @@ -2486,7 +2525,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, if (link.Read(&yRadius) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&rect); + fCurrentView->PenToScreenTransform().Apply(&rect); float scale = fCurrentView->CurrentState()->CombinedScale(); drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale, code == AS_FILL_ROUNDRECT); @@ -2505,8 +2544,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, BGradient* gradient; if (link.ReadGradient(&gradient) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&rect); - fCurrentView->ConvertToScreenForDrawing(gradient); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&rect); + transform.Apply(gradient); drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient); delete gradient; break; @@ -2517,18 +2558,20 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", Title())); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); BPoint pts[3]; BRect rect; for (int32 i = 0; i < 3; i++) { link.Read(&(pts[i])); - fCurrentView->ConvertToScreenForDrawing(&pts[i]); + transform.Apply(&pts[i]); } if (link.Read(&rect) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&rect); + transform.Apply(&rect); drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE); break; } @@ -2537,18 +2580,20 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n", Title())); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); BPoint pts[3]; BRect rect; for (int32 i = 0; i < 3; i++) { link.Read(&(pts[i])); - fCurrentView->ConvertToScreenForDrawing(&pts[i]); + transform.Apply(&pts[i]); } link.Read(&rect); BGradient* gradient; if (link.ReadGradient(&gradient) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(&rect); - fCurrentView->ConvertToScreenForDrawing(gradient); + transform.Apply(&rect); + transform.Apply(gradient); drawingEngine->FillTriangle(pts, rect, *gradient); delete gradient; break; @@ -2568,11 +2613,13 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, link.Read(&isClosed); link.Read(&pointCount); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); BPoint* pointList = new(nothrow) BPoint[pointCount]; if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { for (int32 i = 0; i < pointCount; i++) - fCurrentView->ConvertToScreenForDrawing(&pointList[i]); - fCurrentView->ConvertToScreenForDrawing(&polyFrame); + transform.Apply(&pointList[i]); + transform.Apply(&polyFrame); drawingEngine->DrawPolygon(pointList, pointCount, polyFrame, code == AS_FILL_POLYGON, isClosed && pointCount > 2); @@ -2591,14 +2638,16 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, link.Read(&polyFrame); link.Read(&pointCount); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); BPoint* pointList = new(nothrow) BPoint[pointCount]; BGradient* gradient; if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK && link.ReadGradient(&gradient) == B_OK) { for (int32 i = 0; i < pointCount; i++) - fCurrentView->ConvertToScreenForDrawing(&pointList[i]); - fCurrentView->ConvertToScreenForDrawing(&polyFrame); - fCurrentView->ConvertToScreenForDrawing(gradient); + transform.Apply(&pointList[i]); + transform.Apply(&polyFrame); + transform.Apply(gradient); drawingEngine->FillPolygon(pointList, pointCount, polyFrame, *gradient, isClosed && pointCount > 2); @@ -2632,8 +2681,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, = fCurrentView->CurrentState()->PenLocation(); shapeFrame.OffsetBy(screenOffset); - fCurrentView->ConvertToScreenForDrawing(&screenOffset); - fCurrentView->ConvertToScreenForDrawing(&shapeFrame); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&screenOffset); + transform.Apply(&shapeFrame); drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList, code == AS_FILL_SHAPE, screenOffset, @@ -2670,9 +2721,11 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, = fCurrentView->CurrentState()->PenLocation(); shapeFrame.OffsetBy(screenOffset); - fCurrentView->ConvertToScreenForDrawing(&screenOffset); - fCurrentView->ConvertToScreenForDrawing(&shapeFrame); - fCurrentView->ConvertToScreenForDrawing(gradient); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(&screenOffset); + transform.Apply(&shapeFrame); + transform.Apply(gradient); drawingEngine->FillShape(shapeFrame, opCount, opList, ptCount, ptList, *gradient, screenOffset, fCurrentView->Scale()); @@ -2691,7 +2744,7 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, if (link.ReadRegion(®ion) < B_OK) break; - fCurrentView->ConvertToScreenForDrawing(®ion); + fCurrentView->PenToScreenTransform().Apply(®ion); drawingEngine->FillRegion(region); break; @@ -2708,8 +2761,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, if (link.ReadGradient(&gradient) != B_OK) break; - fCurrentView->ConvertToScreenForDrawing(®ion); - fCurrentView->ConvertToScreenForDrawing(gradient); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); + transform.Apply(®ion); + transform.Apply(gradient); drawingEngine->FillRegion(region, *gradient); delete gradient; break; @@ -2748,11 +2803,11 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, } // Convert to screen coords and draw + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); for (int32 i = 0; i < lineCount; i++) { - fCurrentView->ConvertToScreenForDrawing( - &lineData[i].startPoint); - fCurrentView->ConvertToScreenForDrawing( - &lineData[i].endPoint); + transform.Apply(&lineData[i].startPoint); + transform.Apply(&lineData[i].endPoint); } drawingEngine->StrokeLineArray(lineCount, lineData); @@ -2797,11 +2852,11 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s " "-> %s\n", Title(), fCurrentView->Name(), string)); - fCurrentView->ConvertToScreenForDrawing(&info.location); + fCurrentView->PenToScreenTransform().Apply(&info.location); BPoint penLocation = drawingEngine->DrawString(string, info.stringLength, info.location, delta); - fCurrentView->ConvertFromScreenForDrawing(&penLocation); + fCurrentView->ScreenToPenTransform().Apply(&penLocation); fCurrentView->CurrentState()->SetPenLocation(penLocation); if (string != stackString) @@ -2854,13 +2909,15 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s " "-> %s\n", Title(), fCurrentView->Name(), string)); + const SimpleTransform transform = + fCurrentView->PenToScreenTransform(); for (int32 i = 0; i < glyphCount; i++) - fCurrentView->ConvertToScreenForDrawing(&locations[i]); + transform.Apply(&locations[i]); BPoint penLocation = drawingEngine->DrawString(string, stringLength, locations); - fCurrentView->ConvertFromScreenForDrawing(&penLocation); + fCurrentView->ScreenToPenTransform().Apply(&penLocation); fCurrentView->CurrentState()->SetPenLocation(penLocation); break; @@ -2893,6 +2950,16 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, break; } + case AS_VIEW_END_LAYER: + { + DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n", + Title())); + fCurrentView->BlendAllLayers(); + fCurrentView->SetPicture(NULL); + fCurrentView->CurrentState()->SetDrawingModeLocked(false); + break; + } + default: BString codeString; string_for_message_code(code, codeString); @@ -3411,6 +3478,49 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link) fLink.Flush(); return true; } + + case AS_VIEW_BEGIN_LAYER: + { + uint8 opacity; + link.Read(&opacity); + + Layer* layer = dynamic_cast(picture); + if (layer == NULL) + break; + + Layer* nextLayer = new(std::nothrow) Layer(opacity); + if (nextLayer == NULL) + break; + + if (opacity != 255) { + fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA); + fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA, + B_ALPHA_COMPOSITE); + fCurrentView->CurrentState()->SetDrawingModeLocked(true); + } + + nextLayer->PushLayer(layer); + fCurrentView->SetPicture(nextLayer); + break; + } + + case AS_VIEW_END_LAYER: + { + Layer* layer = dynamic_cast(picture); + if (layer == NULL) + break; + + Layer* previousLayer = layer->PopLayer(); + if (previousLayer == NULL) { + // End last layer + return false; + } + fCurrentView->SetPicture(previousLayer); + + previousLayer->WriteBlendLayer(layer); + break; + } + /* case AS_VIEW_SET_BLENDING_MODE: { @@ -3728,11 +3838,11 @@ ServerWindow::_UpdateDrawState(View* view) if (view != NULL && drawingEngine != NULL) { BPoint leftTop(0, 0); if (view->GetAlphaMask() != NULL) { - view->ConvertToScreen(&leftTop); - view->GetAlphaMask()->Update(view->Bounds(), leftTop); + view->LocalToScreenTransform().Apply(&leftTop); + view->GetAlphaMask()->SetViewOrigin(leftTop); leftTop = BPoint(0, 0); } - view->ConvertToScreenForDrawing(&leftTop); + view->PenToScreenTransform().Apply(&leftTop); drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y); } } diff --git a/src/servers/app/SimpleTransform.h b/src/servers/app/SimpleTransform.h new file mode 100644 index 0000000000..00c8f458a5 --- /dev/null +++ b/src/servers/app/SimpleTransform.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2001-2015, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * Stephan Aßmus + * Adrien Destugues + * Julian Harnath + */ + +#ifndef SIMPLE_TRANSFORM_H +#define SIMPLE_TRANSFORM_H + +#include +#include +#include +#include +#include +#include +#include + +#include "IntPoint.h" +#include "IntRect.h" + + +class SimpleTransform { +public: + SimpleTransform() + : + fScale(1.0) + { + } + + void AddOffset(float x, float y) + { + fOffset.x += x; + fOffset.y += y; + } + + void SetScale(float scale) + { + fScale = scale; + } + + void Apply(BPoint* point) const + { + _Apply(point->x, point->y); + } + + void Apply(IntPoint* point) const + { + _Apply(point->x, point->y); + } + + void Apply(BRect* rect) const + { + if (fScale == 1.0) { + rect->OffsetBy(fOffset.x, fOffset.y); + } else { + _Apply(rect->left, rect->top); + _Apply(rect->right, rect->bottom); + } + } + + void Apply(IntRect* rect) const + { + if (fScale == 1.0) { + rect->OffsetBy(fOffset.x, fOffset.y); + } else { + _Apply(rect->left, rect->top); + _Apply(rect->right, rect->bottom); + } + } + + void Apply(BRegion* region) const + { + if (fScale == 1.0) { + region->OffsetBy(fOffset.x, fOffset.y); + } else { + // TODO: optimize some more + BRegion converted; + int32 count = region->CountRects(); + for (int32 i = 0; i < count; i++) { + BRect r = region->RectAt(i); + BPoint lt(r.LeftTop()); + BPoint rb(r.RightBottom()); + // offset to bottom right corner of pixel before transformation + rb.x++; + rb.y++; + // apply transformation + _Apply(lt.x, lt.y); + _Apply(rb.x, rb.y); + // reset bottom right to pixel "index" + rb.x--; + rb.y--; + // add rect to converted region + // NOTE/TODO: the rect would not have to go + // through the whole intersection test process, + // it is guaranteed not to overlap with any rect + // already contained in the region + converted.Include(BRect(lt, rb)); + } + *region = converted; + } + } + + void Apply(BGradient* gradient) const + { + switch (gradient->GetType()) { + case BGradient::TYPE_LINEAR: + { + BGradientLinear* linear = (BGradientLinear*) gradient; + BPoint start = linear->Start(); + BPoint end = linear->End(); + Apply(&start); + Apply(&end); + linear->SetStart(start); + linear->SetEnd(end); + break; + } + + case BGradient::TYPE_RADIAL: + { + BGradientRadial* radial = (BGradientRadial*) gradient; + BPoint center = radial->Center(); + Apply(¢er); + radial->SetCenter(center); + break; + } + + case BGradient::TYPE_RADIAL_FOCUS: + { + BGradientRadialFocus* radialFocus = + (BGradientRadialFocus*)gradient; + BPoint center = radialFocus->Center(); + BPoint focal = radialFocus->Focal(); + Apply(¢er); + Apply(&focal); + radialFocus->SetCenter(center); + radialFocus->SetFocal(focal); + break; + } + + case BGradient::TYPE_DIAMOND: + { + BGradientDiamond* diamond = (BGradientDiamond*) gradient; + BPoint center = diamond->Center(); + Apply(¢er); + diamond->SetCenter(center); + break; + } + + case BGradient::TYPE_CONIC: + { + BGradientConic* conic = (BGradientConic*) gradient; + BPoint center = conic->Center(); + Apply(¢er); + conic->SetCenter(center); + break; + } + + case BGradient::TYPE_NONE: + { + break; + } + } + + // Make sure the gradient is fully padded so that out of bounds access + // get the correct colors + gradient->SortColorStopsByOffset(); + + BGradient::ColorStop* end = gradient->ColorStopAtFast( + gradient->CountColorStops() - 1); + + if (end->offset != 255) + gradient->AddColor(end->color, 255); + + BGradient::ColorStop* start = gradient->ColorStopAtFast(0); + + if (start->offset != 0) + gradient->AddColor(start->color, 0); + + gradient->SortColorStopsByOffset(); + } + + void Apply(BPoint* destination, const BPoint* source, int32 count) const + { + // TODO: optimize this, it should be smarter + while (count--) { + *destination = *source; + Apply(destination); + source++; + destination++; + } + } + + void Apply(BRect* destination, const BRect* source, int32 count) const + { + // TODO: optimize this, it should be smarter + while (count--) { + *destination = *source; + Apply(destination); + source++; + destination++; + } + } + + void Apply(BRegion* destination, const BRegion* source, int32 count) const + { + // TODO: optimize this, it should be smarter + while (count--) { + *destination = *source; + Apply(destination); + source++; + destination++; + } + } + +private: + void _Apply(int32& x, int32& y) const + { + x *= (int32)fScale; + y *= (int32)fScale; + x += (int32)fOffset.x; + y += (int32)fOffset.y; + } + + void _Apply(float& x, float& y) const + { + x *= fScale; + y *= fScale; + x += fOffset.x; + y += fOffset.y; + } + +private: + BPoint fOffset; + float fScale; +}; + + +#endif // SIMPLE_TRANSFORM_H diff --git a/src/servers/app/TestServerLoopAdapter.cpp b/src/servers/app/TestServerLoopAdapter.cpp new file mode 100644 index 0000000000..a12cdc86b6 --- /dev/null +++ b/src/servers/app/TestServerLoopAdapter.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2001-2015, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm + * Axel Dörfler, axeld@pinc-software.de + * Stephan Aßmus + * Christian Packmann + * Julian Harnath + */ +#include "TestServerLoopAdapter.h" + +#include "Desktop.h" +#include "ServerConfig.h" +#include "ServerProtocol.h" + +#include + +#include + +//#define DEBUG_SERVER +#ifdef DEBUG_SERVER +# include +# define STRACE(x) printf x +#else +# define STRACE(x) ; +#endif + + +TestServerLoopAdapter::TestServerLoopAdapter(const char* signature, + const char*, port_id, bool, status_t* outError) + : + MessageLooper("test-app_server"), + fMessagePort(_CreatePort()) +{ + fLink.SetReceiverPort(fMessagePort); + *outError = B_OK; +} + + +TestServerLoopAdapter::~TestServerLoopAdapter() +{ +} + + +bool +TestServerLoopAdapter::Run() +{ + rename_thread(find_thread(NULL), "picasso"); + _message_thread((void*)this); + return true; +} + + +void +TestServerLoopAdapter::_DispatchMessage(int32 code, + BPrivate::LinkReceiver& link) +{ + switch (code) { + case AS_GET_DESKTOP: + { + port_id replyPort = 0; + link.Read(&replyPort); + + int32 userID = -1; + link.Read(&userID); + + char* targetScreen = NULL; + link.ReadString(&targetScreen); + + int32 version = -1; + link.Read(&version); + + BMessage message(AS_GET_DESKTOP); + message.AddInt32("user", userID); + message.AddInt32("version", version); + message.AddString("target", targetScreen); + MessageReceived(&message); + + // AppServer will try to send a reply, we just let that fail + // since we can find out the port by getting the desktop instance + // ourselves + + free(targetScreen); + Desktop* desktop = _FindDesktop(userID, targetScreen); + + BPrivate::LinkSender reply(replyPort); + if (desktop != NULL) { + reply.StartMessage(B_OK); + reply.Attach(desktop->MessagePort()); + } else + reply.StartMessage(B_ERROR); + + reply.Flush(); + + break; + } + + case B_QUIT_REQUESTED: + { + QuitRequested(); + break; + } + + default: + STRACE(("Server::MainLoop received unexpected code %" B_PRId32 " " + "(offset %" B_PRId32 ")\n", code, code - SERVER_TRUE)); + break; + } +} + + +port_id +TestServerLoopAdapter::_CreatePort() +{ + port_id port = create_port(DEFAULT_MONITOR_PORT_SIZE, SERVER_PORT_NAME); + if (port < B_OK) + debugger("test-app_server could not create message port"); + return port; +} diff --git a/src/servers/app/TestServerLoopAdapter.h b/src/servers/app/TestServerLoopAdapter.h new file mode 100644 index 0000000000..f3d2879f6e --- /dev/null +++ b/src/servers/app/TestServerLoopAdapter.h @@ -0,0 +1,51 @@ +/* + * Copyright 2001-2015, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm + * Axel Dörfler, axeld@pinc-software.de + * Julian Harnath, + */ +#ifndef TEST_SERVER_LOOP_ADAPTER_H +#define TEST_SERVER_LOOP_ADAPTER_H + +#include "MessageLooper.h" + + +class BMessage; +class Desktop; + + +class TestServerLoopAdapter : public MessageLooper { +public: + TestServerLoopAdapter(const char* signature, + const char* looperName, port_id port, + bool initGui, status_t* outError); + virtual ~TestServerLoopAdapter(); + + // MessageLooper interface + virtual port_id MessagePort() const { return fMessagePort; } + virtual bool Run(); + + // BApplication interface + virtual void MessageReceived(BMessage* message) = 0; + virtual bool QuitRequested() { return true; } + +private: + // MessageLooper interface + virtual void _DispatchMessage(int32 code, + BPrivate::LinkReceiver &link); + + virtual Desktop* _FindDesktop(uid_t userID, + const char* targetScreen) = 0; + port_id _CreatePort(); + + + +private: + port_id fMessagePort; +}; + + +#endif // TEST_SERVER_LOOP_ADAPTER_H diff --git a/src/servers/app/View.cpp b/src/servers/app/View.cpp index 7831b45cfb..eaf80412fc 100644 --- a/src/servers/app/View.cpp +++ b/src/servers/app/View.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2014, Haiku, Inc. + * Copyright (c) 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: @@ -9,6 +9,7 @@ * Stephan Aßmus * Marcus Overhagen * Adrien Destugues */ #include "View.h" @@ -19,6 +20,7 @@ #include "Desktop.h" #include "DrawingEngine.h" #include "DrawState.h" +#include "Layer.h" #include "Overlay.h" #include "ServerApp.h" #include "ServerBitmap.h" @@ -27,6 +29,7 @@ #include "ServerWindow.h" #include "Window.h" +#include "BitmapHWInterface.h" #include "drawing_support.h" #include @@ -165,7 +168,8 @@ View::ConvertToVisibleInTopView(IntRect* bounds) const { *bounds = *bounds & Bounds(); // NOTE: this step is necessary even if we don't have a parent! - ConvertToParent(bounds); + bounds->OffsetBy(fFrame.left - fScrollingOffset.x, + fFrame.top - fScrollingOffset.y); if (fParent) fParent->ConvertToVisibleInTopView(bounds); @@ -440,7 +444,7 @@ View::ViewAt(const BPoint& where) IntRect frame = Frame(); if (Parent() != NULL) - Parent()->ConvertToScreen(&frame); + Parent()->LocalToScreenTransform().Apply(&frame); if (!frame.Contains(where)) return NULL; @@ -524,7 +528,7 @@ View::_UpdateOverlayView() const return; IntRect destination = fBitmapDestination; - ConvertToScreen(&destination); + LocalToScreenTransform().Apply(&destination); overlay->Configure(fBitmapSource, destination); } @@ -556,201 +560,34 @@ View::UpdateOverlay() void -View::ConvertToParent(BPoint* point) const +View::_LocalToScreenTransform(SimpleTransform& transform) const { - // remove scrolling offset and convert to parent coordinate space - point->x += fFrame.left - fScrollingOffset.x; - point->y += fFrame.top - fScrollingOffset.y; + const View* view = this; + int32 offsetX = 0; + int32 offsetY = 0; + do { + offsetX += view->fFrame.left - view->fScrollingOffset.x; + offsetY += view->fFrame.top - view->fScrollingOffset.y; + view = view->fParent; + } while (view != NULL); + + transform.AddOffset(offsetX, offsetY); } void -View::ConvertToParent(IntPoint* point) const +View::_ScreenToLocalTransform(SimpleTransform& transform) const { - // remove scrolling offset and convert to parent coordinate space - point->x += fFrame.left - fScrollingOffset.x; - point->y += fFrame.top - fScrollingOffset.y; -} + const View* view = this; + int32 offsetX = 0; + int32 offsetY = 0; + do { + offsetX += view->fScrollingOffset.x - view->fFrame.left; + offsetY += view->fScrollingOffset.y - view->fFrame.top; + view = view->fParent; + } while (view != NULL); - -void -View::ConvertToParent(BRect* rect) const -{ - // remove scrolling offset and convert to parent coordinate space - rect->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - - -void -View::ConvertToParent(IntRect* rect) const -{ - // remove scrolling offset and convert to parent coordinate space - rect->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - - -void -View::ConvertToParent(BRegion* region) const -{ - // remove scrolling offset and convert to parent coordinate space - region->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - - -void -View::ConvertFromParent(BPoint* point) const -{ - // convert from parent coordinate space amd add scrolling offset - point->x += fScrollingOffset.x - fFrame.left; - point->y += fScrollingOffset.y - fFrame.top; -} - - -void -View::ConvertFromParent(IntPoint* point) const -{ - // convert from parent coordinate space amd add scrolling offset - point->x += fScrollingOffset.x - fFrame.left; - point->y += fScrollingOffset.y - fFrame.top; -} - - -void -View::ConvertFromParent(BRect* rect) const -{ - // convert from parent coordinate space amd add scrolling offset - rect->OffsetBy(fScrollingOffset.x - fFrame.left, - fScrollingOffset.y - fFrame.top); -} - - -void -View::ConvertFromParent(IntRect* rect) const -{ - // convert from parent coordinate space amd add scrolling offset - rect->OffsetBy(fScrollingOffset.x - fFrame.left, - fScrollingOffset.y - fFrame.top); -} - - -void -View::ConvertFromParent(BRegion* region) const -{ - // convert from parent coordinate space amd add scrolling offset - region->OffsetBy(fScrollingOffset.x - fFrame.left, - fScrollingOffset.y - fFrame.top); -} - -//! converts a point from local to screen coordinate system -void -View::ConvertToScreen(BPoint* pt) const -{ - ConvertToParent(pt); - - if (fParent) - fParent->ConvertToScreen(pt); -} - - -//! converts a point from local to screen coordinate system -void -View::ConvertToScreen(IntPoint* pt) const -{ - ConvertToParent(pt); - - if (fParent) - fParent->ConvertToScreen(pt); -} - - -//! converts a rect from local to screen coordinate system -void -View::ConvertToScreen(BRect* rect) const -{ - BPoint offset(0.0, 0.0); - ConvertToScreen(&offset); - - rect->OffsetBy(offset); -} - - -//! converts a rect from local to screen coordinate system -void -View::ConvertToScreen(IntRect* rect) const -{ - BPoint offset(0.0, 0.0); - ConvertToScreen(&offset); - - rect->OffsetBy(offset); -} - - -//! converts a region from local to screen coordinate system -void -View::ConvertToScreen(BRegion* region) const -{ - BPoint offset(0.0, 0.0); - ConvertToScreen(&offset); - - region->OffsetBy((int)offset.x, (int)offset.y); -} - - -//! converts a point from screen to local coordinate system -void -View::ConvertFromScreen(BPoint* pt) const -{ - ConvertFromParent(pt); - - if (fParent) - fParent->ConvertFromScreen(pt); -} - - -//! converts a point from screen to local coordinate system -void -View::ConvertFromScreen(IntPoint* pt) const -{ - ConvertFromParent(pt); - - if (fParent) - fParent->ConvertFromScreen(pt); -} - - -//! converts a rect from screen to local coordinate system -void -View::ConvertFromScreen(BRect* rect) const -{ - BPoint offset(0.0, 0.0); - ConvertFromScreen(&offset); - - rect->OffsetBy(offset.x, offset.y); -} - - -//! converts a rect from screen to local coordinate system -void -View::ConvertFromScreen(IntRect* rect) const -{ - BPoint offset(0.0, 0.0); - ConvertFromScreen(&offset); - - rect->OffsetBy((int)offset.x, (int)offset.y); -} - - -//! converts a region from screen to local coordinate system -void -View::ConvertFromScreen(BRegion* region) const -{ - BPoint offset(0.0, 0.0); - ConvertFromScreen(&offset); - - region->OffsetBy((int)offset.x, (int)offset.y); + transform.AddOffset(offsetX, offsetY); } @@ -775,7 +612,7 @@ View::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) // local clipping to see which parts need invalidation IntRect oldVisibleBounds(newVisibleBounds); oldVisibleBounds.OffsetBy(-x, -y); - ConvertToScreen(&oldVisibleBounds); + LocalToScreenTransform().Apply(&oldVisibleBounds); ConvertToVisibleInTopView(&newVisibleBounds); @@ -788,7 +625,7 @@ View::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) IntRect oldVisibleBounds(Bounds()); IntRect newVisibleBounds(oldVisibleBounds); oldVisibleBounds.OffsetBy(-x, -y); - ConvertToScreen(&oldVisibleBounds); + LocalToScreenTransform().Apply(&oldVisibleBounds); // NOTE: using ConvertToVisibleInTopView() // instead of ConvertToScreen()! see below @@ -875,7 +712,7 @@ View::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) } } - ConvertToScreen(dirty); + LocalToScreenTransform().Apply(dirty); dirtyRegion->Include(dirty); } fWindow->RecycleRegion(dirty); @@ -1138,6 +975,18 @@ View::SetPicture(ServerPicture* picture) } +void +View::BlendAllLayers() +{ + if (fPicture == NULL) + return; + Layer* layer = dynamic_cast(fPicture); + if (layer == NULL) + return; + BlendLayer(layer); +} + + void View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, BRegion* windowContentClipping, bool deep) @@ -1171,7 +1020,7 @@ View::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, // draw view bitmap // TODO: support other options! BRect rect = fBitmapDestination; - ConvertToScreenForDrawing(&rect); + PenToScreenTransform().Apply(&rect); align_rect_to_pixels(&rect); @@ -1406,7 +1255,7 @@ View::AddTokensForViewsInRegion(BPrivate::PortLink& link, BRegion& region, // This check will prevent descending the view hierarchy // any further than necessary IntRect screenBounds(Bounds()); - ConvertToScreen(&screenBounds); + LocalToScreenTransform().Apply(&screenBounds); if (!region.Intersects((clipping_rect)screenBounds)) return; @@ -1537,7 +1386,7 @@ View::ScreenAndUserClipping(BRegion* windowContentClipping, bool force) const if (fScreenAndUserClipping == NULL) return fScreenClipping; - ConvertToScreen(fScreenAndUserClipping); + LocalToScreenTransform().Apply(fScreenAndUserClipping); fScreenAndUserClipping->IntersectWith( &_ScreenClipping(windowContentClipping, force)); return *fScreenAndUserClipping; @@ -1578,7 +1427,7 @@ View::_ScreenClipping(BRegion* windowContentClipping, bool force) const { if (!fScreenClippingValid || force) { fScreenClipping = fLocalClipping; - ConvertToScreen(&fScreenClipping); + LocalToScreenTransform().Apply(&fScreenClipping); // see if parts of our bounds are hidden underneath // the parent, the local clipping does not account for this diff --git a/src/servers/app/View.h b/src/servers/app/View.h index b2291afe47..fbf66409b9 100644 --- a/src/servers/app/View.h +++ b/src/servers/app/View.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2014, Haiku, Inc. + * Copyright (c) 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT license. * * Authors: @@ -9,12 +9,13 @@ * Stephan Aßmus * Marcus Overhagen * Adrien Destugues + * Julian Harnath */ #ifndef VIEW_H #define VIEW_H -#include "DrawingContext.h" +#include "Canvas.h" #include "IntRect.h" #include @@ -37,7 +38,7 @@ class ServerCursor; class ServerPicture; class BGradient; -class View: public DrawingContext { +class View: public Canvas { public: View(IntRect frame, IntPoint scrollingOffset, const char* name, int32 token, @@ -111,31 +112,7 @@ public: View* ViewAt(const BPoint& where); - // coordinate conversion - void ConvertToParent(BPoint* point) const; - void ConvertToParent(IntPoint* point) const; - void ConvertToParent(BRect* rect) const; - void ConvertToParent(IntRect* rect) const; - void ConvertToParent(BRegion* region) const; - - void ConvertFromParent(BPoint* point) const; - void ConvertFromParent(IntPoint* point) const; - void ConvertFromParent(BRect* rect) const; - void ConvertFromParent(IntRect* rect) const; - void ConvertFromParent(BRegion* region) const; - - void ConvertToScreen(BPoint* point) const; - void ConvertToScreen(IntPoint* point) const; - void ConvertToScreen(BRect* rect) const; - void ConvertToScreen(IntRect* rect) const; - void ConvertToScreen(BRegion* region) const; - - void ConvertFromScreen(BPoint* point) const; - void ConvertFromScreen(IntPoint* point) const; - void ConvertFromScreen(BRect* rect) const; - void ConvertFromScreen(IntRect* rect) const; - void ConvertFromScreen(BRegion* region) const; - +public: void MoveBy(int32 dx, int32 dy, BRegion* dirtyRegion); @@ -180,6 +157,8 @@ public: ServerPicture* Picture() const { return fPicture; } + void BlendAllLayers(); + // for background clearing virtual void Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, @@ -235,6 +214,11 @@ public: #endif protected: + virtual void _LocalToScreenTransform( + SimpleTransform& transform) const; + virtual void _ScreenToLocalTransform( + SimpleTransform& transform) const; + BRegion& _ScreenClipping(BRegion* windowContentClipping, bool force = false) const; void _MoveScreenClipping(int32 x, int32 y, diff --git a/src/servers/app/Window.cpp b/src/servers/app/Window.cpp index 117e67a564..8af42bd2bd 100644 --- a/src/servers/app/Window.cpp +++ b/src/servers/app/Window.cpp @@ -817,7 +817,7 @@ Window::InvalidateView(View* view, BRegion& viewRegion) if (!fContentRegionValid) _UpdateContentRegion(); - view->ConvertToScreen(&viewRegion); + view->LocalToScreenTransform().Apply(&viewRegion); viewRegion.IntersectWith(&VisibleContentRegion()); if (viewRegion.CountRects() > 0) { viewRegion.IntersectWith( diff --git a/src/servers/app/WorkspacesView.cpp b/src/servers/app/WorkspacesView.cpp index be53497cec..2e4aabac75 100644 --- a/src/servers/app/WorkspacesView.cpp +++ b/src/servers/app/WorkspacesView.cpp @@ -90,7 +90,7 @@ WorkspacesView::_WorkspaceAt(int32 i) _GetGrid(columns, rows); BRect frame = Bounds(); - ConvertToScreen(&frame); + LocalToScreenTransform().Apply(&frame); int32 width = frame.IntegerWidth() / columns; int32 height = frame.IntegerHeight() / rows; @@ -356,7 +356,7 @@ void WorkspacesView::_Invalidate() const { BRect frame = Bounds(); - ConvertToScreen(&frame); + LocalToScreenTransform().Apply(&frame); BRegion region(frame); Window()->MarkContentDirty(region); @@ -385,7 +385,7 @@ WorkspacesView::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, drawingEngine->ConstrainClippingRegion(&gridRegion); BRect frame = Bounds(); - ConvertToScreen(&frame); + LocalToScreenTransform().Apply(&frame); // horizontal lines diff --git a/src/servers/app/drawing/AlphaMask.cpp b/src/servers/app/drawing/AlphaMask.cpp index 2a595fca86..fc5e00659d 100644 --- a/src/servers/app/drawing/AlphaMask.cpp +++ b/src/servers/app/drawing/AlphaMask.cpp @@ -1,10 +1,11 @@ /* - * Copyright 2014, Haiku, Inc. + * Copyright 2014-2015, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: * Adrien Destugues * Stephan Aßmus + * Julian Harnath */ @@ -12,168 +13,75 @@ #include "BitmapHWInterface.h" #include "BitmapManager.h" -#include "DrawingContext.h" +#include "Canvas.h" #include "DrawingEngine.h" +#include "PictureBoundingBoxPlayer.h" #include "ServerBitmap.h" #include "ServerPicture.h" +#include "Shape.h" -AlphaMask::AlphaMask(ServerPicture* picture, bool inverse, BPoint origin, - const DrawState& drawState) +// #pragma mark - AlphaMask + + +AlphaMask::AlphaMask(AlphaMask* previousMask, bool inverse) : - fPreviousMask(NULL), - - fPicture(picture), + fPreviousMask(previousMask), + fBounds(), + fViewOrigin(), fInverse(inverse), - fOrigin(origin), - fDrawState(drawState), - - fViewBounds(), - fViewOffset(), - - fCachedBitmap(NULL), - fCachedBounds(), - fCachedOffset(), - + fBackgroundOpacity(0), + fBits(NULL), fBuffer(), - fCachedMask(), - fScanline(fCachedMask) + fMask(), + fScanline(fMask) +{ +} + + +AlphaMask::AlphaMask(uint8 backgroundOpacity) + : + fPreviousMask(), + fBounds(), + fViewOrigin(), + fInverse(false), + fBackgroundOpacity(backgroundOpacity), + fBits(NULL), + fBuffer(), + fMask(), + fScanline(fMask) { - fPicture->AcquireReference(); } AlphaMask::~AlphaMask() { - fPicture->ReleaseReference(); - delete[] fCachedBitmap; - SetPrevious(NULL); + delete[] fBits; } -void -AlphaMask::Update(BRect bounds, BPoint offset) +IntPoint +AlphaMask::SetViewOrigin(IntPoint viewOrigin) { - fViewBounds = bounds; - fViewOffset = offset; - + if (viewOrigin == fViewOrigin) + return fViewOrigin; + + IntPoint oldOrigin = fViewOrigin; + fViewOrigin = viewOrigin; + + _AttachMaskToBuffer(); + if (fPreviousMask != NULL) - fPreviousMask->Update(bounds, offset); -} + fPreviousMask->SetViewOrigin(viewOrigin); - -void -AlphaMask::SetPrevious(AlphaMask* mask) -{ - // Since multiple DrawStates can point to the same AlphaMask, - // don't accept ourself as the "previous" mask on the state stack. - if (mask == this || mask == fPreviousMask) - return; - - if (mask != NULL) - mask->AcquireReference(); - if (fPreviousMask != NULL) - fPreviousMask->ReleaseReference(); - fPreviousMask = mask; -} - - -scanline_unpacked_masked_type* -AlphaMask::Generate() -{ - if (fPicture == NULL || !fViewBounds.IsValid()) - return NULL; - - // See if a cached bitmap can be used. Don't use it when the view offset - // or bounds have changed. - if (fCachedBitmap != NULL - && fViewBounds == fCachedBounds && fViewOffset == fCachedOffset) { - return &fScanline; - } - - uint32 width = fViewBounds.IntegerWidth() + 1; - uint32 height = fViewBounds.IntegerHeight() + 1; - - if (fViewBounds != fCachedBounds || fCachedBitmap == NULL) { - delete[] fCachedBitmap; - fCachedBitmap = new(std::nothrow) uint8[width * height]; - } - - // If rendering the picture fails, we will draw without any clipping. - ServerBitmap* bitmap = _RenderPicture(); - if (bitmap == NULL || fCachedBitmap == NULL) { - fBuffer.attach(NULL, 0, 0, 0); - return NULL; - } - - uint8* bits = bitmap->Bits(); - uint32 bytesPerRow = bitmap->BytesPerRow(); - uint8* row = bits; - uint8* pixel = fCachedBitmap; - - // Let any previous masks also regenerate themselves. Updating the cached - // mask bitmap is only necessary after the view size changed or the - // scrolling offset, which definitely affects any masks of lower states - // as well, so it works recursively until the bottom mask is regenerated. - bool transferBitmap = true; - if (fPreviousMask != NULL) { - fPreviousMask->Generate(); - if (fPreviousMask->fCachedBitmap != NULL) { - uint8* previousBits = fPreviousMask->fCachedBitmap; - for (uint32 y = 0; y < height; y++) { - for (uint32 x = 0; x < width; x++) { - if (previousBits[0] != 0) { - if (fInverse) - pixel[0] = 255 - row[3]; - else - pixel[0] = row[3]; - pixel[0] = pixel[0] * previousBits[0] / 255; - } else - pixel[0] = 0; - previousBits++; - pixel++; - row += 4; - } - bits += bytesPerRow; - row = bits; - } - transferBitmap = false; - } - } - - if (transferBitmap) { - for (uint32 y = 0; y < height; y++) { - for (uint32 x = 0; x < width; x++) { - if (fInverse) - pixel[0] = 255 - row[3]; - else - pixel[0] = row[3]; - pixel++; - row += 4; - } - bits += bytesPerRow; - row = bits; - } - } - - bitmap->ReleaseReference(); - - fCachedBounds = fViewBounds; - fCachedOffset = fViewOffset; - - fBuffer.attach(fCachedBitmap, width, height, width); - - fCachedMask.attach(fBuffer, fViewOffset.x + fOrigin.x, - fViewOffset.y + fOrigin.y, fInverse ? 255 : 0); - - return &fScanline; + return oldOrigin; } ServerBitmap* -AlphaMask::_RenderPicture() const +AlphaMask::_CreateTemporaryBitmap(BRect bounds) const { - UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(fViewBounds, + UtilityBitmap* bitmap = new(std::nothrow) UtilityBitmap(bounds, B_RGBA32, 0); if (bitmap == NULL) return NULL; @@ -183,33 +91,272 @@ AlphaMask::_RenderPicture() const return NULL; } - // Clear the bitmap with the transparent color - memset(bitmap->Bits(), 0, bitmap->BitsLength()); + memset(bitmap->Bits(), fBackgroundOpacity, bitmap->BitsLength()); + + return bitmap; +} + + +void +AlphaMask::_Generate() +{ + ServerBitmap* const bitmap = _RenderSource(); + BReference bitmapRef(bitmap, true); + if (bitmap == NULL) { + _SetNoClipping(); + return; + } + + const int32 width = fBounds.IntegerWidth() + 1; + const int32 height = fBounds.IntegerHeight() + 1; + + delete[] fBits; + fBits = new(std::nothrow) uint8[width * height]; + + uint8* source = bitmap->Bits(); + uint8* destination = fBits; + uint32 numPixels = width * height; + + if (fPreviousMask != NULL) { + int32 previousStartX = fBounds.left - fPreviousMask->fBounds.left; + int32 previousStartY = fBounds.top - fPreviousMask->fBounds.top; + if (previousStartX < 0) + previousStartX = 0; + if (previousStartY < 0) + previousStartY = 0; + + for (int32 y = previousStartY; y < previousStartY + height; y++) { + uint8* previousRow = fPreviousMask->fBuffer.row_ptr(y); + for (int32 x = previousStartX; x < previousStartX + width; x++) { + uint8 sourceAlpha = fInverse ? 255 - source[3] : source[3]; + *destination = sourceAlpha * previousRow[x] / 255; + destination++; + source += 4; + } + } + } else { + while (numPixels--) { + *destination = fInverse ? 255 - source[3] : source[3]; + destination++; + source += 4; + } + } + + fBuffer.attach(fBits, width, height, width); + _AttachMaskToBuffer(); +} + + +void +AlphaMask::_SetNoClipping() +{ + fBuffer.attach(NULL, 0, 0, 0); + _AttachMaskToBuffer(); +} + + +void +AlphaMask::_AttachMaskToBuffer() +{ + uint8 outsideOpacity = fInverse ? 255 - fBackgroundOpacity + : fBackgroundOpacity; + + AlphaMask* previousMask = fPreviousMask; + while (previousMask != NULL && outsideOpacity != 0) { + uint8 previousOutsideOpacity = previousMask->fInverse + ? 255 - previousMask->fBackgroundOpacity + : previousMask->fBackgroundOpacity; + outsideOpacity = outsideOpacity * previousOutsideOpacity / 255; + previousMask = previousMask->fPreviousMask; + } + + const IntPoint maskOffset = _Offset(); + const int32 offsetX = fBounds.left + maskOffset.x + fViewOrigin.x; + const int32 offsetY = fBounds.top + maskOffset.y + fViewOrigin.y; + + fMask.attach(fBuffer, offsetX, offsetY, outsideOpacity); +} + + +// #pragma mark - UniformAlphaMask + + +UniformAlphaMask::UniformAlphaMask(uint8 opacity) + : + AlphaMask(opacity) +{ + fBounds.Set(0, 0, 0, 0); + _SetNoClipping(); +} + + +ServerBitmap* +UniformAlphaMask::_RenderSource() +{ + return NULL; +} + + +IntPoint +UniformAlphaMask::_Offset() +{ + return IntPoint(0, 0); +} + + +// #pragma mark - VectorAlphaMask + + +template +VectorAlphaMask::VectorAlphaMask(AlphaMask* previousMask, + BPoint where, bool inverse) + : + AlphaMask(previousMask, inverse), + fWhere(where) +{ +} + + +template +ServerBitmap* +VectorAlphaMask::_RenderSource() +{ + fBounds = static_cast(this)->DetermineBoundingBox(); + if (fPreviousMask != NULL) + fBounds = fBounds & fPreviousMask->fBounds; + if (!fBounds.IsValid()) + return NULL; + + ServerBitmap* bitmap = _CreateTemporaryBitmap(fBounds); + if (bitmap == NULL) + return NULL; // Render the picture to the bitmap BitmapHWInterface interface(bitmap); DrawingEngine* engine = interface.CreateDrawingEngine(); if (engine == NULL) { - delete bitmap; + bitmap->ReleaseReference(); return NULL; } + engine->SetRendererOffset(fBounds.left, fBounds.top); - OffscreenContext context(engine, fDrawState); - context.PushState(); + OffscreenCanvas canvas(engine, + static_cast(this)->GetDrawState()); + + DrawState* const drawState = canvas.CurrentState(); + drawState->SetDrawingMode(B_OP_ALPHA); + drawState->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE); + drawState->SetDrawingModeLocked(true); + canvas.PushState(); if (engine->LockParallelAccess()) { - // FIXME ConstrainClippingRegion docs says passing NULL disables - // all clipping. This doesn't work and will crash in Painter. BRegion clipping; - clipping.Include(fViewBounds); + clipping.Set((clipping_rect)fBounds); engine->ConstrainClippingRegion(&clipping); - fPicture->Play(&context); + static_cast(this)->DrawVectors(&canvas); engine->UnlockParallelAccess(); } - context.PopState(); delete engine; return bitmap; } + +template +IntPoint +VectorAlphaMask::_Offset() +{ + return fWhere; +} + + + +// #pragma mark - PictureAlphaMask + + +PictureAlphaMask::PictureAlphaMask(AlphaMask* previousMask, + ServerPicture* picture, const DrawState& drawState, BPoint where, + bool inverse) + : + VectorAlphaMask(previousMask, where, inverse), + fPicture(picture), + fDrawState(new DrawState(drawState)) +{ + _Generate(); +} + + +PictureAlphaMask::~PictureAlphaMask() +{ + delete fDrawState; +} + + +void +PictureAlphaMask::DrawVectors(Canvas* canvas) +{ + fPicture->Play(canvas); +} + + +BRect +PictureAlphaMask::DetermineBoundingBox() const +{ + BRect boundingBox; + PictureBoundingBoxPlayer::Play(fPicture, fDrawState, &boundingBox); + + if (!boundingBox.IsValid()) + return boundingBox; + + // Round up and add an additional 2 pixels on the bottom/right to + // compensate for the various types of rounding used in Painter. + boundingBox.left = floorf(boundingBox.left); + boundingBox.right = ceilf(boundingBox.right) + 2; + boundingBox.top = floorf(boundingBox.top); + boundingBox.bottom = ceilf(boundingBox.bottom) + 2; + + return boundingBox; +} + + +const DrawState& +PictureAlphaMask::GetDrawState() const +{ + return *fDrawState; +} + + +// #pragma mark - ShapeAlphaMask + + +ShapeAlphaMask::ShapeAlphaMask(AlphaMask* previousMask, BPoint where, + bool inverse) + : + VectorAlphaMask(previousMask, where, inverse), + fDrawState() +{ + _Generate(); +} + + +void +ShapeAlphaMask::DrawVectors(Canvas* canvas) +{ + // TODO +} + + +BRect +ShapeAlphaMask::DetermineBoundingBox() const +{ + // TODO + return BRect(0, 0, 0, 0); +} + + +const DrawState& +ShapeAlphaMask::GetDrawState() const +{ + return fDrawState; +} diff --git a/src/servers/app/drawing/AlphaMask.h b/src/servers/app/drawing/AlphaMask.h index 661ec7768e..4b9d2ffcb3 100644 --- a/src/servers/app/drawing/AlphaMask.h +++ b/src/servers/app/drawing/AlphaMask.h @@ -1,5 +1,5 @@ /* - * Copyright 2014, Haiku, Inc. + * Copyright 2014-2015, Haiku, Inc. * Distributed under the terms of the MIT License. */ @@ -13,47 +13,123 @@ #include "DrawState.h" #include "drawing/Painter/defines.h" +#include "IntRect.h" +class BShape; class ServerBitmap; class ServerPicture; +// #pragma mark - AlphaMask + + class AlphaMask : public BReferenceable { public: - AlphaMask(ServerPicture* mask, bool inverse, - BPoint origin, const DrawState& drawState); - ~AlphaMask(); + AlphaMask(AlphaMask* previousMask, + bool inverse); + AlphaMask(uint8 backgroundOpacity); + virtual ~AlphaMask(); - void Update(BRect bounds, BPoint offset); + IntPoint SetViewOrigin(IntPoint viewOrigin); - void SetPrevious(AlphaMask* mask); + scanline_unpacked_masked_type* Scanline() + { return &fScanline; } - scanline_unpacked_masked_type* Generate(); + agg::clipped_alpha_mask* Mask() + { return &fMask; } + +protected: + ServerBitmap* _CreateTemporaryBitmap(BRect bounds) const; + void _Generate(); + void _SetNoClipping(); private: - ServerBitmap* _RenderPicture() const; + virtual ServerBitmap* _RenderSource() = 0; + virtual IntPoint _Offset() = 0; + void _AttachMaskToBuffer(); + +public: + BReference fPreviousMask; + IntRect fBounds; private: - AlphaMask* fPreviousMask; - - ServerPicture* fPicture; + IntPoint fViewOrigin; const bool fInverse; - BPoint fOrigin; - DrawState fDrawState; - - BRect fViewBounds; - BPoint fViewOffset; - - uint8* fCachedBitmap; - BRect fCachedBounds; - BPoint fCachedOffset; + uint8 fBackgroundOpacity; + uint8* fBits; agg::rendering_buffer fBuffer; - agg::clipped_alpha_mask fCachedMask; + agg::clipped_alpha_mask fMask; scanline_unpacked_masked_type fScanline; }; +class UniformAlphaMask : public AlphaMask { +public: + UniformAlphaMask(uint8 opacity); + +private: + virtual ServerBitmap* _RenderSource(); + virtual IntPoint _Offset(); +}; + + +// #pragma mark - VectorAlphaMask + + +template +class VectorAlphaMask : public AlphaMask { +public: + VectorAlphaMask(AlphaMask* previousMask, + BPoint where, bool inverse); + +private: + virtual ServerBitmap* _RenderSource(); + virtual IntPoint _Offset(); + +protected: + BPoint fWhere; +}; + + +// #pragma mark - PictureAlphaMask + + +class PictureAlphaMask : public VectorAlphaMask { +public: + PictureAlphaMask(AlphaMask* previousMask, + ServerPicture* picture, + const DrawState& drawState, BPoint where, + bool inverse); + virtual ~PictureAlphaMask(); + + void DrawVectors(Canvas* canvas); + BRect DetermineBoundingBox() const; + const DrawState& GetDrawState() const; + +private: + BReference fPicture; + DrawState* fDrawState; +}; + + +// #pragma mark - ShapeAlphaMask + + +class ShapeAlphaMask : public VectorAlphaMask { +public: + ShapeAlphaMask(AlphaMask* previousMask, + BPoint where, bool inverse); + + void DrawVectors(Canvas* canvas); + BRect DetermineBoundingBox() const; + const DrawState& GetDrawState() const; + +private: + DrawState fDrawState; +}; + + #endif // ALPHA_MASK_H diff --git a/src/servers/app/drawing/DWindowHWInterface.cpp b/src/servers/app/drawing/DWindowHWInterface.cpp index a903ab5b1a..70e535c7b5 100644 --- a/src/servers/app/drawing/DWindowHWInterface.cpp +++ b/src/servers/app/drawing/DWindowHWInterface.cpp @@ -694,7 +694,8 @@ DWindowHWInterface::SetMode(const display_mode& mode) // has not been created either, but we need one to display // a real BWindow in the test environment. // be_app->Run() needs to be called in another thread - BApplication* app = new BApplication("application/x-vnd.haiku-app-server"); + BApplication* app = new BApplication( + "application/x-vnd.Haiku-test-app_server"); app->Unlock(); thread_id appThread = spawn_thread(run_app_thread, "app thread", diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index b5c425a97a..147a359b18 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2001-2009, Haiku, Inc. + * Copyright 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus + * Julian Harnath */ @@ -1070,7 +1071,7 @@ DrawingEngine::FillRegion(BRegion& r) doInSoftware = false; } } - + if (doInSoftware && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0 && fPainter->Pattern() == B_SOLID_HIGH @@ -1555,6 +1556,13 @@ DrawingEngine::CopyRect(BRect src, int32 xOffset, int32 yOffset) const } +void +DrawingEngine::SetRendererOffset(int32 offsetX, int32 offsetY) +{ + fPainter->SetRendererOffset(offsetX, offsetY); +} + + void DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height, uint32 bytesPerRow, int32 xOffset, int32 yOffset) const diff --git a/src/servers/app/drawing/DrawingEngine.h b/src/servers/app/drawing/DrawingEngine.h index dd15db25c3..d9a0896614 100644 --- a/src/servers/app/drawing/DrawingEngine.h +++ b/src/servers/app/drawing/DrawingEngine.h @@ -1,11 +1,12 @@ /* - * Copyright 2001-2009, Haiku, Inc. + * Copyright 2001-2015, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm * Gabe Yoder * Stephan Aßmus + * Julian Harnath */ #ifndef DRAWING_ENGINE_H_ #define DRAWING_ENGINE_H_ @@ -187,6 +188,8 @@ public: virtual BRect CopyRect(BRect rect, int32 xOffset, int32 yOffset) const; + void SetRendererOffset(int32 offsetX, int32 offsetY); + private: void _CopyRect(uint8* bits, uint32 width, uint32 height, uint32 bytesPerRow, diff --git a/src/servers/app/drawing/Painter/Jamfile b/src/servers/app/drawing/Painter/Jamfile index 47703c8b28..61bf424b85 100644 --- a/src/servers/app/drawing/Painter/Jamfile +++ b/src/servers/app/drawing/Painter/Jamfile @@ -12,6 +12,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes UseBuildFeatureHeaders freetype ; SEARCH_SOURCE += [ FDirName $(SUBDIR) drawing_modes ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) bitmap_painter ] ; local PAINTER_ARCH_SOURCES ; if $(TARGET_ARCH) = x86 { @@ -29,6 +30,9 @@ StaticLibrary libpainter.a : # drawing_modes PixelFormat.cpp + # bitmap_painter + BitmapPainter.cpp + AGGTextRenderer.cpp $(PAINTER_ARCH_SOURCES) diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 9ac646eb6c..e382b8dfd4 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -2,6 +2,7 @@ * Copyright 2009, Christian Packmann. * Copyright 2008, Andrej Spielmann . * Copyright 2005-2014, Stephan Aßmus . + * Copyright 2015, Julian Harnath * All rights reserved. Distributed under the terms of the MIT License. */ @@ -53,6 +54,7 @@ #include #include "AlphaMask.h" +#include "BitmapPainter.h" #include "DrawingMode.h" #include "GlobalSubpixelSettings.h" #include "PatternHandler.h" @@ -85,19 +87,29 @@ using std::nothrow; #define CHECK_CLIPPING if (!fValidClipping) return BRect(0, 0, -1, -1); #define CHECK_CLIPPING_NO_RETURN if (!fValidClipping) return; -// Defines for SIMD support. -#define APPSERVER_SIMD_MMX (1 << 0) -#define APPSERVER_SIMD_SSE (1 << 1) -// Prototypes for assembler routines -extern "C" { - void bilinear_scale_xloop_mmxsse(const uint8* src, void* dst, - void* xWeights, uint32 xmin, uint32 xmax, uint32 wTop, uint32 srcBPR); -} +// Shortcuts for accessing internal data +#define fBuffer fInternal.fBuffer +#define fPixelFormat fInternal.fPixelFormat +#define fBaseRenderer fInternal.fBaseRenderer +#define fUnpackedScanline fInternal.fUnpackedScanline +#define fPackedScanline fInternal.fPackedScanline +#define fRasterizer fInternal.fRasterizer +#define fRenderer fInternal.fRenderer +#define fRendererBin fInternal.fRendererBin +#define fSubpixPackedScanline fInternal.fSubpixPackedScanline +#define fSubpixUnpackedScanline fInternal.fSubpixUnpackedScanline +#define fSubpixRasterizer fInternal.fSubpixRasterizer +#define fSubpixRenderer fInternal.fSubpixRenderer +#define fMaskedUnpackedScanline fInternal.fMaskedUnpackedScanline +#define fClippedAlphaMask fInternal.fClippedAlphaMask +#define fPath fInternal.fPath +#define fCurve fInternal.fCurve + static uint32 detect_simd(); -static uint32 sSIMDFlags = detect_simd(); +uint32 gSIMDFlags = detect_simd(); /*! Detect SIMD flags for use in AppServer. Checks all CPUs in the system @@ -169,23 +181,7 @@ detect_simd() Painter::Painter() : - fBuffer(), - fPixelFormat(fBuffer, &fPatternHandler), - fBaseRenderer(fPixelFormat), - fUnpackedScanline(), - fPackedScanline(), - fRasterizer(), - fRenderer(fBaseRenderer), - fRendererBin(fBaseRenderer), - fSubpixPackedScanline(), - fSubpixUnpackedScanline(), - fSubpixRasterizer(), - fSubpixRenderer(fBaseRenderer), - fMaskedUnpackedScanline(NULL), - - fPath(), - fCurve(fPath), - + fInternal(fPatternHandler), fSubpixelPrecise(false), fValidClipping(false), fDrawingText(false), @@ -284,6 +280,7 @@ Painter::SetDrawState(const DrawState* state, int32 xOffset, int32 yOffset) // and messed up the state. For other graphics state changes, the // Painter methods are used directly, so this function is much less // speed critical than it used to be. + SetTransform(state->CombinedTransform(), xOffset, yOffset); SetPenSize(state->PenSize()); @@ -292,10 +289,13 @@ Painter::SetDrawState(const DrawState* state, int32 xOffset, int32 yOffset) fSubpixelPrecise = state->SubPixelPrecise(); - if (state->GetAlphaMask() != NULL) - fMaskedUnpackedScanline = state->GetAlphaMask()->Generate(); - else + if (state->GetAlphaMask() != NULL) { + fMaskedUnpackedScanline = state->GetAlphaMask()->Scanline(); + fClippedAlphaMask = state->GetAlphaMask()->Mask(); + } else { fMaskedUnpackedScanline = NULL; + fClippedAlphaMask = NULL; + } // any of these conditions means we need to use a different drawing // mode instance @@ -667,7 +667,7 @@ Painter::DrawPolygon(BPoint* p, int32 numPts, bool filled, bool closed) const bool centerOffset = !filled && fIdentityTransform && fmodf(fPenSize, 2.0) != 0.0; - + fPath.remove_all(); _Align(p, centerOffset); @@ -1430,27 +1430,11 @@ Painter::DrawBitmap(const ServerBitmap* bitmap, BRect bitmapRect, BRect touched = TransformAlignAndClipRect(viewRect); - if (bitmap && bitmap->IsValid() && touched.IsValid()) { - // the native bitmap coordinate system - BRect actualBitmapRect(bitmap->Bounds()); - - TRACE("Painter::DrawBitmap()\n"); - TRACE(" actualBitmapRect = (%.1f, %.1f) - (%.1f, %.1f)\n", - actualBitmapRect.left, actualBitmapRect.top, - actualBitmapRect.right, actualBitmapRect.bottom); - TRACE(" bitmapRect = (%.1f, %.1f) - (%.1f, %.1f)\n", - bitmapRect.left, bitmapRect.top, bitmapRect.right, - bitmapRect.bottom); - TRACE(" viewRect = (%.1f, %.1f) - (%.1f, %.1f)\n", - viewRect.left, viewRect.top, viewRect.right, viewRect.bottom); - - agg::rendering_buffer srcBuffer; - srcBuffer.attach(bitmap->Bits(), bitmap->Width(), bitmap->Height(), - bitmap->BytesPerRow()); - - _DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, - bitmapRect, viewRect, options); + if (touched.IsValid()) { + BitmapPainter bitmapPainter(this, bitmap, options); + bitmapPainter.Draw(bitmapRect, viewRect); } + return touched; } @@ -1508,6 +1492,13 @@ Painter::InvertRect(const BRect& r) const } +void +Painter::SetRendererOffset(int32 offsetX, int32 offsetY) +{ + fBaseRenderer.set_offset(offsetX, offsetY); +} + + // #pragma mark - private @@ -1634,61 +1625,6 @@ Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3, bool fill) const } -// copy_bitmap_row_cmap8_copy -static inline void -copy_bitmap_row_cmap8_copy(uint8* dst, const uint8* src, int32 numPixels, - const rgb_color* colorMap) -{ - uint32* d = (uint32*)dst; - const uint8* s = src; - while (numPixels--) { - const rgb_color c = colorMap[*s++]; - *d++ = (c.alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue); - } -} - - -// copy_bitmap_row_cmap8_over -static inline void -copy_bitmap_row_cmap8_over(uint8* dst, const uint8* src, int32 numPixels, - const rgb_color* colorMap) -{ - uint32* d = (uint32*)dst; - const uint8* s = src; - while (numPixels--) { - const rgb_color c = colorMap[*s++]; - if (c.alpha) - *d = (c.alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue); - d++; - } -} - - -// copy_bitmap_row_bgr32_copy -static inline void -copy_bitmap_row_bgr32_copy(uint8* dst, const uint8* src, int32 numPixels, - const rgb_color* colorMap) -{ - memcpy(dst, src, numPixels * 4); -} - - -// copy_bitmap_row_bgr32_over -static inline void -copy_bitmap_row_bgr32_over(uint8* dst, const uint8* src, int32 numPixels, - const rgb_color* colorMap) -{ - uint32* d = (uint32*)dst; - uint32* s = (uint32*)src; - while (numPixels--) { - if (*s != B_TRANSPARENT_MAGIC_RGBA32) - *(uint32*)d = *(uint32*)s; - d++; - s++; - } -} - - void Painter::_IterateShapeData(const int32& opCount, const uint32* opList, const int32& ptCount, const BPoint* points, @@ -1756,935 +1692,6 @@ Painter::_IterateShapeData(const int32& opCount, const uint32* opList, } -// copy_bitmap_row_bgr32_alpha -static inline void -copy_bitmap_row_bgr32_alpha(uint8* dst, const uint8* src, int32 numPixels, - const rgb_color* colorMap) -{ - uint32* d = (uint32*)dst; - int32 bytes = numPixels * 4; - uint8 buffer[bytes]; - uint8* b = buffer; - while (numPixels--) { - if (src[3] == 255) { - *(uint32*)b = *(uint32*)src; - } else { - *(uint32*)b = *d; - b[0] = ((src[0] - b[0]) * src[3] + (b[0] << 8)) >> 8; - b[1] = ((src[1] - b[1]) * src[3] + (b[1] << 8)) >> 8; - b[2] = ((src[2] - b[2]) * src[3] + (b[2] << 8)) >> 8; - } - d++; - b += 4; - src += 4; - } - memcpy(dst, buffer, bytes); -} - - -// _TransparentMagicToAlpha -template -void -Painter::_TransparentMagicToAlpha(sourcePixel* buffer, uint32 width, - uint32 height, uint32 sourceBytesPerRow, sourcePixel transparentMagic, - BBitmap* output) const -{ - uint8* sourceRow = (uint8*)buffer; - uint8* destRow = (uint8*)output->Bits(); - uint32 destBytesPerRow = output->BytesPerRow(); - - for (uint32 y = 0; y < height; y++) { - sourcePixel* pixel = (sourcePixel*)sourceRow; - uint32* destPixel = (uint32*)destRow; - for (uint32 x = 0; x < width; x++, pixel++, destPixel++) { - if (*pixel == transparentMagic) - *destPixel &= 0x00ffffff; - } - - sourceRow += sourceBytesPerRow; - destRow += destBytesPerRow; - } -} - - -// _DrawBitmap -void -Painter::_DrawBitmap(agg::rendering_buffer& srcBuffer, color_space format, - BRect actualBitmapRect, BRect bitmapRect, BRect viewRect, - uint32 options) const -{ - if (!fValidClipping - || !bitmapRect.IsValid() || !bitmapRect.Intersects(actualBitmapRect) - || !viewRect.IsValid()) { - return; - } - - if (!fSubpixelPrecise) { - align_rect_to_pixels(&bitmapRect); - align_rect_to_pixels(&viewRect); - } - - TRACE("Painter::_DrawBitmap()\n"); - TRACE(" bitmapRect = (%.1f, %.1f) - (%.1f, %.1f)\n", - bitmapRect.left, bitmapRect.top, bitmapRect.right, bitmapRect.bottom); - TRACE(" viewRect = (%.1f, %.1f) - (%.1f, %.1f)\n", - viewRect.left, viewRect.top, viewRect.right, viewRect.bottom); - - double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1); - double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1); - - if (xScale == 0.0 || yScale == 0.0) - return; - - // compensate for the lefttop offset the actualBitmapRect might have - // actualBitmapRect has the right size, but put it at B_ORIGIN - // bitmapRect is already in good coordinates - actualBitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top); - - // constrain rect to passed bitmap bounds - // and transfer the changes to the viewRect with the right scale - if (bitmapRect.left < actualBitmapRect.left) { - float diff = actualBitmapRect.left - bitmapRect.left; - viewRect.left += diff * xScale; - bitmapRect.left = actualBitmapRect.left; - } - if (bitmapRect.top < actualBitmapRect.top) { - float diff = actualBitmapRect.top - bitmapRect.top; - viewRect.top += diff * yScale; - bitmapRect.top = actualBitmapRect.top; - } - if (bitmapRect.right > actualBitmapRect.right) { - float diff = bitmapRect.right - actualBitmapRect.right; - viewRect.right -= diff * xScale; - bitmapRect.right = actualBitmapRect.right; - } - if (bitmapRect.bottom > actualBitmapRect.bottom) { - float diff = bitmapRect.bottom - actualBitmapRect.bottom; - viewRect.bottom -= diff * yScale; - bitmapRect.bottom = actualBitmapRect.bottom; - } - - double xOffset = viewRect.left - bitmapRect.left; - double yOffset = viewRect.top - bitmapRect.top; - - // optimized code path for B_CMAP8 and no scale - if (xScale == 1.0 && yScale == 1.0 && fIdentityTransform - && fMaskedUnpackedScanline == NULL) { - if (format == B_CMAP8) { - if (fDrawingMode == B_OP_COPY) { - _DrawBitmapNoScale32(copy_bitmap_row_cmap8_copy, 1, - srcBuffer, (int32)xOffset, (int32)yOffset, viewRect); - return; - } - if (fDrawingMode == B_OP_OVER) { - _DrawBitmapNoScale32(copy_bitmap_row_cmap8_over, 1, - srcBuffer, (int32)xOffset, (int32)yOffset, viewRect); - return; - } - } else if (format == B_RGB32) { - if (fDrawingMode == B_OP_OVER) { - _DrawBitmapNoScale32(copy_bitmap_row_bgr32_over, 4, - srcBuffer, (int32)xOffset, (int32)yOffset, viewRect); - return; - } - } - } - - BBitmap* temp = NULL; - ObjectDeleter tempDeleter; - - if ((format != B_RGBA32 && format != B_RGB32) - || (format == B_RGB32 && fDrawingMode != B_OP_COPY -#if 1 -// Enabling this would make the behavior compatible to BeOS, which -// treats B_RGB32 bitmaps as B_RGB*A*32 bitmaps in B_OP_ALPHA - unlike in -// all other drawing modes, where B_TRANSPARENT_MAGIC_RGBA32 is handled. -// B_RGB32 bitmaps therefore don't draw correctly on BeOS if they actually -// use this color, unless the alpha channel contains 255 for all other -// pixels, which is inconsistent. - && fDrawingMode != B_OP_ALPHA -#endif - )) { - temp = new (nothrow) BBitmap(actualBitmapRect, B_BITMAP_NO_SERVER_LINK, - B_RGBA32); - if (temp == NULL) { - fprintf(stderr, "Painter::_DrawBitmap() - " - "out of memory for creating temporary conversion bitmap\n"); - return; - } - - tempDeleter.SetTo(temp); - - status_t err = temp->ImportBits(srcBuffer.buf(), - srcBuffer.height() * srcBuffer.stride(), - srcBuffer.stride(), 0, format); - if (err < B_OK) { - fprintf(stderr, "Painter::_DrawBitmap() - " - "colorspace conversion failed: %s\n", strerror(err)); - return; - } - - // the original bitmap might have had some of the - // transaparent magic colors set that we now need to - // make transparent in our RGBA32 bitmap again. - switch (format) { - case B_RGB32: - _TransparentMagicToAlpha((uint32 *)srcBuffer.buf(), - srcBuffer.width(), srcBuffer.height(), - srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA32, - temp); - break; - - // TODO: not sure if this applies to B_RGBA15 too. It - // should not because B_RGBA15 actually has an alpha - // channel itself and it should have been preserved - // when importing the bitmap. Maybe it applies to - // B_RGB16 though? - case B_RGB15: - _TransparentMagicToAlpha((uint16 *)srcBuffer.buf(), - srcBuffer.width(), srcBuffer.height(), - srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA15, - temp); - break; - - default: - break; - } - - srcBuffer.attach((uint8*)temp->Bits(), - (uint32)actualBitmapRect.IntegerWidth() + 1, - (uint32)actualBitmapRect.IntegerHeight() + 1, - temp->BytesPerRow()); - } - - // maybe we can use an optimized version if there is no scale - if (xScale == 1.0 && yScale == 1.0 && fIdentityTransform - && fMaskedUnpackedScanline == NULL) { - if (fDrawingMode == B_OP_COPY) { - _DrawBitmapNoScale32(copy_bitmap_row_bgr32_copy, 4, srcBuffer, - (int32)xOffset, (int32)yOffset, viewRect); - return; - } - if (fDrawingMode == B_OP_OVER || (fDrawingMode == B_OP_ALPHA - && fAlphaSrcMode == B_PIXEL_ALPHA - && fAlphaFncMode == B_ALPHA_OVERLAY)) { - _DrawBitmapNoScale32(copy_bitmap_row_bgr32_alpha, 4, srcBuffer, - (int32)xOffset, (int32)yOffset, viewRect); - return; - } - } - - if (fDrawingMode == B_OP_COPY && fIdentityTransform - && fMaskedUnpackedScanline == NULL) { - if ((options & B_FILTER_BITMAP_BILINEAR) != 0) { - _DrawBitmapBilinearCopy32(srcBuffer, xOffset, yOffset, xScale, - yScale, viewRect); - } else { - _DrawBitmapNearestNeighborCopy32(srcBuffer, xOffset, yOffset, - xScale, yScale, viewRect); - } - return; - } - - // for all other cases (non-optimized drawing mode or scaled drawing) - _DrawBitmapGeneric32(srcBuffer, xOffset, yOffset, xScale, yScale, viewRect, - options); -} - - -#define DEBUG_DRAW_BITMAP 0 - - -// _DrawBitmapNoScale32 -template -void -Painter::_DrawBitmapNoScale32(F copyRowFunction, uint32 bytesPerSourcePixel, - agg::rendering_buffer& srcBuffer, int32 xOffset, int32 yOffset, - BRect viewRect) const -{ - // NOTE: this would crash if viewRect was large enough to read outside the - // bitmap, so make sure this is not the case before calling this function! - uint8* dst = fBuffer.row_ptr(0); - uint32 dstBPR = fBuffer.stride(); - - const uint8* src = srcBuffer.row_ptr(0); - uint32 srcBPR = srcBuffer.stride(); - - int32 left = (int32)viewRect.left; - int32 top = (int32)viewRect.top; - int32 right = (int32)viewRect.right; - int32 bottom = (int32)viewRect.bottom; - -#if DEBUG_DRAW_BITMAP -if (left - xOffset < 0 || left - xOffset >= (int32)srcBuffer.width() || - right - xOffset >= (int32)srcBuffer.width() || - top - yOffset < 0 || top - yOffset >= (int32)srcBuffer.height() || - bottom - yOffset >= (int32)srcBuffer.height()) { - - char message[256]; - sprintf(message, "reading outside of bitmap (%ld, %ld, %ld, %ld) " - "(%d, %d) (%ld, %ld)", - left - xOffset, top - yOffset, right - xOffset, bottom - yOffset, - srcBuffer.width(), srcBuffer.height(), xOffset, yOffset); - debugger(message); -} -#endif - - const rgb_color* colorMap = SystemPalette(); - - // copy rects, iterate over clipping boxes - fBaseRenderer.first_clip_box(); - do { - int32 x1 = max_c(fBaseRenderer.xmin(), left); - int32 x2 = min_c(fBaseRenderer.xmax(), right); - if (x1 <= x2) { - int32 y1 = max_c(fBaseRenderer.ymin(), top); - int32 y2 = min_c(fBaseRenderer.ymax(), bottom); - if (y1 <= y2) { - uint8* dstHandle = dst + y1 * dstBPR + x1 * 4; - const uint8* srcHandle = src + (y1 - yOffset) * srcBPR - + (x1 - xOffset) * bytesPerSourcePixel; - - for (; y1 <= y2; y1++) { - copyRowFunction(dstHandle, srcHandle, x2 - x1 + 1, colorMap); - - dstHandle += dstBPR; - srcHandle += srcBPR; - } - } - } - } while (fBaseRenderer.next_clip_box()); -} - - -// _DrawBitmapNearestNeighborCopy32 -void -Painter::_DrawBitmapNearestNeighborCopy32(agg::rendering_buffer& srcBuffer, - double xOffset, double yOffset, double xScale, double yScale, - BRect viewRect) const -{ - //bigtime_t now = system_time(); - uint32 dstWidth = viewRect.IntegerWidth() + 1; - uint32 dstHeight = viewRect.IntegerHeight() + 1; - uint32 srcWidth = srcBuffer.width(); - uint32 srcHeight = srcBuffer.height(); - - // Do not calculate more filter weights than necessary and also - // keep the stack based allocations reasonably sized - if (fClippingRegion->Frame().IntegerWidth() + 1 < (int32)dstWidth) - dstWidth = fClippingRegion->Frame().IntegerWidth() + 1; - if (fClippingRegion->Frame().IntegerHeight() + 1 < (int32)dstHeight) - dstHeight = fClippingRegion->Frame().IntegerHeight() + 1; - - // When calculating less filter weights than specified by viewRect, - // we need to compensate the offset. - uint32 filterWeightXIndexOffset = 0; - uint32 filterWeightYIndexOffset = 0; - if (fClippingRegion->Frame().left > viewRect.left) { - filterWeightXIndexOffset = (int32)(fClippingRegion->Frame().left - - viewRect.left); - } - if (fClippingRegion->Frame().top > viewRect.top) { - filterWeightYIndexOffset = (int32)(fClippingRegion->Frame().top - - viewRect.top); - } - - // should not pose a problem with stack overflows - // (needs around 6Kb for 1920x1200) - uint16 xIndices[dstWidth]; - uint16 yIndices[dstHeight]; - - // Extract the cropping information for the source bitmap, - // If only a part of the source bitmap is to be drawn with scale, - // the offset will be different from the viewRect left top corner. - int32 xBitmapShift = (int32)(viewRect.left - xOffset); - int32 yBitmapShift = (int32)(viewRect.top - yOffset); - - for (uint32 i = 0; i < dstWidth; i++) { - // index into source - uint16 index = (uint16)((i + filterWeightXIndexOffset) * srcWidth - / (srcWidth * xScale)); - // round down to get the left pixel - xIndices[i] = index; - // handle cropped source bitmap - xIndices[i] += xBitmapShift; - // precompute index for 32 bit pixels - xIndices[i] *= 4; - } - - for (uint32 i = 0; i < dstHeight; i++) { - // index into source - uint16 index = (uint16)((i + filterWeightYIndexOffset) * srcHeight - / (srcHeight * yScale)); - // round down to get the top pixel - yIndices[i] = index; - // handle cropped source bitmap - yIndices[i] += yBitmapShift; - } -//printf("X: %d ... %d, %d (%ld or %f)\n", -// xIndices[0], xIndices[dstWidth - 2], xIndices[dstWidth - 1], dstWidth, -// srcWidth * xScale); -//printf("Y: %d ... %d, %d (%ld or %f)\n", -// yIndices[0], yIndices[dstHeight - 2], yIndices[dstHeight - 1], dstHeight, -// srcHeight * yScale); - - const int32 left = (int32)viewRect.left; - const int32 top = (int32)viewRect.top; - const int32 right = (int32)viewRect.right; - const int32 bottom = (int32)viewRect.bottom; - - const uint32 dstBPR = fBuffer.stride(); - - // iterate over clipping boxes - fBaseRenderer.first_clip_box(); - do { - const int32 x1 = max_c(fBaseRenderer.xmin(), left); - const int32 x2 = min_c(fBaseRenderer.xmax(), right); - if (x1 > x2) - continue; - - int32 y1 = max_c(fBaseRenderer.ymin(), top); - int32 y2 = min_c(fBaseRenderer.ymax(), bottom); - if (y1 > y2) - continue; - - // buffer offset into destination - uint8* dst = fBuffer.row_ptr(y1) + x1 * 4; - - // x and y are needed as indeces into the wheight arrays, so the - // offset into the target buffer needs to be compensated - const int32 xIndexL = x1 - left - filterWeightXIndexOffset; - const int32 xIndexR = x2 - left - filterWeightXIndexOffset; - y1 -= top + filterWeightYIndexOffset; - y2 -= top + filterWeightYIndexOffset; - -//printf("x: %ld - %ld\n", xIndexL, xIndexR); -//printf("y: %ld - %ld\n", y1, y2); - - for (; y1 <= y2; y1++) { - // buffer offset into source (top row) - register const uint8* src = srcBuffer.row_ptr(yIndices[y1]); - // buffer handle for destination to be incremented per pixel - register uint32* d = (uint32*)dst; - - for (int32 x = xIndexL; x <= xIndexR; x++) { - *d = *(uint32*)(src + xIndices[x]); - d++; - } - dst += dstBPR; - } - } while (fBaseRenderer.next_clip_box()); - -//printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale, system_time() - now); -} - - -// _DrawBitmapBilinearCopy32 -void -Painter::_DrawBitmapBilinearCopy32(agg::rendering_buffer& srcBuffer, - double xOffset, double yOffset, double xScale, double yScale, - BRect viewRect) const -{ - //bigtime_t now = system_time(); - uint32 dstWidth = viewRect.IntegerWidth() + 1; - uint32 dstHeight = viewRect.IntegerHeight() + 1; - uint32 srcWidth = srcBuffer.width(); - uint32 srcHeight = srcBuffer.height(); - - // Do not calculate more filter weights than necessary and also - // keep the stack based allocations reasonably sized - if (fClippingRegion->Frame().IntegerWidth() + 1 < (int32)dstWidth) - dstWidth = fClippingRegion->Frame().IntegerWidth() + 1; - if (fClippingRegion->Frame().IntegerHeight() + 1 < (int32)dstHeight) - dstHeight = fClippingRegion->Frame().IntegerHeight() + 1; - - // When calculating less filter weights than specified by viewRect, - // we need to compensate the offset. - uint32 filterWeightXIndexOffset = 0; - uint32 filterWeightYIndexOffset = 0; - if (fClippingRegion->Frame().left > viewRect.left) { - filterWeightXIndexOffset = (int32)(fClippingRegion->Frame().left - - viewRect.left); - } - if (fClippingRegion->Frame().top > viewRect.top) { - filterWeightYIndexOffset = (int32)(fClippingRegion->Frame().top - - viewRect.top); - } - - struct FilterInfo { - uint16 index; // index into source bitmap row/column - uint16 weight; // weight of the pixel at index [0..255] - }; - -//#define FILTER_INFOS_ON_HEAP -#ifdef FILTER_INFOS_ON_HEAP - FilterInfo* xWeights = new (nothrow) FilterInfo[dstWidth]; - FilterInfo* yWeights = new (nothrow) FilterInfo[dstHeight]; - if (xWeights == NULL || yWeights == NULL) { - delete[] xWeights; - delete[] yWeights; - return; - } -#else - // stack based saves about 200µs on 1.85 GHz Core 2 Duo - // should not pose a problem with stack overflows - // (needs around 12Kb for 1920x1200) - FilterInfo xWeights[dstWidth]; - FilterInfo yWeights[dstHeight]; -#endif - - // Extract the cropping information for the source bitmap, - // If only a part of the source bitmap is to be drawn with scale, - // the offset will be different from the viewRect left top corner. - int32 xBitmapShift = (int32)(viewRect.left - xOffset); - int32 yBitmapShift = (int32)(viewRect.top - yOffset); - - for (uint32 i = 0; i < dstWidth; i++) { - // fractional index into source - // NOTE: It is very important to calculate the fractional index - // into the source pixel grid like this to prevent out of bounds - // access! It will result in the rightmost pixel of the destination - // to access the rightmost pixel of the source with a weighting - // of 255. This in turn will trigger an optimization in the loop - // that also prevents out of bounds access. - float index = (i + filterWeightXIndexOffset) * (srcWidth - 1) - / (srcWidth * xScale - 1); - // round down to get the left pixel - xWeights[i].index = (uint16)index; - xWeights[i].weight = 255 - (uint16)((index - xWeights[i].index) * 255); - // handle cropped source bitmap - xWeights[i].index += xBitmapShift; - // precompute index for 32 bit pixels - xWeights[i].index *= 4; - } - - for (uint32 i = 0; i < dstHeight; i++) { - // fractional index into source - // NOTE: It is very important to calculate the fractional index - // into the source pixel grid like this to prevent out of bounds - // access! It will result in the bottommost pixel of the destination - // to access the bottommost pixel of the source with a weighting - // of 255. This in turn will trigger an optimization in the loop - // that also prevents out of bounds access. - float index = (i + filterWeightYIndexOffset) * (srcHeight - 1) - / (srcHeight * yScale - 1); - // round down to get the top pixel - yWeights[i].index = (uint16)index; - yWeights[i].weight = 255 - (uint16)((index - yWeights[i].index) * 255); - // handle cropped source bitmap - yWeights[i].index += yBitmapShift; - } -//printf("X: %d/%d ... %d/%d, %d/%d (%ld)\n", -// xWeights[0].index, xWeights[0].weight, -// xWeights[dstWidth - 2].index, xWeights[dstWidth - 2].weight, -// xWeights[dstWidth - 1].index, xWeights[dstWidth - 1].weight, -// dstWidth); -//printf("Y: %d/%d ... %d/%d, %d/%d (%ld)\n", -// yWeights[0].index, yWeights[0].weight, -// yWeights[dstHeight - 2].index, yWeights[dstHeight - 2].weight, -// yWeights[dstHeight - 1].index, yWeights[dstHeight - 1].weight, -// dstHeight); - - const int32 left = (int32)viewRect.left; - const int32 top = (int32)viewRect.top; - const int32 right = (int32)viewRect.right; - const int32 bottom = (int32)viewRect.bottom; - - const uint32 dstBPR = fBuffer.stride(); - const uint32 srcBPR = srcBuffer.stride(); - - // Figure out which version of the code we want to use... - enum { - kOptimizeForLowFilterRatio = 0, - kUseDefaultVersion, - kUseSIMDVersion - }; - - int codeSelect = kUseDefaultVersion; - - uint32 neededSIMDFlags = APPSERVER_SIMD_MMX | APPSERVER_SIMD_SSE; - if ((sSIMDFlags & neededSIMDFlags) == neededSIMDFlags) - codeSelect = kUseSIMDVersion; - else { - if (xScale == yScale && (xScale == 1.5 || xScale == 2.0 - || xScale == 2.5 || xScale == 3.0)) { - codeSelect = kOptimizeForLowFilterRatio; - } - } - - // iterate over clipping boxes - fBaseRenderer.first_clip_box(); - do { - const int32 x1 = max_c(fBaseRenderer.xmin(), left); - const int32 x2 = min_c(fBaseRenderer.xmax(), right); - if (x1 > x2) - continue; - - int32 y1 = max_c(fBaseRenderer.ymin(), top); - int32 y2 = min_c(fBaseRenderer.ymax(), bottom); - if (y1 > y2) - continue; - - // buffer offset into destination - uint8* dst = fBuffer.row_ptr(y1) + x1 * 4; - - // x and y are needed as indeces into the wheight arrays, so the - // offset into the target buffer needs to be compensated - const int32 xIndexL = x1 - left - filterWeightXIndexOffset; - const int32 xIndexR = x2 - left - filterWeightXIndexOffset; - y1 -= top + filterWeightYIndexOffset; - y2 -= top + filterWeightYIndexOffset; - -//printf("x: %ld - %ld\n", xIndexL, xIndexR); -//printf("y: %ld - %ld\n", y1, y2); - - switch (codeSelect) { - case kOptimizeForLowFilterRatio: - { - // In this mode, we anticipate to hit many destination pixels - // that map directly to a source pixel, we have more branches - // in the inner loop but save time because of the special - // cases. If there are too few direct hit pixels, the branches - // only waste time. - for (; y1 <= y2; y1++) { - // cache the weight of the top and bottom row - const uint16 wTop = yWeights[y1].weight; - const uint16 wBottom = 255 - yWeights[y1].weight; - - // buffer offset into source (top row) - register const uint8* src - = srcBuffer.row_ptr(yWeights[y1].index); - // buffer handle for destination to be incremented per - // pixel - register uint8* d = dst; - - if (wTop == 255) { - for (int32 x = xIndexL; x <= xIndexR; x++) { - const uint8* s = src + xWeights[x].index; - // This case is important to prevent out - // of bounds access at bottom edge of the source - // bitmap. If the scale is low and integer, it will - // also help the speed. - if (xWeights[x].weight == 255) { - // As above, but to prevent out of bounds - // on the right edge. - *(uint32*)d = *(uint32*)s; - } else { - // Only the left and right pixels are - // interpolated, since the top row has 100% - // weight. - const uint16 wLeft = xWeights[x].weight; - const uint16 wRight = 255 - wLeft; - d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; - d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; - d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; - } - d += 4; - } - } else { - for (int32 x = xIndexL; x <= xIndexR; x++) { - const uint8* s = src + xWeights[x].index; - if (xWeights[x].weight == 255) { - // Prevent out of bounds access on the right - // edge or simply speed up. - const uint8* sBottom = s + srcBPR; - d[0] = (s[0] * wTop + sBottom[0] * wBottom) - >> 8; - d[1] = (s[1] * wTop + sBottom[1] * wBottom) - >> 8; - d[2] = (s[2] * wTop + sBottom[2] * wBottom) - >> 8; - } else { - // calculate the weighted sum of all four - // interpolated pixels - const uint16 wLeft = xWeights[x].weight; - const uint16 wRight = 255 - wLeft; - // left and right of top row - uint32 t0 = (s[0] * wLeft + s[4] * wRight) - * wTop; - uint32 t1 = (s[1] * wLeft + s[5] * wRight) - * wTop; - uint32 t2 = (s[2] * wLeft + s[6] * wRight) - * wTop; - - // left and right of bottom row - s += srcBPR; - t0 += (s[0] * wLeft + s[4] * wRight) * wBottom; - t1 += (s[1] * wLeft + s[5] * wRight) * wBottom; - t2 += (s[2] * wLeft + s[6] * wRight) * wBottom; - - d[0] = t0 >> 16; - d[1] = t1 >> 16; - d[2] = t2 >> 16; - } - d += 4; - } - } - dst += dstBPR; - } - break; - } - - case kUseDefaultVersion: - { - // In this mode we anticipate many pixels wich need filtering, - // there are no special cases for direct hit pixels except for - // the last column/row and the right/bottom corner pixel. - - // The last column/row handling does not need to be performed - // for all clipping rects! - int32 yMax = y2; - if (yWeights[yMax].weight == 255) - yMax--; - int32 xIndexMax = xIndexR; - if (xWeights[xIndexMax].weight == 255) - xIndexMax--; - - for (; y1 <= yMax; y1++) { - // cache the weight of the top and bottom row - const uint16 wTop = yWeights[y1].weight; - const uint16 wBottom = 255 - yWeights[y1].weight; - - // buffer offset into source (top row) - register const uint8* src - = srcBuffer.row_ptr(yWeights[y1].index); - // buffer handle for destination to be incremented per - // pixel - register uint8* d = dst; - - for (int32 x = xIndexL; x <= xIndexMax; x++) { - const uint8* s = src + xWeights[x].index; - // calculate the weighted sum of all four - // interpolated pixels - const uint16 wLeft = xWeights[x].weight; - const uint16 wRight = 255 - wLeft; - // left and right of top row - uint32 t0 = (s[0] * wLeft + s[4] * wRight) * wTop; - uint32 t1 = (s[1] * wLeft + s[5] * wRight) * wTop; - uint32 t2 = (s[2] * wLeft + s[6] * wRight) * wTop; - - // left and right of bottom row - s += srcBPR; - t0 += (s[0] * wLeft + s[4] * wRight) * wBottom; - t1 += (s[1] * wLeft + s[5] * wRight) * wBottom; - t2 += (s[2] * wLeft + s[6] * wRight) * wBottom; - d[0] = t0 >> 16; - d[1] = t1 >> 16; - d[2] = t2 >> 16; - d += 4; - } - // last column of pixels if necessary - if (xIndexMax < xIndexR) { - const uint8* s = src + xWeights[xIndexR].index; - const uint8* sBottom = s + srcBPR; - d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; - d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; - d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; - } - - dst += dstBPR; - } - - // last row of pixels if necessary - // buffer offset into source (bottom row) - register const uint8* src - = srcBuffer.row_ptr(yWeights[y2].index); - // buffer handle for destination to be incremented per pixel - register uint8* d = dst; - - if (yMax < y2) { - for (int32 x = xIndexL; x <= xIndexMax; x++) { - const uint8* s = src + xWeights[x].index; - const uint16 wLeft = xWeights[x].weight; - const uint16 wRight = 255 - wLeft; - d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; - d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; - d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; - d += 4; - } - } - - // pixel in bottom right corner if necessary - if (yMax < y2 && xIndexMax < xIndexR) { - const uint8* s = src + xWeights[xIndexR].index; - *(uint32*)d = *(uint32*)s; - } - break; - } - -#ifdef __INTEL__ - case kUseSIMDVersion: - { - // Basically the same as the "standard" mode, but we use SIMD - // routines for the processing of the single display lines. - - // The last column/row handling does not need to be performed - // for all clipping rects! - int32 yMax = y2; - if (yWeights[yMax].weight == 255) - yMax--; - int32 xIndexMax = xIndexR; - if (xWeights[xIndexMax].weight == 255) - xIndexMax--; - - for (; y1 <= yMax; y1++) { - // cache the weight of the top and bottom row - const uint16 wTop = yWeights[y1].weight; - const uint16 wBottom = 255 - yWeights[y1].weight; - - // buffer offset into source (top row) - const uint8* src = srcBuffer.row_ptr(yWeights[y1].index); - // buffer handle for destination to be incremented per - // pixel - uint8* d = dst; - bilinear_scale_xloop_mmxsse(src, dst, xWeights, xIndexL, - xIndexMax, wTop, srcBPR); - // increase pointer by processed pixels - d += (xIndexMax - xIndexL + 1) * 4; - - // last column of pixels if necessary - if (xIndexMax < xIndexR) { - const uint8* s = src + xWeights[xIndexR].index; - const uint8* sBottom = s + srcBPR; - d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; - d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; - d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; - } - - dst += dstBPR; - } - - // last row of pixels if necessary - // buffer offset into source (bottom row) - register const uint8* src - = srcBuffer.row_ptr(yWeights[y2].index); - // buffer handle for destination to be incremented per pixel - register uint8* d = dst; - - if (yMax < y2) { - for (int32 x = xIndexL; x <= xIndexMax; x++) { - const uint8* s = src + xWeights[x].index; - const uint16 wLeft = xWeights[x].weight; - const uint16 wRight = 255 - wLeft; - d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; - d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; - d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; - d += 4; - } - } - - // pixel in bottom right corner if necessary - if (yMax < y2 && xIndexMax < xIndexR) { - const uint8* s = src + xWeights[xIndexR].index; - *(uint32*)d = *(uint32*)s; - } - break; - } -#endif // __INTEL__ - } - } while (fBaseRenderer.next_clip_box()); - -#ifdef FILTER_INFOS_ON_HEAP - delete[] xWeights; - delete[] yWeights; -#endif -//printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale, system_time() - now); -} - - -// _DrawBitmapGeneric32 -void -Painter::_DrawBitmapGeneric32(agg::rendering_buffer& srcBuffer, - double xOffset, double yOffset, double xScale, double yScale, - BRect viewRect, uint32 options) const -{ - TRACE("Painter::_DrawBitmapGeneric32()\n"); - TRACE(" offset: %.1f, %.1f\n", xOffset, yOffset); - TRACE(" scale: %.3f, %.3f\n", xScale, yScale); - TRACE(" viewRect: (%.1f, %.1f) - (%.1f, %.1f)\n", - viewRect.left, viewRect.top, viewRect.right, viewRect.bottom); - // AGG pipeline - - // pixel format attached to bitmap - typedef agg::pixfmt_bgra32 pixfmt_image; - pixfmt_image pixf_img(srcBuffer); - - agg::trans_affine srcMatrix; - // NOTE: R5 seems to ignore this offset when drawing bitmaps - // srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, - // -actualBitmapRect.top); - srcMatrix *= fTransform; - - agg::trans_affine imgMatrix; - imgMatrix *= agg::trans_affine_translation(xOffset - viewRect.left, - yOffset - viewRect.top); - imgMatrix *= agg::trans_affine_scaling(xScale, yScale); - imgMatrix *= agg::trans_affine_translation(viewRect.left, viewRect.top); - imgMatrix *= fTransform; - imgMatrix.invert(); - - // image interpolator - typedef agg::span_interpolator_linear<> interpolator_type; - interpolator_type interpolator(imgMatrix); - - // scanline allocator - agg::span_allocator spanAllocator; - - // image accessor attached to pixel format of bitmap - typedef agg::image_accessor_clone source_type; - source_type source(pixf_img); - - // clip to the current clipping region's frame - if (fIdentityTransform) - viewRect = viewRect & fClippingRegion->Frame(); - // convert to pixel coords (versus pixel indices) - viewRect.right++; - viewRect.bottom++; - - // path enclosing the bitmap - fPath.remove_all(); - fPath.move_to(viewRect.left, viewRect.top); - fPath.line_to(viewRect.right, viewRect.top); - fPath.line_to(viewRect.right, viewRect.bottom); - fPath.line_to(viewRect.left, viewRect.bottom); - fPath.close_polygon(); - - agg::conv_transform transformedPath(fPath, srcMatrix); - fRasterizer.reset(); - fRasterizer.add_path(transformedPath); - - if ((options & B_FILTER_BITMAP_BILINEAR) != 0) { - // image filter (bilinear) - typedef agg::span_image_filter_rgba_bilinear< - source_type, interpolator_type> span_gen_type; - span_gen_type spanGenerator(source, interpolator); - - // render the path with the bitmap as scanline fill - if (fMaskedUnpackedScanline != NULL) { - agg::render_scanlines_aa(fRasterizer, *fMaskedUnpackedScanline, - fBaseRenderer, spanAllocator, spanGenerator); - } else { - agg::render_scanlines_aa(fRasterizer, fUnpackedScanline, - fBaseRenderer, spanAllocator, spanGenerator); - } - } else { - // image filter (nearest neighbor) - typedef agg::span_image_filter_rgba_nn< - source_type, interpolator_type> span_gen_type; - span_gen_type spanGenerator(source, interpolator); - - // render the path with the bitmap as scanline fill - if (fMaskedUnpackedScanline != NULL) { - agg::render_scanlines_aa(fRasterizer, *fMaskedUnpackedScanline, - fBaseRenderer, spanAllocator, spanGenerator); - } else { - agg::render_scanlines_aa(fRasterizer, fUnpackedScanline, - fBaseRenderer, spanAllocator, spanGenerator); - } - } -} - - // _InvertRect32 void Painter::_InvertRect32(BRect r) const @@ -2939,7 +1946,7 @@ Painter::_RasterizePath(VertexSource& path, const BGradient& gradient) const _RasterizePath(path, gradient, gradientFunction, gradientTransform); break; } - + default: case BGradient::TYPE_NONE: GTRACE(("Painter::_FillPathGradient> type == TYPE_NONE/unkown\n")); @@ -3124,4 +2131,3 @@ Painter::_RasterizePath(VertexSource& path, const BGradient& gradient, gradientRenderer); } } - diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index 166de5b8b1..fc22b08193 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -1,6 +1,7 @@ /* * Copyright 2005-2007, Stephan Aßmus . * Copyright 2008, Andrej Spielmann . + * Copyright 2015, Julian Harnath * All rights reserved. Distributed under the terms of the MIT License. * * API to the Anti-Grain Geometry based "Painter" drawing backend. Manages @@ -13,6 +14,7 @@ #include "AGGTextRenderer.h" #include "FontManager.h" +#include "PainterAggInterface.h" #include "PatternHandler.h" #include "ServerFont.h" #include "Transformable.h" @@ -20,7 +22,6 @@ #include "defines.h" #include -#include #include #include @@ -42,6 +43,11 @@ class ServerBitmap; class ServerFont; +// Defines for SIMD support. +#define APPSERVER_SIMD_MMX (1 << 0) +#define APPSERVER_SIMD_SSE (1 << 1) + + class Painter { public: Painter(); @@ -67,6 +73,8 @@ public: inline bool IsIdentityTransform() const { return fIdentityTransform; } + const Transformable& Transform() const + { return fTransform; } void SetHighColor(const rgb_color& color); inline rgb_color HighColor() const @@ -243,6 +251,8 @@ public: inline BRect AlignAndClipRect(BRect rect) const; inline BRect AlignRect(BRect rect) const; + void SetRendererOffset(int32 offsetX, + int32 offsetY); private: float _Align(float coord, bool round, @@ -270,41 +280,6 @@ private: const BPoint& viewToScreenOffset, float viewScale) const; - template - void _TransparentMagicToAlpha(sourcePixel *buffer, - uint32 width, uint32 height, - uint32 sourceBytesPerRow, - sourcePixel transparentMagic, - BBitmap *output) const; - - void _DrawBitmap(agg::rendering_buffer& srcBuffer, - color_space format, - BRect actualBitmapRect, - BRect bitmapRect, BRect viewRect, - uint32 bitmapFlags) const; - template - void _DrawBitmapNoScale32( F copyRowFunction, - uint32 bytesPerSourcePixel, - agg::rendering_buffer& srcBuffer, - int32 xOffset, int32 yOffset, - BRect viewRect) const; - void _DrawBitmapNearestNeighborCopy32( - agg::rendering_buffer& srcBuffer, - double xOffset, double yOffset, - double xScale, double yScale, - BRect viewRect) const; - void _DrawBitmapBilinearCopy32( - agg::rendering_buffer& srcBuffer, - double xOffset, double yOffset, - double xScale, double yScale, - BRect viewRect) const; - void _DrawBitmapGeneric32( - agg::rendering_buffer& srcBuffer, - double xOffset, double yOffset, - double xScale, double yScale, - BRect viewRect, - uint32 bitmapFlags) const; - void _InvertRect32(BRect r) const; void _BlendRect32(const BRect& r, const rgb_color& c) const; @@ -353,33 +328,12 @@ private: int gradientStop = 100) const; private: - mutable agg::rendering_buffer fBuffer; + class BitmapPainter; - // AGG rendering and rasterization classes - pixfmt fPixelFormat; - mutable renderer_base fBaseRenderer; + friend class BitmapPainter; // needed only for gcc2 - // Regular drawing mode: pixel-aligned, no alpha masking - mutable scanline_unpacked_type fUnpackedScanline; - mutable scanline_packed_type fPackedScanline; - mutable rasterizer_type fRasterizer; - mutable renderer_type fRenderer; - - // Fast mode: no antialiasing needed (horizontal/vertical lines, ...) - mutable renderer_bin_type fRendererBin; - - // Subpixel mode - mutable scanline_packed_subpix_type fSubpixPackedScanline; - mutable scanline_unpacked_subpix_type fSubpixUnpackedScanline; - mutable rasterizer_subpix_type fSubpixRasterizer; - mutable renderer_subpix_type fSubpixRenderer; - - // Alpha-Masked mode: for ClipToPicture - // (this uses the standard rasterizer and renderer) - mutable scanline_unpacked_masked_type* fMaskedUnpackedScanline; - - mutable agg::path_storage fPath; - mutable agg::conv_curve fCurve; +private: + mutable PainterAggInterface fInternal; // for internal coordinate rounding/transformation bool fSubpixelPrecise : 1; diff --git a/src/servers/app/drawing/Painter/PainterAggInterface.h b/src/servers/app/drawing/Painter/PainterAggInterface.h new file mode 100644 index 0000000000..2f4e6ea16e --- /dev/null +++ b/src/servers/app/drawing/Painter/PainterAggInterface.h @@ -0,0 +1,69 @@ +/* + * Copyright 2005-2007, Stephan Aßmus . + * Copyright 2008, Andrej Spielmann . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef PAINTER_DATA_H +#define PAINTER_DATA_H + + +#include "defines.h" + +#include + + +struct PainterAggInterface { + PainterAggInterface(PatternHandler& patternHandler) + : + fBuffer(), + fPixelFormat(fBuffer, &patternHandler), + fBaseRenderer(fPixelFormat), + fUnpackedScanline(), + fPackedScanline(), + fRasterizer(), + fRenderer(fBaseRenderer), + fRendererBin(fBaseRenderer), + fSubpixPackedScanline(), + fSubpixUnpackedScanline(), + fSubpixRasterizer(), + fSubpixRenderer(fBaseRenderer), + fMaskedUnpackedScanline(NULL), + fClippedAlphaMask(NULL), + fPath(), + fCurve(fPath) + { + } + + agg::rendering_buffer fBuffer; + + // AGG rendering and rasterization classes + pixfmt fPixelFormat; + renderer_base fBaseRenderer; + + // Regular drawing mode: pixel-aligned, no alpha masking + scanline_unpacked_type fUnpackedScanline; + scanline_packed_type fPackedScanline; + rasterizer_type fRasterizer; + renderer_type fRenderer; + + // Fast mode: no antialiasing needed (horizontal/vertical lines, ...) + renderer_bin_type fRendererBin; + + // Subpixel mode + scanline_packed_subpix_type fSubpixPackedScanline; + scanline_unpacked_subpix_type fSubpixUnpackedScanline; + rasterizer_subpix_type fSubpixRasterizer; + renderer_subpix_type fSubpixRenderer; + + // Alpha-Masked mode: for ClipToPicture + // (this uses the standard rasterizer and renderer) + scanline_unpacked_masked_type* fMaskedUnpackedScanline; + agg::clipped_alpha_mask* fClippedAlphaMask; + + agg::path_storage fPath; + agg::conv_curve fCurve; +}; + + +#endif // PAINTER_DATA_H diff --git a/src/servers/app/drawing/Painter/agg_clipped_alpha_mask.h b/src/servers/app/drawing/Painter/agg_clipped_alpha_mask.h index 59c77740e9..08e34a251c 100644 --- a/src/servers/app/drawing/Painter/agg_clipped_alpha_mask.h +++ b/src/servers/app/drawing/Painter/agg_clipped_alpha_mask.h @@ -23,7 +23,7 @@ namespace agg public: typedef int8u cover_type; enum cover_scale_e - { + { cover_shift = 8, cover_none = 0, cover_full = 255 @@ -44,46 +44,13 @@ namespace agg void combine_hspan(int x, int y, cover_type* dst, int num_pix) const { - x -= m_xOffset; - y -= m_yOffset; - - int xmax = m_rbuf->width() - 1; - int ymax = m_rbuf->height() - 1; - int count = num_pix; cover_type* covers = dst; - if(y < 0 || y > ymax) - { - memset(dst, m_outside, num_pix * sizeof(cover_type)); + bool has_inside = _set_outside(x, y, covers, count); + if (!has_inside) return; - } - if(x < 0) - { - count += x; - if(count <= 0) - { - memset(dst, m_outside, num_pix * sizeof(cover_type)); - return; - } - memset(covers, m_outside, -x * sizeof(cover_type)); - covers -= x; - x = 0; - } - - if(x + count > xmax) - { - int rest = x + count - xmax - 1; - count -= rest; - if(count <= 0) - { - memset(dst, m_outside, num_pix * sizeof(cover_type)); - return; - } - memset(covers + count, m_outside, rest * sizeof(cover_type)); - } - const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; do { @@ -95,6 +62,67 @@ namespace agg while(--count); } + void get_hspan(int x, int y, cover_type* dst, int num_pix) const + { + int count = num_pix; + cover_type* covers = dst; + + bool has_inside = _set_outside(x, y, covers, count); + if (!has_inside) + return; + + const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset; + memcpy(covers, mask, count); + } + + private: + bool _set_outside(int& x, int& y, cover_type*& covers, + int& count) const + { + x -= m_xOffset; + y -= m_yOffset; + + int xmax = m_rbuf->width() - 1; + int ymax = m_rbuf->height() - 1; + + int num_pix = count; + cover_type* dst = covers; + + if(y < 0 || y > ymax) + { + memset(dst, m_outside, num_pix * sizeof(cover_type)); + return false; + } + + if(x < 0) + { + count += x; + if(count <= 0) + { + memset(dst, m_outside, num_pix * sizeof(cover_type)); + return false; + } + memset(covers, m_outside, -x * sizeof(cover_type)); + covers -= x; + x = 0; + } + + if(x + count > xmax) + { + int rest = x + count - xmax - 1; + count -= rest; + if(count <= 0) + { + memset(dst, m_outside, num_pix * sizeof(cover_type)); + return false; + } + memset(covers + count, m_outside, rest * sizeof(cover_type)); + } + + return true; + } + + private: int m_xOffset; int m_yOffset; diff --git a/src/servers/app/drawing/Painter/agg_renderer_region.h b/src/servers/app/drawing/Painter/agg_renderer_region.h index e761129744..faf0664fc2 100644 --- a/src/servers/app/drawing/Painter/agg_renderer_region.h +++ b/src/servers/app/drawing/Painter/agg_renderer_region.h @@ -1,6 +1,7 @@ /* * Copyright 2005-2006, Stephan Aßmus . * Copyright 2008, Andrej Spielmann . + * Copyright 2015, Julian Harnath * All rights reserved. Distributed under the terms of the MIT License. * * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com) @@ -36,7 +37,9 @@ namespace agg m_ren(ren), m_region(NULL), m_curr_cb(0), - m_bounds(m_ren.xmin(), m_ren.ymin(), m_ren.xmax(), m_ren.ymax()) + m_bounds(m_ren.xmin(), m_ren.ymin(), m_ren.xmax(), m_ren.ymax()), + m_offset_x(0), + m_offset_y(0) { } @@ -49,11 +52,15 @@ namespace agg unsigned height() const { return m_ren.height(); } //-------------------------------------------------------------------- - const rect_i& clip_box() const { return m_ren.clip_box(); } - int xmin() const { return m_ren.xmin(); } - int ymin() const { return m_ren.ymin(); } - int xmax() const { return m_ren.xmax(); } - int ymax() const { return m_ren.ymax(); } + const rect_i& clip_box() const { return m_bounds; } + int xmin() const { return translate_from_base_ren_x( + m_ren.xmin()); } + int ymin() const { return translate_from_base_ren_y( + m_ren.ymin()); } + int xmax() const { return translate_from_base_ren_x( + m_ren.xmax()); } + int ymax() const { return translate_from_base_ren_y( + m_ren.ymax()); } //-------------------------------------------------------------------- const rect_i& bounding_clip_box() const { return m_bounds; } @@ -69,7 +76,12 @@ namespace agg if(m_region && m_region->CountRects() > 0) { clipping_rect cb = m_region->RectAtInt(0); - m_ren.clip_box_naked(cb.left, cb.top, cb.right, cb.bottom); + translate_to_base_ren(cb); + m_ren.clip_box_naked( + cb.left, + cb.top, + cb.right, + cb.bottom); } else m_ren.clip_box_naked(0, 0, -1, -1); @@ -81,7 +93,12 @@ namespace agg if(m_region && (int)(++m_curr_cb) < m_region->CountRects()) { clipping_rect cb = m_region->RectAtInt(m_curr_cb); - m_ren.clip_box_naked(cb.left, cb.top, cb.right, cb.bottom); + translate_to_base_ren(cb); + m_ren.clip_box_naked( + cb.left, + cb.top, + cb.right, + cb.bottom); return true; } return false; @@ -94,6 +111,7 @@ namespace agg m_region = NULL; m_curr_cb = 0; m_bounds = m_ren.clip_box(); + translate_from_base_ren(m_bounds); } //-------------------------------------------------------------------- @@ -117,6 +135,68 @@ namespace agg } } + //-------------------------------------------------------------------- + void set_offset(int offset_x, int offset_y) + { + m_offset_x = offset_x; + m_offset_y = offset_y; + + if (m_region == NULL) { + m_bounds = m_ren.clip_box(); + translate_from_base_ren(m_bounds); + } + } + + //-------------------------------------------------------------------- + void translate_to_base_ren_x(int& x) + { + x -= m_offset_x; + } + + void translate_to_base_ren_y(int& y) + { + y -= m_offset_y; + } + + void translate_to_base_ren(int& x, int&y) + { + x -= m_offset_x; + y -= m_offset_y; + } + + void translate_to_base_ren(clipping_rect& clip) + { + clip.left -= m_offset_x; + clip.right -= m_offset_x; + clip.top -= m_offset_y; + clip.bottom -= m_offset_y; + } + + //-------------------------------------------------------------------- + int translate_from_base_ren_x(int x) const + { + return x + m_offset_x; + } + + int translate_from_base_ren_y(int y) const + { + return y + m_offset_y; + } + + void translate_from_base_ren(int& x, int& y) + { + x += m_offset_x; + y += m_offset_y; + } + + void translate_from_base_ren(rect_i& rect) + { + rect.x1 += m_offset_x; + rect.x2 += m_offset_x; + rect.y1 += m_offset_y; + rect.y2 += m_offset_y; + } + //-------------------------------------------------------------------- void clear(const color_type& c) { @@ -126,6 +206,8 @@ namespace agg //-------------------------------------------------------------------- void copy_pixel(int x, int y, const color_type& c) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -141,6 +223,8 @@ namespace agg //-------------------------------------------------------------------- void blend_pixel(int x, int y, const color_type& c, cover_type cover) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -156,6 +240,8 @@ namespace agg //-------------------------------------------------------------------- color_type pixel(int x, int y) const { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -171,6 +257,9 @@ namespace agg //-------------------------------------------------------------------- void copy_hline(int x1, int y, int x2, const color_type& c) { + translate_to_base_ren(x1, y); + translate_to_base_ren_x(x2); + first_clip_box(); do { @@ -182,6 +271,9 @@ namespace agg //-------------------------------------------------------------------- void copy_vline(int x, int y1, int y2, const color_type& c) { + translate_to_base_ren(x, y1); + translate_to_base_ren_y(y2); + first_clip_box(); do { @@ -194,6 +286,9 @@ namespace agg void blend_hline(int x1, int y, int x2, const color_type& c, cover_type cover) { + translate_to_base_ren(x1, y); + translate_to_base_ren_x(x2); + first_clip_box(); do { @@ -201,11 +296,14 @@ namespace agg } while(next_clip_box()); } - + //-------------------------------------------------------------------- void blend_vline(int x, int y1, int y2, const color_type& c, cover_type cover) { + translate_to_base_ren(x, y1); + translate_to_base_ren_y(y2); + first_clip_box(); do { @@ -217,6 +315,9 @@ namespace agg //-------------------------------------------------------------------- void copy_bar(int x1, int y1, int x2, int y2, const color_type& c) { + translate_to_base_ren(x1, y1); + translate_to_base_ren(x2, y2); + first_clip_box(); do { @@ -229,6 +330,9 @@ namespace agg void blend_bar(int x1, int y1, int x2, int y2, const color_type& c, cover_type cover) { + translate_to_base_ren(x1, y1); + translate_to_base_ren(x2, y2); + first_clip_box(); do { @@ -242,6 +346,8 @@ namespace agg void blend_solid_hspan(int x, int y, int len, const color_type& c, const cover_type* covers) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -254,6 +360,8 @@ namespace agg void blend_solid_hspan_subpix(int x, int y, int len, const color_type& c, const cover_type* covers) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -266,6 +374,8 @@ namespace agg void blend_solid_vspan(int x, int y, int len, const color_type& c, const cover_type* covers) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -280,6 +390,8 @@ namespace agg const cover_type* covers, cover_type cover = cover_full) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -294,6 +406,8 @@ namespace agg const cover_type* covers, cover_type cover = cover_full) { + translate_to_base_ren(x, y); + first_clip_box(); do { @@ -308,6 +422,7 @@ namespace agg const cover_type* covers, cover_type cover = cover_full) { + translate_to_base_ren(x, y); m_ren.blend_color_hspan_no_clip(x, y, len, colors, covers, cover); } @@ -317,6 +432,7 @@ namespace agg const cover_type* covers, cover_type cover = cover_full) { + translate_to_base_ren(x, y); m_ren.blend_color_vspan_no_clip(x, y, len, colors, covers, cover); } @@ -326,6 +442,7 @@ namespace agg int x_to=0, int y_to=0) { + translate_to_base_ren(x_to, y_to); first_clip_box(); do { @@ -343,6 +460,9 @@ namespace agg BRegion* m_region; unsigned m_curr_cb; rect_i m_bounds; + + int m_offset_x; + int m_offset_y; }; diff --git a/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp b/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp new file mode 100644 index 0000000000..d22e8c0e62 --- /dev/null +++ b/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.cpp @@ -0,0 +1,338 @@ +/* + * Copyright 2009, Christian Packmann. + * Copyright 2008, Andrej Spielmann . + * Copyright 2005-2014, Stephan Aßmus . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include "BitmapPainter.h" + +#include + +#include +#include +#include + +#include "DrawBitmapBilinear.h" +#include "DrawBitmapGeneric.h" +#include "DrawBitmapNearestNeighbor.h" +#include "DrawBitmapNoScale.h" +#include "drawing_support.h" +#include "ServerBitmap.h" +#include "SystemPalette.h" + + +// #define TRACE_BITMAP_PAINTER +#ifdef TRACE_BITMAP_PAINTER +# define TRACE(x...) printf(x) +#else +# define TRACE(x...) +#endif + + +Painter::BitmapPainter::BitmapPainter(const Painter* painter, + const ServerBitmap* bitmap, uint32 options) + : + fPainter(painter), + fStatus(B_NO_INIT), + fOptions(options) +{ + if (bitmap == NULL || !bitmap->IsValid()) + return; + + fBitmapBounds = bitmap->Bounds(); + fBitmapBounds.OffsetBy(-fBitmapBounds.left, -fBitmapBounds.top); + // Compensate for the lefttop offset the bitmap bounds might have + // It has the right size, but put it at B_ORIGIN + + fColorSpace = bitmap->ColorSpace(); + + fBitmap.attach(bitmap->Bits(), bitmap->Width(), bitmap->Height(), + bitmap->BytesPerRow()); + + fStatus = B_OK; +} + + +void +Painter::BitmapPainter::Draw(const BRect& sourceRect, + const BRect& destinationRect) +{ + using namespace BitmapPainterPrivate; + + if (fStatus != B_OK) + return; + + TRACE("BitmapPainter::Draw()\n"); + TRACE(" bitmapBounds = (%.1f, %.1f) - (%.1f, %.1f)\n", + bitmapBounds.left, bitmapBounds.top, + bitmapBounds.right, bitmapBounds.bottom); + TRACE(" sourceRect = (%.1f, %.1f) - (%.1f, %.1f)\n", + sourceRect.left, sourceRect.top, + sourceRect.right, sourceRect.bottom); + TRACE(" destinationRect = (%.1f, %.1f) - (%.1f, %.1f)\n", + destinationRect.left, destinationRect.top, + destinationRect.right, destinationRect.bottom); + + bool success = _DetermineTransform(sourceRect, destinationRect); + if (!success) + return; + + // optimized version for no scale in CMAP8 or RGB32 OP_OVER + if (!_HasScale() && !_HasAffineTransform() && !_HasAlphaMask()) { + if (fColorSpace == B_CMAP8) { + if (fPainter->fDrawingMode == B_OP_COPY) { + DrawBitmapNoScale drawNoScale; + drawNoScale.Draw(fPainter->fInternal, fBitmap, 1, fOffset, + fDestinationRect); + return; + } + if (fPainter->fDrawingMode == B_OP_OVER) { + DrawBitmapNoScale drawNoScale; + drawNoScale.Draw(fPainter->fInternal, fBitmap, 1, fOffset, + fDestinationRect); + return; + } + } else if (fColorSpace == B_RGB32) { + if (fPainter->fDrawingMode == B_OP_OVER) { + DrawBitmapNoScale drawNoScale; + drawNoScale.Draw(fPainter->fInternal, fBitmap, 4, fOffset, + fDestinationRect); + return; + } + } + } + + ObjectDeleter convertedBitmapDeleter; + _ConvertColorSpace(convertedBitmapDeleter); + + // optimized version if there is no scale + if (!_HasScale() && !_HasAffineTransform() && !_HasAlphaMask()) { + if (fPainter->fDrawingMode == B_OP_COPY) { + DrawBitmapNoScale drawNoScale; + drawNoScale.Draw(fPainter->fInternal, fBitmap, 4, fOffset, + fDestinationRect); + return; + } + if (fPainter->fDrawingMode == B_OP_OVER + || (fPainter->fDrawingMode == B_OP_ALPHA + && fPainter->fAlphaSrcMode == B_PIXEL_ALPHA + && fPainter->fAlphaFncMode == B_ALPHA_OVERLAY)) { + DrawBitmapNoScale drawNoScale; + drawNoScale.Draw(fPainter->fInternal, fBitmap, 4, fOffset, + fDestinationRect); + return; + } + } + + if (!_HasScale() && !_HasAffineTransform() && _HasAlphaMask()) { + if (fPainter->fDrawingMode == B_OP_COPY) { + DrawBitmapNoScale drawNoScale; + drawNoScale.Draw(fPainter->fInternal, fBitmap, 4, fOffset, + fDestinationRect); + return; + } + } + + // bilinear and nearest-neighbor scaled, OP_COPY only + if (fPainter->fDrawingMode == B_OP_COPY + && !_HasAffineTransform() && !_HasAlphaMask()) { + if ((fOptions & B_FILTER_BITMAP_BILINEAR) != 0) { + DrawBitmapBilinear drawBilinear; + drawBilinear.Draw(fPainter, fPainter->fInternal, + fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect); + } else { + DrawBitmapNearestNeighborCopy::Draw(fPainter, fPainter->fInternal, + fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect); + } + return; + } + + if (fPainter->fDrawingMode == B_OP_ALPHA + && fPainter->fAlphaSrcMode == B_PIXEL_ALPHA + && fPainter->fAlphaFncMode == B_ALPHA_OVERLAY + && !_HasAffineTransform() && !_HasAlphaMask() + && (fOptions & B_FILTER_BITMAP_BILINEAR) != 0) { + DrawBitmapBilinear drawBilinear; + drawBilinear.Draw(fPainter, fPainter->fInternal, + fBitmap, fOffset, fScaleX, fScaleY, fDestinationRect); + return; + } + + // for all other cases (non-optimized drawing mode or scaled drawing) + DrawBitmapGeneric::Draw(fPainter, fPainter->fInternal, fBitmap, fOffset, + fScaleX, fScaleY, fDestinationRect, fOptions); +} + + +bool +Painter::BitmapPainter::_DetermineTransform(BRect sourceRect, + const BRect& destinationRect) +{ + if (!fPainter->fValidClipping + || !sourceRect.IsValid() + || !sourceRect.Intersects(fBitmapBounds) + || !destinationRect.IsValid()) { + return false; + } + + fDestinationRect = destinationRect; + + if (!fPainter->fSubpixelPrecise) { + align_rect_to_pixels(&sourceRect); + align_rect_to_pixels(&fDestinationRect); + } + + fScaleX = (fDestinationRect.Width() + 1) / (sourceRect.Width() + 1); + fScaleY = (fDestinationRect.Height() + 1) / (sourceRect.Height() + 1); + + if (fScaleX == 0.0 || fScaleY == 0.0) + return false; + + // constrain source rect to bitmap bounds and transfer the changes to + // the destination rect with the right scale + if (sourceRect.left < fBitmapBounds.left) { + float diff = fBitmapBounds.left - sourceRect.left; + fDestinationRect.left += diff * fScaleX; + sourceRect.left = fBitmapBounds.left; + } + if (sourceRect.top < fBitmapBounds.top) { + float diff = fBitmapBounds.top - sourceRect.top; + fDestinationRect.top += diff * fScaleY; + sourceRect.top = fBitmapBounds.top; + } + if (sourceRect.right > fBitmapBounds.right) { + float diff = sourceRect.right - fBitmapBounds.right; + fDestinationRect.right -= diff * fScaleX; + sourceRect.right = fBitmapBounds.right; + } + if (sourceRect.bottom > fBitmapBounds.bottom) { + float diff = sourceRect.bottom - fBitmapBounds.bottom; + fDestinationRect.bottom -= diff * fScaleY; + sourceRect.bottom = fBitmapBounds.bottom; + } + + fOffset.x = fDestinationRect.left - sourceRect.left; + fOffset.y = fDestinationRect.top - sourceRect.top; + + return true; +} + + +bool +Painter::BitmapPainter::_HasScale() +{ + return fScaleX != 1.0 || fScaleY != 1.0; +} + + +bool +Painter::BitmapPainter::_HasAffineTransform() +{ + return !fPainter->fIdentityTransform; +} + + +bool +Painter::BitmapPainter::_HasAlphaMask() +{ + return fPainter->fInternal.fMaskedUnpackedScanline != NULL; +} + + +void +Painter::BitmapPainter::_ConvertColorSpace( + ObjectDeleter& convertedBitmapDeleter) +{ + if (fColorSpace == B_RGBA32) + return; + + if (fColorSpace == B_RGB32 + && (fPainter->fDrawingMode == B_OP_COPY +#if 1 +// Enabling this would make the behavior compatible to BeOS, which +// treats B_RGB32 bitmaps as B_RGB*A*32 bitmaps in B_OP_ALPHA - unlike in +// all other drawing modes, where B_TRANSPARENT_MAGIC_RGBA32 is handled. +// B_RGB32 bitmaps therefore don't draw correctly on BeOS if they actually +// use this color, unless the alpha channel contains 255 for all other +// pixels, which is inconsistent. + || fPainter->fDrawingMode == B_OP_ALPHA +#endif + )) { + return; + } + + BBitmap* conversionBitmap = new(nothrow) BBitmap(fBitmapBounds, + B_BITMAP_NO_SERVER_LINK, B_RGBA32); + if (conversionBitmap == NULL) { + fprintf(stderr, "BitmapPainter::_ConvertColorSpace() - " + "out of memory for creating temporary conversion bitmap\n"); + return; + } + convertedBitmapDeleter.SetTo(conversionBitmap); + + status_t err = conversionBitmap->ImportBits(fBitmap.buf(), + fBitmap.height() * fBitmap.stride(), + fBitmap.stride(), 0, fColorSpace); + if (err < B_OK) { + fprintf(stderr, "BitmapPainter::_ConvertColorSpace() - " + "colorspace conversion failed: %s\n", strerror(err)); + return; + } + + // the original bitmap might have had some of the + // transaparent magic colors set that we now need to + // make transparent in our RGBA32 bitmap again. + switch (fColorSpace) { + case B_RGB32: + _TransparentMagicToAlpha((uint32 *)fBitmap.buf(), + fBitmap.width(), fBitmap.height(), + fBitmap.stride(), B_TRANSPARENT_MAGIC_RGBA32, + conversionBitmap); + break; + + // TODO: not sure if this applies to B_RGBA15 too. It + // should not because B_RGBA15 actually has an alpha + // channel itself and it should have been preserved + // when importing the bitmap. Maybe it applies to + // B_RGB16 though? + case B_RGB15: + _TransparentMagicToAlpha((uint16 *)fBitmap.buf(), + fBitmap.width(), fBitmap.height(), + fBitmap.stride(), B_TRANSPARENT_MAGIC_RGBA15, + conversionBitmap); + break; + + default: + break; + } + + fBitmap.attach((uint8*)conversionBitmap->Bits(), + (uint32)fBitmapBounds.IntegerWidth() + 1, + (uint32)fBitmapBounds.IntegerHeight() + 1, + conversionBitmap->BytesPerRow()); +} + + +template +void +Painter::BitmapPainter::_TransparentMagicToAlpha(sourcePixel* buffer, + uint32 width, uint32 height, uint32 sourceBytesPerRow, + sourcePixel transparentMagic, BBitmap* output) +{ + uint8* sourceRow = (uint8*)buffer; + uint8* destRow = (uint8*)output->Bits(); + uint32 destBytesPerRow = output->BytesPerRow(); + + for (uint32 y = 0; y < height; y++) { + sourcePixel* pixel = (sourcePixel*)sourceRow; + uint32* destPixel = (uint32*)destRow; + for (uint32 x = 0; x < width; x++, pixel++, destPixel++) { + if (*pixel == transparentMagic) + *destPixel &= 0x00ffffff; + } + + sourceRow += sourceBytesPerRow; + destRow += destBytesPerRow; + } +} diff --git a/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.h b/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.h new file mode 100644 index 0000000000..4afaa50645 --- /dev/null +++ b/src/servers/app/drawing/Painter/bitmap_painter/BitmapPainter.h @@ -0,0 +1,60 @@ +/* + * Copyright 2005-2007, Stephan Aßmus . + * Copyright 2008, Andrej Spielmann . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef BITMAP_PAINTER_H +#define BITMAP_PAINTER_H + +#include + +#include "Painter.h" + + +class Painter::BitmapPainter { +public: + +public: + BitmapPainter(const Painter* painter, + const ServerBitmap* bitmap, + uint32 options); + + void Draw(const BRect& sourceRect, + const BRect& destinationRect); + +private: + bool _DetermineTransform( + BRect sourceRect, + const BRect& destinationRect); + + bool _HasScale(); + bool _HasAffineTransform(); + bool _HasAlphaMask(); + + void _ConvertColorSpace(ObjectDeleter& + convertedBitmapDeleter); + + template + void _TransparentMagicToAlpha(sourcePixel *buffer, + uint32 width, uint32 height, + uint32 sourceBytesPerRow, + sourcePixel transparentMagic, + BBitmap *output); + +private: + const Painter* fPainter; + status_t fStatus; + agg::rendering_buffer fBitmap; + BRect fBitmapBounds; + color_space fColorSpace; + uint32 fOptions; + + BRect fDestinationRect; + double fScaleX; + double fScaleY; + BPoint fOffset; +}; + + +#endif // BITMAP_PAINTER_H diff --git a/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h new file mode 100644 index 0000000000..5268a6b2d4 --- /dev/null +++ b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapBilinear.h @@ -0,0 +1,647 @@ +/* + * Copyright 2009, Christian Packmann. + * Copyright 2008, Andrej Spielmann . + * Copyright 2005-2014, Stephan Aßmus . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef DRAW_BITMAP_BILINEAR_H +#define DRAW_BITMAP_BILINEAR_H + +#include "Painter.h" + +#include + + +// Prototypes for assembler routines +extern "C" { + void bilinear_scale_xloop_mmxsse(const uint8* src, void* dst, + void* xWeights, uint32 xmin, uint32 xmax, uint32 wTop, uint32 srcBPR); +} + + +extern uint32 gSIMDFlags; + + +namespace BitmapPainterPrivate { + + +struct FilterInfo { + uint16 index; // index into source bitmap row/column + uint16 weight; // weight of the pixel at index [0..255] +}; + + +struct FilterData { + FilterInfo* fWeightsX; + FilterInfo* fWeightsY; + uint32 fIndexOffsetX; + uint32 fIndexOffsetY; +}; + + +template +struct DrawBitmapBilinearOptimized { + void Draw(PainterAggInterface& aggInterface, const BRect& destinationRect, + agg::rendering_buffer* bitmap, const FilterData& filterData) + { + fSource = bitmap; + fSourceBytesPerRow = bitmap->stride(); + fDestination = NULL; + fDestinationBytesPerRow = aggInterface.fBuffer.stride(); + fWeightsX = filterData.fWeightsX; + fWeightsY = filterData.fWeightsY; + + const int32 left = (int32)destinationRect.left; + const int32 top = (int32)destinationRect.top; + const int32 right = (int32)destinationRect.right; + const int32 bottom = (int32)destinationRect.bottom; + + renderer_base& baseRenderer = aggInterface.fBaseRenderer; + + // iterate over clipping boxes + baseRenderer.first_clip_box(); + do { + const int32 x1 = max_c(baseRenderer.xmin(), left); + const int32 x2 = min_c(baseRenderer.xmax(), right); + if (x1 > x2) + continue; + + int32 y1 = max_c(baseRenderer.ymin(), top); + int32 y2 = min_c(baseRenderer.ymax(), bottom); + if (y1 > y2) + continue; + + // buffer offset into destination + fDestination = aggInterface.fBuffer.row_ptr(y1) + x1 * 4; + + // x and y are needed as indices into the weight arrays, so the + // offset into the target buffer needs to be compensated + const int32 xIndexL = x1 - left - filterData.fIndexOffsetX; + const int32 xIndexR = x2 - left - filterData.fIndexOffsetX; + y1 -= top + filterData.fIndexOffsetY; + y2 -= top + filterData.fIndexOffsetY; + + //printf("x: %ld - %ld\n", xIndexL, xIndexR); + //printf("y: %ld - %ld\n", y1, y2); + + static_cast(this)->DrawToClipRect( + xIndexL, xIndexR, y1, y2); + + } while (baseRenderer.next_clip_box()); + } + +protected: + agg::rendering_buffer* fSource; + uint32 fSourceBytesPerRow; + uint8* fDestination; + uint32 fDestinationBytesPerRow; + FilterInfo* fWeightsX; + FilterInfo* fWeightsY; +}; + + +struct ColorTypeRgb { + static void + Interpolate(uint32* t, const uint8* s, uint32 sourceBytesPerRow, + uint16 wLeft, uint16 wTop, uint16 wRight, uint16 wBottom) + { + // left and right of top row + t[0] = (s[0] * wLeft + s[4] * wRight) * wTop; + t[1] = (s[1] * wLeft + s[5] * wRight) * wTop; + t[2] = (s[2] * wLeft + s[6] * wRight) * wTop; + + // left and right of bottom row + s += sourceBytesPerRow; + t[0] += (s[0] * wLeft + s[4] * wRight) * wBottom; + t[1] += (s[1] * wLeft + s[5] * wRight) * wBottom; + t[2] += (s[2] * wLeft + s[6] * wRight) * wBottom; + + t[0] >>= 16; + t[1] >>= 16; + t[2] >>= 16; + } + + static void + InterpolateLastColumn(uint32* t, const uint8* s, const uint8* sBottom, + uint16 wTop, uint16 wBottom) + { + t[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; + t[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; + t[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; + } + + static void + InterpolateLastRow(uint32* t, const uint8* s, uint16 wLeft, + uint16 wRight) + { + t[0] = (s[0] * wLeft + s[4] * wRight) >> 8; + t[1] = (s[1] * wLeft + s[5] * wRight) >> 8; + t[2] = (s[2] * wLeft + s[6] * wRight) >> 8; + } +}; + + +struct ColorTypeRgba { + static void + Interpolate(uint32* t, const uint8* s, uint32 sourceBytesPerRow, + uint16 wLeft, uint16 wTop, uint16 wRight, uint16 wBottom) + { + // left and right of top row + t[0] = (s[0] * wLeft + s[4] * wRight) * wTop; + t[1] = (s[1] * wLeft + s[5] * wRight) * wTop; + t[2] = (s[2] * wLeft + s[6] * wRight) * wTop; + t[3] = (s[3] * wLeft + s[7] * wRight) * wTop; + + // left and right of bottom row + s += sourceBytesPerRow; + + t[0] += (s[0] * wLeft + s[4] * wRight) * wBottom; + t[1] += (s[1] * wLeft + s[5] * wRight) * wBottom; + t[2] += (s[2] * wLeft + s[6] * wRight) * wBottom; + t[3] += (s[3] * wLeft + s[7] * wRight) * wBottom; + + t[0] >>= 16; + t[1] >>= 16; + t[2] >>= 16; + t[3] >>= 16; + } + + static void + InterpolateLastColumn(uint32* t, const uint8* s, const uint8* sBottom, + uint16 wTop, uint16 wBottom) + { + t[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; + t[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; + t[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; + t[3] = (s[3] * wTop + sBottom[3] * wBottom) >> 8; + } + + static void + InterpolateLastRow(uint32* t, const uint8* s, uint16 wLeft, + uint16 wRight) + { + t[0] = (s[0] * wLeft + s[4] * wRight) >> 8; + t[1] = (s[1] * wLeft + s[5] * wRight) >> 8; + t[2] = (s[2] * wLeft + s[6] * wRight) >> 8; + t[3] = (s[3] * wLeft + s[7] * wRight) >> 8; + } +}; + + +struct DrawModeCopy { + static void + Blend(uint8*& d, uint32* t) + { + d[0] = t[0]; + d[1] = t[1]; + d[2] = t[2]; + d += 4; + } +}; + + +struct DrawModeAlphaOverlay { + static void + Blend(uint8*& d, uint32* t) + { + uint8 t0 = t[0]; + uint8 t1 = t[1]; + uint8 t2 = t[2]; + uint8 t3 = t[3]; + + if (t3 == 255) { + d[0] = t0; + d[1] = t1; + d[2] = t2; + } else { + d[0] = ((t0 - d[0]) * t3 + (d[0] << 8)) >> 8; + d[1] = ((t1 - d[1]) * t3 + (d[1] << 8)) >> 8; + d[2] = ((t2 - d[2]) * t3 + (d[2] << 8)) >> 8; + } + + d += 4; + } +}; + + +template +struct BilinearDefault : + DrawBitmapBilinearOptimized > { + + void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) + { + // In this mode we anticipate many pixels wich need filtering, + // there are no special cases for direct hit pixels except for + // the last column/row and the right/bottom corner pixel. + + // The last column/row handling does not need to be performed + // for all clipping rects! + int32 yMax = y2; + if (fWeightsY[yMax].weight == 255) + yMax--; + int32 xIndexMax = xIndexR; + if (fWeightsX[xIndexMax].weight == 255) + xIndexMax--; + + for (; y1 <= yMax; y1++) { + // cache the weight of the top and bottom row + const uint16 wTop = fWeightsY[y1].weight; + const uint16 wBottom = 255 - fWeightsY[y1].weight; + + // buffer offset into source (top row) + register const uint8* src = fSource->row_ptr(fWeightsY[y1].index); + + // buffer handle for destination to be incremented per + // pixel + register uint8* d = fDestination; + + for (int32 x = xIndexL; x <= xIndexMax; x++) { + const uint8* s = src + fWeightsX[x].index; + + // calculate the weighted sum of all four + // interpolated pixels + const uint16 wLeft = fWeightsX[x].weight; + const uint16 wRight = 255 - wLeft; + + uint32 t[4]; + ColorType::Interpolate(&t[0], s, fSourceBytesPerRow, + wLeft, wTop, wRight, wBottom); + DrawMode::Blend(d, &t[0]); + } + // last column of pixels if necessary + if (xIndexMax < xIndexR) { + const uint8* s = src + fWeightsX[xIndexR].index; + const uint8* sBottom = s + fSourceBytesPerRow; + + uint32 t[4]; + ColorType::InterpolateLastColumn(&t[0], s, sBottom, wTop, + wBottom); + DrawMode::Blend(d, &t[0]); + } + + fDestination += fDestinationBytesPerRow; + } + + // last row of pixels if necessary + // buffer offset into source (bottom row) + register const uint8* src + = fSource->row_ptr(fWeightsY[y2].index); + // buffer handle for destination to be incremented per pixel + register uint8* d = fDestination; + + if (yMax < y2) { + for (int32 x = xIndexL; x <= xIndexMax; x++) { + const uint8* s = src + fWeightsX[x].index; + const uint16 wLeft = fWeightsX[x].weight; + const uint16 wRight = 255 - wLeft; + uint32 t[4]; + ColorType::InterpolateLastRow(&t[0], s, wLeft, wRight); + DrawMode::Blend(d, &t[0]); + } + } + + // pixel in bottom right corner if necessary + if (yMax < y2 && xIndexMax < xIndexR) { + const uint8* s = src + fWeightsX[xIndexR].index; + *(uint32*)d = *(uint32*)s; + } + } +}; + + +struct BilinearLowFilterRatio : + DrawBitmapBilinearOptimized { + void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) + { + // In this mode, we anticipate to hit many destination pixels + // that map directly to a source pixel, we have more branches + // in the inner loop but save time because of the special + // cases. If there are too few direct hit pixels, the branches + // only waste time. + + for (; y1 <= y2; y1++) { + // cache the weight of the top and bottom row + const uint16 wTop = fWeightsY[y1].weight; + const uint16 wBottom = 255 - fWeightsY[y1].weight; + + // buffer offset into source (top row) + register const uint8* src = fSource->row_ptr(fWeightsY[y1].index); + // buffer handle for destination to be incremented per + // pixel + register uint8* d = fDestination; + + if (wTop == 255) { + for (int32 x = xIndexL; x <= xIndexR; x++) { + const uint8* s = src + fWeightsX[x].index; + // This case is important to prevent out + // of bounds access at bottom edge of the source + // bitmap. If the scale is low and integer, it will + // also help the speed. + if (fWeightsX[x].weight == 255) { + // As above, but to prevent out of bounds + // on the right edge. + *(uint32*)d = *(uint32*)s; + } else { + // Only the left and right pixels are + // interpolated, since the top row has 100% + // weight. + const uint16 wLeft = fWeightsX[x].weight; + const uint16 wRight = 255 - wLeft; + d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; + d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; + d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; + } + d += 4; + } + } else { + for (int32 x = xIndexL; x <= xIndexR; x++) { + const uint8* s = src + fWeightsX[x].index; + if (fWeightsX[x].weight == 255) { + // Prevent out of bounds access on the right + // edge or simply speed up. + const uint8* sBottom = s + fSourceBytesPerRow; + d[0] = (s[0] * wTop + sBottom[0] * wBottom) + >> 8; + d[1] = (s[1] * wTop + sBottom[1] * wBottom) + >> 8; + d[2] = (s[2] * wTop + sBottom[2] * wBottom) + >> 8; + } else { + // calculate the weighted sum of all four + // interpolated pixels + const uint16 wLeft = fWeightsX[x].weight; + const uint16 wRight = 255 - wLeft; + // left and right of top row + uint32 t0 = (s[0] * wLeft + s[4] * wRight) + * wTop; + uint32 t1 = (s[1] * wLeft + s[5] * wRight) + * wTop; + uint32 t2 = (s[2] * wLeft + s[6] * wRight) + * wTop; + + // left and right of bottom row + s += fSourceBytesPerRow; + t0 += (s[0] * wLeft + s[4] * wRight) * wBottom; + t1 += (s[1] * wLeft + s[5] * wRight) * wBottom; + t2 += (s[2] * wLeft + s[6] * wRight) * wBottom; + + d[0] = t0 >> 16; + d[1] = t1 >> 16; + d[2] = t2 >> 16; + } + d += 4; + } + } + fDestination += fDestinationBytesPerRow; + } + } +}; + + +#ifdef __INTEL__ + +struct BilinearSimd : DrawBitmapBilinearOptimized { + void DrawToClipRect(int32 xIndexL, int32 xIndexR, int32 y1, int32 y2) + { + // Basically the same as the "standard" mode, but we use SIMD + // routines for the processing of the single display lines. + + // The last column/row handling does not need to be performed + // for all clipping rects! + int32 yMax = y2; + if (fWeightsY[yMax].weight == 255) + yMax--; + int32 xIndexMax = xIndexR; + if (fWeightsX[xIndexMax].weight == 255) + xIndexMax--; + + for (; y1 <= yMax; y1++) { + // cache the weight of the top and bottom row + const uint16 wTop = fWeightsY[y1].weight; + const uint16 wBottom = 255 - fWeightsY[y1].weight; + + // buffer offset into source (top row) + const uint8* src = fSource->row_ptr(fWeightsY[y1].index); + // buffer handle for destination to be incremented per + // pixel + uint8* d = fDestination; + bilinear_scale_xloop_mmxsse(src, fDestination, fWeightsX, xIndexL, + xIndexMax, wTop, fSourceBytesPerRow); + // increase pointer by processed pixels + d += (xIndexMax - xIndexL + 1) * 4; + + // last column of pixels if necessary + if (xIndexMax < xIndexR) { + const uint8* s = src + fWeightsX[xIndexR].index; + const uint8* sBottom = s + fSourceBytesPerRow; + d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8; + d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8; + d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8; + } + + fDestination += fDestinationBytesPerRow; + } + + // last row of pixels if necessary + // buffer offset into source (bottom row) + register const uint8* src = fSource->row_ptr(fWeightsY[y2].index); + // buffer handle for destination to be incremented per pixel + register uint8* d = fDestination; + + if (yMax < y2) { + for (int32 x = xIndexL; x <= xIndexMax; x++) { + const uint8* s = src + fWeightsX[x].index; + const uint16 wLeft = fWeightsX[x].weight; + const uint16 wRight = 255 - wLeft; + d[0] = (s[0] * wLeft + s[4] * wRight) >> 8; + d[1] = (s[1] * wLeft + s[5] * wRight) >> 8; + d[2] = (s[2] * wLeft + s[6] * wRight) >> 8; + d += 4; + } + } + + // pixel in bottom right corner if necessary + if (yMax < y2 && xIndexMax < xIndexR) { + const uint8* s = src + fWeightsX[xIndexR].index; + *(uint32*)d = *(uint32*)s; + } + } +}; + +#endif // __INTEL__ + + +template +struct DrawBitmapBilinear { + void + Draw(const Painter* painter, PainterAggInterface& aggInterface, + agg::rendering_buffer& bitmap, BPoint offset, + double scaleX, double scaleY, BRect destinationRect) + { + //bigtime_t now = system_time(); + uint32 dstWidth = destinationRect.IntegerWidth() + 1; + uint32 dstHeight = destinationRect.IntegerHeight() + 1; + uint32 srcWidth = bitmap.width(); + uint32 srcHeight = bitmap.height(); + + // Do not calculate more filter weights than necessary and also + // keep the stack based allocations reasonably sized + const BRegion& clippingRegion = *painter->ClippingRegion(); + if (clippingRegion.Frame().IntegerWidth() + 1 < (int32)dstWidth) + dstWidth = clippingRegion.Frame().IntegerWidth() + 1; + if (clippingRegion.Frame().IntegerHeight() + 1 < (int32)dstHeight) + dstHeight = clippingRegion.Frame().IntegerHeight() + 1; + + // When calculating less filter weights than specified by + // destinationRect, we need to compensate the offset. + FilterData filterData; + filterData.fIndexOffsetX = 0; + filterData.fIndexOffsetY = 0; + if (clippingRegion.Frame().left > destinationRect.left) { + filterData.fIndexOffsetX = (int32)(clippingRegion.Frame().left + - destinationRect.left); + } + if (clippingRegion.Frame().top > destinationRect.top) { + filterData.fIndexOffsetY = (int32)(clippingRegion.Frame().top + - destinationRect.top); + } + +//#define FILTER_INFOS_ON_HEAP +#ifdef FILTER_INFOS_ON_HEAP + filterData.fWeightsX = new (nothrow) FilterInfo[dstWidth]; + filterData.fWeightsY = new (nothrow) FilterInfo[dstHeight]; + if (filterData.fWeightsX == NULL || filterData.fWeightsY == NULL) { + delete[] filterData.fWeightsX; + delete[] filterData.fWeightsY; + return; + } +#else + // stack based saves about 200µs on 1.85 GHz Core 2 Duo + // should not pose a problem with stack overflows + // (needs around 12Kb for 1920x1200) + FilterInfo xWeights[dstWidth]; + FilterInfo yWeights[dstHeight]; + filterData.fWeightsX = &xWeights[0]; + filterData.fWeightsY = &yWeights[0]; +#endif + + // Extract the cropping information for the source bitmap, + // If only a part of the source bitmap is to be drawn with scale, + // the offset will be different from the destinationRect left top + // corner. + const int32 xBitmapShift = (int32)(destinationRect.left - offset.x); + const int32 yBitmapShift = (int32)(destinationRect.top - offset.y); + + for (uint32 i = 0; i < dstWidth; i++) { + // fractional index into source + // NOTE: It is very important to calculate the fractional index + // into the source pixel grid like this to prevent out of bounds + // access! It will result in the rightmost pixel of the destination + // to access the rightmost pixel of the source with a weighting + // of 255. This in turn will trigger an optimization in the loop + // that also prevents out of bounds access. + float index = (i + filterData.fIndexOffsetX) * (srcWidth - 1) + / (srcWidth * scaleX - 1); + // round down to get the left pixel + filterData.fWeightsX[i].index = (uint16)index; + filterData.fWeightsX[i].weight = + 255 - (uint16)((index - filterData.fWeightsX[i].index) * 255); + // handle cropped source bitmap + filterData.fWeightsX[i].index += xBitmapShift; + // precompute index for 32 bit pixels + filterData.fWeightsX[i].index *= 4; + } + + for (uint32 i = 0; i < dstHeight; i++) { + // fractional index into source + // NOTE: It is very important to calculate the fractional index + // into the source pixel grid like this to prevent out of bounds + // access! It will result in the bottommost pixel of the + // destination to access the bottommost pixel of the source with a + // weighting of 255. This in turn will trigger an optimization in + // the loop that also prevents out of bounds access. + float index = (i + filterData.fIndexOffsetY) * (srcHeight - 1) + / (srcHeight * scaleY - 1); + // round down to get the top pixel + filterData.fWeightsY[i].index = (uint16)index; + filterData.fWeightsY[i].weight = + 255 - (uint16)((index - filterData.fWeightsY[i].index) * 255); + // handle cropped source bitmap + filterData.fWeightsY[i].index += yBitmapShift; + } + //printf("X: %d/%d ... %d/%d, %d/%d (%ld)\n", + // xWeights[0].index, xWeights[0].weight, + // xWeights[dstWidth - 2].index, xWeights[dstWidth - 2].weight, + // xWeights[dstWidth - 1].index, xWeights[dstWidth - 1].weight, + // dstWidth); + //printf("Y: %d/%d ... %d/%d, %d/%d (%ld)\n", + // yWeights[0].index, yWeights[0].weight, + // yWeights[dstHeight - 2].index, yWeights[dstHeight - 2].weight, + // yWeights[dstHeight - 1].index, yWeights[dstHeight - 1].weight, + // dstHeight); + + // Figure out which version of the code we want to use... + enum { + kOptimizeForLowFilterRatio = 0, + kUseDefaultVersion, + kUseSIMDVersion + }; + + int codeSelect = kUseDefaultVersion; + + if (typeid(ColorType) == typeid(ColorTypeRgb) + && typeid(DrawMode) == typeid(DrawModeCopy)) { + uint32 neededSIMDFlags = APPSERVER_SIMD_MMX | APPSERVER_SIMD_SSE; + if ((gSIMDFlags & neededSIMDFlags) == neededSIMDFlags) + codeSelect = kUseSIMDVersion; + else { + if (scaleX == scaleY && (scaleX == 1.5 || scaleX == 2.0 + || scaleX == 2.5 || scaleX == 3.0)) { + codeSelect = kOptimizeForLowFilterRatio; + } + } + } + + switch (codeSelect) { + case kUseDefaultVersion: + { + BilinearDefault bilinearPainter; + bilinearPainter.Draw(aggInterface, destinationRect, &bitmap, + filterData); + break; + } + + case kOptimizeForLowFilterRatio: + { + BilinearLowFilterRatio bilinearPainter; + bilinearPainter.Draw(aggInterface, destinationRect, + &bitmap, filterData); + break; + } + +#ifdef __INTEL__ + case kUseSIMDVersion: + { + BilinearSimd bilinearPainter; + bilinearPainter.Draw(aggInterface, destinationRect, &bitmap, + filterData); + break; + } +#endif // __INTEL__ + } + +#ifdef FILTER_INFOS_ON_HEAP + delete[] filterData.fWeightsX; + delete[] filterData.fWeightsY; +#endif + //printf("draw bitmap %.5fx%.5f: %lld\n", scaleX, scaleY, + // system_time() - now); + } +}; + + +} // namespace BitmapPainterPrivate + + +#endif // DRAW_BITMAP_BILINEAR_H diff --git a/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapGeneric.h b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapGeneric.h new file mode 100644 index 0000000000..f148583f81 --- /dev/null +++ b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapGeneric.h @@ -0,0 +1,112 @@ +/* + * Copyright 2009, Christian Packmann. + * Copyright 2008, Andrej Spielmann . + * Copyright 2005-2014, Stephan Aßmus . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef DRAW_BITMAP_GENERIC_H +#define DRAW_BITMAP_GENERIC_H + +#include "Painter.h" + + +struct DrawBitmapGeneric { + static void + Draw(const Painter* painter, PainterAggInterface& aggInterface, + agg::rendering_buffer& bitmap, BPoint offset, + double scaleX, double scaleY, BRect destinationRect, uint32 options) + { + // pixel format attached to bitmap + typedef agg::pixfmt_bgra32 pixfmt_image; + pixfmt_image pixf_img(bitmap); + + agg::trans_affine srcMatrix; + // NOTE: R5 seems to ignore this offset when drawing bitmaps + // srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, + // -actualBitmapRect.top); + srcMatrix *= painter->Transform(); + + agg::trans_affine imgMatrix; + imgMatrix *= agg::trans_affine_translation( + offset.x - destinationRect.left, offset.y - destinationRect.top); + imgMatrix *= agg::trans_affine_scaling(scaleX, scaleY); + imgMatrix *= agg::trans_affine_translation(destinationRect.left, + destinationRect.top); + imgMatrix *= painter->Transform(); + imgMatrix.invert(); + + // image interpolator + typedef agg::span_interpolator_linear<> interpolator_type; + interpolator_type interpolator(imgMatrix); + + // scanline allocator + agg::span_allocator spanAllocator; + + // image accessor attached to pixel format of bitmap + typedef agg::image_accessor_clone source_type; + source_type source(pixf_img); + + // clip to the current clipping region's frame + if (painter->IsIdentityTransform()) { + destinationRect = destinationRect + & painter->ClippingRegion()->Frame(); + } + // convert to pixel coords (versus pixel indices) + destinationRect.right++; + destinationRect.bottom++; + + // path enclosing the bitmap + agg::path_storage& path = aggInterface.fPath; + rasterizer_type& rasterizer = aggInterface.fRasterizer; + + path.remove_all(); + path.move_to(destinationRect.left, destinationRect.top); + path.line_to(destinationRect.right, destinationRect.top); + path.line_to(destinationRect.right, destinationRect.bottom); + path.line_to(destinationRect.left, destinationRect.bottom); + path.close_polygon(); + + agg::conv_transform transformedPath(path, + srcMatrix); + rasterizer.reset(); + rasterizer.add_path(transformedPath); + + if ((options & B_FILTER_BITMAP_BILINEAR) != 0) { + // image filter (bilinear) + typedef agg::span_image_filter_rgba_bilinear< + source_type, interpolator_type> span_gen_type; + span_gen_type spanGenerator(source, interpolator); + + // render the path with the bitmap as scanline fill + if (aggInterface.fMaskedUnpackedScanline != NULL) { + agg::render_scanlines_aa(rasterizer, + *aggInterface.fMaskedUnpackedScanline, + aggInterface.fBaseRenderer, spanAllocator, spanGenerator); + } else { + agg::render_scanlines_aa(rasterizer, + aggInterface.fUnpackedScanline, + aggInterface.fBaseRenderer, spanAllocator, spanGenerator); + } + } else { + // image filter (nearest neighbor) + typedef agg::span_image_filter_rgba_nn< + source_type, interpolator_type> span_gen_type; + span_gen_type spanGenerator(source, interpolator); + + // render the path with the bitmap as scanline fill + if (aggInterface.fMaskedUnpackedScanline != NULL) { + agg::render_scanlines_aa(rasterizer, + *aggInterface.fMaskedUnpackedScanline, + aggInterface.fBaseRenderer, spanAllocator, spanGenerator); + } else { + agg::render_scanlines_aa(rasterizer, + aggInterface.fUnpackedScanline, + aggInterface.fBaseRenderer, spanAllocator, spanGenerator); + } + } + } +}; + + +#endif // DRAW_BITMAP_GENERIC_H diff --git a/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapNearestNeighbor.h b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapNearestNeighbor.h new file mode 100644 index 0000000000..59fc68b097 --- /dev/null +++ b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapNearestNeighbor.h @@ -0,0 +1,143 @@ +/* + * Copyright 2009, Christian Packmann. + * Copyright 2008, Andrej Spielmann . + * Copyright 2005-2014, Stephan Aßmus . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef DRAW_BITMAP_NEAREST_NEIGHBOR_H +#define DRAW_BITMAP_NEAREST_NEIGHBOR_H + +#include "Painter.h" + + +struct DrawBitmapNearestNeighborCopy { + static void + Draw(const Painter* painter, PainterAggInterface& aggInterface, + agg::rendering_buffer& bitmap, BPoint offset, + double scaleX, double scaleY, BRect destinationRect) + { + //bigtime_t now = system_time(); + uint32 dstWidth = destinationRect.IntegerWidth() + 1; + uint32 dstHeight = destinationRect.IntegerHeight() + 1; + uint32 srcWidth = bitmap.width(); + uint32 srcHeight = bitmap.height(); + + // Do not calculate more filter weights than necessary and also + // keep the stack based allocations reasonably sized + const BRegion& clippingRegion = *painter->ClippingRegion(); + if (clippingRegion.Frame().IntegerWidth() + 1 < (int32)dstWidth) + dstWidth = clippingRegion.Frame().IntegerWidth() + 1; + if (clippingRegion.Frame().IntegerHeight() + 1 < (int32)dstHeight) + dstHeight = clippingRegion.Frame().IntegerHeight() + 1; + + // When calculating less filter weights than specified by + // destinationRect, we need to compensate the offset. + uint32 filterWeightXIndexOffset = 0; + uint32 filterWeightYIndexOffset = 0; + if (clippingRegion.Frame().left > destinationRect.left) { + filterWeightXIndexOffset = (int32)(clippingRegion.Frame().left + - destinationRect.left); + } + if (clippingRegion.Frame().top > destinationRect.top) { + filterWeightYIndexOffset = (int32)(clippingRegion.Frame().top + - destinationRect.top); + } + + // should not pose a problem with stack overflows + // (needs around 6Kb for 1920x1200) + uint16 xIndices[dstWidth]; + uint16 yIndices[dstHeight]; + + // Extract the cropping information for the source bitmap, + // If only a part of the source bitmap is to be drawn with scale, + // the offset will be different from the destinationRect left top + // corner. + const int32 xBitmapShift = (int32)(destinationRect.left - offset.x); + const int32 yBitmapShift = (int32)(destinationRect.top - offset.y); + + for (uint32 i = 0; i < dstWidth; i++) { + // index into source + uint16 index = (uint16)((i + filterWeightXIndexOffset) * srcWidth + / (srcWidth * scaleX)); + // round down to get the left pixel + xIndices[i] = index; + // handle cropped source bitmap + xIndices[i] += xBitmapShift; + // precompute index for 32 bit pixels + xIndices[i] *= 4; + } + + for (uint32 i = 0; i < dstHeight; i++) { + // index into source + uint16 index = (uint16)((i + filterWeightYIndexOffset) * srcHeight + / (srcHeight * scaleY)); + // round down to get the top pixel + yIndices[i] = index; + // handle cropped source bitmap + yIndices[i] += yBitmapShift; + } + //printf("X: %d ... %d, %d (%ld or %f)\n", + // xIndices[0], xIndices[dstWidth - 2], xIndices[dstWidth - 1], + // dstWidth, srcWidth * scaleX); + //printf("Y: %d ... %d, %d (%ld or %f)\n", + // yIndices[0], yIndices[dstHeight - 2], yIndices[dstHeight - 1], + // dstHeight, srcHeight * scaleY); + + const int32 left = (int32)destinationRect.left; + const int32 top = (int32)destinationRect.top; + const int32 right = (int32)destinationRect.right; + const int32 bottom = (int32)destinationRect.bottom; + + const uint32 dstBPR = aggInterface.fBuffer.stride(); + + renderer_base& baseRenderer = aggInterface.fBaseRenderer; + + // iterate over clipping boxes + baseRenderer.first_clip_box(); + do { + const int32 x1 = max_c(baseRenderer.xmin(), left); + const int32 x2 = min_c(baseRenderer.xmax(), right); + if (x1 > x2) + continue; + + int32 y1 = max_c(baseRenderer.ymin(), top); + int32 y2 = min_c(baseRenderer.ymax(), bottom); + if (y1 > y2) + continue; + + // buffer offset into destination + uint8* dst = aggInterface.fBuffer.row_ptr(y1) + x1 * 4; + + // x and y are needed as indeces into the wheight arrays, so the + // offset into the target buffer needs to be compensated + const int32 xIndexL = x1 - left - filterWeightXIndexOffset; + const int32 xIndexR = x2 - left - filterWeightXIndexOffset; + y1 -= top + filterWeightYIndexOffset; + y2 -= top + filterWeightYIndexOffset; + + //printf("x: %ld - %ld\n", xIndexL, xIndexR); + //printf("y: %ld - %ld\n", y1, y2); + + for (; y1 <= y2; y1++) { + // buffer offset into source (top row) + register const uint8* src = bitmap.row_ptr(yIndices[y1]); + // buffer handle for destination to be incremented per pixel + register uint32* d = (uint32*)dst; + + for (int32 x = xIndexL; x <= xIndexR; x++) { + *d = *(uint32*)(src + xIndices[x]); + d++; + } + dst += dstBPR; + } + } while (baseRenderer.next_clip_box()); + + //printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale, + // system_time() - now); + } +}; + + + +#endif // DRAW_BITMAP_NEAREST_NEIGHBOR_H diff --git a/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapNoScale.h b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapNoScale.h new file mode 100644 index 0000000000..d42371552d --- /dev/null +++ b/src/servers/app/drawing/Painter/bitmap_painter/DrawBitmapNoScale.h @@ -0,0 +1,196 @@ +/* + * Copyright 2009, Christian Packmann. + * Copyright 2008, Andrej Spielmann . + * Copyright 2005-2014, Stephan Aßmus . + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef DRAW_BITMAP_NO_SCALE_H +#define DRAW_BITMAP_NO_SCALE_H + +#include "IntPoint.h" +#include "IntRect.h" +#include "Painter.h" + + +template +struct DrawBitmapNoScale { +public: + void + Draw(PainterAggInterface& aggInterface, agg::rendering_buffer& bitmap, + uint32 bytesPerSourcePixel, IntPoint offset, BRect destinationRect) + { + // NOTE: this would crash if destinationRect was large enough to read + // outside the bitmap, so make sure this is not the case before calling + // this function! + uint8* dst = aggInterface.fBuffer.row_ptr(0); + const uint32 dstBPR = aggInterface.fBuffer.stride(); + + const uint8* src = bitmap.row_ptr(0); + const uint32 srcBPR = bitmap.stride(); + + const int32 left = (int32)destinationRect.left; + const int32 top = (int32)destinationRect.top; + const int32 right = (int32)destinationRect.right; + const int32 bottom = (int32)destinationRect.bottom; + +#if DEBUG_DRAW_BITMAP + if (left - offset.x < 0 + || left - offset.x >= (int32)bitmap.width() + || right - offset.x >= (int32)srcBuffer.width() + || top - offset.y < 0 + || top - offset.y >= (int32)bitmap.height() + || bottom - offset.y >= (int32)bitmap.height()) { + char message[256]; + sprintf(message, "reading outside of bitmap (%ld, %ld, %ld, %ld) " + "(%d, %d) (%ld, %ld)", + left - offset.x, top - offset.y, + right - offset.x, bottom - offset.y, + bitmap.width(), bitmap.height(), offset.x, offset.y); + debugger(message); + } +#endif + + fColorMap = SystemPalette(); + fAlphaMask = aggInterface.fClippedAlphaMask; + renderer_base& baseRenderer = aggInterface.fBaseRenderer; + + // copy rects, iterate over clipping boxes + baseRenderer.first_clip_box(); + do { + fRect.left = max_c(baseRenderer.xmin(), left); + fRect.right = min_c(baseRenderer.xmax(), right); + if (fRect.left <= fRect.right) { + fRect.top = max_c(baseRenderer.ymin(), top); + fRect.bottom = min_c(baseRenderer.ymax(), bottom); + if (fRect.top <= fRect.bottom) { + uint8* dstHandle = dst + fRect.top * dstBPR + + fRect.left * 4; + const uint8* srcHandle = src + + (fRect.top - offset.y) * srcBPR + + (fRect.left - offset.x) * bytesPerSourcePixel; + + for (; fRect.top <= fRect.bottom; fRect.top++) { + static_cast(this)->BlendRow(dstHandle, + srcHandle, fRect.right - fRect.left + 1); + + dstHandle += dstBPR; + srcHandle += srcBPR; + } + } + } + } while (baseRenderer.next_clip_box()); + } + +protected: + IntRect fRect; + const rgb_color* fColorMap; + const agg::clipped_alpha_mask* fAlphaMask; +}; + + +struct CMap8Copy : public DrawBitmapNoScale +{ + void BlendRow(uint8* dst, const uint8* src, int32 numPixels) + { + uint32* d = (uint32*)dst; + const uint8* s = src; + while (numPixels--) { + const rgb_color c = fColorMap[*s++]; + *d++ = (c.alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue); + } + } +}; + + +struct CMap8Over : public DrawBitmapNoScale +{ + void BlendRow(uint8* dst, const uint8* src, int32 numPixels) + { + uint32* d = (uint32*)dst; + const uint8* s = src; + while (numPixels--) { + const rgb_color c = fColorMap[*s++]; + if (c.alpha) + *d = (c.alpha << 24) | (c.red << 16) + | (c.green << 8) | (c.blue); + d++; + } + } +}; + + +struct Bgr32Copy : public DrawBitmapNoScale +{ + void BlendRow(uint8* dst, const uint8* src, int32 numPixels) + { + memcpy(dst, src, numPixels * 4); + } +}; + + +struct Bgr32Over : public DrawBitmapNoScale +{ + void BlendRow(uint8* dst, const uint8* src, int32 numPixels) + { + uint32* d = (uint32*)dst; + uint32* s = (uint32*)src; + while (numPixels--) { + if (*s != B_TRANSPARENT_MAGIC_RGBA32) + *(uint32*)d = *(uint32*)s; + d++; + s++; + } + } +}; + + +struct Bgr32Alpha : public DrawBitmapNoScale +{ + void BlendRow(uint8* dst, const uint8* src, int32 numPixels) + { + uint32* d = (uint32*)dst; + int32 bytes = numPixels * 4; + uint8 buffer[bytes]; + uint8* b = buffer; + while (numPixels--) { + if (src[3] == 255) { + *(uint32*)b = *(uint32*)src; + } else { + *(uint32*)b = *d; + b[0] = ((src[0] - b[0]) * src[3] + (b[0] << 8)) >> 8; + b[1] = ((src[1] - b[1]) * src[3] + (b[1] << 8)) >> 8; + b[2] = ((src[2] - b[2]) * src[3] + (b[2] << 8)) >> 8; + } + d++; + b += 4; + src += 4; + } + memcpy(dst, buffer, bytes); + } +}; + + +struct Bgr32CopyMasked : public DrawBitmapNoScale +{ + void BlendRow(uint8* dst, const uint8* src, int32 numPixels) + { + uint8 covers[numPixels]; + fAlphaMask->get_hspan(fRect.left, fRect.top, covers, numPixels); + + uint32* destination = (uint32*)dst; + uint32* source = (uint32*)src; + uint8* mask = (uint8*)&covers[0]; + + while (numPixels--) { + if (*mask != 0) + *destination = *source; + destination++; + source++; + mask++; + } + } +}; + + +#endif // DRAW_BITMAP_NO_SCALE_H diff --git a/src/servers/app/drawing/Painter/painter_bilinear_scale.nasm b/src/servers/app/drawing/Painter/bitmap_painter/painter_bilinear_scale.nasm similarity index 100% rename from src/servers/app/drawing/Painter/painter_bilinear_scale.nasm rename to src/servers/app/drawing/Painter/bitmap_painter/painter_bilinear_scale.nasm diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPC.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPC.h index 0313d3a00e..07a92b8703 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPC.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPC.h @@ -43,7 +43,7 @@ blend_pixel_alpha_pc(int x, int y, const color_type& c, uint8 cover, // blend_hline_alpha_pc void -blend_hline_alpha_pc(int x, int y, unsigned len, +blend_hline_alpha_pc(int x, int y, unsigned len, const color_type& c, uint8 cover, agg_buffer* buffer, const PatternHandler* pattern) { @@ -52,7 +52,7 @@ blend_hline_alpha_pc(int x, int y, unsigned len, rgb_color color = pattern->ColorAt(x, y); uint16 alpha = color.alpha * cover; if (alpha) { - if (alpha == 255) { + if (alpha == 255 * 255) { ASSIGN_ALPHA_PC(p, color.red, color.green, color.blue); } else { BLEND_ALPHA_PC(p, color.red, color.green, color.blue, alpha); @@ -65,7 +65,7 @@ blend_hline_alpha_pc(int x, int y, unsigned len, // blend_solid_hspan_alpha_pc void -blend_solid_hspan_alpha_pc(int x, int y, unsigned len, +blend_solid_hspan_alpha_pc(int x, int y, unsigned len, const color_type& c, const uint8* covers, agg_buffer* buffer, const PatternHandler* pattern) { @@ -88,7 +88,7 @@ blend_solid_hspan_alpha_pc(int x, int y, unsigned len, // blend_solid_vspan_alpha_pc void -blend_solid_vspan_alpha_pc(int x, int y, unsigned len, +blend_solid_vspan_alpha_pc(int x, int y, unsigned len, const color_type& c, const uint8* covers, agg_buffer* buffer, const PatternHandler* pattern) { @@ -112,8 +112,8 @@ blend_solid_vspan_alpha_pc(int x, int y, unsigned len, // blend_color_hspan_alpha_pc void -blend_color_hspan_alpha_pc(int x, int y, unsigned len, - const color_type* colors, +blend_color_hspan_alpha_pc(int x, int y, unsigned len, + const color_type* colors, const uint8* covers, uint8 cover, agg_buffer* buffer, const PatternHandler* pattern) { diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPCSolid.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPCSolid.h new file mode 100644 index 0000000000..da5f0de2ef --- /dev/null +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPCSolid.h @@ -0,0 +1,155 @@ +/* + * Copyright 2005, Stephan Aßmus + * Copyright 2015, Julian Harnath + * All rights reserved. Distributed under the terms of the MIT License. + * + * DrawingMode implementing B_OP_ALPHA in "Pixel Composite" mode on B_RGBA32. + * + */ + +#ifndef DRAWING_MODE_ALPHA_PC_SOLID_H +#define DRAWING_MODE_ALPHA_PC_SOLID_H + +#include "DrawingMode.h" + + +#define BLEND_ALPHA_PC(d, r, g, b, a) \ +{ \ + BLEND_COMPOSITE16(d, r, g, b, a); \ +} + + +#define ASSIGN_ALPHA_PC(d, r, g, b) \ +{ \ + d[0] = (b); \ + d[1] = (g); \ + d[2] = (r); \ + d[3] = 255; \ +} + + +void +blend_pixel_alpha_pc_solid(int x, int y, const color_type& color, uint8 cover, + agg_buffer* buffer, const PatternHandler*) +{ + uint8* p = buffer->row_ptr(y) + (x << 2); + uint16 alpha = color.a * cover; + if (alpha == 255 * 255) { + ASSIGN_ALPHA_PC(p, color.r, color.g, color.b); + } else { + BLEND_ALPHA_PC(p, color.r, color.g, color.b, alpha); + } +} + + +void +blend_hline_alpha_pc_solid(int x, int y, unsigned len, + const color_type& color, uint8 cover, + agg_buffer* buffer, const PatternHandler*) +{ + uint8* p = buffer->row_ptr(y) + (x << 2); + uint16 alpha = color.a * cover; + if (alpha == 0) + return; + + if (alpha == 255 * 255) { + do { + ASSIGN_ALPHA_PC(p, color.r, color.g, color.b); + p += 4; + } while(--len); + return; + } + + do { + BLEND_ALPHA_PC(p, color.r, color.g, color.b, alpha); + p += 4; + } while(--len); +} + + +void +blend_solid_hspan_alpha_pc_solid(int x, int y, unsigned len, + const color_type& color, const uint8* covers, + agg_buffer* buffer, const PatternHandler*) +{ + uint8* p = buffer->row_ptr(y) + (x << 2); + do { + uint16 alpha = color.a * *covers; + if (alpha) { + if(alpha == 255 * 255) { + ASSIGN_ALPHA_PC(p, color.r, color.g, color.b); + } else { + BLEND_ALPHA_PC(p, color.r, color.g, color.b, alpha); + } + } + covers++; + p += 4; + } while(--len); +} + + +void +blend_solid_vspan_alpha_pc_solid(int x, int y, unsigned len, + const color_type& color, const uint8* covers, + agg_buffer* buffer, const PatternHandler*) +{ + uint8* p = buffer->row_ptr(y) + (x << 2); + do { + uint16 alpha = color.a * *covers; + if (alpha) { + if (alpha == 255 * 255) { + ASSIGN_ALPHA_PC(p, color.r, color.g, color.b); + } else { + BLEND_ALPHA_PC(p, color.r, color.g, color.b, alpha); + } + } + covers++; + p += buffer->stride(); + } while(--len); +} + + +void +blend_color_hspan_alpha_pc_solid(int x, int y, unsigned len, + const color_type* colors, + const uint8* covers, uint8 cover, + agg_buffer* buffer, const PatternHandler*) +{ + uint8* p = buffer->row_ptr(y) + (x << 2); + if (covers) { + // non-solid opacity + do { + uint16 alpha = colors->a * *covers; + if (alpha) { + if (alpha == 255 * 255) { + ASSIGN_ALPHA_PC(p, colors->r, colors->g, colors->b); + } else { + BLEND_ALPHA_PC(p, colors->r, colors->g, colors->b, alpha); + } + } + covers++; + p += 4; + ++colors; + } while(--len); + } else { + // solid full opcacity + uint16 alpha = colors->a * cover; + if (alpha == 255 * 255) { + do { + ASSIGN_ALPHA_PC(p, colors->r, colors->g, colors->b); + p += 4; + ++colors; + } while(--len); + // solid partial opacity + } else if (alpha) { + do { + BLEND_ALPHA_PC(p, colors->r, colors->g, colors->b, alpha); + p += 4; + ++colors; + } while(--len); + } + } +} + + +#endif // DRAWING_MODE_ALPHA_PC_SOLID_H diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPO.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPO.h index bd82411c34..1d2d27f002 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPO.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPO.h @@ -2,7 +2,7 @@ * Copyright 2005, Stephan Aßmus . All rights reserved. * Distributed under the terms of the MIT License. * - * DrawingMode implementing B_OP_ALPHA in "Constant Overlay" mode on B_RGBA32. + * DrawingMode implementing B_OP_ALPHA in "Pixel Overlay" mode on B_RGBA32. * */ @@ -43,7 +43,7 @@ blend_pixel_alpha_po(int x, int y, const color_type& c, uint8 cover, // blend_hline_alpha_po void -blend_hline_alpha_po(int x, int y, unsigned len, +blend_hline_alpha_po(int x, int y, unsigned len, const color_type& c, uint8 cover, agg_buffer* buffer, const PatternHandler* pattern) { @@ -65,7 +65,7 @@ blend_hline_alpha_po(int x, int y, unsigned len, // blend_solid_hspan_alpha_po void -blend_solid_hspan_alpha_po(int x, int y, unsigned len, +blend_solid_hspan_alpha_po(int x, int y, unsigned len, const color_type& c, const uint8* covers, agg_buffer* buffer, const PatternHandler* pattern) { @@ -90,7 +90,7 @@ blend_solid_hspan_alpha_po(int x, int y, unsigned len, // blend_solid_vspan_alpha_po void -blend_solid_vspan_alpha_po(int x, int y, unsigned len, +blend_solid_vspan_alpha_po(int x, int y, unsigned len, const color_type& c, const uint8* covers, agg_buffer* buffer, const PatternHandler* pattern) { @@ -114,8 +114,8 @@ blend_solid_vspan_alpha_po(int x, int y, unsigned len, // blend_color_hspan_alpha_po void -blend_color_hspan_alpha_po(int x, int y, unsigned len, - const color_type* colors, +blend_color_hspan_alpha_po(int x, int y, unsigned len, + const color_type* colors, const uint8* covers, uint8 cover, agg_buffer* buffer, const PatternHandler* pattern) { diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSUBPIX.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSUBPIX.h index 7cc0b1c509..1d4227e8f3 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSUBPIX.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSUBPIX.h @@ -3,7 +3,7 @@ * Copyright 2008, Andrej Spielmann . * All rights reserved. Distributed under the terms of the MIT License. * - * DrawingMode implementing B_OP_ALPHA in "Constant Overlay" mode on B_RGBA32. + * DrawingMode implementing B_OP_ALPHA in "Pixel Overlay" mode on B_RGBA32. * */ diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h index 53ea222f5b..fa850be0a8 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h @@ -2,7 +2,7 @@ * Copyright 2005, Stephan Aßmus . All rights reserved. * Distributed under the terms of the MIT License. * - * DrawingMode implementing B_OP_ALPHA in "Constant Overlay" mode on B_RGBA32. + * DrawingMode implementing B_OP_ALPHA in "Pixel Overlay" mode on B_RGBA32. * */ @@ -27,7 +27,7 @@ blend_pixel_alpha_po_solid(int x, int y, const color_type& c, uint8 cover, // blend_hline_alpha_po_solid void -blend_hline_alpha_po_solid(int x, int y, unsigned len, +blend_hline_alpha_po_solid(int x, int y, unsigned len, const color_type& c, uint8 cover, agg_buffer* buffer, const PatternHandler* pattern) { @@ -64,7 +64,7 @@ blend_hline_alpha_po_solid(int x, int y, unsigned len, // blend_solid_hspan_alpha_po_solid void -blend_solid_hspan_alpha_po_solid(int x, int y, unsigned len, +blend_solid_hspan_alpha_po_solid(int x, int y, unsigned len, const color_type& c, const uint8* covers, agg_buffer* buffer, const PatternHandler* pattern) { @@ -88,7 +88,7 @@ blend_solid_hspan_alpha_po_solid(int x, int y, unsigned len, // blend_solid_vspan_alpha_po_solid void -blend_solid_vspan_alpha_po_solid(int x, int y, unsigned len, +blend_solid_vspan_alpha_po_solid(int x, int y, unsigned len, const color_type& c, const uint8* covers, agg_buffer* buffer, const PatternHandler* pattern) { diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolidSUBPIX.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolidSUBPIX.h index e52632737c..c8b1f107b7 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolidSUBPIX.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolidSUBPIX.h @@ -3,7 +3,7 @@ * Copyright 2008, Andrej Spielmann . * All rights reserved. Distributed under the terms of the MIT License. * - * DrawingMode implementing B_OP_ALPHA in "Constant Overlay" mode on B_RGBA32. + * DrawingMode implementing B_OP_ALPHA in "Pixel Overlay" mode on B_RGBA32. * */ diff --git a/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp b/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp index 0e4508ffe3..40ca5d3505 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp +++ b/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp @@ -20,6 +20,7 @@ #include "DrawingModeAlphaCO.h" #include "DrawingModeAlphaCOSolid.h" #include "DrawingModeAlphaPC.h" +#include "DrawingModeAlphaPCSolid.h" #include "DrawingModeAlphaPO.h" #include "DrawingModeAlphaPOSolid.h" #include "DrawingModeBlend.h" @@ -211,7 +212,7 @@ PixelFormat::SetDrawingMode(drawing_mode mode, source_alpha alphaSrcMode, case B_OP_COPY: if (text) { fBlendPixel = blend_pixel_copy_text; - fBlendHLine = blend_hline_copy_text; + fBlendHLine = blend_hline_copy_text; fBlendSolidHSpanSubpix = blend_solid_hspan_copy_text_subpix; fBlendSolidHSpan = blend_solid_hspan_copy_text; fBlendSolidVSpan = blend_solid_vspan_copy_text; @@ -327,12 +328,21 @@ PixelFormat::SetDrawingMode(drawing_mode mode, source_alpha alphaSrcMode, } fBlendColorHSpan = blend_color_hspan_alpha_po; } else if (alphaFncMode == B_ALPHA_COMPOSITE) { - fBlendPixel = blend_pixel_alpha_pc; - fBlendHLine = blend_hline_alpha_pc; - fBlendSolidHSpanSubpix = blend_solid_hspan_alpha_pc_subpix; - fBlendSolidHSpan = blend_solid_hspan_alpha_pc; - fBlendSolidVSpan = blend_solid_vspan_alpha_pc; - fBlendColorHSpan = blend_color_hspan_alpha_pc; + if (fPatternHandler->IsSolid()) { + fBlendPixel = blend_pixel_alpha_pc_solid; + fBlendHLine = blend_hline_alpha_pc_solid; + fBlendSolidHSpanSubpix = blend_solid_hspan_alpha_pc_subpix; + fBlendSolidHSpan = blend_solid_hspan_alpha_pc_solid; + fBlendSolidVSpan = blend_solid_vspan_alpha_pc_solid; + fBlendColorHSpan = blend_color_hspan_alpha_pc_solid; + } else { + fBlendPixel = blend_pixel_alpha_pc; + fBlendHLine = blend_hline_alpha_pc; + fBlendSolidHSpanSubpix = blend_solid_hspan_alpha_pc_subpix; + fBlendSolidHSpan = blend_solid_hspan_alpha_pc; + fBlendSolidVSpan = blend_solid_vspan_alpha_pc; + fBlendColorHSpan = blend_color_hspan_alpha_pc; + } } } break; diff --git a/src/servers/app/drawing/ViewHWInterface.cpp b/src/servers/app/drawing/ViewHWInterface.cpp index fe4ca9879c..4fec110348 100644 --- a/src/servers/app/drawing/ViewHWInterface.cpp +++ b/src/servers/app/drawing/ViewHWInterface.cpp @@ -483,7 +483,8 @@ ViewHWInterface::SetMode(const display_mode& mode) // has not been created either, but we need one to display // a real BWindow in the test environment. // be_app->Run() needs to be called in another thread - BApplication* app = new BApplication("application/x-vnd.haiku-app-server"); + BApplication* app = new BApplication( + "application/x-vnd.Haiku-test-app_server"); app->Unlock(); thread_id appThread = spawn_thread(run_app_thread, "app thread", diff --git a/src/servers/app/test_app_server.rdef b/src/servers/app/test_app_server.rdef index 29a0c4c9fe..e71bea4fbc 100644 --- a/src/servers/app/test_app_server.rdef +++ b/src/servers/app/test_app_server.rdef @@ -2,7 +2,7 @@ * app_server.rdef */ -resource app_signature "application/x-vnd.Haiku-app-server"; +resource app_signature "application/x-vnd.Haiku-test-app_server"; resource app_flags B_EXCLUSIVE_LAUNCH ; diff --git a/src/servers/registrar/Registrar.cpp b/src/servers/registrar/Registrar.cpp index 79b3d02a66..7987a1bc63 100644 --- a/src/servers/registrar/Registrar.cpp +++ b/src/servers/registrar/Registrar.cpp @@ -57,7 +57,7 @@ static const bigtime_t kRosterSanityEventInterval = 1000000LL; */ Registrar::Registrar(status_t* _error) : - BServer(B_REGISTRAR_SIGNATURE, "system:roster", -1, false, _error), + BServer(B_REGISTRAR_SIGNATURE, B_REGISTRAR_PORT_NAME, -1, false, _error), fRoster(NULL), fClipboardHandler(NULL), fMIMEManager(NULL), diff --git a/src/tests/servers/app/Jamfile b/src/tests/servers/app/Jamfile index 376d56291d..24598d765f 100644 --- a/src/tests/servers/app/Jamfile +++ b/src/tests/servers/app/Jamfile @@ -127,6 +127,7 @@ SharedLibrary libtestappserver.so : ProfileMessageSupport.cpp EventDispatcher.cpp EventStream.cpp + TestServerLoopAdapter.cpp MessageLooper.cpp # Decorator @@ -152,10 +153,12 @@ SharedLibrary libtestappserver.so : AlphaMask.cpp BitmapHWInterface.cpp + Canvas.cpp DesktopSettings.cpp - DrawingContext.cpp + Layer.cpp OffscreenServerWindow.cpp OffscreenWindow.cpp + PictureBoundingBoxPlayer.cpp RegionPool.cpp Screen.cpp ScreenConfigurations.cpp @@ -173,9 +176,9 @@ SharedLibrary libtestappserver.so : [ BuildFeatureAttribute freetype : library ] ; -Includes [ FGristFiles AppServer.cpp BitmapManager.cpp +Includes [ FGristFiles AppServer.cpp BitmapManager.cpp Canvas.cpp ClientMemoryAllocator.cpp Desktop.cpp DesktopSettings.cpp - DrawState.cpp DrawingContext.cpp DrawingEngine.cpp ServerApp.cpp + DrawState.cpp DrawingEngine.cpp ServerApp.cpp ServerBitmap.cpp ServerCursor.cpp ServerFont.cpp ServerPicture.cpp ServerWindow.cpp View.cpp Window.cpp WorkspacesView.cpp $(decorator_src) $(font_src) ] @@ -249,6 +252,7 @@ SubInclude HAIKU_TOP src tests servers app statusbar ; SubInclude HAIKU_TOP src tests servers app stress_test ; SubInclude HAIKU_TOP src tests servers app textview ; SubInclude HAIKU_TOP src tests servers app transformation ; +SubInclude HAIKU_TOP src tests servers app unit_tests ; SubInclude HAIKU_TOP src tests servers app view_state ; SubInclude HAIKU_TOP src tests servers app view_transit ; SubInclude HAIKU_TOP src tests servers app window_creation ; diff --git a/src/tests/servers/app/unit_tests/AppServerUnitTestAddOn.cpp b/src/tests/servers/app/unit_tests/AppServerUnitTestAddOn.cpp new file mode 100644 index 0000000000..2044db51de --- /dev/null +++ b/src/tests/servers/app/unit_tests/AppServerUnitTestAddOn.cpp @@ -0,0 +1,20 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include +#include + +#include "SimpleTransformTest.h" + + +BTestSuite* +getTestSuite() +{ + BTestSuite* suite = new BTestSuite("AppServerUnitTests"); + + SimpleTransformTest::AddTests(*suite); + + return suite; +} diff --git a/src/tests/servers/app/unit_tests/Jamfile b/src/tests/servers/app/unit_tests/Jamfile new file mode 100644 index 0000000000..89fbc1b0fd --- /dev/null +++ b/src/tests/servers/app/unit_tests/Jamfile @@ -0,0 +1,15 @@ +SubDir HAIKU_TOP src tests servers app unit_tests ; + +UseHeaders [ FDirName $(HAIKU_TOP) src servers app ] : true ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers app ] ; + +UnitTestLib app_server_unit_tests.so : + AppServerUnitTestAddOn.cpp + + IntPoint.cpp + IntRect.cpp + SimpleTransformTest.cpp + + : be [ TargetLibstdc++ ] + ; diff --git a/src/tests/servers/app/unit_tests/SimpleTransformTest.cpp b/src/tests/servers/app/unit_tests/SimpleTransformTest.cpp new file mode 100644 index 0000000000..db4872b9f3 --- /dev/null +++ b/src/tests/servers/app/unit_tests/SimpleTransformTest.cpp @@ -0,0 +1,269 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "SimpleTransformTest.h" + +#include "IntPoint.h" +#include "IntRect.h" + +#include +#include + + +void +SimpleTransformTest::TransformPoint() +{ + BPoint point(1.0, 1.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 10.0); + specimen.Apply(&point); + CPPUNIT_ASSERT(point == BPoint(11.0, 11.0)); + + specimen.AddOffset(10.0, 10.0); + point.Set(0.0, 0.0); + specimen.Apply(&point); + CPPUNIT_ASSERT(point == BPoint(20.0, 20.0)); +} + + +void +SimpleTransformTest::TransformIntPoint() +{ + IntPoint point(1, 1); + SimpleTransform specimen; + specimen.AddOffset(10.0, 10.0); + specimen.Apply(&point); + CPPUNIT_ASSERT(point == BPoint(11.0, 11.0)); +} + + +void +SimpleTransformTest::TransformRect() +{ + BRect rect(5.0, 10.0, 15.0, 20.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 10.0); + specimen.Apply(&rect); + CPPUNIT_ASSERT(rect == BRect(15.0, 20.0, 25.0, 30.0)); + + specimen.SetScale(2.5); + specimen.Apply(&rect); + CPPUNIT_ASSERT(rect == BRect(47.5, 60.0, 72.5, 85.0)); +} + + +void +SimpleTransformTest::TransformIntRect() +{ + IntRect rect(5, 10, 15, 20); + SimpleTransform specimen; + specimen.AddOffset(10.0, 10.0); + specimen.Apply(&rect); + CPPUNIT_ASSERT(rect == IntRect(15, 20, 25, 30)); + + specimen.SetScale(2); + specimen.Apply(&rect); + CPPUNIT_ASSERT(rect == BRect(40, 50, 60, 70)); +} + + +void +SimpleTransformTest::TransformRegion() +{ + BRegion region; + region.Include(BRect( 5.0, 5.0, 20.0, 20.0)); + region.Include(BRect(10.0, 10.0, 30.0, 30.0)); + region.Exclude(BRect(10.0, 20.0, 20.0, 25.0)); + + BRegion reference1 = region; + reference1.OffsetBy(10, 20); + + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.Apply(®ion); + CPPUNIT_ASSERT(region == reference1); + + specimen.SetScale(2.5); + + BRegion reference2; + reference2.Include(BRect(47.0, 82.0, 87.0, 122.0)); + reference2.Include(BRect(60.0, 95.0, 112.0, 147.0)); + reference2.Exclude(BRect(60.0, 120.0, 86.0, 134.0)); + + specimen.Apply(®ion); + CPPUNIT_ASSERT(region == reference2); +} + + +void +SimpleTransformTest::TransformGradientLinear() +{ + BGradientLinear gradient(10.0, 20.0, 30.0, 40.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&gradient); + CPPUNIT_ASSERT(gradient.Start() == BPoint(35.0, 70.0)); + CPPUNIT_ASSERT(gradient.End() == BPoint(85.0, 120.0)); +} + + +void +SimpleTransformTest::TransformGradientRadial() +{ + BGradientRadial gradient(10.0, 20.0, 10.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&gradient); + CPPUNIT_ASSERT(gradient.Center() == BPoint(35.0, 70.0)); +} + + +void +SimpleTransformTest::TransformGradientRadialFocus() +{ + BGradientRadialFocus gradient(10.0, 20.0, 10.0, 30.0, 40.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&gradient); + CPPUNIT_ASSERT(gradient.Center() == BPoint(35.0, 70.0)); + CPPUNIT_ASSERT(gradient.Focal() == BPoint(85.0, 120.0)); +} + + +void +SimpleTransformTest::TransformGradientDiamond() +{ + BGradientDiamond gradient(10.0, 20.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&gradient); + CPPUNIT_ASSERT(gradient.Center() == BPoint(35.0, 70.0)); +} + + +void +SimpleTransformTest::TransformGradientConic() +{ + BGradientConic gradient(10.0, 20.0, 10.0); + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&gradient); + CPPUNIT_ASSERT(gradient.Center() == BPoint(35.0, 70.0)); +} + + +void +SimpleTransformTest::TransformPointArray() +{ + BPoint points[3]; + points[0].Set(10.0, 20.0); + points[1].Set(30.0, 40.0); + points[2].Set(50.0, 60.0); + BPoint transformedPoints[3]; + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.Apply(&transformedPoints[0], &points[0], 3); + CPPUNIT_ASSERT(transformedPoints[0] == BPoint(20.0, 40.0)); + CPPUNIT_ASSERT(transformedPoints[1] == BPoint(40.0, 60.0)); + CPPUNIT_ASSERT(transformedPoints[2] == BPoint(60.0, 80.0)); +} + + +void +SimpleTransformTest::TransformRectArray() +{ + BRect rects[3]; + rects[0].Set( 5.0, 10.0, 15.0, 20.0); + rects[1].Set(15.0, 20.0, 25.0, 30.0); + rects[2].Set(25.0, 30.0, 35.0, 40.0); + BRect transformedRects[3]; + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&transformedRects[0], &rects[0], 3); + CPPUNIT_ASSERT(transformedRects[0] == BRect(22.5, 45.0, 47.5, 70.0)); + CPPUNIT_ASSERT(transformedRects[1] == BRect(47.5, 70.0, 72.5, 95.0)); + CPPUNIT_ASSERT(transformedRects[2] == BRect(72.5, 95.0, 97.5, 120.0)); +} + + +void +SimpleTransformTest::TransformRegionArray() +{ + BRegion regions[2]; + regions[0].Include(BRect( 5.0, 5.0, 20.0, 20.0)); + regions[0].Include(BRect(10.0, 10.0, 30.0, 30.0)); + regions[0].Exclude(BRect(10.0, 20.0, 20.0, 25.0)); + regions[1].Include(BRect( 5.0, 5.0, 20.0, 20.0)); + regions[1].Include(BRect(10.0, 10.0, 30.0, 30.0)); + regions[1].Exclude(BRect(10.0, 20.0, 20.0, 25.0)); + BRegion transformedRegions[3]; + SimpleTransform specimen; + specimen.AddOffset(10.0, 20.0); + specimen.SetScale(2.5); + specimen.Apply(&transformedRegions[0], ®ions[0], 2); + BRegion reference; + reference.Include(BRect(22.0, 32.0, 62.0, 72.0)); + reference.Include(BRect(35.0, 45.0, 87.0, 97.0)); + reference.Exclude(BRect(35.0, 70.0, 61.0, 84.0)); + + CPPUNIT_ASSERT(transformedRegions[0] == reference); + CPPUNIT_ASSERT(transformedRegions[1] == reference); +} + + +/* static */ void +SimpleTransformTest::AddTests(BTestSuite& parent) +{ + CppUnit::TestSuite* const suite = new CppUnit::TestSuite( + "SimpleTransformTest"); + + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformPoint", + &SimpleTransformTest::TransformPoint)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformIntPoint", + &SimpleTransformTest::TransformIntPoint)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformRect", + &SimpleTransformTest::TransformRect)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformIntRect", + &SimpleTransformTest::TransformIntRect)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformRegion", + &SimpleTransformTest::TransformRegion)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformGradientLinear", + &SimpleTransformTest::TransformGradientLinear)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformGradientRadial", + &SimpleTransformTest::TransformGradientRadial)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformGradientRadialFocus", + &SimpleTransformTest::TransformGradientRadialFocus)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformGradientDiamond", + &SimpleTransformTest::TransformGradientDiamond)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformGradientConic", + &SimpleTransformTest::TransformGradientConic)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformPointArray", + &SimpleTransformTest::TransformPointArray)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformRectArray", + &SimpleTransformTest::TransformRectArray)); + suite->addTest(new CppUnit::TestCaller( + "SimpleTransformTest::TransformRegionArray", + &SimpleTransformTest::TransformRegionArray)); + + parent.addTest("SimpleTransformTest", suite); +} diff --git a/src/tests/servers/app/unit_tests/SimpleTransformTest.h b/src/tests/servers/app/unit_tests/SimpleTransformTest.h new file mode 100644 index 0000000000..89a889fd46 --- /dev/null +++ b/src/tests/servers/app/unit_tests/SimpleTransformTest.h @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Julian Harnath + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef SIMPLE_TRANSFORM_TEST_H +#define SIMPLE_TRANSFORM_TEST_H + +#include +#include + +#include "SimpleTransform.h" + + +class SimpleTransformTest : public BTestCase { +public: + static void AddTests(BTestSuite& parent); + + void TransformPoint(); + void TransformIntPoint(); + void TransformRect(); + void TransformIntRect(); + void TransformRegion(); + + void TransformGradientLinear(); + void TransformGradientRadial(); + void TransformGradientRadialFocus(); + void TransformGradientDiamond(); + void TransformGradientConic(); + + void TransformPointArray(); + void TransformRectArray(); + void TransformRegionArray(); +}; + + +#endif // SIMPLE_TRANSFORM_TEST_H diff --git a/src/tests/servers/registrar/Jamfile b/src/tests/servers/registrar/Jamfile index 91d8c362c2..fe142624dc 100644 --- a/src/tests/servers/registrar/Jamfile +++ b/src/tests/servers/registrar/Jamfile @@ -110,7 +110,7 @@ Server test_registrar libstorage_kit_mime.a be localestub [ TargetLibstdc++ ] : - registrar.rdef + test_registrar.rdef ; if $(TARGET_PLATFORM) = libbe_test { diff --git a/src/tests/servers/registrar/run_test_registrar.cpp b/src/tests/servers/registrar/run_test_registrar.cpp index 20cf63bcb1..a32a2382a7 100644 --- a/src/tests/servers/registrar/run_test_registrar.cpp +++ b/src/tests/servers/registrar/run_test_registrar.cpp @@ -53,7 +53,7 @@ main(int argc, char* argv[]) while (get_next_thread_info(teamInfo.team, &threadCookie, &threadInfo) == B_OK) { // search for the roster thread - if (!strcmp(threadInfo.name, "_roster_thread_")) { + if (!strcmp(threadInfo.name, "roster")) { port_id port = find_port("haiku-test:roster"); port_info portInfo; if (get_port_info(port, &portInfo) == B_OK diff --git a/src/tests/servers/registrar/test_registrar.rdef b/src/tests/servers/registrar/test_registrar.rdef new file mode 100644 index 0000000000..2748c0b157 --- /dev/null +++ b/src/tests/servers/registrar/test_registrar.rdef @@ -0,0 +1,96 @@ +/* + * registrar.rdef + */ + +resource app_signature "application/x-vnd.test-registrar"; + +resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP; + /* the registrar's application flags are actually + * ignored. + * The actually used flags are set in TRoster::Init(). + */ + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "registrar", + long_info = "registrar ©2005-2008 Haiku Inc." +}; + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU + +resource vector_icon array { + $"6E6369660704006B0500020006023BB8A43D8642BF898E3DBC1F4BAE5447805C" + $"00E3AD00FFBC8F05020106023D66A73B07B6B9BEF73C1A2B48379549C4DE3D76" + $"9564FF536E4402000602B898C93319083A5C163FF4CC4AB5EA4451BB00B58A00" + $"FF8565030200060236EEF83B80F5BF3E743AB74A4B669742DBD600FFEFC0FFFF" + $"DE7C05FF0D0A044D5B585B59594D530A0626484C5B4E594E32282626270A0426" + $"484C5B4C3426270A0448542A452A2C48370A042C442C2D2A2C2A450A044C5B4E" + $"594E324C340A04282626274C344E320A042A45485448512C4408023133313C08" + $"023534353E08023936394008023D373D4208022E344040090A00010010011584" + $"00040A0101011001178400040A020102000A030103000A040104000A04010500" + $"0A050106000A050107000A06050C0B0A0908100117820004" +}; + +#else + +resource large_icon array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF00D9D9D90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF00D98383D9D90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF00D900008383D9D90000FFFFFFFFFFFFFFFFFF00000000FFFFFFFFFF" + $"FFFFFFFF00D9008F00008383D9D9000000000000FFFF003FD9D9D90000FFFFFF" + $"FFFFFFFF00D9008F8F8F00008383D9D900003F3F00003FD9D9D9D9D9D90000FF" + $"FFFFFFFF00D9008F3F8F8F8F00008383D9D900003F3FAAAAD9D9D9D9D9D98300" + $"FFFFFFFF00D9003F3F8F3F8F8F8F00008383D9D900008383AAAAD9D9D983AA00" + $"FFFFFFFF00D9008F3F3F3F8F3F8F8F8F00008383D9D900003F3FAAAA83AAAA00" + $"FFFFFFFF00D9008F3F8F3F8F3F8F8F8F8F8F00008383D9D900D93F3FAAAAAA00" + $"FFFFFFFF00D9008F3F8F3F3F3F8F8F8F8F8F8F8F000083AA00D9D9D983AA0111" + $"FFFFFFFF00D9008F8F8F3F8F3F8F8F8F8F8F8F8F8F0083AA00D9D9D9D9AA0017" + $"FFFFFFFF00D9008F8F8F8F8F3F3F8F8F8F8F8F8F8F0083AA00D9D9D9D9830011" + $"FFFFFFFF00D9008F8F8F8F8F8F8F3F8F8F8F8F8F8F0083AA00D9D9D983AA0111" + $"FFFFFFFF00D900008F8F8F8F8F8F8F8F8F8F8F8F8F0083AA00D9D983AA001111" + $"FFFFFFFF0000838300008F8F8F8F8F8F8F8F8F8F8F0083AA00D983AA001111FF" + $"FFFFFFFFFF000000838300008F8F8F8F8F8F8F8F8F0083AA0083AA001111FFFF" + $"FFFFFFFF003FD9830000838300008F8F8F8F8F8F8F0083AA00AA001111FFFFFF" + $"FFFFFF003FD98383001E0000838300008F8F8F8F8F0083AA00001111FFFFFFFF" + $"FFFF003FD98383031ED9D9830000838300008F8F8F0083AA001111FFFFFFFFFF" + $"FF003FD98383003FD9D98383003F0000838300008F0083AA0011FFFFFFFFFFFF" + $"003FD98383003FD9D98383003FD9D9D900008383000083AA0011FFFFFFFFFFFF" + $"00D98383003FD9D98383003FD9D98383003F0000838383AA0011FFFFFFFFFFFF" + $"FF0000003FD9D98383003FD9D98383003FD98383000083001111FFFFFFFFFFFF" + $"FFFF003FD9D98383003FD9D98383003FD98383001111001111FFFFFFFFFFFFFF" + $"FFFF00D9838306003FD9D98383003FD98383001111FFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF0000001000D9D98383003FD98383001111FFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFF000000003FD98300001111FFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFF000000111111FFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource mini_icon array { + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFF000000FFFFFFFFFFFFFFFFFFFFFF" + $"FF03D9D9D90000FFFFFFFF0000FFFFFF" + $"FF03D9B6B6D9D900000000D9D90000FF" + $"FF03D9B669B6B6D9D90000AAAAD98300" + $"FF03D9B6116868B6B6D9D9003FAAAA00" + $"FF03D9B68F681B8FB683AA00D9D9AA00" + $"FF03D9B68F181B8FB683AA003FD9AA01" + $"FF03D9B6B68F188FB683AA00D9830011" + $"FF03038383B6B68FB683AA00830011FF" + $"FF00D933048383B6B683AA000011FFFF" + $"00D98300D90303838383AA0011FFFFFF" + $"008300D98300D90303030011FFFFFFFF" + $"FF00D98300D900D9830011FFFFFFFFFF" + $"FFFF0000000000000011FFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +#endif // HAIKU_TARGET_PLATFORM_HAIKU