diff --git a/headers/private/servers/app/DrawState.h b/headers/private/servers/app/DrawState.h index 3f93c12a89..7ebea18a35 100644 --- a/headers/private/servers/app/DrawState.h +++ b/headers/private/servers/app/DrawState.h @@ -59,6 +59,16 @@ class DrawState { float Scale() const { return fScale; } + // 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; + // additional clipping as requested by client void SetClippingRegion(const BRegion& region); const BRegion* ClippingRegion() const @@ -124,8 +134,6 @@ class DrawState { { return fMiterLimit; } // convenience functions - inline BPoint Transform(const BPoint& point) const; - inline BRect Transform(const BRect& rect) const; void PrintToStream() const; void SetSubPixelPrecise(bool precise); @@ -177,24 +185,6 @@ class DrawState { // inline implementations -// Transform -BPoint -DrawState::Transform(const BPoint& point) const -{ - BPoint p(point); - p += fOrigin; - p.x *= fScale; - p.y *= fScale; - return p; -} - -// Transform -BRect -DrawState::Transform(const BRect& rect) const -{ - return BRect(Transform(rect.LeftTop()), - Transform(rect.LeftBottom())); -} /* // ClippingRectAt BRect diff --git a/src/servers/app/DrawState.cpp b/src/servers/app/DrawState.cpp index 8d60ce40e7..b89eb32968 100644 --- a/src/servers/app/DrawState.cpp +++ b/src/servers/app/DrawState.cpp @@ -301,6 +301,79 @@ DrawState::SetScale(float scale) } } +// Transform +void +DrawState::Transform(float* x, float* y) const +{ + *x += fOrigin.x; + *y += fOrigin.y; + *x *= fScale; + *y *= fScale; +} + +// InverseTransform +void +DrawState::InverseTransform(float* x, float* y) const +{ + // TODO: watch out for fScale = 0? + *x /= fScale; + *y /= fScale; + *x -= fOrigin.x; + *y -= fOrigin.y; +} + +// Transform +void +DrawState::Transform(BPoint* point) const +{ + Transform(&(point->x), &(point->y)); +} + +// Transform +void +DrawState::Transform(BRect* rect) const +{ + Transform(&(rect->left), &(rect->top)); + Transform(&(rect->right), &(rect->bottom)); +} + +// Transform +void +DrawState::Transform(BRegion* region) const +{ + if (fScale == 1.0) { + if (fOrigin.x != 0.0 || fOrigin.y != 0.0) + region->OffsetBy((int32)fOrigin.x, (int32)fOrigin.y); + } else { + // TODO: optimize some more + BRegion converted; + int32 count = region->CountRects(); + for (int32 i = 0; i < count; i++) { + BRect r = region->RectAt(i); + BPoint lt(r.LeftTop()); + BPoint rb(r.RightBottom()); + // offset to bottom right corner of pixel before transformation + rb.x++; + rb.y++; + // apply transformation + Transform(<.x, <.y); + Transform(&rb.x, &rb.y); + // reset bottom right to pixel "index" + rb.x++; + rb.y++; + } + *region = converted; + } +} + +// InverseTransform +void +DrawState::InverseTransform(BPoint* point) const +{ + InverseTransform(&(point->x), &(point->y)); +} + + void DrawState::SetClippingRegion(const BRegion& region) diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp index 6cd6caf22e..ef73f12b76 100644 --- a/src/servers/app/Layer.cpp +++ b/src/servers/app/Layer.cpp @@ -45,6 +45,7 @@ Layer::Layer(BRect frame, const char* name, int32 token, : fName(name), fFrame(frame), + fScrollingOffset(0.0, 0.0), fDriver(driver), fRootLayer(NULL), @@ -559,8 +560,7 @@ BRect Layer::Bounds() const { BRect r(fFrame); -// r.OffsetTo(fBoundsLeftTop); - r.OffsetTo(BoundsOrigin()); + r.OffsetTo(ScrollingOffset()); return r; } @@ -730,9 +730,11 @@ Layer::ScrollBy(float x, float y) if (x == 0.0f && y == 0.0f) return; + fScrollingOffset.x += x; + fScrollingOffset.y += y; + // must lock, even if we change frame/origin coordinates if (!IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) { - fDrawState->OffsetOrigin(BPoint(x, y)); // set the region to be invalidated. BRegion invalid(fFullVisible); @@ -762,9 +764,6 @@ Layer::ScrollBy(float x, float y) GetRootLayer()->Unlock(); } - else { - fDrawState->OffsetOrigin(BPoint(x, y)); - } ScrolledByHook(x, y); @@ -877,17 +876,28 @@ Layer::Activated(bool active) BPoint -Layer::BoundsOrigin() const +Layer::ScrollingOffset() const +{ + return fScrollingOffset; +} + +void +Layer::SetDrawingOrigin(BPoint origin) +{ + fDrawState->SetOrigin(origin); + + // rebuild clipping + if (fDrawState->ClippingRegion()) + _RebuildDrawingRegion(); +} + + +BPoint +Layer::DrawingOrigin() const { BPoint origin(fDrawState->Origin()); float scale = Scale(); - // TODO: Figure this out, BoundsOrigin() - // is used for BView::Bounds(), but I think - // that the scale has nothing to do with it - // "local coordinate system origin" does have - // something to do with scale. - origin.x *= scale; origin.y *= scale; @@ -895,6 +905,17 @@ Layer::BoundsOrigin() const } +void +Layer::SetScale(float scale) +{ + fDrawState->SetScale(scale); + + // rebuild clipping + if (fDrawState->ClippingRegion()) + _RebuildDrawingRegion(); +} + + float Layer::Scale() const { @@ -950,7 +971,7 @@ void Layer::ConvertToParent(BPoint* pt) const { if (fParent) { - BPoint origin = BoundsOrigin(); + BPoint origin = ScrollingOffset(); pt->x -= origin.x; pt->y -= origin.y; pt->x += fFrame.left; @@ -963,7 +984,7 @@ void Layer::ConvertToParent(BRect* rect) const { if (fParent) { - BPoint origin = BoundsOrigin(); + BPoint origin = ScrollingOffset(); rect->OffsetBy(-origin.x, -origin.y); rect->OffsetBy(fFrame.left, fFrame.top); } @@ -974,7 +995,7 @@ void Layer::ConvertToParent(BRegion* reg) const { if (fParent) { - BPoint origin = BoundsOrigin(); + BPoint origin = ScrollingOffset(); reg->OffsetBy(-origin.x, -origin.y); reg->OffsetBy(fFrame.left, fFrame.top); } @@ -985,7 +1006,7 @@ void Layer::ConvertFromParent(BPoint* pt) const { if (fParent) { - BPoint origin = BoundsOrigin(); + BPoint origin = ScrollingOffset(); pt->x += origin.x; pt->y += origin.y; pt->x -= fFrame.left; @@ -998,7 +1019,7 @@ void Layer::ConvertFromParent(BRect* rect) const { if (fParent) { - BPoint origin = BoundsOrigin(); + BPoint origin = ScrollingOffset(); rect->OffsetBy(origin.x, origin.y); rect->OffsetBy(-fFrame.left, -fFrame.top); } @@ -1009,7 +1030,7 @@ void Layer::ConvertFromParent(BRegion* reg) const { if (fParent) { - BPoint origin = BoundsOrigin(); + BPoint origin = ScrollingOffset(); reg->OffsetBy(origin.x, origin.y); reg->OffsetBy(-fFrame.left, -fFrame.top); } @@ -1075,6 +1096,57 @@ Layer::ConvertFromScreen(BRegion* reg) const } } +//! converts a point from local *drawing* to screen coordinate system +void +Layer::ConvertToScreenForDrawing(BPoint* pt) const +{ + if (fParent) { + fDrawState->Transform(pt); + // NOTE: from here on, don't use the + // "*ForDrawing()" versions of the parent! + ConvertToParent(pt); + fParent->ConvertToScreen(pt); + } +} + +//! converts a rect from local *drawing* to screen coordinate system +void +Layer::ConvertToScreenForDrawing(BRect* rect) const +{ + if (fParent) { + fDrawState->Transform(rect); + // NOTE: from here on, don't use the + // "*ForDrawing()" versions of the parent! + ConvertToParent(rect); + fParent->ConvertToScreen(rect); + } +} + +//! converts a region from local *drawing* to screen coordinate system +void +Layer::ConvertToScreenForDrawing(BRegion* region) const +{ + if (fParent) { + fDrawState->Transform(region); + // NOTE: from here on, don't use the + // "*ForDrawing()" versions of the parent! + ConvertToParent(region); + fParent->ConvertToScreen(region); + } +} + +//! converts a point from screen to local coordinate system +void +Layer::ConvertFromScreenForDrawing(BPoint* pt) const +{ + if (fParent) { + ConvertFromParent(pt); + fParent->ConvertFromScreen(pt); + + fDrawState->InverseTransform(pt); + } +} + void Layer::_ResizeLayerFrameBy(float x, float y) { @@ -1333,7 +1405,7 @@ Layer::_RebuildDrawingRegion() // apply user clipping which is in native coordinate system if (const BRegion* userClipping = fDrawState->ClippingRegion()) { BRegion screenUserClipping(*userClipping); - ConvertToScreen(&screenUserClipping); + ConvertToScreenForDrawing(&screenUserClipping); fDrawingRegion.IntersectWith(&screenUserClipping); } } diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h index af51434ab1..a411f7a95b 100644 --- a/src/servers/app/Layer.h +++ b/src/servers/app/Layer.h @@ -119,7 +119,12 @@ class Layer { // coordinate system BRect Bounds() const; BRect Frame() const; - BPoint BoundsOrigin() const; // BoundsFrameDiff()? + BPoint ScrollingOffset() const; + + void SetDrawingOrigin(BPoint origin); + BPoint DrawingOrigin() const; + + void SetScale(float scale); float Scale() const; void ConvertToParent(BPoint* pt) const; @@ -136,6 +141,12 @@ class Layer { void ConvertFromScreen(BRect* rect) const; void ConvertFromScreen(BRegion* reg) const; + void ConvertToScreenForDrawing(BPoint* pt) const; + void ConvertToScreenForDrawing(BRect* rect) const; + void ConvertToScreenForDrawing(BRegion* reg) const; + + void ConvertFromScreenForDrawing(BPoint* pt) const; + virtual void MoveBy(float x, float y); virtual void ResizeBy(float x, float y); virtual void ScrollBy(float x, float y); @@ -226,11 +237,7 @@ class Layer { BString fName; BRect fFrame; -// TODO: should be removed or reused in a similar fashion -// to hold the accumulated origins from the graphics state stack. -// The same needs to be done for "scale". (Keeping an accumulated -// value.) -// BPoint fBoundsLeftTop; + BPoint fScrollingOffset; BRegion fVisible; BRegion fFullVisible; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index a3686533e6..e00ef2d758 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -515,6 +515,7 @@ ServerWindow::CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent) // TODO: rework the clipping stuff to remove RootLayer dependency and then // remove this hack: if (fWinBorder->IsOffscreenWindow()) { + newLayer->fVisible.Set(newLayer->fFrame); newLayer->fDrawingRegion.Set(newLayer->fFrame); } @@ -570,7 +571,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&src); link.Read(&dst); - // TODO: Are origin and scale handled in this conversion? + // TODO: confirm that in R5 this call is affected by origin and scale +// fCurrentLayer->ConvertToScreenForDrawing(&src); +// fCurrentLayer->ConvertToScreenForDrawing(&dst); fCurrentLayer->ConvertToScreen(&src); fCurrentLayer->ConvertToScreen(&dst); @@ -798,14 +801,16 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&x); link.Read(&y); - fCurrentLayer->CurrentState()->SetOrigin(BPoint(x, y)); + fCurrentLayer->SetDrawingOrigin(BPoint(x, y)); break; } case AS_LAYER_GET_ORIGIN: { STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: Layer: %s\n", Title(), fCurrentLayer->Name())); fLink.StartMessage(SERVER_TRUE); - fLink.Attach(fCurrentLayer->CurrentState()->Origin()); + // TODO: rename this where it is used in the BView code! + // (it wants to know scrolling offset, not drawing origin) + fLink.Attach(fCurrentLayer->ScrollingOffset()); fLink.Flush(); break; } @@ -899,7 +904,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) float scale; link.Read(&scale); - fCurrentLayer->CurrentState()->SetScale(scale); + fCurrentLayer->SetScale(scale); break; } case AS_LAYER_GET_SCALE: @@ -1138,8 +1143,9 @@ if (rootLayer) { DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: Layer: %s\n", Title(), fCurrentLayer->Name())); - // TODO: handle transformation (origin and scale) prior to converting to top - BRect invalRect; + // NOTE: looks like this call is NOT affected by origin and scale on R5 + // so this implementation is "correct" + BRect invalRect; link.Read(&invalRect); @@ -1159,8 +1165,8 @@ if (rootLayer) { DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: Layer: %s\n", Title(), fCurrentLayer->Name())); - // TODO: handle transformation (origin and scale) prior to converting to top - // TODO: Handle conversion to top + // NOTE: looks like this call is NOT affected by origin and scale on R5 + // so this implementation is "correct" BRegion invalidReg; int32 noOfRects; BRect rect; @@ -1683,8 +1689,8 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BPoint p1(x1, y1); BPoint p2(x2, y2); BPoint penPos = p2; - fCurrentLayer->ConvertToScreen(&p1); - fCurrentLayer->ConvertToScreen(&p2); + fCurrentLayer->ConvertToScreenForDrawing(&p1); + fCurrentLayer->ConvertToScreenForDrawing(&p2); driver->StrokeLine(p1, p2, fCurrentLayer->CurrentState()); // We update the pen here because many DrawingEngine calls which do not update the @@ -1703,7 +1709,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BRect rect; link.Read(&rect); - fCurrentLayer->ConvertToScreen(&rect); + fCurrentLayer->ConvertToScreenForDrawing(&rect); driver->InvertRect(rect); break; } @@ -1718,7 +1724,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&bottom); BRect rect(left,top,right,bottom); - fCurrentLayer->ConvertToScreen(&rect); + fCurrentLayer->ConvertToScreenForDrawing(&rect); driver->StrokeRect(rect, fCurrentLayer->CurrentState()); break; @@ -1730,7 +1736,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BRect rect; link.Read(&rect); - fCurrentLayer->ConvertToScreen(&rect); + fCurrentLayer->ConvertToScreenForDrawing(&rect); driver->FillRect(rect, fCurrentLayer->CurrentState()); break; } @@ -1748,7 +1754,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) if (sbmp) { BRect src = sbmp->Bounds(); BRect dst = src.OffsetToCopy(point); - fCurrentLayer->ConvertToScreen(&dst); + fCurrentLayer->ConvertToScreenForDrawing(&dst); driver->DrawBitmap(sbmp, src, dst, fCurrentLayer->CurrentState()); } @@ -1772,7 +1778,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) ServerBitmap* sbmp = fServerApp->FindBitmap(bitmapToken); if (sbmp) { - fCurrentLayer->ConvertToScreen(&dstRect); + fCurrentLayer->ConvertToScreenForDrawing(&dstRect); driver->DrawBitmap(sbmp, srcRect, dstRect, fCurrentLayer->CurrentState()); } @@ -1792,7 +1798,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&angle); link.Read(&span); - fCurrentLayer->ConvertToScreen(&r); + fCurrentLayer->ConvertToScreenForDrawing(&r); driver->DrawArc(r, angle, span, fCurrentLayer->CurrentState(), code == AS_FILL_ARC); break; @@ -1805,7 +1811,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BPoint pts[4]; for (int32 i = 0; i < 4; i++) { link.Read(&(pts[i])); - fCurrentLayer->ConvertToScreen(&pts[i]); + fCurrentLayer->ConvertToScreenForDrawing(&pts[i]); } driver->DrawBezier(pts, fCurrentLayer->CurrentState(), code == AS_FILL_BEZIER); @@ -1820,7 +1826,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BRect rect; link.Read(&rect); - fCurrentLayer->ConvertToScreen(&rect); + fCurrentLayer->ConvertToScreenForDrawing(&rect); driver->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE); break; @@ -1836,7 +1842,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&xrad); link.Read(&yrad); - fCurrentLayer->ConvertToScreen(&rect); + fCurrentLayer->ConvertToScreenForDrawing(&rect); driver->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT); break; @@ -1851,12 +1857,12 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) for (int32 i = 0; i < 3; i++) { link.Read(&(pts[i])); - fCurrentLayer->ConvertToScreen(&pts[i]); + fCurrentLayer->ConvertToScreenForDrawing(&pts[i]); } link.Read(&rect); - fCurrentLayer->ConvertToScreen(&rect); + fCurrentLayer->ConvertToScreenForDrawing(&rect); driver->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE); break; @@ -1879,14 +1885,14 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { for (int32 i = 0; i < pointCount; i++) - fCurrentLayer->ConvertToScreen(&pointList[i]); + fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]); driver->DrawPolygon(pointList, pointCount, polyFrame, fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON, isClosed && pointCount > 2); - delete[] pointList; } + delete[] pointList; break; } @@ -1909,7 +1915,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) { for (int32 i = 0; i < ptCount; i++) - fCurrentLayer->ConvertToScreen(&ptList[i]); + fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]); driver->DrawShape(shapeFrame, opCount, opList, ptCount, ptList, fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE); @@ -1941,7 +1947,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) region.Include(rects[i]); } - fCurrentLayer->ConvertToScreen(®ion); + fCurrentLayer->ConvertToScreenForDrawing(®ion); driver->FillRegion(region, fCurrentLayer->CurrentState()); delete[] rects; @@ -1974,8 +1980,8 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&(index->pt2.y)); link.Read(&(index->color)); - fCurrentLayer->ConvertToScreen(&index->pt1); - fCurrentLayer->ConvertToScreen(&index->pt2); + fCurrentLayer->ConvertToScreenForDrawing(&index->pt1); + fCurrentLayer->ConvertToScreenForDrawing(&index->pt2); } driver->StrokeLineArray(linecount, linedata, fCurrentLayer->CurrentState()); } @@ -1994,10 +2000,10 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&delta); link.ReadString(&string); - fCurrentLayer->ConvertToScreen(&location); + fCurrentLayer->ConvertToScreenForDrawing(&location); BPoint penLocation = driver->DrawString(string, length, location, fCurrentLayer->CurrentState(), &delta); - fCurrentLayer->ConvertFromScreen(&penLocation); + fCurrentLayer->ConvertFromScreenForDrawing(&penLocation); fCurrentLayer->CurrentState()->SetPenLocation(penLocation); free(string);