diff --git a/headers/os/interface/InterfaceDefs.h b/headers/os/interface/InterfaceDefs.h index b1808cd73d..accef2cbff 100644 --- a/headers/os/interface/InterfaceDefs.h +++ b/headers/os/interface/InterfaceDefs.h @@ -261,6 +261,14 @@ enum cap_mode { const float B_DEFAULT_MITER_LIMIT = 10.0F; +// Polygon filling rules + +enum { + B_EVEN_ODD = 0, + B_NONZERO +}; + + // Bitmap and overlay constants enum bitmap_tiling { diff --git a/headers/os/interface/View.h b/headers/os/interface/View.h index bda8acd059..84a63b0f5b 100644 --- a/headers/os/interface/View.h +++ b/headers/os/interface/View.h @@ -282,6 +282,9 @@ public: cap_mode LineCapMode() const; float LineMiterLimit() const; + void SetFillRule(int32 rule); + int32 FillRule() const; + void SetOrigin(BPoint pt); void SetOrigin(float x, float y); BPoint Origin() const; diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 782a5780fb..e85f774ba6 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -345,6 +345,10 @@ enum { AS_VIEW_SET_TRANSFORM, AS_VIEW_GET_TRANSFORM, + // Polygon filling rules + AS_VIEW_SET_FILL_RULE, + AS_VIEW_GET_FILL_RULE, + AS_LAST_CODE }; diff --git a/headers/private/interface/ViewPrivate.h b/headers/private/interface/ViewPrivate.h index 4be0f77869..a9073d4edd 100644 --- a/headers/private/interface/ViewPrivate.h +++ b/headers/private/interface/ViewPrivate.h @@ -40,8 +40,9 @@ enum { B_VIEW_VIEW_COLOR_BIT = 0x00010000, B_VIEW_PATTERN_BIT = 0x00020000, B_VIEW_TRANSFORM_BIT = 0x00040000, + B_VIEW_FILL_RULE_BIT = 0x00080000, - B_VIEW_ALL_BITS = 0x0007ffff, + B_VIEW_ALL_BITS = 0x000fffff, // these used for archiving only B_VIEW_RESIZE_BIT = 0x00001000, @@ -123,6 +124,9 @@ class ViewState { cap_mode line_cap; float miter_limit; + // fill rule + int32 fill_rule; + // alpha blending source_alpha alpha_source_mode; alpha_function alpha_function_mode; diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index 9aaae85a50..c7395ddb69 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -149,6 +149,7 @@ ViewState::ViewState() line_join = B_MITER_JOIN; line_cap = B_BUTT_CAP; miter_limit = B_DEFAULT_MITER_LIMIT; + fill_rule = B_NONZERO; alpha_source_mode = B_PIXEL_ALPHA; alpha_function_mode = B_ALPHA_OVERLAY; @@ -494,6 +495,10 @@ BView::BView(BMessage* archive) && archive->FindFloat("_lmmiter", &lineMiter) == B_OK) SetLineMode((cap_mode)lineCap, (join_mode)lineJoin, lineMiter); + int16 fillRule; + if (archive->FindInt16("_fillrule", &fillRule) == B_OK) + SetFillRule(fillRule); + int16 alphaBlend; int16 modeBlend; if (archive->FindInt16("_blend", 0, &alphaBlend) == B_OK @@ -617,6 +622,9 @@ BView::Archive(BMessage* data, bool deep) const ret = data->AddFloat("_lmmiter", LineMiterLimit()); } + if (ret == B_OK && (fState->archiving_flags & B_VIEW_FILL_RULE_BIT) != 0) + ret = data->AddInt16("_fillrule", (int16)FillRule()); + if (ret == B_OK && (fState->archiving_flags & B_VIEW_BLENDING_BIT) != 0) { source_alpha alphaSourceMode; alpha_function alphaFunctionMode; @@ -1992,6 +2000,51 @@ BView::LineMiterLimit() const } +void +BView::SetFillRule(int32 fillRule) +{ + if (fState->IsValid(B_VIEW_FILL_RULE_BIT) && fillRule == fState->fill_rule) + return; + + if (fOwner) { + _CheckLockAndSwitchCurrent(); + + fOwner->fLink->StartMessage(AS_VIEW_SET_FILL_RULE); + fOwner->fLink->Attach(fillRule); + + fState->valid_flags |= B_VIEW_FILL_RULE_BIT; + } + + fState->fill_rule = fillRule; + + fState->archiving_flags |= B_VIEW_FILL_RULE_BIT; +} + + +int32 +BView::FillRule() const +{ + if (!fState->IsValid(B_VIEW_FILL_RULE_BIT) && fOwner) { + _CheckLockAndSwitchCurrent(); + + fOwner->fLink->StartMessage(AS_VIEW_GET_FILL_RULE); + + int32 code; + if (fOwner->fLink->FlushWithReply(code) == B_OK && code == B_OK) { + + int32 fillRule; + fOwner->fLink->Read(&fillRule); + + fState->fill_rule = fillRule; + } + + fState->valid_flags |= B_VIEW_FILL_RULE_BIT; + } + + return fState->fill_rule; +} + + void BView::SetDrawingMode(drawing_mode mode) { diff --git a/src/servers/app/DrawState.cpp b/src/servers/app/DrawState.cpp index c5b5ca3916..6d1dd32231 100644 --- a/src/servers/app/DrawState.cpp +++ b/src/servers/app/DrawState.cpp @@ -55,6 +55,7 @@ DrawState::DrawState() fLineCapMode(B_BUTT_CAP), fLineJoinMode(B_MITER_JOIN), fMiterLimit(B_DEFAULT_MITER_LIMIT), + fFillRule(B_NONZERO), fPreviousState(NULL) { fUnscaledFontSize = fFont.Size(); @@ -690,6 +691,13 @@ DrawState::SetMiterLimit(float limit) } +void +DrawState::SetFillRule(int32 fillRule) +{ + fFillRule = fillRule; +} + + void DrawState::PrintToStream() const { diff --git a/src/servers/app/DrawState.h b/src/servers/app/DrawState.h index 58ca037907..48508ed6cf 100644 --- a/src/servers/app/DrawState.h +++ b/src/servers/app/DrawState.h @@ -144,6 +144,10 @@ public: float MiterLimit() const { return fMiterLimit; } + void SetFillRule(int32 fillRule); + int32 FillRule() const + { return fFillRule; } + // convenience functions void PrintToStream() const; @@ -192,6 +196,7 @@ protected: cap_mode fLineCapMode; join_mode fLineJoinMode; float fMiterLimit; + int32 fFillRule; // "internal", used to calculate the size // of the font (again) when the scale changes float fUnscaledFontSize; diff --git a/src/servers/app/ProfileMessageSupport.cpp b/src/servers/app/ProfileMessageSupport.cpp index 519ebbf942..1dbb357d74 100644 --- a/src/servers/app/ProfileMessageSupport.cpp +++ b/src/servers/app/ProfileMessageSupport.cpp @@ -256,6 +256,8 @@ string_for_message_code(uint32 code, BString& string) CODE(AS_VIEW_SCROLL); CODE(AS_VIEW_SET_LINE_MODE); CODE(AS_VIEW_GET_LINE_MODE); + CODE(AS_VIEW_SET_FILL_RULE); + CODE(AS_VIEW_GET_FILL_RULE); CODE(AS_VIEW_PUSH_STATE); CODE(AS_VIEW_POP_STATE); CODE(AS_VIEW_SET_SCALE); diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index fdeb46722f..88d1c02e49 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1529,6 +1529,31 @@ fDesktop->LockSingleWindow(); break; } + case AS_VIEW_SET_FILL_RULE: + { + DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: " + "View: %s\n", Title(), fCurrentView->Name())); + int32 fillRule; + if (link.Read(&fillRule) != B_OK) + break; + + fCurrentView->CurrentState()->SetFillRule(fillRule); + fWindow->GetDrawingEngine()->SetFillRule(fillRule); + + break; + } + case AS_VIEW_GET_FILL_RULE: + { + DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: " + "View: %s\n", Title(), fCurrentView->Name())); + int32 fillRule = fCurrentView->CurrentState()->FillRule(); + + fLink.StartMessage(B_OK); + fLink.Attach(fillRule); + fLink.Flush(); + + break; + } case AS_VIEW_PUSH_STATE: { DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: " diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index 3fdc48f4f4..e37ad034bf 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -271,6 +271,13 @@ DrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode, } +void +DrawingEngine::SetFillRule(int32 fillRule) +{ + fPainter->SetFillRule(fillRule); +} + + void DrawingEngine::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc) { diff --git a/src/servers/app/drawing/DrawingEngine.h b/src/servers/app/drawing/DrawingEngine.h index ce89487ea3..dd15db25c3 100644 --- a/src/servers/app/drawing/DrawingEngine.h +++ b/src/servers/app/drawing/DrawingEngine.h @@ -76,6 +76,7 @@ public: virtual void SetPenSize(float size); virtual void SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit); + virtual void SetFillRule(int32 fillRule); virtual void SetPattern(const struct pattern& pattern); virtual void SetDrawingMode(drawing_mode mode); virtual void SetDrawingMode(drawing_mode mode, diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 2300d6cf48..95d53984ba 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -199,6 +199,7 @@ Painter::Painter() fLineCapMode(B_BUTT_CAP), fLineJoinMode(B_MITER_JOIN), fMiterLimit(B_DEFAULT_MITER_LIMIT), + fFillRule(B_NONZERO), fPatternHandler(), fTextRenderer(fSubpixRenderer, fRenderer, fRendererBin, fUnpackedScanline, @@ -423,6 +424,13 @@ Painter::SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit) } +void +Painter::SetFillRule(int32 fillRule) +{ + fFillRule = fillRule; +} + + // SetPattern void Painter::SetPattern(const pattern& p, bool drawingText) @@ -2827,16 +2835,22 @@ Painter::_RasterizePath(VertexSource& path) const if (fMaskedUnpackedScanline != NULL) { // TODO: we can't do both alpha-masking and subpixel AA. fRasterizer.reset(); + fRasterizer.filling_rule( + fFillRule == B_EVEN_ODD ? agg::fill_even_odd : agg::fill_non_zero); fRasterizer.add_path(path); agg::render_scanlines(fRasterizer, *fMaskedUnpackedScanline, fRenderer); } else if (gSubpixelAntialiasing) { fSubpixRasterizer.reset(); + fSubpixRasterizer.filling_rule( + fFillRule == B_EVEN_ODD ? agg::fill_even_odd : agg::fill_non_zero); fSubpixRasterizer.add_path(path); agg::render_scanlines(fSubpixRasterizer, fSubpixPackedScanline, fSubpixRenderer); } else { fRasterizer.reset(); + fRasterizer.filling_rule( + fFillRule == B_EVEN_ODD ? agg::fill_even_odd : agg::fill_non_zero); fRasterizer.add_path(path); agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer); } diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index 5042ed9e2d..b2ccc49bef 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -81,6 +81,7 @@ public: { return fPenSize; } void SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit); + void SetFillRule(int32 fillRule); void SetPattern(const pattern& p, bool drawingText = false); inline pattern Pattern() const @@ -394,6 +395,7 @@ private: cap_mode fLineCapMode; join_mode fLineJoinMode; float fMiterLimit; + int32 fFillRule; PatternHandler fPatternHandler;