summaryrefslogtreecommitdiff
path: root/drawinglayer/source
diff options
context:
space:
mode:
authorPatrick Jaap <patrick.jaap@tu-dresden.de>2017-08-07 13:17:05 +0200
committerBartosz Kosiorek <gang65@poczta.onet.pl>2017-08-08 09:47:59 +0200
commit70dd00331e3112e7c32d5c7ac121ad7e77535817 (patch)
tree87c987b7c45ba05b3f5a51a2d4b9e0386c902b3b /drawinglayer/source
parenta3c695c12386c2708a0c06ec0ccd42ee2b8aeb98 (diff)
new EMF+ Parser: Implementation of fillPolygon
This implementation replaces hte old one. It uses the workaround hatch blending from the old implentation (basically just copied) It provides correct linear gradients, with correct transformations PathGradients are approximated via RadialGradients. Also, there is a better line width choice, solving problems caused by pictures like tdf#38580. Change-Id: Ida4f36a5de83b6325702a153b642abe5e45982ee Reviewed-on: https://gerrit.libreoffice.org/40831 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
Diffstat (limited to 'drawinglayer/source')
-rw-r--r--drawinglayer/source/tools/emfphelperdata.cxx203
1 files changed, 196 insertions, 7 deletions
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx
index d5249b1c5d39..0aac3e95f6f5 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -28,6 +28,8 @@
#include <basegfx/curve/b2dcubicbezier.hxx>
#include <wmfemfhelper.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
#include <drawinglayer/attribute/fontattribute.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
@@ -348,7 +350,15 @@ namespace emfplushelper
SAL_WARN_IF(pen->startCap != pen->endCap, "cppcanvas.emf", "emf+ pen uses different start and end cap");
}
// transform the pen width
- const double transformedPenWidth = MapSize(pen->penWidth, 0).getX();
+ double adjustedPenWidth = pen->penWidth;
+ if (!pen->penWidth) // no width specified, then use default value
+ {
+ adjustedPenWidth = pen->penUnit == 0 ? 0.18f // 0.18f is determined by comparison with MSO (case of Unit == World)
+ : 0.05f; // 0.05f is taken from old EMF+ implementation (case of Unit == Pixel etc.)
+ }
+
+ // transform and compare to 5 (the value 5 is determined by comparison to MSO)
+ const double transformedPenWidth = std::max( MapSize(adjustedPenWidth,0).getX() , 5.);
drawinglayer::attribute::LineAttribute lineAttribute(pen->GetColor().getBColor(),
transformedPenWidth,
lineJoin,
@@ -362,14 +372,193 @@ namespace emfplushelper
void EmfPlusHelperData::EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, bool isColor, sal_uInt32 brushIndexOrColor)
{
- if (polygon.count())
+ if (!polygon.count())
+ return;
+
+ SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
+ if (isColor) // use Color
{
- if (isColor)
+ mrTargetHolders.Current().append(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ polygon,
+ ::Color(0xff - (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff).getBColor()));
+ }
+ else // use Brush
+ {
+ EMFPBrush* brush = static_cast<EMFPBrush*>( maEMFPObjects[brushIndexOrColor & 0xff].get() );
+ SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor << " (type: " << (brush ? brush->GetType() : -1) << ")");
+
+ // give up in case something wrong happened
+ if( !brush )
+ return;
+ if (brush->type == BrushTypeHatchFill)
+ {
+ // EMF+ like hatching is currently not supported. These are just color blends which serve as an approximation for some of them
+ // for the others the hatch "background" color (secondColor in brush) is used.
+
+ bool isHatchBlend = true;
+ double blendFactor = 0.0;
+
+ switch (brush->hatchStyle)
+ {
+ case HatchStyle05Percent: blendFactor = 0.05; break;
+ case HatchStyle10Percent: blendFactor = 0.10; break;
+ case HatchStyle20Percent: blendFactor = 0.20; break;
+ case HatchStyle25Percent: blendFactor = 0.25; break;
+ case HatchStyle30Percent: blendFactor = 0.30; break;
+ case HatchStyle40Percent: blendFactor = 0.40; break;
+ case HatchStyle50Percent: blendFactor = 0.50; break;
+ case HatchStyle60Percent: blendFactor = 0.60; break;
+ case HatchStyle70Percent: blendFactor = 0.70; break;
+ case HatchStyle75Percent: blendFactor = 0.75; break;
+ case HatchStyle80Percent: blendFactor = 0.80; break;
+ case HatchStyle90Percent: blendFactor = 0.90; break;
+ default:
+ isHatchBlend = false;
+ break;
+ }
+ ::Color fillColor;
+ if (isHatchBlend)
+ {
+ fillColor = brush->solidColor;
+ fillColor.Merge(brush->secondColor, static_cast<sal_uInt8>(255 * blendFactor));
+ }
+ else
+ {
+ fillColor = brush->secondColor;
+ }
+ EMFPPlusFillPolygon(polygon,true,fillColor.GetRGBColor());
+ }
+ else if (brush->type == BrushTypeTextureFill)
{
- mrTargetHolders.Current().append(
- new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
- polygon,
- ::Color(0xff - (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff).getBColor()));
+ SAL_WARN("cppcanvas.emf", "EMF+\tTODO: implement BrushTypeTextureFill brush");
+ }
+ else if (brush->type == BrushTypePathGradient || brush->type == BrushTypeLinearGradient)
+
+ {
+ if (brush->type == BrushTypePathGradient && !(brush->additionalFlags & 0x1))
+ {
+ SAL_WARN("cppcanvas.emf", "EMF+\t TODO Verify proper displaying of BrushTypePathGradient with flags: " << std::hex << brush->additionalFlags << std::dec);
+ }
+ ::basegfx::B2DHomMatrix aTextureTransformation;
+
+ if (brush->hasTransformation) {
+ aTextureTransformation *= brush->brush_transformation;
+ }
+
+ // adjust aTextureTransformation for our world space:
+ // -> revert the mapping -> apply the transformation -> map back
+ basegfx::B2DHomMatrix aInvertedMapTrasform(maMapTransform);
+ aInvertedMapTrasform.invert();
+ aTextureTransformation = maMapTransform * aTextureTransformation * aInvertedMapTrasform;
+
+ // select the stored colors
+ basegfx::BColor aStartColor = brush->solidColor.getBColor();
+ basegfx::BColor aEndColor = brush->secondColor.getBColor();
+ drawinglayer::primitive2d::SvgGradientEntryVector aVector;
+
+ if (brush->blendPositions)
+ {
+ SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
+
+ // store the blendpoints in the vector
+ for (int i = 0; i < brush->blendPoints; i++)
+ {
+ double aBlendPoint;
+ 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() * (1. - brush->blendFactors[i]) + aEndColor.getGreen() * brush->blendFactors[i] );
+ aColor.setBlue ( aStartColor.getBlue() * (1. - brush->blendFactors[i]) + aEndColor.getBlue() * brush->blendFactors[i] );
+ aColor.setRed ( aStartColor.getRed() * (1. - brush->blendFactors[i]) + aEndColor.getRed() * brush->blendFactors[i] );
+ aVector.push_back( drawinglayer::primitive2d::SvgGradientEntry(aBlendPoint, aColor, 1.) );
+ }
+ }
+ else if (brush->colorblendPositions)
+ {
+ SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
+
+ // store the colorBlends in the vector
+ for (int 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.push_back( drawinglayer::primitive2d::SvgGradientEntry(aBlendPoint, aColor, 1.) );
+ }
+ }
+ else // ok, no extra points: just start and end
+ {
+ if (brush->type == BrushTypeLinearGradient)
+ {
+ aVector.push_back( drawinglayer::primitive2d::SvgGradientEntry(0.0, aStartColor, 1.) );
+ aVector.push_back( drawinglayer::primitive2d::SvgGradientEntry(1.0, aEndColor, 1.) );
+ }
+ else // again, here reverse
+ {
+ aVector.push_back( drawinglayer::primitive2d::SvgGradientEntry(0.0, aEndColor, 1.) );
+ aVector.push_back( drawinglayer::primitive2d::SvgGradientEntry(1.0, aStartColor, 1.) );
+ }
+ }
+
+ // get the polygon range to be able to map the start/end/center point correctly
+ // threrefore, create a mapping and invert it
+ basegfx::B2DRange aPolygonRange= polygon.getB2DRange();
+ basegfx::B2DHomMatrix aPolygonTransformation = basegfx::tools::createScaleTranslateB2DHomMatrix(
+ aPolygonRange.getWidth(),aPolygonRange.getHeight(),
+ aPolygonRange.getMinX(), aPolygonRange.getMinY());
+ aPolygonTransformation.invert();
+
+ if (brush->type == BrushTypeLinearGradient)
+ {
+ basegfx::B2DPoint aStartPoint = Map(brush->areaX,brush->areaY);
+ aStartPoint = aPolygonTransformation * aStartPoint;
+ basegfx::B2DPoint aEndPoint = Map(brush->areaX + brush->areaWidth ,brush->areaY + brush->areaHeight);
+ aEndPoint = aPolygonTransformation * aEndPoint;
+
+ // create the same one used for SVG
+ mrTargetHolders.Current().append(
+ new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
+ aTextureTransformation,
+ polygon,
+ aVector,
+ aStartPoint,
+ aEndPoint,
+ false, // do not use UnitCoordinates
+ drawinglayer::primitive2d::SpreadMethod::Pad));
+ }
+ else // BrushTypePathGradient
+ {
+ basegfx::B2DPoint aCenterPoint = Map(brush->areaX,brush->areaY);
+ aCenterPoint = aPolygonTransformation * aCenterPoint;
+
+ // create the same one used for SVG
+ mrTargetHolders.Current().append(
+ new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
+ aTextureTransformation,
+ polygon,
+ aVector,
+ aCenterPoint,
+ 0.5, // relative radius
+ true, // use UnitCoordinates to strectch the gradient
+ drawinglayer::primitive2d::SpreadMethod::Repeat,
+ nullptr));
+ }
}
}
}