diff options
Diffstat (limited to 'drawinglayer/source/tools/emfphelperdata.cxx')
-rw-r--r-- | drawinglayer/source/tools/emfphelperdata.cxx | 729 |
1 files changed, 390 insertions, 339 deletions
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index d2d082424493..1d95f0a8f38a 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> @@ -79,6 +80,9 @@ namespace emfplushelper case EmfPlusRecordTypeDrawRects: return "EmfPlusRecordTypeDrawRects"; case EmfPlusRecordTypeFillPolygon: return "EmfPlusRecordTypeFillPolygon"; case EmfPlusRecordTypeDrawLines: return "EmfPlusRecordTypeDrawLines"; + case EmfPlusRecordTypeFillClosedCurve: return "EmfPlusRecordTypeFillClosedCurve"; + case EmfPlusRecordTypeDrawClosedCurve: return "EmfPlusRecordTypeDrawClosedCurve"; + case EmfPlusRecordTypeDrawCurve: return "EmfPlusRecordTypeDrawCurve"; case EmfPlusRecordTypeFillEllipse: return "EmfPlusRecordTypeFillEllipse"; case EmfPlusRecordTypeDrawEllipse: return "EmfPlusRecordTypeDrawEllipse"; case EmfPlusRecordTypeFillPie: return "EmfPlusRecordTypeFillPie"; @@ -225,33 +229,33 @@ namespace emfplushelper { } - float EmfPlusHelperData::getUnitToPixelMultiplier(const UnitType aUnitType, const sal_uInt32 aDPI) + double EmfPlusHelperData::unitToPixel(double n, sal_uInt32 aUnitType, Direction d) { - switch (aUnitType) + switch (static_cast<UnitType>(aUnitType)) { case UnitTypePixel: - return 1.0f; + return n; case UnitTypePoint: - return aDPI / 72.0; + return o3tl::convert(n, o3tl::Length::pt, o3tl::Length::in) * DPI(d); case UnitTypeInch: - return aDPI; + return n * DPI(d); case UnitTypeMillimeter: - return aDPI / 25.4; + return o3tl::convert(n, o3tl::Length::mm, o3tl::Length::in) * DPI(d); case UnitTypeDocument: - return aDPI / 300.0; + return n * DPI(d) / 300.0; case UnitTypeWorld: case UnitTypeDisplay: SAL_WARN("drawinglayer.emf", "EMF+\t Converting to World/Display."); - return 1.0f; + return n; default: SAL_WARN("drawinglayer.emf", "EMF+\tTODO Unimplemented support of Unit Type: 0x" << std::hex << aUnitType); - return 1.0f; + return n; } } @@ -277,7 +281,7 @@ namespace emfplushelper EMFPPen *pen = new EMFPPen(); maEMFPObjects[index].reset(pen); pen->Read(rObjectStream, *this); - pen->penWidth = pen->penWidth * getUnitToPixelMultiplier(static_cast<UnitType>(pen->penUnit), mnHDPI); + pen->penWidth = unitToPixel(pen->penWidth, pen->penUnit, Direction::horizontal); break; } case EmfPlusObjectTypePath: @@ -321,7 +325,7 @@ namespace emfplushelper font->fontFlags = 0; font->Read(rObjectStream); // tdf#113624 Convert unit to Pixels - font->emSize = font->emSize * getUnitToPixelMultiplier(static_cast<UnitType>(font->sizeUnit), mnHDPI); + font->emSize = unitToPixel(font->emSize, font->sizeUnit, Direction::horizontal); break; } @@ -442,6 +446,10 @@ namespace emfplushelper maMapTransform *= basegfx::utils::createScaleTranslateB2DHomMatrix(100.0 * mnMmX / mnPixX, 100.0 * mnMmY / mnPixY, double(-mnFrameLeft), double(-mnFrameTop)); maMapTransform *= maBaseTransform; + + // Used only for performance optimization, to do not calculate it every line draw + mdExtractedXScale = std::hypot(maMapTransform.a(), maMapTransform.b()); + mdExtractedYScale = std::hypot(maMapTransform.c(), maMapTransform.d()); } ::basegfx::B2DPoint EmfPlusHelperData::Map(double ix, double iy) const @@ -459,7 +467,7 @@ namespace emfplushelper } else // we use a brush { - const EMFPBrush* brush = static_cast<EMFPBrush*>(maEMFPObjects[brushIndexOrColor & 0xff].get()); + const EMFPBrush* brush = dynamic_cast<EMFPBrush*>(maEMFPObjects[brushIndexOrColor & 0xff].get()); if (brush) { color = brush->GetColor(); @@ -486,203 +494,175 @@ namespace emfplushelper map[ index ] = state; } - void EmfPlusHelperData::GraphicStatePop(GraphicStateMap& map, sal_Int32 index, wmfemfhelper::PropertyHolder& rState) + void EmfPlusHelperData::GraphicStatePop(GraphicStateMap& map, sal_Int32 index) { - GraphicStateMap::iterator iter = map.find( index ); + GraphicStateMap::iterator iter = map.find(index); - if ( iter != map.end() ) + if (iter != map.end()) { wmfemfhelper::PropertyHolder state = iter->second; maWorldTransform = state.getTransformation(); - rState.setClipPolyPolygon( state.getClipPolyPolygon() ); + if (state.getClipPolyPolygonActive()) + { + SAL_INFO("drawinglayer.emf", + "EMF+\t Restore clipping region to saved in index: " << index); + wmfemfhelper::HandleNewClipRegion(state.getClipPolyPolygon(), mrTargetHolders, + mrPropertyHolders); + } + else + { + SAL_INFO("drawinglayer.emf", "EMF+\t Disable clipping"); + wmfemfhelper::HandleNewClipRegion(::basegfx::B2DPolyPolygon(), mrTargetHolders, + mrPropertyHolders); + } mappingChanged(); - SAL_INFO("drawinglayer.emf", "EMF+\t\tStack index: " << index << " found, maWorldTransform: " << maWorldTransform); + SAL_INFO("drawinglayer.emf", + "EMF+\t\tStack index: " << index + << " found, maWorldTransform: " << maWorldTransform); } } - void EmfPlusHelperData::EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex) + drawinglayer::attribute::LineStartEndAttribute + EmfPlusHelperData::CreateLineEnd(const sal_Int32 aCap, const float aPenWidth) const { - const EMFPPen* pen = dynamic_cast<EMFPPen*>(maEMFPObjects[penIndex & 0xff].get()); - SAL_WARN_IF(!pen, "drawinglayer.emf", "emf+ missing pen"); - - if (!(pen && polygon.count())) - return; - - // we need a line join attribute - basegfx::B2DLineJoin lineJoin = basegfx::B2DLineJoin::Round; - if (pen->penDataFlags & EmfPlusPenDataJoin) // additional line join information + const double pw = mdExtractedYScale * aPenWidth; + if (aCap == LineCapTypeSquare) { - lineJoin = static_cast<basegfx::B2DLineJoin>(EMFPPen::lcl_convertLineJoinType(pen->lineJoin)); + 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); } - - // we need a line cap attribute - css::drawing::LineCap lineCap = css::drawing::LineCap_BUTT; - if (pen->penDataFlags & EmfPlusPenDataStartCap) // additional line cap information + else if (aCap == LineCapTypeRound) { - 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"); + 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); } - - const double transformedPenWidth = maMapTransform.get(0, 0) * pen->penWidth; - drawinglayer::attribute::LineAttribute lineAttribute(pen->GetColor().getBColor(), - transformedPenWidth, - lineJoin, - lineCap); - - drawinglayer::attribute::StrokeAttribute aStrokeAttribute; - if (pen->penDataFlags & EmfPlusPenDataLineStyle && pen->dashStyle != EmfPlusLineStyleCustom) // pen has a predefined line style + else if (aCap == LineCapTypeTriangle) { - // short writing - const double pw = maMapTransform.get(1, 1) * pen->penWidth; - // taken from the old cppcanvas implementation and multiplied with pen width - const std::vector<double> dash = { 3*pw, 3*pw }; - const std::vector<double> dot = { pw, 3*pw }; - const std::vector<double> dashdot = { 3*pw, 3*pw, pw, 3*pw }; - const std::vector<double> dashdotdot = { 3*pw, 3*pw, pw, 3*pw, pw, 3*pw }; - - switch (pen->dashStyle) - { - case EmfPlusLineStyleSolid: // do nothing special, use default stroke attribute - break; - case EmfPlusLineStyleDash: - aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(std::vector(dash)); - break; - case EmfPlusLineStyleDot: - aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(std::vector(dot)); - break; - case EmfPlusLineStyleDashDot: - aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(std::vector(dashdot)); - break; - case EmfPlusLineStyleDashDotDot: - aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(std::vector(dashdotdot)); - break; - } + 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 (pen->penDataFlags & EmfPlusPenDataDashedLine) // pen has a custom dash line + else if (aCap == LineCapTypeSquareAnchor) { - // StrokeAttribute needs a double vector while the pen provides a float vector - std::vector<double> aPattern(pen->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] = maMapTransform.get(1, 1) * pen->penWidth * pen->dashPattern[i]; - } - aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(std::move(aPattern)); + 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); } - - if (!pen->GetColor().IsTransparent()) + else if (aCap == LineCapTypeRoundAnchor) { - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - polygon, - lineAttribute, - aStrokeAttribute)); + 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 + else if (aCap == LineCapTypeDiamondAnchor) { - const drawinglayer::primitive2d::Primitive2DReference aPrimitive( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - polygon, - lineAttribute, - aStrokeAttribute)); - - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( - drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }, - (255 - pen->GetColor().GetAlpha()) / 255.0)); + 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); } - - if ((pen->penDataFlags & EmfPlusPenDataCustomStartCap) && (pen->customStartCap->polygon.begin()->count() > 1)) + else if (aCap == LineCapTypeArrowAnchor) { - SAL_WARN("drawinglayer.emf", "EMF+\tCustom Start Line Cap"); - ::basegfx::B2DPolyPolygon startCapPolygon(pen->customStartCap->polygon); - - // get the gradient of the first line in the polypolygon - double x1 = polygon.begin()->getB2DPoint(0).getX(); - double y1 = polygon.begin()->getB2DPoint(0).getY(); - double x2 = polygon.begin()->getB2DPoint(1).getX(); - double y2 = polygon.begin()->getB2DPoint(1).getY(); - - if ((x2 - x1) != 0) - { - double gradient = (y2 - y1) / (x2 - x1); - - // now we get the angle that we need to rotate the arrow by - double angle = (M_PI / 2) - atan(gradient); + 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(); + } - // rotate the arrow - startCapPolygon.transform(basegfx::utils::createRotateB2DHomMatrix(angle)); - } + 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"); - startCapPolygon.transform(maMapTransform); + if (!(pen && polygon.count())) + return; - basegfx::B2DHomMatrix tran(pen->penWidth, 0.0, polygon.begin()->getB2DPoint(0).getX(), - 0.0, pen->penWidth, polygon.begin()->getB2DPoint(0).getY()); - startCapPolygon.transform(tran); + const double transformedPenWidth = mdExtractedYScale * pen->penWidth; + drawinglayer::attribute::LineAttribute lineAttribute( + pen->GetColor().getBColor(), transformedPenWidth, pen->maLineJoin, + css::drawing::LineCap_BUTT, //TODO implement PenDataDashedLineCap support here + pen->fMiterMinimumAngle); - if (pen->customStartCap->mbIsFilled) - { - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( - startCapPolygon, - pen->GetColor().getBColor())); - } + drawinglayer::attribute::LineStartEndAttribute aStart; + if (pen->penDataFlags & EmfPlusPenDataStartCap) + { + if ((pen->penDataFlags & EmfPlusPenDataCustomStartCap) + && (pen->customStartCap->polygon.begin()->count() > 1)) + aStart = drawinglayer::attribute::LineStartEndAttribute( + pen->customStartCap->polygon.getB2DRange().getRange().getX() * mdExtractedXScale + * pen->customStartCap->widthScale * pen->penWidth, + pen->customStartCap->polygon, false); else - { - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - startCapPolygon, - lineAttribute, - aStrokeAttribute)); - } + aStart = EmfPlusHelperData::CreateLineEnd(pen->startCap, pen->penWidth); } - if ((pen->penDataFlags & EmfPlusPenDataCustomEndCap) && (pen->customEndCap->polygon.begin()->count() > 1)) + drawinglayer::attribute::LineStartEndAttribute aEnd; + if (pen->penDataFlags & EmfPlusPenDataEndCap) { - SAL_WARN("drawinglayer.emf", "EMF+\tCustom End Line Cap"); - - ::basegfx::B2DPolyPolygon endCapPolygon(pen->customEndCap->polygon); - - // get the gradient of the first line in the polypolygon - double x1 = polygon.begin()->getB2DPoint(polygon.begin()->count() - 1).getX(); - double y1 = polygon.begin()->getB2DPoint(polygon.begin()->count() - 1).getY(); - double x2 = polygon.begin()->getB2DPoint(polygon.begin()->count() - 2).getX(); - double y2 = polygon.begin()->getB2DPoint(polygon.begin()->count() - 2).getY(); + if ((pen->penDataFlags & EmfPlusPenDataCustomEndCap) + && (pen->customEndCap->polygon.begin()->count() > 1)) + aEnd = drawinglayer::attribute::LineStartEndAttribute( + pen->customEndCap->polygon.getB2DRange().getRange().getX() * mdExtractedXScale + * pen->customEndCap->widthScale * pen->penWidth, + pen->customEndCap->polygon, false); + else + aEnd = EmfPlusHelperData::CreateLineEnd(pen->endCap, pen->penWidth); + } - if ((x2 - x1) != 0) + if (pen->GetColor().IsTransparent()) + { + drawinglayer::primitive2d::Primitive2DContainer aContainer; + if (aStart.isDefault() && aEnd.isDefault()) + aContainer.append( + new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale))); + else { - double gradient = (y2 - y1) / (x2 - x1); - - // now we get the angle that we need to rotate the arrow by - double angle = (M_PI / 2) - atan(gradient); - - // rotate the arrow - endCapPolygon.transform(basegfx::utils::createRotateB2DHomMatrix(angle)); + aContainer.resize(polygon.count()); + for (sal_uInt32 i = 0; i < polygon.count(); i++) + aContainer[i] = + new drawinglayer::primitive2d::PolygonStrokeArrowPrimitive2D( + polygon.getB2DPolygon(i), lineAttribute, + pen->GetStrokeAttribute(mdExtractedXScale), aStart, aEnd); } - - endCapPolygon.transform(maMapTransform); - basegfx::B2DHomMatrix tran(pen->penWidth, 0.0, polygon.begin()->getB2DPoint(polygon.begin()->count() - 1).getX(), - 0.0, pen->penWidth, polygon.begin()->getB2DPoint(polygon.begin()->count() - 1).getY()); - endCapPolygon.transform(tran); - - if (pen->customEndCap->mbIsFilled) - { + mrTargetHolders.Current().append( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + std::move(aContainer), (255 - pen->GetColor().GetAlpha()) / 255.0)); + } + else + { + if (aStart.isDefault() && aEnd.isDefault()) mrTargetHolders.Current().append( - new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( - endCapPolygon, - pen->GetColor().getBColor())); - } + new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale))); else - { - mrTargetHolders.Current().append( - new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( - endCapPolygon, - lineAttribute, - aStrokeAttribute)); - } + 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)); + } } - mrPropertyHolders.Current().setLineColor(pen->GetColor().getBColor()); mrPropertyHolders.Current().setLineColorActive(true); mrPropertyHolders.Current().setFillColorActive(false); @@ -735,7 +715,7 @@ namespace emfplushelper } else // use Brush { - EMFPBrush* brush = static_cast<EMFPBrush*>( maEMFPObjects[brushIndexOrColor & 0xff].get() ); + EMFPBrush* brush = dynamic_cast<EMFPBrush*>(maEMFPObjects[brushIndexOrColor & 0xff].get()); SAL_INFO("drawinglayer.emf", "EMF+\t\t Fill polygon, brush slot: " << brushIndexOrColor << " (brush type: " << (brush ? brush->GetType() : -1) << ")"); // give up in case something wrong happened @@ -826,23 +806,14 @@ namespace emfplushelper SAL_INFO("drawinglayer.emf", "EMF+\t\tUse blend"); // store the blendpoints in the vector - for (int i = 0; i < brush->blendPoints; i++) + for (sal_uInt32 i = 0; i < brush->blendPoints; i++) { - double aBlendPoint; + const double aBlendPoint = brush->blendPositions[i]; basegfx::BColor aColor; - if (brush->type == BrushTypeLinearGradient) - { - aBlendPoint = brush->blendPositions [i]; - } - else - { - // seems like SvgRadialGradientPrimitive2D needs doubled, inverted radius - aBlendPoint = 2. * ( 1. - brush->blendPositions [i] ); - } - aColor.setGreen( aStartColor.getGreen() + brush->blendFactors[i] * ( aEndColor.getGreen() - aStartColor.getGreen() ) ); - aColor.setBlue ( aStartColor.getBlue() + brush->blendFactors[i] * ( aEndColor.getBlue() - aStartColor.getBlue() ) ); - aColor.setRed ( aStartColor.getRed() + brush->blendFactors[i] * ( aEndColor.getRed() - aStartColor.getRed() ) ); - const double aAlpha = brush->solidColor.GetAlpha() + brush->blendFactors[i] * ( brush->secondColor.GetAlpha() - brush->solidColor.GetAlpha() ); + aColor.setGreen(aStartColor.getGreen() + brush->blendFactors[i] * (aEndColor.getGreen() - aStartColor.getGreen())); + aColor.setBlue (aStartColor.getBlue() + brush->blendFactors[i] * (aEndColor.getBlue() - aStartColor.getBlue())); + aColor.setRed (aStartColor.getRed() + brush->blendFactors[i] * (aEndColor.getRed() - aStartColor.getRed())); + const double aAlpha = brush->solidColor.GetAlpha() + brush->blendFactors[i] * (brush->secondColor.GetAlpha() - brush->solidColor.GetAlpha()); aVector.emplace_back(aBlendPoint, aColor, aAlpha / 255.0); } } @@ -851,35 +822,17 @@ namespace emfplushelper SAL_INFO("drawinglayer.emf", "EMF+\t\tUse color blend"); // store the colorBlends in the vector - for (int i = 0; i < brush->colorblendPoints; i++) + for (sal_uInt32 i = 0; i < brush->colorblendPoints; i++) { - double aBlendPoint; - basegfx::BColor aColor; - if (brush->type == BrushTypeLinearGradient) - { - aBlendPoint = brush->colorblendPositions [i]; - } - else - { - // seems like SvgRadialGradientPrimitive2D needs doubled, inverted radius - aBlendPoint = 2. * ( 1. - brush->colorblendPositions [i] ); - } - aColor = brush->colorblendColors[i].getBColor(); - aVector.emplace_back(aBlendPoint, aColor, brush->colorblendColors[i].GetAlpha() / 255.0 ); + const double aBlendPoint = brush->colorblendPositions[i]; + const basegfx::BColor aColor = brush->colorblendColors[i].getBColor(); + aVector.emplace_back(aBlendPoint, aColor, brush->colorblendColors[i].GetAlpha() / 255.0); } } else // ok, no extra points: just start and end { - if (brush->type == BrushTypeLinearGradient) - { - aVector.emplace_back(0.0, aStartColor, brush->solidColor.GetAlpha() / 255.0); - aVector.emplace_back(1.0, aEndColor, brush->secondColor.GetAlpha() / 255.0); - } - else // again, here reverse - { - aVector.emplace_back(0.0, aEndColor, brush->secondColor.GetAlpha() / 255.0); - aVector.emplace_back(1.0, aStartColor, brush->solidColor.GetAlpha() / 255.0); - } + aVector.emplace_back(0.0, aStartColor, brush->solidColor.GetAlpha() / 255.0); + aVector.emplace_back(1.0, aEndColor, brush->secondColor.GetAlpha() / 255.0); } // get the polygon range to be able to map the start/end/center point correctly @@ -930,7 +883,7 @@ namespace emfplushelper aSpreadMethod)); } else // BrushTypePathGradient - { + { // TODO The PathGradient is not implemented, and Radial Gradient is used instead basegfx::B2DPoint aCenterPoint = Map(brush->firstPointX, brush->firstPointY); aCenterPoint = aPolygonTransformation * aCenterPoint; @@ -941,9 +894,9 @@ namespace emfplushelper polygon, std::move(aVector), aCenterPoint, - 0.5, // relative radius - true, // use UnitCoordinates to stretch the gradient - drawinglayer::primitive2d::SpreadMethod::Repeat, + 0.7, // relative radius little bigger to cover all elements + true, // use UnitCoordinates to stretch the gradient + drawinglayer::primitive2d::SpreadMethod::Pad, nullptr)); } } @@ -971,6 +924,8 @@ namespace emfplushelper mnMmY(0), mbMultipart(false), mMFlags(0), + mdExtractedXScale(1.0), + mdExtractedYScale(1.0), mrTargetHolders(rTargetHolders), mrPropertyHolders(rPropertyHolders), bIsGetDCProcessing(false) @@ -1000,14 +955,8 @@ namespace emfplushelper } case EmfPlusCombineModeIntersect: { - if (leftPolygon.count()) - { - aClippedPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon( - leftPolygon, - rightPolygon, - true, - false); - } + aClippedPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon( + leftPolygon, rightPolygon, true, false); break; } case EmfPlusCombineModeUnion: @@ -1080,8 +1029,18 @@ namespace emfplushelper if (bIsGetDCProcessing) { - SAL_INFO("drawinglayer.emf", "EMF+\t reset the current clipping region for the world space to infinity."); - wmfemfhelper::HandleNewClipRegion(::basegfx::B2DPolyPolygon(), mrTargetHolders, mrPropertyHolders); + if (aGetDCState.getClipPolyPolygonActive()) + { + SAL_INFO("drawinglayer.emf", "EMF+\t Restore region to GetDC saved"); + wmfemfhelper::HandleNewClipRegion(aGetDCState.getClipPolyPolygon(), mrTargetHolders, + mrPropertyHolders); + } + else + { + SAL_INFO("drawinglayer.emf", "EMF+\t Disable clipping"); + wmfemfhelper::HandleNewClipRegion(::basegfx::B2DPolyPolygon(), mrTargetHolders, + mrPropertyHolders); + } bIsGetDCProcessing = false; } if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) @@ -1117,14 +1076,15 @@ namespace emfplushelper { case EmfPlusRecordTypeHeader: { - sal_uInt32 header, version; + sal_uInt32 version, emfPlusFlags; + SAL_INFO("drawinglayer.emf", "EMF+\tDual: " << ((flags & 1) ? "true" : "false")); - rMS.ReadUInt32(header).ReadUInt32(version).ReadUInt32(mnHDPI).ReadUInt32(mnVDPI); - SAL_INFO("drawinglayer.emf", "EMF+\tHeader: 0x" << std::hex << header); - SAL_INFO("drawinglayer.emf", "EMF+\tVersion: " << std::dec << version); + rMS.ReadUInt32(version).ReadUInt32(emfPlusFlags).ReadUInt32(mnHDPI).ReadUInt32(mnVDPI); + SAL_INFO("drawinglayer.emf", "EMF+\tVersion: 0x" << std::hex << version); + SAL_INFO("drawinglayer.emf", "EMF+\tEmf+ Flags: 0x" << emfPlusFlags << std::dec); + SAL_INFO("drawinglayer.emf", "EMF+\tMetafile was recorded with a reference device context for " << ((emfPlusFlags & 1) ? "video display" : "printer")); SAL_INFO("drawinglayer.emf", "EMF+\tHorizontal DPI: " << mnHDPI); SAL_INFO("drawinglayer.emf", "EMF+\tVertical DPI: " << mnVDPI); - SAL_INFO("drawinglayer.emf", "EMF+\tDual: " << ((flags & 1) ? "true" : "false")); break; } case EmfPlusRecordTypeEndOfFile: @@ -1160,6 +1120,7 @@ namespace emfplushelper case EmfPlusRecordTypeGetDC: { bIsGetDCProcessing = true; + aGetDCState = mrPropertyHolders.Current(); SAL_INFO("drawinglayer.emf", "EMF+\tAlready used in svtools wmf/emf filter parser"); break; } @@ -1257,7 +1218,11 @@ namespace emfplushelper rMS.ReadUInt32(brushIndexOrColor); SAL_INFO("drawinglayer.emf", "EMF+\t FillRegion slot: " << index); - EMFPPlusFillPolygon(static_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get())->regionPolyPolygon, flags & 0x8000, brushIndexOrColor); + EMFPRegion* region = dynamic_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get()); + if (region) + EMFPPlusFillPolygon(region->regionPolyPolygon, flags & 0x8000, brushIndexOrColor); + else + SAL_WARN("drawinglayer.emf", "EMF+\tEmfPlusRecordTypeFillRegion missing region"); } break; case EmfPlusRecordTypeDrawEllipse: @@ -1292,7 +1257,9 @@ namespace emfplushelper { // Silent MSVC warning C4701: potentially uninitialized local variable 'brushIndexOrColor' used sal_uInt32 brushIndexOrColor = 999; - sal_Int32 rectangles; + ::basegfx::B2DPolyPolygon polyPolygon; + sal_uInt32 rectangles; + float x, y, width, height; const bool isColor = (flags & 0x8000); ::basegfx::B2DPolygon polygon; @@ -1307,11 +1274,9 @@ namespace emfplushelper SAL_INFO("drawinglayer.emf", "EMF+\t DrawRects"); } - rMS.ReadInt32(rectangles); - - for (int i = 0; i < rectangles; i++) + rMS.ReadUInt32(rectangles); + for (sal_uInt32 i = 0; i < rectangles; i++) { - float x, y, width, height; ReadRectangle(rMS, x, y, width, height, bool(flags & 0x4000)); polygon.clear(); polygon.append(Map(x, y)); @@ -1321,37 +1286,34 @@ namespace emfplushelper polygon.setClosed(true); SAL_INFO("drawinglayer.emf", "EMF+\t\t rectangle: " << x << ", "<< y << " " << width << "x" << height); - - ::basegfx::B2DPolyPolygon polyPolygon(polygon); - if (type == EmfPlusRecordTypeFillRects) - EMFPPlusFillPolygon(polyPolygon, isColor, brushIndexOrColor); - else - EMFPPlusDrawPolygon(polyPolygon, flags & 0xff); + polyPolygon.append(polygon); } + if (type == EmfPlusRecordTypeFillRects) + EMFPPlusFillPolygon(polyPolygon, isColor, brushIndexOrColor); + else + EMFPPlusDrawPolygon(polyPolygon, flags & 0xff); break; } case EmfPlusRecordTypeFillPolygon: { - const sal_uInt8 index = flags & 0xff; sal_uInt32 brushIndexOrColor, points; rMS.ReadUInt32(brushIndexOrColor); rMS.ReadUInt32(points); - SAL_INFO("drawinglayer.emf", "EMF+\t FillPolygon in slot: " << index << " points: " << points); + SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points); SAL_INFO("drawinglayer.emf", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << " : 0x" << std::hex << brushIndexOrColor << std::dec); EMFPPath path(points, true); path.Read(rMS, flags); EMFPPlusFillPolygon(path.GetPolygon(*this), flags & 0x8000, brushIndexOrColor); - break; } case EmfPlusRecordTypeDrawLines: { sal_uInt32 points; rMS.ReadUInt32(points); - SAL_INFO("drawinglayer.emf", "EMF+\t DrawLines in slot: " << (flags & 0xff) << " points: " << points); + SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points); EMFPPath path(points, true); path.Read(rMS, flags); @@ -1379,46 +1341,98 @@ namespace emfplushelper { sal_uInt32 aCount; float x1, y1, x2, y2, x3, y3, x4, y4; - ::basegfx::B2DPoint aStartPoint, aControlPointA, aControlPointB, aEndPoint; ::basegfx::B2DPolygon aPolygon; rMS.ReadUInt32(aCount); SAL_INFO("drawinglayer.emf", "EMF+\t DrawBeziers slot: " << (flags & 0xff)); SAL_INFO("drawinglayer.emf", "EMF+\t Number of points: " << aCount); - SAL_WARN_IF((aCount - 1) % 3 != 0, "drawinglayer.emf", "EMF+\t Bezier Draw not support number of points other than 4, 7, 10, 13, 16..."); + SAL_WARN_IF((aCount - 1) % 3 != 0, "drawinglayer.emf", + "EMF+\t Bezier Draw not support number of points other than 4, 7, " + "10, 13, 16..."); if (aCount < 4) { - SAL_WARN("drawinglayer.emf", "EMF+\t Bezier Draw does not support less than 4 points. Number of points: " << aCount); + SAL_WARN("drawinglayer.emf", "EMF+\t Bezier Draw does not support less " + "than 4 points. Number of points: " + << aCount); break; } ReadPoint(rMS, x1, y1, flags); // We need to add first starting point - aStartPoint = Map(x1, y1); - aPolygon.append(aStartPoint); - + aPolygon.append(Map(x1, y1)); + SAL_INFO("drawinglayer.emf", + "EMF+\t Bezier starting point: " << x1 << "," << y1); for (sal_uInt32 i = 4; i <= aCount; i += 3) { ReadPoint(rMS, x2, y2, flags); ReadPoint(rMS, x3, y3, flags); ReadPoint(rMS, x4, y4, flags); - SAL_INFO("drawinglayer.emf", "EMF+\t Bezier points: " << x1 << "," << y1 << " " << x2 << "," << y2 << " " << x3 << "," << y3 << " " << x4 << "," << y4); - - aStartPoint = Map(x1, y1); - aControlPointA = Map(x2, y2); - aControlPointB = Map(x3, y3); - aEndPoint = Map(x4, y4); - - ::basegfx::B2DCubicBezier cubicBezier(aStartPoint, aControlPointA, aControlPointB, aEndPoint); - cubicBezier.adaptiveSubdivideByDistance(aPolygon, 10.0); + SAL_INFO("drawinglayer.emf", + "EMF+\t Bezier points: " << x2 << "," << y2 << " " << x3 << "," + << y3 << " " << x4 << "," << y4); + aPolygon.appendBezierSegment(Map(x2, y2), Map(x3, y3), Map(x4, y4)); + } + EMFPPlusDrawPolygon(::basegfx::B2DPolyPolygon(aPolygon), flags & 0xff); + break; + } + case EmfPlusRecordTypeDrawCurve: + { + sal_uInt32 aOffset, aNumSegments, points; + float aTension; + rMS.ReadFloat(aTension); + rMS.ReadUInt32(aOffset); + rMS.ReadUInt32(aNumSegments); + rMS.ReadUInt32(points); + SAL_WARN("drawinglayer.emf", + "EMF+\t Tension: " << aTension << " Offset: " << aOffset + << " NumSegments: " << aNumSegments + << " Points: " << points); - EMFPPlusDrawPolygon(::basegfx::B2DPolyPolygon(aPolygon), flags & 0xff); + EMFPPath path(points, true); + path.Read(rMS, flags); - // The ending coordinate of one Bezier curve is the starting coordinate of the next. - x1 = x4; - y1 = y4; + if (points >= 2) + EMFPPlusDrawPolygon( + path.GetCardinalSpline(*this, aTension, aOffset, aNumSegments), + flags & 0xff); + else + SAL_WARN("drawinglayer.emf", "Not enough number of points"); + break; + } + case EmfPlusRecordTypeDrawClosedCurve: + case EmfPlusRecordTypeFillClosedCurve: + { + // Silent MSVC warning C4701: potentially uninitialized local variable 'brushIndexOrColor' used + sal_uInt32 brushIndexOrColor = 999, points; + float aTension; + if (type == EmfPlusRecordTypeFillClosedCurve) + { + rMS.ReadUInt32(brushIndexOrColor); + SAL_INFO( + "drawinglayer.emf", + "EMF+\t Fill Mode: " << (flags & 0x2000 ? "Winding" : "Alternate")); } + rMS.ReadFloat(aTension); + rMS.ReadUInt32(points); + SAL_WARN("drawinglayer.emf", + "EMF+\t Tension: " << aTension << " Points: " << points); + SAL_INFO("drawinglayer.emf", + "EMF+\t " << (flags & 0x8000 ? "Color" : "Brush index") << " : 0x" + << std::hex << brushIndexOrColor << std::dec); + if (points < 3) + { + SAL_WARN("drawinglayer.emf", "Not enough number of points"); + break; + } + EMFPPath path(points, true); + path.Read(rMS, flags); + if (type == EmfPlusRecordTypeFillClosedCurve) + EMFPPlusFillPolygon(path.GetClosedCardinalSpline(*this, aTension), + flags & 0x8000, brushIndexOrColor); + else + EMFPPlusDrawPolygon(path.GetClosedCardinalSpline(*this, aTension), + flags & 0xff); break; } case EmfPlusRecordTypeDrawImage: @@ -1435,16 +1449,16 @@ namespace emfplushelper SAL_INFO("drawinglayer.emf", "EMF+\t TODO: use image attributes"); // Source unit of measurement type must be 1 pixel - if (sourceUnit == UnitTypePixel && maEMFPObjects[flags & 0xff]) + if (EMFPImage* image = sourceUnit == UnitTypePixel ? + dynamic_cast<EMFPImage*>(maEMFPObjects[flags & 0xff].get()) : + nullptr) { - EMFPImage& image - = *static_cast<EMFPImage*>(maEMFPObjects[flags & 0xff].get()); float sx, sy, sw, sh; ReadRectangle(rMS, sx, sy, sw, sh); ::tools::Rectangle aSource(Point(sx, sy), Size(sw + 1, sh + 1)); SAL_INFO("drawinglayer.emf", - "EMF+\t " + "EMF+\t " << (type == EmfPlusRecordTypeDrawImage ? "DrawImage" : "DrawImagePoints") << " source rectangle: " << sx << "," << sy << " " << sw << "x" @@ -1488,9 +1502,9 @@ namespace emfplushelper SAL_INFO("drawinglayer.emf", "EMF+\t Rectangle: " << dx << "," << dy << " " << dw << "x" << dh); Size aSize; - if (image.type == ImageDataTypeBitmap) + if (image->type == ImageDataTypeBitmap) { - aSize = image.graphic.GetBitmapEx().GetSizePixel(); + aSize = image->graphic.GetBitmapEx().GetSizePixel(); SAL_INFO("drawinglayer.emf", "EMF+\t Bitmap size: " << aSize.Width() << "x" << aSize.Height()); @@ -1522,36 +1536,36 @@ namespace emfplushelper SAL_INFO( "drawinglayer.emf", "EMF+\t TODO: Add support for SrcRect to ImageDataTypeMetafile"); - ::basegfx::B2DPoint aDstPoint(dx, dy); - ::basegfx::B2DSize aDstSize(dw, dh); + const ::basegfx::B2DPoint aDstPoint(dx, dy); + const ::basegfx::B2DSize aDstSize(dw, dh); const basegfx::B2DHomMatrix aTransformMatrix = maMapTransform * basegfx::B2DHomMatrix( - /* Row 0, Column 0 */ aDstSize.getX(), + /* Row 0, Column 0 */ aDstSize.getWidth(), /* Row 0, Column 1 */ fShearX, /* Row 0, Column 2 */ aDstPoint.getX(), /* Row 1, Column 0 */ fShearY, - /* Row 1, Column 1 */ aDstSize.getY(), + /* Row 1, Column 1 */ aDstSize.getHeight(), /* Row 1, Column 2 */ aDstPoint.getY()); - if (image.type == ImageDataTypeBitmap) + if (image->type == ImageDataTypeBitmap) { - BitmapEx aBmp(image.graphic.GetBitmapEx()); + BitmapEx aBmp(image->graphic.GetBitmapEx()); aBmp.Crop(aSource); aSize = aBmp.GetSizePixel(); if (aSize.Width() > 0 && aSize.Height() > 0) { mrTargetHolders.Current().append( new drawinglayer::primitive2d::BitmapPrimitive2D( - VCLUnoHelper::CreateVCLXBitmap(aBmp), aTransformMatrix)); + aBmp, aTransformMatrix)); } else SAL_WARN("drawinglayer.emf", "EMF+\t warning: empty bitmap"); } - else if (image.type == ImageDataTypeMetafile) + else if (image->type == ImageDataTypeMetafile) { - GDIMetaFile aGDI(image.graphic.GetGDIMetaFile()); + GDIMetaFile aGDI(image->graphic.GetGDIMetaFile()); aGDI.Clip(aSource); mrTargetHolders.Current().append( new drawinglayer::primitive2d::MetafilePrimitive2D(aTransformMatrix, @@ -1586,7 +1600,7 @@ namespace emfplushelper // get the stringFormat from the Object table ( this is OPTIONAL and may be nullptr ) const EMFPStringFormat *stringFormat = dynamic_cast<EMFPStringFormat*>(maEMFPObjects[formatId & 0xff].get()); // get the font from the flags - const EMFPFont *font = static_cast< EMFPFont* >( maEMFPObjects[flags & 0xff].get() ); + const EMFPFont *font = dynamic_cast<EMFPFont*>(maEMFPObjects[flags & 0xff].get()); if (!font) { break; @@ -1648,7 +1662,7 @@ namespace emfplushelper } const basegfx::B2DHomMatrix transformMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix( - ::basegfx::B2DSize(font->emSize, font->emSize), + ::basegfx::B2DVector(font->emSize, font->emSize), ::basegfx::B2DPoint(lx + stringAlignmentHorizontalOffset, ly + stringAlignmentVerticalOffset)); @@ -1690,6 +1704,7 @@ namespace emfplushelper 0, // text always starts at 0 stringLength, std::move(emptyVector), // EMF-PLUS has no DX-array + {}, fontAttribute, locale, color.getBColor(), // Font Color @@ -1709,6 +1724,7 @@ namespace emfplushelper 0, // text always starts at 0 stringLength, std::move(emptyVector), // EMF-PLUS has no DX-array + {}, fontAttribute, locale, color.getBColor()); @@ -1739,8 +1755,8 @@ namespace emfplushelper } else { - mnMmX *= mfPageScale * getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnHDPI); - mnMmY *= mfPageScale * getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnVDPI); + mnMmX = std::round(unitToPixel(static_cast<double>(mnMmX) * mfPageScale, flags, Direction::horizontal)); + mnMmY = std::round(unitToPixel(static_cast<double>(mnMmY) * mfPageScale, flags, Direction::vertical)); mappingChanged(); } break; @@ -1815,7 +1831,7 @@ namespace emfplushelper rMS.ReadUInt32(stackIndex); SAL_INFO("drawinglayer.emf", "EMF+\t Restore stack index: " << stackIndex); - GraphicStatePop(mGSStack, stackIndex, mrPropertyHolders.Current()); + GraphicStatePop(mGSStack, stackIndex); break; } case EmfPlusRecordTypeBeginContainer: @@ -1837,12 +1853,12 @@ namespace emfplushelper SAL_WARN("drawinglayer.emf", "EMF+\t file error. UnitTypeDisplay and UnitTypeWorld are not supported by BeginContainer in EMF+ specification."); break; } - const float aPageScaleX = getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnHDPI); - const float aPageScaleY = getUnitToPixelMultiplier(static_cast<UnitType>(flags), mnVDPI); GraphicStatePush(mGSContainerStack, stackIndex); const basegfx::B2DHomMatrix transform = basegfx::utils::createScaleTranslateB2DHomMatrix( - aPageScaleX * ( dw / sw ), aPageScaleY * ( dh / sh ), - aPageScaleX * ( dx - sx ), aPageScaleY * ( dy - sy) ); + unitToPixel(static_cast<double>(dw) / sw, flags, Direction::horizontal), + unitToPixel(static_cast<double>(dh) / sh, flags, Direction::vertical), + unitToPixel(static_cast<double>(dx) - sx, flags, Direction::horizontal), + unitToPixel(static_cast<double>(dy) - sy, flags, Direction::vertical)); maWorldTransform *= transform; mappingChanged(); break; @@ -1862,7 +1878,7 @@ namespace emfplushelper rMS.ReadUInt32(stackIndex); SAL_INFO("drawinglayer.emf", "EMF+\t End Container stack index: " << stackIndex); - GraphicStatePop(mGSContainerStack, stackIndex, mrPropertyHolders.Current()); + GraphicStatePop(mGSContainerStack, stackIndex); break; } case EmfPlusRecordTypeSetWorldTransform: @@ -1997,62 +2013,95 @@ namespace emfplushelper break; } case EmfPlusRecordTypeSetClipRect: - { - int combineMode = (flags >> 8) & 0xf; - - SAL_INFO("drawinglayer.emf", "EMF+\t SetClipRect combine mode: " << combineMode); - - float dx, dy, dw, dh; - ReadRectangle(rMS, dx, dy, dw, dh); - SAL_INFO("drawinglayer.emf", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh); - ::basegfx::B2DPoint mappedPoint1(Map(dx, dy)); - ::basegfx::B2DPoint mappedPoint2(Map(dx + dw, dy + dh)); - - ::basegfx::B2DPolyPolygon polyPolygon( - ::basegfx::utils::createPolygonFromRect( - ::basegfx::B2DRectangle( - mappedPoint1.getX(), - mappedPoint1.getY(), - mappedPoint2.getX(), - mappedPoint2.getY()))); - - HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(), - combineMode, polyPolygon), mrTargetHolders, mrPropertyHolders); - break; - } case EmfPlusRecordTypeSetClipPath: + case EmfPlusRecordTypeSetClipRegion: { int combineMode = (flags >> 8) & 0xf; - SAL_INFO("drawinglayer.emf", "EMF+\t SetClipPath combine mode: " << combineMode); - SAL_INFO("drawinglayer.emf", "EMF+\t Path in slot: " << (flags & 0xff)); - - EMFPPath *path = static_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get()); - if (!path) + ::basegfx::B2DPolyPolygon polyPolygon; + if (type == EmfPlusRecordTypeSetClipRect) { - SAL_WARN("drawinglayer.emf", "EMF+\t TODO Unable to find path in slot: " << (flags & 0xff)); - break; - } + SAL_INFO("drawinglayer.emf", "EMF+\t SetClipRect"); - ::basegfx::B2DPolyPolygon& clipPoly(path->GetPolygon(*this)); + float dx, dy, dw, dh; + ReadRectangle(rMS, dx, dy, dw, dh); + SAL_INFO("drawinglayer.emf", + "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh); + ::basegfx::B2DPoint mappedPoint1(Map(dx, dy)); + ::basegfx::B2DPoint mappedPoint2(Map(dx + dw, dy + dh)); + + polyPolygon + = ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect( + ::basegfx::B2DRectangle(mappedPoint1.getX(), mappedPoint1.getY(), + mappedPoint2.getX(), mappedPoint2.getY()))); + } + else if (type == EmfPlusRecordTypeSetClipPath) + { + SAL_INFO("drawinglayer.emf", "EMF+\tSetClipPath " << (flags & 0xff)); - HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(), - combineMode, clipPoly), mrTargetHolders, mrPropertyHolders); - break; - } - case EmfPlusRecordTypeSetClipRegion: - { - int combineMode = (flags >> 8) & 0xf; - SAL_INFO("drawinglayer.emf", "EMF+\t Region in slot: " << (flags & 0xff)); + EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get()); + if (!path) + { + SAL_WARN("drawinglayer.emf", + "EMF+\t TODO Unable to find path in slot: " << (flags & 0xff)); + break; + } + polyPolygon = path->GetPolygon(*this); + } + else if (type == EmfPlusRecordTypeSetClipRegion) + { + SAL_INFO("drawinglayer.emf", "EMF+\t Region in slot: " << (flags & 0xff)); + EMFPRegion* region + = dynamic_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get()); + if (!region) + { + SAL_WARN( + "drawinglayer.emf", + "EMF+\t TODO Unable to find region in slot: " << (flags & 0xff)); + break; + } + polyPolygon = region->regionPolyPolygon; + } SAL_INFO("drawinglayer.emf", "EMF+\t Combine mode: " << combineMode); - EMFPRegion *region = static_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get()); - if (!region) + ::basegfx::B2DPolyPolygon aClippedPolyPolygon; + if (mrPropertyHolders.Current().getClipPolyPolygonActive()) { - SAL_WARN("drawinglayer.emf", "EMF+\t TODO Unable to find region in slot: " << (flags & 0xff)); - break; + aClippedPolyPolygon + = combineClip(mrPropertyHolders.Current().getClipPolyPolygon(), + combineMode, polyPolygon); } - - HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(), - combineMode, region->regionPolyPolygon), mrTargetHolders, mrPropertyHolders); + else + { + //Combine with infinity + switch (combineMode) + { + case EmfPlusCombineModeReplace: + case EmfPlusCombineModeIntersect: + { + aClippedPolyPolygon = polyPolygon; + break; + } + case EmfPlusCombineModeUnion: + { + // Disable clipping as the clipping is infinity + aClippedPolyPolygon = ::basegfx::B2DPolyPolygon(); + break; + } + case EmfPlusCombineModeXOR: + case EmfPlusCombineModeComplement: + { + //TODO It is not correct and it should be fixed + aClippedPolyPolygon = polyPolygon; + break; + } + case EmfPlusCombineModeExclude: + { + //TODO It is not correct and it should be fixed + aClippedPolyPolygon = ::basegfx::B2DPolyPolygon(); + break; + } + } + } + HandleNewClipRegion(aClippedPolyPolygon, mrTargetHolders, mrPropertyHolders); break; } case EmfPlusRecordTypeOffsetClip: @@ -2113,7 +2162,7 @@ namespace emfplushelper } // get the font from the flags - EMFPFont *font = static_cast< EMFPFont* >( maEMFPObjects[flags & 0xff].get() ); + EMFPFont *font = dynamic_cast<EMFPFont*>(maEMFPObjects[flags & 0xff].get()); if (!font) { break; @@ -2154,7 +2203,7 @@ namespace emfplushelper aDXArray.push_back(0); basegfx::B2DHomMatrix transformMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix( - ::basegfx::B2DSize(font->emSize, font->emSize), + ::basegfx::B2DVector(font->emSize, font->emSize), ::basegfx::B2DPoint(charsPosX[pos], charsPosY[pos])); if (hasMatrix) transformMatrix *= transform; @@ -2169,6 +2218,7 @@ namespace emfplushelper pos, // take character at current pos aLength, // use determined length std::move(aDXArray), // generated DXArray + {}, fontAttribute, Application::GetSettings().GetLanguageTag().getLocale(), color.getBColor(), @@ -2188,6 +2238,7 @@ namespace emfplushelper pos, // take character at current pos aLength, // use determined length std::move(aDXArray), // generated DXArray + {}, fontAttribute, Application::GetSettings().GetLanguageTag().getLocale(), color.getBColor()); |