Merge branch 'app_server'

Conflicts:
	src/kits/interface/PicturePlayer.cpp
	src/servers/app/ServerPicture.cpp

In addition, the following files were also adapted to master branch
BPicture changes during the merge:
	src/kits/interface/PicturePlayer.h
	src/servers/app/PictureBoundingBoxPlayer.cpp
This commit is contained in:
Julian Harnath
2015-11-10 23:09:54 +01:00
71 changed files with 5461 additions and 2390 deletions
+3
View File
@@ -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,
+8 -1
View File
@@ -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"
+7
View File
@@ -7,6 +7,7 @@
* Jérôme Duval, [email protected]
* Axel Dörfler, [email protected]
* Andrej Spielmann, <[email protected]>
* Julian Harnath, <[email protected]>
*/
#ifndef APP_SERVER_PROTOCOL_H
#define APP_SERVER_PROTOCOL_H
@@ -15,6 +16,10 @@
#include <SupportDefs.h>
#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,
@@ -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, [email protected]
* Julian Harnath, <[email protected]>
*/
#ifndef _PICTURE_DATA_WRITER_H
#define _PICTURE_DATA_WRITER_H
@@ -17,6 +18,7 @@
#include <stack>
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);
@@ -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);
};
+2 -1
View File
@@ -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
+60
View File
@@ -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<port_id>(clientPort);
link->Attach<int32>(getuid());
link->AttachString(getenv("TARGET_SCREEN"));
link->Attach<int32>(AS_PROTOCOL_VERSION);
int32 code;
if (link->FlushWithReply(code) != B_OK || code != B_OK) {
link->SetSenderPort(-1);
return B_ERROR;
}
link->Read<port_id>(&serverPort);
link->SetSenderPort(serverPort);
return B_OK;
}
#endif // HAIKU_TARGET_PLATFORM_LIBBE_TEST
} // namespace BPrivate
+13 -3
View File
@@ -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"));
}
+17 -1
View File
@@ -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, <julian.harnath@rwth-achen.de>
*/
#include <PictureDataWriter.h>
@@ -660,6 +661,21 @@ PictureDataWriter::WritePopState()
}
status_t
PictureDataWriter::WriteBlendLayer(Layer* layer)
{
try {
BeginOp(B_PIC_BLEND_LAYER);
Write<Layer*>(layer);
EndOp();
} catch (status_t& status) {
return status;
}
return B_OK;
}
// private
void
PictureDataWriter::BeginOp(const int16& op)
+10
View File
@@ -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*>(layer))
break;
callbacks.blend_layer(userData, *layer);
break;
}
default:
break;
}
+24 -2
View File
@@ -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<uint8>(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<int32>(-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)
+6 -2
View File
@@ -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
+11 -3
View File
@@ -15,7 +15,6 @@
#include <Locker.h>
#include <ObjectList.h>
#include <OS.h>
#include <Server.h>
#include <String.h>
#include <Window.h>
@@ -23,12 +22,21 @@
#include "ServerConfig.h"
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
# include <Server.h>
# 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();
+289
View File
@@ -0,0 +1,289 @@
/*
* Copyright (c) 2001-2015, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adi Oanca <adioanca@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
* Marcus Overhagen <marcus@overhagen.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#include "Canvas.h"
#include <new>
#include <Region.h>
#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);
}
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2001-2015, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adi Oanca <adioanca@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
* Marcus Overhagen <marcus@overhagen.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#ifndef CANVAS_H
#define CANVAS_H
#include <Point.h>
#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
+62 -94
View File
@@ -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 <superstippi@gmx.de>
* Axel Dörfler, axeld@pinc-software.de
* Michael Pfeiffer <laplace@users.sourceforge.net>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
//! 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<ViewSetStateInfo>(&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(&lt.x, &lt.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)
{
+15 -12
View File
@@ -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 <adioanca@mymail.ro>
* Stephan Aßmus <superstippi@gmx.de>
* Axel Dörfler, axeld@pinc-software.de
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#ifndef _DRAW_STATE_H_
#define _DRAW_STATE_H_
@@ -16,10 +17,12 @@
#include <GraphicsDefs.h>
#include <InterfaceDefs.h>
#include <Point.h>
#include <Referenceable.h>
#include <View.h>
#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<AlphaMask> 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;
-345
View File
@@ -1,345 +0,0 @@
/*
* Copyright (c) 2001-2014, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adi Oanca <adioanca@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
* Marcus Overhagen <marcus@overhagen.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk
*/
#include "DrawingContext.h"
#include <new>
#include <GradientLinear.h>
#include <GradientRadial.h>
#include <GradientRadialFocus.h>
#include <GradientDiamond.h>
#include <GradientConic.h>
#include <Region.h>
#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(&center);
ConvertToScreen(&center);
radial->SetCenter(center);
break;
}
case BGradient::TYPE_RADIAL_FOCUS:
{
BGradientRadialFocus* radialFocus = (BGradientRadialFocus*) gradient;
BPoint center = radialFocus->Center();
BPoint focal = radialFocus->Focal();
fDrawState->Transform(&center);
ConvertToScreen(&center);
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(&center);
ConvertToScreen(&center);
diamond->SetCenter(center);
break;
}
case BGradient::TYPE_CONIC:
{
BGradientConic* conic = (BGradientConic*) gradient;
BPoint center = conic->Center();
fDrawState->Transform(&center);
ConvertToScreen(&center);
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);
}
-111
View File
@@ -1,111 +0,0 @@
/*
* Copyright (c) 2001-2014, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adi Oanca <adioanca@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
* Marcus Overhagen <marcus@overhagen.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk>
*/
#ifndef DRAWING_CONTEXT_H
#define DRAWING_CONTEXT_H
#include <Point.h>
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
+7 -5
View File
@@ -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
+216
View File
@@ -0,0 +1,216 @@
/*
* Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
* 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<Layer*>(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(&region);
// 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;
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
* 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
+2 -2
View File
@@ -154,9 +154,9 @@ MessageLooper::_MessageLooper()
Lock();
if (code == kMsgQuitLooper) {
if (code == kMsgQuitLooper)
Quit();
} else
else
_DispatchMessage(code, receiver);
Unlock();
@@ -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 <marcus@overhagen.de>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#include "PictureBoundingBoxPlayer.h"
#include <new>
#include <stdio.h>
#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 <Bitmap.h>
#include <Debug.h>
#include <List.h>
#include <ObjectListPrivate.h>
#include <PicturePlayer.h>
#include <PictureProtocol.h>
#include <Shape.h>
//#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<class RectType>
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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_state);
state->PushDrawState();
}
static void
pop_state(void* _state)
{
TRACE_BB("%p pop state\n", _state);
BoundingBoxState* const state =
reinterpret_cast<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_state);
state->GetDrawState()->SetPenSize(size);
}
static void
set_fore_color(void* _state, const rgb_color& color)
{
BoundingBoxState* const state =
reinterpret_cast<BoundingBoxState*>(_state);
state->GetDrawState()->SetHighColor(color);
}
static void
set_back_color(void* _state, const rgb_color& color)
{
BoundingBoxState* const state =
reinterpret_cast<BoundingBoxState*>(_state);
state->GetDrawState()->SetLowColor(color);
}
static void
set_stipple_pattern(void* _state, const pattern& _pattern)
{
BoundingBoxState* const state =
reinterpret_cast<BoundingBoxState*>(_state);
state->GetDrawState()->SetPattern(Pattern(_pattern));
}
static void
set_scale(void* _state, float scale)
{
BoundingBoxState* const state =
reinterpret_cast<BoundingBoxState*>(_state);
state->GetDrawState()->SetScale(scale);
}
static void
set_font_family(void* _state, const char* _family, size_t length)
{
BoundingBoxState* const state =
reinterpret_cast<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BoundingBoxState*>(_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<BMallocIO*>(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);
}
@@ -0,0 +1,28 @@
/*
* Copyright 2015, Haiku.
* Distributed under the terms of the MIT license.
*
* Authors:
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#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
+195 -170
View File
@@ -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 <marcus@overhagen.de>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#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<uint32> fOpStack;
stack<BPoint> 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<DrawingContext *>(_context);
context->CurrentState()->SetPenLocation(
context->CurrentState()->PenLocation() + delta);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
ShapePainter drawShape(context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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(&region);
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(&region);
}
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<DrawingContext *>(_context);
/* TODO
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->PushState();
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
canvas->PushState();
}
static void
pop_state(void* _context)
pop_state(void* _canvas)
{
DrawingContext* context = reinterpret_cast<DrawingContext *>(_context);
context->PopState();
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->ResyncDrawState();
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->GetDrawingEngine()->SetFont(context->CurrentState()->Font());
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetOrigin(pt);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetPenLocation(pt);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetDrawingMode(mode);
context->GetDrawingEngine()->SetDrawingMode(mode);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
DrawState* state = context->CurrentState();
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetPenSize(size);
context->GetDrawingEngine()->SetPenSize(
context->CurrentState()->PenSize());
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetHighColor(color);
context->GetDrawingEngine()->SetHighColor(color);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetLowColor(color);
context->GetDrawingEngine()->SetLowColor(color);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetPattern(Pattern(pattern));
context->GetDrawingEngine()->SetPattern(pattern);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetScale(scale);
context->ResyncDrawState();
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
Canvas* const canvas = reinterpret_cast<Canvas*>(_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<DrawingContext *>(_context);
context->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
canvas->CurrentState()->SetBlendingMode(alphaSrcMode, alphaFncMode);
}
static void
set_transform(void* _canvas, const BAffineTransform& transform)
{
Canvas* const canvas = reinterpret_cast<Canvas*>(_canvas);
canvas->CurrentState()->SetTransform(transform);
}
static void
blend_layer(void* _canvas, Layer* layer)
{
Canvas* const canvas = reinterpret_cast<Canvas*>(_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
+7 -4
View File
@@ -1,10 +1,11 @@
/*
* Copyright 2001-2010, Haiku.
* Copyright 2001-2015, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Stefano Ceccherini <stefano.ceccherini@gmail.com>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#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<ServerPicture> PictureList;
int32 fToken;
+164 -54
View File
@@ -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 <harakash@gmail.com>
* Philippe Saint-Pierre <stpere@gmail.com>
* Brecht Machiels <brecht@mos6581.org>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
@@ -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(&region);
fCurrentView->ScreenToLocalTransform().Apply(&region);
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<uint8>(&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<float>(&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<BPoint>(&(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<BPoint>(&(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<BRect>(&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<float>(&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<BPoint>(&(pts[i]));
fCurrentView->ConvertToScreenForDrawing(&pts[i]);
transform.Apply(&pts[i]);
}
if (link.Read<BRect>(&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<BPoint>(&(pts[i]));
fCurrentView->ConvertToScreenForDrawing(&pts[i]);
transform.Apply(&pts[i]);
}
link.Read<BRect>(&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<bool>(&isClosed);
link.Read<int32>(&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<BRect>(&polyFrame);
link.Read<int32>(&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(&region) < B_OK)
break;
fCurrentView->ConvertToScreenForDrawing(&region);
fCurrentView->PenToScreenTransform().Apply(&region);
drawingEngine->FillRegion(region);
break;
@@ -2708,8 +2761,10 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
if (link.ReadGradient(&gradient) != B_OK)
break;
fCurrentView->ConvertToScreenForDrawing(&region);
fCurrentView->ConvertToScreenForDrawing(gradient);
const SimpleTransform transform =
fCurrentView->PenToScreenTransform();
transform.Apply(&region);
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<uint8>(&opacity);
Layer* layer = dynamic_cast<Layer*>(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<Layer*>(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);
}
}
+243
View File
@@ -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 <superstippi@gmx.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#ifndef SIMPLE_TRANSFORM_H
#define SIMPLE_TRANSFORM_H
#include <GradientLinear.h>
#include <GradientRadial.h>
#include <GradientRadialFocus.h>
#include <GradientDiamond.h>
#include <GradientConic.h>
#include <Point.h>
#include <Region.h>
#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(&center);
radial->SetCenter(center);
break;
}
case BGradient::TYPE_RADIAL_FOCUS:
{
BGradientRadialFocus* radialFocus =
(BGradientRadialFocus*)gradient;
BPoint center = radialFocus->Center();
BPoint focal = radialFocus->Focal();
Apply(&center);
Apply(&focal);
radialFocus->SetCenter(center);
radialFocus->SetFocal(focal);
break;
}
case BGradient::TYPE_DIAMOND:
{
BGradientDiamond* diamond = (BGradientDiamond*) gradient;
BPoint center = diamond->Center();
Apply(&center);
diamond->SetCenter(center);
break;
}
case BGradient::TYPE_CONIC:
{
BGradientConic* conic = (BGradientConic*) gradient;
BPoint center = conic->Center();
Apply(&center);
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
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright 2001-2015, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
* Christian Packmann
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#include "TestServerLoopAdapter.h"
#include "Desktop.h"
#include "ServerConfig.h"
#include "ServerProtocol.h"
#include <PortLink.h>
#include <stdio.h>
//#define DEBUG_SERVER
#ifdef DEBUG_SERVER
# include <stdio.h>
# 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<port_id>(&replyPort);
int32 userID = -1;
link.Read<int32>(&userID);
char* targetScreen = NULL;
link.ReadString(&targetScreen);
int32 version = -1;
link.Read<int32>(&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<port_id>(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;
}
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright 2001-2015, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Axel Dörfler, axeld@pinc-software.de
* Julian Harnath, <julian.harnath@rwth-aachen.de>
*/
#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
+48 -199
View File
@@ -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 <superstippi@gmx.de>
* Marcus Overhagen <marcus@overhagen.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#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 <List.h>
@@ -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<Layer*>(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
+12 -28
View File
@@ -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 <superstippi@gmx.de>
* Marcus Overhagen <marcus@overhagen.de>
* Adrien Destugues <pulkomandy@pulkomandy.tk>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#ifndef VIEW_H
#define VIEW_H
#include "DrawingContext.h"
#include "Canvas.h"
#include "IntRect.h"
#include <GraphicsDefs.h>
@@ -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,
+1 -1
View File
@@ -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(
+3 -3
View File
@@ -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
+295 -148
View File
@@ -1,10 +1,11 @@
/*
* Copyright 2014, Haiku, Inc.
* Copyright 2014-2015, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues <pulkomandy@pulkomandy.tk>
* Stephan Aßmus <superstippi@gmx.de>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
@@ -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<ServerBitmap> 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<class VectorMaskType>
VectorAlphaMask<VectorMaskType>::VectorAlphaMask(AlphaMask* previousMask,
BPoint where, bool inverse)
:
AlphaMask(previousMask, inverse),
fWhere(where)
{
}
template<class VectorMaskType>
ServerBitmap*
VectorAlphaMask<VectorMaskType>::_RenderSource()
{
fBounds = static_cast<VectorMaskType*>(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<VectorMaskType*>(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<VectorMaskType*>(this)->DrawVectors(&canvas);
engine->UnlockParallelAccess();
}
context.PopState();
delete engine;
return bitmap;
}
template<class VectorMaskType>
IntPoint
VectorAlphaMask<VectorMaskType>::_Offset()
{
return fWhere;
}
// #pragma mark - PictureAlphaMask
PictureAlphaMask::PictureAlphaMask(AlphaMask* previousMask,
ServerPicture* picture, const DrawState& drawState, BPoint where,
bool inverse)
:
VectorAlphaMask<PictureAlphaMask>(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<ShapeAlphaMask>(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;
}
+97 -21
View File
@@ -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<AlphaMask> 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 VectorMaskType>
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<PictureAlphaMask> {
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<ServerPicture> fPicture;
DrawState* fDrawState;
};
// #pragma mark - ShapeAlphaMask
class ShapeAlphaMask : public VectorAlphaMask<ShapeAlphaMask> {
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
@@ -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",
+10 -2
View File
@@ -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 <superstippi@gmx.de>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
@@ -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
+4 -1
View File
@@ -1,11 +1,12 @@
/*
* Copyright 2001-2009, Haiku, Inc.
* Copyright 2001-2015, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Gabe Yoder <gyoder@stny.rr.com>
* Stephan Aßmus <superstippi@gmx.de>
* Julian Harnath <julian.harnath@rwth-aachen.de>
*/
#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,
+4
View File
@@ -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)
File diff suppressed because it is too large Load Diff
+15 -61
View File
@@ -1,6 +1,7 @@
/*
* Copyright 2005-2007, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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 <agg_conv_curve.h>
#include <agg_path_storage.h>
#include <AffineTransform.h>
#include <Font.h>
@@ -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<typename sourcePixel>
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 <class F>
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<agg::path_storage> fCurve;
private:
mutable PainterAggInterface fInternal;
// for internal coordinate rounding/transformation
bool fSubpixelPrecise : 1;
@@ -0,0 +1,69 @@
/*
* Copyright 2005-2007, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PAINTER_DATA_H
#define PAINTER_DATA_H
#include "defines.h"
#include <agg_path_storage.h>
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<agg::path_storage> fCurve;
};
#endif // PAINTER_DATA_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;
@@ -1,6 +1,7 @@
/*
* Copyright 2005-2006, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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;
};
@@ -0,0 +1,338 @@
/*
* Copyright 2009, Christian Packmann.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "BitmapPainter.h"
#include <Bitmap.h>
#include <agg_image_accessors.h>
#include <agg_pixfmt_rgba.h>
#include <agg_span_image_filter_rgba.h>
#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<CMap8Copy> drawNoScale;
drawNoScale.Draw(fPainter->fInternal, fBitmap, 1, fOffset,
fDestinationRect);
return;
}
if (fPainter->fDrawingMode == B_OP_OVER) {
DrawBitmapNoScale<CMap8Over> drawNoScale;
drawNoScale.Draw(fPainter->fInternal, fBitmap, 1, fOffset,
fDestinationRect);
return;
}
} else if (fColorSpace == B_RGB32) {
if (fPainter->fDrawingMode == B_OP_OVER) {
DrawBitmapNoScale<Bgr32Over> drawNoScale;
drawNoScale.Draw(fPainter->fInternal, fBitmap, 4, fOffset,
fDestinationRect);
return;
}
}
}
ObjectDeleter<BBitmap> convertedBitmapDeleter;
_ConvertColorSpace(convertedBitmapDeleter);
// optimized version if there is no scale
if (!_HasScale() && !_HasAffineTransform() && !_HasAlphaMask()) {
if (fPainter->fDrawingMode == B_OP_COPY) {
DrawBitmapNoScale<Bgr32Copy> 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<Bgr32Alpha> drawNoScale;
drawNoScale.Draw(fPainter->fInternal, fBitmap, 4, fOffset,
fDestinationRect);
return;
}
}
if (!_HasScale() && !_HasAffineTransform() && _HasAlphaMask()) {
if (fPainter->fDrawingMode == B_OP_COPY) {
DrawBitmapNoScale<Bgr32CopyMasked> 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<ColorTypeRgb, DrawModeCopy> 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<ColorTypeRgba, DrawModeAlphaOverlay> 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<BBitmap>& 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<typename sourcePixel>
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;
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2005-2007, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef BITMAP_PAINTER_H
#define BITMAP_PAINTER_H
#include <AutoDeleter.h>
#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<BBitmap>&
convertedBitmapDeleter);
template<typename sourcePixel>
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
@@ -0,0 +1,647 @@
/*
* Copyright 2009, Christian Packmann.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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 <typeinfo>
// 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<class OptimizedVersion>
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<OptimizedVersion*>(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<class ColorType, class DrawMode>
struct BilinearDefault :
DrawBitmapBilinearOptimized<BilinearDefault<ColorType, DrawMode> > {
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<BilinearLowFilterRatio> {
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<BilinearSimd> {
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<class ColorType, class DrawMode>
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<ColorType, DrawMode> 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
@@ -0,0 +1,112 @@
/*
* Copyright 2009, Christian Packmann.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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<pixfmt_image::color_type> spanAllocator;
// image accessor attached to pixel format of bitmap
typedef agg::image_accessor_clone<pixfmt_image> 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<agg::path_storage> 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
@@ -0,0 +1,143 @@
/*
* Copyright 2009, Christian Packmann.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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
@@ -0,0 +1,196 @@
/*
* Copyright 2009, Christian Packmann.
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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<class BlendType>
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<BlendType*>(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<CMap8Copy>
{
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<CMap8Over>
{
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<Bgr32Copy>
{
void BlendRow(uint8* dst, const uint8* src, int32 numPixels)
{
memcpy(dst, src, numPixels * 4);
}
};
struct Bgr32Over : public DrawBitmapNoScale<Bgr32Over>
{
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<Bgr32Alpha>
{
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<Bgr32CopyMasked>
{
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
@@ -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)
{
@@ -0,0 +1,155 @@
/*
* Copyright 2005, Stephan Aßmus <superstippi@gmx.de>
* Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
* 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
@@ -2,7 +2,7 @@
* Copyright 2005, Stephan Aßmus <superstippi@gmx.de>. 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)
{
@@ -3,7 +3,7 @@
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* 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.
*
*/
@@ -2,7 +2,7 @@
* Copyright 2005, Stephan Aßmus <superstippi@gmx.de>. 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)
{
@@ -3,7 +3,7 @@
* Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
* 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.
*
*/
@@ -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;
+2 -1
View File
@@ -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",
+1 -1
View File
@@ -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 ;
+1 -1
View File
@@ -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),
+7 -3
View File
@@ -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 ;
@@ -0,0 +1,20 @@
/*
* Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include <TestSuite.h>
#include <TestSuiteAddon.h>
#include "SimpleTransformTest.h"
BTestSuite*
getTestSuite()
{
BTestSuite* suite = new BTestSuite("AppServerUnitTests");
SimpleTransformTest::AddTests(*suite);
return suite;
}
+15
View File
@@ -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++ ]
;
@@ -0,0 +1,269 @@
/*
* Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "SimpleTransformTest.h"
#include "IntPoint.h"
#include "IntRect.h"
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
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(&region);
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(&region);
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], &regions[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>(
"SimpleTransformTest::TransformPoint",
&SimpleTransformTest::TransformPoint));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformIntPoint",
&SimpleTransformTest::TransformIntPoint));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformRect",
&SimpleTransformTest::TransformRect));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformIntRect",
&SimpleTransformTest::TransformIntRect));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformRegion",
&SimpleTransformTest::TransformRegion));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformGradientLinear",
&SimpleTransformTest::TransformGradientLinear));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformGradientRadial",
&SimpleTransformTest::TransformGradientRadial));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformGradientRadialFocus",
&SimpleTransformTest::TransformGradientRadialFocus));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformGradientDiamond",
&SimpleTransformTest::TransformGradientDiamond));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformGradientConic",
&SimpleTransformTest::TransformGradientConic));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformPointArray",
&SimpleTransformTest::TransformPointArray));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformRectArray",
&SimpleTransformTest::TransformRectArray));
suite->addTest(new CppUnit::TestCaller<SimpleTransformTest>(
"SimpleTransformTest::TransformRegionArray",
&SimpleTransformTest::TransformRegionArray));
parent.addTest("SimpleTransformTest", suite);
}
@@ -0,0 +1,36 @@
/*
* Copyright 2015 Julian Harnath <julian.harnath@rwth-aachen.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef SIMPLE_TRANSFORM_TEST_H
#define SIMPLE_TRANSFORM_TEST_H
#include <TestCase.h>
#include <TestSuite.h>
#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
+1 -1
View File
@@ -110,7 +110,7 @@ Server test_registrar
libstorage_kit_mime.a
be localestub [ TargetLibstdc++ ]
:
registrar.rdef
test_registrar.rdef
;
if $(TARGET_PLATFORM) = libbe_test {
@@ -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
@@ -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