diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index f1dde49d47..12af4882eb 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -134,23 +134,11 @@ DrawingEngine::SetHWInterface(HWInterface* interface) // #pragma mark - +//! the DrawingEngine needs to be locked! void DrawingEngine::ConstrainClippingRegion(const BRegion* region) { - if (Lock()) { - if (!region) { -// BRegion empty; -// fPainter->ConstrainClipping(empty); - if (RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer()) { - BRegion all; - all.Include(BRect(0, 0, buffer->Width() - 1, buffer->Height() - 1)); - fPainter->ConstrainClipping(all); - } - } else { - fPainter->ConstrainClipping(*region); - } - Unlock(); - } + fPainter->ConstrainClipping(region); } // SuspendAutoSync @@ -518,19 +506,10 @@ DrawingEngine::DrawEllipse(BRect r, const DrawState *d, bool filled) extend_by_stroke_width(clipped, d); clipped = fPainter->ClipRect(clipped); if (clipped.IsValid()) { - fGraphicsCard->HideSoftwareCursor(r); + fGraphicsCard->HideSoftwareCursor(clipped); fPainter->SetDrawState(d); - - float xRadius = r.Width() / 2.0; - float yRadius = r.Height() / 2.0; - BPoint center(r.left + xRadius, - r.top + yRadius); - - if (filled) - fPainter->FillEllipse(center, xRadius, yRadius); - else - fPainter->StrokeEllipse(center, xRadius, yRadius); + fPainter->DrawEllipse(r, filled); fGraphicsCard->Invalidate(clipped); fGraphicsCard->ShowSoftwareCursor(); @@ -573,6 +552,31 @@ DrawingEngine::StrokePoint(const BPoint& pt, const RGBColor &color) StrokeLine(pt, pt, color); } +// StrokeLine +// +// * this function is only used by Decorators +// * it assumes a one pixel wide line +void +DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, const RGBColor &color) +{ + if (Lock()) { + BRect touched(start, end); + make_rect_valid(touched); + touched = fPainter->ClipRect(touched); + fGraphicsCard->HideSoftwareCursor(touched); + + if (!fPainter->StraightLine(start, end, color.GetColor32())) { + DrawState context; + context.SetHighColor(color); + context.SetDrawingMode(B_OP_OVER); + StrokeLine(start, end, &context); + } else { + fGraphicsCard->Invalidate(touched); + } + fGraphicsCard->ShowSoftwareCursor(); + Unlock(); + } +} // this function is used to draw a one pixel wide rect void @@ -671,24 +675,20 @@ DrawingEngine::FillRegion(BRegion& r, const RGBColor& color) void DrawingEngine::StrokeRect(BRect r, const DrawState *d) { - if (Lock()) { - // support invalid rects - make_rect_valid(r); - BRect clipped(r); - extend_by_stroke_width(clipped, d); - clipped = fPainter->ClipRect(clipped); - if (clipped.IsValid()) { - - fGraphicsCard->HideSoftwareCursor(clipped); - - fPainter->SetDrawState(d); - fPainter->StrokeRect(r); - - fGraphicsCard->Invalidate(clipped); - fGraphicsCard->ShowSoftwareCursor(); - } + // support invalid rects + make_rect_valid(r); + BRect clipped(r); + extend_by_stroke_width(clipped, d); + clipped = fPainter->ClipRect(clipped); + if (clipped.IsValid()) { - Unlock(); + fGraphicsCard->HideSoftwareCursor(clipped); + + fPainter->SetDrawState(d); + fPainter->StrokeRect(r); + + fGraphicsCard->Invalidate(clipped); + fGraphicsCard->ShowSoftwareCursor(); } } @@ -804,9 +804,6 @@ void DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, const DrawState* d, bool filled) { - if (!Lock()) - return; - // NOTE: the stroke does not extend past "r" in R5, // though I consider this unexpected behaviour. make_rect_valid(r); @@ -821,8 +818,6 @@ DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); } - - Unlock(); } @@ -831,9 +826,6 @@ DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, const uint32* opList, int32 ptCount, const BPoint* ptList, const DrawState* d, bool filled) { - if (!Lock()) - return; - fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawState(d); @@ -843,8 +835,6 @@ DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); - - Unlock(); } @@ -852,51 +842,21 @@ void DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, const DrawState* d, bool filled) { - if (Lock()) { - BRect clipped(bounds); - if (!filled) - extend_by_stroke_width(clipped, d); - clipped = fPainter->ClipRect(clipped); - if (clipped.IsValid()) { - fGraphicsCard->HideSoftwareCursor(clipped); + BRect clipped(bounds); + if (!filled) + extend_by_stroke_width(clipped, d); + clipped = fPainter->ClipRect(clipped); + if (clipped.IsValid()) { + fGraphicsCard->HideSoftwareCursor(clipped); - fPainter->SetDrawState(d); - if (filled) - fPainter->FillTriangle(pts[0], pts[1], pts[2]); - else - fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); + fPainter->SetDrawState(d); + if (filled) + fPainter->FillTriangle(pts[0], pts[1], pts[2]); + else + fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); - fGraphicsCard->Invalidate(clipped); - fGraphicsCard->ShowSoftwareCursor(); - } - - Unlock(); - } -} - -// StrokeLine -// -// * this function is only used by Decorators -// * it assumes a one pixel wide line -void -DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, const RGBColor &color) -{ - if (Lock()) { - BRect touched(start, end); - make_rect_valid(touched); - touched = fPainter->ClipRect(touched); - fGraphicsCard->HideSoftwareCursor(touched); - - if (!fPainter->StraightLine(start, end, color.GetColor32())) { - DrawState context; - context.SetHighColor(color); - context.SetDrawingMode(B_OP_OVER); - StrokeLine(start, end, &context); - } else { - fGraphicsCard->Invalidate(touched); - } + fGraphicsCard->Invalidate(clipped); fGraphicsCard->ShowSoftwareCursor(); - Unlock(); } } @@ -904,22 +864,18 @@ DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, const RGBColor void DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, DrawState* context) { - if (Lock()) { - BRect touched(start, end); - make_rect_valid(touched); - extend_by_stroke_width(touched, context); - touched = fPainter->ClipRect(touched); - if (touched.IsValid()) { - fGraphicsCard->HideSoftwareCursor(touched); + BRect touched(start, end); + make_rect_valid(touched); + extend_by_stroke_width(touched, context); + touched = fPainter->ClipRect(touched); + if (touched.IsValid()) { + fGraphicsCard->HideSoftwareCursor(touched); - fPainter->SetDrawState(context); - touched = fPainter->StrokeLine(start, end); + fPainter->SetDrawState(context); + touched = fPainter->StrokeLine(start, end); - fGraphicsCard->Invalidate(touched); - fGraphicsCard->ShowSoftwareCursor(); - } - - Unlock(); + fGraphicsCard->Invalidate(touched); + fGraphicsCard->ShowSoftwareCursor(); } } @@ -931,51 +887,47 @@ DrawingEngine::StrokeLineArray(int32 numLines, if (!d || !linedata || numLines <= 0) return; - if (Lock()) { - // figure out bounding box for line array - const LineArrayData *data = (const LineArrayData *)&(linedata[0]); - BRect touched(min_c(data->pt1.x, data->pt2.x), - min_c(data->pt1.y, data->pt2.y), - max_c(data->pt1.x, data->pt2.x), - max_c(data->pt1.y, data->pt2.y)); + // figure out bounding box for line array + const LineArrayData *data = (const LineArrayData *)&(linedata[0]); + BRect touched(min_c(data->pt1.x, data->pt2.x), + min_c(data->pt1.y, data->pt2.y), + max_c(data->pt1.x, data->pt2.x), + max_c(data->pt1.y, data->pt2.y)); + + for (int32 i = 1; i < numLines; i++) { + data = (const LineArrayData *)&(linedata[i]); + BRect box(min_c(data->pt1.x, data->pt2.x), + min_c(data->pt1.y, data->pt2.y), + max_c(data->pt1.x, data->pt2.x), + max_c(data->pt1.y, data->pt2.y)); + touched = touched | box; + } + extend_by_stroke_width(touched, d); + touched = fPainter->ClipRect(touched); + if (touched.IsValid()) { + fGraphicsCard->HideSoftwareCursor(touched); + + data = (const LineArrayData *)&(linedata[0]); + + DrawState context; + context.SetDrawingMode(d->GetDrawingMode()); + context.SetLowColor(d->LowColor()); + context.SetHighColor(data->color); + context.SetPenSize(d->PenSize()); + // pen size is already correctly scaled + + fPainter->SetDrawState(&context); + + fPainter->StrokeLine(data->pt1, data->pt2); for (int32 i = 1; i < numLines; i++) { data = (const LineArrayData *)&(linedata[i]); - BRect box(min_c(data->pt1.x, data->pt2.x), - min_c(data->pt1.y, data->pt2.y), - max_c(data->pt1.x, data->pt2.x), - max_c(data->pt1.y, data->pt2.y)); - touched = touched | box; - } - extend_by_stroke_width(touched, d); - touched = fPainter->ClipRect(touched); - if (touched.IsValid()) { - fGraphicsCard->HideSoftwareCursor(touched); - - data = (const LineArrayData *)&(linedata[0]); - - DrawState context; - context.SetDrawingMode(d->GetDrawingMode()); - context.SetLowColor(d->LowColor()); - context.SetHighColor(data->color); - context.SetPenSize(d->PenSize()); - // pen size is already correctly scaled - - fPainter->SetDrawState(&context); - + fPainter->SetHighColor(data->color); fPainter->StrokeLine(data->pt1, data->pt2); - - for (int32 i = 1; i < numLines; i++) { - data = (const LineArrayData *)&(linedata[i]); - fPainter->SetHighColor(data->color); - fPainter->StrokeLine(data->pt1, data->pt2); - } - - fGraphicsCard->Invalidate(touched); - fGraphicsCard->ShowSoftwareCursor(); } - Unlock(); + fGraphicsCard->Invalidate(touched); + fGraphicsCard->ShowSoftwareCursor(); } } @@ -990,8 +942,8 @@ DrawingEngine::DrawString(const char* string, int32 length, FontLocker locker(d); BPoint penLocation = pt; - if (Lock()) { - fPainter->SetDrawState(d, true); + + fPainter->SetDrawState(d, true); //bigtime_t now = system_time(); // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. // Cursiously, the DrawString after it is actually faster!?! @@ -1000,22 +952,21 @@ DrawingEngine::DrawString(const char* string, int32 length, // in case we don't have one. // TODO: Watch out about penLocation and use Painter::PenLocation() when // not using BoundindBox anymore. - BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta); - // stop here if we're supposed to render outside of the clipping - b = fPainter->ClipRect(b); - if (b.IsValid()) { + BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta); + // stop here if we're supposed to render outside of the clipping + b = fPainter->ClipRect(b); + if (b.IsValid()) { //printf("bounding box '%s': %lld µs\n", string, system_time() - now); - fGraphicsCard->HideSoftwareCursor(b); + fGraphicsCard->HideSoftwareCursor(b); //now = system_time(); - BRect touched = fPainter->DrawString(string, length, pt, delta); + BRect touched = fPainter->DrawString(string, length, pt, delta); //printf("drawing string: %lld µs\n", system_time() - now); - fGraphicsCard->Invalidate(touched); - fGraphicsCard->ShowSoftwareCursor(); - } - Unlock(); + fGraphicsCard->Invalidate(touched); + fGraphicsCard->ShowSoftwareCursor(); } + return penLocation; } diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 20470aaf2d..6b84d7ed5d 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -215,7 +215,7 @@ Painter::SetDrawState(const DrawState* data, bool updateFont) SetHighColor(data->HighColor().GetColor32()); SetLowColor(data->LowColor().GetColor32()); - if (updateDrawingMode) + if (updateDrawingMode || fPixelFormat->UsesOpCopyForText()) _UpdateDrawingMode(); } @@ -223,10 +223,14 @@ Painter::SetDrawState(const DrawState* data, bool updateFont) // ConstrainClipping void -Painter::ConstrainClipping(const BRegion& region) +Painter::ConstrainClipping(const BRegion* region) { - *fClippingRegion = region; + *fClippingRegion = *region; fValidClipping = fClippingRegion->Frame().IsValid(); +// TODO: would be nice if we didn't need to copy a region +// for *each* drawing command... +//fBaseRenderer->set_clipping_region(const_cast(region)); +//fValidClipping = region->Frame().IsValid(); } // SetHighColor @@ -829,18 +833,67 @@ Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius) const return _FillPath(rect); } -// StrokeEllipse +// DrawEllipse BRect -Painter::StrokeEllipse(BPoint center, float xRadius, float yRadius) const +Painter::DrawEllipse(BRect r, bool fill) const { - return _DrawEllipse(center, xRadius, yRadius, false); -} + CHECK_CLIPPING -// FillEllipse -BRect -Painter::FillEllipse(BPoint center, float xRadius, float yRadius) const -{ - return _DrawEllipse(center, xRadius, yRadius, true); + if (!fSubpixelPrecise) { + // align rect to pixels + align_rect_to_pixels(&r); + // account for "pixel index" versus "pixel area" + r.right++; + r.bottom++; + if (!fill && fmodf(fPenSize, 2.0) != 0.0) { + // align the stroke + r.InsetBy(0.5, 0.5); + } + } + + float xRadius = r.Width() / 2.0; + float yRadius = r.Height() / 2.0; + BPoint center(r.left + xRadius, + r.top + yRadius); + + int32 divisions = (int32)max_c(12, (xRadius + yRadius + 2 * fPenSize) * PI / 2); + + if (fill) { + agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions); + + return _FillPath(path); + } else { + // NOTE: This implementation might seem a little strange, but it makes + // stroked ellipses look like on R5. A more correct way would be to use + // _StrokePath(), but it currently has its own set of problems with narrow + // ellipses (for small xRadii or yRadii). + float inset = fPenSize / 2.0; + agg::ellipse inner(center.x, center.y, + max_c(0.0, xRadius - inset), + max_c(0.0, yRadius - inset), + divisions); + agg::ellipse outer(center.x, center.y, + xRadius + inset, + yRadius + inset, + divisions); + + fRasterizer->reset(); + fRasterizer->add_path(outer); + fRasterizer->add_path(inner); + + // make the inner ellipse work as a hole + fRasterizer->filling_rule(agg::fill_even_odd); + + if (fPenSize > 4) + agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); + else + agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); + + // reset to default + fRasterizer->filling_rule(agg::fill_non_zero); + + return _Clipped(_BoundingBox(outer)); + } } // StrokeArc @@ -1120,16 +1173,20 @@ Painter::_UpdateDrawingMode(bool drawingText) // instead. If we have a B_SOLID_* pattern, we can actually use // the color in the renderer and special versions of drawing modes // that don't use PatternHandler and are more efficient. This - // has been implemented for B_OP_COPY as of now, the last parameter - // to DrawingModeFor() is a flag if a special "solid" drawing mode - // should be used if available. In this case, _SetRendererColor() + // has been implemented for B_OP_COPY and a couple others (the + // DrawingMode*Solid ones) as of now. The PixelFormat knows the + // PatternHandler and makes its decision based on the pattern. + // The last parameter to SetDrawingMode() is a flag if a special + // for when Painter is used to draw text. In this case, another + // special version of B_OP_COPY is used that acts like R5 in that + // anti-aliased pixel are not rendered against the actual background + // but the current low color instead. This way, the frame buffer + // doesn't need to be read. + // When a solid pattern is used, _SetRendererColor() // has to be called so that all internal colors in the renderes // are up to date for use by the solid drawing mode version. - if (fPixelFormat) { - fPixelFormat->SetDrawingMode(fDrawingMode, fAlphaSrcMode, - fAlphaFncMode, drawingText); - } - + fPixelFormat->SetDrawingMode(fDrawingMode, fAlphaSrcMode, + fAlphaFncMode, drawingText); } // _SetRendererColor @@ -1156,11 +1213,11 @@ Painter::_SetRendererColor(const rgb_color& color) const color.blue / 255.0, color.alpha / 255.0)); // TODO: bitmap fonts not yet correctly setup in AGGTextRenderer -// if (RendererBin) -// RendererBin->color(agg::rgba(color.red / 255.0, -// color.green / 255.0, -// color.blue / 255.0, -// color.alpha / 255.0)); +// if (fRendererBin) +// fRendererBin->color(agg::rgba(color.red / 255.0, +// color.green / 255.0, +// color.blue / 255.0, +// color.alpha / 255.0)); } @@ -1190,59 +1247,6 @@ Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3, bool fill) const return _StrokePath(path); } -// _DrawEllipse -inline BRect -Painter::_DrawEllipse(BPoint center, float xRadius, float yRadius, - bool fill) const -{ - CHECK_CLIPPING - - // TODO: I think the conversion and the offset of - // pixel centers might not be correct here, and it - // might even be necessary to treat Fill and Stroke - // differently, as with Fill-/StrokeRect(). - _Transform(¢er); - - int32 divisions = (int32)max_c(12, (xRadius + yRadius + 2 * fPenSize) * PI / 2); - - if (fill) { - agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions); - - return _FillPath(path); - } else { - // NOTE: This implementation might seem a little strange, but it makes - // stroked ellipses look like on R5. A more correct way would be to use - // _StrokePath(), but it currently has its own set of problems with narrow - // ellipses (for small xRadii or yRadii). - float inset = fPenSize / 2.0; - agg::ellipse inner(center.x, center.y, - max_c(0.0, xRadius - inset), - max_c(0.0, yRadius - inset), - divisions); - agg::ellipse outer(center.x, center.y, - xRadius + inset, - yRadius + inset, - divisions); - - fRasterizer->reset(); - fRasterizer->add_path(outer); - fRasterizer->add_path(inner); - - // make the inner ellipse work as a hole - fRasterizer->filling_rule(agg::fill_even_odd); - - if (fPenSize > 4) - agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); - else - agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); - - // reset to default - fRasterizer->filling_rule(agg::fill_non_zero); - - return _Clipped(_BoundingBox(outer)); - } -} - // copy_bitmap_row_cmap8_copy static inline void copy_bitmap_row_cmap8_copy(uint8* dst, const uint8* src, int32 numPixels, diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index 802b317017..d1876bfcd5 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -57,7 +57,7 @@ class Painter { void AttachToBuffer(RenderingBuffer* buffer); void DetachFromBuffer(); - void ConstrainClipping(const BRegion& region); + void ConstrainClipping(const BRegion* region); const BRegion* ClippingRegion() const { return fClippingRegion; } @@ -147,13 +147,8 @@ class Painter { float yRadius) const; // ellipses - BRect StrokeEllipse( BPoint center, - float xRadius, - float yRadius) const; - - BRect FillEllipse( BPoint center, - float xRadius, - float yRadius) const; + BRect DrawEllipse( BRect r, + bool filled) const; // arcs BRect StrokeArc( BPoint center, @@ -217,10 +212,6 @@ class Painter { BPoint pt2, BPoint pt3, bool fill) const; - BRect _DrawEllipse( BPoint center, - float xRadius, - float yRadius, - bool fill) const; void _DrawBitmap( const agg::rendering_buffer& srcBuffer, color_space format,