* implemented view bitmap options (B_BITMAP_TILE...) in

ViewLayer (for example, fixes NetPositive rendering
  HTML with a background image)
* use BRegion pool everywhere in ViewLayer
* WindowLayer update sessions distinguish between
  different reasons for the update: exposed and requested -
  on expose updates, the view backgrounds are cleared
  immidiately (as on R5), to keep the time previous stuff
  keeps showing as short as possible, while on requested
  updates, the background clearing is delayed until the
  client draws something, to keep the time until the client
  fills a view with content as small as possible to reduce
  flickering (might need more work, could be buggy yet)
* HWInterface and DrawingEngine support delayed syncing to
  the graphics hardware at least for FillRect/Region. The
  speed up gained by this is minor though.
* HWInterface cursor rendering uses a bit of rounding to
  avoid the slight transparent shadow around the cursor
  (I don't know if it is fully correct though, at least the
  shasow disappeared)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17172 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2006-04-19 14:12:57 +00:00
parent 99f695c9a5
commit dd98ed8dfc
20 changed files with 502 additions and 106 deletions
+107 -30
View File
@@ -22,6 +22,8 @@
#include "ServerWindow.h"
#include "WindowLayer.h"
#include "drawing_support.h"
#include <List.h>
#include <Message.h>
#include <PortLink.h>
@@ -809,14 +811,16 @@ ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
// do the blit, this will make sure
// that other more complex dirty regions
// are taken care of
BRegion copyRegion(stillVisibleBounds);
fWindow->CopyContents(&copyRegion, -x, -y);
BRegion* copyRegion = fWindow->GetRegion();
if (!copyRegion)
return;
copyRegion->Set(stillVisibleBounds);
fWindow->CopyContents(copyRegion, -x, -y);
// find the dirty region as far as we are
// concerned
BRegion* dirty = fWindow->GetRegion();
if (!dirty)
return;
BRegion* dirty = copyRegion;
// reuse copyRegion and call it dirty
dirty->Set(oldBounds);
stillVisibleBounds.OffsetBy(-x, -y);
@@ -860,17 +864,20 @@ ViewLayer::CopyBits(BRect src, BRect dst, BRegion& windowContentClipping)
// do the blit, this will make sure
// that other more complex dirty regions
// are taken care of
BRegion copyRegion(visibleSrc);
copyRegion.IntersectWith(&ScreenClipping(&windowContentClipping));
fWindow->CopyContents(&copyRegion, xOffset, yOffset);
BRegion* copyRegion = fWindow->GetRegion();
if (!copyRegion)
return;
copyRegion->Set(visibleSrc);
copyRegion->IntersectWith(&ScreenClipping(&windowContentClipping));
fWindow->CopyContents(copyRegion, xOffset, yOffset);
// find the dirty region as far as we are concerned
BRect dirtyDst(dst);
ConvertToVisibleInTopView(&dirtyDst);
BRegion* dirty = fWindow->GetRegion();
if (!dirty)
return;
BRegion* dirty = copyRegion;
// reuse copyRegion and call it "dirty"
dirty->Set(dirtyDst);
// exclude the part that we could copy
@@ -965,9 +972,11 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
if (fViewBitmap != NULL || !fViewColor.IsTransparentMagic()) {
// we can only draw within our own area
BRegion redraw(ScreenClipping(windowContentClipping));
BRegion* redraw = fWindow->GetRegion(ScreenClipping(windowContentClipping));
if (!redraw)
return;
// add the current clipping
redraw.IntersectWith(effectiveClipping);
redraw->IntersectWith(effectiveClipping);
if (fViewBitmap != NULL) {
// draw view bitmap
@@ -975,20 +984,79 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
BRect rect = fBitmapDestination;
ConvertToScreenForDrawing(&rect);
// lock the drawing engine for as long as we need the clipping
// to be valid
if (drawingEngine->Lock()) {
drawingEngine->ConstrainClippingRegion(&redraw);
align_rect_to_pixels(&rect);
DrawState defaultDrawState;
drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
rect, &defaultDrawState);
// NOTE: It is ok not to reset the clipping, that
// would only waste time
drawingEngine->Unlock();
if (fBitmapOptions & B_TILE_BITMAP_Y) {
// move rect up as much as needed
while (rect.top > redraw->Frame().top)
rect.OffsetBy(0.0, -(rect.Height() + 1));
}
if (fBitmapOptions & B_TILE_BITMAP_X) {
// move rect left as much as needed
while (rect.left > redraw->Frame().left)
rect.OffsetBy(-(rect.Width() + 1), 0.0);
}
// XXX: locking removed because the WindowLayer keeps the engine locked
// because it keeps track of syncing right now
// lock the drawing engine for as long as we need the clipping
// to be valid
if (rect.IsValid()/* && drawingEngine->Lock()*/) {
drawingEngine->ConstrainClippingRegion(redraw);
DrawState defaultDrawState;
if (fBitmapOptions & B_TILE_BITMAP) {
// tile across entire view
float start = rect.left;
while (rect.top < redraw->Frame().bottom) {
while (rect.left < redraw->Frame().right) {
drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
rect, &defaultDrawState);
rect.OffsetBy(rect.Width() + 1, 0.0);
}
rect.OffsetBy(start - rect.left, rect.Height() + 1);
}
// nothing left to be drawn
redraw->MakeEmpty();
} else if (fBitmapOptions & B_TILE_BITMAP_X) {
// tile in x direction
while (rect.left < redraw->Frame().right) {
drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
rect, &defaultDrawState);
rect.OffsetBy(rect.Width() + 1, 0.0);
}
// remove horizontal stripe from clipping
rect.left = redraw->Frame().left;
rect.right = redraw->Frame().right;
redraw->Exclude(rect);
} else if (fBitmapOptions & B_TILE_BITMAP_Y) {
// tile in y direction
while (rect.top < redraw->Frame().bottom) {
drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
rect, &defaultDrawState);
rect.OffsetBy(0.0, rect.Height() + 1);
}
// remove vertical stripe from clipping
rect.top = redraw->Frame().top;
rect.bottom = redraw->Frame().bottom;
redraw->Exclude(rect);
} else {
// no tiling at all
drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
rect, &defaultDrawState);
redraw->Exclude(rect);
}
// NOTE: It is ok not to reset the clipping, that
// would only waste time
// drawingEngine->Unlock();
}
redraw.Exclude(rect);
}
if (!fViewColor.IsTransparentMagic()) {
@@ -996,8 +1064,10 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
// this version of FillRegion ignores any
// clipping, that's why "redraw" needs to
// be correct
drawingEngine->FillRegion(redraw, fViewColor);
drawingEngine->FillRegion(*redraw, fViewColor);
}
fWindow->RecycleRegion(redraw);
}
fBackgroundDirty = false;
@@ -1176,9 +1246,12 @@ ViewLayer::RebuildClipping(bool deep)
// hand, views for which this feature is actually used will
// probably not have any children, so it is not that expensive
// after all
BRegion screenUserClipping(*userClipping);
fDrawState->Transform(&screenUserClipping);
fLocalClipping.IntersectWith(&screenUserClipping);
BRegion* screenUserClipping = fWindow->GetRegion(*userClipping);
if (!screenUserClipping)
return;
fDrawState->Transform(screenUserClipping);
fLocalClipping.IntersectWith(screenUserClipping);
fWindow->RecycleRegion(screenUserClipping);
}
fScreenClippingValid = false;
@@ -1198,8 +1271,12 @@ ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const
ConvertToVisibleInTopView(&clippedBounds);
if (clippedBounds.Width() < fScreenClipping.Frame().Width() ||
clippedBounds.Height() < fScreenClipping.Frame().Height()) {
BRegion temp(clippedBounds);
fScreenClipping.IntersectWith(&temp);
BRegion* temp = fWindow->GetRegion();
if (temp) {
temp->Set(clippedBounds);
fScreenClipping.IntersectWith(temp);
fWindow->RecycleRegion(temp);
}
}
fScreenClipping.IntersectWith(windowContentClipping);
+54 -33
View File
@@ -65,7 +65,6 @@ using std::nothrow;
// its previous position though if the exposed parts are not
// cleared right away. maybe there ought to be a flag in
// the update session, which tells us the cause of the update
#define DELAYED_BACKGROUND_CLEARING 1
WindowLayer::WindowLayer(const BRect& frame, const char *name,
@@ -81,6 +80,7 @@ WindowLayer::WindowLayer(const BRect& frame, const char *name,
fVisibleContentRegion(),
fVisibleContentRegionValid(false),
fDirtyRegion(),
fDirtyCause(0),
fBorderRegion(),
fBorderRegionValid(false),
@@ -609,8 +609,8 @@ WindowLayer::ProcessDirtyRegion(BRegion& region)
ServerWindow()->RequestRedraw();
}
// this is executed from the desktop thread
fDirtyRegion.Include(&region);
fDirtyCause |= UPDATE_EXPOSE;
}
@@ -639,6 +639,7 @@ WindowLayer::RedrawDirtyRegion()
// get write access, since we're holding
// the read lock for the whole time.
fDirtyRegion.MakeEmpty();
fDirtyCause = 0;
}
@@ -665,6 +666,7 @@ WindowLayer::MarkContentDirty(BRegion& regionOnScreen)
return;
regionOnScreen.IntersectWith(&VisibleContentRegion());
fDirtyCause |= UPDATE_REQUEST;
_TriggerContentRedraw(regionOnScreen);
}
@@ -684,7 +686,7 @@ WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion)
//fDrawingEngine->FillRegion(layerRegion, RGBColor(0, 255, 0, 255));
//snooze(10000);
fDirtyCause |= UPDATE_REQUEST;
_TriggerContentRedraw(layerRegion);
}
}
@@ -1621,25 +1623,32 @@ WindowLayer::_TriggerContentRedraw(BRegion& dirtyContentRegion)
if (IsVisible() && dirtyContentRegion.CountRects() > 0) {
// put this into the pending dirty region
// to eventually trigger a client redraw
bool wasExpose = fPendingUpdateSession.IsExpose();
BRegion* backgroundClearingRegion = &dirtyContentRegion;
_TransferToUpdateSession(&dirtyContentRegion);
#if DELAYED_BACKGROUND_CLEARING
// NOTE: currently not used, might come in handy later though
// if (!fTopLayer->IsBackgroundDirty())
// fTopLayer->MarkBackgroundDirty();
#else
// NOTE: turning off DELAYED_BACKGROUND_CLEARING will
// need investigation if it even still works...
if (!fContentRegionValid)
_UpdateContentRegion();
if (fPendingUpdateSession.IsExpose()) {
if (!fContentRegionValid)
_UpdateContentRegion();
if (fDrawingEngine->Lock()) {
fDrawingEngine->ConstrainClippingRegion(&dirtyContentRegion);
fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion,
&fContentRegion, true);
fDrawingEngine->Unlock();
if (!wasExpose) {
// there was suddenly added a dirty region
// caused by exposing content, we need to clear
// the entire background
backgroundClearingRegion = &fPendingUpdateSession.DirtyRegion();
}
if (fDrawingEngine->Lock()) {
fDrawingEngine->SuspendAutoSync();
fTopLayer->Draw(fDrawingEngine, backgroundClearingRegion,
&fContentRegion, true);
fDrawingEngine->Sync();
fDrawingEngine->Unlock();
}
}
#endif
}
}
@@ -1691,6 +1700,8 @@ WindowLayer::_TransferToUpdateSession(BRegion* contentDirtyRegion)
// add to pending
fPendingUpdateSession.SetUsed(true);
// if (!fPendingUpdateSession.IsExpose())
fPendingUpdateSession.AddCause(fDirtyCause);
fPendingUpdateSession.Include(contentDirtyRegion);
// clip pending update session from current
@@ -1699,14 +1710,10 @@ WindowLayer::_TransferToUpdateSession(BRegion* contentDirtyRegion)
// this could be done smarter (clip layers from pending
// that have not yet been redrawn in the current update
// session)
#if !DELAYED_BACKGROUND_CLEARING
// NOTE: turning off DELAYED_BACKGROUND_CLEARING will
// need investigation if it even still works...
if (fCurrentUpdateSession.IsUsed()) {
if (fCurrentUpdateSession.IsUsed() && fCurrentUpdateSession.IsExpose()) {
fCurrentUpdateSession.Exclude(contentDirtyRegion);
fEffectiveDrawingRegionValid = false;
}
#endif
if (!fUpdateRequested) {
// send this to client
@@ -1768,8 +1775,6 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
dirty->IntersectWith(&VisibleContentRegion());
//fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 0, 255));
link.StartMessage(B_OK);
// append the current window geometry to the
// message, the client will need it
@@ -1785,14 +1790,19 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
link.Attach<int32>(B_NULL_TOKEN);
link.Flush();
#if DELAYED_BACKGROUND_CLEARING
// NOTE: turning off DELAYED_BACKGROUND_CLEARING will
// need investigation if it even still works...
fTopLayer->Draw(fDrawingEngine, dirty,
&fContentRegion, true);
if (!fCurrentUpdateSession.IsExpose() && fDrawingEngine->Lock()) {
//fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 0, 255));
fDrawingEngine->SuspendAutoSync();
fTopLayer->Draw(fDrawingEngine, dirty,
&fContentRegion, true);
fDrawingEngine->Sync();
fDrawingEngine->Unlock();
} // else the background was cleared already
fRegionPool.Recycle(dirty);
#endif
} else {
printf("BeginUpdate() but no update requested!!\n");
link.StartMessage(B_ERROR);
@@ -1908,7 +1918,8 @@ WindowLayer::_ObeySizeLimits()
// constructor
WindowLayer::UpdateSession::UpdateSession()
: fDirtyRegion(),
fInUse(false)
fInUse(false),
fCause(0)
{
}
@@ -1943,8 +1954,17 @@ void
WindowLayer::UpdateSession::SetUsed(bool used)
{
fInUse = used;
if (!fInUse)
if (!fInUse) {
fDirtyRegion.MakeEmpty();
fCause = 0;
}
}
void
WindowLayer::UpdateSession::AddCause(uint8 cause)
{
fCause |= cause;
}
@@ -1953,6 +1973,7 @@ WindowLayer::UpdateSession::operator=(const WindowLayer::UpdateSession& other)
{
fDirtyRegion = other.fDirtyRegion;
fInUse = other.fInUse;
fCause = other.fCause;
return *this;
}
+13
View File
@@ -35,6 +35,11 @@ class WindowLayer;
// TODO: move this into a proper place
#define AS_REDRAW 'rdrw'
enum {
UPDATE_REQUEST = 0x01,
UPDATE_EXPOSE = 0x02,
};
class WindowLayer {
public:
WindowLayer(const BRect& frame,
@@ -248,6 +253,7 @@ class WindowLayer {
// the clipping, since it is local and the desktop
// thread is blocked
BRegion fDirtyRegion;
uint32 fDirtyCause;
// caching local regions
BRegion fBorderRegion;
@@ -301,12 +307,19 @@ class WindowLayer {
void SetUsed(bool used);
inline bool IsUsed() const
{ return fInUse; }
void AddCause(uint8 cause);
inline bool IsExpose() const
{ return fCause & UPDATE_EXPOSE; }
inline bool IsRequest() const
{ return fCause & UPDATE_REQUEST; }
UpdateSession& operator=(const UpdateSession& other);
private:
BRegion fDirtyRegion;
bool fInUse;
uint8 fCause;
};
BRegion fDecoratorRegion;
@@ -733,7 +733,8 @@ AccelerantHWInterface::CopyRegion(const clipping_rect* sortedRectList,
// FillRegion
void
AccelerantHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& color)
AccelerantHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& color,
bool autoSync)
{
if (fAccFillRect && fAccAcquireEngine) {
if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) {
@@ -750,7 +751,7 @@ AccelerantHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& col
fAccReleaseEngine(fEngineToken, &fSyncToken);
// sync
if (fAccSyncToToken)
if (autoSync && fAccSyncToToken)
fAccSyncToToken(&fSyncToken);
}
}
@@ -781,6 +782,14 @@ AccelerantHWInterface::InvertRegion(/*const*/ BRegion& region)
}
}
// Sync
void
AccelerantHWInterface::Sync()
{
if (fAccSyncToToken)
fAccSyncToToken(&fSyncToken);
}
// SetCursor
void
AccelerantHWInterface::SetCursor(ServerCursor* cursor)
@@ -59,9 +59,12 @@ public:
uint32 count,
int32 xOffset, int32 yOffset);
virtual void FillRegion(/*const*/ BRegion& region,
const RGBColor& color);
const RGBColor& color,
bool autoSync);
virtual void InvertRegion(/*const*/ BRegion& region);
virtual void Sync();
// cursor handling
virtual void SetCursor(ServerCursor* cursor);
virtual void SetCursorVisible(bool visible);
+10 -2
View File
@@ -944,7 +944,7 @@ DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList,
// FillRegion
void
DWindowHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& color)
DWindowHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& color, bool autoSync)
{
if (fAccFillRect && fAccAcquireEngine) {
if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) {
@@ -961,7 +961,7 @@ DWindowHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& color)
fAccReleaseEngine(fEngineToken, &fSyncToken);
// sync
if (fAccSyncToToken)
if (autoSync && fAccSyncToToken)
fAccSyncToToken(&fSyncToken);
}
}
@@ -997,6 +997,14 @@ DWindowHWInterface::InvertRegion(/*const*/ BRegion& region)
}
}
// Sync
void
DWindowHWInterface::Sync()
{
if (fAccSyncToToken)
fAccSyncToToken(&fSyncToken);
}
// FrontBuffer
RenderingBuffer*
DWindowHWInterface::FrontBuffer() const
+4 -1
View File
@@ -59,9 +59,12 @@ class DWindowHWInterface : public HWInterface {
uint32 count,
int32 xOffset, int32 yOffset);
virtual void FillRegion(/*const*/ BRegion& region,
const RGBColor& color);
const RGBColor& color,
bool autoSync);
virtual void InvertRegion(/*const*/ BRegion& region);
virtual void Sync();
// frame buffer access
virtual RenderingBuffer* FrontBuffer() const;
virtual RenderingBuffer* BackBuffer() const;
+52 -17
View File
@@ -21,7 +21,7 @@
#include "ServerCursor.h"
#include "RenderingBuffer.h"
#include "frame_buffer_support.h"
#include "drawing_support.h"
// make_rect_valid
static inline void
@@ -82,7 +82,8 @@ class FontLocker {
DrawingEngine::DrawingEngine(HWInterface* interface)
: fPainter(new Painter()),
fGraphicsCard(interface),
fAvailableHWAccleration(0)
fAvailableHWAccleration(0),
fSuspendSyncLevel(0)
{
}
@@ -152,6 +153,24 @@ DrawingEngine::ConstrainClippingRegion(const BRegion* region)
}
}
// SuspendAutoSync
void
DrawingEngine::SuspendAutoSync()
{
fSuspendSyncLevel++;
}
// Sync
void
DrawingEngine::Sync()
{
fSuspendSyncLevel--;
if (fSuspendSyncLevel == 0)
fGraphicsCard->Sync();
}
// #pragma mark -
// CopyRegion() does a topological sort of the rects in the
// region. The algorithm was suggested by Ingo Weinhold.
// It compares each rect with each rect and builds a tree
@@ -596,20 +615,23 @@ DrawingEngine::FillRect(BRect r, const RGBColor& color)
make_rect_valid(r);
r = fPainter->ClipRect(r);
if (r.IsValid()) {
fGraphicsCard->HideSoftwareCursor(r);
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(r);
// try hardware optimized version first
if (fAvailableHWAccleration & HW_ACC_FILL_REGION) {
BRegion region(r);
region.IntersectWith(fPainter->ClippingRegion());
fGraphicsCard->FillRegion(region, color);
fGraphicsCard->FillRegion(region, color,
fSuspendSyncLevel == 0
|| cursorTouched);
} else {
fPainter->FillRect(r, color.GetColor32());
fGraphicsCard->Invalidate(r);
}
fGraphicsCard->ShowSoftwareCursor();
if (cursorTouched)
fGraphicsCard->ShowSoftwareCursor();
}
WriteUnlock();
@@ -626,13 +648,14 @@ DrawingEngine::FillRegion(BRegion& r, const RGBColor& color)
// NOTE: region expected to be already clipped correctly!!
if (WriteLock()) {
BRect frame = r.Frame();
fGraphicsCard->HideSoftwareCursor(frame);
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(frame);
bool doInSoftware = true;
// try hardware optimized version first
if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0
&& frame.Width() * frame.Height() > 100) {
fGraphicsCard->FillRegion(r, color);
fGraphicsCard->FillRegion(r, color, fSuspendSyncLevel == 0
|| cursorTouched);
doInSoftware = false;
}
@@ -646,7 +669,8 @@ DrawingEngine::FillRegion(BRegion& r, const RGBColor& color)
fGraphicsCard->Invalidate(r.Frame());
}
fGraphicsCard->ShowSoftwareCursor();
if (cursorTouched)
fGraphicsCard->ShowSoftwareCursor();
WriteUnlock();
}
@@ -689,7 +713,7 @@ DrawingEngine::FillRect(BRect r, const DrawState *d)
make_rect_valid(r);
r = fPainter->ClipRect(r);
if (r.IsValid()) {
fGraphicsCard->HideSoftwareCursor(r);
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(r);
bool doInSoftware = true;
if ((r.Width() + 1) * (r.Height() + 1) > 100.0) {
@@ -701,13 +725,17 @@ DrawingEngine::FillRect(BRect r, const DrawState *d)
|| d->GetDrawingMode() == B_OP_OVER)) {
BRegion region(r);
region.IntersectWith(fPainter->ClippingRegion());
fGraphicsCard->FillRegion(region, d->HighColor());
fGraphicsCard->FillRegion(region, d->HighColor(),
fSuspendSyncLevel == 0
|| cursorTouched);
doInSoftware = false;
} else if (d->GetPattern() == B_SOLID_LOW
&& d->GetDrawingMode() == B_OP_COPY) {
BRegion region(r);
region.IntersectWith(fPainter->ClippingRegion());
fGraphicsCard->FillRegion(region, d->LowColor());
fGraphicsCard->FillRegion(region, d->LowColor(),
fSuspendSyncLevel == 0
|| cursorTouched);
doInSoftware = false;
}
}
@@ -719,7 +747,8 @@ DrawingEngine::FillRect(BRect r, const DrawState *d)
fGraphicsCard->Invalidate(r);
}
fGraphicsCard->ShowSoftwareCursor();
if (cursorTouched)
fGraphicsCard->ShowSoftwareCursor();
}
WriteUnlock();
@@ -736,7 +765,7 @@ DrawingEngine::FillRegion(BRegion& r, const DrawState *d)
if (WriteLock()) {
BRect clipped = fPainter->ClipRect(r.Frame());
if (clipped.IsValid()) {
fGraphicsCard->HideSoftwareCursor(clipped);
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(clipped);
bool doInSoftware = true;
// try hardware optimized version first
@@ -745,12 +774,16 @@ DrawingEngine::FillRegion(BRegion& r, const DrawState *d)
&& (d->GetDrawingMode() == B_OP_COPY
|| d->GetDrawingMode() == B_OP_OVER)) {
r.IntersectWith(fPainter->ClippingRegion());
fGraphicsCard->FillRegion(r, d->HighColor());
fGraphicsCard->FillRegion(r, d->HighColor(),
fSuspendSyncLevel == 0
|| cursorTouched);
doInSoftware = false;
} else if (d->GetPattern() == B_SOLID_LOW
&& d->GetDrawingMode() == B_OP_COPY) {
r.IntersectWith(fPainter->ClippingRegion());
fGraphicsCard->FillRegion(r, d->LowColor());
fGraphicsCard->FillRegion(r, d->LowColor(),
fSuspendSyncLevel == 0
|| cursorTouched);
doInSoftware = false;
}
}
@@ -768,7 +801,8 @@ DrawingEngine::FillRegion(BRegion& r, const DrawState *d)
fGraphicsCard->Invalidate(touched);
}
fGraphicsCard->ShowSoftwareCursor();
if (cursorTouched)
fGraphicsCard->ShowSoftwareCursor();
}
WriteUnlock();
@@ -1270,3 +1304,4 @@ DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height,
}
}
@@ -66,6 +66,9 @@ public:
// will remove any clipping (drawing allowed everywhere)
void ConstrainClippingRegion(const BRegion* region);
void SuspendAutoSync();
void Sync();
// drawing functions
void CopyRegion(/*const*/ BRegion* region,
int32 xOffset, int32 yOffset);
@@ -156,6 +159,7 @@ public:
Painter* fPainter;
HWInterface* fGraphicsCard;
uint32 fAvailableHWAccleration;
int32 fSuspendSyncLevel;
};
#endif // DRAWING_ENGINE_H_
+13 -9
View File
@@ -10,7 +10,7 @@
#include <stdio.h>
#include <string.h>
#include "frame_buffer_support.h"
#include "drawing_support.h"
#include "RenderingBuffer.h"
#include "ServerCursor.h"
@@ -302,7 +302,7 @@ HWInterface::CopyBackToFront(const BRect& frame)
}
// HideSoftwareCursor
void
bool
HWInterface::HideSoftwareCursor(const BRect& area)
{
if (fCursorAreaBackup && !fCursorAreaBackup->cursor_hidden) {
@@ -312,8 +312,10 @@ HWInterface::HideSoftwareCursor(const BRect& area)
fCursorAreaBackup->bottom);
if (area.Intersects(backupArea)) {
_RestoreCursorArea();
return true;
}
}
return false;
}
// HideSoftwareCursor
@@ -404,10 +406,11 @@ HWInterface::_DrawCursor(BRect area) const
*(uint32*)b = *(uint32*)s;
// assumes backbuffer alpha = 255
// assuming pre-multiplied cursor bitmap
uint8 a = 255 - c[3];
d[0] = ((b[0] * a) >> 8) + c[0];
d[1] = ((b[1] * a) >> 8) + c[1];
d[2] = ((b[2] * a) >> 8) + c[2];
int a = 255 - c[3];
d[0] = ((int)(b[0] * a + 255) >> 8) + c[0];
d[1] = ((int)(b[1] * a + 255) >> 8) + c[1];
d[2] = ((int)(b[2] * a + 255) >> 8) + c[2];
s += 4;
c += 4;
d += 4;
@@ -428,9 +431,10 @@ HWInterface::_DrawCursor(BRect area) const
// assumes backbuffer alpha = 255
// assuming pre-multiplied cursor bitmap
uint8 a = 255 - c[3];
d[0] = ((s[0] * a) >> 8) + c[0];
d[1] = ((s[1] * a) >> 8) + c[1];
d[2] = ((s[2] * a) >> 8) + c[2];
d[0] = ((s[0] * a + 255) >> 8) + c[0];
d[1] = ((s[1] * a + 255) >> 8) + c[1];
d[2] = ((s[2] * a + 255) >> 8) + c[2];
s += 4;
c += 4;
d += 4;
+5 -2
View File
@@ -73,9 +73,12 @@ class HWInterface : public MultiLocker {
uint32 count,
int32 xOffset, int32 yOffset) {}
virtual void FillRegion(/*const*/ BRegion& region,
const RGBColor& color) {}
const RGBColor& color,
bool autoSync) {}
virtual void InvertRegion(/*const*/ BRegion& region) {}
virtual void Sync() {}
// cursor handling (these do their own Read/Write locking)
ServerCursor* Cursor() const { return fCursor; }
virtual void SetCursor(ServerCursor* cursor);
@@ -115,7 +118,7 @@ class HWInterface : public MultiLocker {
// ---
// NOTE: Investigate locking for these! The client code should already hold a
// ReadLock, but maybe these functions should acquire a WriteLock!
void HideSoftwareCursor(const BRect& area);
bool HideSoftwareCursor(const BRect& area);
void HideSoftwareCursor();
void ShowSoftwareCursor();
+1
View File
@@ -13,6 +13,7 @@ StaticLibrary libasdrawing.a :
AccelerantBuffer.cpp
AccelerantHWInterface.cpp
BitmapBuffer.cpp
drawing_support.cpp
DrawingEngine.cpp
MallocBuffer.cpp
UpdateQueue.cpp
+6 -8
View File
@@ -26,7 +26,7 @@
#include <agg_span_image_filter_rgba32.h>
#include <agg_span_interpolator_linear.h>
#include "frame_buffer_support.h"
#include "drawing_support.h"
#include "DrawState.h"
@@ -210,6 +210,8 @@ Painter::SetDrawState(const DrawState* data, bool updateFont)
fLineJoinMode = data->LineJoinMode();
fMiterLimit = data->MiterLimit();
// adopt the color *after* the pattern is set
// to set the renderers to the correct color
SetHighColor(data->HighColor().GetColor32());
SetLowColor(data->LowColor().GetColor32());
@@ -240,7 +242,7 @@ Painter::SetHighColor(const rgb_color& color)
void
Painter::SetLowColor(const rgb_color& color)
{
fPatternHandler->SetLowColor(color);;
fPatternHandler->SetLowColor(color);
if (*(fPatternHandler->GetR5Pattern()) == B_SOLID_LOW)
_SetRendererColor(color);
}
@@ -1356,12 +1358,8 @@ Painter::_DrawBitmap(const agg::rendering_buffer& srcBuffer, color_space format,
return;
}
if (!fSubpixelPrecise) {
// round off viewRect (in a way avoiding too much distortion)
viewRect.OffsetTo(roundf(viewRect.left), roundf(viewRect.top));
viewRect.right = roundf(viewRect.right);
viewRect.bottom = roundf(viewRect.bottom);
}
if (!fSubpixelPrecise)
align_rect_to_pixels(&viewRect);
double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
@@ -9,7 +9,7 @@
#ifndef DRAWING_MODE_H
#define DRAWING_MODE_H
#include "frame_buffer_support.h"
#include "drawing_support.h"
#include "PatternHandler.h"
#include "PixelFormat.h"
@@ -0,0 +1,13 @@
#include "drawing_support.h"
#include <Rect.h>
void
align_rect_to_pixels(BRect* rect)
{
// round the rect with the least ammount of distortion
rect->OffsetTo(roundf(rect->left), roundf(rect->top));
rect->right = roundf(rect->right);
rect->bottom = roundf(rect->bottom);
}
@@ -138,6 +138,9 @@ blend_line32(uint8* buffer, int32 pixels, uint8 r, uint8 g, uint8 b, uint8 a)
gfxcpy32(buffer, tempBuffer, pixels * 4);
}
void
align_rect_to_pixels(BRect* rect);
#endif // SUPPORT_H
+2
View File
@@ -103,6 +103,7 @@ Server haiku_app_server :
AccelerantBuffer.cpp
AccelerantHWInterface.cpp
BitmapBuffer.cpp
drawing_support.cpp
DrawingEngine.cpp
MallocBuffer.cpp
UpdateQueue.cpp
@@ -148,6 +149,7 @@ SubInclude HAIKU_TOP src tests servers app copy_bits ;
SubInclude HAIKU_TOP src tests servers app cursor_test ;
SubInclude HAIKU_TOP src tests servers app desktop_window ;
SubInclude HAIKU_TOP src tests servers app event_mask ;
SubInclude HAIKU_TOP src tests servers app following ;
SubInclude HAIKU_TOP src tests servers app look_and_feel ;
SubInclude HAIKU_TOP src tests servers app painter ;
SubInclude HAIKU_TOP src tests servers app playground ;
+17
View File
@@ -0,0 +1,17 @@
SubDir HAIKU_TOP src tests servers app following ;
SetSubDirSupportedPlatformsBeOSCompatible ;
AddSubDirSupportedPlatforms libbe_test ;
UseHeaders [ FDirName os app ] ;
UseHeaders [ FDirName os interface ] ;
SimpleTest Following :
main.cpp
: be ;
if ( $(TARGET_PLATFORM) = libbe_test ) {
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : Following
: tests!apps ;
}
+164
View File
@@ -0,0 +1,164 @@
// main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <Application.h>
#include <Message.h>
#include <Button.h>
#include <View.h>
#include <Window.h>
enum {
TRACKING_NONE = 0,
TRACKING_ALL,
TRACKING_RIGHT,
TRACKING_BOTTOM,
TRACKING_RIGHT_BOTTOM,
};
class TestView : public BView {
public:
TestView(BRect frame, const char* name,
uint32 resizeFlags, uint32 flags)
: BView(frame, name, resizeFlags, flags),
fTracking(TRACKING_NONE),
fLastMousePos(0.0, 0.0)
{
rgb_color color;
color.red = rand() / 256;
color.green = rand() / 256;
color.blue = rand() / 256;
color.alpha = 255;
SetViewColor(color);
SetLowColor(color);
}
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:
uint32 fTracking;
BPoint fLastMousePos;
};
// Draw
void
TestView::Draw(BRect updateRect)
{
// text
SetHighColor(0, 0, 0, 255);
const char* message = "Click and drag to move this view!";
DrawString(message, BPoint(20.0, 30.0));
BRect r(Bounds());
r.right -= 15.0;
r.bottom -= 15.0;
StrokeLine(r.RightTop(), BPoint(r.right, Bounds().bottom));
StrokeLine(r.LeftBottom(), BPoint(Bounds().right, r.bottom));
}
// MouseDown
void
TestView::MouseDown(BPoint where)
{
BRect r(Bounds());
r.right -= 15.0;
r.bottom -= 15.0;
if (r.Contains(where))
fTracking = TRACKING_ALL;
else if (r.bottom < where.y && r.right < where.x)
fTracking = TRACKING_RIGHT_BOTTOM;
else if (r.bottom < where.y)
fTracking = TRACKING_BOTTOM;
else if (r.right < where.x)
fTracking = TRACKING_RIGHT;
fLastMousePos = where;
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
}
// MouseUp
void
TestView::MouseUp(BPoint where)
{
fTracking = TRACKING_NONE;
}
// MouseMoved
void
TestView::MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage)
{
BPoint offset = where - fLastMousePos;
switch (fTracking) {
case TRACKING_ALL:
MoveBy(offset.x, offset.y);
// fLastMousePos stays fixed
break;
case TRACKING_RIGHT:
ResizeBy(offset.x, 0.0);
fLastMousePos = where;
break;
case TRACKING_BOTTOM:
ResizeBy(0.0, offset.y);
fLastMousePos = where;
break;
case TRACKING_RIGHT_BOTTOM:
ResizeBy(offset.x, offset.y);
fLastMousePos = where;
break;
}
}
// 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 1", B_FOLLOW_ALL,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
window->AddChild(view);
BRect bounds = view->Bounds();
bounds.InsetBy(20, 20);
BView* view1 = new TestView(bounds, "test 2", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
view->AddChild(view1);
bounds = view1->Bounds();
bounds.InsetBy(20, 20);
BView* view2 = new TestView(bounds, "test 3", B_FOLLOW_NONE,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
view1->AddChild(view2);
window->Show();
}
// main
int
main(int argc, char** argv)
{
BApplication* app = new BApplication("application/x.vnd-Haiku.Following");
BRect frame(50.0, 50.0, 300.0, 250.0);
show_window(frame, "Following Test");
app->Run();
delete app;
return 0;
}
+18
View File
@@ -0,0 +1,18 @@
#!/bin/sh
../../../../../generated/tests/apps/run_haiku_registrar || exit
if test -f ../../../../../generated/tests/apps/haiku_app_server; then
../../../../../generated/tests/apps/haiku_app_server &
else
echo "You need to \"TARGET_PLATFORM=r5 jam install-test-apps\" first."
fi
sleep 1s
if test -f ../../../../../generated/tests/apps/Following; then
../../../../../generated/tests/apps/Following
else
echo "You need to \"TARGET_PLATFORM=r5 jam install-test-apps\" first."
fi