diff options
-rw-r--r-- | goodies/source/filter.vcl/epict/epict.cxx | 120 | ||||
-rw-r--r-- | goodies/source/filter.vcl/epict/makefile.mk | 2 | ||||
-rw-r--r-- | goodies/source/filter.vcl/eps/eps.cxx | 60 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/emfwr.cxx | 93 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/emfwr.hxx | 4 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmfwr.cxx | 84 | ||||
-rw-r--r-- | svtools/source/filter.vcl/wmf/wmfwr.hxx | 4 | ||||
-rw-r--r-- | svtools/util/makefile.mk | 1 | ||||
-rw-r--r-- | vcl/inc/vcl/cvtsvm.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/vcl/lineinfo.hxx | 14 | ||||
-rw-r--r-- | vcl/source/gdi/cvtsvm.cxx | 310 | ||||
-rw-r--r-- | vcl/source/gdi/lineinfo.cxx | 79 | ||||
-rw-r--r-- | vcl/win/source/gdi/salgdi_gdiplus.cxx | 2 |
13 files changed, 707 insertions, 68 deletions
diff --git a/goodies/source/filter.vcl/epict/epict.cxx b/goodies/source/filter.vcl/epict/epict.cxx index 4df7abea01fc..123aaa5e98c7 100644 --- a/goodies/source/filter.vcl/epict/epict.cxx +++ b/goodies/source/filter.vcl/epict/epict.cxx @@ -55,6 +55,9 @@ #include "dlgepct.hrc" #include "dlgepct.hxx" +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + //============================== PictWriter =================================== struct PictWriterAttrStackMember { @@ -77,7 +80,6 @@ struct PictPattern { sal_uInt32 nLo, nHi; }; - class PictWriter { private: @@ -178,6 +180,7 @@ private: void WriteTextArray(Point & rPoint, const String& rString, const sal_Int32 * pDXAry); + void HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); void WriteOpcodes(const GDIMetaFile & rMTF); void WriteHeader(const GDIMetaFile & rMTF); @@ -1371,6 +1374,65 @@ void PictWriter::WriteTextArray(Point & rPoint, const String& rString, const sal } } +void PictWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + aLinePolyPolygon = aLinePolyPolygon.getDefaultAdaptiveSubdivision(); + const sal_uInt32 nPolyCount(aLinePolyPolygon.count()); + SetAttrForFrame(); + + for(sal_uInt32 a(0); a < nPolyCount; a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount) + { + const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount + 1 : nPointCount); + const basegfx::B2DPoint aCurr(aCandidate.getB2DPoint(0)); + Point nCurr(basegfx::fround(aCurr.getX()), basegfx::fround(aCurr.getY())); + + for(sal_uInt32 b(0); b < nEdgeCount; b++) + { + const sal_uInt32 nNextIndex((b + 1) % nPointCount); + const basegfx::B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex)); + const Point nNext(basegfx::fround(aNext.getX()), basegfx::fround(aNext.getY())); + + WriteOpcode_Line(nCurr, nNext); + nCurr = nNext; + } + } + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(aLineColor); + const Color aOldFillColor(aFillColor); + + aLineColor = Color( COL_TRANSPARENT ); + aFillColor = aOldLineColor; + SetAttrForPaint(); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a).getDefaultAdaptiveSubdivision()); + WriteOpcode_Poly(PDM_PAINT, aPolygon); + } + + aLineColor = aOldLineColor; + aFillColor = aOldFillColor; + } + } +} void PictWriter::WriteOpcodes( const GDIMetaFile & rMTF ) { @@ -1417,8 +1479,19 @@ void PictWriter::WriteOpcodes( const GDIMetaFile & rMTF ) if( aLineColor != Color( COL_TRANSPARENT ) ) { - SetAttrForFrame(); - WriteOpcode_Line( pA->GetStartPoint(),pA->GetEndPoint() ); + if(pA->GetLineInfo().IsDefault()) + { + SetAttrForFrame(); + WriteOpcode_Line( pA->GetStartPoint(),pA->GetEndPoint() ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } } break; } @@ -1571,24 +1644,35 @@ void PictWriter::WriteOpcodes( const GDIMetaFile & rMTF ) { const Polygon& rPoly = pA->GetPolygon(); - Polygon aSimplePoly; - if ( rPoly.HasFlags() ) - rPoly.GetSimple( aSimplePoly ); - else - aSimplePoly = rPoly; - - const USHORT nSize = aSimplePoly.GetSize(); - Point aLast; - - if ( nSize ) + if( rPoly.GetSize() ) { - SetAttrForFrame(); - aLast = aSimplePoly[0]; + if(pA->GetLineInfo().IsDefault()) + { + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.GetSimple( aSimplePoly ); + else + aSimplePoly = rPoly; - for ( USHORT i = 1; i < nSize; i++ ) + const USHORT nSize = aSimplePoly.GetSize(); + Point aLast; + + if ( nSize ) + { + SetAttrForFrame(); + aLast = aSimplePoly[0]; + + for ( USHORT i = 1; i < nSize; i++ ) + { + WriteOpcode_Line( aLast, aSimplePoly[i] ); + aLast = aSimplePoly[i]; + } + } + } + else { - WriteOpcode_Line( aLast, aSimplePoly[i] ); - aLast = aSimplePoly[i]; + // LineInfo used; handle Dash/Dot and fat lines + HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); } } } diff --git a/goodies/source/filter.vcl/epict/makefile.mk b/goodies/source/filter.vcl/epict/makefile.mk index 33af96f1fb85..43a489dea78c 100644 --- a/goodies/source/filter.vcl/epict/makefile.mk +++ b/goodies/source/filter.vcl/epict/makefile.mk @@ -61,7 +61,7 @@ RESLIB1SRSFILES=$(SRS)$/$(TARGET).srs SHL1TARGET= ept$(DLLPOSTFIX) SHL1IMPLIB= epict -SHL1STDLIBS= $(TOOLSLIB) $(VCLLIB) $(SVTOOLLIB) $(CPPULIB) $(SALLIB) +SHL1STDLIBS= $(TOOLSLIB) $(VCLLIB) $(SVTOOLLIB) $(CPPULIB) $(SALLIB) $(BASEGFXLIB) SHL1LIBS= $(SLB)$/epict.lib diff --git a/goodies/source/filter.vcl/eps/eps.cxx b/goodies/source/filter.vcl/eps/eps.cxx index 8a163659050a..b66c118dbf8a 100644 --- a/goodies/source/filter.vcl/eps/eps.cxx +++ b/goodies/source/filter.vcl/eps/eps.cxx @@ -701,7 +701,40 @@ void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev ) Polygon aPoly( ( (const MetaPolyLineAction*) pMA )->GetPolygon() ); const LineInfo& rLineInfo = ( ( const MetaPolyLineAction*)pMA )->GetLineInfo(); ImplWriteLineInfo( rLineInfo ); - ImplPolyLine( aPoly ); + + if(basegfx::B2DLINEJOIN_NONE == rLineInfo.GetLineJoin() + && rLineInfo.GetWidth() > 1) + { + // emulate B2DLINEJOIN_NONE by creating single edges + const sal_uInt16 nPoints(aPoly.GetSize()); + const bool bCurve(aPoly.HasFlags()); + + for(sal_uInt16 a(0); a + 1 < nPoints; a++) + { + if(bCurve + && POLY_NORMAL != aPoly.GetFlags(a + 1) + && a + 2 < nPoints + && POLY_NORMAL != aPoly.GetFlags(a + 2) + && a + 3 < nPoints) + { + const Polygon aSnippet(4, + aPoly.GetConstPointAry() + a, + aPoly.GetConstFlagAry() + a); + ImplPolyLine(aSnippet); + a += 2; + } + else + { + const Polygon aSnippet(2, + aPoly.GetConstPointAry() + a); + ImplPolyLine(aSnippet); + } + } + } + else + { + ImplPolyLine( aPoly ); + } } break; @@ -2343,8 +2376,29 @@ void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo ) SvtGraphicStroke::DashArray l_aDashArray; if ( rLineInfo.GetStyle() == LINE_DASH ) l_aDashArray.push_back( 2 ); - double fLWidth = ( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5; - ImplWriteLineInfo( fLWidth, 10.0, SvtGraphicStroke::capButt, SvtGraphicStroke::joinMiter, l_aDashArray ); + const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5); + const double fMiterLimit(15.0); + SvtGraphicStroke::JoinType aJoinType(SvtGraphicStroke::joinMiter); + + switch(rLineInfo.GetLineJoin()) + { + default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE + // do NOT use SvtGraphicStroke::joinNone here + // since it will be written as numerical value directly + // and is NOT a valid EPS value + break; + case basegfx::B2DLINEJOIN_MITER: + aJoinType = SvtGraphicStroke::joinMiter; + break; + case basegfx::B2DLINEJOIN_BEVEL: + aJoinType = SvtGraphicStroke::joinBevel; + break; + case basegfx::B2DLINEJOIN_ROUND: + aJoinType = SvtGraphicStroke::joinRound; + break; + } + + ImplWriteLineInfo( fLWidth, fMiterLimit, SvtGraphicStroke::capButt, aJoinType, l_aDashArray ); } //--------------------------------------------------------------------------------- diff --git a/svtools/source/filter.vcl/wmf/emfwr.cxx b/svtools/source/filter.vcl/wmf/emfwr.cxx index df56afc4a250..f516c2eefbd0 100644 --- a/svtools/source/filter.vcl/wmf/emfwr.cxx +++ b/svtools/source/filter.vcl/wmf/emfwr.cxx @@ -33,6 +33,8 @@ #include "emfwr.hxx" #include <vcl/salbtype.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> // ----------- // - Defines - @@ -829,6 +831,46 @@ void EMFWriter::ImplWriteTextRecord( const Point& rPos, const String rText, cons // ----------------------------------------------------------------------------- +void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + ImplWritePolygonRecord( Polygon(aCandidate), FALSE ); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(maVDev.GetLineColor()); + const Color aOldFillColor(maVDev.GetFillColor()); + + maVDev.SetLineColor(); + maVDev.SetFillColor(aOldLineColor); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + ImplWritePolyPolygonRecord(PolyPolygon(Polygon(aPolygon))); + } + + maVDev.SetLineColor(aOldLineColor); + maVDev.SetFillColor(aOldFillColor); + } + } +} + +// ----------------------------------------------------------------------------- + void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) { for( ULONG j = 0, nActionCount = rMtf.GetActionCount(); j < nActionCount; j++ ) @@ -871,20 +913,31 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) { const MetaLineAction* pA = (const MetaLineAction*) pAction; - ImplCheckLineAttr(); + if(pA->GetLineInfo().IsDefault()) + { + ImplCheckLineAttr(); - ImplBeginRecord( WIN_EMR_MOVETOEX ); - ImplWritePoint( pA->GetStartPoint() ); - ImplEndRecord(); + ImplBeginRecord( WIN_EMR_MOVETOEX ); + ImplWritePoint( pA->GetStartPoint() ); + ImplEndRecord(); - ImplBeginRecord( WIN_EMR_LINETO ); - ImplWritePoint( pA->GetEndPoint() ); - ImplEndRecord(); + ImplBeginRecord( WIN_EMR_LINETO ); + ImplWritePoint( pA->GetEndPoint() ); + ImplEndRecord(); - ImplBeginRecord( WIN_EMR_SETPIXELV ); - ImplWritePoint( pA->GetEndPoint() ); - ImplWriteColor( maVDev.GetLineColor() ); - ImplEndRecord(); + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetEndPoint() ); + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } } } break; @@ -983,7 +1036,23 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) case( META_POLYLINE_ACTION ): { if( maVDev.IsLineColor() ) - ImplWritePolygonRecord( ( (const MetaPolyLineAction*) pAction )->GetPolygon(), FALSE ); + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + ImplWritePolygonRecord( rPoly, FALSE ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } + } } break; diff --git a/svtools/source/filter.vcl/wmf/emfwr.hxx b/svtools/source/filter.vcl/wmf/emfwr.hxx index 150aa1692ade..2d3c8801ba49 100644 --- a/svtools/source/filter.vcl/wmf/emfwr.hxx +++ b/svtools/source/filter.vcl/wmf/emfwr.hxx @@ -42,6 +42,9 @@ // - EMFWriter - // ------------- +class LineInfo; +namespace basegfx { class B2DPolygon; } + class EMFWriter { private: @@ -86,6 +89,7 @@ private: void ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, const Size& rSz, UINT32 nROP ); void ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth ); + void Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); void ImplWrite( const GDIMetaFile& rMtf ); public: diff --git a/svtools/source/filter.vcl/wmf/wmfwr.cxx b/svtools/source/filter.vcl/wmf/wmfwr.cxx index 3c3ca09692af..9b712e6f020c 100644 --- a/svtools/source/filter.vcl/wmf/wmfwr.cxx +++ b/svtools/source/filter.vcl/wmf/wmfwr.cxx @@ -42,8 +42,9 @@ #include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType #endif - #include <vcl/metric.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> //====================== MS-Windows-defines =============================== @@ -1145,6 +1146,49 @@ void WMFWriter::SetAllAttr() } +void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + aSrcLineInfo = rInfo; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + WMFRecord_PolyLine(Polygon(aCandidate)); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(aSrcLineColor); + const Color aOldFillColor(aSrcFillColor); + + aSrcLineColor = Color( COL_TRANSPARENT ); + aSrcFillColor = aOldLineColor; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + WMFRecord_Polygon(Polygon(aPolygon)); + } + + aSrcLineColor = aOldLineColor; + aSrcFillColor = aOldFillColor; + SetLineAndFillAttr(); + } + } +} + void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) { ULONG nA, nACount; @@ -1185,10 +1229,21 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) case META_LINE_ACTION: { const MetaLineAction* pA = (const MetaLineAction *) pMA; - aSrcLineInfo = pA->GetLineInfo(); - SetLineAndFillAttr(); - WMFRecord_MoveTo( pA->GetStartPoint() ); - WMFRecord_LineTo( pA->GetEndPoint() ); + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_MoveTo( pA->GetStartPoint() ); + WMFRecord_LineTo( pA->GetEndPoint() ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } } break; @@ -1250,9 +1305,22 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) case META_POLYLINE_ACTION: { const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA; - aSrcLineInfo = pA->GetLineInfo(); - SetLineAndFillAttr(); - WMFRecord_PolyLine( pA->GetPolygon() ); + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyLine( rPoly ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } } break; diff --git a/svtools/source/filter.vcl/wmf/wmfwr.hxx b/svtools/source/filter.vcl/wmf/wmfwr.hxx index 48986a280404..03ca14e7633f 100644 --- a/svtools/source/filter.vcl/wmf/wmfwr.hxx +++ b/svtools/source/filter.vcl/wmf/wmfwr.hxx @@ -65,6 +65,9 @@ struct WMFWriterAttrStackMember // ------------- class StarSymbolToMSMultiFont; +class LineInfo; +namespace basegfx { class B2DPolygon; } + class WMFWriter { private: @@ -202,6 +205,7 @@ private: void SetLineAndFillAttr(); void SetAllAttr(); + void HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); void WriteRecords(const GDIMetaFile & rMTF); void WriteHeader(const GDIMetaFile & rMTF, BOOL bPlaceable); diff --git a/svtools/util/makefile.mk b/svtools/util/makefile.mk index 80596d23e866..e95c55706549 100644 --- a/svtools/util/makefile.mk +++ b/svtools/util/makefile.mk @@ -140,6 +140,7 @@ SHL1STDLIBS+= \ $(VCLLIB) \ $(SVLLIB) \ $(SOTLIB) \ + $(BASEGFXLIB) \ $(UNOTOOLSLIB) \ $(TOOLSLIB) \ $(I18NISOLANGLIB) \ diff --git a/vcl/inc/vcl/cvtsvm.hxx b/vcl/inc/vcl/cvtsvm.hxx index cf4f3117a6ed..c6f4f2c9a126 100644 --- a/vcl/inc/vcl/cvtsvm.hxx +++ b/vcl/inc/vcl/cvtsvm.hxx @@ -86,6 +86,8 @@ #define GDI_UNICODE_COMMENT 1032 #define GDI_LINEJOIN_ACTION 1033 +#define GDI_EXTENDEDPOLYGON_ACTION 1034 +#define GDI_LINEDASHDOT_ACTION 1035 // ---------------- // - SVMConverter - diff --git a/vcl/inc/vcl/lineinfo.hxx b/vcl/inc/vcl/lineinfo.hxx index a57513b2826b..33758046c41e 100644 --- a/vcl/inc/vcl/lineinfo.hxx +++ b/vcl/inc/vcl/lineinfo.hxx @@ -41,6 +41,7 @@ // ---------------- class SvStream; +namespace basegfx { class B2DPolyPolygon; } struct ImplLineInfo { @@ -116,6 +117,19 @@ public: friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, LineInfo& rLineInfo ); friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo ); + + // helper to check if line width or DashDot is used + bool isDashDotOrFatLineUsed() const; + + // helper to get decomposed polygon data with the LineInfo applied. The source + // hairline polygon is given in io_rLinePolyPolygon. Both given polygons may + // contain results; e.g. when no fat line but DasDot is defined, the resut will + // be in io_rLinePolyPolygon while o_rFillPolyPolygon will be empty. When fat line + // is defined, it will be vice-versa. If none is defined, io_rLinePolyPolygon will + // not be changed (but o_rFillPolyPolygon will be freed) + void applyToB2DPolyPolygon( + basegfx::B2DPolyPolygon& io_rLinePolyPolygon, + basegfx::B2DPolyPolygon& o_rFillPolyPolygon) const; }; #endif // _SV_LINEINFO_HXX diff --git a/vcl/source/gdi/cvtsvm.cxx b/vcl/source/gdi/cvtsvm.cxx index 86d7d6bb39ee..27ce6630116c 100644 --- a/vcl/source/gdi/cvtsvm.cxx +++ b/vcl/source/gdi/cvtsvm.cxx @@ -88,18 +88,6 @@ void ImplReadPoly( SvStream& rIStm, Polygon& rPoly ) // ------------------------------------------------------------------------ -void ImplWritePoly( SvStream& rOStm, const Polygon& rPoly ) -{ - INT32 nSize = rPoly.GetSize(); - - rOStm << nSize; - - for( INT32 i = 0; i < nSize; i++ ) - rOStm << rPoly[ (USHORT) i ]; -} - -// ------------------------------------------------------------------------ - void ImplReadPolyPoly( SvStream& rIStm, PolyPolygon& rPolyPoly ) { Polygon aPoly; @@ -131,13 +119,15 @@ void ImplWritePolyPolyAction( SvStream& rOStm, const PolyPolygon& rPolyPoly ) for( n = 0; n < nPoly; n++ ) { - const Polygon& rPoly = rPolyPoly[ n ]; - const USHORT nSize = rPoly.GetSize(); + // #i102224# + Polygon aSimplePoly; + rPolyPoly[n].AdaptiveSubdivide(aSimplePoly); + const USHORT nSize(aSimplePoly.GetSize()); rOStm << (INT32) nSize; for( USHORT j = 0; j < nSize; j++ ) - rOStm << rPoly[ j ]; + rOStm << aSimplePoly[ j ]; } } @@ -378,6 +368,128 @@ void ImplSkipActions( SvStream& rIStm, ULONG nSkipCount ) } } +// ------------------------------------------------------------------------ + +bool ImplWriteExtendedPolyPolygonAction(SvStream& rOStm, const PolyPolygon& rPolyPolygon, bool bOnlyWhenCurve) +{ + const sal_uInt16 nPolygonCount(rPolyPolygon.Count()); + + if(nPolygonCount) + { + sal_uInt32 nAllPolygonCount(0); + sal_uInt32 nAllPointCount(0); + sal_uInt32 nAllFlagCount(0); + sal_uInt16 a(0); + + for(a = 0; a < nPolygonCount; a++) + { + const Polygon& rCandidate = rPolyPolygon.GetObject(a); + const sal_uInt16 nPointCount(rCandidate.GetSize()); + + if(nPointCount) + { + nAllPolygonCount++; + nAllPointCount += nPointCount; + + if(rCandidate.HasFlags()) + { + nAllFlagCount += nPointCount; + } + } + } + + if((bOnlyWhenCurve && nAllFlagCount) || (!bOnlyWhenCurve && nAllPointCount)) + { + rOStm << (INT16) GDI_EXTENDEDPOLYGON_ACTION; + + const sal_Int32 nActionSize( + 4 + // Action size + 2 + // PolygonCount + (nAllPolygonCount * 2) + // Points per polygon + (nAllPointCount << 3) + // Points themselves + nAllPolygonCount + // Bool if (when poly has points) it has flags, too + nAllFlagCount); // Flags themselves + + rOStm << nActionSize; + rOStm << (sal_uInt16)nAllPolygonCount; + + for(a = 0; a < nPolygonCount; a++) + { + const Polygon& rCandidate = rPolyPolygon.GetObject(a); + const sal_uInt16 nPointCount(rCandidate.GetSize()); + + if(nPointCount) + { + rOStm << nPointCount; + + for(sal_uInt16 b(0); b < nPointCount; b++) + { + rOStm << rCandidate[b]; + } + + if(rCandidate.HasFlags()) + { + rOStm << (BYTE)true; + + for(sal_uInt16 c(0); c < nPointCount; c++) + { + rOStm << (BYTE)rCandidate.GetFlags(c); + } + } + else + { + rOStm << (BYTE)false; + } + } + } + + return true; + } + } + + return false; +} + +// ------------------------------------------------------------------------ + +void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, PolyPolygon& rPolyPoly) +{ + rPolyPoly.Clear(); + sal_uInt16 nPolygonCount(0); + rIStm >> nPolygonCount; + + for(sal_uInt16 a(0); a < nPolygonCount; a++) + { + sal_uInt16 nPointCount(0); + rIStm >> nPointCount; + Polygon aCandidate(nPointCount); + + if(nPointCount) + { + for(sal_uInt16 b(0); b < nPointCount; b++) + { + rIStm >> aCandidate[b]; + } + + BYTE bHasFlags(false); + rIStm >> bHasFlags; + + if(bHasFlags) + { + BYTE aPolyFlags(0); + + for(sal_uInt16 c(0); c < nPointCount; c++) + { + rIStm >> aPolyFlags; + aCandidate.SetFlags(c, (PolyFlags)aPolyFlags); + } + } + } + + rPolyPoly.Insert(aCandidate); + } +} + // ---------------- // - SVMConverter - // ---------------- @@ -450,6 +562,7 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) rMtf.SetPrefSize( aPrefSz ); rMtf.SetPrefMapMode( aMapMode ); + sal_uInt32 nLastPolygonAction(0); for( INT32 i = 0L; i < nActions; i++ ) { @@ -491,6 +604,91 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) } break; + case (GDI_LINEDASHDOT_ACTION) : + { + INT16 a(0); + INT32 b(0); + + rIStm >> a; aLineInfo.SetDashCount(a); + rIStm >> b; aLineInfo.SetDashLen(b); + rIStm >> a; aLineInfo.SetDotCount(a); + rIStm >> b; aLineInfo.SetDotLen(b); + rIStm >> b; aLineInfo.SetDistance(b); + + if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen()) + || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen())) + && aLineInfo.GetDistance()) + { + aLineInfo.SetStyle(LINE_DASH); + } + } + break; + + case (GDI_EXTENDEDPOLYGON_ACTION) : + { + // read the PolyPolygon in every case + PolyPolygon aInputPolyPolygon; + ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon); + + // now check if it can be set somewhere + if(nLastPolygonAction < rMtf.GetActionCount()) + { + MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolyLineAction) + { + // replace MetaPolyLineAction when we have a single polygon. Do not rely on the + // same point count; the originally written GDI_POLYLINE_ACTION may have been + // Subdivided for better quality for older usages + if(1 == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolyLineAction( + aInputPolyPolygon.GetObject(0), + pPolyLineAction->GetLineInfo()), + nLastPolygonAction); + pPolyLineAction->Delete(); + } + } + else + { + MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolyPolygonAction) + { + // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the + // same sub-polygon count + if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolyPolygonAction( + aInputPolyPolygon), + nLastPolygonAction); + pPolyPolygonAction->Delete(); + } + } + else + { + MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction)); + + if(pPolygonAction) + { + // replace MetaPolygonAction + if(1 == aInputPolyPolygon.Count()) + { + rMtf.ReplaceAction( + new MetaPolygonAction( + aInputPolyPolygon.GetObject(0)), + nLastPolygonAction); + pPolygonAction->Delete(); + } + } + } + } + } + } + break; + case( GDI_RECT_ACTION ): { ImplReadRect( rIStm, aRect ); @@ -581,6 +779,7 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) case( GDI_POLYLINE_ACTION ): { ImplReadPoly( rIStm, aActionPoly ); + nLastPolygonAction = rMtf.GetActionCount(); if( bFatLine ) rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) ); @@ -602,7 +801,10 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) ); } else + { + nLastPolygonAction = rMtf.GetActionCount(); rMtf.AddAction( new MetaPolygonAction( aActionPoly ) ); + } } break; @@ -623,7 +825,10 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ) rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) ); } else + { + nLastPolygonAction = rMtf.GetActionCount(); rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) ); + } } break; @@ -1257,6 +1462,7 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, const LineInfo& rInfo = pAct->GetLineInfo(); const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle())); const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin()); + const bool bLineDashDot(LINE_DASH == rInfo.GetStyle()); if( bFatLine ) { @@ -1269,6 +1475,17 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, rOStm << (INT32) 6; rOStm << (INT16) rInfo.GetLineJoin(); } + + if(bLineDashDot) + { + rOStm << (INT16) GDI_LINEDASHDOT_ACTION; + rOStm << (INT32) 4 + 16; + rOStm << (INT16)rInfo.GetDashCount(); + rOStm << (INT32)rInfo.GetDashLen(); + rOStm << (INT16)rInfo.GetDotCount(); + rOStm << (INT32)rInfo.GetDotLen(); + rOStm << (INT32)rInfo.GetDistance(); + } } rOStm << (INT16) GDI_LINE_ACTION; @@ -1286,6 +1503,11 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, { nCount += 1; } + + if(bLineDashDot) + { + nCount += 1; + } } } break; @@ -1366,19 +1588,21 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, for( USHORT n = 0; n < nPoints; n++ ) rOStm << aChordPoly[ n ]; - nCount++; } break; case( META_POLYLINE_ACTION ): { + // #i102224# MetaPolyLineAction* pAct = (MetaPolyLineAction*) pAction; - const Polygon& rPoly = pAct->GetPolygon(); - const LineInfo& rInfo = pAct->GetLineInfo(); - const USHORT nPoints = rPoly.GetSize(); + Polygon aSimplePoly; + pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly); + const LineInfo& rInfo = pAct->GetLineInfo(); + const USHORT nPoints(aSimplePoly.GetSize()); const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle())); const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin()); + const bool bLineDashDot(LINE_DASH == rInfo.GetStyle()); if( bFatLine ) { @@ -1391,6 +1615,17 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, rOStm << (INT32) 6; rOStm << (INT16) rInfo.GetLineJoin(); } + + if(bLineDashDot) + { + rOStm << (INT16) GDI_LINEDASHDOT_ACTION; + rOStm << (INT32) 4 + 16; + rOStm << (INT16)rInfo.GetDashCount(); + rOStm << (INT32)rInfo.GetDashLen(); + rOStm << (INT16)rInfo.GetDotCount(); + rOStm << (INT32)rInfo.GetDotLen(); + rOStm << (INT32)rInfo.GetDistance(); + } } rOStm << (INT16) GDI_POLYLINE_ACTION; @@ -1398,10 +1633,18 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, rOStm << (INT32) nPoints; for( USHORT n = 0; n < nPoints; n++ ) - rOStm << rPoly[ n ]; + { + rOStm << aSimplePoly[ n ]; + } nCount++; + const PolyPolygon aPolyPolygon(pAct->GetPolygon()); + if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true)) + { + nCount++; + } + if( bFatLine ) { ImplWritePopAction( rOStm ); @@ -1411,24 +1654,36 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, { nCount += 1; } + + if(bLineDashDot) + { + nCount += 1; + } } } break; case( META_POLYGON_ACTION ): { - MetaPolygonAction* pAct = (MetaPolygonAction*) pAction; - const Polygon& rPoly = pAct->GetPolygon(); - const USHORT nPoints = rPoly.GetSize(); + // #i102224# + MetaPolygonAction* pAct = (MetaPolygonAction*)pAction; + Polygon aSimplePoly; + pAct->GetPolygon().AdaptiveSubdivide(aSimplePoly); + const USHORT nPoints(aSimplePoly.GetSize()); rOStm << (INT16) GDI_POLYGON_ACTION; rOStm << (INT32) ( 8 + ( nPoints << 3 ) ); rOStm << (INT32) nPoints; for( USHORT n = 0; n < nPoints; n++ ) - rOStm << rPoly[ n ]; - + rOStm << aSimplePoly[ n ]; nCount++; + + const PolyPolygon aPolyPolygon(pAct->GetPolygon()); + if(ImplWriteExtendedPolyPolygonAction(rOStm, aPolyPolygon, true)) + { + nCount++; + } } break; @@ -1437,6 +1692,11 @@ ULONG SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf, MetaPolyPolygonAction* pAct = (MetaPolyPolygonAction*) pAction; ImplWritePolyPolyAction( rOStm, pAct->GetPolyPolygon() ); nCount++; + + if(ImplWriteExtendedPolyPolygonAction(rOStm, pAct->GetPolyPolygon(), true)) + { + nCount++; + } } break; diff --git a/vcl/source/gdi/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx index 85a48f2b0f5e..7aa50811106b 100644 --- a/vcl/source/gdi/lineinfo.cxx +++ b/vcl/source/gdi/lineinfo.cxx @@ -34,6 +34,10 @@ #include <tools/vcompat.hxx> #include <tools/debug.hxx> #include <vcl/lineinfo.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dlinegeometry.hxx> +#include <numeric> DBG_NAME( LineInfo ) @@ -283,3 +287,78 @@ SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo ) { return( rOStm << *rLineInfo.mpImplLineInfo ); } + +// ----------------------------------------------------------------------- + +bool LineInfo::isDashDotOrFatLineUsed() const +{ + return (LINE_DASH == GetStyle() || GetWidth() > 1); +} + +// ----------------------------------------------------------------------- + +void LineInfo::applyToB2DPolyPolygon( + basegfx::B2DPolyPolygon& io_rLinePolyPolygon, + basegfx::B2DPolyPolygon& o_rFillPolyPolygon) const +{ + o_rFillPolyPolygon.clear(); + + if(io_rLinePolyPolygon.count()) + { + if(LINE_DASH == GetStyle()) + { + ::std::vector< double > fDotDashArray; + const double fDashLen(GetDashLen()); + const double fDotLen(GetDotLen()); + const double fDistance(GetDistance()); + + for(sal_uInt16 a(0); a < GetDashCount(); a++) + { + fDotDashArray.push_back(fDashLen); + fDotDashArray.push_back(fDistance); + } + + for(sal_uInt16 b(0); b < GetDotCount(); b++) + { + fDotDashArray.push_back(fDotLen); + fDotDashArray.push_back(fDistance); + } + + const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0)); + + if(fAccumulated > 0.0) + { + basegfx::B2DPolyPolygon aResult; + + for(sal_uInt32 c(0); c < io_rLinePolyPolygon.count(); c++) + { + basegfx::B2DPolyPolygon aLineTraget; + basegfx::tools::applyLineDashing( + io_rLinePolyPolygon.getB2DPolygon(c), + fDotDashArray, + &aLineTraget); + aResult.append(aLineTraget); + } + + io_rLinePolyPolygon = aResult; + } + } + + if(GetWidth() > 1 && io_rLinePolyPolygon.count()) + { + const double fHalfLineWidth((GetWidth() * 0.5) + 0.5); + + for(sal_uInt32 a(0); a < io_rLinePolyPolygon.count(); a++) + { + o_rFillPolyPolygon.append(basegfx::tools::createAreaGeometry( + io_rLinePolyPolygon.getB2DPolygon(a), + fHalfLineWidth, + GetLineJoin())); + } + + io_rLinePolyPolygon.clear(); + } + } +} + +// ----------------------------------------------------------------------- diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx index a9d346e74476..29e4ff1d801e 100644 --- a/vcl/win/source/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx @@ -243,7 +243,7 @@ bool WinSalGraphics::drawPolyLine(const basegfx::B2DPolygon& rPolygon, const bas impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin); } - if(rPolygon.isClosed()) + if(rPolygon.isClosed() && !bNoLineJoin) { // #i101491# needed to create the correct line joins aPath.CloseFigure(); |