summaryrefslogtreecommitdiff
path: root/drawinglayer/source/tools/emfphelperdata.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/tools/emfphelperdata.cxx')
-rw-r--r--drawinglayer/source/tools/emfphelperdata.cxx1403
1 files changed, 748 insertions, 655 deletions
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx
index d55babc0e960..1d95f0a8f38a 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -29,11 +29,13 @@
#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>
#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
@@ -78,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";
@@ -224,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+\t Converting to World/Display.");
- return 1.0f;
+ SAL_WARN("drawinglayer.emf", "EMF+\t Converting to World/Display.");
+ return n;
default:
- SAL_WARN("drawinglayer", "EMF+\tTODO Unimplemented support of Unit Type: 0x" << std::hex << aUnitType);
- return 1.0f;
+ SAL_WARN("drawinglayer.emf", "EMF+\tTODO Unimplemented support of Unit Type: 0x" << std::hex << aUnitType);
+ return n;
}
}
@@ -258,9 +263,9 @@ namespace emfplushelper
{
sal_uInt16 objecttype = flags & 0x7f00;
sal_uInt16 index = flags & 0xff;
- SAL_INFO("drawinglayer", "EMF+ Object: " << emfObjectToName(objecttype) << " (0x" << objecttype << ")");
- SAL_INFO("drawinglayer", "EMF+\tObject slot: " << index);
- SAL_INFO("drawinglayer", "EMF+\tFlags: " << (flags & 0xff00));
+ SAL_INFO("drawinglayer.emf", "EMF+ Object: " << emfObjectToName(objecttype) << " (0x" << objecttype << ")");
+ SAL_INFO("drawinglayer.emf", "EMF+\tObject slot: " << index);
+ SAL_INFO("drawinglayer.emf", "EMF+\tFlags: " << (flags & 0xff00));
switch (objecttype)
{
@@ -276,21 +281,20 @@ 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:
{
- sal_uInt32 header, pathFlags;
- sal_Int32 points;
-
- rObjectStream.ReadUInt32(header).ReadInt32(points).ReadUInt32(pathFlags);
- SAL_INFO("drawinglayer", "EMF+\t\tHeader: 0x" << std::hex << header);
- SAL_INFO("drawinglayer", "EMF+\t\tPoints: " << std::dec << points);
- SAL_INFO("drawinglayer", "EMF+\t\tAdditional flags: 0x" << std::hex << pathFlags << std::dec);
- EMFPPath *path = new EMFPPath(points);
+ sal_uInt32 aVersion, aPathPointCount, aPathPointFlags;
+
+ rObjectStream.ReadUInt32(aVersion).ReadUInt32(aPathPointCount).ReadUInt32(aPathPointFlags);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\tVersion: 0x" << std::hex << aVersion);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\tNumber of points: " << std::dec << aPathPointCount);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\tPath point flags: 0x" << std::hex << aPathPointFlags << std::dec);
+ EMFPPath *path = new EMFPPath(aPathPointCount);
maEMFPObjects[index].reset(path);
- path->Read(rObjectStream, pathFlags);
+ path->Read(rObjectStream, aPathPointFlags);
break;
}
case EmfPlusObjectTypeRegion:
@@ -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;
}
@@ -341,12 +345,12 @@ namespace emfplushelper
}
case EmfPlusObjectTypeCustomLineCap:
{
- SAL_WARN("drawinglayer", "EMF+\t TODO Object type 'custom line cap' not yet implemented");
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO Object type 'custom line cap' not yet implemented");
break;
}
default:
{
- SAL_WARN("drawinglayer", "EMF+\t TODO Object unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO Object unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
}
}
}
@@ -358,7 +362,7 @@ namespace emfplushelper
// specifies a location in the coordinate space that is relative to
// the location specified by the previous element in the array. In the case of the first element in
// PointData, a previous location at coordinates (0,0) is assumed.
- SAL_WARN("drawinglayer", "EMF+\t\t TODO Relative coordinates bit detected. Implement parse EMFPlusPointR");
+ SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO Relative coordinates bit detected. Implement parse EMFPlusPointR");
}
if (flags & 0x4000)
@@ -425,7 +429,7 @@ namespace emfplushelper
{
if (mnPixX == 0 || mnPixY == 0)
{
- SAL_WARN("drawinglayer", "dimensions in pixels is 0");
+ SAL_WARN("drawinglayer.emf", "dimensions in pixels is 0");
return;
}
// Call when mnMmX/mnMmY/mnPixX/mnPixY/mnFrameLeft/mnFrameTop/maWorldTransform/ changes.
@@ -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
@@ -457,12 +465,14 @@ namespace emfplushelper
color = Color(ColorAlpha, (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff,
(brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff);
}
- else // we use a pen
+ else // we use a brush
{
- const EMFPPen* pen = static_cast<EMFPPen*>(maEMFPObjects[brushIndexOrColor & 0xff].get());
- if (pen)
+ const EMFPBrush* brush = dynamic_cast<EMFPBrush*>(maEMFPObjects[brushIndexOrColor & 0xff].get());
+ if (brush)
{
- color = pen->GetColor();
+ color = brush->GetColor();
+ if (brush->type != BrushTypeSolidColor)
+ SAL_WARN("drawinglayer.emf", "EMF+\t\t TODO Brush other than solid color is not supported");
}
}
return color;
@@ -475,7 +485,7 @@ namespace emfplushelper
if ( iter != map.end() )
{
map.erase( iter );
- SAL_INFO("drawinglayer", "EMF+\t\tStack index: " << index << " found and erased");
+ SAL_INFO("drawinglayer.emf", "EMF+\t\tStack index: " << index << " found and erased");
}
wmfemfhelper::PropertyHolder state = mrPropertyHolders.Current();
@@ -484,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+\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+ 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+ 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(dash);
- break;
- case EmfPlusLineStyleDot:
- aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(dot);
- break;
- case EmfPlusLineStyleDashDot:
- aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(dashdot);
- break;
- case EmfPlusLineStyleDashDotDot:
- aStrokeAttribute = drawinglayer::attribute::StrokeAttribute(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(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(
- std::make_unique<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(
- std::make_unique<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+\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(
- std::make_unique<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(
- std::make_unique<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+\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(
- std::make_unique<drawinglayer::primitive2d::PolyPolygonColorPrimitive2D>(
- endCapPolygon,
- pen->GetColor().getBColor()));
- }
+ new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ polygon, lineAttribute, pen->GetStrokeAttribute(mdExtractedXScale)));
else
- {
- mrTargetHolders.Current().append(
- std::make_unique<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);
@@ -695,7 +677,7 @@ namespace emfplushelper
{
// not transparent
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::PolyPolygonColorPrimitive2D>(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
polygon,
color.getBColor()));
}
@@ -707,7 +689,7 @@ namespace emfplushelper
color.getBColor()));
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::UnifiedTransparencePrimitive2D>(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
drawinglayer::primitive2d::Primitive2DContainer { aPrimitive },
(255 - color.GetAlpha()) / 255.0));
}
@@ -720,7 +702,7 @@ namespace emfplushelper
if (isColor) // use Color
{
- SAL_INFO("drawinglayer", "EMF+\t\t Fill polygon, ARGB color: 0x" << std::hex << brushIndexOrColor << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\t Fill polygon, ARGB color: 0x" << std::hex << brushIndexOrColor << std::dec);
// EMF Alpha (1 byte): An 8-bit unsigned integer that specifies the transparency of the background,
// ranging from 0 for completely transparent to 0xFF for completely opaque.
@@ -733,8 +715,8 @@ namespace emfplushelper
}
else // use Brush
{
- EMFPBrush* brush = static_cast<EMFPBrush*>( maEMFPObjects[brushIndexOrColor & 0xff].get() );
- SAL_INFO("drawinglayer", "EMF+\t\t Fill polygon, brush slot: " << brushIndexOrColor << " (brush type: " << (brush ? brush->GetType() : -1) << ")");
+ 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
if( !brush )
@@ -787,20 +769,20 @@ namespace emfplushelper
// temporal solution: create a solid colored polygon
// TODO create a 'real' hatching primitive
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::PolyPolygonColorPrimitive2D>(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
polygon,
fillColor.getBColor()));
}
else if (brush->type == BrushTypeTextureFill)
{
- SAL_WARN("drawinglayer", "EMF+\tTODO: implement BrushTypeTextureFill brush");
+ SAL_WARN("drawinglayer.emf", "EMF+\tTODO: implement BrushTypeTextureFill brush");
}
else if (brush->type == BrushTypePathGradient || brush->type == BrushTypeLinearGradient)
{
if (brush->type == BrushTypePathGradient && !(brush->additionalFlags & 0x1))
{
- SAL_WARN("drawinglayer", "EMF+\t TODO Implement displaying BrushTypePathGradient with Boundary: ");
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO Implement displaying BrushTypePathGradient with Boundary: ");
}
::basegfx::B2DHomMatrix aTextureTransformation;
@@ -821,63 +803,36 @@ namespace emfplushelper
if (brush->blendPositions)
{
- SAL_INFO("drawinglayer", "EMF+\t\tUse blend");
+ 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);
}
}
else if (brush->colorblendPositions)
{
- SAL_INFO("drawinglayer", "EMF+\t\tUse color blend");
+ 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
@@ -918,30 +873,30 @@ namespace emfplushelper
// create the same one used for SVG
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::SvgLinearGradientPrimitive2D>(
+ new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
aTextureTransformation,
polygon,
- aVector,
+ std::move(aVector),
aStartPoint,
aEndPoint,
false, // do not use UnitCoordinates
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;
// create the same one used for SVG
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::SvgRadialGradientPrimitive2D>(
+ new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
aTextureTransformation,
polygon,
- aVector,
+ 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));
}
}
@@ -952,11 +907,7 @@ namespace emfplushelper
SvMemoryStream& rMS,
wmfemfhelper::TargetHolders& rTargetHolders,
wmfemfhelper::PropertyHolders& rPropertyHolders)
- : maBaseTransform(),
- maWorldTransform(),
- maMapTransform(),
- maEMFPObjects(),
- mfPageScale(0.0),
+ : mfPageScale(0.0),
mnOriginX(0),
mnOriginY(0),
mnHDPI(0),
@@ -973,17 +924,18 @@ namespace emfplushelper
mnMmY(0),
mbMultipart(false),
mMFlags(0),
- mMStream(),
+ mdExtractedXScale(1.0),
+ mdExtractedYScale(1.0),
mrTargetHolders(rTargetHolders),
mrPropertyHolders(rPropertyHolders),
bIsGetDCProcessing(false)
{
rMS.ReadInt32(mnFrameLeft).ReadInt32(mnFrameTop).ReadInt32(mnFrameRight).ReadInt32(mnFrameBottom);
- SAL_INFO("drawinglayer", "EMF+ picture frame: " << mnFrameLeft << "," << mnFrameTop << " - " << mnFrameRight << "," << mnFrameBottom);
+ SAL_INFO("drawinglayer.emf", "EMF+ picture frame: " << mnFrameLeft << "," << mnFrameTop << " - " << mnFrameRight << "," << mnFrameBottom);
rMS.ReadInt32(mnPixX).ReadInt32(mnPixY).ReadInt32(mnMmX).ReadInt32(mnMmY);
- SAL_INFO("drawinglayer", "EMF+ ref device pixel size: " << mnPixX << "x" << mnPixY << " mm size: " << mnMmX << "x" << mnMmY);
+ SAL_INFO("drawinglayer.emf", "EMF+ ref device pixel size: " << mnPixX << "x" << mnPixY << " mm size: " << mnMmX << "x" << mnMmY);
readXForm(rMS, maBaseTransform);
- SAL_INFO("drawinglayer", "EMF+ base transform: " << maBaseTransform);
+ SAL_INFO("drawinglayer.emf", "EMF+ base transform: " << maBaseTransform);
mappingChanged();
}
@@ -1003,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:
@@ -1046,7 +992,7 @@ namespace emfplushelper
sal_uInt64 length = rMS.GetSize();
if (length < 12)
- SAL_WARN("drawinglayer", "length is less than required header size");
+ SAL_WARN("drawinglayer.emf", "length is less than required header size");
// 12 is minimal valid EMF+ record size; remaining bytes are padding
while (length >= 12)
@@ -1061,30 +1007,40 @@ namespace emfplushelper
if (size < 12)
{
- SAL_WARN("drawinglayer", "Size field is less than 12 bytes");
+ SAL_WARN("drawinglayer.emf", "Size field is less than 12 bytes");
break;
}
else if (size > length)
{
- SAL_WARN("drawinglayer", "Size field is greater than bytes left");
+ SAL_WARN("drawinglayer.emf", "Size field is greater than bytes left");
break;
}
if (dataSize > (size - 12))
{
- SAL_WARN("drawinglayer", "DataSize field is greater than Size-12");
+ SAL_WARN("drawinglayer.emf", "DataSize field is greater than Size-12");
break;
}
- SAL_INFO("drawinglayer", "EMF+ " << emfTypeToName(type) << " (0x" << std::hex << type << ")" << std::dec);
- SAL_INFO("drawinglayer", "EMF+\t record size: " << size);
- SAL_INFO("drawinglayer", "EMF+\t flags: 0x" << std::hex << flags << std::dec);
- SAL_INFO("drawinglayer", "EMF+\t data size: " << dataSize);
+ SAL_INFO("drawinglayer.emf", "EMF+ " << emfTypeToName(type) << " (0x" << std::hex << type << ")" << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\t record size: " << size);
+ SAL_INFO("drawinglayer.emf", "EMF+\t flags: 0x" << std::hex << flags << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\t data size: " << dataSize);
if (bIsGetDCProcessing)
{
- SAL_INFO("drawinglayer", "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)))
@@ -1100,13 +1056,13 @@ namespace emfplushelper
// 1st 4 bytes are TotalObjectSize
mMStream.WriteBytes(static_cast<const char *>(rMS.GetData()) + rMS.Tell() + 4, dataSize - 4);
- SAL_INFO("drawinglayer", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
+ SAL_INFO("drawinglayer.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
}
else
{
if (mbMultipart)
{
- SAL_INFO("drawinglayer", "EMF+ multipart record flags: " << mMFlags);
+ SAL_INFO("drawinglayer.emf", "EMF+ multipart record flags: " << mMFlags);
mMStream.Seek(0);
processObjectRecord(mMStream, mMFlags, 0, true);
}
@@ -1120,14 +1076,15 @@ namespace emfplushelper
{
case EmfPlusRecordTypeHeader:
{
- sal_uInt32 header, version;
-
- rMS.ReadUInt32(header).ReadUInt32(version).ReadUInt32(mnHDPI).ReadUInt32(mnVDPI);
- SAL_INFO("drawinglayer", "EMF+\tHeader: 0x" << std::hex << header);
- SAL_INFO("drawinglayer", "EMF+\tVersion: " << std::dec << version);
- SAL_INFO("drawinglayer", "EMF+\tHorizontal DPI: " << mnHDPI);
- SAL_INFO("drawinglayer", "EMF+\tVertical DPI: " << mnVDPI);
- SAL_INFO("drawinglayer", "EMF+\tDual: " << ((flags & 1) ? "true" : "false"));
+ sal_uInt32 version, emfPlusFlags;
+ SAL_INFO("drawinglayer.emf", "EMF+\tDual: " << ((flags & 1) ? "true" : "false"));
+
+ 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);
break;
}
case EmfPlusRecordTypeEndOfFile:
@@ -1140,7 +1097,7 @@ namespace emfplushelper
unsigned char data;
OUString hexdata;
- SAL_INFO("drawinglayer", "EMF+\tDatasize: 0x" << std::hex << dataSize << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\tDatasize: 0x" << std::hex << dataSize << std::dec);
for (sal_uInt32 i=0; i<dataSize; i++)
{
@@ -1156,14 +1113,15 @@ namespace emfplushelper
hexdata += "0x" + padding + OUString::number(data, 16) + " ";
}
- SAL_INFO("drawinglayer", "EMF+\t" << hexdata);
+ SAL_INFO("drawinglayer.emf", "EMF+\t" << hexdata);
#endif
break;
}
case EmfPlusRecordTypeGetDC:
{
bIsGetDCProcessing = true;
- SAL_INFO("drawinglayer", "EMF+\tAlready used in svtools wmf/emf filter parser");
+ aGetDCState = mrPropertyHolders.Current();
+ SAL_INFO("drawinglayer.emf", "EMF+\tAlready used in svtools wmf/emf filter parser");
break;
}
case EmfPlusRecordTypeObject:
@@ -1183,21 +1141,21 @@ namespace emfplushelper
if (type == EmfPlusRecordTypeFillPie)
{
rMS.ReadUInt32(brushIndexOrColor);
- SAL_INFO("drawinglayer", "EMF+\t FillPie colorOrIndex: " << brushIndexOrColor);
+ SAL_INFO("drawinglayer.emf", "EMF+\t FillPie colorOrIndex: " << brushIndexOrColor);
}
else if (type == EmfPlusRecordTypeDrawPie)
{
- SAL_INFO("drawinglayer", "EMF+\t DrawPie");
+ SAL_INFO("drawinglayer.emf", "EMF+\t DrawPie");
}
else
{
- SAL_INFO("drawinglayer", "EMF+\t DrawArc");
+ SAL_INFO("drawinglayer.emf", "EMF+\t DrawArc");
}
rMS.ReadFloat(startAngle).ReadFloat(sweepAngle);
float dx, dy, dw, dh;
ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
- SAL_INFO("drawinglayer", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
+ SAL_INFO("drawinglayer.emf", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
startAngle = basegfx::deg2rad(startAngle);
sweepAngle = basegfx::deg2rad(sweepAngle);
float endAngle = startAngle + sweepAngle;
@@ -1218,7 +1176,7 @@ namespace emfplushelper
std::swap(endAngle, startAngle);
}
- SAL_INFO("drawinglayer", "EMF+\t Adjusted angles: start " <<
+ SAL_INFO("drawinglayer.emf", "EMF+\t Adjusted angles: start " <<
basegfx::rad2deg(startAngle) << ", end: " << basegfx::rad2deg(endAngle) <<
" startAngle: " << startAngle << " sweepAngle: " << sweepAngle);
const ::basegfx::B2DPoint centerPoint(dx + 0.5 * dw, dy + 0.5 * dh);
@@ -1244,13 +1202,13 @@ namespace emfplushelper
sal_uInt32 index = flags & 0xff;
sal_uInt32 brushIndexOrColor;
rMS.ReadUInt32(brushIndexOrColor);
- SAL_INFO("drawinglayer", "EMF+ FillPath slot: " << index);
+ SAL_INFO("drawinglayer.emf", "EMF+ FillPath slot: " << index);
EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[index].get());
if (path)
EMFPPlusFillPolygon(path->GetPolygon(*this), flags & 0x8000, brushIndexOrColor);
else
- SAL_WARN("drawinglayer", "EMF+\tEmfPlusRecordTypeFillPath missing path");
+ SAL_WARN("drawinglayer.emf", "EMF+\tEmfPlusRecordTypeFillPath missing path");
}
break;
case EmfPlusRecordTypeFillRegion:
@@ -1258,9 +1216,13 @@ namespace emfplushelper
sal_uInt32 index = flags & 0xff;
sal_uInt32 brushIndexOrColor;
rMS.ReadUInt32(brushIndexOrColor);
- SAL_INFO("drawinglayer", "EMF+\t FillRegion slot: " << index);
+ 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:
@@ -1276,10 +1238,10 @@ namespace emfplushelper
rMS.ReadUInt32(brushIndexOrColor);
}
- SAL_INFO("drawinglayer", "EMF+\t " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
+ SAL_INFO("drawinglayer.emf", "EMF+\t " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
float dx, dy, dw, dh;
ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
- SAL_INFO("drawinglayer", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
+ SAL_INFO("drawinglayer.emf", "EMF+\t RectData: " << dx << "," << dy << " " << dw << "x" << dh);
::basegfx::B2DPolyPolygon polyPolygon(
::basegfx::utils::createPolygonFromEllipse(::basegfx::B2DPoint(dx + 0.5 * dw, dy + 0.5 * dh),
0.5 * dw, 0.5 * dh));
@@ -1295,26 +1257,26 @@ 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;
if (EmfPlusRecordTypeFillRects == type)
{
- SAL_INFO("drawinglayer", "EMF+\t FillRects");
+ SAL_INFO("drawinglayer.emf", "EMF+\t FillRects");
rMS.ReadUInt32(brushIndexOrColor);
- SAL_INFO("drawinglayer", "EMF+\t" << (isColor ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\t" << (isColor ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
}
else
{
- SAL_INFO("drawinglayer", "EMF+\t DrawRects");
+ 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));
@@ -1323,39 +1285,35 @@ namespace emfplushelper
polygon.append(Map(x, y + height));
polygon.setClosed(true);
- SAL_INFO("drawinglayer", "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);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\t rectangle: " << x << ", "<< y << " " << width << "x" << height);
+ 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;
- sal_Int32 points;
+ sal_uInt32 brushIndexOrColor, points;
rMS.ReadUInt32(brushIndexOrColor);
- rMS.ReadInt32(points);
- SAL_INFO("drawinglayer", "EMF+\t FillPolygon in slot: " << index << " points: " << points);
- SAL_INFO("drawinglayer", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << " : 0x" << std::hex << brushIndexOrColor << std::dec);
+ rMS.ReadUInt32(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+\t DrawLines in slot: " << (flags & 0xff) << " points: " << points);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Points: " << points);
EMFPPath path(points, true);
path.Read(rMS, flags);
@@ -1369,13 +1327,13 @@ namespace emfplushelper
{
sal_uInt32 penIndex;
rMS.ReadUInt32(penIndex);
- SAL_INFO("drawinglayer", "EMF+\t Pen: " << penIndex);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Pen: " << penIndex);
EMFPPath* path = dynamic_cast<EMFPPath*>(maEMFPObjects[flags & 0xff].get());
if (path)
EMFPPlusDrawPolygon(path->GetPolygon(*this), penIndex);
else
- SAL_WARN("drawinglayer", "\t\tEmfPlusRecordTypeDrawPath missing path");
+ SAL_WARN("drawinglayer.emf", "\t\tEmfPlusRecordTypeDrawPath missing path");
break;
}
@@ -1383,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+\t DrawBeziers slot: " << (flags & 0xff));
- SAL_INFO("drawinglayer", "EMF+\t Number of points: " << aCount);
- SAL_WARN_IF((aCount - 1) % 3 != 0, "drawinglayer", "EMF+\t Bezier Draw not support number of points other than 4, 7, 10, 13, 16...");
+ 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...");
if (aCount < 4)
{
- SAL_WARN("drawinglayer", "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+\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:
@@ -1431,20 +1441,30 @@ namespace emfplushelper
sal_uInt32 imageAttributesId;
sal_Int32 sourceUnit;
rMS.ReadUInt32(imageAttributesId).ReadInt32(sourceUnit);
- SAL_INFO("drawinglayer", "EMF+\t " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << " image attributes Id: " << imageAttributesId << " source unit: " << sourceUnit);
- SAL_INFO("drawinglayer", "EMF+\t TODO: use image attributes");
-
- // For DrawImage and DrawImagePoints, source unit of measurement type must be 1 pixel
- if (sourceUnit == UnitTypePixel && maEMFPObjects[flags & 0xff])
+ SAL_INFO("drawinglayer.emf",
+ "EMF+\t " << (type == EmfPlusRecordTypeDrawImage ? "DrawImage"
+ : "DrawImagePoints")
+ << " image attributes Id: " << imageAttributesId
+ << " source unit: " << sourceUnit);
+ SAL_INFO("drawinglayer.emf", "EMF+\t TODO: use image attributes");
+
+ // Source unit of measurement type must be 1 pixel
+ 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, sh));
- SAL_INFO("drawinglayer", "EMF+\t " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx << "," << sy << " " << sw << "x" << sh);
- ::basegfx::B2DPoint aDstPoint;
- ::basegfx::B2DSize aDstSize;
+ ::tools::Rectangle aSource(Point(sx, sy), Size(sw + 1, sh + 1));
+ SAL_INFO("drawinglayer.emf",
+ "EMF+\t "
+ << (type == EmfPlusRecordTypeDrawImage ? "DrawImage"
+ : "DrawImagePoints")
+ << " source rectangle: " << sx << "," << sy << " " << sw << "x"
+ << sh);
+
+ float dx(0.), dy(0.), dw(0.), dh(0.);
double fShearX = 0.0;
double fShearY = 0.0;
if (type == EmfPlusRecordTypeDrawImagePoints)
@@ -1453,251 +1473,290 @@ namespace emfplushelper
rMS.ReadUInt32(aCount);
// Number of points used by DrawImagePoints. Exactly 3 points must be specified.
- if(aCount == 3)
- {
- float x1, y1, x2, y2, x3, y3;
-
- ReadPoint(rMS, x1, y1, flags); // upper-left point
- ReadPoint(rMS, x2, y2, flags); // upper-right
- ReadPoint(rMS, x3, y3, flags); // lower-left
-
- SAL_INFO("drawinglayer", "EMF+\t destination points: P1:" << x1 << "," << y1 << " P2:" << x2 << "," << y2 << " P3:" << x3 << "," << y3);
-
- aDstPoint = ::basegfx::B2DPoint(x1, y1);
- aDstSize = ::basegfx::B2DSize(x2 - x1, y3 - y1);
- fShearX = x3 - x1;
- fShearY = y2 - y1;
- }
- else
+ if (aCount != 3)
{
- SAL_WARN("drawinglayer", "EMF+\t DrawImagePoints Wrong EMF+ file. Expected 3 points, received: "<< aCount);
+ SAL_WARN("drawinglayer.emf", "EMF+\t Wrong EMF+ file. Expected "
+ "3 points, received: "
+ << aCount);
break;
}
+ float x1, y1, x2, y2, x3, y3;
+
+ ReadPoint(rMS, x1, y1, flags); // upper-left point
+ ReadPoint(rMS, x2, y2, flags); // upper-right
+ ReadPoint(rMS, x3, y3, flags); // lower-left
+
+ SAL_INFO("drawinglayer.emf", "EMF+\t destination points: "
+ << x1 << "," << y1 << " " << x2 << ","
+ << y2 << " " << x3 << "," << y3);
+ dx = x1;
+ dy = y2;
+ dw = x2 - x1;
+ dh = y3 - y1;
+ fShearX = x3 - x1;
+ fShearY = y2 - y1;
}
else if (type == EmfPlusRecordTypeDrawImage)
- {
- float dx, dy, dw, dh;
ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
- SAL_INFO("drawinglayer", "EMF+\t destination rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
- aDstPoint = ::basegfx::B2DPoint(dx, dy);
- aDstSize = ::basegfx::B2DSize(dw, dh);
- }
- const basegfx::B2DHomMatrix aTransformMatrix = maMapTransform *
- basegfx::B2DHomMatrix(
- /* Row 0, Column 0 */ aDstSize.getX(),
- /* 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 2 */ aDstPoint.getY());
+ SAL_INFO("drawinglayer.emf",
+ "EMF+\t Rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
+ Size aSize;
+ if (image->type == ImageDataTypeBitmap)
+ {
+ aSize = image->graphic.GetBitmapEx().GetSizePixel();
+ SAL_INFO("drawinglayer.emf", "EMF+\t Bitmap size: " << aSize.Width()
+ << "x"
+ << aSize.Height());
+ if (sx < 0)
+ {
+ // If src position is negative then we need shift image to right
+ dx = dx + ((-sx) / sw) * dw;
+ if (sx + sw <= aSize.Width())
+ dw = ((sw + sx) / sw) * dw;
+ else
+ dw = (aSize.Width() / sw) * dw;
+ }
+ else if (sx + sw > aSize.Width())
+ // If the src image is smaller that what we want to cut, then we need to scale down
+ dw = ((aSize.Width() - sx) / sw) * dw;
- if (image.type == ImageDataTypeBitmap)
+ if (sy < 0)
+ {
+ dy = dy + ((-sy) / sh) * dh;
+ if (sy + sh <= aSize.Height())
+ dh = ((sh + sy) / sh) * dh;
+ else
+ dh = (aSize.Height() / sh) * dh;
+ }
+ else if (sy + sh > aSize.Height())
+ dh = ((aSize.Height() - sy) / sh) * dh;
+ }
+ else
+ SAL_INFO(
+ "drawinglayer.emf",
+ "EMF+\t TODO: Add support for SrcRect to ImageDataTypeMetafile");
+ const ::basegfx::B2DPoint aDstPoint(dx, dy);
+ const ::basegfx::B2DSize aDstSize(dw, dh);
+
+ const basegfx::B2DHomMatrix aTransformMatrix
+ = maMapTransform
+ * basegfx::B2DHomMatrix(
+ /* 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.getHeight(),
+ /* Row 1, Column 2 */ aDstPoint.getY());
+
+ if (image->type == ImageDataTypeBitmap)
{
- BitmapEx aBmp(image.graphic.GetBitmapEx());
+ BitmapEx aBmp(image->graphic.GetBitmapEx());
aBmp.Crop(aSource);
- Size aSize(aBmp.GetSizePixel());
- SAL_INFO("drawinglayer", "EMF+\t Bitmap size: " << aSize.Width() << "x" << aSize.Height());
+ aSize = aBmp.GetSizePixel();
if (aSize.Width() > 0 && aSize.Height() > 0)
{
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::BitmapPrimitive2D>(
- VCLUnoHelper::CreateVCLXBitmap(aBmp),
- aTransformMatrix));
+ new drawinglayer::primitive2d::BitmapPrimitive2D(
+ aBmp, aTransformMatrix));
}
else
- {
- SAL_WARN("drawinglayer", "EMF+\t warning: empty bitmap");
- break;
- }
+ 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(
- std::make_unique<drawinglayer::primitive2d::MetafilePrimitive2D>(aTransformMatrix, aGDI));
+ new drawinglayer::primitive2d::MetafilePrimitive2D(aTransformMatrix,
+ aGDI));
}
}
else
{
- SAL_WARN("drawinglayer", "EMF+\tDrawImage(Points) Wrong EMF+ file. Only Unit Type Pixel is support by EMF+ specification for DrawImage(Points)");
+ SAL_WARN("drawinglayer.emf",
+ "EMF+\tDrawImage(Points) Wrong EMF+ file. Only Unit Type Pixel is "
+ "support by EMF+ specification for DrawImage(Points)");
}
break;
}
case EmfPlusRecordTypeDrawString:
{
- sal_uInt32 brushId;
- sal_uInt32 formatId;
- sal_uInt32 stringLength;
+ sal_uInt32 brushId, formatId, stringLength;
rMS.ReadUInt32(brushId).ReadUInt32(formatId).ReadUInt32(stringLength);
- SAL_INFO("drawinglayer", "EMF+\t FontId: " << OUString::number(flags & 0xFF));
- SAL_INFO("drawinglayer", "EMF+\t BrushId: " << BrushIDToString(flags, brushId));
- SAL_INFO("drawinglayer", "EMF+\t FormatId: " << formatId);
- SAL_INFO("drawinglayer", "EMF+\t Length: " << stringLength);
-
- if (flags & 0x8000)
+ SAL_INFO("drawinglayer.emf", "EMF+\t FontId: " << OUString::number(flags & 0xFF));
+ SAL_INFO("drawinglayer.emf", "EMF+\t BrushId: " << BrushIDToString(flags, brushId));
+ SAL_INFO("drawinglayer.emf", "EMF+\t FormatId: " << formatId);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Length: " << stringLength);
+
+ // read the layout rectangle
+ float lx, ly, lw, lh;
+ rMS.ReadFloat(lx).ReadFloat(ly).ReadFloat(lw).ReadFloat(lh);
+
+ SAL_INFO("drawinglayer.emf", "EMF+\t DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
+ // parse the string
+ const OUString text = read_uInt16s_ToOUString(rMS, stringLength);
+ SAL_INFO("drawinglayer.emf", "EMF+\t DrawString string: " << text);
+ // 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 = dynamic_cast<EMFPFont*>(maEMFPObjects[flags & 0xff].get());
+ if (!font)
{
- // read the layout rectangle
- float lx, ly, lw, lh;
- rMS.ReadFloat(lx).ReadFloat(ly).ReadFloat(lw).ReadFloat(lh);
-
- SAL_INFO("drawinglayer", "EMF+\t DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
- // parse the string
- const OUString text = read_uInt16s_ToOUString(rMS, stringLength);
- SAL_INFO("drawinglayer", "EMF+\t DrawString string: " << text);
- // 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() );
- if (!font)
- {
- break;
- }
- mrPropertyHolders.Current().setFont(vcl::Font(font->family, Size(font->emSize, font->emSize)));
+ break;
+ }
+ mrPropertyHolders.Current().setFont(vcl::Font(font->family, Size(font->emSize, font->emSize)));
+
+ drawinglayer::attribute::FontAttribute fontAttribute(
+ font->family, // font family
+ "", // (no) font style
+ font->Bold() ? 8u : 1u, // weight: 8 = bold
+ font->family == "SYMBOL", // symbol
+ stringFormat && stringFormat->DirectionVertical(), // vertical
+ font->Italic(), // italic
+ false, // monospaced
+ false, // outline = false, no such thing in MS-EMFPLUS
+ stringFormat && stringFormat->DirectionRightToLeft(), // right-to-left
+ false); // BiDiStrong
+
+ css::lang::Locale locale;
+ double stringAlignmentHorizontalOffset = 0.0;
+ double stringAlignmentVerticalOffset = font->emSize;
+ if (stringFormat)
+ {
+ LanguageTag aLanguageTag(static_cast<LanguageType>(stringFormat->language));
+ locale = aLanguageTag.getLocale();
+ drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
- drawinglayer::attribute::FontAttribute fontAttribute(
- font->family, // font family
- "", // (no) font style
- font->Bold() ? 8u : 1u, // weight: 8 = bold
- font->family == "SYMBOL", // symbol
- stringFormat && stringFormat->DirectionVertical(), // vertical
- font->Italic(), // italic
- false, // monospaced
- false, // outline = false, no such thing in MS-EMFPLUS
- stringFormat && stringFormat->DirectionRightToLeft(), // right-to-left
- false); // BiDiStrong
-
- css::lang::Locale locale;
- double stringAlignmentHorizontalOffset = 0.0;
- if (stringFormat)
- {
- SAL_WARN_IF(stringFormat->DirectionRightToLeft(), "drawinglayer", "EMF+\t DrawString Alignment TODO For a right-to-left layout rectangle, the origin should be at the upper right.");
- if (stringFormat->stringAlignment == StringAlignmentNear)
+ aTextLayouter.setFontAttribute(fontAttribute, font->emSize,
+ font->emSize, locale);
+
+ double fTextWidth = aTextLayouter.getTextWidth(text, 0, stringLength);
+ SAL_WARN_IF(stringFormat->DirectionRightToLeft(), "drawinglayer.emf",
+ "EMF+\t DrawString Alignment TODO For a right-to-left layout rectangle, the origin should be at the upper right.");
+ if (stringFormat->stringAlignment == StringAlignmentNear)
// Alignment is to the left side of the layout rectangle (lx, ly, lw, lh)
- {
- stringAlignmentHorizontalOffset = stringFormat->leadingMargin * font->emSize;
- } else if (stringFormat->stringAlignment == StringAlignmentCenter)
+ stringAlignmentHorizontalOffset = stringFormat->leadingMargin * font->emSize;
+ else if (stringFormat->stringAlignment == StringAlignmentCenter)
// Alignment is centered between the origin and extent of the layout rectangle
- {
- stringAlignmentHorizontalOffset = 0.5 * lw + stringFormat->leadingMargin * font->emSize - 0.3 * font->emSize * stringLength;
- } else if (stringFormat->stringAlignment == StringAlignmentFar)
+ stringAlignmentHorizontalOffset = 0.5 * lw + (stringFormat->leadingMargin - stringFormat->trailingMargin) * font->emSize - 0.5 * fTextWidth;
+ else if (stringFormat->stringAlignment == StringAlignmentFar)
// Alignment is to the right side of the layout rectangle
- {
- stringAlignmentHorizontalOffset = lw - stringFormat->trailingMargin * font->emSize - 0.6 * font->emSize * stringLength;
- }
+ stringAlignmentHorizontalOffset = lw - stringFormat->trailingMargin * font->emSize - fTextWidth;
+
+ if (stringFormat->lineAlign == StringAlignmentNear)
+ stringAlignmentVerticalOffset = font->emSize;
+ else if (stringFormat->lineAlign == StringAlignmentCenter)
+ stringAlignmentVerticalOffset = 0.5 * lh + 0.5 * font->emSize;
+ else if (stringFormat->lineAlign == StringAlignmentFar)
+ stringAlignmentVerticalOffset = lh;
+ }
+ else
+ {
+ // By default LeadingMargin is 1/6 inch
+ // TODO for typographic fonts set value to 0.
+ stringAlignmentHorizontalOffset = 16.0;
- LanguageTag aLanguageTag(static_cast< LanguageType >(stringFormat->language));
- locale = aLanguageTag.getLocale();
- }
- else
- {
- // By default LeadingMargin is 1/6 inch
- // TODO for typographic fonts set value to 0.
- stringAlignmentHorizontalOffset = 16.0;
+ // use system default
+ locale = Application::GetSettings().GetLanguageTag().getLocale();
+ }
- // use system default
- locale = Application::GetSettings().GetLanguageTag().getLocale();
- }
+ const basegfx::B2DHomMatrix transformMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ ::basegfx::B2DVector(font->emSize, font->emSize),
+ ::basegfx::B2DPoint(lx + stringAlignmentHorizontalOffset,
+ ly + stringAlignmentVerticalOffset));
- const basegfx::B2DHomMatrix transformMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(
- ::basegfx::B2DSize(font->emSize, font->emSize),
- ::basegfx::B2DPoint(lx + stringAlignmentHorizontalOffset, ly + font->emSize));
+ Color uncorrectedColor = EMFPGetBrushColorOrARGBColor(flags, brushId);
+ Color color;
- Color uncorrectedColor = EMFPGetBrushColorOrARGBColor(flags, brushId);
- Color color;
+ if (mbSetTextContrast)
+ {
+ const auto gammaVal = mnTextContrast / 1000;
+ const basegfx::BColorModifier_gamma gamma(gammaVal);
+
+ // gamma correct transparency color
+ sal_uInt16 alpha = uncorrectedColor.GetAlpha();
+ alpha = std::clamp(std::pow(alpha, 1.0 / gammaVal), 0.0, 1.0) * 255;
+
+ basegfx::BColor modifiedColor(gamma.getModifiedColor(uncorrectedColor.getBColor()));
+ color.SetRed(modifiedColor.getRed() * 255);
+ color.SetGreen(modifiedColor.getGreen() * 255);
+ color.SetBlue(modifiedColor.getBlue() * 255);
+ color.SetAlpha(alpha);
+ }
+ else
+ {
+ color = uncorrectedColor;
+ }
- if (mbSetTextContrast)
+ mrPropertyHolders.Current().setTextColor(color.getBColor());
+ mrPropertyHolders.Current().setTextColorActive(true);
+
+ if (color.GetAlpha() > 0)
+ {
+ std::vector<double> emptyVector;
+ rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> pBaseText;
+ if (font->Underline() || font->Strikeout())
{
- const auto gammaVal = mnTextContrast / 1000;
- const basegfx::BColorModifier_gamma gamma(gammaVal);
-
- // gamma correct transparency color
- sal_uInt16 alpha = uncorrectedColor.GetAlpha();
- alpha = std::clamp(std::pow(alpha, 1.0 / gammaVal), 0.0, 1.0) * 255;
-
- basegfx::BColor modifiedColor(gamma.getModifiedColor(uncorrectedColor.getBColor()));
- color.SetRed(modifiedColor.getRed() * 255);
- color.SetGreen(modifiedColor.getGreen() * 255);
- color.SetBlue(modifiedColor.getBlue() * 255);
- color.SetAlpha(alpha);
+ pBaseText = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
+ transformMatrix,
+ text,
+ 0, // text always starts at 0
+ stringLength,
+ std::move(emptyVector), // EMF-PLUS has no DX-array
+ {},
+ fontAttribute,
+ locale,
+ color.getBColor(), // Font Color
+ COL_TRANSPARENT, // Fill Color
+ color.getBColor(), // OverlineColor
+ color.getBColor(), // TextlineColor
+ drawinglayer::primitive2d::TEXT_LINE_NONE,
+ font->Underline() ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
+ false,
+ font->Strikeout() ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE);
}
else
{
- color = uncorrectedColor;
+ pBaseText = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ transformMatrix,
+ text,
+ 0, // text always starts at 0
+ stringLength,
+ std::move(emptyVector), // EMF-PLUS has no DX-array
+ {},
+ fontAttribute,
+ locale,
+ color.getBColor());
}
-
- mrPropertyHolders.Current().setTextColor(color.getBColor());
- mrPropertyHolders.Current().setTextColorActive(true);
-
- if (color.GetAlpha() > 0)
+ drawinglayer::primitive2d::Primitive2DReference aPrimitiveText(pBaseText);
+ if (color.IsTransparent())
{
- std::vector<double> emptyVector;
- drawinglayer::primitive2d::BasePrimitive2D* pBaseText = nullptr;
- if (font->Underline() || font->Strikeout())
- {
- pBaseText = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
- transformMatrix,
- text,
- 0, // text always starts at 0
- stringLength,
- emptyVector, // EMF-PLUS has no DX-array
- fontAttribute,
- locale,
- color.getBColor(),
- COL_TRANSPARENT,
- color.getBColor(),
- color.getBColor(),
- drawinglayer::primitive2d::TEXT_LINE_NONE,
- font->Underline() ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE,
- false,
- font->Strikeout() ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE);
- }
- else
- {
- pBaseText = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
- transformMatrix,
- text,
- 0, // text always starts at 0
- stringLength,
- emptyVector, // EMF-PLUS has no DX-array
- fontAttribute,
- locale,
- color.getBColor());
- }
- drawinglayer::primitive2d::Primitive2DReference aPrimitiveText(pBaseText);
- if (color.IsTransparent())
- {
- aPrimitiveText = new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
- drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText },
- (255 - color.GetAlpha()) / 255.0);
- }
-
- mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::TransformPrimitive2D>(
- maMapTransform,
- drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText } ));
+ aPrimitiveText = new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText },
+ (255 - color.GetAlpha()) / 255.0);
}
- }
- else
- {
- SAL_WARN("drawinglayer", "EMF+\t DrawString TODO - drawing with brush not yet supported");
+
+ mrTargetHolders.Current().append(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ maMapTransform,
+ drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText } ));
}
break;
}
case EmfPlusRecordTypeSetPageTransform:
{
rMS.ReadFloat(mfPageScale);
- SAL_INFO("drawinglayer", "EMF+\t Scale: " << mfPageScale << " unit: " << UnitTypeToString(flags));
+ SAL_INFO("drawinglayer.emf", "EMF+\t Scale: " << mfPageScale << " unit: " << UnitTypeToString(flags));
if ((flags == UnitTypeDisplay) || (flags == UnitTypeWorld))
{
- SAL_WARN("drawinglayer", "EMF+\t file error. UnitTypeDisplay and UnitTypeWorld are not supported by SetPageTransform in EMF+ specification.");
+ SAL_WARN("drawinglayer.emf", "EMF+\t file error. UnitTypeDisplay and UnitTypeWorld are not supported by SetPageTransform in EMF+ specification.");
}
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;
@@ -1705,7 +1764,7 @@ namespace emfplushelper
case EmfPlusRecordTypeSetRenderingOrigin:
{
rMS.ReadInt32(mnOriginX).ReadInt32(mnOriginY);
- SAL_INFO("drawinglayer", "EMF+\t SetRenderingOrigin, [x,y]: " << mnOriginX << "," << mnOriginY);
+ SAL_INFO("drawinglayer.emf", "EMF+\t SetRenderingOrigin, [x,y]: " << mnOriginX << "," << mnOriginY);
break;
}
case EmfPlusRecordTypeSetTextContrast:
@@ -1716,51 +1775,51 @@ namespace emfplushelper
mbSetTextContrast = true;
mnTextContrast = flags & 0xFFF;
SAL_WARN_IF(mnTextContrast > UPPERGAMMA || mnTextContrast < LOWERGAMMA,
- "drawinglayer", "EMF+\t Gamma value is not with bounds 1000 to 2200, value is " << mnTextContrast);
+ "drawinglayer.emf", "EMF+\t Gamma value is not with bounds 1000 to 2200, value is " << mnTextContrast);
mnTextContrast = std::min(mnTextContrast, UPPERGAMMA);
mnTextContrast = std::max(mnTextContrast, LOWERGAMMA);
- SAL_INFO("drawinglayer", "EMF+\t Text contrast: " << (mnTextContrast / 1000) << " gamma");
+ SAL_INFO("drawinglayer.emf", "EMF+\t Text contrast: " << (mnTextContrast / 1000) << " gamma");
break;
}
case EmfPlusRecordTypeSetTextRenderingHint:
{
sal_uInt8 nTextRenderingHint = (flags & 0xFF) >> 1;
- SAL_INFO("drawinglayer", "EMF+\t Text rendering hint: " << TextRenderingHintToString(nTextRenderingHint));
- SAL_WARN("drawinglayer", "EMF+\t TODO SetTextRenderingHint");
+ SAL_INFO("drawinglayer.emf", "EMF+\t Text rendering hint: " << TextRenderingHintToString(nTextRenderingHint));
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO SetTextRenderingHint");
break;
}
case EmfPlusRecordTypeSetAntiAliasMode:
{
bool bUseAntiAlias = (flags & 0x0001);
sal_uInt8 nSmoothingMode = (flags & 0xFE00) >> 1;
- SAL_INFO("drawinglayer", "EMF+\t Antialiasing: " << (bUseAntiAlias ? "enabled" : "disabled"));
- SAL_INFO("drawinglayer", "EMF+\t Smoothing mode: " << SmoothingModeToString(nSmoothingMode));
- SAL_WARN("drawinglayer", "EMF+\t TODO SetAntiAliasMode");
+ SAL_INFO("drawinglayer.emf", "EMF+\t Antialiasing: " << (bUseAntiAlias ? "enabled" : "disabled"));
+ SAL_INFO("drawinglayer.emf", "EMF+\t Smoothing mode: " << SmoothingModeToString(nSmoothingMode));
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO SetAntiAliasMode");
break;
}
case EmfPlusRecordTypeSetInterpolationMode:
{
sal_uInt16 nInterpolationMode = flags & 0xFF;
- SAL_INFO("drawinglayer", "EMF+\t Interpolation mode: " << InterpolationModeToString(nInterpolationMode));
- SAL_WARN("drawinglayer", "EMF+\t TODO InterpolationMode");
+ SAL_INFO("drawinglayer.emf", "EMF+\t Interpolation mode: " << InterpolationModeToString(nInterpolationMode));
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO InterpolationMode");
break;
}
case EmfPlusRecordTypeSetPixelOffsetMode:
{
- SAL_INFO("drawinglayer", "EMF+\t Pixel offset mode: " << PixelOffsetModeToString(flags));
- SAL_WARN("drawinglayer", "EMF+\t TODO SetPixelOffsetMode");
+ SAL_INFO("drawinglayer.emf", "EMF+\t Pixel offset mode: " << PixelOffsetModeToString(flags));
+ SAL_WARN("drawinglayer.emf", "EMF+\t TODO SetPixelOffsetMode");
break;
}
case EmfPlusRecordTypeSetCompositingQuality:
{
- SAL_INFO("drawinglayer", "EMF+\t TODO SetCompositingQuality");
+ SAL_INFO("drawinglayer.emf", "EMF+\t TODO SetCompositingQuality");
break;
}
case EmfPlusRecordTypeSave:
{
sal_uInt32 stackIndex;
rMS.ReadUInt32(stackIndex);
- SAL_INFO("drawinglayer", "EMF+\t Save stack index: " << stackIndex);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Save stack index: " << stackIndex);
GraphicStatePush(mGSStack, stackIndex);
@@ -1770,36 +1829,36 @@ namespace emfplushelper
{
sal_uInt32 stackIndex;
rMS.ReadUInt32(stackIndex);
- SAL_INFO("drawinglayer", "EMF+\t Restore stack index: " << stackIndex);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Restore stack index: " << stackIndex);
- GraphicStatePop(mGSStack, stackIndex, mrPropertyHolders.Current());
+ GraphicStatePop(mGSStack, stackIndex);
break;
}
case EmfPlusRecordTypeBeginContainer:
{
float dx, dy, dw, dh;
ReadRectangle(rMS, dx, dy, dw, dh);
- SAL_INFO("drawinglayer", "EMF+\t Dest RectData: " << dx << "," << dy << " " << dw << "x" << dh);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Dest RectData: " << dx << "," << dy << " " << dw << "x" << dh);
float sx, sy, sw, sh;
ReadRectangle(rMS, sx, sy, sw, sh);
- SAL_INFO("drawinglayer", "EMF+\t Source RectData: " << sx << "," << sy << " " << sw << "x" << sh);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Source RectData: " << sx << "," << sy << " " << sw << "x" << sh);
sal_uInt32 stackIndex;
rMS.ReadUInt32(stackIndex);
- SAL_INFO("drawinglayer", "EMF+\t Begin Container stack index: " << stackIndex << ", PageUnit: " << flags);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Begin Container stack index: " << stackIndex << ", PageUnit: " << flags);
if ((flags == UnitTypeDisplay) || (flags == UnitTypeWorld))
{
- SAL_WARN("drawinglayer", "EMF+\t file error. UnitTypeDisplay and UnitTypeWorld are not supported by BeginContainer in EMF+ specification.");
+ 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;
@@ -1808,7 +1867,7 @@ namespace emfplushelper
{
sal_uInt32 stackIndex;
rMS.ReadUInt32(stackIndex);
- SAL_INFO("drawinglayer", "EMF+\t Begin Container No Params stack index: " << stackIndex);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Begin Container No Params stack index: " << stackIndex);
GraphicStatePush(mGSContainerStack, stackIndex);
break;
@@ -1817,33 +1876,33 @@ namespace emfplushelper
{
sal_uInt32 stackIndex;
rMS.ReadUInt32(stackIndex);
- SAL_INFO("drawinglayer", "EMF+\t End Container stack index: " << stackIndex);
+ SAL_INFO("drawinglayer.emf", "EMF+\t End Container stack index: " << stackIndex);
- GraphicStatePop(mGSContainerStack, stackIndex, mrPropertyHolders.Current());
+ GraphicStatePop(mGSContainerStack, stackIndex);
break;
}
case EmfPlusRecordTypeSetWorldTransform:
{
- SAL_INFO("drawinglayer", "EMF+\t SetWorldTransform, Post multiply: " << bool(flags & 0x2000));
+ SAL_INFO("drawinglayer.emf", "EMF+\t SetWorldTransform, Post multiply: " << bool(flags & 0x2000));
readXForm(rMS, maWorldTransform);
mappingChanged();
- SAL_INFO("drawinglayer", "EMF+\t\t: " << maWorldTransform);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\t: " << maWorldTransform);
break;
}
case EmfPlusRecordTypeResetWorldTransform:
{
maWorldTransform.identity();
- SAL_INFO("drawinglayer", "EMF+\t World transform: " << maWorldTransform);
+ SAL_INFO("drawinglayer.emf", "EMF+\t World transform: " << maWorldTransform);
mappingChanged();
break;
}
case EmfPlusRecordTypeMultiplyWorldTransform:
{
- SAL_INFO("drawinglayer", "EMF+\t MultiplyWorldTransform, post multiply: " << bool(flags & 0x2000));
+ SAL_INFO("drawinglayer.emf", "EMF+\t MultiplyWorldTransform, post multiply: " << bool(flags & 0x2000));
basegfx::B2DHomMatrix transform;
readXForm(rMS, transform);
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t Transform matrix: " << transform);
if (flags & 0x2000)
@@ -1860,13 +1919,13 @@ namespace emfplushelper
mappingChanged();
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t World transform matrix: " << maWorldTransform);
break;
}
case EmfPlusRecordTypeTranslateWorldTransform:
{
- SAL_INFO("drawinglayer", "EMF+\t TranslateWorldTransform, Post multiply: " << bool(flags & 0x2000));
+ SAL_INFO("drawinglayer.emf", "EMF+\t TranslateWorldTransform, Post multiply: " << bool(flags & 0x2000));
basegfx::B2DHomMatrix transform;
float eDx, eDy;
@@ -1874,7 +1933,7 @@ namespace emfplushelper
transform.set(0, 2, eDx);
transform.set(1, 2, eDy);
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t Translate matrix: " << transform);
if (flags & 0x2000)
@@ -1891,7 +1950,7 @@ namespace emfplushelper
mappingChanged();
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t World transform matrix: " << maWorldTransform);
break;
}
@@ -1903,9 +1962,9 @@ namespace emfplushelper
transform.set(0, 0, eSx);
transform.set(1, 1, eSy);
- SAL_INFO("drawinglayer", "EMF+\t ScaleWorldTransform Sx: " << eSx <<
+ SAL_INFO("drawinglayer.emf", "EMF+\t ScaleWorldTransform Sx: " << eSx <<
" Sy: " << eSy << ", Post multiply:" << bool(flags & 0x2000));
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t World transform matrix: " << maWorldTransform);
if (flags & 0x2000)
@@ -1922,7 +1981,7 @@ namespace emfplushelper
mappingChanged();
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t World transform matrix: " << maWorldTransform);
break;
}
@@ -1932,20 +1991,20 @@ namespace emfplushelper
float eAngle;
rMS.ReadFloat(eAngle);
- SAL_INFO("drawinglayer", "EMF+\t RotateWorldTransform Angle: " << eAngle <<
+ SAL_INFO("drawinglayer.emf", "EMF+\t RotateWorldTransform Angle: " << eAngle <<
", post multiply: " << bool(flags & 0x2000));
// Skipping flags & 0x2000
// For rotation transformation there is no difference between post and pre multiply
maWorldTransform.rotate(basegfx::deg2rad(eAngle));
mappingChanged();
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t " << maWorldTransform);
break;
}
case EmfPlusRecordTypeResetClip:
{
- SAL_INFO("drawinglayer", "EMF+ ResetClip");
+ SAL_INFO("drawinglayer.emf", "EMF+ ResetClip");
// We don't need to read anything more, as Size needs to be set 0x0000000C
// and DataSize must be set to 0.
@@ -1954,74 +2013,107 @@ namespace emfplushelper
break;
}
case EmfPlusRecordTypeSetClipRect:
- {
- int combineMode = (flags >> 8) & 0xf;
-
- SAL_INFO("drawinglayer", "EMF+\t SetClipRect combine mode: " << combineMode);
-
- float dx, dy, dw, dh;
- ReadRectangle(rMS, dx, dy, dw, dh);
- SAL_INFO("drawinglayer", "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+\t SetClipPath combine mode: " << combineMode);
- SAL_INFO("drawinglayer", "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+\t TODO Unable to find path in slot: " << (flags & 0xff));
- break;
+ SAL_INFO("drawinglayer.emf", "EMF+\t SetClipRect");
+
+ 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));
- ::basegfx::B2DPolyPolygon& clipPoly(path->GetPolygon(*this));
-
- HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
- combineMode, clipPoly), mrTargetHolders, mrPropertyHolders);
- break;
- }
- case EmfPlusRecordTypeSetClipRegion:
- {
- int combineMode = (flags >> 8) & 0xf;
- SAL_INFO("drawinglayer", "EMF+\t Region in slot: " << (flags & 0xff));
- SAL_INFO("drawinglayer", "EMF+\t Combine mode: " << combineMode);
- EMFPRegion *region = static_cast<EMFPRegion*>(maEMFPObjects[flags & 0xff].get());
- if (!region)
+ 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_WARN("drawinglayer", "EMF+\t TODO Unable to find region in slot: " << (flags & 0xff));
- break;
+ 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;
}
-
- HandleNewClipRegion(combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
- combineMode, region->regionPolyPolygon), mrTargetHolders, mrPropertyHolders);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Combine mode: " << combineMode);
+ ::basegfx::B2DPolyPolygon aClippedPolyPolygon;
+ if (mrPropertyHolders.Current().getClipPolyPolygonActive())
+ {
+ aClippedPolyPolygon
+ = combineClip(mrPropertyHolders.Current().getClipPolyPolygon(),
+ combineMode, polyPolygon);
+ }
+ 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:
{
float dx, dy;
rMS.ReadFloat(dx).ReadFloat(dy);
- SAL_INFO("drawinglayer", "EMF+\tOffset x:" << dx << ", y:" << dy);
+ SAL_INFO("drawinglayer.emf", "EMF+\tOffset x:" << dx << ", y:" << dy);
basegfx::B2DPolyPolygon aPolyPolygon(
mrPropertyHolders.Current().getClipPolyPolygon());
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t PolyPolygon before translate: " << aPolyPolygon);
basegfx::B2DPoint aOffset = Map(dx, dy);
@@ -2030,7 +2122,7 @@ namespace emfplushelper
transformMatrix.set(1, 2, aOffset.getY());
aPolyPolygon.transform(transformMatrix);
- SAL_INFO("drawinglayer",
+ SAL_INFO("drawinglayer.emf",
"EMF+\t PolyPolygon after translate: " << aPolyPolygon <<
", mapped offset x" << aOffset.getX() << ", mapped offset y" << aOffset.getY());
HandleNewClipRegion(aPolyPolygon, mrTargetHolders, mrPropertyHolders);
@@ -2043,22 +2135,22 @@ namespace emfplushelper
sal_uInt32 hasMatrix;
sal_uInt32 glyphsCount;
rMS.ReadUInt32(brushIndexOrColor).ReadUInt32(optionFlags).ReadUInt32(hasMatrix).ReadUInt32(glyphsCount);
- SAL_INFO("drawinglayer", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
- SAL_INFO("drawinglayer", "EMF+\t Option flags: 0x" << std::hex << optionFlags << std::dec);
- SAL_INFO("drawinglayer", "EMF+\t Has matrix: " << hasMatrix);
- SAL_INFO("drawinglayer", "EMF+\t Glyphs: " << glyphsCount);
+ SAL_INFO("drawinglayer.emf", "EMF+\t " << ((flags & 0x8000) ? "Color" : "Brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Option flags: 0x" << std::hex << optionFlags << std::dec);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Has matrix: " << hasMatrix);
+ SAL_INFO("drawinglayer.emf", "EMF+\t Glyphs: " << glyphsCount);
if ((optionFlags & 1) && glyphsCount > 0)
{
std::unique_ptr<float[]> charsPosX(new float[glyphsCount]);
std::unique_ptr<float[]> charsPosY(new float[glyphsCount]);
OUString text = read_uInt16s_ToOUString(rMS, glyphsCount);
- SAL_INFO("drawinglayer", "EMF+\t DrawDriverString string: " << text);
+ SAL_INFO("drawinglayer.emf", "EMF+\t DrawDriverString string: " << text);
for (sal_uInt32 i = 0; i<glyphsCount; i++)
{
rMS.ReadFloat(charsPosX[i]).ReadFloat(charsPosY[i]);
- SAL_INFO("drawinglayer", "EMF+\t\t glyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
+ SAL_INFO("drawinglayer.emf", "EMF+\t\t glyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
}
basegfx::B2DHomMatrix transform;
@@ -2066,11 +2158,11 @@ namespace emfplushelper
if (hasMatrix)
{
readXForm(rMS, transform);
- SAL_INFO("drawinglayer", "EMF+\tmatrix: " << transform);
+ SAL_INFO("drawinglayer.emf", "EMF+\tmatrix: " << transform);
}
// 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;
@@ -2090,7 +2182,6 @@ namespace emfplushelper
false); // BiDiStrong
const Color color = EMFPGetBrushColorOrARGBColor(flags, brushIndexOrColor);
- std::vector<double> aDXArray; // dummy for DX array (not used)
// generate TextSimplePortionPrimitive2Ds or TextDecoratedPortionPrimitive2D
// for all portions of text with the same charsPosY values
@@ -2103,7 +2194,7 @@ namespace emfplushelper
aLength++;
// generate the DX-Array
- aDXArray.clear();
+ std::vector<double> aDXArray;
for (size_t i = 0; i < aLength - 1; i++)
{
aDXArray.push_back(charsPosX[pos + i + 1] - charsPosX[pos]);
@@ -2112,13 +2203,13 @@ 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;
if (color.GetAlpha() > 0)
{
- drawinglayer::primitive2d::BasePrimitive2D* pBaseText = nullptr;
+ rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> pBaseText;
if (font->Underline() || font->Strikeout())
{
pBaseText = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
@@ -2126,7 +2217,8 @@ namespace emfplushelper
text,
pos, // take character at current pos
aLength, // use determined length
- aDXArray, // generated DXArray
+ std::move(aDXArray), // generated DXArray
+ {},
fontAttribute,
Application::GetSettings().GetLanguageTag().getLocale(),
color.getBColor(),
@@ -2145,7 +2237,8 @@ namespace emfplushelper
text,
pos, // take character at current pos
aLength, // use determined length
- aDXArray, // generated DXArray
+ std::move(aDXArray), // generated DXArray
+ {},
fontAttribute,
Application::GetSettings().GetLanguageTag().getLocale(),
color.getBColor());
@@ -2158,7 +2251,7 @@ namespace emfplushelper
(255 - color.GetAlpha()) / 255.0);
}
mrTargetHolders.Current().append(
- std::make_unique<drawinglayer::primitive2d::TransformPrimitive2D>(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
maMapTransform,
drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText } ));
}
@@ -2169,13 +2262,13 @@ namespace emfplushelper
}
else
{
- SAL_WARN("drawinglayer", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
+ SAL_WARN("drawinglayer.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
}
break;
}
default:
{
- SAL_WARN("drawinglayer", "EMF+ TODO unhandled record type: 0x" << std::hex << type << std::dec);
+ SAL_WARN("drawinglayer.emf", "EMF+ TODO unhandled record type: 0x" << std::hex << type << std::dec);
}
}
}
@@ -2188,7 +2281,7 @@ namespace emfplushelper
}
else
{
- SAL_WARN("drawinglayer", "ImplRenderer::processEMFPlus: "
+ SAL_WARN("drawinglayer.emf", "ImplRenderer::processEMFPlus: "
"size " << size << " > length " << length);
length = 0;
}