summaryrefslogtreecommitdiff
path: root/drawinglayer
diff options
context:
space:
mode:
authorBartosz Kosiorek <gang65@poczta.onet.pl>2022-04-24 02:29:59 +0200
committerBartosz Kosiorek <gang65@poczta.onet.pl>2022-05-09 20:50:37 +0200
commit1440ab87386bb5d1ad3634082577bf27f279e066 (patch)
treee1806ad786db4a51cfcc81354393396d7af8c190 /drawinglayer
parent6abc09926c9b55a445b906303f56c6ec7fdeabf9 (diff)
tdf#143875 tdf#55058 EMF+ Add support for individual line endings
EMF+ is allowing different caps and arrows on both ends It is not possible to implement that with css::drawing::LineCap, as it is set line endings on both line start and line end. Additionally when the Dash Pattern is used, the css::drawing::LineCap is also applied there. To resolve that limitation, the Cap needs to be implemented independetly by using PolygonStrokeArrowPrimitive2D, and the css::drawing::LineCap inside drawinglayer::attribute::LineAttribute always set to css::drawing::LineCap_BUTT Change-Id: I4be76e2dbefcb34154a1404c3b57dc4b7f7ada85 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133299 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
Diffstat (limited to 'drawinglayer')
-rw-r--r--drawinglayer/source/tools/emfphelperdata.cxx144
-rw-r--r--drawinglayer/source/tools/emfphelperdata.hxx4
-rw-r--r--drawinglayer/source/tools/emfppen.cxx17
-rw-r--r--drawinglayer/source/tools/emfppen.hxx1
-rw-r--r--drawinglayer/source/tools/primitive2dxmldump.cxx44
5 files changed, 161 insertions, 49 deletions
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx
index c405a4c4876b..c5b282998d71 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -29,6 +29,7 @@
#include "emfpstringformat.hxx"
#include <basegfx/curve/b2dcubicbezier.hxx>
#include <wmfemfhelper.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
@@ -519,7 +520,72 @@ namespace emfplushelper
}
}
- void EmfPlusHelperData::EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex)
+ drawinglayer::attribute::LineStartEndAttribute
+ EmfPlusHelperData::CreateLineEnd(const sal_Int32 aCap, const float aPenWidth) const
+ {
+ const double pw = mdExtractedYScale * aPenWidth;
+ if (aCap == LineCapTypeSquare)
+ {
+ basegfx::B2DPolygon aCapPolygon(
+ { {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} });
+ aCapPolygon.setClosed(true);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ else if (aCap == LineCapTypeRound)
+ {
+ basegfx::B2DPolygon aCapPolygon(
+ { {-1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.9236, -0.3827},
+ {0.7071, -0.7071}, {0.3827, -0.9236}, {0.0, -1.0}, {-0.3827, -0.9236},
+ {-0.7071, -0.7071}, {-0.9236, -0.3827}, {-1.0, 0.0} });
+ aCapPolygon.setClosed(true);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ else if (aCap == LineCapTypeTriangle)
+ {
+ basegfx::B2DPolygon aCapPolygon(
+ { {-1.0, 1.0}, {1.0, 1.0}, {1.0, 0.0}, {0.0, -1.0}, {-1.0, 0.0} });
+ aCapPolygon.setClosed(true);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ else if (aCap == LineCapTypeSquareAnchor)
+ {
+ basegfx::B2DPolygon aCapPolygon(
+ { {-1.0, -1.0}, {1.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} });
+ aCapPolygon.setClosed(true);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ 1.5 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ else if (aCap == LineCapTypeRoundAnchor)
+ {
+ const basegfx::B2DPolygon aCapPolygon
+ = ::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(0.0, 0.0), 1.0, 1.0);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ else if (aCap == LineCapTypeDiamondAnchor)
+ {
+ basegfx::B2DPolygon aCapPolygon({ {0.0, -1.0}, {1.0, 0.0}, {0.5, 0.5},
+ {0.5, 1.0}, {-0.5, 1.0}, {-0.5, 0.5},
+ {-1.0, 0.0} });
+ aCapPolygon.setClosed(true);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ else if (aCap == LineCapTypeArrowAnchor)
+ {
+ basegfx::B2DPolygon aCapPolygon({ {0.0, -1.0}, {1.0, 1.0}, {-1.0, 1.0} });
+ aCapPolygon.setClosed(true);
+ return drawinglayer::attribute::LineStartEndAttribute(
+ 2.0 * pw, basegfx::B2DPolyPolygon(aCapPolygon), true);
+ }
+ return drawinglayer::attribute::LineStartEndAttribute();
+ }
+
+ void EmfPlusHelperData::EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon,
+ sal_uInt32 penIndex)
{
const EMFPPen* pen = dynamic_cast<EMFPPen*>(maEMFPObjects[penIndex & 0xff].get());
SAL_WARN_IF(!pen, "drawinglayer.emf", "emf+ missing pen");
@@ -527,40 +593,56 @@ namespace emfplushelper
if (!(pen && polygon.count()))
return;
- // we need a line cap attribute
- css::drawing::LineCap lineCap = css::drawing::LineCap_BUTT;
- if (pen->penDataFlags & EmfPlusPenDataStartCap) // additional line cap information
- {
- lineCap = static_cast<css::drawing::LineCap>(EMFPPen::lcl_convertStrokeCap(pen->startCap));
- SAL_WARN_IF(pen->startCap != pen->endCap, "drawinglayer.emf", "emf+ pen uses different start and end cap");
- }
-
const double transformedPenWidth = mdExtractedYScale * pen->penWidth;
- drawinglayer::attribute::LineAttribute lineAttribute(pen->GetColor().getBColor(),
- transformedPenWidth,
- pen->GetLineJoinType(),
- lineCap,
- basegfx::deg2rad(15.0)); // TODO Add MiterLimit support
- if (!pen->GetColor().IsTransparent())
+ drawinglayer::attribute::LineAttribute lineAttribute(
+ pen->GetColor().getBColor(), transformedPenWidth, pen->GetLineJoinType(),
+ css::drawing::LineCap_BUTT,
+ basegfx::deg2rad(15.0)); // TODO Add MiterLimit support
+
+ drawinglayer::attribute::LineStartEndAttribute aStart;
+ if (pen->penDataFlags & EmfPlusPenDataStartCap)
+ aStart = EmfPlusHelperData::CreateLineEnd(pen->startCap, pen->penWidth);
+
+ drawinglayer::attribute::LineStartEndAttribute aEnd;
+ if (pen->penDataFlags & EmfPlusPenDataEndCap)
+ aEnd = EmfPlusHelperData::CreateLineEnd(pen->endCap, pen->penWidth);
+
+ if (pen->GetColor().IsTransparent())
{
+ drawinglayer::primitive2d::Primitive2DContainer aContainer;
+ if ((pen->penDataFlags & EmfPlusPenDataStartCap)
+ || (pen->penDataFlags & EmfPlusPenDataEndCap))
+ {
+ aContainer.resize(polygon.count());
+ for (sal_uInt32 i = 0; i < polygon.count(); i++)
+ aContainer[i] = drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D(
+ polygon.getB2DPolygon(i), lineAttribute,
+ pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd));
+ }
+ else
+ aContainer.append(drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale))));
mrTargetHolders.Current().append(
- new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
- polygon,
- lineAttribute,
- pen->GetStrokeAttribute(mdExtractedXScale)));
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ std::move(aContainer), (255 - pen->GetColor().GetAlpha()) / 255.0));
}
else
{
- const drawinglayer::primitive2d::Primitive2DReference aPrimitive(
- new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
- polygon,
- lineAttribute,
- pen->GetStrokeAttribute(mdExtractedXScale)));
-
- mrTargetHolders.Current().append(
- new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
- drawinglayer::primitive2d::Primitive2DContainer { aPrimitive },
- (255 - pen->GetColor().GetAlpha()) / 255.0));
+ if ((pen->penDataFlags & EmfPlusPenDataStartCap)
+ || (pen->penDataFlags & EmfPlusPenDataEndCap))
+ for (sal_uInt32 i = 0; i < polygon.count(); i++)
+ {
+ mrTargetHolders.Current().append(
+ new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D(
+ polygon.getB2DPolygon(i), lineAttribute,
+ pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd));
+ }
+ else
+ mrTargetHolders.Current().append(
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale)));
}
if ((pen->penDataFlags & EmfPlusPenDataCustomStartCap) && (pen->customStartCap->polygon.begin()->count() > 1))
@@ -604,7 +686,7 @@ namespace emfplushelper
new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
startCapPolygon,
lineAttribute,
- pen->GetStrokeAttribute(maMapTransform.get(1, 1))));
+ pen->GetStrokeAttribute(mdExtractedXScale)));
}
}
@@ -649,7 +731,7 @@ namespace emfplushelper
new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
endCapPolygon,
lineAttribute,
- pen->GetStrokeAttribute(maMapTransform.get(1, 1))));
+ pen->GetStrokeAttribute(mdExtractedXScale)));
}
}
diff --git a/drawinglayer/source/tools/emfphelperdata.hxx b/drawinglayer/source/tools/emfphelperdata.hxx
index 600f666145af..796cbff03387 100644
--- a/drawinglayer/source/tools/emfphelperdata.hxx
+++ b/drawinglayer/source/tools/emfphelperdata.hxx
@@ -21,6 +21,7 @@
#include <wmfemfhelper.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <drawinglayer/attribute/linestartendattribute.hxx>
#include <tools/stream.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <map>
@@ -232,6 +233,9 @@ namespace emfplushelper
void GraphicStatePush(GraphicStateMap& map, sal_Int32 index);
void GraphicStatePop(GraphicStateMap& map, sal_Int32 index);
+ drawinglayer::attribute::LineStartEndAttribute CreateLineEnd(const sal_Int32 aCap,
+ const float aPenWidth) const;
+
// primitive creators
void EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex);
void EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, const bool isColor, const sal_uInt32 brushIndexOrColor);
diff --git a/drawinglayer/source/tools/emfppen.cxx b/drawinglayer/source/tools/emfppen.cxx
index b927ac186174..b0408f8d0e80 100644
--- a/drawinglayer/source/tools/emfppen.cxx
+++ b/drawinglayer/source/tools/emfppen.cxx
@@ -173,23 +173,6 @@ namespace emfplushelper
return "";
}
- /// Convert stroke caps between EMF+ and rendering API
- sal_Int8 EMFPPen::lcl_convertStrokeCap(sal_uInt32 nEmfStroke)
- {
- switch (nEmfStroke)
- {
- case EmfPlusLineCapTypeSquare:
- return rendering::PathCapType::SQUARE;
- // we have no mapping for EmfPlusLineCapTypeTriangle,
- // but it is similar to Round
- case EmfPlusLineCapTypeTriangle: // fall-through
- case EmfPlusLineCapTypeRound:
- return rendering::PathCapType::ROUND;
- }
-
- return rendering::PathCapType::BUTT;
- }
-
basegfx::B2DLineJoin EMFPPen::GetLineJoinType() const
{
if (penDataFlags & EmfPlusPenDataJoin) // additional line join information
diff --git a/drawinglayer/source/tools/emfppen.hxx b/drawinglayer/source/tools/emfppen.hxx
index a22ae14fc247..cad849e4f278 100644
--- a/drawinglayer/source/tools/emfppen.hxx
+++ b/drawinglayer/source/tools/emfppen.hxx
@@ -123,7 +123,6 @@ namespace emfplushelper
void Read(SvStream& s, EmfPlusHelperData const & rR);
- static sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke);
drawinglayer::attribute::StrokeAttribute GetStrokeAttribute(const double aTransformation) const;
basegfx::B2DLineJoin GetLineJoinType() const;
};
diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx
index 3074ad30690a..886ffbf7fdd3 100644
--- a/drawinglayer/source/tools/primitive2dxmldump.cxx
+++ b/drawinglayer/source/tools/primitive2dxmldump.cxx
@@ -23,6 +23,7 @@
#include <drawinglayer/primitive2d/Tools.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
@@ -722,6 +723,49 @@ void Primitive2dXmlDump::decomposeAndWrite(
rWriter.endElement();
}
break;
+
+ case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D:
+ {
+ const PolygonStrokeArrowPrimitive2D& rPolygonStrokeArrowPrimitive2D
+ = dynamic_cast<const PolygonStrokeArrowPrimitive2D&>(*pBasePrimitive);
+ rWriter.startElement("polygonstrokearrow");
+
+ rWriter.startElement("polygon");
+ rWriter.content(basegfx::utils::exportToSvgPoints(
+ rPolygonStrokeArrowPrimitive2D.getB2DPolygon()));
+ rWriter.endElement();
+
+ if (rPolygonStrokeArrowPrimitive2D.getStart().getB2DPolyPolygon().count())
+ {
+ rWriter.startElement("linestartattribute");
+ rWriter.attribute("width",
+ rPolygonStrokeArrowPrimitive2D.getStart().getWidth());
+ rWriter.attribute("centered",
+ static_cast<sal_Int32>(
+ rPolygonStrokeArrowPrimitive2D.getStart().isCentered()));
+ writePolyPolygon(rWriter,
+ rPolygonStrokeArrowPrimitive2D.getStart().getB2DPolyPolygon());
+ rWriter.endElement();
+ }
+
+ if (rPolygonStrokeArrowPrimitive2D.getEnd().getB2DPolyPolygon().count())
+ {
+ rWriter.startElement("lineendattribute");
+ rWriter.attribute("width", rPolygonStrokeArrowPrimitive2D.getEnd().getWidth());
+ rWriter.attribute("centered",
+ static_cast<sal_Int32>(
+ rPolygonStrokeArrowPrimitive2D.getEnd().isCentered()));
+ writePolyPolygon(rWriter,
+ rPolygonStrokeArrowPrimitive2D.getEnd().getB2DPolyPolygon());
+ rWriter.endElement();
+ }
+
+ writeLineAttribute(rWriter, rPolygonStrokeArrowPrimitive2D.getLineAttribute());
+ writeStrokeAttribute(rWriter, rPolygonStrokeArrowPrimitive2D.getStrokeAttribute());
+ rWriter.endElement();
+ }
+ break;
+
case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
{
const PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D