diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 2a86d6f726..290f5b0791 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -524,13 +524,45 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) { BRect src; BRect dest; - + link.Read(&src); link.Read(&dest); - + + // NOTE: The correct behaviour is this: + // * The region that is copied is the + // src rectangle, no matter if it fits + // into the dest rectangle. It is copied + // by the offset dest.LeftTop() - src.LeftTop() + // * The dest rectangle is used for invalidation: + // Any area in the dest rectangle that could + // not be copied from src (because either the + // src rectangle was not big enough, or because there + // were parts cut off by the current layer clipping), + // are triggering BView::Draw() to be called + // and for these parts only. + // TODO: The DisplayDriver::CopyBits() call needs + // to get a BRegion and an offset by which to copy + // all the rects in that region. The region is calculated as + // * The src rectangle minus the currect clipping of the layer + // * minus the part of the region that is outside the layer + // when the region is translated by the offset! + // Then, an invalidation needs to be triggered for the + // following region: the dest rectangle minus the + // region we calculated in step one translated by the + // offset. + // By implementing it this way, we don't mix the update + // triggering with the actual graphical operation in + // DisplayDriver. I know that normally DisplayDriver takes + // care of the clipping, but this is different, because + // CopyBits() is the only drawing call that can trigger + // invalidation. + // TODO: In DisplayDriver, implement the described CopyBits() + // version. Also, the current implementation is wrong because it + // clips the source rectangle to the dest rectangle. + src = cl->ConvertToTop(src); dest = cl->ConvertToTop(dest); - + cl->fDriver->CopyBits(src, dest, cl->fLayerData); break; diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 77011547ac..57030ddfdd 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -423,10 +423,9 @@ Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const fBaseRenderer->ymax() >= y) { int32 i = max_c(fBaseRenderer->xmin(), x1); int32 end = min_c(fBaseRenderer->xmax(), x2); - uint8* handle = dst + i * 4; + uint32* handle = (uint32*)(dst + i * 4); for (; i <= end; i++) { - *(uint32*)handle = color.data32; - handle += 4; + *handle++ = color.data32; } } } while (fBaseRenderer->next_clip_box()); diff --git a/src/tests/servers/app/Jamfile b/src/tests/servers/app/Jamfile index 1a94100f1c..86ad3ecec0 100644 --- a/src/tests/servers/app/Jamfile +++ b/src/tests/servers/app/Jamfile @@ -1,4 +1,5 @@ SubDir OBOS_TOP src tests servers app ; +SubInclude OBOS_TOP src tests servers app copy_bits ; SubInclude OBOS_TOP src tests servers app painter ; SubInclude OBOS_TOP src tests servers app windows ; diff --git a/src/tests/servers/app/copy_bits/Jamfile b/src/tests/servers/app/copy_bits/Jamfile new file mode 100644 index 0000000000..5aed55b870 --- /dev/null +++ b/src/tests/servers/app/copy_bits/Jamfile @@ -0,0 +1,14 @@ +SubDir OBOS_TOP src tests servers app copy_bits ; + +UseHeaders [ FDirName os app ] ; +UseHeaders [ FDirName os interface ] ; + +SimpleTest CopyBits : + main.cpp +# for running natively under R5: +# : be ; +# for running in the Haiku app_server under R5: + : libopenbeos.so ; +# for running on Haiku: +# : libbe.so ; + diff --git a/src/tests/servers/app/copy_bits/NOTES b/src/tests/servers/app/copy_bits/NOTES new file mode 100644 index 0000000000..1b144f5a46 --- /dev/null +++ b/src/tests/servers/app/copy_bits/NOTES @@ -0,0 +1,3 @@ +For the test to run properly on BeOS, you need to make links to some Haiku libs in your ~/config/lib folder. The test itself links to libopenbeos.so, app_server additionally links to libappserver.so, libz.so, libpng.so and libfreetype.so. + +The script "run" launches the Haiku app_server and a second later the test app which connects to it. diff --git a/src/tests/servers/app/copy_bits/main.cpp b/src/tests/servers/app/copy_bits/main.cpp new file mode 100644 index 0000000000..4100b6f97f --- /dev/null +++ b/src/tests/servers/app/copy_bits/main.cpp @@ -0,0 +1,242 @@ +// main.cpp + +#include + +#include "Application.h" +#include "Message.h" +#include "Button.h" +#include "View.h" +#include "Window.h" + +#define MSG_COPY_BITS 'cbts' + +class TestView : public BView { + + enum { + TRACKING_NONE, + TRACKING_SOURCE, + TRACKING_DEST + }; + + public: + TestView(BRect frame, const char* name, + uint32 resizeFlags, uint32 flags) + : BView(frame, name, resizeFlags, flags), + fTracking(TRACKING_NONE), + fCopyBitsJustCalled(false) + { + fSourceRect.Set(frame.left, frame.top, + (frame.left + frame.right) / 2, + frame.bottom); + fDestRect.Set((frame.left + frame.right) / 2, + frame.top, + frame.right, frame.bottom); + fSourceRect.InsetBy(10.0, 10.0); + fDestRect.InsetBy(10.0, 10.0); + } + + virtual void MessageReceived(BMessage* message); + + virtual void Draw(BRect updateRect); + + virtual void MouseDown(BPoint where); + virtual void MouseUp(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage); + + private: + void _TrackMouse(BPoint where); + + BRect fSourceRect; + BRect fDestRect; + + uint32 fTracking; + + bool fCopyBitsJustCalled; +}; + +// MessageReceived +void +TestView::MessageReceived(BMessage* message) +{ + if (message->what == MSG_COPY_BITS) { + printf("MSG_COPY_BITS\n"); + fSourceRect.PrintToStream(); + fDestRect.PrintToStream(); + CopyBits(fSourceRect, fDestRect); + fCopyBitsJustCalled = true; + } else + BView::MessageReceived(message); +} + +// Draw +void +TestView::Draw(BRect updateRect) +{ + if (fCopyBitsJustCalled) { + printf("TestView::Draw(%.1f, %.1f, %.1f, %.1f) after CopyBits()\n", + updateRect.left, updateRect.top, updateRect.right, updateRect.bottom); + fCopyBitsJustCalled = false; + } + + SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + FillRect(updateRect); + + BRect r(Bounds()); + + // draw some pattern with lines + float width = r.Width(); + float height = r.Height(); + int32 lineCount = 20; + for (int32 i = 0; i < lineCount; i++) { + SetHighColor(255, (255 / lineCount) * i, 255 - (255 / lineCount) * i); + StrokeLine(BPoint(r.left + (width / lineCount) * i, r.top), + BPoint(r.left, r.top + (height / lineCount) * i)); + StrokeLine(BPoint(r.right - (width / lineCount) * i, r.bottom), + BPoint(r.right, r.bottom - (height / lineCount) * i)); + } + + SetHighColor(255, 0, 0, 128); + + const char* message = "Left-Click and drag"; + width = StringWidth(message); + BPoint p(r.left + r.Width() / 2.0 - width / 2.0, + r.top + r.Height() / 2.0); + + DrawString(message, p); + + message = "to draw source rect!"; + width = StringWidth(message); + p.x = r.left + r.Width() / 2.0 - width / 2.0; + p.y += 20; + + DrawString(message, p); + + SetHighColor(0, 255, 0, 255); + StrokeRect(fSourceRect); + + SetHighColor(0, 0, 255, 255); + StrokeRect(fDestRect); +} + +// MouseDown +void +TestView::MouseDown(BPoint where) +{ + BMessage* message = Window()->CurrentMessage(); + uint32 buttons; + if (message && message->FindInt32("buttons", (int32*)&buttons) >= B_OK) { + if (buttons & B_PRIMARY_MOUSE_BUTTON) { + fTracking = TRACKING_SOURCE; + fSourceRect.left = where.x; + fSourceRect.top = where.y; + } + if (buttons & B_SECONDARY_MOUSE_BUTTON) { + fTracking = TRACKING_DEST; + fDestRect.left = where.x; + fDestRect.top = where.y; + } + Invalidate(); + _TrackMouse(where); + } +} + +// MouseUp +void +TestView::MouseUp(BPoint where) +{ + fTracking = TRACKING_NONE; +} + +// MouseMoved +void +TestView::MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage) +{ + if (fTracking > TRACKING_NONE) { + _TrackMouse(where); + } +} + +float +min4(float a, float b, float c, float d) +{ + return min_c(a, min_c(b, min_c(c, d))); +} + +float +max4(float a, float b, float c, float d) +{ + return max_c(a, max_c(b, max_c(c, d))); +} + +// _TrackMouse +void +TestView::_TrackMouse(BPoint where) +{ + BRect before; + BRect after; + bool invalidate = false; + switch (fTracking) { + case TRACKING_SOURCE: + before = fSourceRect; + fSourceRect.right = where.x; + fSourceRect.bottom = where.y; + after = fSourceRect; + invalidate = true; + break; + case TRACKING_DEST: + before = fDestRect; + fDestRect.right = where.x; + fDestRect.bottom = where.y; + after = fDestRect; + invalidate = true; + break; + } + if (invalidate) { + BRect dirty(min4(before.left, before.right, after.left, after.right), + min4(before.top, before.bottom, after.top, after.bottom), + max4(before.left, before.right, after.left, after.right), + max4(before.top, before.bottom, after.top, after.bottom)); + Invalidate(dirty); + } +} + + +// show_window +void +show_window(BRect frame, const char* name) +{ + BWindow* window = new BWindow(frame, name, + B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE); + + BView* view = new TestView(window->Bounds(), "test", B_FOLLOW_ALL, + B_WILL_DRAW/* | B_FULL_UPDATE_ON_RESIZE*/); + + window->AddChild(view); + BRect b(0.0, 0.0, 50.0, 15.0); + b.OffsetTo(5.0, view->Bounds().bottom - (b.Height() + 15.0)); + BButton* control = new BButton(b, "button", "Copy", new BMessage(MSG_COPY_BITS)); + view->AddChild(control); +printf("button frame:\n"); +control->Frame().PrintToStream(); + control->SetTarget(view); + + window->Show(); +} + +// main +int +main(int argc, char** argv) +{ + BApplication* app = new BApplication("application/x.vnd-Haiku.CopyBits"); + + BRect frame(50.0, 50.0, 300.0, 250.0); + show_window(frame, "CopyBits Test"); + + app->Run(); + + delete app; + return 0; +} diff --git a/src/tests/servers/app/copy_bits/run b/src/tests/servers/app/copy_bits/run new file mode 100755 index 0000000000..250609ddf1 --- /dev/null +++ b/src/tests/servers/app/copy_bits/run @@ -0,0 +1,5 @@ +#!/bin/sh + +../../../../../distro/x86.R1/beos/system/servers/app_server & +sleep 1s +../../../../../tests/servers/app/copy_bits/CopyBits