summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Le Grand <alg@apache.org>2012-01-17 16:54:04 +0000
committerArmin Le Grand <alg@apache.org>2012-01-17 16:54:04 +0000
commit2a0cd925bebb0c7d3513db311b185a04f259b68d (patch)
tree8d1ed154b241a9823c54b76ed091ecb6b6935a9d
parent63480c993d8e2fb0929d3c39f621aae9443faa04 (diff)
linecap: Reintegrating finished LineCap feature, kudos to Regina Henschel for doing the basic implementation and offering it under apache license
Notes
Notes: merged as: 44cfc7cb6533d827fd2d6e586d92c61d7d7f7a70
-rw-r--r--basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx5
-rw-r--r--basegfx/inc/basegfx/polygon/b2dpolygontools.hxx3
-rw-r--r--basegfx/source/polygon/b2dlinegeometry.cxx377
-rw-r--r--basegfx/source/polygon/b2dpolygontools.cxx27
-rw-r--r--basegfx/source/polygon/b3dpolygontools.cxx73
-rw-r--r--basegfx/source/polygon/b3dpolypolygontools.cxx29
-rw-r--r--canvas/source/vcl/canvashelper.cxx26
-rw-r--r--cppcanvas/source/mtfrenderer/implrenderer.cxx22
-rw-r--r--cui/source/inc/cuitabline.hxx7
-rw-r--r--cui/source/tabpages/tabline.hrc6
-rw-r--r--cui/source/tabpages/tabline.src25
-rw-r--r--cui/source/tabpages/tpline.cxx117
-rw-r--r--drawinglayer/inc/drawinglayer/attribute/lineattribute.hxx5
-rw-r--r--drawinglayer/inc/drawinglayer/attribute/sdrlineattribute.hxx3
-rw-r--r--drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx6
-rw-r--r--drawinglayer/source/attribute/lineattribute.cxx30
-rw-r--r--drawinglayer/source/attribute/sdrlineattribute.cxx28
-rw-r--r--drawinglayer/source/primitive2d/metafileprimitive2d.cxx3
-rw-r--r--drawinglayer/source/primitive2d/polygonprimitive2d.cxx25
-rw-r--r--drawinglayer/source/primitive3d/polygonprimitive3d.cxx9
-rw-r--r--drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx229
-rw-r--r--drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx2
-rw-r--r--drawinglayer/source/processor2d/canvasprocessor.cxx17
-rw-r--r--drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx24
-rw-r--r--editeng/inc/editeng/unoprnms.hxx1
-rw-r--r--filter/source/graphicfilter/eps/eps.cxx22
-rw-r--r--filter/source/msfilter/escherex.cxx30
-rw-r--r--filter/source/msfilter/msdffimp.cxx65
-rw-r--r--filter/source/svg/svgwriter.cxx89
-rw-r--r--filter/source/svg/svgwriter.hxx22
-rw-r--r--offapi/com/sun/star/drawing/LineCap.idl58
-rw-r--r--offapi/com/sun/star/drawing/LineProperties.idl22
-rw-r--r--offapi/com/sun/star/drawing/makefile.mk1
-rw-r--r--svgio/source/svgreader/svgstyleattributes.cxx29
-rw-r--r--svx/Package_inc.mk1
-rwxr-xr-xsvx/inc/svx/dialogs.hrc5
-rw-r--r--svx/inc/svx/unoshprp.hxx2
-rw-r--r--svx/inc/svx/xattr.hxx1
-rw-r--r--svx/inc/svx/xdef.hxx3
-rw-r--r--svx/inc/svx/xlncapit.hxx57
-rw-r--r--svx/source/dialog/sdstring.src13
-rw-r--r--svx/source/sdr/attribute/sdrformtextattribute.cxx9
-rw-r--r--svx/source/sdr/primitive2d/sdrattributecreator.cxx4
-rw-r--r--svx/source/sdr/primitive2d/sdrdecompositiontools.cxx2
-rw-r--r--svx/source/svdraw/svdfmtf.cxx7
-rw-r--r--svx/source/svdraw/svdfmtf.hxx1
-rw-r--r--svx/source/xoutdev/xattr2.cxx145
-rw-r--r--svx/source/xoutdev/xpool.cxx1
-rwxr-xr-xvcl/aqua/source/gdi/salgdi.cxx6
-rw-r--r--vcl/inc/aqua/salgdi.h7
-rw-r--r--vcl/inc/os2/salgdi.h7
-rwxr-xr-xvcl/inc/salgdi.hxx17
-rw-r--r--vcl/inc/unx/pspgraphics.h7
-rw-r--r--vcl/inc/unx/salgdi.h7
-rw-r--r--vcl/inc/vcl/cvtsvm.hxx3
-rw-r--r--vcl/inc/vcl/lineinfo.hxx7
-rw-r--r--vcl/inc/vcl/outdev.hxx14
-rw-r--r--vcl/inc/vcl/print.hxx5
-rwxr-xr-xvcl/inc/win/salgdi.h7
-rw-r--r--vcl/source/gdi/cvtsvm.cxx52
-rw-r--r--vcl/source/gdi/lineinfo.cxx45
-rw-r--r--vcl/source/gdi/outdev.cxx70
-rw-r--r--vcl/source/gdi/outdev6.cxx4
-rwxr-xr-xvcl/source/gdi/pdfwriter_impl.cxx88
-rwxr-xr-xvcl/source/gdi/salgdilayout.cxx15
-rw-r--r--vcl/unx/generic/gdi/pspgraphics.cxx7
-rw-r--r--vcl/unx/generic/gdi/salgdi.cxx9
-rw-r--r--vcl/unx/headless/svpgdi.cxx7
-rw-r--r--vcl/unx/headless/svpgdi.hxx7
-rw-r--r--vcl/unx/headless/svppspgraphics.cxx7
-rw-r--r--vcl/unx/headless/svppspgraphics.hxx7
-rw-r--r--vcl/win/source/gdi/salgdi_gdiplus.cxx28
-rw-r--r--xmloff/inc/xmloff/xmltoken.hxx2
-rw-r--r--xmloff/source/core/xmltoken.cxx2
-rw-r--r--xmloff/source/draw/sdpropls.cxx15
-rw-r--r--xmloff/source/draw/sdpropls.hxx1
76 files changed, 1832 insertions, 309 deletions
diff --git a/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx b/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx
index d90065f37c84..4e2270e75b6f 100644
--- a/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx
+++ b/basegfx/inc/basegfx/polygon/b2dlinegeometry.hxx
@@ -28,6 +28,7 @@
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
//////////////////////////////////////////////////////////////////////////////
@@ -101,6 +102,9 @@ namespace basegfx
The LineJoin if the edges meeting in a point do not have a C1
or C2 continuity
+ @param eCap
+ The kind of cap, which is added to the line.
+
@param fMaxAllowedAngle
Allows to hand over the maximum allowed angle between an edge and
it's control vectors. The smaller, the more subdivisions will be
@@ -128,6 +132,7 @@ namespace basegfx
const B2DPolygon& rCandidate,
double fHalfLineWidth,
B2DLineJoin eJoin = B2DLINEJOIN_ROUND,
+ com::sun::star::drawing::LineCap eCap = com::sun::star::drawing::LineCap_BUTT,
double fMaxAllowedAngle = (12.5 * F_PI180),
double fMaxPartOfEdge = 0.4,
double fMiterMinimumAngle = (15.0 * F_PI180));
diff --git a/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx b/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
index 11ccd395cf5d..592ab4b9209d 100644
--- a/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
+++ b/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
@@ -285,6 +285,9 @@ namespace basegfx
*/
B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double fRadius );
+ /// create half circle centered on (0,0) from [0 .. F_PI]
+ B2DPolygon createHalfUnitCircle();
+
/** create a polygon which describes the unit circle and close it
@param nStartQuadrant
diff --git a/basegfx/source/polygon/b2dlinegeometry.cxx b/basegfx/source/polygon/b2dlinegeometry.cxx
index e588be5368d2..b723cd5a63b1 100644
--- a/basegfx/source/polygon/b2dlinegeometry.cxx
+++ b/basegfx/source/polygon/b2dlinegeometry.cxx
@@ -34,6 +34,7 @@
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/curve/b2dcubicbezier.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
//////////////////////////////////////////////////////////////////////////////
@@ -338,7 +339,13 @@ namespace basegfx
}
}
- B2DPolygon createAreaGeometryForEdge(const B2DCubicBezier& rEdge, double fHalfLineWidth)
+ B2DPolyPolygon createAreaGeometryForEdge(
+ const B2DCubicBezier& rEdge,
+ double fHalfLineWidth,
+ bool bStartRound,
+ bool bEndRound,
+ bool bStartSquare,
+ bool bEndSquare)
{
// create polygon for edge
// Unfortunately, while it would be geometrically correct to not add
@@ -347,35 +354,102 @@ namespace basegfx
if(rEdge.isBezier())
{
// prepare target and data common for upper and lower
+ B2DPolyPolygon aRetval;
B2DPolygon aBezierPolygon;
const B2DVector aPureEdgeVector(rEdge.getEndPoint() - rEdge.getStartPoint());
const double fEdgeLength(aPureEdgeVector.getLength());
const bool bIsEdgeLengthZero(fTools::equalZero(fEdgeLength));
- const B2DVector aTangentA(rEdge.getTangent(0.0));
- const B2DVector aTangentB(rEdge.getTangent(1.0));
+ B2DVector aTangentA(rEdge.getTangent(0.0)); aTangentA.normalize();
+ B2DVector aTangentB(rEdge.getTangent(1.0)); aTangentB.normalize();
+ const B2DVector aNormalizedPerpendicularA(getPerpendicular(aTangentA));
+ const B2DVector aNormalizedPerpendicularB(getPerpendicular(aTangentB));
+
+ // create upper displacement vectors and check if they cut
+ const B2DVector aPerpendStartA(aNormalizedPerpendicularA * -fHalfLineWidth);
+ const B2DVector aPerpendEndA(aNormalizedPerpendicularB * -fHalfLineWidth);
+ double fCutA(0.0);
+ const tools::CutFlagValue aCutA(tools::findCut(
+ rEdge.getStartPoint(), aPerpendStartA,
+ rEdge.getEndPoint(), aPerpendEndA,
+ CUTFLAG_ALL, &fCutA));
+ const bool bCutA(CUTFLAG_NONE != aCutA);
+
+ // create lower displacement vectors and check if they cut
+ const B2DVector aPerpendStartB(aNormalizedPerpendicularA * fHalfLineWidth);
+ const B2DVector aPerpendEndB(aNormalizedPerpendicularB * fHalfLineWidth);
+ double fCutB(0.0);
+ const tools::CutFlagValue aCutB(tools::findCut(
+ rEdge.getEndPoint(), aPerpendEndB,
+ rEdge.getStartPoint(), aPerpendStartB,
+ CUTFLAG_ALL, &fCutB));
+ const bool bCutB(CUTFLAG_NONE != aCutB);
+
+ // check if cut happens
+ const bool bCut(bCutA || bCutB);
+
+ // create left edge
+ if(bStartRound || bStartSquare)
+ {
+ basegfx::B2DPolygon aStartPolygon;
+
+ if(bStartRound)
+ {
+ aStartPolygon = tools::createHalfUnitCircle();
+ aStartPolygon.transform(
+ tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ fHalfLineWidth, fHalfLineWidth,
+ 0.0,
+ atan2(aTangentA.getY(), aTangentA.getX()) + F_PI2,
+ rEdge.getStartPoint().getX(), rEdge.getStartPoint().getY()));
+ }
+ else // bStartSquare
+ {
+ const basegfx::B2DPoint aStart(rEdge.getStartPoint() - (aTangentA * fHalfLineWidth));
+
+ if(bCut)
+ {
+ aStartPolygon.append(rEdge.getStartPoint() + aPerpendStartB);
+ }
+
+ aStartPolygon.append(aStart + aPerpendStartB);
+ aStartPolygon.append(aStart + aPerpendStartA);
+
+ if(bCut)
+ {
+ aStartPolygon.append(rEdge.getStartPoint() + aPerpendStartA);
+ }
+ }
+
+ if(bCut)
+ {
+ aStartPolygon.append(rEdge.getStartPoint());
+ aStartPolygon.setClosed(true);
+ aRetval.append(aStartPolygon);
+ }
+ else
+ {
+ aBezierPolygon.append(aStartPolygon);
+ }
+ }
+ else
+ {
+ // append original in-between point
+ aBezierPolygon.append(rEdge.getStartPoint());
+ }
// create upper edge.
{
- // create displacement vectors and check if they cut
- const B2DVector aPerpendStart(getNormalizedPerpendicular(aTangentA) * -fHalfLineWidth);
- const B2DVector aPerpendEnd(getNormalizedPerpendicular(aTangentB) * -fHalfLineWidth);
- double fCut(0.0);
- const tools::CutFlagValue aCut(tools::findCut(
- rEdge.getStartPoint(), aPerpendStart,
- rEdge.getEndPoint(), aPerpendEnd,
- CUTFLAG_ALL, &fCut));
-
- if(CUTFLAG_NONE != aCut)
+ if(bCutA)
{
// calculate cut point and add
- const B2DPoint aCutPoint(rEdge.getStartPoint() + (aPerpendStart * fCut));
+ const B2DPoint aCutPoint(rEdge.getStartPoint() + (aPerpendStartA * fCutA));
aBezierPolygon.append(aCutPoint);
}
else
{
// create scaled bezier segment
- const B2DPoint aStart(rEdge.getStartPoint() + aPerpendStart);
- const B2DPoint aEnd(rEdge.getEndPoint() + aPerpendEnd);
+ const B2DPoint aStart(rEdge.getStartPoint() + aPerpendStartA);
+ const B2DPoint aEnd(rEdge.getEndPoint() + aPerpendEndA);
const B2DVector aEdge(aEnd - aStart);
const double fLength(aEdge.getLength());
const double fScale(bIsEdgeLengthZero ? 1.0 : fLength / fEdgeLength);
@@ -387,31 +461,69 @@ namespace basegfx
}
}
- // append original in-between point
- aBezierPolygon.append(rEdge.getEndPoint());
+ // create right edge
+ if(bEndRound || bEndSquare)
+ {
+ basegfx::B2DPolygon aEndPolygon;
+
+ if(bEndRound)
+ {
+ aEndPolygon = tools::createHalfUnitCircle();
+ aEndPolygon.transform(
+ tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ fHalfLineWidth, fHalfLineWidth,
+ 0.0,
+ atan2(aTangentB.getY(), aTangentB.getX()) - F_PI2,
+ rEdge.getEndPoint().getX(), rEdge.getEndPoint().getY()));
+ }
+ else // bEndSquare
+ {
+ const basegfx::B2DPoint aEnd(rEdge.getEndPoint() + (aTangentB * fHalfLineWidth));
+
+ if(bCut)
+ {
+ aEndPolygon.append(rEdge.getEndPoint() + aPerpendEndA);
+ }
+
+ aEndPolygon.append(aEnd + aPerpendEndA);
+ aEndPolygon.append(aEnd + aPerpendEndB);
+
+ if(bCut)
+ {
+ aEndPolygon.append(rEdge.getEndPoint() + aPerpendEndB);
+ }
+ }
+
+ if(bCut)
+ {
+ aEndPolygon.append(rEdge.getEndPoint());
+ aEndPolygon.setClosed(true);
+ aRetval.append(aEndPolygon);
+ }
+ else
+ {
+ aBezierPolygon.append(aEndPolygon);
+ }
+ }
+ else
+ {
+ // append original in-between point
+ aBezierPolygon.append(rEdge.getEndPoint());
+ }
// create lower edge.
{
- // create displacement vectors and check if they cut
- const B2DVector aPerpendStart(getNormalizedPerpendicular(aTangentA) * fHalfLineWidth);
- const B2DVector aPerpendEnd(getNormalizedPerpendicular(aTangentB) * fHalfLineWidth);
- double fCut(0.0);
- const tools::CutFlagValue aCut(tools::findCut(
- rEdge.getEndPoint(), aPerpendEnd,
- rEdge.getStartPoint(), aPerpendStart,
- CUTFLAG_ALL, &fCut));
-
- if(CUTFLAG_NONE != aCut)
+ if(bCutB)
{
// calculate cut point and add
- const B2DPoint aCutPoint(rEdge.getEndPoint() + (aPerpendEnd * fCut));
+ const B2DPoint aCutPoint(rEdge.getEndPoint() + (aPerpendEndB * fCutB));
aBezierPolygon.append(aCutPoint);
}
else
{
// create scaled bezier segment
- const B2DPoint aStart(rEdge.getEndPoint() + aPerpendEnd);
- const B2DPoint aEnd(rEdge.getStartPoint() + aPerpendStart);
+ const B2DPoint aStart(rEdge.getEndPoint() + aPerpendEndB);
+ const B2DPoint aEnd(rEdge.getStartPoint() + aPerpendStartB);
const B2DVector aEdge(aEnd - aStart);
const double fLength(aEdge.getLength());
const double fScale(bIsEdgeLengthZero ? 1.0 : fLength / fEdgeLength);
@@ -423,39 +535,108 @@ namespace basegfx
}
}
- // append original in-between point
- aBezierPolygon.append(rEdge.getStartPoint());
-
// close and return
aBezierPolygon.setClosed(true);
- return aBezierPolygon;
+ aRetval.append(aBezierPolygon);
+
+ return aRetval;
}
else
{
- // #i101491# emulate rEdge.getTangent call which applies a factor of 0.3 to the
- // full-length edge vector to have numerically exactly the same results as in the
- // createAreaGeometryForJoin implementation
- const B2DVector aEdgeTangent((rEdge.getEndPoint() - rEdge.getStartPoint()) * 0.3);
- const B2DVector aPerpendEdgeVector(getNormalizedPerpendicular(aEdgeTangent) * fHalfLineWidth);
+ // Get start and end point, create tangent and set to needed length
+ B2DVector aTangent(rEdge.getEndPoint() - rEdge.getStartPoint());
+ aTangent.setLength(fHalfLineWidth);
+
+ // prepare return value
B2DPolygon aEdgePolygon;
- // create upper edge
- aEdgePolygon.append(rEdge.getStartPoint() - aPerpendEdgeVector);
- aEdgePolygon.append(rEdge.getEndPoint() - aPerpendEdgeVector);
+ // buffered angle
+ double fAngle(0.0);
+ bool bAngle(false);
- // append original in-between point
- aEdgePolygon.append(rEdge.getEndPoint());
+ // buffered perpendicular
+ B2DVector aPerpend;
+ bool bPerpend(false);
- // create lower edge
- aEdgePolygon.append(rEdge.getEndPoint() + aPerpendEdgeVector);
- aEdgePolygon.append(rEdge.getStartPoint() + aPerpendEdgeVector);
+ // create left vertical
+ if(bStartRound)
+ {
+ aEdgePolygon = tools::createHalfUnitCircle();
+ fAngle = atan2(aTangent.getY(), aTangent.getX());
+ bAngle = true;
+ aEdgePolygon.transform(
+ tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ fHalfLineWidth, fHalfLineWidth,
+ 0.0,
+ fAngle + F_PI2,
+ rEdge.getStartPoint().getX(), rEdge.getStartPoint().getY()));
+ }
+ else
+ {
+ aPerpend.setX(-aTangent.getY());
+ aPerpend.setY(aTangent.getX());
+ bPerpend = true;
- // append original in-between point
- aEdgePolygon.append(rEdge.getStartPoint());
+ if(bStartSquare)
+ {
+ const basegfx::B2DPoint aStart(rEdge.getStartPoint() - aTangent);
+
+ aEdgePolygon.append(aStart + aPerpend);
+ aEdgePolygon.append(aStart - aPerpend);
+ }
+ else
+ {
+ aEdgePolygon.append(rEdge.getStartPoint() + aPerpend);
+ aEdgePolygon.append(rEdge.getStartPoint()); // keep the in-between point for numerical reasons
+ aEdgePolygon.append(rEdge.getStartPoint() - aPerpend);
+ }
+ }
+
+ // create right vertical
+ if(bEndRound)
+ {
+ basegfx::B2DPolygon aEndPolygon(tools::createHalfUnitCircle());
+
+ if(!bAngle)
+ {
+ fAngle = atan2(aTangent.getY(), aTangent.getX());
+ }
+
+ aEndPolygon.transform(
+ tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ fHalfLineWidth, fHalfLineWidth,
+ 0.0,
+ fAngle - F_PI2,
+ rEdge.getEndPoint().getX(), rEdge.getEndPoint().getY()));
+ aEdgePolygon.append(aEndPolygon);
+ }
+ else
+ {
+ if(!bPerpend)
+ {
+ aPerpend.setX(-aTangent.getY());
+ aPerpend.setY(aTangent.getX());
+ }
+
+ if(bEndSquare)
+ {
+ const basegfx::B2DPoint aEnd(rEdge.getEndPoint() + aTangent);
+
+ aEdgePolygon.append(aEnd - aPerpend);
+ aEdgePolygon.append(aEnd + aPerpend);
+ }
+ else
+ {
+ aEdgePolygon.append(rEdge.getEndPoint() - aPerpend);
+ aEdgePolygon.append(rEdge.getEndPoint()); // keep the in-between point for numerical reasons
+ aEdgePolygon.append(rEdge.getEndPoint() + aPerpend);
+ }
+ }
// close and return
aEdgePolygon.setClosed(true);
- return aEdgePolygon;
+
+ return B2DPolyPolygon(aEdgePolygon);
}
}
@@ -574,6 +755,7 @@ namespace basegfx
const B2DPolygon& rCandidate,
double fHalfLineWidth,
B2DLineJoin eJoin,
+ com::sun::star::drawing::LineCap eCap,
double fMaxAllowedAngle,
double fMaxPartOfEdge,
double fMiterMinimumAngle)
@@ -619,6 +801,7 @@ namespace basegfx
const bool bEventuallyCreateLineJoin(B2DLINEJOIN_NONE != eJoin);
const bool bIsClosed(aCandidate.isClosed());
const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);
+ const bool bLineCap(!bIsClosed && com::sun::star::drawing::LineCap_BUTT != eCap);
if(nEdgeCount)
{
@@ -649,16 +832,16 @@ namespace basegfx
// check and create linejoin
if(bEventuallyCreateLineJoin && (bIsClosed || 0 != a))
{
- const B2DVector aTangentPrev(aPrev.getTangent(1.0));
- const B2DVector aTangentEdge(aEdge.getTangent(0.0));
+ B2DVector aTangentPrev(aPrev.getTangent(1.0)); aTangentPrev.normalize();
+ B2DVector aTangentEdge(aEdge.getTangent(0.0)); aTangentEdge.normalize();
B2VectorOrientation aOrientation(getOrientation(aTangentPrev, aTangentEdge));
if(ORIENTATION_NEUTRAL == aOrientation)
{
- // they are parallell or empty; if they are both not zero and point
- // in opposite direction, a half-circle is needed
- if(!aTangentPrev.equalZero() && !aTangentEdge.equalZero())
- {
+ // they are parallell or empty; if they are both not zero and point
+ // in opposite direction, a half-circle is needed
+ if(!aTangentPrev.equalZero() && !aTangentEdge.equalZero())
+ {
const double fAngle(fabs(aTangentPrev.angle(aTangentEdge)));
if(fTools::equal(fAngle, F_PI))
@@ -672,38 +855,76 @@ namespace basegfx
if(ORIENTATION_POSITIVE == aOrientation)
{
- const B2DVector aPerpendPrev(getNormalizedPerpendicular(aTangentPrev) * -fHalfLineWidth);
- const B2DVector aPerpendEdge(getNormalizedPerpendicular(aTangentEdge) * -fHalfLineWidth);
-
- aRetval.append(createAreaGeometryForJoin(
- aTangentPrev, aTangentEdge,
- aPerpendPrev, aPerpendEdge,
- aEdge.getStartPoint(), fHalfLineWidth,
- eJoin, fMiterMinimumAngle));
+ const B2DVector aPerpendPrev(getPerpendicular(aTangentPrev) * -fHalfLineWidth);
+ const B2DVector aPerpendEdge(getPerpendicular(aTangentEdge) * -fHalfLineWidth);
+
+ aRetval.append(
+ createAreaGeometryForJoin(
+ aTangentPrev,
+ aTangentEdge,
+ aPerpendPrev,
+ aPerpendEdge,
+ aEdge.getStartPoint(),
+ fHalfLineWidth,
+ eJoin,
+ fMiterMinimumAngle));
}
else if(ORIENTATION_NEGATIVE == aOrientation)
{
- const B2DVector aPerpendPrev(getNormalizedPerpendicular(aTangentPrev) * fHalfLineWidth);
- const B2DVector aPerpendEdge(getNormalizedPerpendicular(aTangentEdge) * fHalfLineWidth);
-
- aRetval.append(createAreaGeometryForJoin(
- aTangentEdge, aTangentPrev,
- aPerpendEdge, aPerpendPrev,
- aEdge.getStartPoint(), fHalfLineWidth,
- eJoin, fMiterMinimumAngle));
+ const B2DVector aPerpendPrev(getPerpendicular(aTangentPrev) * fHalfLineWidth);
+ const B2DVector aPerpendEdge(getPerpendicular(aTangentEdge) * fHalfLineWidth);
+
+ aRetval.append(
+ createAreaGeometryForJoin(
+ aTangentEdge,
+ aTangentPrev,
+ aPerpendEdge,
+ aPerpendPrev,
+ aEdge.getStartPoint(),
+ fHalfLineWidth,
+ eJoin,
+ fMiterMinimumAngle));
}
}
// create geometry for edge
- aRetval.append(createAreaGeometryForEdge(aEdge, fHalfLineWidth));
+ const bool bLast(a + 1 == nEdgeCount);
- // prepare next step
- if(bEventuallyCreateLineJoin)
+ if(bLineCap)
+ {
+ const bool bFirst(!a);
+
+ aRetval.append(
+ createAreaGeometryForEdge(
+ aEdge,
+ fHalfLineWidth,
+ bFirst && com::sun::star::drawing::LineCap_ROUND == eCap,
+ bLast && com::sun::star::drawing::LineCap_ROUND == eCap,
+ bFirst && com::sun::star::drawing::LineCap_SQUARE == eCap,
+ bLast && com::sun::star::drawing::LineCap_SQUARE == eCap));
+ }
+ else
{
- aPrev = aEdge;
+ aRetval.append(
+ createAreaGeometryForEdge(
+ aEdge,
+ fHalfLineWidth,
+ false,
+ false,
+ false,
+ false));
}
- aEdge.setStartPoint(aEdge.getEndPoint());
+ // prepare next step
+ if(!bLast)
+ {
+ if(bEventuallyCreateLineJoin)
+ {
+ aPrev = aEdge;
+ }
+
+ aEdge.setStartPoint(aEdge.getEndPoint());
+ }
}
}
diff --git a/basegfx/source/polygon/b2dpolygontools.cxx b/basegfx/source/polygon/b2dpolygontools.cxx
index e95526898177..e8be1b3b10d5 100644
--- a/basegfx/source/polygon/b2dpolygontools.cxx
+++ b/basegfx/source/polygon/b2dpolygontools.cxx
@@ -1889,6 +1889,33 @@ namespace basegfx
return aUnitCircle;
}
+ B2DPolygon createHalfUnitCircle()
+ {
+ static B2DPolygon aUnitHalfCircle;
+
+ if(!aUnitHalfCircle.count())
+ {
+ const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
+ const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
+ const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
+ B2DPoint aPoint(1.0, 0.0);
+ B2DPoint aForward(1.0, fScaledKappa);
+ B2DPoint aBackward(1.0, -fScaledKappa);
+
+ aUnitHalfCircle.append(aPoint);
+
+ for(sal_uInt32 a(0); a < STEPSPERQUARTER * 2; a++)
+ {
+ aPoint *= aRotateMatrix;
+ aBackward *= aRotateMatrix;
+ aUnitHalfCircle.appendBezierSegment(aForward, aBackward, aPoint);
+ aForward *= aRotateMatrix;
+ }
+ }
+
+ return aUnitHalfCircle;
+ }
+
B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
{
switch(nStartQuadrant % 4)
diff --git a/basegfx/source/polygon/b3dpolygontools.cxx b/basegfx/source/polygon/b3dpolygontools.cxx
index 3f2ecd938bad..e573c0140eec 100644
--- a/basegfx/source/polygon/b3dpolygontools.cxx
+++ b/basegfx/source/polygon/b3dpolygontools.cxx
@@ -418,56 +418,59 @@ namespace basegfx
const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
- while(fTools::less(fDotDashMovingLength, fEdgeLength))
+ if(!fTools::equalZero(fEdgeLength))
{
- // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
- const bool bHandleLine(bIsLine && pLineTarget);
- const bool bHandleGap(!bIsLine && pGapTarget);
-
- if(bHandleLine || bHandleGap)
+ while(fTools::less(fDotDashMovingLength, fEdgeLength))
{
- if(!aSnippet.count())
+ // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
+ const bool bHandleLine(bIsLine && pLineTarget);
+ const bool bHandleGap(!bIsLine && pGapTarget);
+
+ if(bHandleLine || bHandleGap)
{
- aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
- }
+ if(!aSnippet.count())
+ {
+ aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
+ }
- aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
+ aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
- if(bHandleLine)
- {
- pLineTarget->append(aSnippet);
- }
- else
- {
- pGapTarget->append(aSnippet);
+ if(bHandleLine)
+ {
+ pLineTarget->append(aSnippet);
+ }
+ else
+ {
+ pGapTarget->append(aSnippet);
+ }
+
+ aSnippet.clear();
}
- aSnippet.clear();
+ // prepare next DotDashArray step and flip line/gap flag
+ fLastDotDashMovingLength = fDotDashMovingLength;
+ fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
+ bIsLine = !bIsLine;
}
- // prepare next DotDashArray step and flip line/gap flag
- fLastDotDashMovingLength = fDotDashMovingLength;
- fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
- bIsLine = !bIsLine;
- }
-
- // append snippet [fLastDotDashMovingLength, fEdgeLength]
- const bool bHandleLine(bIsLine && pLineTarget);
- const bool bHandleGap(!bIsLine && pGapTarget);
+ // append snippet [fLastDotDashMovingLength, fEdgeLength]
+ const bool bHandleLine(bIsLine && pLineTarget);
+ const bool bHandleGap(!bIsLine && pGapTarget);
- if(bHandleLine || bHandleGap)
- {
- if(!aSnippet.count())
+ if(bHandleLine || bHandleGap)
{
- aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
+ if(!aSnippet.count())
+ {
+ aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
+ }
+
+ aSnippet.append(aNextPoint);
}
- aSnippet.append(aNextPoint);
+ // prepare move to next edge
+ fDotDashMovingLength -= fEdgeLength;
}
- // prepare move to next edge
- fDotDashMovingLength -= fEdgeLength;
-
// prepare next edge step (end point gets new start point)
aCurrentPoint = aNextPoint;
}
diff --git a/basegfx/source/polygon/b3dpolypolygontools.cxx b/basegfx/source/polygon/b3dpolypolygontools.cxx
index 5895990712c4..cd1a96e3d0cd 100644
--- a/basegfx/source/polygon/b3dpolypolygontools.cxx
+++ b/basegfx/source/polygon/b3dpolypolygontools.cxx
@@ -34,6 +34,11 @@
#include <osl/mutex.hxx>
//////////////////////////////////////////////////////////////////////////////
+// predefines
+#define nMinSegments sal_uInt32(1)
+#define nMaxSegments sal_uInt32(512)
+
+//////////////////////////////////////////////////////////////////////////////
namespace basegfx
{
@@ -268,20 +273,16 @@ namespace basegfx
nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
}
- if(!nHorSeg)
- {
- nHorSeg = 1L;
- }
+ // min/max limitations
+ nHorSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nHorSeg));
if(!nVerSeg)
{
nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
}
- if(!nVerSeg)
- {
- nVerSeg = 1L;
- }
+ // min/max limitations
+ nVerSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nVerSeg));
// create constants
const double fVerDiffPerStep((fVerStop - fVerStart) / (double)nVerSeg);
@@ -371,20 +372,16 @@ namespace basegfx
nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
}
- if(!nHorSeg)
- {
- nHorSeg = 1L;
- }
+ // min/max limitations
+ nHorSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nHorSeg));
if(!nVerSeg)
{
nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
}
- if(!nVerSeg)
- {
- nVerSeg = 1L;
- }
+ // min/max limitations
+ nVerSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nVerSeg));
// vertical loop
for(sal_uInt32 a(0L); a < nVerSeg; a++)
diff --git a/canvas/source/vcl/canvashelper.cxx b/canvas/source/vcl/canvashelper.cxx
index 41550361c202..0dcc74fd03fc 100644
--- a/canvas/source/vcl/canvashelper.cxx
+++ b/canvas/source/vcl/canvashelper.cxx
@@ -35,6 +35,7 @@
#include <com/sun/star/rendering/TexturingMode.hpp>
#include <com/sun/star/rendering/PathCapType.hpp>
#include <com/sun/star/rendering/PathJoinType.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
#include <tools/poly.hxx>
#include <vcl/window.hxx>
@@ -94,6 +95,26 @@ namespace vclcanvas
return basegfx::B2DLINEJOIN_NONE;
}
+
+ drawing::LineCap unoCapeFromCap( sal_Int8 nCapType)
+ {
+ switch ( nCapType)
+ {
+ case rendering::PathCapType::BUTT:
+ return drawing::LineCap_BUTT;
+
+ case rendering::PathCapType::ROUND:
+ return drawing::LineCap_ROUND;
+
+ case rendering::PathCapType::SQUARE:
+ return drawing::LineCap_SQUARE;
+
+ default:
+ ENSURE_OR_THROW( false,
+ "unoCapeFromCap(): Unexpected cap type" );
+ }
+ return drawing::LineCap_BUTT;
+ }
}
CanvasHelper::CanvasHelper() :
@@ -384,7 +405,10 @@ namespace vclcanvas
// AW: New interface, will create bezier polygons now
aStrokedPolyPoly.append(basegfx::tools::createAreaGeometry(
- aPolyPoly.getB2DPolygon(i), strokeAttributes.StrokeWidth*0.5, b2DJoineFromJoin(strokeAttributes.JoinType)));
+ aPolyPoly.getB2DPolygon(i),
+ strokeAttributes.StrokeWidth*0.5,
+ b2DJoineFromJoin(strokeAttributes.JoinType),
+ unoCapeFromCap(strokeAttributes.StartCapType)));
//aStrokedPolyPoly.append(
// ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i),
// strokeAttributes.StrokeWidth*0.5,
diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index a395092f1ad3..d02bb0551b42 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -289,6 +289,28 @@ namespace
break;
}
+ switch(rLineInfo.GetLineCap())
+ {
+ default: /* com::sun::star::drawing::LineCap_BUTT */
+ {
+ o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
+ o_rStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ o_rStrokeAttributes.StartCapType = rendering::PathCapType::ROUND;
+ o_rStrokeAttributes.EndCapType = rendering::PathCapType::ROUND;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ o_rStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE;
+ o_rStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE;
+ break;
+ }
+ }
+
if( LINE_DASH == rLineInfo.GetStyle() )
{
const ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) );
diff --git a/cui/source/inc/cuitabline.hxx b/cui/source/inc/cuitabline.hxx
index 08d29b1f3476..828dd7527196 100644
--- a/cui/source/inc/cuitabline.hxx
+++ b/cui/source/inc/cuitabline.hxx
@@ -127,6 +127,10 @@ private:
FixedText maFTEdgeStyle;
LineEndLB maLBEdgeStyle;
+ // LineCaps
+ FixedText maFTCapStyle;
+ LineEndLB maLBCapStyle;
+
//#58425# Symbole auf einer Linie (z.B. StarChart) ->
SdrObjList* pSymbolList; //a list of symbols to be shown in menu. Symbol at position SID_ATTR_SYMBOLTYPE is to be shown in preview. The list position is to be used cyclic.
bool bNewSize;
@@ -197,6 +201,9 @@ private:
// #116827#
DECL_LINK( ChangeEdgeStyleHdl_Impl, void * );
+ // LineCaps
+ DECL_LINK ( ChangeCapStyleHdl_Impl, void * );
+
sal_Bool FillXLSet_Impl();
#endif
diff --git a/cui/source/tabpages/tabline.hrc b/cui/source/tabpages/tabline.hrc
index 30dd2cb1a125..8319873eece8 100644
--- a/cui/source/tabpages/tabline.hrc
+++ b/cui/source/tabpages/tabline.hrc
@@ -97,6 +97,12 @@
#define FT_EDGE_STYLE 13
#define LB_EDGE_STYLE 5
+// since LO3.6
+#define FT_CAP_STYLE 14
+#define LB_CAP_STYLE 6
+// not sure about IAccessibility2, add it nevertheless
+#define STR_LB_CAP_STYLE 42
+
//Symbole (fuer StarChart)
#define FT_SYMBOL_WIDTH 20
#define FT_SYMBOL_HEIGHT 21
diff --git a/cui/source/tabpages/tabline.src b/cui/source/tabpages/tabline.src
index eda4161bb138..4538b01c25ac 100644
--- a/cui/source/tabpages/tabline.src
+++ b/cui/source/tabpages/tabline.src
@@ -235,13 +235,13 @@ TabPage RID_SVXPAGE_LINE
{
Pos = MAP_APPFONT ( 124 , 3 + (16 * 6) - 4 ) ;
Size = MAP_APPFONT ( 130 , 8 ) ;
- Text [ en-US ] = "Corner style" ;
+ Text [ en-US ] = "Corner and cap styles" ;
};
FixedText FT_EDGE_STYLE
{
Pos = MAP_APPFONT ( 130 , 14 + (16 * 6) - 4 ) ;
Size = MAP_APPFONT ( 118 , 8 ) ;
- Text [ en-US ] = "Sty~le" ;
+ Text [ en-US ] = "~Corner style" ;
};
ListBox LB_EDGE_STYLE
{
@@ -259,6 +259,27 @@ TabPage RID_SVXPAGE_LINE
< "Beveled" ; > ;
};
};
+ FixedText FT_CAP_STYLE
+ {
+ Pos = MAP_APPFONT ( 191 , 14 + (16 * 6) - 4 ) ;
+ Size = MAP_APPFONT ( 118 , 8 ) ;
+ Text [ en-US ] = "Ca~p style" ;
+ };
+ ListBox LB_CAP_STYLE
+ {
+ HelpID = "cui:ListBox:RID_SVXPAGE_LINE:LB_CAP_STYLE";
+ Border = TRUE ;
+ Pos = MAP_APPFONT ( 191 , 25 + (16 * 6) - 4 ) ;
+ Size = MAP_APPFONT ( 57 , 99 ) ;
+ TabStop = TRUE ;
+ DropDown = TRUE ;
+ StringList [ en-US ] =
+ {
+ < "Flat" ; Default ; > ; // Same string as in Excel
+ < "Round" ; > ;
+ < "Square" ; > ;
+ };
+ };
//////////////////////////////////////////////////////////////////////////////
diff --git a/cui/source/tabpages/tpline.cxx b/cui/source/tabpages/tpline.cxx
index 2627a6687659..2a4d59374815 100644
--- a/cui/source/tabpages/tpline.cxx
+++ b/cui/source/tabpages/tpline.cxx
@@ -129,6 +129,10 @@ SvxLineTabPage::SvxLineTabPage
maFTEdgeStyle ( this, CUI_RES( FT_EDGE_STYLE ) ),
maLBEdgeStyle ( this, CUI_RES( LB_EDGE_STYLE ) ),
+ // LineCaps
+ maFTCapStyle ( this, CUI_RES( FT_CAP_STYLE ) ),
+ maLBCapStyle ( this, CUI_RES( LB_CAP_STYLE ) ),
+
pSymbolList(NULL),
bNewSize(false),
nNumMenuGalleryItems(0),
@@ -234,6 +238,10 @@ SvxLineTabPage::SvxLineTabPage
Link aEdgeStyle = LINK( this, SvxLineTabPage, ChangeEdgeStyleHdl_Impl );
maLBEdgeStyle.SetSelectHdl( aEdgeStyle );
+ // LineCaps
+ Link aCapStyle = LINK( this, SvxLineTabPage, ChangeCapStyleHdl_Impl );
+ maLBCapStyle.SetSelectHdl( aCapStyle );
+
//#58425# Symbole auf einer Linie (z.B. StarChart) , MB-Handler setzen
aSymbolMB.SetSelectHdl(LINK(this, SvxLineTabPage, GraphicHdl_Impl));
aSymbolMB.SetActivateHdl(LINK(this, SvxLineTabPage, MenuCreateHdl_Impl));
@@ -484,6 +492,10 @@ void SvxLineTabPage::ActivatePage( const SfxItemSet& rSet )
maFLEdgeStyle.Hide();
maFTEdgeStyle.Hide();
maLBEdgeStyle.Hide();
+
+ // LineCaps
+ maFTCapStyle.Hide();
+ maLBCapStyle.Hide();
}
}
@@ -751,6 +763,45 @@ sal_Bool SvxLineTabPage::FillItemSet( SfxItemSet& rAttrs )
}
}
+ // LineCaps
+ nPos = maLBCapStyle.GetSelectEntryPos();
+ if( LISTBOX_ENTRY_NOTFOUND != nPos && nPos != maLBCapStyle.GetSavedValue() )
+ {
+ XLineCapItem* pNew = 0L;
+
+ switch(nPos)
+ {
+ case 0: // Butt (=Flat), default
+ {
+ pNew = new XLineCapItem(com::sun::star::drawing::LineCap_BUTT);
+ break;
+ }
+ case 1: // Round
+ {
+ pNew = new XLineCapItem(com::sun::star::drawing::LineCap_ROUND);
+ break;
+ }
+ case 2: // Square
+ {
+ pNew = new XLineCapItem(com::sun::star::drawing::LineCap_SQUARE);
+ break;
+ }
+ }
+
+ if(pNew)
+ {
+ pOld = GetOldItem( rAttrs, XATTR_LINECAP );
+
+ if(!pOld || !(*(const XLineCapItem*)pOld == *pNew))
+ {
+ rAttrs.Put( *pNew );
+ bModified = sal_True;
+ }
+
+ delete pNew;
+ }
+ }
+
if(nSymbolType!=SVX_SYMBOLTYPE_UNKNOWN || bNewSize)
{
//wurde also per Auswahl gesetzt oder Gr��e ist anders
@@ -866,6 +917,30 @@ sal_Bool SvxLineTabPage::FillXLSet_Impl()
}
}
+ // LineCaps
+ nPos = maLBCapStyle.GetSelectEntryPos();
+ if(LISTBOX_ENTRY_NOTFOUND != nPos)
+ {
+ switch(nPos)
+ {
+ case 0: // Butt (=Flat), default
+ {
+ rXLSet.Put(XLineCapItem(com::sun::star::drawing::LineCap_BUTT));
+ break;
+ }
+ case 1: // Round
+ {
+ rXLSet.Put(XLineCapItem(com::sun::star::drawing::LineCap_ROUND));
+ break;
+ }
+ case 2: // Square
+ {
+ rXLSet.Put(XLineCapItem(com::sun::star::drawing::LineCap_SQUARE));
+ break;
+ }
+ }
+ }
+
rXLSet.Put( XLineStartWidthItem( GetCoreValue( aMtrStartWidth, ePoolUnit ) ) );
rXLSet.Put( XLineEndWidthItem( GetCoreValue( aMtrEndWidth, ePoolUnit ) ) );
@@ -1284,6 +1359,28 @@ void SvxLineTabPage::Reset( const SfxItemSet& rAttrs )
}
*/
+ // fdo#43209
+ if(bObjSelected && SFX_ITEM_DEFAULT == rAttrs.GetItemState(XATTR_LINECAP))
+ {
+ maFTCapStyle.Disable();
+ maLBCapStyle.Disable();
+ }
+ else if(SFX_ITEM_DONTCARE != rAttrs.GetItemState(XATTR_LINECAP))
+ {
+ const com::sun::star::drawing::LineCap eLineCap(((const XLineCapItem&)(rAttrs.Get(XATTR_LINECAP))).GetValue());
+
+ switch(eLineCap)
+ {
+ case com::sun::star::drawing::LineCap_ROUND: maLBCapStyle.SelectEntryPos(1); break;
+ case com::sun::star::drawing::LineCap_SQUARE : maLBCapStyle.SelectEntryPos(2); break;
+ default /*com::sun::star::drawing::LineCap_BUTT*/: maLBCapStyle.SelectEntryPos(0); break;
+ }
+ }
+ else
+ {
+ maLBCapStyle.SetNoSelection();
+ }
+
// Werte sichern
aLbLineStyle.SaveValue();
aMtrLineWidth.SaveValue();
@@ -1299,6 +1396,9 @@ void SvxLineTabPage::Reset( const SfxItemSet& rAttrs )
// #116827#
maLBEdgeStyle.SaveValue();
+ // LineCaps
+ maLBCapStyle.SaveValue();
+
ClickInvisibleHdl_Impl( this );
//ClickMeasuringHdl_Impl( this );
//aCtlPosition.Reset();
@@ -1416,6 +1516,15 @@ IMPL_LINK( SvxLineTabPage, ChangeEdgeStyleHdl_Impl, void *, EMPTYARG )
}
//------------------------------------------------------------------------
+// fdo#43209
+
+IMPL_LINK( SvxLineTabPage, ChangeCapStyleHdl_Impl, void *, EMPTYARG )
+{
+ ChangePreviewHdl_Impl( this );
+
+ return( 0L );
+}
+//------------------------------------------------------------------------
IMPL_LINK( SvxLineTabPage, ClickInvisibleHdl_Impl, void *, EMPTYARG )
{
@@ -1442,6 +1551,10 @@ IMPL_LINK( SvxLineTabPage, ClickInvisibleHdl_Impl, void *, EMPTYARG )
// #116827#
maFTEdgeStyle.Disable();
maLBEdgeStyle.Disable();
+
+ // LineCaps
+ maFTCapStyle.Disable();
+ maLBCapStyle.Disable();
}
}
else
@@ -1466,6 +1579,10 @@ IMPL_LINK( SvxLineTabPage, ClickInvisibleHdl_Impl, void *, EMPTYARG )
// #116827#
maFTEdgeStyle.Enable();
maLBEdgeStyle.Enable();
+
+ // LineCaps
+ maFTCapStyle.Enable();
+ maLBCapStyle.Enable();
}
}
ChangePreviewHdl_Impl( NULL );
diff --git a/drawinglayer/inc/drawinglayer/attribute/lineattribute.hxx b/drawinglayer/inc/drawinglayer/attribute/lineattribute.hxx
index 15521ebeccd8..f46689f78f1d 100644
--- a/drawinglayer/inc/drawinglayer/attribute/lineattribute.hxx
+++ b/drawinglayer/inc/drawinglayer/attribute/lineattribute.hxx
@@ -26,6 +26,7 @@
#include <drawinglayer/drawinglayerdllapi.h>
#include <basegfx/vector/b2enums.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
//////////////////////////////////////////////////////////////////////////////
// predefines
@@ -54,7 +55,8 @@ namespace drawinglayer
LineAttribute(
const basegfx::BColor& rColor,
double fWidth = 0.0,
- basegfx::B2DLineJoin aB2DLineJoin = basegfx::B2DLINEJOIN_ROUND);
+ basegfx::B2DLineJoin aB2DLineJoin = basegfx::B2DLINEJOIN_ROUND,
+ com::sun::star::drawing::LineCap aLineCap = com::sun::star::drawing::LineCap_BUTT);
LineAttribute();
LineAttribute(const LineAttribute& rCandidate);
LineAttribute& operator=(const LineAttribute& rCandidate);
@@ -70,6 +72,7 @@ namespace drawinglayer
const basegfx::BColor& getColor() const;
double getWidth() const;
basegfx::B2DLineJoin getLineJoin() const;
+ com::sun::star::drawing::LineCap getLineCap() const;
};
} // end of namespace attribute
} // end of namespace drawinglayer
diff --git a/drawinglayer/inc/drawinglayer/attribute/sdrlineattribute.hxx b/drawinglayer/inc/drawinglayer/attribute/sdrlineattribute.hxx
index 78dbbdcff6ee..1af59daf42ba 100644
--- a/drawinglayer/inc/drawinglayer/attribute/sdrlineattribute.hxx
+++ b/drawinglayer/inc/drawinglayer/attribute/sdrlineattribute.hxx
@@ -38,6 +38,7 @@
#include <drawinglayer/drawinglayerdllapi.h>
#include <basegfx/vector/b2enums.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
#include <vector>
//////////////////////////////////////////////////////////////////////////////
@@ -69,6 +70,7 @@ namespace drawinglayer
double fWidth,
double fTransparence,
const basegfx::BColor& rColor,
+ com::sun::star::drawing::LineCap eCap,
const ::std::vector< double >& rDotDashArray,
double fFullDotDashLen);
SdrLineAttribute(const basegfx::BColor& rColor);
@@ -90,6 +92,7 @@ namespace drawinglayer
const basegfx::BColor& getColor() const;
const ::std::vector< double >& getDotDashArray() const;
double getFullDotDashLen() const;
+ com::sun::star::drawing::LineCap getCap() const;
// bool access
bool isDashed() const;
diff --git a/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx b/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
index 438b3bcb4f36..b00b3b369722 100644
--- a/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
+++ b/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
@@ -59,6 +59,7 @@ namespace drawinglayer
double mfDegreeStepWidth;
double mfMiterMinimumAngle;
basegfx::B2DLineJoin maLineJoin;
+ com::sun::star::drawing::LineCap maLineCap;
protected:
/** access methods to maLast3DDecomposition. The usage of this methods may allow
@@ -76,7 +77,9 @@ namespace drawinglayer
PolygonTubePrimitive3D(
const basegfx::B3DPolygon& rPolygon,
const basegfx::BColor& rBColor,
- double fRadius, basegfx::B2DLineJoin aLineJoin,
+ double fRadius,
+ basegfx::B2DLineJoin aLineJoin,
+ com::sun::star::drawing::LineCap aLineCap,
double fDegreeStepWidth = 10.0 * F_PI180,
double fMiterMinimumAngle = 15.0 * F_PI180);
@@ -85,6 +88,7 @@ namespace drawinglayer
double getDegreeStepWidth() const { return mfDegreeStepWidth; }
double getMiterMinimumAngle() const { return mfMiterMinimumAngle; }
basegfx::B2DLineJoin getLineJoin() const { return maLineJoin; }
+ com::sun::star::drawing::LineCap getLineCap() const { return maLineCap; }
/// compare operator
virtual bool operator==(const BasePrimitive3D& rPrimitive) const;
diff --git a/drawinglayer/source/attribute/lineattribute.cxx b/drawinglayer/source/attribute/lineattribute.cxx
index 86576002b32f..da46682d2860 100644
--- a/drawinglayer/source/attribute/lineattribute.cxx
+++ b/drawinglayer/source/attribute/lineattribute.cxx
@@ -43,15 +43,18 @@ namespace drawinglayer
basegfx::BColor maColor; // color
double mfWidth; // absolute line width
basegfx::B2DLineJoin meLineJoin; // type of LineJoin
+ com::sun::star::drawing::LineCap meLineCap; // BUTT, ROUND, or SQUARE
ImpLineAttribute(
const basegfx::BColor& rColor,
double fWidth,
- basegfx::B2DLineJoin aB2DLineJoin)
+ basegfx::B2DLineJoin aB2DLineJoin,
+ com::sun::star::drawing::LineCap aLineCap)
: mnRefCount(0),
maColor(rColor),
mfWidth(fWidth),
- meLineJoin(aB2DLineJoin)
+ meLineJoin(aB2DLineJoin),
+ meLineCap(aLineCap)
{
}
@@ -59,12 +62,14 @@ namespace drawinglayer
const basegfx::BColor& getColor() const { return maColor; }
double getWidth() const { return mfWidth; }
basegfx::B2DLineJoin getLineJoin() const { return meLineJoin; }
+ com::sun::star::drawing::LineCap getLineCap() const { return meLineCap; }
bool operator==(const ImpLineAttribute& rCandidate) const
{
return (getColor() == rCandidate.getColor()
&& getWidth() == rCandidate.getWidth()
- && getLineJoin() == rCandidate.getLineJoin());
+ && getLineJoin() == rCandidate.getLineJoin()
+ && getLineCap() == rCandidate.getLineCap());
}
static ImpLineAttribute* get_global_default()
@@ -76,7 +81,8 @@ namespace drawinglayer
pDefault = new ImpLineAttribute(
basegfx::BColor(),
0.0,
- basegfx::B2DLINEJOIN_ROUND);
+ basegfx::B2DLINEJOIN_ROUND,
+ com::sun::star::drawing::LineCap_BUTT);
// never delete; start with RefCount 1, not 0
pDefault->mnRefCount++;
@@ -89,9 +95,14 @@ namespace drawinglayer
LineAttribute::LineAttribute(
const basegfx::BColor& rColor,
double fWidth,
- basegfx::B2DLineJoin aB2DLineJoin)
- : mpLineAttribute(new ImpLineAttribute(
- rColor, fWidth, aB2DLineJoin))
+ basegfx::B2DLineJoin aB2DLineJoin,
+ com::sun::star::drawing::LineCap aLineCap)
+ : mpLineAttribute(
+ new ImpLineAttribute(
+ rColor,
+ fWidth,
+ aB2DLineJoin,
+ aLineCap))
{
}
@@ -174,6 +185,11 @@ namespace drawinglayer
return mpLineAttribute->getLineJoin();
}
+ com::sun::star::drawing::LineCap LineAttribute::getLineCap() const
+ {
+ return mpLineAttribute->getLineCap();
+ }
+
} // end of namespace attribute
} // end of namespace drawinglayer
diff --git a/drawinglayer/source/attribute/sdrlineattribute.cxx b/drawinglayer/source/attribute/sdrlineattribute.cxx
index 1850d919069f..5707bcbef0ec 100644
--- a/drawinglayer/source/attribute/sdrlineattribute.cxx
+++ b/drawinglayer/source/attribute/sdrlineattribute.cxx
@@ -56,6 +56,7 @@ namespace drawinglayer
double mfWidth; // 1/100th mm, 0.0==hair
double mfTransparence; // [0.0 .. 1.0], 0.0==no transp.
basegfx::BColor maColor; // color of line
+ com::sun::star::drawing::LineCap meCap; // BUTT, ROUND, or SQUARE
::std::vector< double > maDotDashArray; // array of double which defines the dot-dash pattern
double mfFullDotDashLen; // sum of maDotDashArray (for convenience)
@@ -64,6 +65,7 @@ namespace drawinglayer
double fWidth,
double fTransparence,
const basegfx::BColor& rColor,
+ com::sun::star::drawing::LineCap eCap,
const ::std::vector< double >& rDotDashArray,
double fFullDotDashLen)
: mnRefCount(0),
@@ -71,6 +73,7 @@ namespace drawinglayer
mfWidth(fWidth),
mfTransparence(fTransparence),
maColor(rColor),
+ meCap(eCap),
maDotDashArray(rDotDashArray),
mfFullDotDashLen(fFullDotDashLen)
{
@@ -82,6 +85,7 @@ namespace drawinglayer
mfWidth(0.0),
mfTransparence(0.0),
maColor(rColor),
+ meCap(com::sun::star::drawing::LineCap_BUTT),
maDotDashArray(),
mfFullDotDashLen(0.0)
{
@@ -92,6 +96,7 @@ namespace drawinglayer
double getWidth() const { return mfWidth; }
double getTransparence() const { return mfTransparence; }
const basegfx::BColor& getColor() const { return maColor; }
+ com::sun::star::drawing::LineCap getCap() const { return meCap; }
const ::std::vector< double >& getDotDashArray() const { return maDotDashArray; }
double getFullDotDashLen() const { return mfFullDotDashLen; }
@@ -101,6 +106,7 @@ namespace drawinglayer
&& getWidth() == rCandidate.getWidth()
&& getTransparence() == rCandidate.getTransparence()
&& getColor() == rCandidate.getColor()
+ && getCap() == rCandidate.getCap()
&& getDotDashArray() == rCandidate.getDotDashArray());
}
@@ -115,6 +121,7 @@ namespace drawinglayer
0.0,
0.0,
basegfx::BColor(),
+ com::sun::star::drawing::LineCap_BUTT,
std::vector< double >(),
0.0);
@@ -131,16 +138,26 @@ namespace drawinglayer
double fWidth,
double fTransparence,
const basegfx::BColor& rColor,
+ com::sun::star::drawing::LineCap eCap,
const ::std::vector< double >& rDotDashArray,
double fFullDotDashLen)
- : mpSdrLineAttribute(new ImpSdrLineAttribute(
- eJoin, fWidth, fTransparence, rColor, rDotDashArray, fFullDotDashLen))
+ : mpSdrLineAttribute(
+ new ImpSdrLineAttribute(
+ eJoin,
+ fWidth,
+ fTransparence,
+ rColor,
+ eCap,
+ rDotDashArray,
+ fFullDotDashLen))
{
}
SdrLineAttribute::SdrLineAttribute(
const basegfx::BColor& rColor)
- : mpSdrLineAttribute(new ImpSdrLineAttribute(rColor))
+ : mpSdrLineAttribute(
+ new ImpSdrLineAttribute(
+ rColor))
{
}
@@ -243,6 +260,11 @@ namespace drawinglayer
return (0L != getDotDashArray().size());
}
+ com::sun::star::drawing::LineCap SdrLineAttribute::getCap() const
+ {
+ return mpSdrLineAttribute->getCap();
+ }
+
} // end of namespace attribute
} // end of namespace drawinglayer
diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
index a3eff771d4da..d8574093b23d 100644
--- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
@@ -706,7 +706,8 @@ namespace
const drawinglayer::attribute::LineAttribute aLineAttribute(
rProperties.getLineColor(),
bWidthUsed ? rLineInfo.GetWidth() : 0.0,
- rLineInfo.GetLineJoin());
+ rLineInfo.GetLineJoin(),
+ rLineInfo.GetLineCap());
if(bDashDotUsed)
{
diff --git a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
index 1acf268f777c..1c8e150c6642 100644
--- a/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/polygonprimitive2d.cxx
@@ -32,6 +32,7 @@
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
#include <drawinglayer/geometry/viewinformation2d.hxx>
#include <basegfx/polygon/b2dlinegeometry.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
//////////////////////////////////////////////////////////////////////////////
@@ -252,13 +253,17 @@ namespace drawinglayer
// create fat line data
const double fHalfLineWidth(getLineAttribute().getWidth() / 2.0);
const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin());
+ const com::sun::star::drawing::LineCap aLineCap(getLineAttribute().getLineCap());
basegfx::B2DPolyPolygon aAreaPolyPolygon;
for(sal_uInt32 a(0L); a < nCount; a++)
{
// New version of createAreaGeometry; now creates bezier polygons
aAreaPolyPolygon.append(basegfx::tools::createAreaGeometry(
- aHairLinePolyPolygon.getB2DPolygon(a), fHalfLineWidth, aLineJoin));
+ aHairLinePolyPolygon.getB2DPolygon(a),
+ fHalfLineWidth,
+ aLineJoin,
+ aLineCap));
}
// prepare return value
@@ -339,10 +344,28 @@ namespace drawinglayer
if(getLineAttribute().getWidth())
{
+ bool bUseDecomposition(false);
+
if(basegfx::B2DLINEJOIN_MITER == getLineAttribute().getLineJoin())
{
// if line is mitered, use parent call since mitered line
// geometry may use more space than the geometry grown by half line width
+ bUseDecomposition = true;
+ }
+
+ if(!bUseDecomposition && com::sun::star::drawing::LineCap_SQUARE == getLineAttribute().getLineCap())
+ {
+ // when drawing::LineCap_SQUARE is used the below method to grow the polygon
+ // range by half line width will not work, so use decomposition. Interestingly,
+ // the grow method below works perfectly for LineCap_ROUND since the grow is in
+ // all directions and the rounded cap needs the same grow in all directions independent
+ // from it's orientation. Unfortunately this is not the case for drawing::LineCap_SQUARE
+ bUseDecomposition = true;
+ }
+
+ if(bUseDecomposition)
+ {
+ // get correct range by using the decomposition fallback, reasons see above cases
aRetval = BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
}
else
diff --git a/drawinglayer/source/primitive3d/polygonprimitive3d.cxx b/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
index 69dc188031ae..669dc5ee171e 100644
--- a/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
+++ b/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
@@ -106,11 +106,18 @@ namespace drawinglayer
// create fat line data
const double fRadius(getLineAttribute().getWidth() / 2.0);
const basegfx::B2DLineJoin aLineJoin(getLineAttribute().getLineJoin());
+ const com::sun::star::drawing::LineCap aLineCap(getLineAttribute().getLineCap());
for(sal_uInt32 a(0L); a < aHairLinePolyPolygon.count(); a++)
{
// create tube primitives
- const Primitive3DReference xRef(new PolygonTubePrimitive3D(aHairLinePolyPolygon.getB3DPolygon(a), getLineAttribute().getColor(), fRadius, aLineJoin));
+ const Primitive3DReference xRef(
+ new PolygonTubePrimitive3D(
+ aHairLinePolyPolygon.getB3DPolygon(a),
+ getLineAttribute().getColor(),
+ fRadius,
+ aLineJoin,
+ aLineCap));
aRetval[a] = xRef;
}
}
diff --git a/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx b/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
index 320e50872a3e..39c8952980bd 100644
--- a/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
+++ b/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
@@ -156,6 +156,76 @@ namespace drawinglayer
return aLineCapList;
}
+ Primitive3DSequence getLineCapRoundSegments(
+ sal_uInt32 nSegments,
+ const attribute::MaterialAttribute3D& rMaterial)
+ {
+ // static data for buffered tube primitives
+ static Primitive3DSequence aLineCapRoundList;
+ static sal_uInt32 nLineCapRoundSegments(0);
+ static attribute::MaterialAttribute3D aLineMaterial;
+
+ // may exclusively change static data, use mutex
+ ::osl::Mutex m_mutex;
+
+ if(nSegments != nLineCapRoundSegments || !(rMaterial == aLineMaterial))
+ {
+ nLineCapRoundSegments = nSegments;
+ aLineMaterial = rMaterial;
+ aLineCapRoundList = Primitive3DSequence();
+ }
+
+ if(!aLineCapRoundList.hasElements() && nLineCapRoundSegments)
+ {
+ // calculate new horizontal segments
+ sal_uInt32 nVerSeg(nSegments / 2);
+
+ if(nVerSeg < 1)
+ {
+ nVerSeg = 1;
+ }
+
+ // create half-sphere; upper half of unit sphere
+ basegfx::B3DPolyPolygon aSphere(
+ basegfx::tools::createUnitSphereFillPolyPolygon(
+ nSegments,
+ nVerSeg,
+ true,
+ F_PI2, 0.0,
+ 0.0, F_2PI));
+ const sal_uInt32 nCount(aSphere.count());
+
+ if(nCount)
+ {
+ // rotate to have sphere cap orientned to negative X-Axis; do not
+ // forget to transform normals, too
+ basegfx::B3DHomMatrix aSphereTrans;
+
+ aSphereTrans.rotate(0.0, 0.0, F_PI2);
+ aSphere.transform(aSphereTrans);
+ aSphere.transformNormals(aSphereTrans);
+
+ // realloc for primitives and create based on polygon snippets
+ aLineCapRoundList.realloc(nCount);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a));
+ const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon);
+
+ // need to create one primitive per Polygon since the primitive
+ // is for planar PolyPolygons which is definitely not the case here
+ aLineCapRoundList[a] = new PolyPolygonMaterialPrimitive3D(
+ aPartPolyPolygon,
+ rMaterial,
+ false);
+ }
+ }
+ }
+
+ return aLineCapRoundList;
+ }
+
Primitive3DSequence getLineJoinSegments(
sal_uInt32 nSegments,
const attribute::MaterialAttribute3D& rMaterial,
@@ -173,7 +243,7 @@ namespace drawinglayer
if(basegfx::B2DLINEJOIN_ROUND == aLineJoin)
{
// calculate new horizontal segments
- const sal_uInt32 nHorSeg((sal_uInt32)((fAngle / F_2PI) * (double)nSegments));
+ const sal_uInt32 nHorSeg(basegfx::fround((fAngle / F_2PI) * (double)nSegments));
if(nHorSeg)
{
@@ -410,40 +480,88 @@ namespace drawinglayer
const sal_uInt32 nPointCount(getB3DPolygon().count());
std::vector< BasePrimitive3D* > aResultVector;
- if(0L != nPointCount)
+ if(nPointCount)
{
if(basegfx::fTools::more(getRadius(), 0.0))
{
const attribute::MaterialAttribute3D aMaterial(getBColor());
- static sal_uInt32 nSegments(8L); // default for 3d line segments, for more quality just raise this value (in even steps)
+ static sal_uInt32 nSegments(8); // default for 3d line segments, for more quality just raise this value (in even steps)
const bool bClosed(getB3DPolygon().isClosed());
const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin());
- const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1L);
- basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1L));
- basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0L));
+ const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1);
+ basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1));
+ basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0));
- for(sal_uInt32 a(0L); a < nLoopCount; a++)
+ for(sal_uInt32 a(0); a < nLoopCount; a++)
{
// get next data
- const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1L) % nPointCount));
+ const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1) % nPointCount));
const basegfx::B3DVector aForw(aNext - aCurr);
const double fForwLen(aForw.getLength());
if(basegfx::fTools::more(fForwLen, 0.0))
{
+ // find out if linecap is active
+ const bool bFirst(!a);
+ const bool bLast(a + 1 == nLoopCount);
+ const bool bLineCapPossible(!bClosed && (bFirst || bLast));
+ const bool bLineCapRound(bLineCapPossible && com::sun::star::drawing::LineCap_ROUND == getLineCap());
+ const bool bLineCapSquare(bLineCapPossible && com::sun::star::drawing::LineCap_SQUARE == getLineCap());
+
// get rotation from vector, this describes rotation from (1, 0, 0) to aForw
basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw));
- // create default transformation with scale and rotate
- basegfx::B3DHomMatrix aVectorTrans;
- aVectorTrans.scale(fForwLen, getRadius(), getRadius());
- aVectorTrans *= aRotVector;
- aVectorTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
+ // prepare transformations for tube and cap
+ basegfx::B3DHomMatrix aTubeTrans;
+ basegfx::B3DHomMatrix aCapTrans;
+
+ // cap gets radius size
+ aCapTrans.scale(getRadius(), getRadius(), getRadius());
- if(bNoLineJoin || (!bClosed && !a))
+ if(bLineCapSquare)
+ {
+ // when square line cap just prolong line segment in X, maybe 2 x radius when
+ // first and last (simple line segment)
+ const double fExtraLength(bFirst && bLast ? getRadius() * 2.0 : getRadius());
+
+ aTubeTrans.scale(fForwLen + fExtraLength, getRadius(), getRadius());
+
+ if(bFirst)
+ {
+ // correct start positions for tube and cap when first and square prolonged
+ aTubeTrans.translate(-getRadius(), 0.0, 0.0);
+ aCapTrans.translate(-getRadius(), 0.0, 0.0);
+ }
+ }
+ else
+ {
+ // normal tube size
+ aTubeTrans.scale(fForwLen, getRadius(), getRadius());
+ }
+
+ // rotate and translate tube and cap
+ aTubeTrans *= aRotVector;
+ aTubeTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
+ aCapTrans *= aRotVector;
+ aCapTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
+
+ if(bNoLineJoin || (!bClosed && bFirst))
{
// line start edge, build transformed primitiveVector3D
- TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aVectorTrans, getLineCapSegments(nSegments, aMaterial));
+ Primitive3DSequence aSequence;
+
+ if(bLineCapRound && bFirst)
+ {
+ // LineCapRound used
+ aSequence = getLineCapRoundSegments(nSegments, aMaterial);
+ }
+ else
+ {
+ // simple closing cap
+ aSequence = getLineCapSegments(nSegments, aMaterial);
+ }
+
+ TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aCapTrans, aSequence);
aResultVector.push_back(pNewTransformedA);
}
else
@@ -455,7 +573,14 @@ namespace drawinglayer
{
// line connect non-parallel, aBack, aForw, use getLineJoin()
const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2
- Primitive3DSequence aNewList(getLineJoinSegments(nSegments, aMaterial, fAngle, getDegreeStepWidth(), getMiterMinimumAngle(), getLineJoin()));
+ Primitive3DSequence aNewList(
+ getLineJoinSegments(
+ nSegments,
+ aMaterial,
+ fAngle,
+ getDegreeStepWidth(),
+ getMiterMinimumAngle(),
+ getLineJoin()));
// calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack
basegfx::B3DHomMatrix aInvRotVector(aRotVector);
@@ -473,28 +598,61 @@ namespace drawinglayer
aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
// line start edge, build transformed primitiveVector3D
- TransformPrimitive3D* pNewTransformedB = new TransformPrimitive3D(aSphereTrans, aNewList);
- aResultVector.push_back(pNewTransformedB);
+ aResultVector.push_back(
+ new TransformPrimitive3D(
+ aSphereTrans,
+ aNewList));
}
}
// create line segments, build transformed primitiveVector3D
- TransformPrimitive3D* pNewTransformedC = new TransformPrimitive3D(aVectorTrans, getLineTubeSegments(nSegments, aMaterial));
- aResultVector.push_back(pNewTransformedC);
+ aResultVector.push_back(
+ new TransformPrimitive3D(
+ aTubeTrans,
+ getLineTubeSegments(nSegments, aMaterial)));
- if(bNoLineJoin || (!bClosed && ((a + 1L) == nLoopCount)))
+ if(bNoLineJoin || (!bClosed && bLast))
{
- // line end edge, first rotate (mirror) and translate, then use use aRotVector
- basegfx::B3DHomMatrix aBackTrans;
- aBackTrans.rotate(0.0, F_PI, 0.0);
- aBackTrans.translate(1.0, 0.0, 0.0);
- aBackTrans.scale(fForwLen, getRadius(), getRadius());
- aBackTrans *= aRotVector;
- aBackTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
-
- // line end edge, build transformed primitiveVector3D
- TransformPrimitive3D* pNewTransformedD = new TransformPrimitive3D(aBackTrans, getLineCapSegments(nSegments, aMaterial));
- aResultVector.push_back(pNewTransformedD);
+ // line end edge
+ basegfx::B3DHomMatrix aBackCapTrans;
+
+ // Mirror (line end) and radius scale
+ aBackCapTrans.rotate(0.0, F_PI, 0.0);
+ aBackCapTrans.scale(getRadius(), getRadius(), getRadius());
+
+ if(bLineCapSquare && bLast)
+ {
+ // correct position when square and prolonged
+ aBackCapTrans.translate(fForwLen + getRadius(), 0.0, 0.0);
+ }
+ else
+ {
+ // standard position
+ aBackCapTrans.translate(fForwLen, 0.0, 0.0);
+ }
+
+ // rotate and translate to destination
+ aBackCapTrans *= aRotVector;
+ aBackCapTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
+
+ // get primitiveVector3D
+ Primitive3DSequence aSequence;
+
+ if(bLineCapRound && bLast)
+ {
+ // LineCapRound used
+ aSequence = getLineCapRoundSegments(nSegments, aMaterial);
+ }
+ else
+ {
+ // simple closing cap
+ aSequence = getLineCapSegments(nSegments, aMaterial);
+ }
+
+ aResultVector.push_back(
+ new TransformPrimitive3D(
+ aBackCapTrans,
+ aSequence));
}
}
@@ -526,6 +684,7 @@ namespace drawinglayer
const basegfx::B3DPolygon& rPolygon,
const basegfx::BColor& rBColor,
double fRadius, basegfx::B2DLineJoin aLineJoin,
+ com::sun::star::drawing::LineCap aLineCap,
double fDegreeStepWidth,
double fMiterMinimumAngle)
: PolygonHairlinePrimitive3D(rPolygon, rBColor),
@@ -533,7 +692,8 @@ namespace drawinglayer
mfRadius(fRadius),
mfDegreeStepWidth(fDegreeStepWidth),
mfMiterMinimumAngle(fMiterMinimumAngle),
- maLineJoin(aLineJoin)
+ maLineJoin(aLineJoin),
+ maLineCap(aLineCap)
{
}
@@ -546,7 +706,8 @@ namespace drawinglayer
return (getRadius() == rCompare.getRadius()
&& getDegreeStepWidth() == rCompare.getDegreeStepWidth()
&& getMiterMinimumAngle() == rCompare.getMiterMinimumAngle()
- && getLineJoin() == rCompare.getLineJoin());
+ && getLineJoin() == rCompare.getLineJoin()
+ && getLineCap() == rCompare.getLineCap());
}
return false;
diff --git a/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx
index 87b7904e9885..08c79e7c8226 100644
--- a/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx
+++ b/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx
@@ -150,7 +150,7 @@ namespace drawinglayer
aScaledPolyPolygon.transform(rObjectTransform);
// create line and stroke attribute
- const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin());
+ const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), rLine.getCap());
const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen());
// create primitives
diff --git a/drawinglayer/source/processor2d/canvasprocessor.cxx b/drawinglayer/source/processor2d/canvasprocessor.cxx
index 4bf7c0bd9dda..875f28003699 100644
--- a/drawinglayer/source/processor2d/canvasprocessor.cxx
+++ b/drawinglayer/source/processor2d/canvasprocessor.cxx
@@ -57,6 +57,7 @@
#include <com/sun/star/rendering/CompositeOperation.hpp>
#include <com/sun/star/rendering/StrokeAttributes.hpp>
#include <com/sun/star/rendering/PathJoinType.hpp>
+#include <com/sun/star/rendering/PathCapType.hpp>
#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
#include <com/sun/star/rendering/TexturingMode.hpp>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
@@ -1753,6 +1754,22 @@ namespace drawinglayer
break;
}
+ switch(rLineAttribute.getLineCap())
+ {
+ case com::sun::star::drawing::LineCap_ROUND:
+ aStrokeAttribute.StartCapType = rendering::PathCapType::ROUND;
+ aStrokeAttribute.EndCapType = rendering::PathCapType::ROUND;
+ break;
+ case com::sun::star::drawing::LineCap_SQUARE:
+ aStrokeAttribute.StartCapType = rendering::PathCapType::SQUARE;
+ aStrokeAttribute.EndCapType = rendering::PathCapType::SQUARE;
+ break;
+ default: // com::sun::star::drawing::LineCap_BUTT
+ aStrokeAttribute.StartCapType = rendering::PathCapType::BUTT;
+ aStrokeAttribute.EndCapType = rendering::PathCapType::BUTT;
+ break;
+ }
+
const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index 54cb95dc1672..21bc128e3edb 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -416,6 +416,7 @@ namespace drawinglayer
}
SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
+ SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
double fLineWidth(0.0);
double fMiterLength(0.0);
SvtGraphicStroke::DashArray aDashArray;
@@ -455,6 +456,26 @@ namespace drawinglayer
break;
}
}
+
+ // get stroke
+ switch(pLineAttribute->getLineCap())
+ {
+ default: /* com::sun::star::drawing::LineCap_BUTT */
+ {
+ eCap = SvtGraphicStroke::capButt;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ eCap = SvtGraphicStroke::capRound;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ eCap = SvtGraphicStroke::capSquare;
+ break;
+ }
+ }
}
if(pStrokeAttribute)
@@ -482,7 +503,7 @@ namespace drawinglayer
PolyPolygon(aEndArrow),
mfCurrentUnifiedTransparence,
fLineWidth,
- SvtGraphicStroke::capButt,
+ eCap,
eJoin,
fMiterLength,
aDashArray);
@@ -1203,6 +1224,7 @@ namespace drawinglayer
LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth));
aLineInfo.SetLineJoin(rLine.getLineJoin());
+ aLineInfo.SetLineCap(rLine.getLineCap());
for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
{
diff --git a/editeng/inc/editeng/unoprnms.hxx b/editeng/inc/editeng/unoprnms.hxx
index 9379e1b0616f..f612182349da 100644
--- a/editeng/inc/editeng/unoprnms.hxx
+++ b/editeng/inc/editeng/unoprnms.hxx
@@ -92,6 +92,7 @@
#define UNO_NAME_LINESTARTCENTER "LineStartCenter"
#define UNO_NAME_LINEENDCENTER "LineEndCenter"
#define UNO_NAME_LINETRANSPARENCE "LineTransparence"
+#define UNO_NAME_LINECAP "LineCap"
#define UNO_NAME_SHADOW "Shadow"
#define UNO_NAME_SHADOWCOLOR "ShadowColor"
diff --git a/filter/source/graphicfilter/eps/eps.cxx b/filter/source/graphicfilter/eps/eps.cxx
index 2f63c27017d7..9e21611da409 100644
--- a/filter/source/graphicfilter/eps/eps.cxx
+++ b/filter/source/graphicfilter/eps/eps.cxx
@@ -2370,6 +2370,7 @@ void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo )
l_aDashArray.push_back( 2 );
const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5);
SvtGraphicStroke::JoinType aJoinType(SvtGraphicStroke::joinMiter);
+ SvtGraphicStroke::CapType aCapType(SvtGraphicStroke::capButt);
switch(rLineInfo.GetLineJoin())
{
@@ -2389,7 +2390,26 @@ void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo )
break;
}
- ImplWriteLineInfo( fLWidth, fMiterLimit, SvtGraphicStroke::capButt, aJoinType, l_aDashArray );
+ switch(rLineInfo.GetLineCap())
+ {
+ default: /* com::sun::star::drawing::LineCap_BUTT */
+ {
+ aCapType = SvtGraphicStroke::capButt;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ aCapType = SvtGraphicStroke::capRound;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ aCapType = SvtGraphicStroke::capSquare;
+ break;
+ }
+ }
+
+ ImplWriteLineInfo( fLWidth, fMiterLimit, aCapType, aJoinType, l_aDashArray );
}
//---------------------------------------------------------------------------------
diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx
index 5cc5f8a58477..f6e011fcf5e5 100644
--- a/filter/source/msfilter/escherex.cxx
+++ b/filter/source/msfilter/escherex.cxx
@@ -51,6 +51,7 @@
#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/LineJoint.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineDash.hpp>
#include <com/sun/star/drawing/BezierPoint.hpp>
@@ -853,6 +854,35 @@ void EscherPropertyContainer::CreateLineProperties(
AddOpt( ESCHER_Prop_lineEndArrowhead, eLineEnd );
nLineFlags |= 0x100010;
}
+
+ // support LineCaps
+ if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, String(RTL_CONSTASCII_USTRINGPARAM("LineCap")), sal_False))
+ {
+ ::com::sun::star::drawing::LineCap aLineCap(com::sun::star::drawing::LineCap_BUTT);
+
+ if(aAny >>= aLineCap)
+ {
+ switch (aLineCap)
+ {
+ default: /* com::sun::star::drawing::LineCap_BUTT */
+ {
+ AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapFlat);
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapRound);
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapSquare);
+ break;
+ }
+ }
+ }
+ }
+
if ( EscherPropertyValueHelper::GetPropertyValue(
aAny, rXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( "LineStyle" ) ), sal_False ) )
{
diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx
index 73d2320a6d98..ecebfd4b9f2a 100644
--- a/filter/source/msfilter/msdffimp.cxx
+++ b/filter/source/msfilter/msdffimp.cxx
@@ -920,19 +920,41 @@ void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eSh
// Linienattribute
sal_Int32 nLineWidth = (sal_Int32)GetPropertyValue( DFF_Prop_lineWidth, 9525 );
+ // support LineCap
+ const MSO_LineCap eLineCap((MSO_LineCap)GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapSquare));
+
+ switch(eLineCap)
+ {
+ default: /* case mso_lineEndCapFlat */
+ {
+ // no need to set, it is the default. If this changes, this needs to be activated
+ // rSet.Put(XLineCapItem(com::sun::star::drawing::LineCap_BUTT));
+ break;
+ }
+ case mso_lineEndCapRound:
+ {
+ rSet.Put(XLineCapItem(com::sun::star::drawing::LineCap_ROUND));
+ break;
+ }
+ case mso_lineEndCapSquare:
+ {
+ rSet.Put(XLineCapItem(com::sun::star::drawing::LineCap_SQUARE));
+ break;
+ }
+ }
+
MSO_LineDashing eLineDashing = (MSO_LineDashing)GetPropertyValue( DFF_Prop_lineDashing, mso_lineSolid );
if ( eLineDashing == mso_lineSolid )
rSet.Put(XLineStyleItem( XLINE_SOLID ) );
else
{
-// MSO_LineCap eLineCap = (MSO_LineCap)GetPropertyValue( DFF_Prop_lineEndCapStyle, mso_lineEndCapSquare );
XDashStyle eDash = XDASH_RECT;
sal_uInt16 nDots = 1;
sal_uInt32 nDotLen = nLineWidth / 360;
sal_uInt16 nDashes = 0;
sal_uInt32 nDashLen = ( 8 * nLineWidth ) / 360;
- sal_uInt32 nDistance = ( 3 * nLineWidth ) / 360;;
+ sal_uInt32 nDistance = ( 3 * nLineWidth ) / 360;
switch ( eLineDashing )
{
@@ -1049,24 +1071,27 @@ void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eSh
rSet.Put( XLineEndItem( aArrowName, basegfx::B2DPolyPolygon(aPoly) ) );
rSet.Put( XLineEndCenterItem( bArrowCenter ) );
}
- if ( IsProperty( DFF_Prop_lineEndCapStyle ) )
- {
- MSO_LineCap eLineCap = (MSO_LineCap)GetPropertyValue( DFF_Prop_lineEndCapStyle );
- const SfxPoolItem* pPoolItem = NULL;
- if ( rSet.GetItemState( XATTR_LINEDASH, sal_False, &pPoolItem ) == SFX_ITEM_SET )
- {
- XDashStyle eNewStyle = XDASH_RECT;
- if ( eLineCap == mso_lineEndCapRound )
- eNewStyle = XDASH_ROUND;
- const XDash& rOldDash = ( (const XLineDashItem*)pPoolItem )->GetDashValue();
- if ( rOldDash.GetDashStyle() != eNewStyle )
- {
- XDash aNew( rOldDash );
- aNew.SetDashStyle( eNewStyle );
- rSet.Put( XLineDashItem( XubString(), aNew ) );
- }
- }
- }
+
+ // this was used to at least adapt the lineDash to the lineCap before lineCap was
+ // supported, so with supporting lineCap this is no longer needed
+ //if ( IsProperty( DFF_Prop_lineEndCapStyle ) )
+ //{
+ // MSO_LineCap eLineCap = (MSO_LineCap)GetPropertyValue( DFF_Prop_lineEndCapStyle );
+ // const SfxPoolItem* pPoolItem = NULL;
+ // if ( rSet.GetItemState( XATTR_LINEDASH, sal_False, &pPoolItem ) == SFX_ITEM_SET )
+ // {
+ // XDashStyle eNewStyle = XDASH_RECT;
+ // if ( eLineCap == mso_lineEndCapRound )
+ // eNewStyle = XDASH_ROUND;
+ // const XDash& rOldDash = ( (const XLineDashItem*)pPoolItem )->GetDashValue();
+ // if ( rOldDash.GetDashStyle() != eNewStyle )
+ // {
+ // XDash aNew( rOldDash );
+ // aNew.SetDashStyle( eNewStyle );
+ // rSet.Put( XLineDashItem( XubString(), aNew ) );
+ // }
+ // }
+ //}
}
}
else
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index ce85fca3df6c..5651a7f3d5c3 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -83,6 +83,10 @@ static const char aXMLAttrGradientUnits[] = "gradientUnits";
static const char aXMLAttrOffset[] = "offset";
static const char aXMLAttrStopColor[] = "stop-color";
+// added support for LineJoin and LineCap
+static const char aXMLAttrStrokeLinejoin[] = "stroke-linejoin";
+static const char aXMLAttrStrokeLinecap[] = "stroke-linecap";
+
// -----------------------------------------------------------------------------
static const sal_Unicode pBase64[] =
@@ -674,6 +678,51 @@ void SVGActionWriter::ImplWriteShape( const SVGShapeDescriptor& rShape, sal_Bool
mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, ::rtl::OUString::valueOf( nStrokeWidth ) );
}
+ // support for LineJoin
+ switch(rShape.maLineJoin)
+ {
+ default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
+ case basegfx::B2DLINEJOIN_MITER:
+ {
+ // miter is Svg default, so no need to write until the exporter might write styles.
+ // If this happens, activate here
+ // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("miter"));
+ break;
+ }
+ case basegfx::B2DLINEJOIN_BEVEL:
+ {
+ mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("bevel"));
+ break;
+ }
+ case basegfx::B2DLINEJOIN_ROUND:
+ {
+ mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, ::rtl::OUString::createFromAscii("round"));
+ break;
+ }
+ }
+
+ // support for LineCap
+ switch(rShape.maLineCap)
+ {
+ default: /* com::sun::star::drawing::LineCap_BUTT */
+ {
+ // butt is Svg default, so no need to write until the exporter might write styles.
+ // If this happens, activate here
+ // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("butt"));
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("round"));
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, ::rtl::OUString::createFromAscii("square"));
+ break;
+ }
+ }
+
if( rShape.maDashArray.size() )
{
const ::rtl::OUString aComma( B2UCONST( "," ) );
@@ -1486,6 +1535,46 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
mapCurShape->maShapeLineColor.SetTransparency( (sal_uInt8) FRound( aStroke.getTransparency() * 255.0 ) );
mapCurShape->mnStrokeWidth = FRound( aStroke.getStrokeWidth() );
aStroke.getDashArray( mapCurShape->maDashArray );
+
+ // added support for LineJoin
+ switch(aStroke.getJoinType())
+ {
+ default: /* SvtGraphicStroke::joinMiter, SvtGraphicStroke::joinNone */
+ {
+ mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_MITER;
+ break;
+ }
+ case SvtGraphicStroke::joinRound:
+ {
+ mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_ROUND;
+ break;
+ }
+ case SvtGraphicStroke::joinBevel:
+ {
+ mapCurShape->maLineJoin = basegfx::B2DLINEJOIN_BEVEL;
+ break;
+ }
+ }
+
+ // added support for LineCap
+ switch(aStroke.getCapType())
+ {
+ default: /* SvtGraphicStroke::capButt */
+ {
+ mapCurShape->maLineCap = com::sun::star::drawing::LineCap_BUTT;
+ break;
+ }
+ case SvtGraphicStroke::capRound:
+ {
+ mapCurShape->maLineCap = com::sun::star::drawing::LineCap_ROUND;
+ break;
+ }
+ case SvtGraphicStroke::capSquare:
+ {
+ mapCurShape->maLineCap = com::sun::star::drawing::LineCap_SQUARE;
+ break;
+ }
+ }
}
// write open shape in every case
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 233a244e5cd4..e00b43062ded 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -137,20 +137,26 @@ public:
struct SVGShapeDescriptor
{
- PolyPolygon maShapePolyPoly;
- Color maShapeFillColor;
- Color maShapeLineColor;
- sal_Int32 mnStrokeWidth;
- SvtGraphicStroke::DashArray maDashArray;
- ::std::auto_ptr< Gradient > mapShapeGradient;
- ::rtl::OUString maId;
+ PolyPolygon maShapePolyPoly;
+ Color maShapeFillColor;
+ Color maShapeLineColor;
+ sal_Int32 mnStrokeWidth;
+ SvtGraphicStroke::DashArray maDashArray;
+ ::std::auto_ptr< Gradient > mapShapeGradient;
+ ::rtl::OUString maId;
+
+ // added support for LineJoin and LineCap
+ basegfx::B2DLineJoin maLineJoin;
+ com::sun::star::drawing::LineCap maLineCap;
// -------------------------------------------------------------------------
SVGShapeDescriptor() :
maShapeFillColor( Color( COL_TRANSPARENT ) ),
maShapeLineColor( Color( COL_TRANSPARENT ) ),
- mnStrokeWidth( 0 )
+ mnStrokeWidth( 0 ),
+ maLineJoin(basegfx::B2DLINEJOIN_MITER), // miter is Svg 'stroke-linejoin' default
+ maLineCap(com::sun::star::drawing::LineCap_BUTT) // butt is Svg 'stroke-linecap' default
{
}
};
diff --git a/offapi/com/sun/star/drawing/LineCap.idl b/offapi/com/sun/star/drawing/LineCap.idl
new file mode 100644
index 000000000000..ba825356407b
--- /dev/null
+++ b/offapi/com/sun/star/drawing/LineCap.idl
@@ -0,0 +1,58 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+#ifndef __com_sun_star_drawing_LineCap_idl__
+#define __com_sun_star_drawing_LineCap_idl__
+
+//=============================================================================
+
+ module com { module sun { module star { module drawing {
+
+//=============================================================================
+
+// DocMerge from xml: enum com::sun::star::drawing::LineCap
+/** The <type>LineCap</type> defines rendering of ends of thick lines
+ */
+published enum LineCap
+{
+
+ // DocMerge from xml: value com::sun::star::drawing::LineCap::BUTT
+ /** the line will end without any additional shape
+ */
+ BUTT,
+
+ // DocMerge from xml: value com::sun::star::drawing::LineCap::ROUND
+ /** the line will get a half cirle as additional cap
+ */
+ ROUND,
+
+ // DocMerge from xml: value com::sun::star::drawing::LineCap::SQUARE
+ /** the line will get a half square as additional cap
+ */
+ SQUARE
+};
+
+//=============================================================================
+
+}; }; }; };
+
+#endif
+
diff --git a/offapi/com/sun/star/drawing/LineProperties.idl b/offapi/com/sun/star/drawing/LineProperties.idl
index 9e7cbc992444..af14fa365eaa 100644
--- a/offapi/com/sun/star/drawing/LineProperties.idl
+++ b/offapi/com/sun/star/drawing/LineProperties.idl
@@ -23,26 +23,12 @@
#ifndef __com_sun_star_drawing_LineProperties_idl__
#define __com_sun_star_drawing_LineProperties_idl__
-#ifndef __com_sun_star_drawing_LineStyle_idl__
#include <com/sun/star/drawing/LineStyle.idl>
-#endif
-
-#ifndef __com_sun_star_util_Color_idl__
#include <com/sun/star/util/Color.idl>
-#endif
-
-#ifndef __com_sun_star_drawing_LineDash_idl__
#include <com/sun/star/drawing/LineDash.idl>
-#endif
-
-#ifndef __com_sun_star_drawing_PolyPolygonBezierCoords_idl__
#include <com/sun/star/drawing/PolyPolygonBezierCoords.idl>
-#endif
-
-#ifndef __com_sun_star_drawing_LineJoint_idl__
#include <com/sun/star/drawing/LineJoint.idl>
-#endif
-
+#include <com/sun/star/drawing/LineCap.idl>
//=============================================================================
@@ -98,6 +84,12 @@ published service LineProperties
//-------------------------------------------------------------------------
+ /** This property defines the rendering of ends of thick lines
+ */
+ [optional, property] com::sun::star::drawing::LineCap LineCap;
+
+ //-------------------------------------------------------------------------
+
/** This property contains the name of the line start poly polygon bezier.
<p>If this string is empty, no line start polygon is rendered.
*/
diff --git a/offapi/com/sun/star/drawing/makefile.mk b/offapi/com/sun/star/drawing/makefile.mk
index 47f97f950b66..6c7a23fc747d 100644
--- a/offapi/com/sun/star/drawing/makefile.mk
+++ b/offapi/com/sun/star/drawing/makefile.mk
@@ -120,6 +120,7 @@ IDLFILES=\
Layer.idl\
LayerManager.idl\
LayerType.idl\
+ LineCap.idl\
LineDash.idl\
LineEndType.idl\
LineJoint.idl\
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx
index d43a9fbad55d..b8b6c369a501 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -63,6 +63,28 @@ namespace svgio
return basegfx::B2DLINEJOIN_MITER;
}
+ com::sun::star::drawing::LineCap StrokeLinecapToDrawingLineCap(StrokeLinecap aStrokeLinecap)
+ {
+ switch(aStrokeLinecap)
+ {
+ default: /* StrokeLinecap_notset, StrokeLinecap_butt */
+ {
+ return com::sun::star::drawing::LineCap_BUTT;
+ break;
+ }
+ case StrokeLinecap_round:
+ {
+ return com::sun::star::drawing::LineCap_ROUND;
+ break;
+ }
+ case StrokeLinecap_square:
+ {
+ return com::sun::star::drawing::LineCap_SQUARE;
+ break;
+ }
+ }
+ }
+
FontStretch getWider(FontStretch aSource)
{
switch(aSource)
@@ -658,8 +680,9 @@ namespace svgio
if(basegfx::fTools::more(fStrokeWidth, 0.0))
{
- // get LineJoin and stroke array
+ // get LineJoin, LineCap and stroke array
const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin()));
+ const com::sun::star::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap()));
::std::vector< double > aDashArray;
if(!getStrokeDasharray().empty())
@@ -668,14 +691,14 @@ namespace svgio
}
// todo: Handle getStrokeDashOffset()
- // todo: Handle getStrokeLinecap()
// prepare line attribute
drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive;
const drawinglayer::attribute::LineAttribute aLineAttribute(
pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0),
fStrokeWidth,
- aB2DLineJoin);
+ aB2DLineJoin,
+ aLineCap);
if(aDashArray.empty())
{
diff --git a/svx/Package_inc.mk b/svx/Package_inc.mk
index 6550b70493a5..d157384731b7 100644
--- a/svx/Package_inc.mk
+++ b/svx/Package_inc.mk
@@ -172,6 +172,7 @@ $(eval $(call gb_Package_add_file,svx_inc,inc/svx/dbexch.hrc,svx/dbexch.hrc))
$(eval $(call gb_Package_add_file,svx_inc,inc/svx/unomaster.hxx,svx/unomaster.hxx))
$(eval $(call gb_Package_add_file,svx_inc,inc/svx/svdedtv.hxx,svx/svdedtv.hxx))
$(eval $(call gb_Package_add_file,svx_inc,inc/svx/xlinjoit.hxx,svx/xlinjoit.hxx))
+$(eval $(call gb_Package_add_file,svx_inc,inc/svx/xlncapit.hxx,svx/xlncapit.hxx))
$(eval $(call gb_Package_add_file,svx_inc,inc/svx/sxmbritm.hxx,svx/sxmbritm.hxx))
$(eval $(call gb_Package_add_file,svx_inc,inc/svx/AccessibleGraphicShape.hxx,svx/AccessibleGraphicShape.hxx))
$(eval $(call gb_Package_add_file,svx_inc,inc/svx/xlnstit.hxx,svx/xlnstit.hxx))
diff --git a/svx/inc/svx/dialogs.hrc b/svx/inc/svx/dialogs.hrc
index 9df4d1638d29..0310b8a32791 100755
--- a/svx/inc/svx/dialogs.hrc
+++ b/svx/inc/svx/dialogs.hrc
@@ -633,6 +633,11 @@
#define RID_SVXSTR_TBLAFMT_YELLOW (RID_SVX_START + 575)
#define RID_SVXSTR_TBLAFMT_END (RID_SVX_START + 576)
+// string resources for XLineCap item
+#define RID_SVXSTR_LINECAP_BUTT (RID_SVX_START + 586 )
+#define RID_SVXSTR_LINECAP_ROUND (RID_SVX_START + 587 )
+#define RID_SVXSTR_LINECAP_SQUARE (RID_SVX_START + 588 )
+
// string resources for XLineJoint item
#define RID_SVXSTR_LINEJOINT_NONE RID_SVXSTR_NONE
#define RID_SVXSTR_LINEJOINT_MIDDLE (RID_SVX_START + 589 )
diff --git a/svx/inc/svx/unoshprp.hxx b/svx/inc/svx/unoshprp.hxx
index 13c265a29365..5c31a0aaa8f4 100644
--- a/svx/inc/svx/unoshprp.hxx
+++ b/svx/inc/svx/unoshprp.hxx
@@ -32,6 +32,7 @@
#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/drawing/Hatch.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
#include <com/sun/star/drawing/LineDash.hpp>
#include <com/sun/star/drawing/LineJoint.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
@@ -211,6 +212,7 @@
{ MAP_CHAR_LEN(UNO_NAME_SHADOWYDIST), SDRATTR_SHADOWYDIST, &::getCppuType((const sal_Int32*)0), 0, SFX_METRIC_ITEM},
#define LINE_PROPERTIES_DEFAULTS\
+ { MAP_CHAR_LEN(UNO_NAME_LINECAP), XATTR_LINECAP, &::getCppuType((const ::com::sun::star::drawing::LineCap*)0), 0, 0}, \
{ MAP_CHAR_LEN(UNO_NAME_LINECOLOR), XATTR_LINECOLOR, &::getCppuType((const sal_Int32*)0) , 0, 0}, \
{ MAP_CHAR_LEN(UNO_NAME_LINEENDCENTER), XATTR_LINEENDCENTER, &::getBooleanCppuType() , 0, 0}, \
{ MAP_CHAR_LEN(UNO_NAME_LINEENDWIDTH), XATTR_LINEENDWIDTH, &::getCppuType((const sal_Int32*)0) , 0, SFX_METRIC_ITEM}, \
diff --git a/svx/inc/svx/xattr.hxx b/svx/inc/svx/xattr.hxx
index b85efde692b7..6dea0ad2cbcf 100644
--- a/svx/inc/svx/xattr.hxx
+++ b/svx/inc/svx/xattr.hxx
@@ -57,6 +57,7 @@ class XGradientTable;
#include <svx/xtextit0.hxx>
#include <svx/xsetit.hxx>
#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
#endif // _XATTR_HXX
diff --git a/svx/inc/svx/xdef.hxx b/svx/inc/svx/xdef.hxx
index e6a26669323e..099542c573b4 100644
--- a/svx/inc/svx/xdef.hxx
+++ b/svx/inc/svx/xdef.hxx
@@ -50,7 +50,8 @@
#define XATTR_LINEENDCENTER (XATTR_LINE_FIRST + 9) /* V3: 1009 V2: 1009 */
#define XATTR_LINETRANSPARENCE (XATTR_LINE_FIRST + 10) /* V3: 1010 V2: 1010 */
#define XATTR_LINEJOINT (XATTR_LINE_FIRST + 11) /* V3: 1011 V2: 1011 */
-#define XATTR_LINE_LAST XATTR_LINEJOINT
+#define XATTR_LINECAP (XATTR_LINE_FIRST + 12) /* V3: 1012 */
+#define XATTR_LINE_LAST XATTR_LINECAP
#define XATTRSET_LINE (XATTR_LINE_LAST + 1) /* V3: 1017 V2: 1017 */
#define XATTR_FILL_FIRST (XATTRSET_LINE + 1) /* V3: 1018 V2: 1018 */
diff --git a/svx/inc/svx/xlncapit.hxx b/svx/inc/svx/xlncapit.hxx
new file mode 100644
index 000000000000..1949e9fda419
--- /dev/null
+++ b/svx/inc/svx/xlncapit.hxx
@@ -0,0 +1,57 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+#ifndef _SVX_XLNCAPIT_HXX
+#define _SVX_XLNCAPIT_HXX
+
+#include <svx/svxdllapi.h>
+#include <svl/eitem.hxx>
+#include <svx/xenum.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
+
+//---------------------
+// class LineStyleItem
+//---------------------
+
+class SVX_DLLPUBLIC XLineCapItem : public SfxEnumItem
+{
+public:
+ TYPEINFO();
+ XLineCapItem(com::sun::star::drawing::LineCap eLineCap = com::sun::star::drawing::LineCap_BUTT);
+ XLineCapItem(SvStream& rIn);
+
+ virtual sal_uInt16 GetVersion( sal_uInt16 nFileFormatVersion ) const;
+ virtual SfxPoolItem* Clone( SfxItemPool* pPool = 0 ) const;
+ virtual SfxPoolItem* Create( SvStream& rIn, sal_uInt16 nVer ) const;
+
+ virtual sal_Bool QueryValue( com::sun::star::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const;
+ virtual sal_Bool PutValue( const com::sun::star::uno::Any& rVal, sal_uInt8 nMemberId = 0 );
+ virtual SfxItemPresentation GetPresentation( SfxItemPresentation ePres,
+ SfxMapUnit eCoreMetric, SfxMapUnit ePresMetric,
+ String &rText, const IntlWrapper * = 0 ) const;
+
+ virtual sal_uInt16 GetValueCount() const;
+ com::sun::star::drawing::LineCap GetValue() const;
+};
+
+#endif // _SVX_XLNCAPIT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/sdstring.src b/svx/source/dialog/sdstring.src
index b53fcbea056a..319689163e73 100644
--- a/svx/source/dialog/sdstring.src
+++ b/svx/source/dialog/sdstring.src
@@ -359,6 +359,19 @@ String RID_SVXSTR_LINEJOINT_ROUND
{
Text [ en-US ] = "Line joint round";
};
+String RID_SVXSTR_LINECAP_BUTT
+{
+ Text [ en-US ] = "Line cap flat"; // string as in Excel
+};
+String RID_SVXSTR_LINECAP_ROUND
+{
+ Text [ en-US ] = "Line cap round";
+};
+String RID_SVXSTR_LINECAP_SQUARE
+{
+ Text [ en-US ] = "Line cap square";
+};
+
///////////////////////////////////////////////////////////////////////////////
//
diff --git a/svx/source/sdr/attribute/sdrformtextattribute.cxx b/svx/source/sdr/attribute/sdrformtextattribute.cxx
index d128d7f8a1da..1608b9524391 100644
--- a/svx/source/sdr/attribute/sdrformtextattribute.cxx
+++ b/svx/source/sdr/attribute/sdrformtextattribute.cxx
@@ -42,12 +42,14 @@
#include <svx/xlnclit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xdash.hxx>
#include <svx/xlndsit.hxx>
#include <drawinglayer/attribute/lineattribute.hxx>
#include <drawinglayer/attribute/strokeattribute.hxx>
#include <svx/sdr/attribute/sdrformtextoutlineattribute.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
//////////////////////////////////////////////////////////////////////////////
// helper to get line, stroke and transparence attributes from SfxItemSet
@@ -114,8 +116,13 @@ namespace
const sal_uInt32 nLineWidth = ((const XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue();
const XLineJoint eLineJoint = ((const XLineJointItem&)(rSet.Get(XATTR_LINEJOINT))).GetValue();
+ const com::sun::star::drawing::LineCap eLineCap = ((const XLineCapItem&)(rSet.Get(XATTR_LINECAP))).GetValue();
- return drawinglayer::attribute::LineAttribute(aColorAttribute, (double)nLineWidth, impGetB2DLineJoin(eLineJoint));
+ return drawinglayer::attribute::LineAttribute(
+ aColorAttribute,
+ (double)nLineWidth,
+ impGetB2DLineJoin(eLineJoint),
+ eLineCap);
}
drawinglayer::attribute::StrokeAttribute impGetStrokeAttribute(const SfxItemSet& rSet)
diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
index 11d64679b738..40a42e74849a 100644
--- a/svx/source/sdr/primitive2d/sdrattributecreator.cxx
+++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
@@ -31,6 +31,7 @@
#include <svx/xlntrit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xlinjoit.hxx>
+#include <svx/xlncapit.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlnedwit.hxx>
@@ -78,6 +79,7 @@
#include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
#include <drawinglayer/attribute/sdrlightattribute3d.hxx>
#include <svx/sdr/attribute/sdrfilltextattribute.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
//////////////////////////////////////////////////////////////////////////////
@@ -237,6 +239,7 @@ namespace drawinglayer
const sal_uInt32 nWidth(((const XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue());
const Color aColor(((const XLineColorItem&)(rSet.Get(XATTR_LINECOLOR))).GetColorValue());
const XLineJoint eJoint(((const XLineJointItem&)(rSet.Get(XATTR_LINEJOINT))).GetValue());
+ const com::sun::star::drawing::LineCap eCap(((const XLineCapItem&)(rSet.Get(XATTR_LINECAP))).GetValue());
::std::vector< double > aDotDashArray;
double fFullDotDashLen(0.0);
@@ -255,6 +258,7 @@ namespace drawinglayer
(double)nWidth,
(double)nTransparence * 0.01,
aColor.getBColor(),
+ eCap,
aDotDashArray,
fFullDotDashLen);
}
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
index 19cadccbd15e..3b58c04d5717 100644
--- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
+++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
@@ -129,7 +129,7 @@ namespace drawinglayer
aScaledPolygon.transform(rObjectTransform);
// create line and stroke attribute
- const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin());
+ const attribute::LineAttribute aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), rLine.getCap());
const attribute::StrokeAttribute aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen());
BasePrimitive2D* pNewLinePrimitive = 0L;
diff --git a/svx/source/svdraw/svdfmtf.cxx b/svx/source/svdraw/svdfmtf.cxx
index 5519973e0c88..6156e7868f01 100644
--- a/svx/source/svdraw/svdfmtf.cxx
+++ b/svx/source/svdraw/svdfmtf.cxx
@@ -37,6 +37,7 @@
#include <editeng/crsditem.hxx>
#include <editeng/shdditem.hxx>
#include <svx/xlnclit.hxx>
+#include <svx/xlncapit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xflclit.hxx>
#include <svx/xgrad.hxx>
@@ -76,6 +77,7 @@ ImpSdrGDIMetaFileImport::ImpSdrGDIMetaFileImport(SdrModel& rModel):
pPage(NULL),pModel(NULL),nLayer(0),
nLineWidth(0),
maLineJoin(basegfx::B2DLINEJOIN_NONE),
+ maLineCap(com::sun::star::drawing::LineCap_BUTT),
maDash(XDASH_RECT, 0, 0, 0, 0, 0),
bFntDirty(sal_True),
bLastObjWasPolyWithoutLine(sal_False),bNoLine(sal_False),bNoFill(sal_False),bLastObjWasLine(sal_False)
@@ -305,6 +307,9 @@ void ImpSdrGDIMetaFileImport::SetAttributes(SdrObject* pObj, FASTBOOL bForceText
break;
}
+ // Add LineCap support
+ pLineAttr->Put(XLineCapItem(maLineCap));
+
if(((maDash.GetDots() && maDash.GetDotLen()) || (maDash.GetDashes() && maDash.GetDashLen())) && maDash.GetDistance())
{
pLineAttr->Put(XLineDashItem(String(), maDash));
@@ -480,6 +485,7 @@ void ImpSdrGDIMetaFileImport::DoAction(MetaLineAction& rAct)
SdrPathObj* pPath = new SdrPathObj(OBJ_LINE, basegfx::B2DPolyPolygon(aLine));
nLineWidth = nNewLineWidth;
maLineJoin = rLineInfo.GetLineJoin();
+ maLineCap = rLineInfo.GetLineCap();
maDash = XDash(XDASH_RECT,
rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
@@ -685,6 +691,7 @@ void ImpSdrGDIMetaFileImport::DoAction( MetaPolyLineAction& rAct )
basegfx::B2DPolyPolygon(aSource));
nLineWidth = nNewLineWidth;
maLineJoin = rLineInfo.GetLineJoin();
+ maLineCap = rLineInfo.GetLineCap();
maDash = XDash(XDASH_RECT,
rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
diff --git a/svx/source/svdraw/svdfmtf.hxx b/svx/source/svdraw/svdfmtf.hxx
index c311a8d5dc2f..0d3f23a693b0 100644
--- a/svx/source/svdraw/svdfmtf.hxx
+++ b/svx/source/svdraw/svdfmtf.hxx
@@ -80,6 +80,7 @@ protected:
Color aOldLineColor;
sal_Int32 nLineWidth;
basegfx::B2DLineJoin maLineJoin;
+ com::sun::star::drawing::LineCap maLineCap;
XDash maDash;
sal_Bool bMov;
diff --git a/svx/source/xoutdev/xattr2.cxx b/svx/source/xoutdev/xattr2.cxx
index 28b22f08e6e0..33ac5abb2835 100644
--- a/svx/source/xoutdev/xattr2.cxx
+++ b/svx/source/xoutdev/xattr2.cxx
@@ -28,6 +28,7 @@
#include <com/sun/star/drawing/LineJoint.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <svx/dialogs.hrc>
@@ -309,6 +310,150 @@ sal_uInt16 XLineJointItem::GetValueCount() const
return 5;
}
+//-----------------------
+// class XLineCapItem -
+//-----------------------
+
+TYPEINIT1_AUTOFACTORY(XLineCapItem, SfxEnumItem);
+
+// -----------------------------------------------------------------------------
+
+XLineCapItem::XLineCapItem(com::sun::star::drawing::LineCap eLineCap)
+: SfxEnumItem(XATTR_LINECAP, sal::static_int_cast< sal_uInt16 >(eLineCap))
+{
+}
+
+// -----------------------------------------------------------------------------
+
+XLineCapItem::XLineCapItem( SvStream& rIn )
+: SfxEnumItem(XATTR_LINECAP, rIn)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+sal_uInt16 XLineCapItem::GetVersion( sal_uInt16 /*nFileFormatVersion*/) const
+{
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+SfxPoolItem* XLineCapItem::Create( SvStream& rIn, sal_uInt16 nVer ) const
+{
+ XLineCapItem* pRet = new XLineCapItem( rIn );
+
+ if(nVer < 1)
+ pRet->SetValue(com::sun::star::drawing::LineCap_BUTT);
+
+ return pRet;
+}
+
+// -----------------------------------------------------------------------------
+
+SfxPoolItem* XLineCapItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new XLineCapItem( *this );
+}
+
+// -----------------------------------------------------------------------------
+
+SfxItemPresentation XLineCapItem::GetPresentation( SfxItemPresentation ePres, SfxMapUnit /*eCoreUnit*/,
+ SfxMapUnit /*ePresUnit*/, XubString& rText, const IntlWrapper*) const
+{
+ rText.Erase();
+
+ switch( ePres )
+ {
+ case SFX_ITEM_PRESENTATION_NONE: return ePres;
+
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ {
+ sal_uInt16 nId = 0;
+
+ switch( GetValue() )
+ {
+ default: /*com::sun::star::drawing::LineCap_BUTT*/
+ nId = RID_SVXSTR_LINECAP_BUTT;
+ break;
+
+ case(com::sun::star::drawing::LineCap_ROUND):
+ nId = RID_SVXSTR_LINECAP_ROUND;
+ break;
+
+ case(com::sun::star::drawing::LineCap_SQUARE):
+ nId = RID_SVXSTR_LINECAP_SQUARE;
+ break;
+ }
+
+ if( nId )
+ rText = SVX_RESSTR( nId );
+
+ return ePres;
+ }
+ default:
+ return SFX_ITEM_PRESENTATION_NONE;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Bool XLineCapItem::QueryValue( ::com::sun::star::uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ const com::sun::star::drawing::LineCap eCap(GetValue());
+ rVal <<= eCap;
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_Bool XLineCapItem::PutValue( const ::com::sun::star::uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ com::sun::star::drawing::LineCap eUnoCap;
+
+ if(!(rVal >>= eUnoCap))
+ {
+ // also try an int (for Basic)
+ sal_Int32 nLJ(0);
+
+ if(!(rVal >>= nLJ))
+ {
+ return false;
+ }
+
+ eUnoCap = (com::sun::star::drawing::LineCap)nLJ;
+ }
+
+ OSL_ENSURE(com::sun::star::drawing::LineCap_BUTT == eUnoCap
+ || com::sun::star::drawing::LineCap_ROUND == eUnoCap
+ || com::sun::star::drawing::LineCap_SQUARE == eUnoCap, "Unknown enum value in XATTR_LINECAP (!)");
+
+ SetValue(sal::static_int_cast< sal_uInt16 >(eUnoCap));
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+sal_uInt16 XLineCapItem::GetValueCount() const
+{
+ // don't forget to update the api interface also
+ return 3;
+}
+
+// -----------------------------------------------------------------------------
+
+com::sun::star::drawing::LineCap XLineCapItem::GetValue() const
+{
+ const com::sun::star::drawing::LineCap eRetval((com::sun::star::drawing::LineCap)SfxEnumItem::GetValue());
+ OSL_ENSURE(com::sun::star::drawing::LineCap_BUTT == eRetval
+ || com::sun::star::drawing::LineCap_ROUND == eRetval
+ || com::sun::star::drawing::LineCap_SQUARE == eRetval, "Unknown enum value in XATTR_LINECAP (!)");
+
+ return (com::sun::star::drawing::LineCap)SfxEnumItem::GetValue();
+}
+
//------------------------------
// class XFillTransparenceItem
//------------------------------
diff --git a/svx/source/xoutdev/xpool.cxx b/svx/source/xoutdev/xpool.cxx
index ab3de0a3659e..f1c8ac9f1ed5 100644
--- a/svx/source/xoutdev/xpool.cxx
+++ b/svx/source/xoutdev/xpool.cxx
@@ -87,6 +87,7 @@ XOutdevItemPool::XOutdevItemPool(
mppLocalPoolDefaults[XATTR_LINEENDCENTER -XATTR_START] = new XLineEndCenterItem;
mppLocalPoolDefaults[XATTR_LINETRANSPARENCE -XATTR_START] = new XLineTransparenceItem;
mppLocalPoolDefaults[XATTR_LINEJOINT -XATTR_START] = new XLineJointItem;
+ mppLocalPoolDefaults[XATTR_LINECAP -XATTR_START] = new XLineCapItem;
mppLocalPoolDefaults[XATTR_FILLSTYLE -XATTR_START] = new XFillStyleItem;
mppLocalPoolDefaults[XATTR_FILLCOLOR -XATTR_START] = new XFillColorItem (aNullStr,aNullFillCol);
mppLocalPoolDefaults[XATTR_FILLGRADIENT -XATTR_START] = new XFillGradientItem(this,aNullGrad);
diff --git a/vcl/aqua/source/gdi/salgdi.cxx b/vcl/aqua/source/gdi/salgdi.cxx
index 444436cad5d9..b2652ac17437 100755
--- a/vcl/aqua/source/gdi/salgdi.cxx
+++ b/vcl/aqua/source/gdi/salgdi.cxx
@@ -980,10 +980,12 @@ bool AquaSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPol
// -----------------------------------------------------------------------
-bool AquaSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine,
+bool AquaSalGraphics::drawPolyLine(
+ const ::basegfx::B2DPolygon& rPolyLine,
double fTransparency,
const ::basegfx::B2DVector& rLineWidths,
- basegfx::B2DLineJoin eLineJoin )
+ basegfx::B2DLineJoin eLineJoin,
+ com::sun::star::drawing::LineCap eLineCap)
{
// short circuit if there is nothing to do
const int nPointCount = rPolyLine.count();
diff --git a/vcl/inc/aqua/salgdi.h b/vcl/inc/aqua/salgdi.h
index 7d53df93a46c..8cc6dd7ba6fd 100644
--- a/vcl/inc/aqua/salgdi.h
+++ b/vcl/inc/aqua/salgdi.h
@@ -186,7 +186,12 @@ public:
virtual sal_Bool drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual sal_Bool drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual sal_Bool drawPolyPolygonBezier( sal_uLong nPoly, const sal_uLong* pPoints, const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry );
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap eLineCap);
// CopyArea --> No RasterOp, but ClipRegion
virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
diff --git a/vcl/inc/os2/salgdi.h b/vcl/inc/os2/salgdi.h
index de95e5b2ec41..7a5c475adec0 100644
--- a/vcl/inc/os2/salgdi.h
+++ b/vcl/inc/os2/salgdi.h
@@ -166,7 +166,12 @@ protected:
virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry );
virtual void drawPolyPolygon( ULONG nPoly, const ULONG* pPoints, PCONSTSALPOINT* pPtAry );
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidth,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap);
virtual sal_Bool drawPolyLineBezier( sal_uIntPtr nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual sal_Bool drawPolygonBezier( sal_uIntPtr nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry );
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 7e9feaf80706..72720845a307 100755
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -119,7 +119,12 @@ protected:
virtual void drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry ) = 0;
virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0;
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) = 0;
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin ) = 0;
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap) = 0;
virtual sal_Bool drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) = 0;
virtual sal_Bool drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) = 0;
virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry ) = 0;
@@ -361,7 +366,15 @@ public:
PCONSTSALPOINT* pPtAry,
const OutputDevice *pOutDev );
bool DrawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency, const OutputDevice* );
- bool DrawPolyLine( const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin, const OutputDevice* );
+
+ bool DrawPolyLine(
+ const basegfx::B2DPolygon& i_rPolygon,
+ double i_fTransparency,
+ const basegfx::B2DVector& i_rLineWidth,
+ basegfx::B2DLineJoin i_eLineJoin,
+ com::sun::star::drawing::LineCap i_eLineCap,
+ const OutputDevice* i_pOutDev);
+
sal_Bool DrawPolyLineBezier( sal_uLong nPoints,
const SalPoint* pPtAry,
const sal_uInt8* pFlgAry,
diff --git a/vcl/inc/unx/pspgraphics.h b/vcl/inc/unx/pspgraphics.h
index a534611d0fa9..3323a6e85d0a 100644
--- a/vcl/inc/unx/pspgraphics.h
+++ b/vcl/inc/unx/pspgraphics.h
@@ -136,7 +136,12 @@ public:
const sal_uInt32* pPoints,
PCONSTSALPOINT* pPtAry );
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
- virtual bool drawPolyLine( const basegfx::B2DPolygon&, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin);
+ virtual bool drawPolyLine(
+ const basegfx::B2DPolygon&,
+ double fTransparency,
+ const basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap);
virtual sal_Bool drawPolyLineBezier( sal_uIntPtr nPoints,
const SalPoint* pPtAry,
const sal_uInt8* pFlgAry );
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index c69e4b0630c4..60a734be51b2 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -284,7 +284,12 @@ public:
const sal_uInt32* pPoints,
PCONSTSALPOINT* pPtAry );
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidth,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap);
virtual bool drawFilledTrapezoids( const ::basegfx::B2DTrapezoid*, int nTrapCount, double fTransparency );
#if 1 // TODO: remove these obselete methods
diff --git a/vcl/inc/vcl/cvtsvm.hxx b/vcl/inc/vcl/cvtsvm.hxx
index 80ae55056a54..07a565857f9f 100644
--- a/vcl/inc/vcl/cvtsvm.hxx
+++ b/vcl/inc/vcl/cvtsvm.hxx
@@ -82,6 +82,9 @@
#define GDI_EXTENDEDPOLYGON_ACTION 1034
#define GDI_LINEDASHDOT_ACTION 1035
+// Added LineCap support
+#define GDI_LINECAP_ACTION 1036
+
// ----------------
// - SVMConverter -
// ----------------
diff --git a/vcl/inc/vcl/lineinfo.hxx b/vcl/inc/vcl/lineinfo.hxx
index 6bf56af43258..13f2a9f2a19e 100644
--- a/vcl/inc/vcl/lineinfo.hxx
+++ b/vcl/inc/vcl/lineinfo.hxx
@@ -28,6 +28,7 @@
#include <tools/gen.hxx>
#include <vcl/vclenum.hxx>
#include <basegfx/vector/b2enums.hxx>
+#include <com/sun/star/drawing/LineCap.hpp>
// ----------------
// - ImplLineInfo -
@@ -48,6 +49,7 @@ struct ImplLineInfo
long mnDistance;
basegfx::B2DLineJoin meLineJoin;
+ com::sun::star::drawing::LineCap meLineCap;
ImplLineInfo();
ImplLineInfo( const ImplLineInfo& rImplLineInfo );
@@ -108,7 +110,10 @@ public:
void SetLineJoin(basegfx::B2DLineJoin eLineJoin);
basegfx::B2DLineJoin GetLineJoin() const { return mpImplLineInfo->meLineJoin; }
- sal_Bool IsDefault() const { return( !mpImplLineInfo->mnWidth && ( LINE_SOLID == mpImplLineInfo->meStyle ) ); }
+ void SetLineCap(com::sun::star::drawing::LineCap eLineCap);
+ com::sun::star::drawing::LineCap GetLineCap() const { return mpImplLineInfo->meLineCap; }
+
+ sal_Bool IsDefault() const;
friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, LineInfo& rLineInfo );
friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const LineInfo& rLineInfo );
diff --git a/vcl/inc/vcl/outdev.hxx b/vcl/inc/vcl/outdev.hxx
index 30d8c0f3eaa0..8c4e9b2c3720 100644
--- a/vcl/inc/vcl/outdev.hxx
+++ b/vcl/inc/vcl/outdev.hxx
@@ -41,7 +41,7 @@
#include <com/sun/star/uno/Reference.h>
#include <unotools/fontdefs.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
-
+#include <com/sun/star/drawing/LineCap.hpp>
#include <vector>
struct ImplOutDevData;
@@ -556,7 +556,11 @@ public:
// #i101491#
// Helper who tries to use SalGDI's DrawPolyLine direct and returns it's bool. Contains no AA check.
- SAL_DLLPRIVATE bool ImpTryDrawPolyLineDirect(const basegfx::B2DPolygon& rB2DPolygon, double fLineWidth, basegfx::B2DLineJoin eLineJoin);
+ SAL_DLLPRIVATE bool ImpTryDrawPolyLineDirect(
+ const basegfx::B2DPolygon& rB2DPolygon,
+ double fLineWidth = 0.0,
+ basegfx::B2DLineJoin eLineJoin = basegfx::B2DLINEJOIN_NONE,
+ com::sun::star::drawing::LineCap eLineCap = com::sun::star::drawing::LineCap_BUTT);
// Helper for line geometry paint with support for graphic expansion (pattern and fat_to_area)
void impPaintLineGeometryWithEvtlExpand(const LineInfo& rInfo, basegfx::B2DPolyPolygon aLinePolyPolygon);
@@ -687,7 +691,11 @@ public:
@see DrawPolyPolygon
*/
void DrawPolyLine( const Polygon& rPoly );
- void DrawPolyLine( const basegfx::B2DPolygon&, double fLineWidth = 0.0, basegfx::B2DLineJoin = basegfx::B2DLINEJOIN_ROUND );
+ void DrawPolyLine(
+ const basegfx::B2DPolygon&,
+ double fLineWidth = 0.0,
+ basegfx::B2DLineJoin = basegfx::B2DLINEJOIN_ROUND,
+ com::sun::star::drawing::LineCap = com::sun::star::drawing::LineCap_BUTT);
/** Render the given polygon as a line stroke
diff --git a/vcl/inc/vcl/print.hxx b/vcl/inc/vcl/print.hxx
index 755197147563..de0649a3b4ea 100644
--- a/vcl/inc/vcl/print.hxx
+++ b/vcl/inc/vcl/print.hxx
@@ -84,11 +84,6 @@ public:
GDIMetaFile* GetGDIMetaFile() const { return mpMtf; }
const JobSetup& GetJobSetup() const { return maJobSetup; }
sal_Bool IsNewJobSetup() const { return (mbNewJobSetup != 0); }
-
- friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const PrinterPage& rPage )
- { rOStm << rPage.mbNewJobSetup; rOStm << rPage.maJobSetup; rPage.mpMtf->Write( rOStm ); return rOStm; }
- friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, PrinterPage& rPage )
- { return rIStm >> rPage.mbNewJobSetup >> rPage.maJobSetup >> *rPage.mpMtf; }
};
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 9227b2da7005..1ba1c51f36fb 100755
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -186,7 +186,12 @@ protected:
virtual void drawPolygon( sal_uIntPtr nPoints, const SalPoint* pPtAry );
virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry );
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidth,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap);
virtual sal_Bool drawPolyLineBezier( sal_uIntPtr nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual sal_Bool drawPolygonBezier( sal_uIntPtr nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry );
diff --git a/vcl/source/gdi/cvtsvm.cxx b/vcl/source/gdi/cvtsvm.cxx
index 10e9971e08b1..414b0c51600f 100644
--- a/vcl/source/gdi/cvtsvm.cxx
+++ b/vcl/source/gdi/cvtsvm.cxx
@@ -599,6 +599,14 @@ void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf )
}
break;
+ case (GDI_LINECAP_ACTION) :
+ {
+ sal_Int16 nLineCap(0);
+ rIStm >> nLineCap;
+ aLineInfo.SetLineCap((com::sun::star::drawing::LineCap)nLineCap);
+ }
+ break;
+
case (GDI_LINEDASHDOT_ACTION) :
{
sal_Int16 a(0);
@@ -1457,6 +1465,7 @@ sal_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 bLineCap(bFatLine && com::sun::star::drawing::LineCap_BUTT != rInfo.GetLineCap());
const bool bLineDashDot(LINE_DASH == rInfo.GetStyle());
if( bFatLine )
@@ -1471,18 +1480,25 @@ sal_uLong SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
rOStm << (sal_Int16) rInfo.GetLineJoin();
}
- if(bLineDashDot)
+ if(bLineCap)
{
- rOStm << (sal_Int16) GDI_LINEDASHDOT_ACTION;
- rOStm << (sal_Int32) 4 + 16;
- rOStm << (sal_Int16)rInfo.GetDashCount();
- rOStm << (sal_Int32)rInfo.GetDashLen();
- rOStm << (sal_Int16)rInfo.GetDotCount();
- rOStm << (sal_Int32)rInfo.GetDotLen();
- rOStm << (sal_Int32)rInfo.GetDistance();
+ rOStm << (sal_Int16) GDI_LINECAP_ACTION;
+ rOStm << (sal_Int32) 6;
+ rOStm << (sal_Int16) rInfo.GetLineCap();
}
}
+ if(bLineDashDot)
+ {
+ rOStm << (sal_Int16) GDI_LINEDASHDOT_ACTION;
+ rOStm << (sal_Int32) 4 + 16;
+ rOStm << (sal_Int16)rInfo.GetDashCount();
+ rOStm << (sal_Int32)rInfo.GetDashLen();
+ rOStm << (sal_Int16)rInfo.GetDotCount();
+ rOStm << (sal_Int32)rInfo.GetDotLen();
+ rOStm << (sal_Int32)rInfo.GetDistance();
+ }
+
rOStm << (sal_Int16) GDI_LINE_ACTION;
rOStm << (sal_Int32) 20;
rOStm << pAct->GetStartPoint();
@@ -1499,11 +1515,16 @@ sal_uLong SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
nCount += 1;
}
- if(bLineDashDot)
+ if(bLineCap)
{
nCount += 1;
}
}
+
+ if(bLineDashDot)
+ {
+ nCount += 1;
+ }
}
break;
@@ -1600,6 +1621,7 @@ sal_uLong SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
const sal_uInt16 nPoints(aSimplePoly.GetSize());
const bool bFatLine(!rInfo.IsDefault() && (LINE_NONE != rInfo.GetStyle()));
const bool bLineJoin(bFatLine && basegfx::B2DLINEJOIN_ROUND != rInfo.GetLineJoin());
+ const bool bLineCap(bFatLine && com::sun::star::drawing::LineCap_BUTT != rInfo.GetLineCap());
const bool bLineDashDot(LINE_DASH == rInfo.GetStyle());
if( bFatLine )
@@ -1613,6 +1635,13 @@ sal_uLong SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
rOStm << (sal_Int32) 6;
rOStm << (sal_Int16) rInfo.GetLineJoin();
}
+
+ if(bLineCap)
+ {
+ rOStm << (sal_Int16) GDI_LINECAP_ACTION;
+ rOStm << (sal_Int32) 6;
+ rOStm << (sal_Int16) rInfo.GetLineCap();
+ }
}
if(bLineDashDot)
@@ -1652,6 +1681,11 @@ sal_uLong SVMConverter::ImplWriteActions( SvStream& rOStm, GDIMetaFile& rMtf,
{
nCount += 1;
}
+
+ if(bLineCap)
+ {
+ nCount += 1;
+ }
}
if(bLineDashDot)
diff --git a/vcl/source/gdi/lineinfo.cxx b/vcl/source/gdi/lineinfo.cxx
index 339b17792825..87c313c2e48c 100644
--- a/vcl/source/gdi/lineinfo.cxx
+++ b/vcl/source/gdi/lineinfo.cxx
@@ -47,7 +47,8 @@ ImplLineInfo::ImplLineInfo() :
mnDotCount ( 0 ),
mnDotLen ( 0 ),
mnDistance ( 0 ),
- meLineJoin ( basegfx::B2DLINEJOIN_ROUND )
+ meLineJoin ( basegfx::B2DLINEJOIN_ROUND ),
+ meLineCap ( com::sun::star::drawing::LineCap_BUTT )
{
}
@@ -62,7 +63,8 @@ ImplLineInfo::ImplLineInfo( const ImplLineInfo& rImplLineInfo ) :
mnDotCount ( rImplLineInfo.mnDotCount ),
mnDotLen ( rImplLineInfo.mnDotLen ),
mnDistance ( rImplLineInfo.mnDistance ),
- meLineJoin ( rImplLineInfo.meLineJoin )
+ meLineJoin ( rImplLineInfo.meLineJoin ),
+ meLineCap ( rImplLineInfo.meLineCap )
{
}
@@ -77,7 +79,8 @@ inline bool ImplLineInfo::operator==( const ImplLineInfo& rB ) const
&& mnDotCount == rB.mnDotCount
&& mnDotLen == rB.mnDotLen
&& mnDistance == rB.mnDistance
- && meLineJoin == rB.meLineJoin);
+ && meLineJoin == rB.meLineJoin
+ && meLineCap == rB.meLineCap);
}
// ------------
@@ -229,6 +232,28 @@ void LineInfo::SetLineJoin(basegfx::B2DLineJoin eLineJoin)
// -----------------------------------------------------------------------
+void LineInfo::SetLineCap(com::sun::star::drawing::LineCap eLineCap)
+{
+ DBG_CHKTHIS( LineInfo, NULL );
+
+ if(eLineCap != mpImplLineInfo->meLineCap)
+ {
+ ImplMakeUnique();
+ mpImplLineInfo->meLineCap = eLineCap;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool LineInfo::IsDefault() const
+{
+ return( !mpImplLineInfo->mnWidth
+ && ( LINE_SOLID == mpImplLineInfo->meStyle )
+ && ( com::sun::star::drawing::LineCap_BUTT == mpImplLineInfo->meLineCap));
+}
+
+// -----------------------------------------------------------------------
+
SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo )
{
VersionCompat aCompat( rIStm, STREAM_READ );
@@ -251,6 +276,12 @@ SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo )
rIStm >> nTmp16; rImplLineInfo.meLineJoin = (basegfx::B2DLineJoin) nTmp16;
}
+ if( aCompat.GetVersion() >= 4 )
+ {
+ // version 4
+ rIStm >> nTmp16; rImplLineInfo.meLineCap = (com::sun::star::drawing::LineCap) nTmp16;
+ }
+
return rIStm;
}
@@ -258,7 +289,7 @@ SvStream& operator>>( SvStream& rIStm, ImplLineInfo& rImplLineInfo )
SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo )
{
- VersionCompat aCompat( rOStm, STREAM_WRITE, 3 );
+ VersionCompat aCompat( rOStm, STREAM_WRITE, 4 );
// version 1
rOStm << (sal_uInt16) rImplLineInfo.meStyle << rImplLineInfo.mnWidth;
@@ -271,6 +302,9 @@ SvStream& operator<<( SvStream& rOStm, const ImplLineInfo& rImplLineInfo )
// since version3
rOStm << (sal_uInt16) rImplLineInfo.meLineJoin;
+ // since version4
+ rOStm << (sal_uInt16) rImplLineInfo.meLineCap;
+
return rOStm;
}
@@ -354,7 +388,8 @@ void LineInfo::applyToB2DPolyPolygon(
o_rFillPolyPolygon.append(basegfx::tools::createAreaGeometry(
io_rLinePolyPolygon.getB2DPolygon(a),
fHalfLineWidth,
- GetLineJoin()));
+ GetLineJoin(),
+ GetLineCap()));
}
io_rLinePolyPolygon.clear();
diff --git a/vcl/source/gdi/outdev.cxx b/vcl/source/gdi/outdev.cxx
index 6a57320c763c..48f4195cbb54 100644
--- a/vcl/source/gdi/outdev.cxx
+++ b/vcl/source/gdi/outdev.cxx
@@ -1509,7 +1509,7 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt )
aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
}
- if( mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this))
+ if( mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this))
{
return;
}
@@ -1596,7 +1596,8 @@ void OutputDevice::impPaintLineGeometryWithEvtlExpand(
aFillPolyPolygon.append(basegfx::tools::createAreaGeometry(
aLinePolyPolygon.getB2DPolygon(a),
fHalfLineWidth,
- rInfo.GetLineJoin()));
+ rInfo.GetLineJoin(),
+ rInfo.GetLineCap()));
}
aLinePolyPolygon.clear();
@@ -1614,7 +1615,7 @@ void OutputDevice::impPaintLineGeometryWithEvtlExpand(
if(bTryAA)
{
- bDone = mpGraphics->DrawPolyLine( aCandidate, 0.0, basegfx::B2DVector(1.0,1.0), basegfx::B2DLINEJOIN_NONE, this);
+ bDone = mpGraphics->DrawPolyLine( aCandidate, 0.0, basegfx::B2DVector(1.0,1.0), basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this);
}
if(!bDone)
@@ -1646,7 +1647,10 @@ void OutputDevice::impPaintLineGeometryWithEvtlExpand(
{
for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
{
- const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
+ Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
+
+ // need to subdivide, mpGraphics->DrawPolygon ignores curves
+ aPolygon.AdaptiveSubdivide(aPolygon);
mpGraphics->DrawPolygon(aPolygon.GetSize(), (const SalPoint*)aPolygon.GetConstPointAry(), this);
}
}
@@ -1789,7 +1793,7 @@ void OutputDevice::DrawPolyLine( const Polygon& rPoly )
&& IsLineColor());
// use b2dpolygon drawing if possible
- if(bTryAA && ImpTryDrawPolyLineDirect(rPoly.getB2DPolygon(), 0.0, basegfx::B2DLINEJOIN_NONE))
+ if(bTryAA && ImpTryDrawPolyLineDirect(rPoly.getB2DPolygon()))
{
basegfx::B2DPolygon aB2DPolyLine(rPoly.getB2DPolygon());
const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
@@ -1803,7 +1807,7 @@ void OutputDevice::DrawPolyLine( const Polygon& rPoly )
aB2DPolyLine = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
}
- if(mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this))
+ if(mpGraphics->DrawPolyLine( aB2DPolyLine, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this))
{
return;
}
@@ -1851,7 +1855,7 @@ void OutputDevice::DrawPolyLine( const Polygon& rPoly, const LineInfo& rLineInfo
if((mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW)
&& LINE_SOLID == rLineInfo.GetStyle())
{
- DrawPolyLine( rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin());
+ DrawPolyLine( rPoly.getB2DPolygon(), (double)rLineInfo.GetWidth(), rLineInfo.GetLineJoin(), rLineInfo.GetLineCap());
return;
}
@@ -1983,7 +1987,13 @@ void OutputDevice::DrawPolygon( const Polygon& rPoly )
aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
}
- bSuccess = mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
+ bSuccess = mpGraphics->DrawPolyLine(
+ aB2DPolygon,
+ 0.0,
+ aB2DLineWidth,
+ basegfx::B2DLINEJOIN_NONE,
+ com::sun::star::drawing::LineCap_BUTT,
+ this);
}
if(bSuccess)
@@ -2075,7 +2085,13 @@ void OutputDevice::DrawPolyPolygon( const PolyPolygon& rPolyPoly )
for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++)
{
- bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
+ bSuccess = mpGraphics->DrawPolyLine(
+ aB2DPolyPolygon.getB2DPolygon(a),
+ 0.0,
+ aB2DLineWidth,
+ basegfx::B2DLINEJOIN_NONE,
+ com::sun::star::drawing::LineCap_BUTT,
+ this);
}
}
@@ -2198,7 +2214,13 @@ void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPo
for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++)
{
- bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a), 0.0, aB2DLineWidth, basegfx::B2DLINEJOIN_NONE, this);
+ bSuccess = mpGraphics->DrawPolyLine(
+ aB2DPolyPolygon.getB2DPolygon(a),
+ 0.0,
+ aB2DLineWidth,
+ basegfx::B2DLINEJOIN_NONE,
+ com::sun::star::drawing::LineCap_BUTT,
+ this);
}
}
@@ -2219,7 +2241,8 @@ void OutputDevice::ImpDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPo
bool OutputDevice::ImpTryDrawPolyLineDirect(
const basegfx::B2DPolygon& rB2DPolygon,
double fLineWidth,
- basegfx::B2DLineJoin eLineJoin)
+ basegfx::B2DLineJoin eLineJoin,
+ com::sun::star::drawing::LineCap eLineCap)
{
const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
basegfx::B2DVector aB2DLineWidth(1.0, 1.0);
@@ -2245,17 +2268,25 @@ bool OutputDevice::ImpTryDrawPolyLineDirect(
}
// draw the polyline
- return mpGraphics->DrawPolyLine( aB2DPolygon, 0.0, aB2DLineWidth, eLineJoin, this);
+ return mpGraphics->DrawPolyLine(
+ aB2DPolygon,
+ 0.0,
+ aB2DLineWidth,
+ eLineJoin,
+ eLineCap,
+ this);
}
void OutputDevice::DrawPolyLine(
const basegfx::B2DPolygon& rB2DPolygon,
double fLineWidth,
- basegfx::B2DLineJoin eLineJoin)
+ basegfx::B2DLineJoin eLineJoin,
+ com::sun::star::drawing::LineCap eLineCap)
{
DBG_TRACE( "OutputDevice::DrawPolyLine(B2D&)" );
DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
(void)eLineJoin; // ATM used in UNX, but not in WNT, access it for warning-free
+ (void)eLineCap;
#if 0 // MetaB2DPolyLineAction is not implemented yet:
// according to AW adding it is very dangerous since there is a lot
@@ -2297,7 +2328,7 @@ void OutputDevice::DrawPolyLine(
&& IsLineColor());
// use b2dpolygon drawing if possible
- if(bTryAA && ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, eLineJoin))
+ if(bTryAA && ImpTryDrawPolyLineDirect(rB2DPolygon, fLineWidth, eLineJoin, eLineCap))
{
return;
}
@@ -2311,9 +2342,12 @@ void OutputDevice::DrawPolyLine(
&& rB2DPolygon.count() <= 1000)
{
const double fHalfLineWidth((fLineWidth * 0.5) + 0.5);
- const basegfx::B2DPolyPolygon aAreaPolyPolygon(basegfx::tools::createAreaGeometry(
- rB2DPolygon, fHalfLineWidth, eLineJoin));
-
+ const basegfx::B2DPolyPolygon aAreaPolyPolygon(
+ basegfx::tools::createAreaGeometry(
+ rB2DPolygon,
+ fHalfLineWidth,
+ eLineJoin,
+ eLineCap));
const Color aOldLineColor(maLineColor);
const Color aOldFillColor(maFillColor);
@@ -2340,7 +2374,7 @@ void OutputDevice::DrawPolyLine(
// to avoid optical gaps
for(sal_uInt32 a(0); a < aAreaPolyPolygon.count(); a++)
{
- ImpTryDrawPolyLineDirect(aAreaPolyPolygon.getB2DPolygon(a), 0.0, basegfx::B2DLINEJOIN_NONE);
+ ImpTryDrawPolyLineDirect(aAreaPolyPolygon.getB2DPolygon(a));
}
}
}
diff --git a/vcl/source/gdi/outdev6.cxx b/vcl/source/gdi/outdev6.cxx
index f4b4dee908c6..626c0989db1e 100644
--- a/vcl/source/gdi/outdev6.cxx
+++ b/vcl/source/gdi/outdev6.cxx
@@ -200,7 +200,7 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly,
for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
{
const ::basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
- mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, this );
+ mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this );
}
}
@@ -317,7 +317,7 @@ void OutputDevice::DrawTransparent( const PolyPolygon& rPolyPoly,
for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
{
const ::basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
- bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, ::basegfx::B2DLINEJOIN_NONE, this );
+ bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this );
}
// prepare to restore the fill color
mbInitFillColor = mbFillColor;
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 896d322185cb..8655cf126588 100755
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -1624,7 +1624,28 @@ void PDFWriterImpl::PDFPage::appendMappedLength( double fLength, OStringBuffer&
bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const
{
- bool bRet = true;
+ if(LINE_DASH == rInfo.GetStyle() && rInfo.GetDashLen() != rInfo.GetDotLen())
+ {
+ // dashed and non-degraded case, check for implementation limits of dash array
+ // in PDF reader apps (e.g. acroread)
+ if(2 * (rInfo.GetDashCount() + rInfo.GetDotCount()) > 10)
+ {
+ return false;
+ }
+ }
+
+ if(basegfx::B2DLINEJOIN_NONE != rInfo.GetLineJoin())
+ {
+ // LineJoin used, ExtLineInfo required
+ return false;
+ }
+
+ if(com::sun::star::drawing::LineCap_BUTT != rInfo.GetLineCap())
+ {
+ // LineCap used, ExtLineInfo required
+ return false;
+ }
+
if( rInfo.GetStyle() == LINE_DASH )
{
rBuffer.append( "[ " );
@@ -1637,10 +1658,6 @@ bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffe
}
else
{
- // check for implementation limits of dash array
- // in PDF reader apps (e.g. acroread)
- if( 2*(rInfo.GetDashCount() + rInfo.GetDotCount()) > 10 )
- bRet = false;
for( int n = 0; n < rInfo.GetDashCount(); n++ )
{
appendMappedLength( (sal_Int32)rInfo.GetDashLen(), rBuffer );
@@ -1658,6 +1675,7 @@ bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffe
}
rBuffer.append( "] 0 d\n" );
}
+
if( rInfo.GetWidth() > 1 )
{
appendMappedLength( (sal_Int32)rInfo.GetWidth(), rBuffer );
@@ -1669,7 +1687,8 @@ bool PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffe
appendDouble( 72.0/double(m_pWriter->getReferenceDevice()->ImplGetDPIX()), rBuffer );
rBuffer.append( " w\n" );
}
- return bRet;
+
+ return true;
}
void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal_Int32 nDelta, OStringBuffer& rBuffer ) const
@@ -9045,21 +9064,68 @@ void PDFWriterImpl::convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter
rOut.m_fMiterLimit = 10;
rOut.m_aDashArray.clear();
- int nDashes = rIn.GetDashCount();
- int nDashLen = rIn.GetDashLen();
- int nDistance = rIn.GetDistance();
+ // add DashDot to DashArray
+ const int nDashes = rIn.GetDashCount();
+ const int nDashLen = rIn.GetDashLen();
+ const int nDistance = rIn.GetDistance();
+
for( int n = 0; n < nDashes; n++ )
{
rOut.m_aDashArray.push_back( nDashLen );
rOut.m_aDashArray.push_back( nDistance );
}
- int nDots = rIn.GetDotCount();
- int nDotLen = rIn.GetDotLen();
+
+ const int nDots = rIn.GetDotCount();
+ const int nDotLen = rIn.GetDotLen();
+
for( int n = 0; n < nDots; n++ )
{
rOut.m_aDashArray.push_back( nDotLen );
rOut.m_aDashArray.push_back( nDistance );
}
+
+ // add LineJoin
+ switch(rIn.GetLineJoin())
+ {
+ case basegfx::B2DLINEJOIN_BEVEL :
+ {
+ rOut.m_eJoin = PDFWriter::joinBevel;
+ break;
+ }
+ default : // basegfx::B2DLINEJOIN_NONE :
+ // Pdf has no 'none' lineJoin, default is miter
+ case basegfx::B2DLINEJOIN_MIDDLE :
+ case basegfx::B2DLINEJOIN_MITER :
+ {
+ rOut.m_eJoin = PDFWriter::joinMiter;
+ break;
+ }
+ case basegfx::B2DLINEJOIN_ROUND :
+ {
+ rOut.m_eJoin = PDFWriter::joinRound;
+ break;
+ }
+ }
+
+ // add LineCap
+ switch(rIn.GetLineCap())
+ {
+ default: /* com::sun::star::drawing::LineCap_BUTT */
+ {
+ rOut.m_eCap = PDFWriter::capButt;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ rOut.m_eCap = PDFWriter::capRound;
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ rOut.m_eCap = PDFWriter::capSquare;
+ break;
+ }
+ }
}
void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo )
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index 094acf76cb92..416d97558c32 100755
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -412,7 +412,8 @@ bool SalGraphics::drawPolyLine(
const basegfx::B2DPolygon& /*rPolyPolygon*/,
double /*fTransparency*/,
const basegfx::B2DVector& /*rLineWidths*/,
- basegfx::B2DLineJoin /*eLineJoin*/)
+ basegfx::B2DLineJoin /*eLineJoin*/,
+ com::sun::star::drawing::LineCap /*eLineCap*/)
{
return false;
}
@@ -542,18 +543,22 @@ sal_Bool SalGraphics::DrawPolyPolygonBezier( sal_uInt32 i_nPoly, const sal_uInt3
return bRet;
}
-bool SalGraphics::DrawPolyLine( const ::basegfx::B2DPolygon& i_rPolygon, double fTransparency,
- const ::basegfx::B2DVector& i_rLineWidth, basegfx::B2DLineJoin i_eLineJoin,
+bool SalGraphics::DrawPolyLine(
+ const ::basegfx::B2DPolygon& i_rPolygon,
+ double i_fTransparency,
+ const ::basegfx::B2DVector& i_rLineWidth,
+ basegfx::B2DLineJoin i_eLineJoin,
+ com::sun::star::drawing::LineCap i_eLineCap,
const OutputDevice* i_pOutDev )
{
bool bRet = false;
if( (m_nLayout & SAL_LAYOUT_BIDI_RTL) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) )
{
basegfx::B2DPolygon aMirror( mirror( i_rPolygon, i_pOutDev ) );
- bRet = drawPolyLine( aMirror, fTransparency, i_rLineWidth, i_eLineJoin );
+ bRet = drawPolyLine( aMirror, i_fTransparency, i_rLineWidth, i_eLineJoin, i_eLineCap );
}
else
- bRet = drawPolyLine( i_rPolygon, fTransparency, i_rLineWidth, i_eLineJoin );
+ bRet = drawPolyLine( i_rPolygon, i_fTransparency, i_rLineWidth, i_eLineJoin, i_eLineCap );
return bRet;
}
diff --git a/vcl/unx/generic/gdi/pspgraphics.cxx b/vcl/unx/generic/gdi/pspgraphics.cxx
index d2a1942f419a..188cff6be9dd 100644
--- a/vcl/unx/generic/gdi/pspgraphics.cxx
+++ b/vcl/unx/generic/gdi/pspgraphics.cxx
@@ -401,7 +401,12 @@ bool PspGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fT
return false;
}
-bool PspGraphics::drawPolyLine( const basegfx::B2DPolygon&, double /*fTranspareny*/, const basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/)
+bool PspGraphics::drawPolyLine(
+ const basegfx::B2DPolygon&,
+ double /*fTranspareny*/,
+ const basegfx::B2DVector& /*rLineWidths*/,
+ basegfx::B2DLineJoin /*eJoin*/,
+ com::sun::star::drawing::LineCap /*eLineCap*/)
{
// TODO: a PS printer can draw B2DPolyLines almost directly
return false;
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
index 79b2a1b1319f..d7a3eccb0d09 100644
--- a/vcl/unx/generic/gdi/salgdi.cxx
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -1186,7 +1186,12 @@ bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTr
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, double fTransparency, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin eLineJoin)
+bool X11SalGraphics::drawPolyLine(
+ const ::basegfx::B2DPolygon& rPolygon,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidth,
+ basegfx::B2DLineJoin eLineJoin,
+ com::sun::star::drawing::LineCap eLineCap)
{
const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2);
@@ -1240,7 +1245,7 @@ bool X11SalGraphics::drawPolyLine(const ::basegfx::B2DPolygon& rPolygon, double
}
// create the area-polygon for the line
- const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin) );
+ const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) );
if( (rLineWidth.getX() != rLineWidth.getY())
&& !basegfx::fTools::equalZero( rLineWidth.getX() ) )
diff --git a/vcl/unx/headless/svpgdi.cxx b/vcl/unx/headless/svpgdi.cxx
index 45cb3214ab7e..c3f4ce549e1e 100644
--- a/vcl/unx/headless/svpgdi.cxx
+++ b/vcl/unx/headless/svpgdi.cxx
@@ -372,7 +372,12 @@ void SvpSalGraphics::drawPolyPolygon( sal_uInt32 nPoly,
dbgOut( m_aDevice );
}
-bool SvpSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon&, double /*fTransparency*/, const ::basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/ )
+bool SvpSalGraphics::drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double /*fTransparency*/,
+ const ::basegfx::B2DVector& /*rLineWidths*/,
+ basegfx::B2DLineJoin /*eJoin*/,
+ com::sun::star::drawing::LineCap /*eLineCap*/)
{
// TODO: implement and advertise OutDevSupport_B2DDraw support
return false;
diff --git a/vcl/unx/headless/svpgdi.hxx b/vcl/unx/headless/svpgdi.hxx
index 93d821ea228a..f36e72aa4c19 100644
--- a/vcl/unx/headless/svpgdi.hxx
+++ b/vcl/unx/headless/svpgdi.hxx
@@ -115,7 +115,12 @@ public:
virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap);
virtual void drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry );
virtual void drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry );
virtual void drawPolyPolygon( sal_uInt32 nPoly,
diff --git a/vcl/unx/headless/svppspgraphics.cxx b/vcl/unx/headless/svppspgraphics.cxx
index 93c22878f775..281f8c57b53a 100644
--- a/vcl/unx/headless/svppspgraphics.cxx
+++ b/vcl/unx/headless/svppspgraphics.cxx
@@ -320,7 +320,12 @@ void PspGraphics::drawPolyPolygon( sal_uInt32 nPoly,
m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, (const Point**)pPtAry);
}
-bool PspGraphics::drawPolyLine( const ::basegfx::B2DPolygon&, double /*fTransparency*/, const ::basegfx::B2DVector& /*rLineWidths*/, basegfx::B2DLineJoin /*eJoin*/ )
+bool PspGraphics::drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double /*fTransparency*/,
+ const ::basegfx::B2DVector& /*rLineWidths*/,
+ basegfx::B2DLineJoin /*eJoin*/,
+ com::sun::star::drawing::LineCap /*eLineCap*/)
{
// TODO: implement and advertise OutDevSupport_B2DDraw support
return false;
diff --git a/vcl/unx/headless/svppspgraphics.hxx b/vcl/unx/headless/svppspgraphics.hxx
index ba2ff841eee6..f8a4d182f369 100644
--- a/vcl/unx/headless/svppspgraphics.hxx
+++ b/vcl/unx/headless/svppspgraphics.hxx
@@ -136,7 +136,12 @@ public:
virtual void drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry );
virtual void drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry );
virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
- virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap);
virtual void drawPolyPolygon( sal_uInt32 nPoly,
const sal_uInt32* pPoints,
PCONSTSALPOINT* pPtAry );
diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx
index f8430d25bc5d..6fc73b86d02c 100644
--- a/vcl/win/source/gdi/salgdi_gdiplus.cxx
+++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx
@@ -187,7 +187,12 @@ bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly
return true;
}
-bool WinSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin )
+bool WinSalGraphics::drawPolyLine(
+ const basegfx::B2DPolygon& rPolygon,
+ double fTransparency,
+ const basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin eLineJoin,
+ com::sun::star::drawing::LineCap eLineCap)
{
const sal_uInt32 nCount(rPolygon.count());
@@ -230,6 +235,27 @@ bool WinSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double f
}
}
+ switch(eLineCap)
+ {
+ default: /*com::sun::star::drawing::LineCap_BUTT*/
+ {
+ // nothing to do
+ break;
+ }
+ case com::sun::star::drawing::LineCap_ROUND:
+ {
+ aTestPen.SetStartCap(Gdiplus::LineCapRound);
+ aTestPen.SetEndCap(Gdiplus::LineCapRound);
+ break;
+ }
+ case com::sun::star::drawing::LineCap_SQUARE:
+ {
+ aTestPen.SetStartCap(Gdiplus::LineCapSquare);
+ aTestPen.SetEndCap(Gdiplus::LineCapSquare);
+ break;
+ }
+ }
+
if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5))
{
impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin);
diff --git a/xmloff/inc/xmloff/xmltoken.hxx b/xmloff/inc/xmloff/xmltoken.hxx
index d13b6cef4cd0..e8e1b8a27ff9 100644
--- a/xmloff/inc/xmloff/xmltoken.hxx
+++ b/xmloff/inc/xmloff/xmltoken.hxx
@@ -340,6 +340,7 @@ namespace xmloff { namespace token {
XML_BUBBLE,
XML_BULLET_CHAR,
XML_BULLET_RELATIVE_SIZE,
+ XML_BUTT,
XML_BUTTON1,
XML_BUTTON2,
XML_BUTTON3,
@@ -1681,6 +1682,7 @@ namespace xmloff { namespace token {
XML_STROKE,
XML_STROKE_COLOR,
XML_STROKE_DASH,
+ XML_STROKE_LINECAP,
XML_STROKE_LINEJOIN,
XML_STROKE_OPACITY,
XML_STROKE_WIDTH,
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index bdf0649cfad2..17f62003397a 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -348,6 +348,7 @@ namespace xmloff { namespace token {
TOKEN( "bubble", XML_BUBBLE ),
TOKEN( "bullet-char", XML_BULLET_CHAR ),
TOKEN( "bullet-relative-size", XML_BULLET_RELATIVE_SIZE ),
+ TOKEN( "butt", XML_BUTT ),
TOKEN( "button1", XML_BUTTON1 ),
TOKEN( "button2", XML_BUTTON2 ),
TOKEN( "button3", XML_BUTTON3 ),
@@ -1689,6 +1690,7 @@ namespace xmloff { namespace token {
TOKEN( "stroke", XML_STROKE ),
TOKEN( "stroke-color", XML_STROKE_COLOR ),
TOKEN( "stroke-dash", XML_STROKE_DASH ),
+ TOKEN( "stroke-linecap", XML_STROKE_LINECAP ),
TOKEN( "stroke-linejoin", XML_STROKE_LINEJOIN ),
TOKEN( "stroke-opacity", XML_STROKE_OPACITY ),
TOKEN( "stroke-width", XML_STROKE_WIDTH ),
diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx
index 415d8ccbefc5..79863c575b5b 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -28,6 +28,7 @@
#include <com/sun/star/container/XIndexReplace.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/LineJoint.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/presentation/AnimationSpeed.hpp>
#include <com/sun/star/presentation/FadeEffect.hpp>
@@ -111,6 +112,7 @@ const XMLPropertyMapEntry aXMLSDProperties[] =
GMAP( "LineEndCenter", XML_NAMESPACE_DRAW, XML_MARKER_END_CENTER, XML_TYPE_BOOL, 0 ),
GMAP( "LineTransparence", XML_NAMESPACE_SVG, XML_STROKE_OPACITY, XML_SD_TYPE_OPACITY, 0 ),
GMAP( "LineJoint", XML_NAMESPACE_DRAW, XML_STROKE_LINEJOIN, XML_SD_TYPE_LINEJOIN, 0 ),
+ GMAP( "LineCap", XML_NAMESPACE_SVG , XML_STROKE_LINECAP, XML_SD_TYPE_LINECAP, 0 ),
// fill attributes
GMAP( "FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SD_TYPE_FILLSTYLE, 0 ),
@@ -392,6 +394,14 @@ SvXMLEnumMapEntry aXML_LineJoint_EnumMap[] =
{ XML_TOKEN_INVALID, 0 }
};
+SvXMLEnumMapEntry aXML_LineCap_EnumMap[] =
+{
+ { XML_BUTT, drawing::LineCap_BUTT },
+ { XML_ROUND, drawing::LineCap_ROUND },
+ { XML_GRADIENTSTYLE_SQUARE, drawing::LineCap_SQUARE }, // use XML_GRADIENTSTYLE_SQUARE as XML_SQUARE, is defined as "square" already
+ { XML_TOKEN_INVALID, 0 }
+};
+
SvXMLEnumMapEntry aXML_FillStyle_EnumMap[] =
{
{ XML_NONE, drawing::FillStyle_NONE },
@@ -887,6 +897,11 @@ const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nTy
pHdl = new XMLEnumPropertyHdl( aXML_LineJoint_EnumMap, ::getCppuType((const drawing::LineJoint*)0) );
break;
}
+ case XML_SD_TYPE_LINECAP :
+ {
+ pHdl = new XMLEnumPropertyHdl( aXML_LineCap_EnumMap, ::getCppuType((const drawing::LineCap*)0) );
+ break;
+ }
case XML_SD_TYPE_FILLSTYLE :
{
pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap, ::getCppuType((const drawing::FillStyle*)0) );
diff --git a/xmloff/source/draw/sdpropls.hxx b/xmloff/source/draw/sdpropls.hxx
index 86113cdc4ac0..b5befc3d1161 100644
--- a/xmloff/source/draw/sdpropls.hxx
+++ b/xmloff/source/draw/sdpropls.hxx
@@ -83,6 +83,7 @@ extern const XMLPropertyMapEntry aXMLSDPresPageProps_onlyHeadersFooter[];
#define XML_SD_TYPE_CONTROL_BORDER (XML_SD_TYPES_START + 32 )
#define XML_SD_TYPE_CONTROL_BORDER_COLOR (XML_SD_TYPES_START + 33 )
#define XML_SD_TYPE_IMAGE_SCALE_MODE (XML_SD_TYPES_START + 34 )
+#define XML_SD_TYPE_LINECAP (XML_SD_TYPES_START + 35 )
// 3D property types
#define XML_SD_TYPE_BACKFACE_CULLING (XML_SD_TYPES_START + 40 )