diff options
Diffstat (limited to 'drawinglayer/source/tools/emfppen.cxx')
-rw-r--r-- | drawinglayer/source/tools/emfppen.cxx | 299 |
1 files changed, 146 insertions, 153 deletions
diff --git a/drawinglayer/source/tools/emfppen.cxx b/drawinglayer/source/tools/emfppen.cxx index c5e7d457be61..aaa944660110 100644 --- a/drawinglayer/source/tools/emfppen.cxx +++ b/drawinglayer/source/tools/emfppen.cxx @@ -18,9 +18,9 @@ */ #include <com/sun/star/rendering/PathCapType.hpp> -#include <com/sun/star/rendering/PathJoinType.hpp> #include <o3tl/safeint.hxx> #include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> #include "emfppen.hxx" #include "emfpcustomlinecap.hxx" @@ -30,36 +30,15 @@ using namespace ::basegfx; namespace emfplushelper { - namespace { - - enum EmfPlusPenData - { - PenDataTransform = 0x00000001, - PenDataStartCap = 0x00000002, - PenDataEndCap = 0x00000004, - PenDataJoin = 0x00000008, - PenDataMiterLimit = 0x00000010, - PenDataLineStyle = 0x00000020, - PenDataDashedLineCap = 0x00000040, - PenDataDashedLineOffset = 0x00000080, - PenDataDashedLine = 0x00000100, - PenDataAlignment = 0x00000200, - PenDataCompoundLine = 0x00000400, - PenDataCustomStartCap = 0x00000800, - PenDataCustomEndCap = 0x00001000 - }; - - } EMFPPen::EMFPPen() - : EMFPBrush() - , penDataFlags(0) + : penDataFlags(0) , penUnit(0) , penWidth(0.0) , startCap(0) , endCap(0) - , lineJoin(0) - , miterLimit(0.0) + , maLineJoin(basegfx::B2DLineJoin::Miter) + , fMiterMinimumAngle(basegfx::deg2rad(5.0)) , dashStyle(0) , dashCap(0) , dashOffset(0.0) @@ -75,143 +54,142 @@ namespace emfplushelper static OUString PenDataFlagsToString(sal_uInt32 flags) { - OUString sFlags; + rtl::OUStringBuffer sFlags; if (flags & EmfPlusPenDataTransform) - sFlags = "\nEMF+\t\t\tEmfPlusPenDataTransform"; + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataTransform"); if (flags & EmfPlusPenDataStartCap) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataStartCap"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataStartCap"); if (flags & EmfPlusPenDataEndCap) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataEndCap"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataEndCap"); if (flags & EmfPlusPenDataJoin) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataJoin"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataJoin"); if (flags & EmfPlusPenDataMiterLimit) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataMiterLimit"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataMiterLimit"); if (flags & EmfPlusPenDataLineStyle) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataLineStyle"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataLineStyle"); if (flags & EmfPlusPenDataDashedLineCap) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataDashedLineCap"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLineCap"); if (flags & EmfPlusPenDataDashedLineOffset) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataDashedLineOffset"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLineOffset"); if (flags & EmfPlusPenDataDashedLine) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataDashedLine"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataDashedLine"); if (flags & EmfPlusPenDataAlignment) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataAlignment"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataAlignment"); if (flags & EmfPlusPenDataCompoundLine) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataCompoundLine"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCompoundLine"); if (flags & EmfPlusPenDataCustomStartCap) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataCustomStartCap"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCustomStartCap"); if (flags & EmfPlusPenDataCustomEndCap) - sFlags = sFlags.concat("\nEMF+\t\t\tEmfPlusPenDataCustomEndCap"); + sFlags.append("\nEMF+\t\t\tEmfPlusPenDataCustomEndCap"); - return sFlags; + return sFlags.makeStringAndClear(); } static OUString LineCapTypeToString(sal_uInt32 linecap) { switch (linecap) { - case LineCapTypeFlat: return "LineCapTypeFlat"; - case LineCapTypeSquare: return "LineCapTypeSquare"; - case LineCapTypeRound: return "LineCapTypeRound"; - case LineCapTypeTriangle: return "LineCapTypeTriangle"; - case LineCapTypeNoAnchor: return "LineCapTypeNoAnchor"; - case LineCapTypeSquareAnchor: return "LineCapTypeSquareAnchor"; - case LineCapTypeRoundAnchor: return "LineCapTypeRoundAchor"; - case LineCapTypeDiamondAnchor: return "LineCapTypeDiamondAnchor"; - case LineCapTypeArrowAnchor: return "LineCapTypeArrowAnchor"; - case LineCapTypeAnchorMask: return "LineCapTypeAnchorMask"; - case LineCapTypeCustom: return "LineCapTypeCustom"; - } - return ""; - } - - static OUString LineJoinTypeToString(sal_uInt32 jointype) - { - switch (jointype) - { - case LineJoinTypeMiter: return "LineJoinTypeMiter"; - case LineJoinTypeBevel: return "LineJoinTypeBevel"; - case LineJoinTypeRound: return "LineJoinTypeRound"; - case LineJoinTypeMiterClipped: return "LineJoinTypeMiterClipped"; + case LineCapTypeFlat: return u"LineCapTypeFlat"_ustr; + case LineCapTypeSquare: return u"LineCapTypeSquare"_ustr; + case LineCapTypeRound: return u"LineCapTypeRound"_ustr; + case LineCapTypeTriangle: return u"LineCapTypeTriangle"_ustr; + case LineCapTypeNoAnchor: return u"LineCapTypeNoAnchor"_ustr; + case LineCapTypeSquareAnchor: return u"LineCapTypeSquareAnchor"_ustr; + case LineCapTypeRoundAnchor: return u"LineCapTypeRoundAchor"_ustr; + case LineCapTypeDiamondAnchor: return u"LineCapTypeDiamondAnchor"_ustr; + case LineCapTypeArrowAnchor: return u"LineCapTypeArrowAnchor"_ustr; + case LineCapTypeAnchorMask: return u"LineCapTypeAnchorMask"_ustr; + case LineCapTypeCustom: return u"LineCapTypeCustom"_ustr; } - return ""; + return u""_ustr; } static OUString DashedLineCapTypeToString(sal_uInt32 dashedlinecaptype) { switch (dashedlinecaptype) { - case DashedLineCapTypeFlat: return "DashedLineCapTypeFlat"; - case DashedLineCapTypeRound: return "DashedLineCapTypeRound"; - case DashedLineCapTypeTriangle: return "DashedLineCapTypeTriangle"; + case DashedLineCapTypeFlat: return u"DashedLineCapTypeFlat"_ustr; + case DashedLineCapTypeRound: return u"DashedLineCapTypeRound"_ustr; + case DashedLineCapTypeTriangle: return u"DashedLineCapTypeTriangle"_ustr; } - return ""; + return u""_ustr; } static OUString PenAlignmentToString(sal_uInt32 alignment) { switch (alignment) { - case PenAlignmentCenter: return "PenAlignmentCenter"; - case PenAlignmentInset: return "PenAlignmentInset"; - case PenAlignmentLeft: return "PenAlignmentLeft"; - case PenAlignmentOutset: return "PenAlignmentOutset"; - case PenAlignmentRight: return "PenAlignmentRight"; + case PenAlignmentCenter: return u"PenAlignmentCenter"_ustr; + case PenAlignmentInset: return u"PenAlignmentInset"_ustr; + case PenAlignmentLeft: return u"PenAlignmentLeft"_ustr; + case PenAlignmentOutset: return u"PenAlignmentOutset"_ustr; + case PenAlignmentRight: return u"PenAlignmentRight"_ustr; } - return ""; + return u""_ustr; } - /// Convert stroke caps between EMF+ and rendering API - sal_Int8 EMFPPen::lcl_convertStrokeCap(sal_uInt32 nEmfStroke) + drawinglayer::attribute::StrokeAttribute + EMFPPen::GetStrokeAttribute(const double aTransformation) const { - switch (nEmfStroke) + if (penDataFlags & EmfPlusPenDataLineStyle // pen has a predefined line style + && dashStyle != EmfPlusLineStyleCustom) { - case EmfPlusLineCapTypeSquare: return rendering::PathCapType::SQUARE; - case EmfPlusLineCapTypeRound: return rendering::PathCapType::ROUND; + const double pw = aTransformation * penWidth; + switch (dashStyle) + { + case EmfPlusLineStyleDash: + // [-loplugin:redundantfcast] false positive: + return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw }); + case EmfPlusLineStyleDot: + // [-loplugin:redundantfcast] false positive: + return drawinglayer::attribute::StrokeAttribute({ pw, pw }); + case EmfPlusLineStyleDashDot: + // [-loplugin:redundantfcast] false positive: + return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw, pw, pw }); + case EmfPlusLineStyleDashDotDot: + // [-loplugin:redundantfcast] false positive: + return drawinglayer::attribute::StrokeAttribute({ 3 * pw, pw, pw, pw, pw, pw }); + } } - - // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003, - // so return BUTT always - return rendering::PathCapType::BUTT; - } - - sal_Int8 EMFPPen::lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin) - { - switch (nEmfLineJoin) + else if (penDataFlags & EmfPlusPenDataDashedLine) // pen has a custom dash line { - case EmfPlusLineJoinTypeMiter: // fall-through - case EmfPlusLineJoinTypeMiterClipped: return rendering::PathJoinType::MITER; - case EmfPlusLineJoinTypeBevel: return rendering::PathJoinType::BEVEL; - case EmfPlusLineJoinTypeRound: return rendering::PathJoinType::ROUND; + const double pw = aTransformation * penWidth; + // StrokeAttribute needs a double vector while the pen provides a float vector + std::vector<double> aPattern(dashPattern.size()); + for (size_t i = 0; i < aPattern.size(); i++) + { + // convert from float to double and multiply with the adjusted pen width + aPattern[i] = pw * dashPattern[i]; + } + return drawinglayer::attribute::StrokeAttribute(std::move(aPattern)); } - - assert(false); // Line Join type isn't in specification. - return 0; + // EmfPlusLineStyleSolid: - do nothing special, use default stroke attribute + return drawinglayer::attribute::StrokeAttribute(); } void EMFPPen::Read(SvStream& s, EmfPlusHelperData const & rR) { + sal_Int32 lineJoin = EmfPlusLineJoinTypeMiter; sal_uInt32 graphicsVersion, penType; - int i; s.ReadUInt32(graphicsVersion).ReadUInt32(penType).ReadUInt32(penDataFlags).ReadUInt32(penUnit).ReadFloat(penWidth); - SAL_INFO("drawinglayer", "EMF+\t\tGraphics version: 0x" << std::hex << graphicsVersion); - SAL_INFO("drawinglayer", "EMF+\t\tType: " << penType); - SAL_INFO("drawinglayer", "EMF+\t\tPen data flags: 0x" << penDataFlags << PenDataFlagsToString(penDataFlags)); - SAL_INFO("drawinglayer", "EMF+\t\tUnit: " << UnitTypeToString(penUnit)); - SAL_INFO("drawinglayer", "EMF+\t\tWidth: " << std::dec << penWidth); + SAL_INFO("drawinglayer.emf", "EMF+\t\tGraphics version: 0x" << std::hex << graphicsVersion); + SAL_INFO("drawinglayer.emf", "EMF+\t\tType: " << penType); + SAL_INFO("drawinglayer.emf", "EMF+\t\tPen data flags: 0x" << penDataFlags << PenDataFlagsToString(penDataFlags)); + SAL_INFO("drawinglayer.emf", "EMF+\t\tUnit: " << UnitTypeToString(penUnit)); + SAL_INFO("drawinglayer.emf", "EMF+\t\tWidth: " << std::dec << penWidth); // If a zero width is specified, a minimum value must be used, which is determined by the units if (penWidth == 0.0) @@ -220,138 +198,153 @@ namespace emfplushelper : 0.05f; // 0.05f is taken from old EMF+ implementation (case of Unit == Pixel etc.) } - if (penDataFlags & PenDataTransform) + if (penDataFlags & EmfPlusPenDataTransform) { EmfPlusHelperData::readXForm(s, pen_transformation); - SAL_WARN("drawinglayer", "EMF+\t\t TODO PenDataTransform: " << pen_transformation); + SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataTransform: " << pen_transformation); } - if (penDataFlags & PenDataStartCap) + if (penDataFlags & EmfPlusPenDataStartCap) { s.ReadInt32(startCap); - SAL_INFO("drawinglayer", "EMF+\t\tstartCap: " << LineCapTypeToString(startCap) << " (0x" << std::hex << startCap << ")"); + SAL_INFO("drawinglayer.emf", "EMF+\t\tstartCap: " << LineCapTypeToString(startCap) << " (0x" << std::hex << startCap << ")"); } else { startCap = 0; } - if (penDataFlags & PenDataEndCap) + if (penDataFlags & EmfPlusPenDataEndCap) { s.ReadInt32(endCap); - SAL_INFO("drawinglayer", "EMF+\t\tendCap: " << LineCapTypeToString(endCap) << " (0x" << std::hex << startCap << ")"); + SAL_INFO("drawinglayer.emf", "EMF+\t\tendCap: " << LineCapTypeToString(endCap) << " (0x" << std::hex << startCap << ")"); } else { endCap = 0; } - if (penDataFlags & PenDataJoin) + if (penDataFlags & EmfPlusPenDataJoin) { s.ReadInt32(lineJoin); - SAL_WARN("drawinglayer", "EMF+\t\tTODO PenDataJoin: " << LineJoinTypeToString(lineJoin) << " (0x" << std::hex << lineJoin << ")"); + SAL_INFO("drawinglayer.emf", "EMF+\t\t LineJoin: " << lineJoin); + switch (lineJoin) + { + case EmfPlusLineJoinTypeBevel: + maLineJoin = basegfx::B2DLineJoin::Bevel; + break; + case EmfPlusLineJoinTypeRound: + maLineJoin = basegfx::B2DLineJoin::Round; + break; + case EmfPlusLineJoinTypeMiter: + case EmfPlusLineJoinTypeMiterClipped: + default: // If nothing set, then apply Miter (based on MS Paint) + maLineJoin = basegfx::B2DLineJoin::Miter; + break; + } } else - { - lineJoin = 0; - } + maLineJoin = basegfx::B2DLineJoin::Miter; - if (penDataFlags & PenDataMiterLimit) + if (penDataFlags & EmfPlusPenDataMiterLimit) { + float miterLimit; s.ReadFloat(miterLimit); - SAL_WARN("drawinglayer", "EMF+\t\tTODO PenDataMiterLimit: " << std::dec << miterLimit); + + // EMF+ JoinTypeMiterClipped is working as our B2DLineJoin::Miter + // For EMF+ LineJoinTypeMiter we are simulating it by changing angle + if (lineJoin == EmfPlusLineJoinTypeMiter) + miterLimit = 3.0 * miterLimit; + // asin angle must be in range [-1, 1] + if (abs(miterLimit) > 1.0) + fMiterMinimumAngle = 2.0 * asin(1.0 / miterLimit); + else + // enable miter limit for all angles + fMiterMinimumAngle = basegfx::deg2rad(180.0); + SAL_INFO("drawinglayer.emf", + "EMF+\t\t MiterLimit: " << std::dec << miterLimit + << ", Miter minimum angle (rad): " << fMiterMinimumAngle); } else - { - miterLimit = 0; - } + fMiterMinimumAngle = basegfx::deg2rad(5.0); + - if (penDataFlags & PenDataLineStyle) + if (penDataFlags & EmfPlusPenDataLineStyle) { s.ReadInt32(dashStyle); - SAL_INFO("drawinglayer", "EMF+\t\tdashStyle: " << DashedLineCapTypeToString(dashStyle) << " (0x" << std::hex << dashStyle << ")"); + SAL_INFO("drawinglayer.emf", "EMF+\t\tdashStyle: " << DashedLineCapTypeToString(dashStyle) << " (0x" << std::hex << dashStyle << ")"); } else { dashStyle = 0; } - if (penDataFlags & PenDataDashedLineCap) + if (penDataFlags & EmfPlusPenDataDashedLineCap) { s.ReadInt32(dashCap); - SAL_WARN("drawinglayer", "EMF+\t\t TODO PenDataDashedLineCap: 0x" << std::hex << dashCap); + SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataDashedLineCap: 0x" << std::hex << dashCap); } else { dashCap = 0; } - if (penDataFlags & PenDataDashedLineOffset) + if (penDataFlags & EmfPlusPenDataDashedLineOffset) { s.ReadFloat(dashOffset); - SAL_WARN("drawinglayer", "EMF+\t\t TODO PenDataDashedLineOffset: 0x" << std::hex << dashOffset); + SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO PenDataDashedLineOffset: 0x" << std::hex << dashOffset); } else { dashOffset = 0; } - if (penDataFlags & PenDataDashedLine) + if (penDataFlags & EmfPlusPenDataDashedLine) { dashStyle = EmfPlusLineStyleCustom; - sal_Int32 dashPatternLen; + sal_uInt32 dashPatternLen; - s.ReadInt32(dashPatternLen); - SAL_INFO("drawinglayer", "EMF+\t\t\tdashPatternLen: " << dashPatternLen); - - if (dashPatternLen<0 || o3tl::make_unsigned(dashPatternLen)>SAL_MAX_INT32 / sizeof(float)) - { - dashPatternLen = SAL_MAX_INT32 / sizeof(float); - } + s.ReadUInt32(dashPatternLen); + SAL_INFO("drawinglayer.emf", "EMF+\t\t\tdashPatternLen: " << dashPatternLen); dashPattern.resize( dashPatternLen ); - for (i = 0; i < dashPatternLen; i++) + for (sal_uInt32 i = 0; i < dashPatternLen; i++) { s.ReadFloat(dashPattern[i]); - SAL_INFO("drawinglayer", "EMF+\t\t\t\tdashPattern[" << i << "]: " << dashPattern[i]); + SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tdashPattern[" << i << "]: " << dashPattern[i]); } } - if (penDataFlags & PenDataAlignment) + if (penDataFlags & EmfPlusPenDataAlignment) { s.ReadInt32(alignment); - SAL_WARN("drawinglayer", "EMF+\t\t\tTODO PenDataAlignment: " << PenAlignmentToString(alignment) << " (0x" << std::hex << alignment << ")"); + SAL_WARN("drawinglayer.emf", "EMF+\t\t\tTODO PenDataAlignment: " << PenAlignmentToString(alignment) << " (0x" << std::hex << alignment << ")"); } else { alignment = 0; } - if (penDataFlags & PenDataCompoundLine) + if (penDataFlags & EmfPlusPenDataCompoundLine) { - SAL_WARN("drawinglayer", "EMF+\t\t\tTODO PenDataCompoundLine"); - sal_Int32 compoundArrayLen; - s.ReadInt32(compoundArrayLen); - - if (compoundArrayLen<0 || o3tl::make_unsigned(compoundArrayLen)>SAL_MAX_INT32 / sizeof(float)) - { - compoundArrayLen = SAL_MAX_INT32 / sizeof(float); - } + SAL_WARN("drawinglayer.emf", "EMF+\t\t\tTODO PenDataCompoundLine"); + sal_uInt32 compoundArrayLen; + s.ReadUInt32(compoundArrayLen); compoundArray.resize(compoundArrayLen); - for (i = 0; i < compoundArrayLen; i++) + for (sal_uInt32 i = 0; i < compoundArrayLen; i++) { s.ReadFloat(compoundArray[i]); - SAL_INFO("drawinglayer", "EMF+\t\t\t\tcompoundArray[" << i << "]: " << compoundArray[i]); + SAL_INFO("drawinglayer.emf", "EMF+\t\t\t\tcompoundArray[" << i << "]: " << compoundArray[i]); } } - if (penDataFlags & PenDataCustomStartCap) + if (penDataFlags & EmfPlusPenDataCustomStartCap) { - s.ReadInt32(customStartCapLen); - SAL_INFO("drawinglayer", "EMF+\t\t\tcustomStartCapLen: " << customStartCapLen); + s.ReadUInt32(customStartCapLen); + SAL_INFO("drawinglayer.emf", "EMF+\t\t\tcustomStartCapLen: " << customStartCapLen); sal_uInt64 const pos = s.Tell(); customStartCap.reset( new EMFPCustomLineCap() ); @@ -365,10 +358,10 @@ namespace emfplushelper customStartCapLen = 0; } - if (penDataFlags & PenDataCustomEndCap) + if (penDataFlags & EmfPlusPenDataCustomEndCap) { - s.ReadInt32(customEndCapLen); - SAL_INFO("drawinglayer", "EMF+\t\t\tcustomEndCapLen: " << customEndCapLen); + s.ReadUInt32(customEndCapLen); + SAL_INFO("drawinglayer.emf", "EMF+\t\t\tcustomEndCapLen: " << customEndCapLen); sal_uInt64 const pos = s.Tell(); customEndCap.reset( new EMFPCustomLineCap() ); |