EMF+ tdf#142975 Add brush support to DrawString record
Change-Id: Icfcb4199dcd755fb20e14a8166571b6d6e763f2e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117671
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
(cherry picked from commit 9e8c35cc3f1f5e1c08afd46e0d0fbc07f1ff21f9)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117721
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx
index 1f31431..e756b16 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -457,12 +457,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 = static_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;
@@ -1527,161 +1529,152 @@ namespace emfplushelper
}
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", "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);
if (flags & 0x8000)
// 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 = static_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);
break;
}
mrPropertyHolders.Current().setFont(vcl::Font(font->family, Size(font->emSize, font->emSize)));
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 = static_cast< EMFPFont* >( maEMFPObjects[flags & 0xff].get() );
if (!font)
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", "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)
{
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;
if (stringFormat)
stringAlignmentHorizontalOffset = stringFormat->leadingMargin * font->emSize;
} else if (stringFormat->stringAlignment == StringAlignmentCenter)
// Alignment is centered between the origin and extent of the layout rectangle
{
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)
// 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)
// Alignment is to the right side of the layout rectangle
{
stringAlignmentHorizontalOffset = lw - stringFormat->trailingMargin * font->emSize - 0.6 * font->emSize * stringLength;
}
LanguageTag aLanguageTag(static_cast< LanguageType >(stringFormat->language));
locale = aLanguageTag.getLocale();
}
else
stringAlignmentHorizontalOffset = 0.5 * lw + stringFormat->leadingMargin * font->emSize - 0.3 * font->emSize * stringLength;
} else if (stringFormat->stringAlignment == StringAlignmentFar)
// Alignment is to the right side of the layout rectangle
{
// 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();
stringAlignmentHorizontalOffset = lw - stringFormat->trailingMargin * font->emSize - 0.6 * font->emSize * stringLength;
}
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;
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;
}
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())
{
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(
new drawinglayer::primitive2d::TransformPrimitive2D(
maMapTransform,
drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText } ));
}
LanguageTag aLanguageTag(static_cast< LanguageType >(stringFormat->language));
locale = aLanguageTag.getLocale();
}
else
{
SAL_WARN("drawinglayer.emf", "EMF+\t DrawString TODO - drawing with brush not yet supported");
// 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();
}
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;
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;
}
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())
{
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(), // 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
{
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(
new drawinglayer::primitive2d::TransformPrimitive2D(
maMapTransform,
drawinglayer::primitive2d::Primitive2DContainer { aPrimitiveText } ));
}
break;
}
diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx
index 9ed0e79..4b0c47f 100644
--- a/drawinglayer/source/tools/primitive2dxmldump.cxx
+++ b/drawinglayer/source/tools/primitive2dxmldump.cxx
@@ -25,6 +25,8 @@
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
#include <primitive2d/textlineprimitive2d.hxx>
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
@@ -56,6 +58,19 @@ OUString convertColorToString(const basegfx::BColor& rColor)
return "#" + aRGBString;
}
void writeMatrix(::tools::XmlWriter& rWriter, const basegfx::B2DHomMatrix& rMatrix)
{
rWriter.attribute("xy11", rMatrix.get(0,0));
rWriter.attribute("xy12", rMatrix.get(0,1));
rWriter.attribute("xy13", rMatrix.get(0,2));
rWriter.attribute("xy21", rMatrix.get(1,0));
rWriter.attribute("xy22", rMatrix.get(1,1));
rWriter.attribute("xy23", rMatrix.get(1,2));
rWriter.attribute("xy31", rMatrix.get(2,0));
rWriter.attribute("xy32", rMatrix.get(2,1));
rWriter.attribute("xy33", rMatrix.get(2,2));
}
void writePolyPolygon(::tools::XmlWriter& rWriter, const basegfx::B2DPolyPolygon& rB2DPolyPolygon)
{
rWriter.startElement("polypolygon");
@@ -211,17 +226,7 @@ void Primitive2dXmlDump::decomposeAndWrite(
{
const BitmapPrimitive2D& rBitmapPrimitive2D = dynamic_cast<const BitmapPrimitive2D&>(*pBasePrimitive);
rWriter.startElement("bitmap");
basegfx::B2DHomMatrix const & rMatrix = rBitmapPrimitive2D.getTransform();
rWriter.attribute("xy11", rMatrix.get(0,0));
rWriter.attribute("xy12", rMatrix.get(0,1));
rWriter.attribute("xy13", rMatrix.get(0,2));
rWriter.attribute("xy21", rMatrix.get(1,0));
rWriter.attribute("xy22", rMatrix.get(1,1));
rWriter.attribute("xy23", rMatrix.get(1,2));
rWriter.attribute("xy31", rMatrix.get(2,0));
rWriter.attribute("xy32", rMatrix.get(2,1));
rWriter.attribute("xy33", rMatrix.get(2,2));
writeMatrix(rWriter, rBitmapPrimitive2D.getTransform());
const BitmapEx aBitmapEx(VCLUnoHelper::GetBitmap(rBitmapPrimitive2D.getXBitmap()));
const Size& rSizePixel(aBitmapEx.GetSizePixel());
@@ -260,18 +265,7 @@ void Primitive2dXmlDump::decomposeAndWrite(
{
const TransformPrimitive2D& rTransformPrimitive2D = dynamic_cast<const TransformPrimitive2D&>(*pBasePrimitive);
rWriter.startElement("transform");
basegfx::B2DHomMatrix const & rMatrix = rTransformPrimitive2D.getTransformation();
rWriter.attributeDouble("xy11", rMatrix.get(0,0));
rWriter.attributeDouble("xy12", rMatrix.get(0,1));
rWriter.attributeDouble("xy13", rMatrix.get(0,2));
rWriter.attributeDouble("xy21", rMatrix.get(1,0));
rWriter.attributeDouble("xy22", rMatrix.get(1,1));
rWriter.attributeDouble("xy23", rMatrix.get(1,2));
rWriter.attributeDouble("xy31", rMatrix.get(2,0));
rWriter.attributeDouble("xy32", rMatrix.get(2,1));
rWriter.attributeDouble("xy33", rMatrix.get(2,2));
writeMatrix(rWriter, rTransformPrimitive2D.getTransformation());
decomposeAndWrite(rTransformPrimitive2D.getChildren(), rWriter);
rWriter.endElement();
}
@@ -355,7 +349,35 @@ void Primitive2dXmlDump::decomposeAndWrite(
rWriter.content(basegfx::utils::exportToSvgPoints(rPolygonHairlinePrimitive2D.getB2DPolygon()));
rWriter.endElement();
rWriter.endElement();
}
break;
case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D:
{
const TextDecoratedPortionPrimitive2D& rTextDecoratedPortionPrimitive2D = dynamic_cast<const TextDecoratedPortionPrimitive2D&>(*pBasePrimitive);
rWriter.startElement("textdecoratedportion");
writeMatrix(rWriter, rTextDecoratedPortionPrimitive2D.getTextTransform());
rWriter.attribute("text", rTextDecoratedPortionPrimitive2D.getText());
rWriter.attribute("fontcolor", convertColorToString(rTextDecoratedPortionPrimitive2D.getFontColor()));
const drawinglayer::attribute::FontAttribute& aFontAttribute = rTextDecoratedPortionPrimitive2D.getFontAttribute();
rWriter.attribute("familyname", aFontAttribute.getFamilyName());
rWriter.endElement();
}
break;
case PRIMITIVE2D_ID_TEXTLINEPRIMITIVE2D:
{
const TextLinePrimitive2D& rTextLinePrimitive2D = dynamic_cast<const TextLinePrimitive2D&>(*pBasePrimitive);
rWriter.startElement("textline");
writeMatrix(rWriter, rTextLinePrimitive2D.getObjectTransformation());
rWriter.attribute("width", rTextLinePrimitive2D.getWidth());
rWriter.attribute("offset", rTextLinePrimitive2D.getOffset());
rWriter.attribute("height", rTextLinePrimitive2D.getHeight());
rWriter.attribute("color", convertColorToString(rTextLinePrimitive2D.getLineColor()));
rWriter.endElement();
}
break;
@@ -406,9 +428,8 @@ void Primitive2dXmlDump::decomposeAndWrite(
{
const UnifiedTransparencePrimitive2D& rUnifiedTransparencePrimitive2D = dynamic_cast<const UnifiedTransparencePrimitive2D&>(*pBasePrimitive);
rWriter.startElement("unifiedtransparence");
rWriter.attribute("transparence", OString::number(rUnifiedTransparencePrimitive2D.getTransparence()));
rWriter.attribute("transparence", std::lround(100 * rUnifiedTransparencePrimitive2D.getTransparence()));
decomposeAndWrite(rUnifiedTransparencePrimitive2D.getChildren(), rWriter);
rWriter.endElement();
}
break;
@@ -452,16 +473,7 @@ void Primitive2dXmlDump::decomposeAndWrite(
rWriter.attributeDouble("opacity", rSvgLinearGradientPrimitive2D.getGradientEntries().front().getOpacity());
rWriter.startElement("transform");
basegfx::B2DHomMatrix const & rMatrix = rSvgLinearGradientPrimitive2D.getGradientTransform();
rWriter.attributeDouble("xy11", rMatrix.get(0,0));
rWriter.attributeDouble("xy12", rMatrix.get(0,1));
rWriter.attributeDouble("xy13", rMatrix.get(0,2));
rWriter.attributeDouble("xy21", rMatrix.get(1,0));
rWriter.attributeDouble("xy22", rMatrix.get(1,1));
rWriter.attributeDouble("xy23", rMatrix.get(1,2));
rWriter.attributeDouble("xy31", rMatrix.get(2,0));
rWriter.attributeDouble("xy32", rMatrix.get(2,1));
rWriter.attributeDouble("xy33", rMatrix.get(2,2));
writeMatrix(rWriter, rSvgLinearGradientPrimitive2D.getGradientTransform());
rWriter.endElement();
writePolyPolygon(rWriter, rSvgLinearGradientPrimitive2D.getPolyPolygon());
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 1383b5f..34288bc 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -48,6 +48,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest:
void testPolyPolygon();
void TestDrawString();
void TestDrawStringTransparent();
void TestDrawStringWithBrush();
void TestDrawLine();
void TestLinearGradient();
void TestTextMapMode();
@@ -87,6 +88,7 @@ public:
CPPUNIT_TEST(testPolyPolygon);
CPPUNIT_TEST(TestDrawString);
CPPUNIT_TEST(TestDrawStringTransparent);
CPPUNIT_TEST(TestDrawStringWithBrush);
CPPUNIT_TEST(TestDrawLine);
CPPUNIT_TEST(TestLinearGradient);
CPPUNIT_TEST(TestTextMapMode);
@@ -189,10 +191,9 @@ void Test::testPolyPolygon()
void Test::TestDrawString()
{
#if HAVE_MORE_FONTS
// This unit checks for a correct import of an EMF+ file with only one DrawString Record
// EMF+ file with only one DrawString Record
// Since the text is undecorated the optimal choice is a simpletextportion primitive
// first, get the sequence of primitives and dump it
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestDrawString.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
@@ -212,17 +213,15 @@ void Test::TestDrawString()
void Test::TestDrawStringTransparent()
{
#if HAVE_MORE_FONTS
// This unit checks for a correct import of an EMF+ file with one DrawString Record with transparency
// EMF+ file with one DrawString Record with transparency
// first, get the sequence of primitives and dump it
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestDrawStringTransparent.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
CPPUNIT_ASSERT (pDocument);
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/transform/unifiedtransparence", "transparence", "0.498039215686275");
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/transform/unifiedtransparence", "transparence", "50");
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/transform/unifiedtransparence/textsimpleportion", "height", "24");
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/transform/unifiedtransparence/textsimpleportion", "x", "66");
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/transform/unifiedtransparence/textsimpleportion", "y", "74");
@@ -232,12 +231,27 @@ void Test::TestDrawStringTransparent()
#endif
}
void Test::TestDrawStringWithBrush()
{
// tdf#142975 EMF+ with records: DrawString, Brush and Font
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestDrawStringWithBrush.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
CPPUNIT_ASSERT (pDocument);
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "xy11", "20");
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "xy13", "16");
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "xy22", "20");
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "xy33", "1");
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "text", "0123456789ABCDEF");
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "fontcolor", "#a50021");
assertXPath(pDocument, "/primitive2D/metafile/transform/transform/textdecoratedportion", "familyname", "TIMES NEW ROMAN");
}
void Test::TestDrawLine()
{
// This unit checks for a correct import of an EMF+ file with only one DrawLine Record
// EMF+ with records: DrawLine
// The line is colored and has a specified width, therefore a polypolygonstroke primitive is the optimal choice
// first, get the sequence of primitives and dump it
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestDrawLine.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
@@ -251,18 +265,18 @@ void Test::TestDrawLine()
void Test::TestLinearGradient()
{
// This unit checks for a correct import of an EMF+ file with LinearGradient brush
// EMF+ file with LinearGradient brush
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestLinearGradient.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
CPPUNIT_ASSERT (pDocument);
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy11", "1.0000656512605");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy11", "1");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy12", "0");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy13", "0");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy21", "0");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy22", "1.00013140604468");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy22", "1");
assertXPath(pDocument, "/primitive2D/metafile/transform", "xy23", "0");
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygon", "height", "7610");
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygon", "width", "15232");
@@ -284,7 +298,7 @@ void Test::TestLinearGradient()
void Test::TestTextMapMode()
{
// Check import of EMF image with records: SETMAPMODE with MM_TEXT MapMode, POLYLINE16, EXTCREATEPEN, EXTTEXTOUTW
// EMF with records: SETMAPMODE with MM_TEXT MapMode, POLYLINE16, EXTCREATEPEN, EXTTEXTOUTW
// MM_TEXT is mapped to one device pixel. Positive x is to the right; positive y is down.
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TextMapMode.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
@@ -318,7 +332,7 @@ void Test::TestTextMapMode()
void Test::TestEnglishMapMode()
{
// Check import of EMF image with records: SETMAPMODE with MM_ENGLISH MapMode, STROKEANDFILLPATH, EXTTEXTOUTW, SETTEXTALIGN, STRETCHDIBITS
// EMF image with records: SETMAPMODE with MM_ENGLISH MapMode, STROKEANDFILLPATH, EXTTEXTOUTW, SETTEXTALIGN, STRETCHDIBITS
// MM_LOENGLISH is mapped to 0.01 inch. Positive x is to the right; positive y is up.M
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/test_mm_hienglish_ref.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
@@ -351,7 +365,7 @@ void Test::TestEnglishMapMode()
void Test::TestRectangleWithModifyWorldTransform()
{
// Check import of EMF image with records: EXTCREATEPEN, SELECTOBJECT, MODIFYWORLDTRANSFORM, RECTANGLE
// EMF image with records: EXTCREATEPEN, SELECTOBJECT, MODIFYWORLDTRANSFORM, RECTANGLE
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestRectangleWithModifyWorldTransform.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
@@ -452,7 +466,7 @@ void Test::TestEllipseXformIntersectClipRect()
void Test::TestDrawPolyLine16WithClip()
{
// Check import of EMF image with records:
// EMF image with records:
// CREATEBRUSHINDIRECT, FILLRGN, BEGINPATH, POLYGON16, SELECTCLIPPATH, MODIFYWORLDTRANSFORM, SELECTOBJECT
Primitive2DSequence aSequence = parseEmf(u"/emfio/qa/cppunit/emf/data/TestDrawPolyLine16WithClip.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
diff --git a/emfio/qa/cppunit/emf/data/TestDrawStringWithBrush.emf b/emfio/qa/cppunit/emf/data/TestDrawStringWithBrush.emf
new file mode 100644
index 0000000..3afb53e
--- /dev/null
+++ b/emfio/qa/cppunit/emf/data/TestDrawStringWithBrush.emf
Binary files differ
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx
index e089558..25baf76 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -381,7 +381,7 @@ void Test::testTdf79163()
CPPUNIT_ASSERT (pDocument);
assertXPath(pDocument, "/primitive2D/transform/unifiedtransparence", "transparence", "0.5");
assertXPath(pDocument, "/primitive2D/transform/unifiedtransparence", "transparence", "50");
}
void Test::testTdf97542_1()
@@ -464,7 +464,7 @@ void Test::testRGBAColor()
CPPUNIT_ASSERT (pDocument);
assertXPath(pDocument, "/primitive2D/transform/unifiedtransparence", "transparence", "0.5");
assertXPath(pDocument, "/primitive2D/transform/unifiedtransparence", "transparence", "50");
}
void Test::testNoneColor()
diff --git a/svx/qa/unit/sdr.cxx b/svx/qa/unit/sdr.cxx
index f6eb744..10f9901 100644
--- a/svx/qa/unit/sdr.cxx
+++ b/svx/qa/unit/sdr.cxx
@@ -86,15 +86,15 @@ CPPUNIT_TEST_FIXTURE(SdrTest, testShadowScaleOrigin)
// Examine the created primitives.
drawinglayer::Primitive2dXmlDump aDumper;
xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence);
double fShadowX = getXPath(pDocument, "//shadow/transform", "xy13").toDouble();
double fShadowY = getXPath(pDocument, "//shadow/transform", "xy23").toDouble();
sal_Int32 fShadowX = getXPath(pDocument, "//shadow/transform", "xy13").toInt32();
sal_Int32 fShadowY = getXPath(pDocument, "//shadow/transform", "xy23").toInt32();
// Without the accompanying fix in place, this test would have failed with:
// - Expected: -705
// - Actual : -158
// i.e. the shadow origin was not the top right corner for scaling (larger x position, so it was
// visible on the right of the shape as well).
CPPUNIT_ASSERT_EQUAL(-705., std::round(fShadowX));
CPPUNIT_ASSERT_EQUAL(-685., std::round(fShadowY));
CPPUNIT_ASSERT_EQUAL(sal_Int32(-705), fShadowX);
CPPUNIT_ASSERT_EQUAL(sal_Int32(-684), fShadowY);
}
CPPUNIT_TEST_FIXTURE(SdrTest, testZeroWidthTextWrap)
diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx
index d6e43d6..fa344d8 100644
--- a/svx/qa/unit/svdraw.cxx
+++ b/svx/qa/unit/svdraw.cxx
@@ -110,9 +110,9 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testSemiTransparentText)
// - Actual : 0
// - XPath '//unifiedtransparence' number of nodes is incorrect
// i.e. the text was just plain red, not semi-transparent.
double fTransparence = getXPath(pDocument, "//unifiedtransparence", "transparence").toDouble();
CPPUNIT_ASSERT_EQUAL(nTransparence,
static_cast<sal_Int16>(basegfx::fround(fTransparence * 100)));
sal_Int16 fTransparence
= getXPath(pDocument, "//unifiedtransparence", "transparence").toInt32();
CPPUNIT_ASSERT_EQUAL(nTransparence, fTransparence);
}
CPPUNIT_TEST_FIXTURE(SvdrawTest, testHandlePathObjScale)