tdf#35986 tdf#92315 tdf#116335 tdf#116622 Add support for MapMode TEXT
To properly import some EMF files, the proper implementation of MapMode Text needs to be done according to MS documentation. I have also added regression tests. Change-Id: Id788294a498b93bebb62118d13ea545f80a60f01 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105771 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
committed by
Tomaž Vajngerl
parent
fc351e37d6
commit
b0b78838e7
@@ -16,6 +16,7 @@
|
||||
#include <memory>
|
||||
#include <sal/log.hxx>
|
||||
|
||||
#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
|
||||
#include <drawinglayer/primitive2d/Tools.hxx>
|
||||
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
|
||||
@@ -206,7 +207,50 @@ void Primitive2dXmlDump::decomposeAndWrite(
|
||||
rWriter.endElement();
|
||||
}
|
||||
break;
|
||||
case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D:
|
||||
{
|
||||
const PointArrayPrimitive2D& rPointArrayPrimitive2D = dynamic_cast<const PointArrayPrimitive2D&>(*pBasePrimitive);
|
||||
rWriter.startElement("pointarray");
|
||||
|
||||
rWriter.attribute("color", convertColorToString(rPointArrayPrimitive2D.getRGBColor()));
|
||||
|
||||
const std::vector< basegfx::B2DPoint > aPositions = rPointArrayPrimitive2D.getPositions();
|
||||
for (std::vector<basegfx::B2DPoint>::const_iterator iter = aPositions.begin(); iter != aPositions.end(); ++iter)
|
||||
{
|
||||
rWriter.startElement("point");
|
||||
rWriter.attribute("x", OUString::number(iter->getX()));
|
||||
rWriter.attribute("y", OUString::number(iter->getY()));
|
||||
rWriter.endElement();
|
||||
}
|
||||
|
||||
rWriter.endElement();
|
||||
}
|
||||
break;
|
||||
case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
|
||||
{
|
||||
const PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D = dynamic_cast<const PolygonStrokePrimitive2D&>(*pBasePrimitive);
|
||||
rWriter.startElement("polygonstroke");
|
||||
|
||||
rWriter.startElement("polygon");
|
||||
rWriter.content(basegfx::utils::exportToSvgPoints(rPolygonStrokePrimitive2D.getB2DPolygon()));
|
||||
rWriter.endElement();
|
||||
|
||||
rWriter.startElement("line");
|
||||
const drawinglayer::attribute::LineAttribute& aLineAttribute = rPolygonStrokePrimitive2D.getLineAttribute();
|
||||
rWriter.attribute("color", convertColorToString(aLineAttribute.getColor()));
|
||||
rWriter.attribute("width", aLineAttribute.getWidth());
|
||||
|
||||
rWriter.endElement();
|
||||
|
||||
rWriter.startElement("stroke");
|
||||
const drawinglayer::attribute::StrokeAttribute& aStrokeAttribute = rPolygonStrokePrimitive2D.getStrokeAttribute();
|
||||
rWriter.attribute("fulldotdashlen", aStrokeAttribute.getFullDotDashLen());
|
||||
//rWriter.attribute("dotdasharray", aStrokeAttribute.getDotDashArray());
|
||||
rWriter.endElement();
|
||||
|
||||
rWriter.endElement();
|
||||
}
|
||||
break;
|
||||
case PRIMITIVE2D_ID_POLYPOLYGONSTROKEPRIMITIVE2D:
|
||||
{
|
||||
const PolyPolygonStrokePrimitive2D& rPolyPolygonStrokePrimitive2D = dynamic_cast<const PolyPolygonStrokePrimitive2D&>(*pBasePrimitive);
|
||||
@@ -434,6 +478,7 @@ void Primitive2dXmlDump::decomposeAndWrite(
|
||||
{
|
||||
rWriter.startElement("unhandled");
|
||||
rWriter.attribute("id", OUStringToOString(sCurrentElementTag, RTL_TEXTENCODING_UTF8));
|
||||
rWriter.attribute("idNumber", nId);
|
||||
drawinglayer::primitive2d::Primitive2DContainer aPrimitiveContainer;
|
||||
pBasePrimitive->get2DDecomposition(aPrimitiveContainer,
|
||||
drawinglayer::geometry::ViewInformation2D());
|
||||
|
@@ -44,13 +44,12 @@ class Test : public test::BootstrapFixture, public XmlTestTools, public unotest:
|
||||
{
|
||||
uno::Reference<lang::XComponent> mxComponent;
|
||||
|
||||
void checkRectPrimitive(Primitive2DSequence const & rPrimitive);
|
||||
|
||||
void testWorking();
|
||||
void testPolyPolygon();
|
||||
void TestDrawString();
|
||||
void TestDrawStringTransparent();
|
||||
void TestDrawLine();
|
||||
void TestLinearGradient();
|
||||
void TestTextMapMode();
|
||||
void TestPdfInEmf();
|
||||
|
||||
Primitive2DSequence parseEmf(const OUString& aSource);
|
||||
@@ -61,11 +60,12 @@ public:
|
||||
uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
|
||||
|
||||
CPPUNIT_TEST_SUITE(Test);
|
||||
CPPUNIT_TEST(testWorking);
|
||||
CPPUNIT_TEST(testPolyPolygon);
|
||||
CPPUNIT_TEST(TestDrawString);
|
||||
CPPUNIT_TEST(TestDrawStringTransparent);
|
||||
CPPUNIT_TEST(TestDrawLine);
|
||||
CPPUNIT_TEST(TestLinearGradient);
|
||||
CPPUNIT_TEST(TestTextMapMode);
|
||||
CPPUNIT_TEST(TestPdfInEmf);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
@@ -105,24 +105,39 @@ Primitive2DSequence Test::parseEmf(const OUString& aSource)
|
||||
return xEmfParser->getDecomposition(aInputStream, aPath, aEmptyValues);
|
||||
}
|
||||
|
||||
void Test::checkRectPrimitive(Primitive2DSequence const & rPrimitive)
|
||||
void Test::testPolyPolygon()
|
||||
{
|
||||
Primitive2DSequence aSequence = parseEmf("/emfio/qa/cppunit/emf/data/fdo79679-2.emf");
|
||||
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
|
||||
drawinglayer::Primitive2dXmlDump dumper;
|
||||
xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(rPrimitive));
|
||||
xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
|
||||
|
||||
CPPUNIT_ASSERT (pDocument);
|
||||
|
||||
// emfio: add examples (later)
|
||||
// assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor", "color", "#00cc00"); // rect background color
|
||||
// assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor", "height", "100"); // rect background height
|
||||
// assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor", "width", "100"); // rect background width
|
||||
}
|
||||
// Chart axis
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygon", "path", "m0 0h19746v14817h-19746z");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor", 2);
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[1]", "color", "#ffffff");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[1]/polypolygon", "path", "m0 0h19780v14851h-19780z");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polypolygoncolor[2]/polypolygon", "path", "m2574 13194v-12065h15303v12065z");
|
||||
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polygonstroke", 116);
|
||||
assertXPathContent(pDocument, "/primitive2D/metafile/transform/mask/polygonstroke[1]/polygon", "2574,13194 2574,1129 17877,1129 17877,13194");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polygonstroke[1]/line", "color", "#ffffff");
|
||||
|
||||
assertXPathContent(pDocument, "/primitive2D/metafile/transform/mask/polygonstroke[10]/polygon", "8674,13194 8674,1129");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/polygonstroke[10]/line", "color", "#000000");
|
||||
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/textsimpleportion", 28);
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/textsimpleportion[6]", "width", "459");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/textsimpleportion[6]", "x", "9908");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/textsimpleportion[6]", "text", "0.5");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/textsimpleportion[6]", "fontcolor", "#000000");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/pointarray", 98);
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/pointarray[1]", "color", "#000000");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/pointarray[1]/point", "x", "2574");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/pointarray[1]/point", "y", "1129");
|
||||
|
||||
void Test::testWorking()
|
||||
{
|
||||
Primitive2DSequence aSequenceRect = parseEmf("/emfio/qa/cppunit/emf/data/fdo79679-2.emf");
|
||||
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequenceRect.getLength()));
|
||||
checkRectPrimitive(aSequenceRect);
|
||||
}
|
||||
|
||||
void Test::TestDrawString()
|
||||
@@ -221,6 +236,40 @@ void Test::TestLinearGradient()
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/mask/svglineargradient[2]/polypolygon", "path", "m7615.75822989746 0.216110019646294h7615.75822989746v7610.21611001965h-7615.75822989746z");
|
||||
}
|
||||
|
||||
void Test::TestTextMapMode()
|
||||
{
|
||||
// Check import of EMF image 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("/emfio/qa/cppunit/emf/data/TextMapMode.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/polypolygoncolor", 2);
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor[1]", "color", "#ffffff");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polypolygoncolor[1]/polypolygon", "path", "m0 0h3542v4647h-3542z");
|
||||
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", 20);
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion[1]", "text", "N");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion[1]", "fontcolor", "#4a70e3");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion[1]", "x", "2099");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion[1]", "y", "1859");
|
||||
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke", 138);
|
||||
assertXPathContent(pDocument, "/primitive2D/metafile/transform/polygonstroke[1]/polygon", "2142,1638 2142,1489");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke[1]/line", "color", "#4a70e3");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke[1]/line", "width", "11");
|
||||
|
||||
assertXPathContent(pDocument, "/primitive2D/metafile/transform/polygonstroke[10]/polygon", "1967,1029 1869,952");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke[10]/line", "color", "#4a70e3");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke[10]/line", "width", "11");
|
||||
|
||||
assertXPathContent(pDocument, "/primitive2D/metafile/transform/polygonstroke[20]/polygon", "2710,1113 2873,1330");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke[20]/line", "color", "#666666");
|
||||
assertXPath(pDocument, "/primitive2D/metafile/transform/polygonstroke[20]/line", "width", "11");
|
||||
}
|
||||
|
||||
void Test::TestPdfInEmf()
|
||||
{
|
||||
// Load a PPTX file, which has a shape, with a bitmap fill, which is an EMF, containing a PDF.
|
||||
|
BIN
emfio/qa/cppunit/emf/data/TextMapMode.emf
Normal file
BIN
emfio/qa/cppunit/emf/data/TextMapMode.emf
Normal file
Binary file not shown.
@@ -374,10 +374,13 @@ namespace emfio
|
||||
{
|
||||
fX2 -= mnWinOrgX;
|
||||
fY2 -= mnWinOrgY;
|
||||
fX2 /= mnWinExtX;
|
||||
fY2 /= mnWinExtY;
|
||||
fX2 *= mnDevWidth;
|
||||
fY2 *= mnDevHeight;
|
||||
if ( mnMapMode != MM_TEXT )
|
||||
{
|
||||
fX2 /= mnWinExtX;
|
||||
fY2 /= mnWinExtY;
|
||||
fX2 *= mnDevWidth;
|
||||
fY2 *= mnDevHeight;
|
||||
}
|
||||
fX2 += mnDevOrgX;
|
||||
fY2 += mnDevOrgY; // fX2, fY2 now in device units
|
||||
fX2 *= static_cast<double>(mnMillX) * 100.0 / static_cast<double>(mnPixX);
|
||||
@@ -464,10 +467,13 @@ namespace emfio
|
||||
}
|
||||
else
|
||||
{
|
||||
fWidth /= mnWinExtX;
|
||||
fHeight /= mnWinExtY;
|
||||
fWidth *= mnDevWidth;
|
||||
fHeight *= mnDevHeight;
|
||||
if ( mnMapMode != MM_TEXT )
|
||||
{
|
||||
fWidth /= mnWinExtX;
|
||||
fHeight /= mnWinExtY;
|
||||
fWidth *= mnDevWidth;
|
||||
fHeight *= mnDevHeight;
|
||||
}
|
||||
fWidth *= static_cast<double>(mnMillX) * 100.0 / static_cast<double>(mnPixX);
|
||||
fHeight *= static_cast<double>(mnMillY) * 100.0 / static_cast<double>(mnPixY);
|
||||
}
|
||||
@@ -2131,6 +2137,12 @@ namespace emfio
|
||||
pSave->maPathObj = maPathObj;
|
||||
pSave->maClipPath = maClipPath;
|
||||
|
||||
SAL_INFO("emfio", "\t\t GfxMode: " << mnGfxMode);
|
||||
SAL_INFO("emfio", "\t\t MapMode: " << mnMapMode);
|
||||
SAL_INFO("emfio", "\t\t WinOrg: " << mnWinOrgX << ", " << mnWinOrgY);
|
||||
SAL_INFO("emfio", "\t\t WinExt: " << mnWinExtX << " x " << mnWinExtY);
|
||||
SAL_INFO("emfio", "\t\t DevOrg: " << mnDevOrgX << ", " << mnDevOrgY);
|
||||
SAL_INFO("emfio", "\t\t DevWidth/Height: " << mnDevWidth << " x " << mnDevHeight);
|
||||
mvSaveStack.push_back( pSave );
|
||||
}
|
||||
|
||||
@@ -2180,6 +2192,13 @@ namespace emfio
|
||||
mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
|
||||
meLatestRasterOp = meRasterOp;
|
||||
}
|
||||
|
||||
SAL_INFO("emfio", "\t\t GfxMode: " << mnGfxMode);
|
||||
SAL_INFO("emfio", "\t\t MapMode: " << mnMapMode);
|
||||
SAL_INFO("emfio", "\t\t WinOrg: " << mnWinOrgX << ", " << mnWinOrgY);
|
||||
SAL_INFO("emfio", "\t\t WinExt: " << mnWinExtX << " x " << mnWinExtY);
|
||||
SAL_INFO("emfio", "\t\t DevOrg: " << mnDevOrgX << ", " << mnDevOrgY);
|
||||
SAL_INFO("emfio", "\t\t DevWidth/Height: " << mnDevWidth << " x " << mnDevHeight);
|
||||
mvSaveStack.pop_back();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user