diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /svx/qa/unit | |
parent | Initial commit. (diff) | |
download | libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svx/qa/unit')
41 files changed, 1967 insertions, 0 deletions
diff --git a/svx/qa/unit/XTableImportExportTest.cxx b/svx/qa/unit/XTableImportExportTest.cxx new file mode 100644 index 000000000..31962a52b --- /dev/null +++ b/svx/qa/unit/XTableImportExportTest.cxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <unotest/bootstrapfixturebase.hxx> + +#include <sal/types.h> +#include <sfx2/app.hxx> +#include <unotools/tempfile.hxx> +#include <svx/xtable.hxx> +#include <vcl/bitmapex.hxx> + +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> + +using namespace css; + +class XTableImportExportTest : public CppUnit::TestFixture +{ +public: + virtual void setUp() override + { + CppUnit::TestFixture::setUp(); + SfxApplication::GetOrCreate(); + } +}; + +CPPUNIT_TEST_FIXTURE(XTableImportExportTest, testImportExport) +{ + utl::TempFile aTempFile(nullptr, true); + aTempFile.EnableKillingFile(); + OUString aTempURL = aTempFile.GetURL(); + BitmapChecksum aChecksum(0); + + { + XBitmapList xBitmapList(aTempURL, "REF"); + uno::Reference<container::XNameContainer> xNameContainer(xBitmapList.createInstance()); + CPPUNIT_ASSERT(xNameContainer.is()); + + Bitmap aBitmap(Size(5, 5), 24); + aBitmap.Erase(COL_RED); + BitmapEx aBitmapEx(aBitmap); + Graphic aGraphic(aBitmapEx); + uno::Reference<awt::XBitmap> xBitmap(aGraphic.GetXGraphic(), css::uno::UNO_QUERY); + + xNameContainer->insertByName("SomeBitmap", uno::makeAny(xBitmap)); + xBitmapList.Save(); + + aChecksum = aBitmap.GetChecksum(); + } + + { + XBitmapList xBitmapList(aTempURL, "REF"); + bool bResult = xBitmapList.Load(); + CPPUNIT_ASSERT(bResult); + uno::Reference<container::XNameContainer> xNameContainer(xBitmapList.createInstance()); + CPPUNIT_ASSERT(xNameContainer.is()); + + uno::Any aAny = xNameContainer->getByName("SomeBitmap"); + CPPUNIT_ASSERT(aAny.has<uno::Reference<awt::XBitmap>>()); + auto xBitmap = aAny.get<uno::Reference<awt::XBitmap>>(); + CPPUNIT_ASSERT(xBitmap.is()); + uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY); + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + CPPUNIT_ASSERT(!aGraphic.IsNone()); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + CPPUNIT_ASSERT_EQUAL(aChecksum, aBitmap.GetChecksum()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/classicshapes.cxx b/svx/qa/unit/classicshapes.cxx new file mode 100644 index 000000000..b03210d12 --- /dev/null +++ b/svx/qa/unit/classicshapes.cxx @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <test/bootstrapfixture.hxx> +#include <unotest/macros_test.hxx> +#include <rtl/ustring.hxx> +#include <editeng/unoprnms.hxx> + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/frame/Desktop.hpp> + +using namespace ::com::sun::star; + +namespace +{ +const OUString sDataDirectory("svx/qa/unit/data/"); + +/// Tests not about special features of custom shapes, but about shapes in general. +class ClassicshapesTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +protected: + uno::Reference<lang::XComponent> mxComponent; + uno::Reference<drawing::XShape> getShape(sal_uInt8 nShapeIndex, sal_uInt8 nPageIndex); + +public: + virtual void setUp() override + { + test::BootstrapFixture::setUp(); + mxDesktop.set(frame::Desktop::create(m_xContext)); + } + + virtual void tearDown() override + { + if (mxComponent.is()) + { + mxComponent->dispose(); + } + test::BootstrapFixture::tearDown(); + } +}; + +uno::Reference<drawing::XShape> ClassicshapesTest::getShape(sal_uInt8 nShapeIndex, + sal_uInt8 nPageIndex) +{ + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier.is()); + uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(nPageIndex), + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage.is()); + uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShapeIndex), uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get xShape", xShape.is()); + return xShape; +} + +CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf98584ShearVertical) +{ + // The document contains draw:rect, draw:polygon and draw:path objects. + // They are vertical sheared by skewY(-0.927295218002) or by matrix(1 2 0 1 1cm 1cm). + // Notice, skewY and matrix are interpreted on file open, but not written on file save. + // They are converted to rotate * shear horizontal * scale. + // Besides using a wrong sign in shear angle, error was, that TRSetGeometry of SdrPathObj did + // not consider the additional scaling (tdf#98565). + const OUString sFileName("tdf98584_ShearVertical.odg"); + const OUString sURL(m_directories.getURLFromSrc(sDataDirectory) + sFileName); + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + // All tests have a small tolerance for to avoid failing because of rounding errors. + + // Tests skewY + sal_Int32 nShearE = -5313; // expected angle for horizontal shear + sal_Int32 nRotE = 30687; // = -5313 expected angle for generated rotation + // expected width of shape, should not change on vertical shearing + sal_Int32 nWidthE = 5001; + + for (sal_uInt8 nPageIndex = 0; nPageIndex < 3; ++nPageIndex) + { + awt::Rectangle aFrameRect; + uno::Reference<drawing::XShape> xShape(getShape(0, nPageIndex)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect; + const sal_Int32 nWidthA(aFrameRect.Width); + if (abs(nWidthE - nWidthA) > 2) + sErrors += "skewY page " + OUString::number(nPageIndex) + " width expected " + + OUString::number(nWidthE) + ", actual " + OUString::number(nWidthA) + "\n"; + sal_Int32 nShearA(0); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_SHEARANGLE) >>= nShearA; + if (abs(nShearE - nShearA) > 2) + sErrors += "skewY page" + OUString::number(nPageIndex) + " shear angle expected " + + OUString::number(nShearE) + ", actual " + OUString::number(nShearA) + "\n"; + sal_Int32 nRotA(0); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_ROTATEANGLE) >>= nRotA; + if (abs(nRotE - nRotA) > 2) + sErrors += "skewY page" + OUString::number(nPageIndex) + " rotate angle expected " + + OUString::number(nRotE) + ", actual " + OUString::number(nRotA) + "\n"; + } + + // Tests matrix + nShearE = -6343; + nRotE = 29657; + nWidthE = 5001; + + for (sal_uInt8 nPageIndex = 3; nPageIndex < 6; ++nPageIndex) + { + awt::Rectangle aFrameRect; + uno::Reference<drawing::XShape> xShape(getShape(0, nPageIndex)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect; + const sal_Int32 nWidthA(aFrameRect.Width); + if (abs(nWidthE - nWidthA) > 2) + sErrors += "matrix page " + OUString::number(nPageIndex) + " width expected " + + OUString::number(nWidthE) + ", actual " + OUString::number(nWidthA) + "\n"; + sal_Int32 nShearA(0); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_SHEARANGLE) >>= nShearA; + if (abs(nShearE - nShearA) > 2) + sErrors += "matrix page" + OUString::number(nPageIndex) + " shear angle expected " + + OUString::number(nShearE) + ", actual " + OUString::number(nShearA) + "\n"; + sal_Int32 nRotA(0); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_ROTATEANGLE) >>= nRotA; + if (abs(nRotE - nRotA) > 2) + sErrors += "matrix page" + OUString::number(nPageIndex) + " rotate angle expected " + + OUString::number(nRotE) + ", actual " + OUString::number(nRotA) + "\n"; + } + + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(ClassicshapesTest, testTdf98583ShearHorizontal) +{ + // The document contains rectangles with LT 3000,5000 and RB 5000,9000. + // skewX (-0.78539816339744830961) = skewX(-45deg) is applied on the first page + // matrix(1 0 1 1 0cm 0cm) on the second page. Both should result in a parallelogram with + // LT 8000,5000 and RB 14000, 9000, which means width 6001, height 4001. + // Error was, that not the mathematical matrix was used, but the API matrix, which has + // wrong sign in shear angle. + const OUString sFileName("tdf98583_ShearHorizontal.odp"); + const OUString sURL(m_directories.getURLFromSrc(sDataDirectory) + sFileName); + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + // All tests have a small tolerance for to avoid failing because of rounding errors. + const sal_Int32 nLeftE(8000); // expected values + const sal_Int32 nTopE(5000); + const sal_Int32 nWidthE(6001); + const sal_Int32 nHeightE(4001); + for (sal_uInt8 nPageIndex = 0; nPageIndex < 2; ++nPageIndex) + { + awt::Rectangle aFrameRect; + uno::Reference<drawing::XShape> xShape(getShape(0, nPageIndex)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect; + const sal_Int32 nLeftA(aFrameRect.X); + const sal_Int32 nTopA(aFrameRect.Y); + const sal_Int32 nWidthA(aFrameRect.Width); + const sal_Int32 nHeightA(aFrameRect.Height); + if (abs(nLeftE - nLeftA) > 2 || abs(nTopE - nTopA) > 2) + sErrors += "page " + OUString::number(nPageIndex) + " LT expected " + + OUString::number(nLeftE) + " | " + OUString::number(nTopE) + ", actual " + + OUString::number(nLeftA) + " | " + OUString::number(nTopA) + "\n"; + if (abs(nWidthE - nWidthA) > 2 || abs(nHeightE - nHeightA) > 2) + sErrors += "page " + OUString::number(nPageIndex) + " width x height expected " + + OUString::number(nWidthE) + " x " + OUString::number(nHeightE) + + ", actual " + OUString::number(nWidthA) + " x " + + OUString::number(nHeightA) + "\n"; + } + + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx new file mode 100644 index 000000000..0c362cac1 --- /dev/null +++ b/svx/qa/unit/customshapes.cxx @@ -0,0 +1,819 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <test/bootstrapfixture.hxx> +#include <unotest/macros_test.hxx> +#include <rtl/ustring.hxx> +#include <editeng/unoprnms.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <svx/EnhancedCustomShape2d.hxx> +#include <svx/svdoashp.hxx> +#include <svx/svdopath.hxx> +#include <svx/unoapi.hxx> +#include <unotools/mediadescriptor.hxx> +#include <unotools/tempfile.hxx> + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XStorable.hpp> + +using namespace ::com::sun::star; + +namespace +{ +const OUString sDataDirectory("svx/qa/unit/data/"); + +/// Tests for svx/source/customshapes/ code. +class CustomshapesTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +protected: + uno::Reference<lang::XComponent> mxComponent; + // get shape nShapeIndex from page 0 + uno::Reference<drawing::XShape> getShape(sal_uInt8 nShapeIndex); + sal_uInt8 countShapes(); + +public: + virtual void setUp() override + { + test::BootstrapFixture::setUp(); + mxDesktop.set(frame::Desktop::create(m_xContext)); + } + + virtual void tearDown() override + { + if (mxComponent.is()) + { + mxComponent->dispose(); + } + test::BootstrapFixture::tearDown(); + } +}; + +uno::Reference<drawing::XShape> CustomshapesTest::getShape(sal_uInt8 nShapeIndex) +{ + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier.is()); + uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage.is()); + uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(nShapeIndex), uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get xShape", xShape.is()); + return xShape; +} + +sal_uInt8 CustomshapesTest::countShapes() +{ + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, + uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier.is()); + uno::Reference<drawing::XDrawPages> xDrawPages(xDrawPagesSupplier->getDrawPages()); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage.is()); + return xDrawPage->getCount(); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testViewBoxLeftTop) +{ + // tdf#121890 formula values "left" and "top" are wrongly calculated + // Load a document with two custom shapes of type "non-primitive" + OUString aURL + = m_directories.getURLFromSrc(sDataDirectory) + "viewBox_positive_twolines_strict.odp"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Get the shape "leftright". Error was, that the identifier "left" was always set to zero, thus + // the path was outside the frame rectangle for a viewBox having a positive "left" value. + uno::Reference<drawing::XShape> xShapeLR(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeLRProps(xShapeLR, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'leftright' properties", xShapeLRProps.is()); + awt::Rectangle aFrameRectLR; + xShapeLRProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRectLR; + awt::Rectangle aBoundRectLR; + xShapeLRProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectLR; + // difference should be zero, but allow some rounding errors + CPPUNIT_ASSERT_LESS(static_cast<long>(3), labs(aFrameRectLR.X - aBoundRectLR.X)); + + // Get the shape "topbottom". Error was, that the identifier "top" was always set to zero, thus + // the path was outside the frame rectangle for a viewBox having a positive "top" value. + uno::Reference<drawing::XShape> xShapeTB(getShape(1)); + uno::Reference<beans::XPropertySet> xShapeTBProps(xShapeTB, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'topbottom' properties", xShapeTBProps.is()); + awt::Rectangle aFrameRectTB; + xShapeTBProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRectTB; + awt::Rectangle aBoundRectTB; + xShapeTBProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectTB; + // difference should be zero, but allow some rounding errors + CPPUNIT_ASSERT_LESS(static_cast<long>(3), labs(aFrameRectTB.Y - aBoundRectTB.Y)); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testAccuracyCommandX) +{ + // 121761 Increase accuracy of quarter circles drawn by command X or Y + // The loaded document has a quarter circle with radius 10000 (unit 1/100 mm) + // which is rotated by 45deg. The test considers the segment. + OUString aURL + = m_directories.getURLFromSrc(sDataDirectory) + "tdf121761_Accuracy_command_X.odp"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Get the shape "arc_45deg_rotated". Error was, that a Bezier curve with bad parameters + // was used, thus the segment height was obviously smaller than for a true circle. + // Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + double fHeight = static_cast<double>(aBoundRect.Height); + // The tolerance is a guess, might be smaller. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 2942.0, fHeight, 8.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testToggleCommandXY) +{ + // 121952 Toggle x- and y-direction if command X has several parameters + // The loaded document has a shape with command X and two parameter placed on a diagonal. + // The radius of the quarter circles are both 10000 (unit 1/100 mm). + // The shape is rotated by 45deg, so you get two segments, one up and one down. + OUString aURL + = m_directories.getURLFromSrc(sDataDirectory) + "tdf121952_Toggle_direction_command_X.odp"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Error was, that the second segment was drawn with same direction as first one. If drawn + // correctly, the bounding box height of the segments together is about twice the single + // segment height. Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + double fHeight = static_cast<double>(aBoundRect.Height); + // The tolerance is a guess, might be smaller. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 5871.0, fHeight, 16.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testMultipleMoveTo) +{ + // tdf122964 Multiple moveTo has to be treated as lineTo in draw:enhanced-path + // Load a document with path "M 0 0 5 10 10 0 N" + OUString aURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf122964_MultipleMoveTo.odg"; + mxComponent = loadFromDesktop(aURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Error was, that the second and further parameter pairs were treated as moveTo, + // and so the generated path was empty, resulting in zero width and height of the + // bounding box. It has to be treated same as "M 0 0 L 5 10 10 0 N". + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + bool bIsZero(aBoundRect.Height == 0 && aBoundRect.Width == 0); + CPPUNIT_ASSERT_MESSAGE("Path is empty", !bIsZero); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testWidthOrientationCommandU) +{ + // tdf121845 custom shape with command U (angleellipse) is wrongly drawn + // Load a document with path "M 750 0 L 750 500 250 500 250 0 U 500 0 500 500 0 180 N" + // in viewBox="0 0 1000 500" and width="10cm", height="5cm". + const OUString sFileName("tdf121845_WidthOrientation_command_U.odg"); + const OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Error was, that the width and height of the ellipse was halved and that the ellipse + // was not drawn clockwise but counter clockwise. + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + const double fWidth = static_cast<double>(aBoundRect.Width); + // Need some tolerance for line width + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong width", 10000.0, fWidth, 40.0); + const double fHeight = static_cast<double>(aBoundRect.Height); + // Wrong orientation draws segment above the top of the viewBox and so increases 'Height'. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong orientation", 5000.0, fHeight, 40.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testHalfEllipseVML) +{ + // tdf121845 custom shape with command U (angleellipse) is wrongly drawn + // Load a document which was converted from VML to doc by Word. It had a VML + // path="m750,al500,,500,500,,-11796480e" resulting in a lower half circle. + const OUString sFileName("tdf121845_HalfEllipseVML.doc"); + const OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Error was, that a full circle instead of the half circle was draw. + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + const double fDiff2HmW = static_cast<double>(2 * aBoundRect.Height - aBoundRect.Width); + // Need some tolerance for line width + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("not a half circle", 0.0, fDiff2HmW, 40.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testLargeSwingAngleVML) +{ + // tdf121845 custom shape with command U (angleellipse) is wrongly drawn + // Load a document which was converted from VML to doc by Word. It had a VML + // path="al50,50,45,45,2621440,31457280e" resulting in a full circle plus 120 deg segment. + const OUString sFileName("tdf121845_start40_swing480.doc"); + const OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + // Error was, that only the 120 deg segment was drawn. + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + const double fDiffWmH = static_cast<double>(aBoundRect.Width - aBoundRect.Height); + // Need some tolerance for line width + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Full circle plus segment expected", 0.0, fDiffWmH, 10.0); +} +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf121845_two_commands_U) +{ + // tdf121845 custom shape with command U (angleellipse) is wrongly drawn + // Load a document with path "U 950 250 200 200 90 180 250 250 200 200 180 270 N" + // Error was, that the second ellipse segment was interpreted as command T and + // thus a line from first to second segment was drawn. + const OUString sFileName("tdf121845_Two_commands_U.odg"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + // In case no line is drawn, two polygons are generated; with line only one polygon + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + SdrPathObj* pPathObj = static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry()); + CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj); + const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(2), + aPolyPolygon.count()); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124212_handle_position) +{ + // tdf124212 Adjustment handle reacts wrongly, if custom shape has a non + // default viewBox. Load a document with svg:viewBox="10800 0 10800 21600" + // Error was, that moving the controller results in a handle position that + // does not reflect the movement. + const OUString sFileName("tdf124212_handle_position.odg"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + // The shape has one, horizontal adjust handle. + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + Point aInitialPosition; + aCustomShape2d.GetHandlePosition(0, aInitialPosition); + css::awt::Point aDesiredPosition(aInitialPosition.X() + 1000, aInitialPosition.Y()); + aCustomShape2d.SetHandleControllerPosition(0, aDesiredPosition); + Point aObservedPosition; + aCustomShape2d.GetHandlePosition(0, aObservedPosition); + sal_Int32 nDesiredX(aDesiredPosition.X); // awt::Point + sal_Int32 nObservedX(aObservedPosition.X()); // tools::Point + CPPUNIT_ASSERT_EQUAL_MESSAGE("handle X coordinate", nDesiredX, nObservedX); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124029_arc_position) +{ + // tdf121029 MS binary custom shape mso_sptArc has wrong position + // MS uses the sector for position reference. Error was, that + // LibreOffice has used the underlying ellipse. + const OUString sFileName("tdf124029_Arc_position.doc"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.text.TextDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + // The visual wrong position is due to a wrong shape width. + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aFrameRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aFrameRect; + CPPUNIT_ASSERT_EQUAL_MESSAGE("shape width", static_cast<sal_uInt32>(1610), + static_cast<sal_uInt32>(aFrameRect.Width)); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf124740_handle_path_coordsystem) +{ + // tdf124740 OOXML shape with handle and w and h attribute on path has wrong + // handle position + // The handle position was scaled erroneously twice. + const OUString sFileName("tdf124740_HandleInOOXMLUserShape.pptx"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + // The shape has one, horizontal adjust handle. It is about 1/5 of 10cm from left + // shape edge, shape is 6cm from left . That results in a position + // of 8cm from left page edge, which is 8000 in 1/100 mm unit. + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + Point aPosition; + aCustomShape2d.GetHandlePosition(0, aPosition); + double fX(aPosition.X()); + // tolerance for rounding to integer + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("handle X coordinate", 8000.0, fX, 2.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf115813_OOXML_XY_handle) +{ + // The test covers all preset shapes with handles. Only these ones are + // excluded: arc, blockArc, chord, circularArrow, gear6, gear9, mathNotEqual, pie, + // leftCircularArrow, leftRightCircularArrow, swooshArrow. + // Connectors are included as ordinary shapes to prevent converting. + // Error was, that the handle movement and the changes to the shape did not follow + // the mouse movement. + const OUString sFileName("tdf115813_HandleMovementOOXMLPresetShapes.pptx"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + + OUString sErrors; + // values in vector InteractionsHandles are in 1/100 mm and refer to page + for (sal_uInt8 i = 0; i < countShapes(); i++) + { + uno::Reference<drawing::XShape> xShape(getShape(i)); + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + OUString sShapeType("non-primitive"); // default for ODF + const SdrCustomShapeGeometryItem& rGeometryItem( + rSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY)); + const uno::Any* pAny = rGeometryItem.GetPropertyValueByName("Type"); + if (pAny) + *pAny >>= sShapeType; + + sal_uInt8 nHandlesCount = rSdrObjCustomShape.GetInteractionHandles().size(); + for (sal_uInt8 j = 0; j < nHandlesCount; j++) + { + css::awt::Point aInitialPosition( + rSdrObjCustomShape.GetInteractionHandles()[j].aPosition); + // The handles are initialized in the test document, so that if the handle is moveable in + // that direction at all, then it can move at least with an amount of 100. + Point aDesiredPosition(aInitialPosition.X + 100, aInitialPosition.Y + 100); + rSdrObjCustomShape.DragMoveCustomShapeHdl(aDesiredPosition, j, false); + css::awt::Point aObservedPosition( + rSdrObjCustomShape.GetInteractionHandles()[j].aPosition); + sal_Int32 nDesiredX(aDesiredPosition.X()); // tools::Point + sal_Int32 nDesiredY(aDesiredPosition.Y()); + sal_Int32 nObservedX(aObservedPosition.X); // css::awt::Point + sal_Int32 nObservedY(aObservedPosition.Y); + // If a handle only moves in one direction, the difference is 100 for the other direction. + // There exists some rounding differences, therefore '<= 1' instead of '== 0'. + // The condition has the form '!(good cases)'. + if (!((abs(nDesiredX - nObservedX) <= 1 && abs(nDesiredY - nObservedY) == 100) + || (abs(nDesiredX - nObservedX) == 100 && abs(nDesiredY - nObservedY) <= 1) + || (abs(nDesiredX - nObservedX) <= 1 && abs(nDesiredY - nObservedY) <= 1))) + { + sErrors += "\n" + + //sErrors += OUString(sal_Unicode(10)); + OUString::number(i) + " " + sShapeType + ": " + OUString::number(j) + + " X " + OUString::number(nDesiredX) + "|" + + OUString::number(nObservedX) + " Y " + OUString::number(nDesiredY) + + "|" + OUString::number(nObservedY); + } + } + } + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testQuadraticCurveTo) +{ + // tdf125782 command Q (quadraticcurveto) uses wrong 'current point'. + // When converting to cubic Bezier curve, this had resulted in a wrong first control point. + // The quadraticcurveto segment starts in shape center in the test file. The first control + // point should produce a horizontal tangent in the start point. + const OUString sFileName("tdf125782_QuadraticCurveTo.odg"); + const OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + const double fHeight = static_cast<double>(aBoundRect.Height); + //Add some tolerance + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("bad height of quadraticcurveto", 3004, fHeight, 10.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf126512_OOXML_handle_in_ODP) +{ + // The test covers all preset shapes with handles. Connectors are included as ordinary + // shapes to prevent converting. The file was created in PowerPoint 365 and then + // opened and exported to ODF format by LibreOffice. + // Error was, that for shapes, which were originally imported from OOXML, the handles + // could not be moved at all. + const OUString sFileName("tdf126512_OOXMLHandleMovementInODF.odp"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + + OUString sErrors; // sErrors collects shape type and handle index for failing cases + for (sal_uInt8 i = 0; i < countShapes(); i++) + { + uno::Reference<drawing::XShape> xShape(getShape(i)); + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + OUString sShapeType("non-primitive"); // only to initialize, value not used here + const SdrCustomShapeGeometryItem& rGeometryItem( + rSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY)); + const uno::Any* pAny = rGeometryItem.GetPropertyValueByName("Type"); + if (pAny) + *pAny >>= sShapeType; + + sal_uInt8 nHandlesCount = rSdrObjCustomShape.GetInteractionHandles().size(); + for (sal_uInt8 j = 0; j < nHandlesCount; j++) + { + css::awt::Point aInitialPosition( + rSdrObjCustomShape.GetInteractionHandles()[j].aPosition); + // The handles are initialized in the test document, so that if the handle is moveable + // in that direction at all, then it can move at least with an amount of 100. + Point aDesiredPosition(aInitialPosition.X + 100, aInitialPosition.Y + 100); + rSdrObjCustomShape.DragMoveCustomShapeHdl(aDesiredPosition, j, false); + css::awt::Point aObservedPosition( + rSdrObjCustomShape.GetInteractionHandles()[j].aPosition); + if (aInitialPosition.X == aObservedPosition.X + && aInitialPosition.Y == aObservedPosition.Y) + { + sErrors + += "\n" + OUString::number(i) + " " + sShapeType + " " + OUString::number(j); + } + } + } + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf127785_Mirror) +{ + // The document contains two shapes, one with horizontal flip, the other with vertical + // flip. They are diamonds, so their text frame is symmetric to the center of the shape. + // The shapes have not stroke and no fill, so that the bounding box surrounds the text + // and therefore equals approximately the text frame. + // Error was, that because of wrong calculation, the flipped shapes do not use the + // text frame but the frame rectangle for their text. + const OUString sFileName("tdf127785_Mirror.odp"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + + uno::Reference<drawing::XShape> xShapeV(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeVProps(xShapeV, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeVProps.is()); + awt::Rectangle aBoundRectV; + xShapeVProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectV; + const sal_Int32 nHeightV = aBoundRectV.Height; + const sal_Int32 nWidthV = aBoundRectV.Width; + const sal_Int32 nLeftV = aBoundRectV.X; + const sal_Int32 nTopV = aBoundRectV.Y; + if (abs(nHeightV - 4149) > 5 || abs(nWidthV - 3819) > 5) + sErrors += "Flip vertical wrong size."; + if (abs(nLeftV - 3155) > 5 || abs(nTopV - 3736) > 5) + sErrors += " Flip vertical wrong position."; + + uno::Reference<drawing::XShape> xShapeH(getShape(1)); + uno::Reference<beans::XPropertySet> xShapeHProps(xShapeH, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeHProps.is()); + awt::Rectangle aBoundRectH; + xShapeHProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectH; + const sal_Int32 nHeightH = aBoundRectH.Height; + const sal_Int32 nWidthH = aBoundRectH.Width; + const sal_Int32 nLeftH = aBoundRectH.X; + const sal_Int32 nTopH = aBoundRectH.Y; + if (abs(nHeightH - 4149) > 5 || abs(nWidthH - 3819) > 5) + sErrors += " Flip horizontal wrong size."; + if (abs(nLeftH - 15026) > 5 || abs(nTopH - 4115) > 5) + sErrors += " Flip horizontal wrong position."; + + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf126060_3D_Z_Rotation) +{ + // The document contains one textbox with inside overflowed text + // and the text has 3D z rotation. When we open the document we + // should see the text vertically and rotated from text bound center not text box. + + const OUString sFileName("tdf126060_3D_Z_Rotation.pptx"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + + uno::Reference<drawing::XShape> xShape(getShape(0)); + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + + if (rSdrObjCustomShape.GetCameraZRotation() != 90) + sErrors += "Wrong text camera Z rotation"; + + basegfx::B2DHomMatrix aObjectTransform; + basegfx::B2DPolyPolygon aObjectPolyPolygon; + rSdrObjCustomShape.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon); + + if (aObjectTransform.get(0, 0) != 1492 || aObjectTransform.get(0, 1) != 0 + || aObjectTransform.get(0, 2) != 1129 || aObjectTransform.get(1, 0) != 0 + || aObjectTransform.get(1, 1) != 2500 || aObjectTransform.get(1, 2) != 5846) + sErrors += " Wrong transformation matrix"; + + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf127785_Asymmetric) +{ + // The document contains a shapes with vertical flip and text frame asymmetrical + // to shape. The shape has not stroke and no fill, so that the bounding box surrounds + // the text and therefore equals approximately the text frame. + // Error was, that the 180deg text rotation was not compensated for the position of + // the flipped text box. + const OUString sFileName("tdf127785_asymmetricTextBoxFlipV.odg"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + const sal_Int32 nLeft = aBoundRect.X; + const sal_Int32 nTop = aBoundRect.Y; + const sal_Int32 nRight = aBoundRect.X + aBoundRect.Width - 1; + const sal_Int32 nBottom = aBoundRect.Y + aBoundRect.Height - 1; + if (abs(nLeft - 10034) > 5) + sErrors += "wrong left"; + if (abs(nRight - 12973) > 5) + sErrors += " wrong right"; + if (abs(nTop - 7892) > 5) + sErrors += " wrong top"; + if (abs(nBottom - 14884) > 5) + sErrors += " wrong bottom"; + + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf127785_TextRotateAngle) +{ + // The document contains a shapes with vertical flip and a text frame with own + // rotate angle. The shape has not stroke and no fill, so that the bounding box + // surrounds the text and therefore equals approximately the text frame. + // Error was, that the compensation for the 180° rotation added for vertical + // flip were not made to the text box position but to the text matrix. + const OUString sFileName("tdf127785_TextRotateAngle.odp"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aBoundRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect; + const sal_Int32 nLeft = aBoundRect.X; + const sal_Int32 nTop = aBoundRect.Y; + const sal_Int32 nRight = aBoundRect.X + aBoundRect.Width - 1; + const sal_Int32 nBottom = aBoundRect.Y + aBoundRect.Height - 1; + if (abs(nLeft - 5054) > 5) + sErrors += "wrong left"; + if (abs(nRight - 6374) > 5) + sErrors += " wrong right"; + if (abs(nTop - 4516) > 5) + sErrors += " wrong top"; + if (abs(nBottom - 8930) > 5) + sErrors += " wrong bottom"; + + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf128413_tbrlOnOff) +{ + // The document contains a rotated shape with text. The error was, that switching + // tb-rl writing-mode on, changed the shape size and position. + + const OUString sFileName("tdf128413_tbrl_OnOff.odp"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps.is()); + awt::Rectangle aOrigRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aOrigRect; + + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + rSdrObjCustomShape.SetVerticalWriting(true); + + awt::Rectangle aObservedRect; + xShapeProps->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT) >>= aObservedRect; + OUString sError; + if (aOrigRect.Width != aObservedRect.Width || aOrigRect.Height != aObservedRect.Height + || aOrigRect.X != aObservedRect.X || aOrigRect.Y != aObservedRect.Y) + { + sError = "Shape has wrong size or wrong position."; + } + CPPUNIT_ASSERT_EQUAL(OUString(), sError); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf129532_MatrixFlipV) +{ + // The document contains two rotated shapes with the same geometry. For one of them + // "matrix(1 0 0 -1 0cm 0cm)" was manually added to the value of the draw:transform + // attribute. That should result in mirroring on the x-axis. Error was, that the lines + // which are drawn on the shape rectangle were mirrored, but not the rectangle itself. + // The rectangle was only shifted. + const OUString sFileName("tdf129532_MatrixFlipV.odg"); + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + sFileName; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + OUString sErrors; // sErrors collects the errors and should be empty in case all is OK. + + uno::Reference<drawing::XShape> xShape0(getShape(0)); + uno::Reference<beans::XPropertySet> xShape0Props(xShape0, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape0Props.is()); + awt::Rectangle aBoundRect0; + xShape0Props->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect0; + + uno::Reference<drawing::XShape> xShape1(getShape(1)); + uno::Reference<beans::XPropertySet> xShape1Props(xShape1, uno::UNO_QUERY); + CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape1Props.is()); + awt::Rectangle aBoundRect1; + xShape1Props->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRect1; + + // The size of the two BoundRect rectangles are the same in case of correct + // vertical mirroring. + if (aBoundRect0.Width != aBoundRect1.Width) + { + sErrors += "\n Width expected: " + OUString::number(aBoundRect1.Width) + + " actual: " + OUString::number(aBoundRect0.Width); + } + if (aBoundRect0.Height != aBoundRect1.Height) + { + sErrors += "\n Height expected: " + OUString::number(aBoundRect1.Height) + + " actual: " + OUString::number(aBoundRect0.Height); + } + CPPUNIT_ASSERT_EQUAL(OUString(), sErrors); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf103474_commandT_CaseZeroHeight) +{ + // tdf103474 custom shape with command T to create quater ellipses in a bracket, + // corner case where the ellipse has zero height. + // Error was, that the calculation of the circle angle from the ellipse + // angle results in a wrong angle for the case 180° and height zero. + OUString sURL + = m_directories.getURLFromSrc(sDataDirectory) + "tdf103474_commandT_CaseZeroHeight.odp"; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + // The end points of the straight line segment should have the same x-coordinate of left + // of shape, and different y-coordinates, one top and the other bottom of the shape. + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + SdrPathObj* pPathObj = static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry()); + CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj); + const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(1), + aPolyPolygon.count()); + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0)); + // Get the middle points of the polygon. They are the endpoints of the + // straight line segment regardless of the quarter ellipse parts, because + // the shape is symmetric. + const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(aPolygon.count() / 2 - 1)); + const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() / 2)); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 13999.0, aStart.getX(), 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 13999.0, aEnd.getX(), 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart.getY(), 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd.getY(), 1.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf103474_commandG_CaseZeroHeight) +{ + // Some as above, but with shape with command G. + OUString sURL + = m_directories.getURLFromSrc(sDataDirectory) + "tdf103474_commandG_CaseZeroHeight.odp"; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + // The end points of the straight line segment should have the same x-coordinate of left + // of shape, and different y-coordinates, one top and the other bottom of the shape. + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + SdrPathObj* pPathObj = static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry()); + CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj); + const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32>(1), + aPolyPolygon.count()); + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0)); + // Get the middle points of the polygon. They are the endpoints of the + // straight line segment regardless of the quarter ellipse parts, because + // the shape is symmetric. + const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(aPolygon.count() / 2 - 1)); + const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() / 2)); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 1999.0, aStart.getX(), 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 1999.0, aEnd.getX(), 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart.getY(), 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd.getY(), 1.0); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf122323_largeSwingAngle) +{ + // SwingAngles are clamped to [-360;360] in MS Office. Error was, that LO calculated + // the end angle and used it modulo 360, no full ellipse was drawn. + OUString sURL + = m_directories.getURLFromSrc(sDataDirectory) + "tdf122323_swingAngle_larger360deg.pptx"; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.presentation.PresentationDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + uno::Reference<drawing::XShape> xShape(getShape(0)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + EnhancedCustomShape2d aCustomShape2d(rSdrObjCustomShape); + SdrPathObj* pPathObj = static_cast<SdrPathObj*>(aCustomShape2d.CreateLineGeometry()); + CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj); + const basegfx::B2DPolyPolygon aPolyPolygon(pPathObj->GetPathPoly()); + const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0)); + const basegfx::B2DPoint aStart(aPolygon.getB2DPoint(0)); + // last point comes from line to center, therefore -2 instead of -1 + const basegfx::B2DPoint aEnd(aPolygon.getB2DPoint(aPolygon.count() - 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Start <> End", aStart, aEnd); +} + +CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf136176) +{ + // Error was, that fObjectRotation was not correctly updated after shearing. + // The problem becomes visible after save and reload. + OUString sURL = m_directories.getURLFromSrc(sDataDirectory) + "tdf136176_rot30_flip.odg"; + mxComponent = loadFromDesktop(sURL, "com.sun.star.comp.drawing.DrawingDocument"); + CPPUNIT_ASSERT_MESSAGE("Could not load document", mxComponent.is()); + + for (sal_uInt16 i = 0; i < 3; i++) + { + // get shape + uno::Reference<drawing::XShape> xShape(getShape(i)); + SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + // apply shearing 20deg + const Point aCenter = rSdrObjCustomShape.GetSnapRect().Center(); + rSdrObjCustomShape.Shear(aCenter, 2000, tan(basegfx::deg2rad(20.0)), false); + } + + // Save and reload + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::TempFile aTempFile; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw8"); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + mxComponent->dispose(); + mxComponent = loadFromDesktop(aTempFile.GetURL()); + + // Expected values of point 4 of the shape polygon + const OString sTestCase[] = { "FlipH", "FlipV", "FlipHV" }; + const double fX[] = { 14981.0, 3849.0, 15214.0 }; + const double fY[] = { 9366.0, 16464.0, 23463.0 }; + + // Verify correct positions + for (sal_uInt16 i = 0; i < 3; i++) + { + // Get shape + const uno::Reference<drawing::XShape> xShape(getShape(i)); + const SdrObjCustomShape& rSdrObjCustomShape( + static_cast<SdrObjCustomShape&>(*GetSdrObjectFromXShape(xShape))); + // Create polygon from shape and examine point 4 of the polygon + const basegfx::B2DPolyPolygon aLineGeometry = rSdrObjCustomShape.GetLineGeometry(false); + const basegfx::B2DPoint aPoint(aLineGeometry.getB2DPolygon(0).getB2DPoint(4)); + // Allow some tolerance for rounding errors + if (fabs(aPoint.getX() - fX[i]) > 2.0 || fabs(aPoint.getY() - fY[i]) > 2.0) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sTestCase[i].getStr(), aPoint, + basegfx::B2DPoint(fX[i], fY[i])); + } + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/data/graphic.pdf b/svx/qa/unit/data/graphic.pdf Binary files differnew file mode 100644 index 000000000..4b53d2056 --- /dev/null +++ b/svx/qa/unit/data/graphic.pdf diff --git a/svx/qa/unit/data/shadow-scale-origin.pptx b/svx/qa/unit/data/shadow-scale-origin.pptx Binary files differnew file mode 100644 index 000000000..a0a164a3c --- /dev/null +++ b/svx/qa/unit/data/shadow-scale-origin.pptx diff --git a/svx/qa/unit/data/svx-dialogs-test.txt b/svx/qa/unit/data/svx-dialogs-test.txt new file mode 100644 index 000000000..bd7ff04ed --- /dev/null +++ b/svx/qa/unit/data/svx-dialogs-test.txt @@ -0,0 +1,80 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +# This file contains all dialogs that the unit tests in the module +# will work on if it is in script mode. It will read one-by-one, +# try to open it and create a screenshot that will be saved in +# workdir/screenshots using the pattern of the ui-file name. +# +# Syntax: +# - empty lines are allowed +# - lines starting with '#' are treated as comment +# - all other lines should contain a *.ui filename in the same +# notation as in the dialog constructors (see code) + +# +# The 'known' dialogs which have a hard-coded representation +# in registerKnownDialogsByID/createDialogByID +# + +# No known dialogs in svx for now + +# +# Dialogs without a hard-coded representation. These will +# be visualized using a fallback based on VclBuilder +# + +# currently deactivated, leads to problems and the test to not work +# This is typically a hint that these should be hard-coded in the +# test case since they need some document and model data to work +# +# svx/ui/asianphoneticguidedialog.ui <- problems under linux + +svx/ui/textcontrolchardialog.ui +svx/ui/textcontrolparadialog.ui +svx/ui/datanavigator.ui +svx/ui/redlineviewpage.ui +svx/ui/redlinefilterpage.ui +svx/ui/headfootformatpage.ui +svx/ui/optgridpage.ui +svx/ui/xformspage.ui +svx/ui/compressgraphicdialog.ui +svx/ui/compressgraphicdialog.ui +svx/ui/docrecoveryprogressdialog.ui +svx/ui/docrecoverybrokendialog.ui +svx/ui/passwd.ui +svx/ui/adddataitemdialog.ui +svx/ui/addconditiondialog.ui +svx/ui/namespacedialog.ui +svx/ui/addnamespacedialog.ui +svx/ui/addsubmissiondialog.ui +svx/ui/addmodeldialog.ui +svx/ui/addinstancedialog.ui +svx/ui/extrustiondepthdialog.ui +svx/ui/fontworkgallerydialog.ui +svx/ui/fontworkspacingdialog.ui +svx/ui/chinesedictionary.ui +svx/ui/chineseconversiondialog.ui +svx/ui/imapdialog.ui +svx/ui/findreplacedialog.ui +svx/ui/crashreportdlg.ui +svx/ui/docrecoverysavedialog.ui +svx/ui/docrecoveryrecoverdialog.ui +svx/ui/querysavecontchangesdialog.ui +svx/ui/querydeletecontourdialog.ui +svx/ui/queryunlinkgraphicsdialog.ui +svx/ui/querynewcontourdialog.ui +svx/ui/querymodifyimagemapchangesdialog.ui +svx/ui/querysaveimagemapchangesdialog.ui +svx/ui/querysaveimagemapchangesdialog.ui +svx/ui/linkwarndialog.ui +svx/ui/formlinkwarndialog.ui +svx/ui/savemodifieddialog.ui +svx/ui/querydeletethemedialog.ui +svx/ui/querydeleteobjectdialog.ui diff --git a/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp b/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp Binary files differnew file mode 100644 index 000000000..9b36d45ee --- /dev/null +++ b/svx/qa/unit/data/tdf103474_commandG_CaseZeroHeight.odp diff --git a/svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odp b/svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odp Binary files differnew file mode 100644 index 000000000..54a4377ca --- /dev/null +++ b/svx/qa/unit/data/tdf103474_commandT_CaseZeroHeight.odp diff --git a/svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptx b/svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptx Binary files differnew file mode 100644 index 000000000..3435fef61 --- /dev/null +++ b/svx/qa/unit/data/tdf115813_HandleMovementOOXMLPresetShapes.pptx diff --git a/svx/qa/unit/data/tdf121761_Accuracy_command_X.odp b/svx/qa/unit/data/tdf121761_Accuracy_command_X.odp Binary files differnew file mode 100644 index 000000000..1de391758 --- /dev/null +++ b/svx/qa/unit/data/tdf121761_Accuracy_command_X.odp diff --git a/svx/qa/unit/data/tdf121845_HalfEllipseVML.doc b/svx/qa/unit/data/tdf121845_HalfEllipseVML.doc Binary files differnew file mode 100644 index 000000000..043e4e15f --- /dev/null +++ b/svx/qa/unit/data/tdf121845_HalfEllipseVML.doc diff --git a/svx/qa/unit/data/tdf121845_Two_commands_U.odg b/svx/qa/unit/data/tdf121845_Two_commands_U.odg Binary files differnew file mode 100644 index 000000000..c0f7ff34f --- /dev/null +++ b/svx/qa/unit/data/tdf121845_Two_commands_U.odg diff --git a/svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odg b/svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odg Binary files differnew file mode 100644 index 000000000..349c2eb81 --- /dev/null +++ b/svx/qa/unit/data/tdf121845_WidthOrientation_command_U.odg diff --git a/svx/qa/unit/data/tdf121845_start40_swing480.doc b/svx/qa/unit/data/tdf121845_start40_swing480.doc Binary files differnew file mode 100644 index 000000000..ff37aab3f --- /dev/null +++ b/svx/qa/unit/data/tdf121845_start40_swing480.doc diff --git a/svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odp b/svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odp Binary files differnew file mode 100644 index 000000000..fbe1b7d40 --- /dev/null +++ b/svx/qa/unit/data/tdf121952_Toggle_direction_command_X.odp diff --git a/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx b/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx Binary files differnew file mode 100644 index 000000000..919675ef9 --- /dev/null +++ b/svx/qa/unit/data/tdf122323_swingAngle_larger360deg.pptx diff --git a/svx/qa/unit/data/tdf122964_MultipleMoveTo.odg b/svx/qa/unit/data/tdf122964_MultipleMoveTo.odg Binary files differnew file mode 100644 index 000000000..63d80fd06 --- /dev/null +++ b/svx/qa/unit/data/tdf122964_MultipleMoveTo.odg diff --git a/svx/qa/unit/data/tdf124029_Arc_position.doc b/svx/qa/unit/data/tdf124029_Arc_position.doc Binary files differnew file mode 100644 index 000000000..d5396c375 --- /dev/null +++ b/svx/qa/unit/data/tdf124029_Arc_position.doc diff --git a/svx/qa/unit/data/tdf124212_handle_position.odg b/svx/qa/unit/data/tdf124212_handle_position.odg Binary files differnew file mode 100644 index 000000000..7a4eb0517 --- /dev/null +++ b/svx/qa/unit/data/tdf124212_handle_position.odg diff --git a/svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptx b/svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptx Binary files differnew file mode 100644 index 000000000..dd6df7b03 --- /dev/null +++ b/svx/qa/unit/data/tdf124740_HandleInOOXMLUserShape.pptx diff --git a/svx/qa/unit/data/tdf125782_QuadraticCurveTo.odg b/svx/qa/unit/data/tdf125782_QuadraticCurveTo.odg Binary files differnew file mode 100644 index 000000000..ba7b49536 --- /dev/null +++ b/svx/qa/unit/data/tdf125782_QuadraticCurveTo.odg diff --git a/svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptx b/svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptx Binary files differnew file mode 100644 index 000000000..8c8798f21 --- /dev/null +++ b/svx/qa/unit/data/tdf126060_3D_Z_Rotation.pptx diff --git a/svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odp b/svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odp Binary files differnew file mode 100644 index 000000000..7dd283f88 --- /dev/null +++ b/svx/qa/unit/data/tdf126512_OOXMLHandleMovementInODF.odp diff --git a/svx/qa/unit/data/tdf127785_Mirror.odp b/svx/qa/unit/data/tdf127785_Mirror.odp Binary files differnew file mode 100644 index 000000000..ff867839f --- /dev/null +++ b/svx/qa/unit/data/tdf127785_Mirror.odp diff --git a/svx/qa/unit/data/tdf127785_TextRotateAngle.odp b/svx/qa/unit/data/tdf127785_TextRotateAngle.odp Binary files differnew file mode 100644 index 000000000..742f12d4d --- /dev/null +++ b/svx/qa/unit/data/tdf127785_TextRotateAngle.odp diff --git a/svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odg b/svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odg Binary files differnew file mode 100644 index 000000000..ea700eaf7 --- /dev/null +++ b/svx/qa/unit/data/tdf127785_asymmetricTextBoxFlipV.odg diff --git a/svx/qa/unit/data/tdf128413_tbrl_OnOff.odp b/svx/qa/unit/data/tdf128413_tbrl_OnOff.odp Binary files differnew file mode 100644 index 000000000..f10f98bbe --- /dev/null +++ b/svx/qa/unit/data/tdf128413_tbrl_OnOff.odp diff --git a/svx/qa/unit/data/tdf129532_MatrixFlipV.odg b/svx/qa/unit/data/tdf129532_MatrixFlipV.odg Binary files differnew file mode 100644 index 000000000..eb0c10b3d --- /dev/null +++ b/svx/qa/unit/data/tdf129532_MatrixFlipV.odg diff --git a/svx/qa/unit/data/tdf136176_rot30_flip.odg b/svx/qa/unit/data/tdf136176_rot30_flip.odg Binary files differnew file mode 100644 index 000000000..75707a0f5 --- /dev/null +++ b/svx/qa/unit/data/tdf136176_rot30_flip.odg diff --git a/svx/qa/unit/data/tdf93998.odp b/svx/qa/unit/data/tdf93998.odp Binary files differnew file mode 100644 index 000000000..889aeeb02 --- /dev/null +++ b/svx/qa/unit/data/tdf93998.odp diff --git a/svx/qa/unit/data/tdf98583_ShearHorizontal.odp b/svx/qa/unit/data/tdf98583_ShearHorizontal.odp Binary files differnew file mode 100644 index 000000000..37719e825 --- /dev/null +++ b/svx/qa/unit/data/tdf98583_ShearHorizontal.odp diff --git a/svx/qa/unit/data/tdf98584_ShearVertical.odg b/svx/qa/unit/data/tdf98584_ShearVertical.odg Binary files differnew file mode 100644 index 000000000..457521d50 --- /dev/null +++ b/svx/qa/unit/data/tdf98584_ShearVertical.odg diff --git a/svx/qa/unit/data/unodraw-writer-image.odt b/svx/qa/unit/data/unodraw-writer-image.odt Binary files differnew file mode 100644 index 000000000..5264118a3 --- /dev/null +++ b/svx/qa/unit/data/unodraw-writer-image.odt diff --git a/svx/qa/unit/data/viewBox_positive_twolines_strict.odp b/svx/qa/unit/data/viewBox_positive_twolines_strict.odp Binary files differnew file mode 100644 index 000000000..3425582b8 --- /dev/null +++ b/svx/qa/unit/data/viewBox_positive_twolines_strict.odp diff --git a/svx/qa/unit/gallery/test_gallery.cxx b/svx/qa/unit/gallery/test_gallery.cxx new file mode 100644 index 000000000..4c95e461a --- /dev/null +++ b/svx/qa/unit/gallery/test_gallery.cxx @@ -0,0 +1,306 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* +* This file is part of the LibreOffice project. +* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#include <tools/urlobj.hxx> +#include <sfx2/app.hxx> +#include <unotools/tempfile.hxx> +#include <comphelper/DirectoryHelper.hxx> + +#include <svx/gallery1.hxx> +#include <svx/galtheme.hxx> +#include <galobj.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +class GalleryObjTest : public CppUnit::TestFixture +{ +public: + void TestCreateTheme(); + void TestDeleteTheme(); + void TestSetThemeName(); + void TestThemeURLCase(); + void TestThemeCount(); + void TestGalleryThemeEntry(); + void TestInsertGalleryObject(); + + CPPUNIT_TEST_SUITE(GalleryObjTest); + + CPPUNIT_TEST(TestCreateTheme); + CPPUNIT_TEST(TestDeleteTheme); + CPPUNIT_TEST(TestSetThemeName); + CPPUNIT_TEST(TestThemeURLCase); + CPPUNIT_TEST(TestThemeCount); + CPPUNIT_TEST(TestGalleryThemeEntry); + CPPUNIT_TEST(TestInsertGalleryObject); + + CPPUNIT_TEST_SUITE_END(); +}; + +// Create and Dereference a theme, check that file exists +void GalleryObjTest::TestCreateTheme() +{ + // Create theme + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + // Check if directory exists + CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory", + comphelper::DirectoryHelper::dirExists(aGalleryURL)); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + const OUString myThemeName = "addytesttheme"; + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + + // check if files exist + CPPUNIT_ASSERT_MESSAGE( + "Could not find .thm file inside it", + comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm")); + CPPUNIT_ASSERT_MESSAGE( + "Could not find .sdv file inside it", + comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv")); +} + +// Create and Delete Theme, check the file doesn't exist +void GalleryObjTest::TestDeleteTheme() +{ + // Create theme + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + const OUString myThemeName = "addytesttheme"; + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + + // Delete Theme + CPPUNIT_ASSERT_MESSAGE("Could not remove theme", pGallery->RemoveTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not remove theme, theme found even after trying to remove", + !pGallery->HasTheme(myThemeName)); + + // Check that files do not exist + CPPUNIT_ASSERT_MESSAGE( + "Found .thm file inside it after deletion", + !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm")); + CPPUNIT_ASSERT_MESSAGE( + "Found .sdv file inside it after deletion", + !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv")); + CPPUNIT_ASSERT_MESSAGE( + "Found .sdg file inside it after deletion", + !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdg")); + CPPUNIT_ASSERT_MESSAGE( + "Found .str file inside it after deletion", + !comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".str")); +} + +// Create theme, set name, assert the name is expected +void GalleryObjTest::TestSetThemeName() +{ + // Create theme + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + const OUString myThemeName = "addytesttheme"; + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + + // Rename theme + const OUString myNewThemeName = "addytestthemenew"; + pGallery->RenameTheme(myThemeName, myNewThemeName); + CPPUNIT_ASSERT_MESSAGE("Could not rename theme because old theme name still exists", + !pGallery->HasTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find new renamed theme", pGallery->HasTheme(myNewThemeName)); + + // Check that files are not renamed + CPPUNIT_ASSERT_MESSAGE( + "Could not find .thm file inside it", + comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm")); + CPPUNIT_ASSERT_MESSAGE( + "Could not find .sdv file inside it", + comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv")); +} + +void GalleryObjTest::TestThemeURLCase() +{ + // Create theme + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + // Check if directory exists + CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory", + comphelper::DirectoryHelper::dirExists(aGalleryURL)); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + + // Mixed Case Theme Name + const OUString myThemeName = "AddyTestTheme"; + + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + +#if defined(LINUX) + CPPUNIT_ASSERT_MESSAGE("[LINUX] Could not find .thm in lowercase", + comphelper::DirectoryHelper::fileExists( + aGalleryURL + "/" + myThemeName.toAsciiLowerCase() + ".thm")); + CPPUNIT_ASSERT_MESSAGE("[LINUX] Could not find .sdv in lowercase", + comphelper::DirectoryHelper::fileExists( + aGalleryURL + "/" + myThemeName.toAsciiLowerCase() + ".sdv")); +#else + CPPUNIT_ASSERT_MESSAGE( + "[WINDOWS] Could not find .thm in mixed case", + comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".thm")); + CPPUNIT_ASSERT_MESSAGE( + "[WINDOWS] Could not find .sdv in mixed case", + comphelper::DirectoryHelper::fileExists(aGalleryURL + "/" + myThemeName + ".sdv")); +#endif +} + +void GalleryObjTest::TestThemeCount() +{ + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + // Check if directory exists + CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory", + comphelper::DirectoryHelper::dirExists(aGalleryURL)); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + + // Loop through and test theme count in each pass. + sal_uInt32 nLimit = 10; + for (sal_uInt32 i = 1; i <= nLimit; i++) + { + OUString myThemeName = "addytesttheme" + OUString::number(i); + // Create theme + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent theme count", + static_cast<sal_uInt32>(pGallery->GetThemeCount()), i); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent theme count", + static_cast<sal_uInt32>(pGallery->GetThemeCount()), nLimit); + for (sal_uInt32 i = nLimit; i > 0; i--) + { + OUString myThemeName = "addytesttheme" + OUString::number(i); + // Delete Theme + CPPUNIT_ASSERT_MESSAGE("Could not remove theme", pGallery->RemoveTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not remove theme, theme found even after trying to remove", + !pGallery->HasTheme(myThemeName)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Inconsistent theme count", + static_cast<sal_uInt32>(pGallery->GetThemeCount()), i - 1); + } +} + +void GalleryObjTest::TestGalleryThemeEntry() +{ + // Create theme + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + // Check if directory exists + CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory", + comphelper::DirectoryHelper::dirExists(aGalleryURL)); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + const OUString myThemeName = "addytesttheme"; + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + + // Get Theme Entry Object + const GalleryThemeEntry* mpThemeEntry = pGallery->GetThemeInfo(myThemeName); + + // Check Theme Name + CPPUNIT_ASSERT_EQUAL_MESSAGE("Theme name doesn't match", mpThemeEntry->GetThemeName(), + myThemeName); + + // Check URLs + INetURLObject aURL(aGalleryURL); + aURL.Append(myThemeName); + INetURLObject aThemeURL(aURL), aSdvURL(aURL), aSdgURL(aURL), aStrURL(aURL); + aThemeURL.setExtension("thm"); + aSdvURL.setExtension("sdv"); + aSdgURL.setExtension("sdg"); + aStrURL.setExtension("str"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Theme URL doesn't match", + mpThemeEntry->GetThmURL().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous), + aThemeURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sdv URL doesn't match", + mpThemeEntry->GetSdvURL().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous), + aSdvURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sdg URL doesn't match", + mpThemeEntry->GetSdgURL().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous), + aSdgURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Str URL doesn't match", + mpThemeEntry->GetStrURL().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous), + aStrURL.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)); +} + +void GalleryObjTest::TestInsertGalleryObject() +{ + // Create theme + std::unique_ptr<utl::TempFile> pTempDir; + pTempDir.reset(new utl::TempFile(nullptr, true)); + CPPUNIT_ASSERT_MESSAGE("Could not create valid temporary directory", pTempDir->IsValid()); + pTempDir->EnableKillingFile(); + const OUString aGalleryURL = pTempDir->GetURL(); + + // Check if directory exists + CPPUNIT_ASSERT_MESSAGE("Could not create temporary directory", + comphelper::DirectoryHelper::dirExists(aGalleryURL)); + + std::unique_ptr<Gallery> pGallery(new Gallery(aGalleryURL)); + CPPUNIT_ASSERT_MESSAGE("Could not create gallery instance", (pGallery != nullptr)); + const OUString myThemeName = "addytesttheme"; + CPPUNIT_ASSERT_MESSAGE("Could not create theme", pGallery->CreateTheme(myThemeName)); + CPPUNIT_ASSERT_MESSAGE("Could not find theme", pGallery->HasTheme(myThemeName)); + + // Insert Objects Into Theme + SfxListener aListener; + SfxApplication::GetOrCreate(); + GalleryTheme* pGalleryTheme = pGallery->AcquireTheme(myThemeName, aListener); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), pGalleryTheme->GetObjectCount()); + + pGallery->ReleaseTheme(pGalleryTheme, aListener); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(GalleryObjTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/svx/qa/unit/sdr.cxx b/svx/qa/unit/sdr.cxx new file mode 100644 index 000000000..18cfd8400 --- /dev/null +++ b/svx/qa/unit/sdr.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <test/bootstrapfixture.hxx> +#include <unotest/macros_test.hxx> +#include <test/xmltesttools.hxx> + +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/frame/Desktop.hpp> + +#include <drawinglayer/tools/primitive2dxmldump.hxx> +#include <rtl/ustring.hxx> +#include <svx/sdr/contact/displayinfo.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/svdpage.hxx> +#include <svx/unopage.hxx> +#include <vcl/virdev.hxx> +#include <sdr/contact/objectcontactofobjlistpainter.hxx> + +using namespace ::com::sun::star; + +namespace +{ +/// Tests for svx/source/sdr/ code. +class SdrTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools +{ +protected: + uno::Reference<lang::XComponent> mxComponent; + +public: + virtual void setUp() override + { + test::BootstrapFixture::setUp(); + mxDesktop.set(frame::Desktop::create(m_xContext)); + } + + virtual void tearDown() override + { + if (mxComponent.is()) + { + mxComponent->dispose(); + } + test::BootstrapFixture::tearDown(); + } + uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } +}; + +CPPUNIT_TEST_FIXTURE(SdrTest, testShadowScaleOrigin) +{ + // Load a document containing a custom shape. + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc("svx/qa/unit/data/shadow-scale-origin.pptx"); + getComponent() = loadFromDesktop(aURL); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + + // Render it. + auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get()); + CPPUNIT_ASSERT(pDrawPage); + SdrPage* pSdrPage = pDrawPage->GetSdrPage(); + ScopedVclPtrInstance<VirtualDevice> aVirtualDevice; + sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice, + { pSdrPage->GetObj(0) }, nullptr); + const sdr::contact::ViewObjectContact& rDrawPageVOContact + = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact); + sdr::contact::DisplayInfo aDisplayInfo; + drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence + = rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo); + + // Examine the created primitives. + drawinglayer::tools::Primitive2dXmlDump aDumper; + xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence); + double fShadowX = getXPath(pDocument, "//shadow/transform", "xy13").toDouble(); + double fShadowY = getXPath(pDocument, "//shadow/transform", "xy23").toDouble(); + // 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)); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx new file mode 100644 index 000000000..5a0f46bba --- /dev/null +++ b/svx/qa/unit/svdraw.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <test/bootstrapfixture.hxx> +#include <unotest/macros_test.hxx> +#include <test/xmltesttools.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +#include <drawinglayer/tools/primitive2dxmldump.hxx> +#include <rtl/ustring.hxx> +#include <svx/sdr/contact/displayinfo.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/svdpage.hxx> +#include <svx/unopage.hxx> +#include <vcl/virdev.hxx> +#include <sdr/contact/objectcontactofobjlistpainter.hxx> + +using namespace ::com::sun::star; + +namespace +{ +/// Tests for svx/source/svdraw/ code. +class SvdrawTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools +{ +protected: + uno::Reference<lang::XComponent> mxComponent; + +public: + virtual void setUp() override + { + test::BootstrapFixture::setUp(); + mxDesktop.set(frame::Desktop::create(m_xContext)); + } + + virtual void tearDown() override + { + if (mxComponent.is()) + { + mxComponent->dispose(); + } + test::BootstrapFixture::tearDown(); + } + uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } +}; + +CPPUNIT_TEST_FIXTURE(SvdrawTest, testSemiTransparentText) +{ + // Create a new Draw document with a rectangle. + getComponent() = loadFromDesktop("private:factory/sdraw"); + uno::Reference<lang::XMultiServiceFactory> xFactory(getComponent(), uno::UNO_QUERY); + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(10000, 10000)); + xShape->setPosition(awt::Point(1000, 1000)); + + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + xDrawPage->add(xShape); + + // Add semi-transparent text on the rectangle. + uno::Reference<text::XTextRange> xShapeText(xShape, uno::UNO_QUERY); + xShapeText->getText()->setString("hello"); + + uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY); + xShapeProperties->setPropertyValue("CharColor", uno::makeAny(COL_RED)); + sal_Int16 nTransparence = 75; + xShapeProperties->setPropertyValue("CharTransparence", uno::makeAny(nTransparence)); + + // Generates drawinglayer primitives for the page. + auto pDrawPage = dynamic_cast<SvxDrawPage*>(xDrawPage.get()); + CPPUNIT_ASSERT(pDrawPage); + SdrPage* pSdrPage = pDrawPage->GetSdrPage(); + ScopedVclPtrInstance<VirtualDevice> aVirtualDevice; + sdr::contact::ObjectContactOfObjListPainter aObjectContact(*aVirtualDevice, + { pSdrPage->GetObj(0) }, nullptr); + const sdr::contact::ViewObjectContact& rDrawPageVOContact + = pSdrPage->GetViewContact().GetViewObjectContact(aObjectContact); + sdr::contact::DisplayInfo aDisplayInfo; + drawinglayer::primitive2d::Primitive2DContainer xPrimitiveSequence + = rDrawPageVOContact.getPrimitive2DSequenceHierarchy(aDisplayInfo); + + // Make sure the text is semi-transparent. + drawinglayer::tools::Primitive2dXmlDump aDumper; + xmlDocUniquePtr pDocument = aDumper.dumpAndParse(xPrimitiveSequence); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - 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))); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/svdraw/test_SdrTextObject.cxx b/svx/qa/unit/svdraw/test_SdrTextObject.cxx new file mode 100644 index 000000000..7af646b0b --- /dev/null +++ b/svx/qa/unit/svdraw/test_SdrTextObject.cxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <svx/svdotext.hxx> +#include <rtl/ustring.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +class SdrTextObjTest : public CppUnit::TestFixture { +public: + void AllFamiliesCanBeRestoredFromSavedString(); + + CPPUNIT_TEST_SUITE(SdrTextObjTest); + CPPUNIT_TEST(AllFamiliesCanBeRestoredFromSavedString); + CPPUNIT_TEST_SUITE_END(); +}; + +void SdrTextObjTest::AllFamiliesCanBeRestoredFromSavedString() { + std::vector<SfxStyleFamily> allFamilies; + allFamilies.push_back(SfxStyleFamily::Char); + allFamilies.push_back(SfxStyleFamily::Para); + allFamilies.push_back(SfxStyleFamily::Page); + allFamilies.push_back(SfxStyleFamily::Pseudo); + + for (SfxStyleFamily family : allFamilies) { + OUString styleName = "styleName"; + SdrTextObj::AppendFamilyToStyleName(styleName, family); + SfxStyleFamily readFamily = SdrTextObj::ReadFamilyFromStyleName(styleName); + CPPUNIT_ASSERT_EQUAL(static_cast<int>(family), static_cast<int>(readFamily)); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(SdrTextObjTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/svx-dialogs-test.cxx b/svx/qa/unit/svx-dialogs-test.cxx new file mode 100644 index 000000000..eaa829569 --- /dev/null +++ b/svx/qa/unit/svx-dialogs-test.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> +#include <test/screenshot_test.hxx> +#include <vcl/abstdlg.hxx> + +using namespace ::com::sun::star; + +/// Test opening a dialog in svx +class SvxDialogsTest : public ScreenshotTest +{ +private: + /// helper method to populate KnownDialogs, called in setUp(). Needs to be + /// written and has to add entries to KnownDialogs + virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override; + + /// dialog creation for known dialogs by ID. Has to be implemented for + /// each registered known dialog + virtual VclPtr<VclAbstractDialog> createDialogByID(sal_uInt32 nID) override; + +public: + SvxDialogsTest(); + + // try to open a dialog + void openAnyDialog(); + + CPPUNIT_TEST_SUITE(SvxDialogsTest); + CPPUNIT_TEST(openAnyDialog); + CPPUNIT_TEST_SUITE_END(); +}; + +SvxDialogsTest::SvxDialogsTest() +{ +} + +void SvxDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/) +{ + // fill map of known dialogs +} + +VclPtr<VclAbstractDialog> SvxDialogsTest::createDialogByID(sal_uInt32 /*nID*/) +{ + return nullptr; +} + +void SvxDialogsTest::openAnyDialog() +{ + /// process input file containing the UXMLDescriptions of the dialogs to dump + processDialogBatchFile("svx/qa/unit/data/svx-dialogs-test.txt"); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(SvxDialogsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/unodraw.cxx b/svx/qa/unit/unodraw.cxx new file mode 100644 index 000000000..a835dee95 --- /dev/null +++ b/svx/qa/unit/unodraw.cxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <cppunit/TestAssert.h> + +#include <com/sun/star/drawing/GraphicExportFilter.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <test/bootstrapfixture.hxx> +#include <unotest/macros_test.hxx> +#include <unotools/tempfile.hxx> + +using namespace ::com::sun::star; + +namespace +{ +char const DATA_DIRECTORY[] = "/svx/qa/unit/data/"; + +/// Tests for svx/source/unodraw/ code. +class UnodrawTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +protected: + uno::Reference<lang::XComponent> mxComponent; + +public: + void setUp() override; + void tearDown() override; +}; + +void UnodrawTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void UnodrawTest::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +CPPUNIT_TEST_FIXTURE(UnodrawTest, testWriterGraphicExport) +{ + // Load a document with a Writer picture in it. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "unodraw-writer-image.odt"; + mxComponent = loadFromDesktop(aURL); + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference<lang::XComponent> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + + // Export it as JPEG. + uno::Reference<drawing::XGraphicExportFilter> xExportFilter + = drawing::GraphicExportFilter::create(mxComponentContext); + // This resulted in a css::lang::IllegalArgumentException for a Writer + // picture. + xExportFilter->setSourceDocument(xShape); + + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + uno::Sequence<beans::PropertyValue> aProperties( + comphelper::InitPropertySequence({ { "URL", uno::Any(aTempFile.GetURL()) }, + { "MediaType", uno::Any(OUString("image/jpeg")) } })); + CPPUNIT_ASSERT(xExportFilter->filter(aProperties)); +} + +CPPUNIT_TEST_FIXTURE(UnodrawTest, testTdf93998) +{ + mxComponent = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf93998.odp"); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xDrawPagesSupplier.is()); + + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xDrawPage.is()); + + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xShape.is()); + + uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory(); + uno::Reference<awt::XControlModel> xModel( + xFactory->createInstance("com.sun.star.awt.UnoControlDialogModel"), uno::UNO_QUERY); + CPPUNIT_ASSERT(xModel.is()); + + uno::Reference<beans::XPropertySet> xModelProps(xModel, uno::UNO_QUERY); + CPPUNIT_ASSERT(xModelProps.is()); + + // This resulted in a uno::RuntimeException, assigning a shape to a dialog model's image was + // broken. + xModelProps->setPropertyValue("ImageURL", xShape->getPropertyValue("GraphicURL")); + uno::Reference<graphic::XGraphic> xGraphic; + xModelProps->getPropertyValue("Graphic") >>= xGraphic; + CPPUNIT_ASSERT(xGraphic.is()); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/qa/unit/xoutdev.cxx b/svx/qa/unit/xoutdev.cxx new file mode 100644 index 000000000..0b5148b39 --- /dev/null +++ b/svx/qa/unit/xoutdev.cxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <config_features.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <unotest/bootstrapfixturebase.hxx> + +#include <sal/types.h> +#include <sfx2/app.hxx> +#include <tools/stream.hxx> +#include <unotest/directories.hxx> +#include <unotools/tempfile.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <svx/xoutbmp.hxx> + +class XOutdevTest : public CppUnit::TestFixture +{ +public: + virtual void setUp() override + { + CppUnit::TestFixture::setUp(); + SfxApplication::GetOrCreate(); + } +}; + +CPPUNIT_TEST_FIXTURE(XOutdevTest, testPdfGraphicExport) +{ +#if HAVE_FEATURE_PDFIUM + // Import the graphic. + Graphic aGraphic; + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc("svx/qa/unit/data/graphic.pdf"); + SvFileStream aStream(aURL, StreamMode::READ); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, + GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aURL, aStream)); + + // Export it. + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + XOutFlags const eFlags = XOutFlags::DontExpandFilename | XOutFlags::DontAddExtension + | XOutFlags::UseNativeIfPossible; + OUString aTempURL = aTempFile.GetURL(); + XOutBitmap::WriteGraphic(aGraphic, aTempURL, "pdf", eFlags); + + // Assert that the output looks like a PDF. + SvStream* pStream = aTempFile.GetStream(StreamMode::READ); + CPPUNIT_ASSERT(pStream->TellEnd() > 5); + sal_uInt8 sFirstBytes[5]; + pStream->ReadBytes(sFirstBytes, 5); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('%'), sFirstBytes[0]); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('P'), sFirstBytes[1]); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('D'), sFirstBytes[2]); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('F'), sFirstBytes[3]); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>('-'), sFirstBytes[4]); +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |