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 /vcl/qa/cppunit | |
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 'vcl/qa/cppunit')
307 files changed, 17837 insertions, 0 deletions
diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx new file mode 100644 index 000000000..ff4ed0d87 --- /dev/null +++ b/vcl/qa/cppunit/BackendTest.cxx @@ -0,0 +1,599 @@ +/* -*- 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 <vcl/bitmap.hxx> +#include <tools/stream.hxx> +#include <vcl/graphicfilter.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include <test/outputdevice.hxx> + +class BackendTest : public test::BootstrapFixture +{ + // if enabled - check the result images with: + // "xdg-open ./workdir/CppunitTest/vcl_backend_test.test.core/" + static constexpr const bool mbExportBitmap = false; + + void exportImage(OUString const& rsFilename, BitmapEx const& rBitmapEx) + { + if (mbExportBitmap) + { + BitmapEx aBitmapEx(rBitmapEx); + aBitmapEx.Scale(Size(128, 128), BmpScaleFlag::Fast); + SvFileStream aStream(rsFilename, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream); + } + } + + void exportImage(OUString const& rsFilename, Bitmap const& rBitmap) + { + if (mbExportBitmap) + { + Bitmap aBitmap(rBitmap); + aBitmap.Scale(Size(128, 128), BmpScaleFlag::Fast); + SvFileStream aStream(rsFilename, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmap, aStream); + } + } + + void exportDevice(const OUString& filename, const VclPtr<VirtualDevice>& device) + { + if (mbExportBitmap) + { + BitmapEx aBitmapEx(device->GetBitmap(Point(0, 0), device->GetOutputSizePixel())); + SvFileStream aStream(filename, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream); + } + } + +public: + BackendTest() + : BootstrapFixture(true, false) + { + } + + // We need to enable tests ONE BY ONE as they fail because of backend bugs + // it is still important to have the test defined so we know the issues + // exist and we need to fix them. Consistent behaviour of our backends + // is of highest priority. + + static bool assertBackendNameNotEmpty(const OUString& name) + { + // This ensures that all backends return a valid name. + assert(!name.isEmpty()); + (void)name; + return false; + } + +// Check whether tests should fail depending on which backend is used +// (not all work). If you want to disable just a specific test +// for a specific backend, use something like +// 'if(SHOULD_ASSERT && aOutDevTest.getRenderBackendName() != "skia")'. +#define SHOULD_ASSERT \ + (assertBackendNameNotEmpty(aOutDevTest.getRenderBackendName()) \ + || aOutDevTest.getRenderBackendName() == "skia") + + void testDrawRectWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-01_rectangle_test-rectangle.png", aBitmap); + + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPixel() + { + vcl::test::OutputDeviceTestPixel aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-02_rectangle_test-pixel.png", aBitmap); + + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-03_rectangle_test-line.png", aBitmap); + + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-04_rectangle_test-polygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyLine() + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-05_rectangle_test-polyline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyLineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-06_rectangle_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyPolygon() + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-07_rectangle_test-polypolygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyPolygonB2D() + { + vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-08_rectangle_test-polypolygon_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-01_rectangle_AA_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPixel() + { + vcl::test::OutputDeviceTestPixel aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-02_rectangle_AA_test-pixel.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-03_rectangle_AA_test-line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-04_rectangle_AA_test-polygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyLine() + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-05_rectangle_AA_test-polyline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyLineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-06_rectangle_AA_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyPolygon() + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-07_rectangle_AA_test-polypolygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyPolygonB2D() + { + vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-08_rectangle_AA_test-polypolygon_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-01_filled_rectangle_test-rectangle_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-01_filled_rectangle_test-rectangle_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-02_filled_rectangle_test-polygon_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-02_filled_rectangle_test-polygon_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithPolyPolygon() + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-03_filled_rectangle_test-polypolygon_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-03_filled_rectangle_test-polypolygon_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithPolyPolygon2D() + { + vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-04_filled_rectangle_test-polypolygon_b2d_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-04_filled_rectangle_test-polypolygon_b2d_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-01_diamond_test-polygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-02_diamond_test-line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithPolyline() + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-03_diamond_test-polyline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithPolylineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-04_diamond_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawInvertWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_NONE(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertRectangle(aBitmap); + exportImage("05-01_invert_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawInvertN50WithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_N50(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertN50Rectangle(aBitmap); + exportImage("05-02_invert_N50_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawInvertTrackFrameWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_TrackFrame(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertTrackFrameRectangle(aBitmap); + exportImage("05-03_invert_TrackFrame_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBezierWithPolylineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupBezier(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkBezier(aBitmap); + exportImage("06-01_bezier_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBezierAAWithPolylineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupAABezier(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkBezier(aBitmap); + exportImage("07-01_bezier_AA_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBitmap() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawBitmap(); + exportImage("08-01_bitmap_test.png", aBitmap); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawTransformedBitmap() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawTransformedBitmap(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap); + exportImage("08-02_transformed_bitmap_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBitmapExWithAlpha() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawBitmapExWithAlpha(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkBitmapExWithAlpha(aBitmap); + exportImage("08-03_bitmapex_with_alpha_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawMask() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawMask(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkMask(aBitmap); + exportImage("08-04_mask_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBlend() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + BitmapEx aBitmapEx = aOutDevTest.setupDrawBlend(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkBlend(aBitmapEx); + exportImage("08-05_blend_test.png", aBitmapEx); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawXor() + { + vcl::test::OutputDeviceTestAnotherOutDev aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupXOR(); + auto eResult = vcl::test::OutputDeviceTestAnotherOutDev::checkXOR(aBitmap); + exportImage("08-06_xor_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipRectangle() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipRectangle(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-01_clip_rectangle_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipPolygon() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipPolygon(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-02_clip_polygon_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipPolyPolygon() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipPolyPolygon(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-03_clip_polypolygon_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipB2DPolyPolygon() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipB2DPolyPolygon(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-04_clip_b2dpolypolygon_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDashedLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDashedLine(); + auto eResult = vcl::test::OutputDeviceTestLine::checkDashedLine(aBitmap); + exportImage("10-01_dashed_line_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testTdf124848() + { + ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT); + device->SetOutputSizePixel(Size(100, 100)); + device->SetBackground(Wallpaper(COL_WHITE)); + device->Erase(); + device->SetAntialiasing(AntialiasingFlags::EnableB2dDraw); + device->SetLineColor(COL_BLACK); + basegfx::B2DHomMatrix matrix; + // DrawPolyLine() would apply the whole matrix to the line width, making it negative + // in case of a larger rotation. + matrix.rotate(M_PI); //180 degrees + matrix.translate(100, 100); + CPPUNIT_ASSERT(device->DrawPolyLineDirect(matrix, + basegfx::B2DPolygon{ { 50, 50 }, { 50, 100 } }, + 100, 0, nullptr, basegfx::B2DLineJoin::Miter)); + exportDevice("/tmp/tdf124848-1.png", device); + // 100px wide line should fill the entire width of the upper half + CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(2, 2))); + + // Also check hairline. + device->Erase(); + CPPUNIT_ASSERT(device->DrawPolyLineDirect(matrix, + basegfx::B2DPolygon{ { 50, 50 }, { 50, 100 } }, 0, + 0, nullptr, basegfx::B2DLineJoin::Miter)); + exportDevice("/tmp/tdf124848-2.png", device); + // 1px wide + CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(50, 20))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(49, 20))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(51, 20))); + } + + CPPUNIT_TEST_SUITE(BackendTest); + CPPUNIT_TEST(testDrawRectWithRectangle); + CPPUNIT_TEST(testDrawRectWithPixel); + CPPUNIT_TEST(testDrawRectWithLine); + CPPUNIT_TEST(testDrawRectWithPolygon); + CPPUNIT_TEST(testDrawRectWithPolyLine); + CPPUNIT_TEST(testDrawRectWithPolyLineB2D); + CPPUNIT_TEST(testDrawRectWithPolyPolygon); + CPPUNIT_TEST(testDrawRectWithPolyPolygonB2D); + + CPPUNIT_TEST(testDrawRectAAWithRectangle); + CPPUNIT_TEST(testDrawRectAAWithPixel); + CPPUNIT_TEST(testDrawRectAAWithLine); + CPPUNIT_TEST(testDrawRectAAWithPolygon); + CPPUNIT_TEST(testDrawRectAAWithPolyLine); + CPPUNIT_TEST(testDrawRectAAWithPolyLineB2D); + CPPUNIT_TEST(testDrawRectAAWithPolyPolygon); + CPPUNIT_TEST(testDrawRectAAWithPolyPolygonB2D); + + CPPUNIT_TEST(testDrawFilledRectWithRectangle); + CPPUNIT_TEST(testDrawFilledRectWithPolygon); + CPPUNIT_TEST(testDrawFilledRectWithPolyPolygon); + CPPUNIT_TEST(testDrawFilledRectWithPolyPolygon2D); + + CPPUNIT_TEST(testDrawDiamondWithPolygon); + CPPUNIT_TEST(testDrawDiamondWithLine); + CPPUNIT_TEST(testDrawDiamondWithPolyline); + CPPUNIT_TEST(testDrawDiamondWithPolylineB2D); + + CPPUNIT_TEST(testDrawInvertWithRectangle); + CPPUNIT_TEST(testDrawInvertN50WithRectangle); + CPPUNIT_TEST(testDrawInvertTrackFrameWithRectangle); + + CPPUNIT_TEST(testDrawBezierWithPolylineB2D); + CPPUNIT_TEST(testDrawBezierAAWithPolylineB2D); + + CPPUNIT_TEST(testDrawBitmap); + CPPUNIT_TEST(testDrawTransformedBitmap); + CPPUNIT_TEST(testDrawBitmapExWithAlpha); + CPPUNIT_TEST(testDrawMask); + CPPUNIT_TEST(testDrawBlend); + CPPUNIT_TEST(testDrawXor); + + CPPUNIT_TEST(testClipRectangle); + CPPUNIT_TEST(testClipPolygon); + CPPUNIT_TEST(testClipPolyPolygon); + CPPUNIT_TEST(testClipB2DPolyPolygon); + + CPPUNIT_TEST(testDashedLine); + + CPPUNIT_TEST(testTdf124848); + + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BackendTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx new file mode 100644 index 000000000..23f40f001 --- /dev/null +++ b/vcl/qa/cppunit/BitmapExTest.cxx @@ -0,0 +1,113 @@ +/* -*- 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 <vcl/bitmapex.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <bitmapwriteaccess.hxx> +#include <svdata.hxx> +#include <salinst.hxx> + +namespace +{ +class BitmapExTest : public CppUnit::TestFixture +{ + void testGetPixelColor24_8(); + void testGetPixelColor32(); + void testTransformBitmapEx(); + + CPPUNIT_TEST_SUITE(BitmapExTest); + CPPUNIT_TEST(testGetPixelColor24_8); + CPPUNIT_TEST(testGetPixelColor32); + CPPUNIT_TEST(testTransformBitmapEx); + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapExTest::testGetPixelColor24_8() +{ + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x00, 0x00, 0xFF, 0x00)); + } + AlphaMask aMask(Size(3, 3)); + { + AlphaScopedWriteAccess pWriteAccess(aMask); + pWriteAccess->Erase(Color(0x00, 0xAA, 0xAA, 0xAA)); + } + + BitmapEx aBitmapEx(aBitmap, aMask); + + CPPUNIT_ASSERT_EQUAL(Color(0xAA, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(0, 0)); +} + +void BitmapExTest::testGetPixelColor32() +{ + // Check backend capabilities and return from the test successfully + // if the backend doesn't support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (!pBackendCapabilities->mbSupportsBitmap32) + return; + + Bitmap aBitmap(Size(3, 3), 32); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0xAA, 0x00, 0xFF, 0x00)); + } + + BitmapEx aBitmapEx(aBitmap); + + CPPUNIT_ASSERT_EQUAL(Color(0xAA, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(0, 0)); +} + +void BitmapExTest::testTransformBitmapEx() +{ + Bitmap aBitmap(Size(16, 16), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(i, j, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + + basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(M_PI / 2); + BitmapEx aTransformed = aBitmapEx.TransformBitmapEx(16, 16, aMatrix); + aBitmap = aTransformed.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + BitmapColor aColor = pAccess->GetPixel(i, j); + std::stringstream ss; + ss << "Color is expected to be white or black, is '" << aColor.AsRGBHexString() << "'"; + // Without the accompanying fix in place, this test would have failed with: + // - Expression: aColor == COL_WHITE || aColor == COL_BLACK + // - Color is expected to be white or black, is 'bfbfbf' + // i.e. smoothing introduced noise for a simple 90 deg rotation. + CPPUNIT_ASSERT_MESSAGE(ss.str(), aColor == COL_WHITE || aColor == COL_BLACK); + } + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapExTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapFilterTest.cxx b/vcl/qa/cppunit/BitmapFilterTest.cxx new file mode 100644 index 000000000..dddfaf571 --- /dev/null +++ b/vcl/qa/cppunit/BitmapFilterTest.cxx @@ -0,0 +1,216 @@ +/* -*- 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 <vcl/bitmap.hxx> +#include <vcl/bitmapaccess.hxx> +#include <bitmapwriteaccess.hxx> + +#include <tools/stream.hxx> +#include <vcl/graphicfilter.hxx> + +#include <vcl/BitmapBasicMorphologyFilter.hxx> +#include <vcl/BitmapFilterStackBlur.hxx> +#include <BitmapSymmetryCheck.hxx> + +#include <chrono> + +namespace +{ +constexpr bool constWriteResultBitmap(false); +constexpr bool constEnablePerformanceTest(false); + +class BitmapFilterTest : public test::BootstrapFixture +{ +public: + BitmapFilterTest() + : test::BootstrapFixture(true, false) + { + } + + void testBlurCorrectness(); + void testBasicMorphology(); + void testPerformance(); + + CPPUNIT_TEST_SUITE(BitmapFilterTest); + CPPUNIT_TEST(testBlurCorrectness); + CPPUNIT_TEST(testBasicMorphology); + CPPUNIT_TEST(testPerformance); + CPPUNIT_TEST_SUITE_END(); + +private: + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc("vcl/qa/cppunit/data/") + sFileName; + } + + BitmapEx loadBitmap(const OUString& sFileName) + { + Graphic aGraphic; + const OUString aURL(getFullUrl(sFileName)); + SvFileStream aFileStream(aURL, StreamMode::READ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + ErrCode aResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aResult); + return aGraphic.GetBitmapEx(); + } + + template <class BitmapT> // handle both Bitmap and BitmapEx + void savePNG(const OUString& sWhere, const BitmapT& rBmp) + { + SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(rBmp, aStream); + } +}; + +void BitmapFilterTest::testBlurCorrectness() +{ + // Setup test bitmap + Size aSize(41, 31); + Bitmap aBitmap24Bit(aSize, 24); + + ScanlineFormat scanlineFormat = ScanlineFormat::NONE; + sal_uInt16 nBPP = aBitmap24Bit.GetBitCount(); + + { + long aMargin1 = 1; + long aMargin2 = 3; + BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit); + scanlineFormat = aWriteAccess->GetScanlineFormat(); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + + tools::Rectangle aRectangle1(aMargin1, aMargin1, aSize.Width() - 1 - aMargin1, + aSize.Height() - 1 - aMargin1); + + tools::Rectangle aRectangle2(aMargin2, aMargin2, aSize.Width() - 1 - aMargin2, + aSize.Height() - 1 - aMargin2); + + tools::Rectangle aRectangle3(aSize.Width() / 2, aSize.Height() / 2, aSize.Width() / 2, + aSize.Height() / 2); + + aWriteAccess->DrawRect(aRectangle1); + aWriteAccess->DrawRect(aRectangle2); + aWriteAccess->DrawRect(aRectangle3); + } + + if (constWriteResultBitmap) + { + savePNG("~/blurBefore.png", aBitmap24Bit); + } + + // Perform blur + BitmapFilterStackBlur aBlurFilter(2); + aBitmap24Bit = aBlurFilter.filter(aBitmap24Bit); + + // Check the result + + if (constWriteResultBitmap) + { + savePNG("~/blurAfter.png", aBitmap24Bit); + } + + // Check blurred bitmap parameters + CPPUNIT_ASSERT_EQUAL(static_cast<long>(41), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(31), aBitmap24Bit.GetSizePixel().Height()); + + CPPUNIT_ASSERT_EQUAL(nBPP, aBitmap24Bit.GetBitCount()); + + // Check that the bitmap is horizontally and vertically symmetrical + CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit)); + + { + Bitmap::ScopedReadAccess aReadAccess(aBitmap24Bit); + CPPUNIT_ASSERT_EQUAL(scanlineFormat, aReadAccess->GetScanlineFormat()); + } +} + +void BitmapFilterTest::testBasicMorphology() +{ + const BitmapEx aOrigBitmap = loadBitmap("testBasicMorphology.png"); + const BitmapEx aRefBitmapDilated1 = loadBitmap("testBasicMorphologyDilated1.png"); + const BitmapEx aRefBitmapDilated1Eroded1 = loadBitmap("testBasicMorphologyDilated1Eroded1.png"); + const BitmapEx aRefBitmapDilated2 = loadBitmap("testBasicMorphologyDilated2.png"); + const BitmapEx aRefBitmapDilated2Eroded1 = loadBitmap("testBasicMorphologyDilated2Eroded1.png"); + + BitmapEx aTransformBitmap = aOrigBitmap; + BitmapFilter::Filter(aTransformBitmap, BitmapDilateFilter(1)); + if (constWriteResultBitmap) + savePNG("~/Dilated1.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated1.GetChecksum(), aTransformBitmap.GetChecksum()); + BitmapFilter::Filter(aTransformBitmap, BitmapErodeFilter(1)); + if (constWriteResultBitmap) + savePNG("~/Dilated1Eroded1.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated1Eroded1.GetChecksum(), aTransformBitmap.GetChecksum()); + + aTransformBitmap = aOrigBitmap; + BitmapFilter::Filter(aTransformBitmap, BitmapDilateFilter(2)); + if (constWriteResultBitmap) + savePNG("~/Dilated2.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated2.GetChecksum(), aTransformBitmap.GetChecksum()); + BitmapFilter::Filter(aTransformBitmap, BitmapErodeFilter(1)); + if (constWriteResultBitmap) + savePNG("~/Dilated2Eroded1.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated2Eroded1.GetChecksum(), aTransformBitmap.GetChecksum()); +} + +void BitmapFilterTest::testPerformance() +{ + if (!constEnablePerformanceTest) + return; + + Size aSize(4000, 3000); // A rather common picture size + + // Prepare bitmap + Bitmap aBigBitmap(aSize, 24); + { + long aMargin = 500; + BitmapScopedWriteAccess aWriteAccess(aBigBitmap); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + aWriteAccess->SetFillColor(COL_BLACK); + tools::Rectangle aRectangle(aMargin, aMargin, aSize.Width() - 1 - aMargin, + aSize.Height() - 1 - aMargin); + + aWriteAccess->DrawRect(aRectangle); + } + + int nIterations = 10; + auto start = std::chrono::high_resolution_clock::now(); + Bitmap aResult; + for (int i = 0; i < nIterations; i++) + { + BitmapFilterStackBlur aBlurFilter(250); + aResult = aBlurFilter.filter(aBigBitmap); + } + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = (end - start) / nIterations; + + if (constWriteResultBitmap) + { + std::unique_ptr<SvFileStream> pStream( + new SvFileStream("~/BlurBigPerformance.png", StreamMode::WRITE | StreamMode::TRUNC)); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aResult, *pStream); + + pStream.reset(new SvFileStream("~/BlurBigPerformance.txt", StreamMode::WRITE)); + pStream->WriteOString("Blur average time: "); + pStream->WriteOString(OString::number( + std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count())); + pStream->WriteOString("\n"); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapFilterTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapProcessorTest.cxx b/vcl/qa/cppunit/BitmapProcessorTest.cxx new file mode 100644 index 000000000..2a628285d --- /dev/null +++ b/vcl/qa/cppunit/BitmapProcessorTest.cxx @@ -0,0 +1,90 @@ +/* -*- 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 <cppunit/plugin/TestPlugIn.h> + +#include <vcl/bitmap.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/alpha.hxx> + +#include <BitmapDisabledImageFilter.hxx> +#include <bitmapwriteaccess.hxx> + +namespace +{ + +class BitmapProcessorTest : public CppUnit::TestFixture +{ + void testDisabledImage(); + + CPPUNIT_TEST_SUITE(BitmapProcessorTest); + CPPUNIT_TEST(testDisabledImage); + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapProcessorTest::testDisabledImage() +{ + { + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x00, 0x00, 0xFF, 0x00)); + } + BitmapEx aBitmapEx(aBitmap); + BitmapDisabledImageFilter aDisabledImageFilter; + BitmapEx aDisabledBitmapEx(aDisabledImageFilter.execute(aBitmapEx)); + Bitmap aDisabledBitmap(aDisabledBitmapEx.GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aDisabledBitmap); + Color aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x00C5C5C5), aColor); + } + } + + { + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x00, 0x00, 0xFF, 0x00)); + } + AlphaMask aMask(Size(3, 3)); + { + AlphaScopedWriteAccess pWriteAccess(aMask); + pWriteAccess->Erase(Color(0x00, 0xAA, 0xAA, 0xAA)); + } + + BitmapEx aBitmapEx(aBitmap, aMask); + BitmapDisabledImageFilter aDisabledImageFilter; + BitmapEx aDisabledBitmapEx(aDisabledImageFilter.execute(aBitmapEx)); + + Bitmap aDisabledBitmap(aDisabledBitmapEx.GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aDisabledBitmap); + Color aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x00C5C5C5), aColor); + } + AlphaMask aDisabledAlphaMask(aDisabledBitmapEx.GetAlpha()); + { + AlphaMask::ScopedReadAccess pReadAccess(aDisabledAlphaMask); + Color aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x0000AA), aColor); + } + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapProcessorTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapScaleTest.cxx b/vcl/qa/cppunit/BitmapScaleTest.cxx new file mode 100644 index 000000000..b804cd1bf --- /dev/null +++ b/vcl/qa/cppunit/BitmapScaleTest.cxx @@ -0,0 +1,293 @@ +/* -*- 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 <vcl/bitmap.hxx> +#include <vcl/bitmapaccess.hxx> + +#include <tools/stream.hxx> +#include <vcl/graphicfilter.hxx> + +#include <BitmapSymmetryCheck.hxx> +#include <bitmapwriteaccess.hxx> + +namespace +{ +class BitmapScaleTest : public CppUnit::TestFixture +{ + void testScale(); + void testScale2(); + void testScaleSymmetry(); + + CPPUNIT_TEST_SUITE(BitmapScaleTest); + CPPUNIT_TEST(testScale); + CPPUNIT_TEST(testScale2); + CPPUNIT_TEST(testScaleSymmetry); + CPPUNIT_TEST_SUITE_END(); +}; + +bool checkBitmapColor(Bitmap const& rBitmap, Color const& rExpectedColor) +{ + bool bResult = true; + Bitmap aBitmap(rBitmap); + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + long nHeight = pReadAccess->Height(); + long nWidth = pReadAccess->Width(); + for (long y = 0; y < nHeight; ++y) + { + Scanline pScanlineRead = pReadAccess->GetScanline(y); + for (long x = 0; x < nWidth; ++x) + { + Color aColor = pReadAccess->GetPixelFromData(pScanlineRead, x); + if (aColor != rExpectedColor) + bResult = false; + } + } + + return bResult; +} + +void assertColorsAreSimilar(int maxDifference, const std::string& message, + const BitmapColor& expected, const BitmapColor& actual) +{ + // Check that the two colors match or are reasonably similar. + if (expected == actual) + return; + if (abs(expected.GetRed() - actual.GetRed()) <= maxDifference + && abs(expected.GetGreen() - actual.GetGreen()) <= maxDifference + && abs(expected.GetBlue() - actual.GetBlue()) <= maxDifference + && abs(expected.GetAlpha() - actual.GetAlpha()) <= maxDifference) + { + return; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual); +} + +void assertColorsAreSimilar(int maxDifference, int line, const BitmapColor& expected, + const BitmapColor& actual) +{ + std::stringstream stream; + stream << "Line: " << line; + assertColorsAreSimilar(maxDifference, stream.str(), expected, actual); +} + +void BitmapScaleTest::testScale() +{ + const bool bExportBitmap(false); + using tools::Rectangle; + + static const BmpScaleFlag scaleMethods[] + = { BmpScaleFlag::Default, BmpScaleFlag::Fast, BmpScaleFlag::BestQuality, + BmpScaleFlag::Interpolate, BmpScaleFlag::Lanczos, BmpScaleFlag::BiCubic, + BmpScaleFlag::BiLinear }; + for (BmpScaleFlag scaleMethod : scaleMethods) + { + struct ScaleSize + { + Size srcSize; + Size destSize; + }; + static const ScaleSize scaleSizes[] + = { // test no-op + { Size(16, 16), Size(16, 16) }, + // powers of 2 (OpenGL may use texture atlas) + { Size(16, 16), Size(14, 14) }, + { Size(14, 14), Size(16, 16) }, // both upscaling and downscaling + // "random" sizes + { Size(18, 18), Size(14, 14) }, + { Size(14, 14), Size(18, 18) }, + // different x/y ratios + { Size(16, 30), Size(14, 18) }, + { Size(14, 18), Size(16, 30) }, + // ratio larger than 16 (triggers different paths in some OpenGL algorithms) + { Size(18 * 20, 18 * 20), Size(14, 14) }, + { Size(14, 14), Size(18 * 20, 18 * 20) } + }; + for (const ScaleSize& scaleSize : scaleSizes) + { + OString testStr = "Testing scale (" + scaleSize.srcSize.toString() + ")->(" + + scaleSize.destSize.toString() + "), method " + + OString::number(static_cast<int>(scaleMethod)); + fprintf(stderr, "%s\n", testStr.getStr()); + Bitmap bitmap(scaleSize.srcSize, 24); + { + // Fill each quarter of the source bitmap with a different color, + // and center with yet another color. + BitmapScopedWriteAccess writeAccess(bitmap); + const int halfW = scaleSize.srcSize.getWidth() / 2; + const int halfH = scaleSize.srcSize.getHeight() / 2; + writeAccess->SetFillColor(COL_GREEN); + writeAccess->FillRect(Rectangle(Point(0, 0), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_RED); + writeAccess->FillRect(Rectangle(Point(0, halfH), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_YELLOW); + writeAccess->FillRect(Rectangle(Point(halfW, 0), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_BLACK); + writeAccess->FillRect(Rectangle(Point(halfW, halfH), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_BLUE); + writeAccess->FillRect(Rectangle(Point(halfW / 2, halfH / 2), Size(halfW, halfH))); + } + if (bExportBitmap) + { + SvFileStream aStream("~/scale_before.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(bitmap, aStream); + } + CPPUNIT_ASSERT(bitmap.Scale(scaleSize.destSize, scaleMethod)); + if (bExportBitmap) + { + SvFileStream aStream("~/scale_after.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(bitmap, aStream); + } + CPPUNIT_ASSERT_EQUAL(scaleSize.destSize, bitmap.GetSizePixel()); + { + // Scaling should keep each quarter of the resulting bitmap have the same color, + // so check that color in each corner of the result bitmap is the same color, + // or reasonably close (some algorithms may alter the color very slightly). + BitmapReadAccess readAccess(bitmap); + const int lastW = scaleSize.destSize.getWidth() - 1; + const int lastH = scaleSize.destSize.getHeight() - 1; + assertColorsAreSimilar(2, __LINE__, COL_GREEN, readAccess.GetColor(0, 0)); + assertColorsAreSimilar(2, __LINE__, COL_RED, readAccess.GetColor(lastH, 0)); + assertColorsAreSimilar(2, __LINE__, COL_YELLOW, readAccess.GetColor(0, lastW)); + assertColorsAreSimilar(2, __LINE__, COL_BLACK, readAccess.GetColor(lastH, lastW)); + assertColorsAreSimilar(2, __LINE__, COL_BLUE, + readAccess.GetColor(lastH / 2, lastW / 2)); + } + } + } +} + +void BitmapScaleTest::testScale2() +{ + const bool bExportBitmap(false); + + Bitmap aBitmap24Bit(Size(4096, 4096), 24); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), aBitmap24Bit.GetBitCount()); + Color aBitmapColor = COL_YELLOW; + { + BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit); + aWriteAccess->Erase(aBitmapColor); + } + + if (bExportBitmap) + { + SvFileStream aStream("scale_before.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aBitmap24Bit, aStream); + } + + // Scale - 65x65 + CPPUNIT_ASSERT_EQUAL(static_cast<long>(4096), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(4096), aBitmap24Bit.GetSizePixel().Height()); + Bitmap aScaledBitmap = aBitmap24Bit; + aScaledBitmap.Scale(Size(65, 65)); + + if (bExportBitmap) + { + SvFileStream aStream("scale_after_65x65.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aScaledBitmap, aStream); + } + + CPPUNIT_ASSERT_EQUAL(static_cast<long>(65), aScaledBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(65), aScaledBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor)); + + // Scale - 64x64 + CPPUNIT_ASSERT_EQUAL(static_cast<long>(4096), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(4096), aBitmap24Bit.GetSizePixel().Height()); + aScaledBitmap = aBitmap24Bit; + aScaledBitmap.Scale(Size(64, 64)); + + if (bExportBitmap) + { + SvFileStream aStream("scale_after_64x64.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aScaledBitmap, aStream); + } + + CPPUNIT_ASSERT_EQUAL(static_cast<long>(64), aScaledBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(64), aScaledBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor)); + + // Scale - 63x63 + CPPUNIT_ASSERT_EQUAL(static_cast<long>(4096), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(4096), aBitmap24Bit.GetSizePixel().Height()); + aScaledBitmap = aBitmap24Bit; + aScaledBitmap.Scale(Size(63, 63)); + + if (bExportBitmap) + { + SvFileStream aStream("scale_after_63x63.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aScaledBitmap, aStream); + } + + CPPUNIT_ASSERT_EQUAL(static_cast<long>(63), aScaledBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(63), aScaledBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor)); +} + +void BitmapScaleTest::testScaleSymmetry() +{ + const bool bExportBitmap(false); + + Bitmap aBitmap24Bit(Size(10, 10), 24); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), aBitmap24Bit.GetBitCount()); + + { + BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + aWriteAccess->DrawRect(tools::Rectangle(1, 1, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 6, 6)); + } + + BitmapSymmetryCheck aBitmapSymmetryCheck; + + CPPUNIT_ASSERT_EQUAL(static_cast<long>(10), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(10), aBitmap24Bit.GetSizePixel().Height()); + + // Check symmetry of the bitmap + CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit)); + + if (bExportBitmap) + { + SvFileStream aStream("~/scale_before.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aBitmap24Bit, aStream); + } + + aBitmap24Bit.Scale(2, 2, BmpScaleFlag::Fast); + + CPPUNIT_ASSERT_EQUAL(static_cast<long>(20), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast<long>(20), aBitmap24Bit.GetSizePixel().Height()); + + // After scaling the bitmap should still be symmetrical. This check guarantees that + // scaling doesn't misalign the bitmap. + CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit)); + + if (bExportBitmap) + { + SvFileStream aStream("~/scale_after.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aBitmap24Bit, aStream); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapScaleTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx new file mode 100644 index 000000000..640c477e3 --- /dev/null +++ b/vcl/qa/cppunit/BitmapTest.cxx @@ -0,0 +1,660 @@ +/* -*- 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 <cppunit/plugin/TestPlugIn.h> + +#include <unordered_map> + +#include <vcl/bitmap.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/virdev.hxx> + +#include <rtl/strbuf.hxx> +#include <config_features.h> +#if HAVE_FEATURE_OPENGL +#include <vcl/opengl/OpenGLHelper.hxx> +#endif +#include <vcl/skia/SkiaHelper.hxx> +#include <vcl/BitmapMonochromeFilter.hxx> + +#include <bitmapwriteaccess.hxx> + +#include <svdata.hxx> +#include <salinst.hxx> +#include <bitmap/Octree.hxx> + +namespace +{ +class BitmapTest : public CppUnit::TestFixture +{ + void testCreation(); + void testEmpty(); + void testMonochrome(); + void testN4Greyscale(); + void testN8Greyscale(); + void testConvert(); + void testCRC(); + void testGreyPalette(); + void testCustom8BitPalette(); + void testErase(); + void testBitmap32(); + void testOctree(); + + CPPUNIT_TEST_SUITE(BitmapTest); + CPPUNIT_TEST(testCreation); + CPPUNIT_TEST(testEmpty); + CPPUNIT_TEST(testMonochrome); + CPPUNIT_TEST(testConvert); + CPPUNIT_TEST(testN4Greyscale); + CPPUNIT_TEST(testN8Greyscale); + CPPUNIT_TEST(testCRC); + CPPUNIT_TEST(testGreyPalette); + CPPUNIT_TEST(testCustom8BitPalette); + CPPUNIT_TEST(testErase); + CPPUNIT_TEST(testBitmap32); + CPPUNIT_TEST(testOctree); + CPPUNIT_TEST_SUITE_END(); +}; + +void assertColorsAreSimilar(int maxDifference, const std::string& message, + const BitmapColor& expected, const BitmapColor& actual) +{ + // Check that the two colors match or are reasonably similar. + if (expected == actual) + return; + if (abs(expected.GetRed() - actual.GetRed()) <= maxDifference + && abs(expected.GetGreen() - actual.GetGreen()) <= maxDifference + && abs(expected.GetBlue() - actual.GetBlue()) <= maxDifference + && abs(expected.GetAlpha() - actual.GetAlpha()) <= maxDifference) + { + return; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual); +} + +void BitmapTest::testCreation() +{ + { + Bitmap aBmp; + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<long>(0), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(0), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Not empty", aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast<sal_uInt16>(0), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(1), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_uLong>(0), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 1); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<long>(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast<sal_uInt16>(1), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(2), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_uLong>(12), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 4); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<long>(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast<sal_uInt16>(4), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(16), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_uLong>(50), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 8); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<long>(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast<sal_uInt16>(8), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(256), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_uLong>(100), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 24); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<long>(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast<sal_uInt16>(24), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(16777216), + aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast<sal_uLong>(300), + aBmp.GetSizeBytes()); + } + + // Check backend capabilities and return from the test successfully + // if the backend doesn't support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (pBackendCapabilities->mbSupportsBitmap32) + { + Bitmap aBmp(Size(10, 10), 32); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast<long>(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast<long>(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", sal_uInt16(32), aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(4294967296ull), + aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", sal_uLong(400), aBmp.GetSizeBytes()); + } +} + +void BitmapTest::testEmpty() +{ + Bitmap aBitmap(Size(10, 10), 8); + aBitmap.Erase(COL_LIGHTGRAYBLUE); + + CPPUNIT_ASSERT(!aBitmap.IsEmpty()); + + aBitmap.SetEmpty(); + CPPUNIT_ASSERT(aBitmap.IsEmpty()); +} + +Bitmap createTestBitmap() +{ + Bitmap aBmp(Size(4, 4), 24); + BitmapWriteAccess aBmpAccess(aBmp); + + // row 1 + aBmpAccess.SetPixel(0, 0, BitmapColor(COL_BLACK)); + aBmpAccess.SetPixel(0, 1, BitmapColor(COL_BLUE)); + aBmpAccess.SetPixel(0, 2, BitmapColor(COL_GREEN)); + aBmpAccess.SetPixel(0, 3, BitmapColor(COL_CYAN)); + + // row 2 + aBmpAccess.SetPixel(1, 0, BitmapColor(COL_RED)); + aBmpAccess.SetPixel(1, 1, BitmapColor(COL_MAGENTA)); + aBmpAccess.SetPixel(1, 2, BitmapColor(COL_BROWN)); + aBmpAccess.SetPixel(1, 3, BitmapColor(COL_GRAY)); + + // row 3 + aBmpAccess.SetPixel(2, 0, BitmapColor(COL_LIGHTGRAY)); + aBmpAccess.SetPixel(2, 1, BitmapColor(COL_LIGHTBLUE)); + aBmpAccess.SetPixel(2, 2, BitmapColor(COL_LIGHTGREEN)); + aBmpAccess.SetPixel(2, 3, BitmapColor(COL_LIGHTCYAN)); + + // row 4 + aBmpAccess.SetPixel(3, 0, BitmapColor(COL_LIGHTRED)); + aBmpAccess.SetPixel(3, 1, BitmapColor(COL_LIGHTMAGENTA)); + aBmpAccess.SetPixel(3, 2, BitmapColor(COL_YELLOW)); + aBmpAccess.SetPixel(3, 3, BitmapColor(COL_WHITE)); + + return aBmp; +} + +void BitmapTest::testMonochrome() +{ + Bitmap aBmp = createTestBitmap(); + + BitmapEx aBmpEx(aBmp); + BitmapFilter::Filter(aBmpEx, BitmapMonochromeFilter(63)); + aBmp = aBmpEx.GetBitmap(); + BitmapReadAccess aBmpReadAccess(aBmp); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(0, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(0, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(0, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(1, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(1, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(1, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(1, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(2, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(2, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(2, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(2, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(3, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong monochrome value", + BitmapColor(COL_WHITE), aBmpReadAccess.GetColor(3, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(3, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(3, 3)); +} + +void BitmapTest::testN4Greyscale() +{ + Bitmap aBmp = createTestBitmap(); + BitmapPalette aGreyscalePalette = Bitmap::GetGreyPalette(16); + + aBmp.Convert(BmpConversion::N4BitGreys); + BitmapReadAccess aBmpReadAccess(aBmp); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong 8-bit greyscale value", aGreyscalePalette[0], + aBmpReadAccess.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong 8-bit greyscale value", aGreyscalePalette[0], + aBmpReadAccess.GetColor(0, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong 8-bit greyscale value", aGreyscalePalette[4], + aBmpReadAccess.GetColor(0, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette[5], + aBmpReadAccess.GetColor(0, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong 8-bit greyscale value", aGreyscalePalette[2], + aBmpReadAccess.GetColor(1, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette[3], + aBmpReadAccess.GetColor(1, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong 8-bit greyscale value", aGreyscalePalette[7], + aBmpReadAccess.GetColor(1, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong 8-bit greyscale value", aGreyscalePalette[8], + aBmpReadAccess.GetColor(1, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong 8-bit greyscale value", + aGreyscalePalette[12], aBmpReadAccess.GetColor(2, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong 8-bit greyscale value", + aGreyscalePalette[1], aBmpReadAccess.GetColor(2, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong 8-bit greyscale value", + aGreyscalePalette[9], aBmpReadAccess.GetColor(2, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong 8-bit greyscale value", + aGreyscalePalette[11], aBmpReadAccess.GetColor(2, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong 8-bit greyscale value", + aGreyscalePalette[4], aBmpReadAccess.GetColor(3, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong 8-bit greyscale value", + aGreyscalePalette[6], aBmpReadAccess.GetColor(3, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette[14], + aBmpReadAccess.GetColor(3, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong 8-bit greyscale value", aGreyscalePalette[15], + aBmpReadAccess.GetColor(3, 3)); +} + +void BitmapTest::testN8Greyscale() +{ + Bitmap aBmp = createTestBitmap(); + BitmapPalette aGreyscalePalette = Bitmap::GetGreyPalette(256); + + aBmp.Convert(BmpConversion::N8BitGreys); + BitmapReadAccess aBmpReadAccess(aBmp); + + assertColorsAreSimilar(1, "Black pixel wrong 8-bit greyscale value", aGreyscalePalette[0], + aBmpReadAccess.GetColor(0, 0)); + assertColorsAreSimilar(1, "Blue pixel wrong 8-bit greyscale value", aGreyscalePalette[14], + aBmpReadAccess.GetColor(0, 1)); + assertColorsAreSimilar(1, "Green pixel wrong 8-bit greyscale value", aGreyscalePalette[75], + aBmpReadAccess.GetColor(0, 2)); + assertColorsAreSimilar(1, "Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette[89], + aBmpReadAccess.GetColor(0, 3)); + assertColorsAreSimilar(1, "Red pixel wrong 8-bit greyscale value", aGreyscalePalette[38], + aBmpReadAccess.GetColor(1, 0)); + assertColorsAreSimilar(1, "Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette[52], + aBmpReadAccess.GetColor(1, 1)); + assertColorsAreSimilar(1, "Brown pixel wrong 8-bit greyscale value", aGreyscalePalette[114], + aBmpReadAccess.GetColor(1, 2)); + assertColorsAreSimilar(1, "Gray pixel wrong 8-bit greyscale value", aGreyscalePalette[128], + aBmpReadAccess.GetColor(1, 3)); + assertColorsAreSimilar(1, "Light gray pixel wrong 8-bit greyscale value", + aGreyscalePalette[192], aBmpReadAccess.GetColor(2, 0)); + assertColorsAreSimilar(1, "Light blue pixel wrong 8-bit greyscale value", aGreyscalePalette[27], + aBmpReadAccess.GetColor(2, 1)); + assertColorsAreSimilar(1, "Light green pixel wrong 8-bit greyscale value", + aGreyscalePalette[150], aBmpReadAccess.GetColor(2, 2)); + assertColorsAreSimilar(1, "Light cyan pixel wrong 8-bit greyscale value", + aGreyscalePalette[178], aBmpReadAccess.GetColor(2, 3)); + assertColorsAreSimilar(1, "Light red pixel wrong 8-bit greyscale value", aGreyscalePalette[76], + aBmpReadAccess.GetColor(3, 0)); + assertColorsAreSimilar(1, "Light magenta pixel wrong 8-bit greyscale value", + aGreyscalePalette[104], aBmpReadAccess.GetColor(3, 1)); + assertColorsAreSimilar(1, "Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette[227], + aBmpReadAccess.GetColor(3, 2)); + assertColorsAreSimilar(1, "White pixel wrong 8-bit greyscale value", aGreyscalePalette[255], + aBmpReadAccess.GetColor(3, 3)); +} + +void BitmapTest::testConvert() +{ + Bitmap aBitmap(Size(10, 10), 8); + + aBitmap.Erase(COL_LIGHTGRAYBLUE); + + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), aBitmap.GetBitCount()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), pReadAccess->GetBitCount()); +#if defined MACOSX || defined IOS + //it would be nice to find and change the stride for quartz to be the same as everyone else + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(10), pReadAccess->GetScanlineSize()); +#else + if (!SkiaHelper::isVCLSkiaEnabled()) +#if HAVE_FEATURE_OPENGL + if (!OpenGLHelper::isVCLOpenGLEnabled()) +#endif + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(12), pReadAccess->GetScanlineSize()); +#endif + CPPUNIT_ASSERT(pReadAccess->HasPalette()); + const BitmapColor& rColor = pReadAccess->GetPaletteColor(pReadAccess->GetPixelIndex(1, 1)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor.GetRed())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor.GetGreen())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(rColor.GetBlue())); + } + + aBitmap.Convert(BmpConversion::N24Bit); + + CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmap.GetBitCount()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + // 24 bit Bitmap on SVP backend can now use 24bit RGB everywhere. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), pReadAccess->GetBitCount()); + + if (SkiaHelper::isVCLSkiaEnabled()) // aligned to 4 bytes + CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize()); + else +#if HAVE_FEATURE_OPENGL + if (OpenGLHelper::isVCLOpenGLEnabled()) + CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess->GetScanlineSize()); + else +#endif +#if defined LINUX || defined FREEBSD + { + CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize()); + } +#elif defined(_WIN32) + { + // GDI Scanlines padded to DWORD multiples, it seems + CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize()); + } +#else + { + CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess->GetScanlineSize()); + } +#endif + + CPPUNIT_ASSERT(!pReadAccess->HasPalette()); + Color aColor = pReadAccess->GetPixel(0, 0); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetRed())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetGreen())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(aColor.GetBlue())); + } +} + +typedef std::unordered_map<sal_uInt64, const char*> CRCHash; + +void checkAndInsert(CRCHash& rHash, sal_uInt64 nCRC, const char* pLocation) +{ + auto it = rHash.find(nCRC); + if (it != rHash.end()) + { + OStringBuffer aBuf("CRC collision between "); + aBuf.append(pLocation); + aBuf.append(" and "); + aBuf.append(it->second); + aBuf.append(" hash is 0x"); + aBuf.append(static_cast<sal_Int64>(nCRC), 16); + CPPUNIT_FAIL(aBuf.toString().getStr()); + } + rHash[nCRC] = pLocation; +} + +void checkAndInsert(CRCHash& rHash, Bitmap const& rBmp, const char* pLocation) +{ + checkAndInsert(rHash, rBmp.GetChecksum(), pLocation); +} + +Bitmap getAsBitmap(VclPtr<OutputDevice> const& pOut) +{ + return pOut->GetBitmap(Point(), pOut->GetOutputSizePixel()); +} + +void BitmapTest::testCRC() +{ + CRCHash aCRCs; + + Bitmap aBitmap(Size(1023, 759), 24, nullptr); + aBitmap.Erase(COL_BLACK); + checkAndInsert(aCRCs, aBitmap, "black bitmap"); + aBitmap.Invert(); + checkAndInsert(aCRCs, aBitmap, "white bitmap"); + + ScopedVclPtrInstance<VirtualDevice> aVDev; + aVDev->SetBackground(Wallpaper(COL_WHITE)); + aVDev->SetOutputSizePixel(Size(1023, 759)); + +#if 0 // disabled for now - oddly breaks on OS/X - but why ? + Bitmap aWhiteCheck = getAsBitmap(aVDev); + CPPUNIT_ASSERT(aCRCs.find(aWhiteCheck.GetChecksum()) != aCRCs.end()); +#endif + + // a 1x1 black & white checkerboard + aVDev->DrawCheckered(Point(), aVDev->GetOutputSizePixel(), 1, Color(0, 0, 1)); + Bitmap aChecker = getAsBitmap(aVDev); + checkAndInsert(aCRCs, aChecker, "checkerboard"); + aChecker.Invert(); + checkAndInsert(aCRCs, aChecker, "inverted checkerboard"); +} + +void BitmapTest::testGreyPalette() +{ + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16>(2), + aPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(255, 255, 255), aPalette[1]); + } + + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16>(4), + aPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(85, 85, 85), aPalette[1]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(170, 170, 170), aPalette[2]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(255, 255, 255), aPalette[3]); + } + + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(16); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast<sal_uInt16>(16), + aPalette.GetEntryCount()); + // this is a *real* specific number of greys, incremented in units of 17 so may + // as well test them all... + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(17, 17, 17), aPalette[1]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(34, 34, 34), aPalette[2]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(51, 51, 51), aPalette[3]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 5 wrong", BitmapColor(68, 68, 68), aPalette[4]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 6 wrong", BitmapColor(85, 85, 85), aPalette[5]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 7 wrong", BitmapColor(102, 102, 102), aPalette[6]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 8 wrong", BitmapColor(119, 119, 119), aPalette[7]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 9 wrong", BitmapColor(136, 136, 136), aPalette[8]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 10 wrong", BitmapColor(153, 153, 153), aPalette[9]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 11 wrong", BitmapColor(170, 170, 170), aPalette[10]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 12 wrong", BitmapColor(187, 187, 187), aPalette[11]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 13 wrong", BitmapColor(204, 204, 204), aPalette[12]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 14 wrong", BitmapColor(221, 221, 221), aPalette[13]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 15 wrong", BitmapColor(238, 238, 238), aPalette[14]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 16 wrong", BitmapColor(255, 255, 255), aPalette[15]); + } + + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(256); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", + static_cast<sal_uInt16>(256), aPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 127 wrong", BitmapColor(127, 127, 127), aPalette[127]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 255 wrong", BitmapColor(255, 255, 255), aPalette[255]); + } +} + +void BitmapTest::testCustom8BitPalette() +{ + BitmapPalette aCustomPalette; + aCustomPalette.SetEntryCount(256); + for (sal_uInt16 i = 0; i < 256; i++) + { + aCustomPalette[i] = BitmapColor(sal_uInt8(i), sal_uInt8(0xCC), sal_uInt8(0x22)); + } + Bitmap aBitmap(Size(3, 2), 8, &aCustomPalette); + + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->SetPixelIndex(0, 0, 0); + pAccess->SetPixelIndex(0, 1, 1); + pAccess->SetPixelIndex(0, 2, 2); + + pAccess->SetPixelIndex(1, 0, 253); + pAccess->SetPixelIndex(1, 1, 254); + pAccess->SetPixelIndex(1, 2, 255); + } + + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(0, int(pAccess->GetPixelIndex(0, 0))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xCC, 0x22), pAccess->GetColor(0, 0)); + + CPPUNIT_ASSERT_EQUAL(1, int(pAccess->GetPixelIndex(0, 1))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x01, 0xCC, 0x22), pAccess->GetColor(0, 1)); + + CPPUNIT_ASSERT_EQUAL(2, int(pAccess->GetPixelIndex(0, 2))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x02, 0xCC, 0x22), pAccess->GetColor(0, 2)); + + CPPUNIT_ASSERT_EQUAL(253, int(pAccess->GetPixelIndex(1, 0))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFD, 0xCC, 0x22), pAccess->GetColor(1, 0)); + + CPPUNIT_ASSERT_EQUAL(254, int(pAccess->GetPixelIndex(1, 1))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFE, 0xCC, 0x22), pAccess->GetColor(1, 1)); + + CPPUNIT_ASSERT_EQUAL(255, int(pAccess->GetPixelIndex(1, 2))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xCC, 0x22), pAccess->GetColor(1, 2)); + } +} + +void BitmapTest::testErase() +{ + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x11, 0x22, 0x33)); + } + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + BitmapColor aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x11, 0x22, 0x33, 0x00), aColor); + } +} + +void BitmapTest::testBitmap32() +{ + // Check backend capabilities and return from the test successfully + // if the backend doesn't support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (!pBackendCapabilities->mbSupportsBitmap32) + return; + + Bitmap aBitmap(Size(3, 3), 32); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0xFF, 0x11, 0x22, 0x33)); + pWriteAccess->SetPixel(1, 1, BitmapColor(0x44, 0xFF, 0xBB, 0x00)); + pWriteAccess->SetPixel(2, 2, BitmapColor(0x99, 0x77, 0x66, 0x55)); + } + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + BitmapColor aColor = pReadAccess->GetPixel(0, 0); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0xFF), aColor); + + aColor = pReadAccess->GetPixel(1, 1); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x44, 0xFF, 0xBB, 0x00), aColor); + + aColor = pReadAccess->GetPixel(2, 2); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x99, 0x77, 0x66, 0x55), aColor); + } +} + +void BitmapTest::testOctree() +{ + Size aSize(1000, 100); + Bitmap aBitmap(aSize, 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + for (long y = 0; y < aSize.Height(); ++y) + { + for (long x = 0; x < aSize.Width(); ++x) + { + double fPercent = double(x) / double(aSize.Width()); + pWriteAccess->SetPixel(y, x, + BitmapColor(255.0 * fPercent, 64.0 + (128.0 * fPercent), + 255.0 - 255.0 * fPercent)); + } + } + } + + { + // Reduce to 1 color + Bitmap::ScopedReadAccess pAccess(aBitmap); + Octree aOctree(*pAccess, 1); + auto aBitmapPalette = aOctree.GetPalette(); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), aBitmapPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7e, 0x7f, 0x7f), aBitmapPalette[0]); + } + + { + // Reduce to 4 color + Bitmap::ScopedReadAccess pAccess(aBitmap); + Octree aOctree(*pAccess, 4); + auto aBitmapPalette = aOctree.GetPalette(); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), aBitmapPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x7f, 0x7f), aBitmapPalette[0]); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x3e, 0x5f, 0xbf), aBitmapPalette[1]); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x80, 0x7f), aBitmapPalette[2]); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xbe, 0x9f, 0x3f), aBitmapPalette[3]); + } + + { + // Reduce to 256 color + Bitmap::ScopedReadAccess pAccess(aBitmap); + Octree aOctree(*pAccess, 256); + auto aBitmapPalette = aOctree.GetPalette(); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(74), aBitmapPalette.GetEntryCount()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/FontFeatureTest.cxx b/vcl/qa/cppunit/FontFeatureTest.cxx new file mode 100644 index 000000000..e4040f35b --- /dev/null +++ b/vcl/qa/cppunit/FontFeatureTest.cxx @@ -0,0 +1,336 @@ +/* -*- 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 <config_features.h> +#include <cppunit/TestAssert.h> + +#include <vcl/font/Feature.hxx> +#include <vcl/font/FeatureParser.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> + +class FontFeatureTest : public test::BootstrapFixture +{ +public: + FontFeatureTest() + : BootstrapFixture(true, false) + { + } + + void testGetFontFeatures(); + void testParseFeature(); + + CPPUNIT_TEST_SUITE(FontFeatureTest); + CPPUNIT_TEST(testGetFontFeatures); + CPPUNIT_TEST(testParseFeature); + CPPUNIT_TEST_SUITE_END(); +}; + +void FontFeatureTest::testGetFontFeatures() +{ +#if HAVE_MORE_FONTS + ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(), + DeviceFormat::DEFAULT, DeviceFormat::DEFAULT); + aVDev->SetOutputSizePixel(Size(10, 10)); + + OUString aFontName("Linux Libertine G"); + CPPUNIT_ASSERT(aVDev->IsFontAvailable(aFontName)); + + vcl::Font aFont = aVDev->GetFont(); + aFont.SetFamilyName(aFontName); + aFont.SetWeight(FontWeight::WEIGHT_NORMAL); + aFont.SetItalic(FontItalic::ITALIC_NORMAL); + aFont.SetWidthType(FontWidth::WIDTH_NORMAL); + aVDev->SetFont(aFont); + + std::vector<vcl::font::Feature> rFontFeatures; + CPPUNIT_ASSERT(aVDev->GetFontFeatures(rFontFeatures)); + + // We're interested only in defaults here + std::vector<vcl::font::Feature> rDefaultFontFeatures; + OUString aFeaturesString; + for (vcl::font::Feature const& rFeature : rFontFeatures) + { + if (rFeature.m_aID.m_aScriptCode == vcl::font::featureCode("DFLT") + && rFeature.m_aID.m_aLanguageCode == vcl::font::featureCode("dflt")) + { + rDefaultFontFeatures.push_back(rFeature); + aFeaturesString += vcl::font::featureCodeAsString(rFeature.m_aID.m_aFeatureCode) + " "; + } + } + + CPPUNIT_ASSERT_EQUAL(size_t(53), rDefaultFontFeatures.size()); + + OUString aExpectedFeaturesString = "c2sc case dlig fina frac hlig liga lnum " + "locl onum pnum sa01 sa02 sa03 sa04 sa05 " + "sa06 sa07 sa08 salt sinf smcp ss01 ss02 " + "ss03 sups tnum zero ingl cpsp lith litt " + "itlc para algn arti circ dash dbls foot " + "frsp grkn hang lng minu nfsp name quot " + "texm thou vari caps ligc "; + + CPPUNIT_ASSERT_EQUAL(aExpectedFeaturesString, aFeaturesString); + + // Check C2SC feature + { + vcl::font::Feature& rFeature = rDefaultFontFeatures[0]; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("c2sc"), rFeature.m_aID.m_aFeatureCode); + + vcl::font::FeatureDefinition& rFracFeatureDefinition = rFeature.m_aDefinition; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("c2sc"), rFracFeatureDefinition.getCode()); + CPPUNIT_ASSERT(!rFracFeatureDefinition.getDescription().isEmpty()); + CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::BOOL, + rFracFeatureDefinition.getType()); + + CPPUNIT_ASSERT_EQUAL(size_t(0), rFracFeatureDefinition.getEnumParameters().size()); + } + + // Check FRAC feature + { + vcl::font::Feature& rFeature = rDefaultFontFeatures[4]; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("frac"), rFeature.m_aID.m_aFeatureCode); + + vcl::font::FeatureDefinition& rFracFeatureDefinition = rFeature.m_aDefinition; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("frac"), rFracFeatureDefinition.getCode()); + CPPUNIT_ASSERT(!rFracFeatureDefinition.getDescription().isEmpty()); + CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::ENUM, + rFracFeatureDefinition.getType()); + + CPPUNIT_ASSERT_EQUAL(size_t(3), rFracFeatureDefinition.getEnumParameters().size()); + + vcl::font::FeatureParameter const& rParameter1 + = rFracFeatureDefinition.getEnumParameters()[0]; + CPPUNIT_ASSERT_EQUAL(uint32_t(0), rParameter1.getCode()); + CPPUNIT_ASSERT(!rParameter1.getDescription().isEmpty()); + + vcl::font::FeatureParameter const& rParameter2 + = rFracFeatureDefinition.getEnumParameters()[1]; + CPPUNIT_ASSERT_EQUAL(uint32_t(1), rParameter2.getCode()); + CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty()); + + vcl::font::FeatureParameter const& rParameter3 + = rFracFeatureDefinition.getEnumParameters()[2]; + CPPUNIT_ASSERT_EQUAL(uint32_t(2), rParameter3.getCode()); + CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty()); + } + + aVDev.disposeAndClear(); +#endif // HAVE_MORE_FONTS +} + +void FontFeatureTest::testParseFeature() +{ + { // No font features specified + vcl::font::FeatureParser aParser("Font name with no features"); + CPPUNIT_ASSERT_EQUAL(size_t(0), aParser.getFeatures().size()); + } + { // One feature specified, no value + vcl::font::FeatureParser aParser("Font name:abcd"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + } + { // One feature specified, explicit value + vcl::font::FeatureParser aParser("Font name:abcd=5"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(5), aFeatures[0].m_nValue); + } + { // One feature specified, explicit zero value + vcl::font::FeatureParser aParser("Font name:abcd=0"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + } + { // One feature specified, using plus prefix + vcl::font::FeatureParser aParser("Font name:+abcd"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + } + { // One feature specified, using minus prefix + vcl::font::FeatureParser aParser("Font name:-abcd"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + } + { // One feature specified, with empty character range + vcl::font::FeatureParser aParser("Font name:abcd[]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), aFeatures[0].m_nEnd); + } + { // One feature specified, with empty character range + vcl::font::FeatureParser aParser("Font name:abcd[:]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), aFeatures[0].m_nEnd); + } + { // One feature specified, with start character range + vcl::font::FeatureParser aParser("Font name:abcd[3:]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(-1), aFeatures[0].m_nEnd); + } + { // One feature specified, with end character range + vcl::font::FeatureParser aParser("Font name:abcd[:3]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(0), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range + vcl::font::FeatureParser aParser("Font name:abcd[3:6]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range + vcl::font::FeatureParser aParser("Font name:abcd[3]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range and value + vcl::font::FeatureParser aParser("Font name:abcd[3:6]=2"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(2), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range and 0 value + vcl::font::FeatureParser aParser("Font name:abcd[3:6]=0"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range and minus prefix + vcl::font::FeatureParser aParser("Font name:-abcd[3:6]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with CSS on + vcl::font::FeatureParser aParser("Font name:\"abcd\" on"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + } + { // One feature specified, with CSS off + vcl::font::FeatureParser aParser("Font name:'abcd' off"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + } + { // One feature specified, with CSS value + vcl::font::FeatureParser aParser("Font name:\"abcd\" 2"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(2), aFeatures[0].m_nValue); + } + { // Multiple features specified, no values + vcl::font::FeatureParser aParser("Font name:abcd&bcde&efgh"); + CPPUNIT_ASSERT_EQUAL(size_t(3), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[1].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("efgh"), aFeatures[2].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[2].m_nValue); + } + { + // Multiple features specified, explicit values + // Only 4 char parameter names supported - "toolong" is too long and ignored + vcl::font::FeatureParser aParser("Font name:abcd=1&bcde=0&toolong=1&cdef=3"); + CPPUNIT_ASSERT_EQUAL(size_t(3), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[1].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("cdef"), aFeatures[2].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(3), aFeatures[2].m_nValue); + } + { + // Special case - "lang" is parsed specially and access separately not as a feature. + + vcl::font::FeatureParser aParser("Font name:abcd=1&lang=slo"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + + CPPUNIT_ASSERT_EQUAL(OUString("slo"), aParser.getLanguage()); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(FontFeatureTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicDescriptorTest.cxx b/vcl/qa/cppunit/GraphicDescriptorTest.cxx new file mode 100644 index 000000000..4ee5e96ed --- /dev/null +++ b/vcl/qa/cppunit/GraphicDescriptorTest.cxx @@ -0,0 +1,103 @@ +/* -*- 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 <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <vcl/graphicfilter.hxx> +#include <tools/stream.hxx> + +using namespace css; + +namespace +{ +class GraphicDescriptorTest : public CppUnit::TestFixture +{ + void testDetectPNG(); + void testDetectJPG(); + void testDetectGIF(); + + CPPUNIT_TEST_SUITE(GraphicDescriptorTest); + CPPUNIT_TEST(testDetectPNG); + CPPUNIT_TEST(testDetectJPG); + CPPUNIT_TEST(testDetectGIF); + CPPUNIT_TEST_SUITE_END(); +}; + +BitmapEx createBitmap() +{ + Bitmap aBitmap(Size(100, 100), 24); + aBitmap.Erase(COL_LIGHTRED); + + return BitmapEx(aBitmap); +} + +void createBitmapAndExportForType(SvStream& rStream, OUString const& sType) +{ + BitmapEx aBitmapEx = createBitmap(); + + uno::Sequence<beans::PropertyValue> aFilterData; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName(sType); + rGraphicFilter.ExportGraphic(aBitmapEx, "none", rStream, nFilterFormat, &aFilterData); + + rStream.Seek(STREAM_SEEK_TO_BEGIN); +} + +void GraphicDescriptorTest::testDetectPNG() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, "png"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::PNG, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Height()); +} + +void GraphicDescriptorTest::testDetectJPG() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, "jpg"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::JPG, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Height()); +} + +void GraphicDescriptorTest::testDetectGIF() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, "gif"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::GIF, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Height()); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicDescriptorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx new file mode 100644 index 000000000..1ce516bf5 --- /dev/null +++ b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx @@ -0,0 +1,416 @@ +/* -*- 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/extensions/HelperMacros.h> +#include <unotest/bootstrapfixturebase.hxx> + +#include <graphic/GraphicFormatDetector.hxx> +#include <graphic/DetectorTools.hxx> + +#include <tools/stream.hxx> + +using namespace css; + +namespace +{ +class GraphicFormatDetectorTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc("/vcl/qa/cppunit/data/") + sFileName; + } + + void testDetectMET(); + void testDetectBMP(); + void testDetectWMF(); + void testDetectPCX(); + void testDetectJPG(); + void testDetectPNG(); + void testDetectGIF(); + void testDetectPSD(); + void testDetectTGA(); + void testDetectTIF(); + void testDetectXBM(); + void testDetectXPM(); + void testDetectSVG(); + void testDetectSVGZ(); + void testDetectPDF(); + void testDetectEPS(); + void testMatchArray(); + void testCheckArrayForMatchingStrings(); + + CPPUNIT_TEST_SUITE(GraphicFormatDetectorTest); + CPPUNIT_TEST(testDetectMET); + CPPUNIT_TEST(testDetectBMP); + CPPUNIT_TEST(testDetectWMF); + CPPUNIT_TEST(testDetectPCX); + CPPUNIT_TEST(testDetectJPG); + CPPUNIT_TEST(testDetectPNG); + CPPUNIT_TEST(testDetectGIF); + CPPUNIT_TEST(testDetectPSD); + CPPUNIT_TEST(testDetectTGA); + CPPUNIT_TEST(testDetectTIF); + CPPUNIT_TEST(testDetectXBM); + CPPUNIT_TEST(testDetectXPM); + CPPUNIT_TEST(testDetectSVG); + CPPUNIT_TEST(testDetectSVGZ); + CPPUNIT_TEST(testDetectPDF); + CPPUNIT_TEST(testDetectEPS); + CPPUNIT_TEST(testMatchArray); + CPPUNIT_TEST(testCheckArrayForMatchingStrings); + CPPUNIT_TEST_SUITE_END(); +}; + +void GraphicFormatDetectorTest::testDetectMET() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.met"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "MET"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkMET()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("MET"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectBMP() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.bmp"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "BMP"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkBMP()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("BMP"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectWMF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.wmf"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "WMF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkWMForEMF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("WMF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPCX() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.pcx"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PCX"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPCX()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PCX"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectJPG() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.jpg"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "JPG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkJPG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("JPG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPNG() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.png"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PNG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPNG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PNG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectGIF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.gif"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "GIF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkGIF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("GIF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPSD() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.psd"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PSD"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPSD()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PSD"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectTGA() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.tga"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "TGA"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkTGA()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension("TGA"); // detection is based on extension only + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("TGA"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectTIF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.tif"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "TIF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkTIF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("TIF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectXBM() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.xbm"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "XBM"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkXBM()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("XBM"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectXPM() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.xpm"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "XPM"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkXPM()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("XPM"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectSVG() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.svg"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "SVG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkSVG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("SVG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectSVGZ() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.svgz"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "SVG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkSVG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("SVG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPDF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.pdf"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PDF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPDF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PDF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectEPS() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.eps"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "EPS"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkEPS()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("EPS"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testMatchArray() +{ + std::string aString("<?xml version=\"1.0\" standalone=\"no\"?>\n" + "<svg width=\"5cm\" height=\"4cm\" version=\"1.1\"\n" + "xmlns=\"http://www.w3.org/2000/svg\">\n" + "</svg>"); + + const char* pCompleteStringPointer = aString.c_str(); + const char* pMatchPointer; + int nCheckSize = aString.size(); + + // Check beginning of the input string + pMatchPointer = vcl::matchArrayWithString(pCompleteStringPointer, nCheckSize, "<?xml"); + CPPUNIT_ASSERT(pMatchPointer != nullptr); + CPPUNIT_ASSERT_EQUAL(0, int(pMatchPointer - pCompleteStringPointer)); + CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("<?xml")); + + // Check middle of the input string + pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, "version"); + CPPUNIT_ASSERT(pMatchPointer != nullptr); + CPPUNIT_ASSERT_EQUAL(6, int(pMatchPointer - pCompleteStringPointer)); + CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("version")); + + pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, "<svg"); + CPPUNIT_ASSERT(pMatchPointer != nullptr); + CPPUNIT_ASSERT_EQUAL(38, int(pMatchPointer - pCompleteStringPointer)); + CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("<svg")); + + // Check end of the input string + pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, "/svg>"); + CPPUNIT_ASSERT(pMatchPointer != nullptr); + CPPUNIT_ASSERT_EQUAL(119, int(pMatchPointer - pCompleteStringPointer)); + CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("/svg>")); + + // Check that non-existing search string + pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, "none"); + CPPUNIT_ASSERT(pMatchPointer == nullptr); +} + +void GraphicFormatDetectorTest::testCheckArrayForMatchingStrings() +{ + std::string aString("<?xml version=\"1.0\" standalone=\"no\"?>\n" + "<svg width=\"5cm\" height=\"4cm\" version=\"1.1\"\n" + "xmlns=\"http://www.w3.org/2000/svg\">\n" + "</svg>"); + const char* pCompleteStringPointer = aString.c_str(); + int nCheckSize = aString.size(); + bool bResult; + + // check beginning string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "<?xml" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check ending string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "/svg>" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check middle string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "version" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check beginning and then ending string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "<?xml", "/svg>" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check ending and then beginning string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "/svg>", "<?xml" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); + + // check middle strings + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "version", "<svg" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check beginning, middle and ending strings + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "<?xml", "version", "<svg", "/svg>" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check non-existing + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "none" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); + + // check non-existing on the beginning + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "none", "version", "<svg", "/svg>" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); + + // check non-existing on the end + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "<?xml", "version", "<svg", "none" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); + + // check non-existing after the end + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "<?xml", "/svg>", "none" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicFormatDetectorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicNativeMetadataTest.cxx b/vcl/qa/cppunit/GraphicNativeMetadataTest.cxx new file mode 100644 index 000000000..7e5d1adcb --- /dev/null +++ b/vcl/qa/cppunit/GraphicNativeMetadataTest.cxx @@ -0,0 +1,101 @@ +/* -*- 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/extensions/HelperMacros.h> +#include <unotest/bootstrapfixturebase.hxx> + +#include <vcl/GraphicNativeMetadata.hxx> +#include <vcl/graphicfilter.hxx> +#include <tools/stream.hxx> + +using namespace css; + +namespace +{ +class GraphicNativeMetadataTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc("/vcl/qa/cppunit/data/") + sFileName; + } + + void testReadFromGraphic(); + void testExifRotationJpeg(); + + CPPUNIT_TEST_SUITE(GraphicNativeMetadataTest); + CPPUNIT_TEST(testReadFromGraphic); + CPPUNIT_TEST(testExifRotationJpeg); + CPPUNIT_TEST_SUITE_END(); +}; + +void GraphicNativeMetadataTest::testReadFromGraphic() +{ + SvFileStream aFileStream(getFullUrl("Exif1_180.jpg"), StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + + // don't load the graphic, but try to get the metadata + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aFileStream); + + { + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1800), aMetadata.getRotation()); + // just the metadata shouldn't make the graphic available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + } + + // now load, and it should still work the same + { + aGraphic.makeAvailable(); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1800), aMetadata.getRotation()); + } +} + +void GraphicNativeMetadataTest::testExifRotationJpeg() +{ + { + // No rotation in metadata + SvFileStream aFileStream(getFullUrl("Exif1.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), aMetadata.getRotation()); + } + { + // Rotation 90 degree clock-wise = 270 degree counter-clock-wise + SvFileStream aFileStream(getFullUrl("Exif1_090CW.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2700), aMetadata.getRotation()); + } + { + // Rotation 180 degree + SvFileStream aFileStream(getFullUrl("Exif1_180.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1800), aMetadata.getRotation()); + } + { + // Rotation 270 degree clock-wise = 90 degree counter-clock-wise + SvFileStream aFileStream(getFullUrl("Exif1_270CW.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(900), aMetadata.getRotation()); + } +} + +} // anonymous namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicNativeMetadataTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx new file mode 100644 index 000000000..6a70ba921 --- /dev/null +++ b/vcl/qa/cppunit/GraphicTest.cxx @@ -0,0 +1,435 @@ +/* -*- 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 <config_oox.h> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <com/sun/star/beans/PropertyValue.hpp> + +#include <vcl/bitmapaccess.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <tools/stream.hxx> +#include <unotest/directories.hxx> +#include <comphelper/DirectoryHelper.hxx> +#include <comphelper/hash.hxx> +#include <unotools/ucbstreamhelper.hxx> + +#include <impgraph.hxx> + +#if USE_TLS_NSS +#include <nss.h> +#endif + +using namespace css; + +namespace +{ +class GraphicTest : public CppUnit::TestFixture +{ +public: + ~GraphicTest(); + +private: + void testUnloadedGraphic(); + void testUnloadedGraphicLoading(); + void testUnloadedGraphicWmf(); + void testUnloadedGraphicAlpha(); + void testUnloadedGraphicSizeUnit(); + void testSwapping(); + void testSwappingVectorGraphic(); + + CPPUNIT_TEST_SUITE(GraphicTest); + CPPUNIT_TEST(testUnloadedGraphic); + CPPUNIT_TEST(testUnloadedGraphicLoading); + CPPUNIT_TEST(testUnloadedGraphicWmf); + CPPUNIT_TEST(testUnloadedGraphicAlpha); + CPPUNIT_TEST(testUnloadedGraphicSizeUnit); + CPPUNIT_TEST(testSwapping); + CPPUNIT_TEST(testSwappingVectorGraphic); + CPPUNIT_TEST_SUITE_END(); +}; + +GraphicTest::~GraphicTest() +{ +#if USE_TLS_NSS + NSS_Shutdown(); +#endif +} + +BitmapEx createBitmap(bool alpha = false) +{ + Bitmap aBitmap(Size(120, 100), 24); + aBitmap.Erase(COL_LIGHTRED); + + aBitmap.SetPrefSize(Size(6000, 5000)); + aBitmap.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + + if (alpha) + { + sal_uInt8 uAlphaValue = 0x80; + AlphaMask aAlphaMask(Size(120, 100), &uAlphaValue); + + return BitmapEx(aBitmap, aAlphaMask); + } + else + { + return BitmapEx(aBitmap); + } +} + +void createBitmapAndExportForType(SvStream& rStream, OUString const& sType, bool alpha) +{ + BitmapEx aBitmapEx = createBitmap(alpha); + + uno::Sequence<beans::PropertyValue> aFilterData; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName(sType); + rGraphicFilter.ExportGraphic(aBitmapEx, "none", rStream, nFilterFormat, &aFilterData); + + rStream.Seek(STREAM_SEEK_TO_BEGIN); +} + +Graphic makeUnloadedGraphic(OUString const& sType, bool alpha = false) +{ + SvMemoryStream aStream; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + createBitmapAndExportForType(aStream, sType, alpha); + return rGraphicFilter.ImportUnloadedGraphic(aStream); +} + +std::string toHexString(const std::vector<unsigned char>& a) +{ + std::stringstream aStrm; + for (auto& i : a) + { + aStrm << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(i); + } + + return aStrm.str(); +} + +std::unique_ptr<SvStream> createStream(OUString const& rSwapFileURL) +{ + std::unique_ptr<SvStream> xStream; + + try + { + xStream = ::utl::UcbStreamHelper::CreateStream( + rSwapFileURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE); + } + catch (const css::uno::Exception&) + { + } + + return xStream; +} + +std::vector<unsigned char> calculateHash(std::unique_ptr<SvStream>& rStream) +{ + comphelper::Hash aHashEngine(comphelper::HashType::SHA1); + const sal_uInt32 nSize(rStream->remainingSize()); + std::vector<sal_uInt8> aData(nSize); + aHashEngine.update(aData.data(), nSize); + return aHashEngine.finalize(); +} + +bool checkBitmap(Graphic& rGraphic) +{ + bool bResult = true; + + Bitmap aBitmap(rGraphic.GetBitmapEx().GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + for (long y = 0; y < rGraphic.GetSizePixel().Height(); y++) + { + for (long x = 0; x < rGraphic.GetSizePixel().Width(); x++) + { + if (pReadAccess->HasPalette()) + { + sal_uInt32 nIndex = pReadAccess->GetPixelIndex(y, x); + Color aColor = pReadAccess->GetPaletteColor(nIndex); + bResult &= (aColor == Color(0xff, 0x00, 0x00)); + } + else + { + Color aColor = pReadAccess->GetPixel(y, x); + bResult &= (aColor == Color(0xff, 0x00, 0x00)); + } + } + } + } + + return bResult; +} + +char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/data/"; + +void GraphicTest::testUnloadedGraphic() +{ + // make unloaded test graphic + Graphic aGraphic = makeUnloadedGraphic("png"); + Graphic aGraphic2 = aGraphic; + + // check available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic2.isAvailable()); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic2.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic2.isAvailable()); + + // check GetSizePixel doesn't load graphic + aGraphic = makeUnloadedGraphic("png"); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // check GetPrefSize doesn't load graphic + CPPUNIT_ASSERT_EQUAL(6000L, aGraphic.GetPrefSize().Width()); + CPPUNIT_ASSERT_EQUAL(5000L, aGraphic.GetPrefSize().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // check GetSizeBytes loads graphic + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + //check Type + aGraphic = makeUnloadedGraphic("png"); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); +} + +void GraphicTest::testUnloadedGraphicLoading() +{ + const OUString aFormats[] = { "png", "gif", "jpg" }; + + for (OUString const& sFormat : aFormats) + { + Graphic aGraphic = makeUnloadedGraphic(sFormat); + + // check available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + if (sFormat != "jpg") + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); + } +} + +void GraphicTest::testUnloadedGraphicWmf() +{ + // Create some in-memory WMF data, set its own preferred size to 99x99. + BitmapEx aBitmapEx = createBitmap(); + SvMemoryStream aStream; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName("wmf"); + Graphic aGraphic(aBitmapEx); + aGraphic.SetPrefSize(Size(99, 99)); + aGraphic.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + rGraphicFilter.ExportGraphic(aGraphic, "none", aStream, nFilterFormat); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Now lazy-load this WMF data, with a custom preferred size of 42x42. + Size aMtfSize100(42, 42); + aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream, 0, &aMtfSize100); + aGraphic.makeAvailable(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 42x42 + // - Actual : 99x99 + // i.e. the custom preferred size was lost after lazy-load. + CPPUNIT_ASSERT_EQUAL(Size(42, 42), aGraphic.GetPrefSize()); +} + +void GraphicTest::testUnloadedGraphicAlpha() +{ + // make unloaded test graphic with alpha + Graphic aGraphic = makeUnloadedGraphic("png", true); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // make unloaded test graphic without alpha + aGraphic = makeUnloadedGraphic("png", false); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); +} + +void GraphicTest::testUnloadedGraphicSizeUnit() +{ + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "inch-size.emf"; + Size aMtfSize100(42, 42); + SvFileStream aStream(aURL, StreamMode::READ); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream, 0, &aMtfSize100); + aGraphic.makeAvailable(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 400x363 + // - Actual : 42x42 + // i.e. a mm100 size was used as a hint and the inch size was set for a non-matching unit. + CPPUNIT_ASSERT_EQUAL(Size(400, 363), aGraphic.GetPrefSize()); +} + +void GraphicTest::testSwapping() +{ + // Prepare Graphic from a PNG image first + Graphic aGraphic = makeUnloadedGraphic("png"); + + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + + BitmapChecksum aChecksumBeforeSwapping = aGraphic.GetChecksum(); + + CPPUNIT_ASSERT_EQUAL(sal_uInt32(319), aGraphic.GetGfxLink().GetDataSize()); + + // We loaded the Graphic and made it available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + // Get the declared byte size of the graphic + sal_uLong rByteSize = aGraphic.GetSizeBytes(); + OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty()); + + // Swapping out + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Byte size doesn't change when we swapped out + CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes()); + + // Let's check the swap file + rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + { // Check the swap file content + std::unique_ptr<SvStream> xStream = createStream(rSwapFileURL); + CPPUNIT_ASSERT_EQUAL(true, bool(xStream)); + + // Check size of the stream + CPPUNIT_ASSERT_EQUAL(sal_uInt64(445), xStream->remainingSize()); + + std::vector<unsigned char> aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("304f17d9c56e79b95f6c337dab88709d4f9b61f0"), + toHexString(aHash)); + } + + // Let's swap in + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + + CPPUNIT_ASSERT_EQUAL(aChecksumBeforeSwapping, aGraphic.GetChecksum()); + + // File shouldn't be available anymore + CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + // Check the bitmap + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); +} + +void GraphicTest::testSwappingVectorGraphic() +{ + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Load the vector graphic + CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData())); + CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), + aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), aGraphic.GetGfxLink().GetDataSize()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum(); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + + // Get the declared byte size of the graphic + sal_uLong rByteSize = aGraphic.GetSizeBytes(); + CPPUNIT_ASSERT_EQUAL(sal_uLong(223), rByteSize); + OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty()); + + // Swapping out + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Byte size doesn't change when we swapped out + // TODO: In case we don't trigger GetBitmapEx (above) the size is 0 + CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes()); + + // Let's check the swap file + rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + { // Check the swap file content + std::unique_ptr<SvStream> xStream = createStream(rSwapFileURL); + CPPUNIT_ASSERT_EQUAL(true, bool(xStream)); + + // Check size of the stream + CPPUNIT_ASSERT_EQUAL(sal_uInt64(349), xStream->remainingSize()); + + std::vector<unsigned char> aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("88b4c1c359e3cf7be005fbb46c93ffa6de9dcf4a"), + toHexString(aHash)); + } + + // Let's swap in + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + + CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum()); + + // File shouldn't be available anymore + CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/ScanlineToolsTest.cxx b/vcl/qa/cppunit/ScanlineToolsTest.cxx new file mode 100644 index 000000000..bf053d3bc --- /dev/null +++ b/vcl/qa/cppunit/ScanlineToolsTest.cxx @@ -0,0 +1,224 @@ +/* -*- 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 <bitmap/ScanlineTools.hxx> + +namespace +{ +class ScanlineToolsTest : public CppUnit::TestFixture +{ + void ScanlineTransformer_32_ARGB(); + void ScanlineTransformer_24_BGR(); + void ScanlineTransformer_8bit_Palette(); + void ScanlineTransformer_4bit_Palette(); + void ScanlineTransformer_1bit_Palette(); + + CPPUNIT_TEST_SUITE(ScanlineToolsTest); + CPPUNIT_TEST(ScanlineTransformer_32_ARGB); + CPPUNIT_TEST(ScanlineTransformer_24_BGR); + CPPUNIT_TEST(ScanlineTransformer_8bit_Palette); + CPPUNIT_TEST(ScanlineTransformer_4bit_Palette); + CPPUNIT_TEST(ScanlineTransformer_1bit_Palette); + CPPUNIT_TEST_SUITE_END(); +}; + +void ScanlineToolsTest::ScanlineTransformer_32_ARGB() +{ + BitmapPalette aPalette; + std::unique_ptr<vcl::bitmap::ScanlineTransformer> pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(32, aPalette); + + std::vector<sal_uInt8> aScanLine(5 * 4, 0); // 5 * 4 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + std::vector<Color> aColors{ + Color(0, 10, 250, 120), Color(50, 30, 230, 110), Color(100, 50, 210, 100), + Color(150, 70, 190, 90), Color(200, 90, 170, 80), + }; + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector<sal_uInt8> aExpectedBytes{ 0, 10, 250, 120, 50, 30, 230, 110, 100, 50, + 210, 100, 150, 70, 190, 90, 200, 90, 170, 80 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } +} + +void ScanlineToolsTest::ScanlineTransformer_24_BGR() +{ + BitmapPalette aPalette; + std::unique_ptr<vcl::bitmap::ScanlineTransformer> pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(24, aPalette); + + std::vector<sal_uInt8> aScanLine(5 * 3, 0); // 5 * 3 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + std::vector<Color> aColors{ + Color(0, 10, 250, 120), Color(50, 30, 230, 110), Color(100, 50, 210, 100), + Color(150, 70, 190, 90), Color(200, 90, 170, 80), + }; + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector<sal_uInt8> aExpectedBytes{ 120, 250, 10, 110, 230, 30, 100, 210, + 50, 90, 190, 70, 80, 170, 90 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } +} + +void ScanlineToolsTest::ScanlineTransformer_8bit_Palette() +{ + std::vector<Color> aColors{ + Color(0, 10, 250, 120), Color(50, 30, 230, 110), Color(100, 50, 210, 100), + Color(150, 70, 190, 90), Color(200, 90, 170, 80), + }; + + BitmapPalette aPalette(256); + for (size_t i = 0; i < aColors.size(); ++i) + aPalette[i] = aColors[i]; + + std::unique_ptr<vcl::bitmap::ScanlineTransformer> pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(8, aPalette); + + std::vector<sal_uInt8> aScanLine(5, 0); // 5 * 1 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector<sal_uInt8> aExpectedBytes{ 0, 1, 2, 3, 4 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } + + pScanlineTransformer->startLine(aScanLine.data()); + + for (size_t i = 0; i < aColors.size(); ++i) + { + Color aColor = pScanlineTransformer->readPixel(); + CPPUNIT_ASSERT_EQUAL(aColors[i], aColor); + } +} + +void ScanlineToolsTest::ScanlineTransformer_4bit_Palette() +{ + std::vector<Color> aColors{ + Color(10, 250, 120), Color(30, 230, 110), Color(50, 210, 100), + Color(70, 190, 90), Color(90, 170, 80), Color(110, 150, 70), + }; + + BitmapPalette aPalette(16); + for (size_t i = 0; i < aColors.size(); ++i) + { + aPalette[i] = aColors[i]; + } + + std::unique_ptr<vcl::bitmap::ScanlineTransformer> pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(4, aPalette); + + std::vector<sal_uInt8> aScanLine(3, 0); // 6 * 0.5 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector<sal_uInt8> aExpectedBytes{ 0x01, 0x23, 0x45 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } + + pScanlineTransformer->startLine(aScanLine.data()); + + for (size_t i = 0; i < aColors.size(); ++i) + { + Color aColor = pScanlineTransformer->readPixel(); + CPPUNIT_ASSERT_EQUAL(aColors[i], aColor); + } +} + +void ScanlineToolsTest::ScanlineTransformer_1bit_Palette() +{ + std::vector<Color> aColors{ + Color(10, 250, 120), Color(30, 230, 110), Color(50, 210, 100), Color(70, 190, 90), + Color(90, 170, 80), Color(110, 150, 70), Color(130, 130, 60), Color(150, 110, 50), + Color(170, 90, 40), Color(190, 70, 30), Color(210, 50, 20), Color(230, 30, 10), + Color(250, 10, 0), + }; + + BitmapPalette aPalette(2); + aPalette[0] = Color(10, 250, 120); + aPalette[1] = Color(110, 150, 70); + + std::unique_ptr<vcl::bitmap::ScanlineTransformer> pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(1, aPalette); + + std::vector<sal_uInt8> aScanLine(2, 0); // 13 * 1/8 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector<sal_uInt8> aExpectedBytes{ + // We expect 3x index 0 and 10x index 1 => 000 111111111 + 0x1f, // 0001 1111 + 0xf8 // 1111 1000 + }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } + + pScanlineTransformer->startLine(aScanLine.data()); + + std::vector<Color> aColorsExpected{ + Color(10, 250, 120), Color(10, 250, 120), Color(10, 250, 120), Color(110, 150, 70), + Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), + Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), + Color(110, 150, 70), + }; + + for (size_t i = 0; i < aColors.size(); ++i) + { + Color aColor = pScanlineTransformer->readPixel(); + CPPUNIT_ASSERT_EQUAL(aColorsExpected[i], aColor); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(ScanlineToolsTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/TypeSerializerTest.cxx b/vcl/qa/cppunit/TypeSerializerTest.cxx new file mode 100644 index 000000000..30966700a --- /dev/null +++ b/vcl/qa/cppunit/TypeSerializerTest.cxx @@ -0,0 +1,502 @@ +/* -*- 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 <config_oox.h> +#include <config_features.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <unotest/directories.hxx> +#include <vcl/graph.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <comphelper/hash.hxx> +#include <tools/vcompat.hxx> +#include <comphelper/fileformat.h> + +#include <TypeSerializer.hxx> + +#if USE_TLS_NSS +#include <nss.h> +#endif + +namespace +{ +constexpr char DATA_DIRECTORY[] = "/vcl/qa/cppunit/data/"; + +std::vector<unsigned char> calculateHash(SvStream& rStream) +{ + rStream.Seek(STREAM_SEEK_TO_BEGIN); + comphelper::Hash aHashEngine(comphelper::HashType::SHA1); + const sal_uInt32 nSize(rStream.remainingSize()); + std::vector<sal_uInt8> aData(nSize); + aHashEngine.update(aData.data(), nSize); + return aHashEngine.finalize(); +} + +std::string toHexString(const std::vector<unsigned char>& a) +{ + std::stringstream aStrm; + for (auto& i : a) + { + aStrm << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(i); + } + + return aStrm.str(); +} + +class TypeSerializerTest : public CppUnit::TestFixture +{ +public: + ~TypeSerializerTest(); + +private: + void testGradient(); + void testGraphic_Vector(); + void testGraphic_Bitmap_NoGfxLink(); + void testGraphic_Animation(); + void testGraphic_GDIMetaFile(); + + CPPUNIT_TEST_SUITE(TypeSerializerTest); + CPPUNIT_TEST(testGradient); + CPPUNIT_TEST(testGraphic_Vector); + CPPUNIT_TEST(testGraphic_Bitmap_NoGfxLink); + CPPUNIT_TEST(testGraphic_Animation); + CPPUNIT_TEST(testGraphic_GDIMetaFile); + CPPUNIT_TEST_SUITE_END(); +}; + +TypeSerializerTest::~TypeSerializerTest() +{ +#if USE_TLS_NSS + NSS_Shutdown(); +#endif +} + +void TypeSerializerTest::testGradient() +{ + Gradient aGradient(GradientStyle::Radial, Color(0xFF, 0x00, 0x00), Color(0x00, 0xFF, 0x00)); + aGradient.SetAngle(900); + aGradient.SetBorder(5); + aGradient.SetOfsX(11); + aGradient.SetOfsY(12); + aGradient.SetStartIntensity(21); + aGradient.SetEndIntensity(22); + aGradient.SetSteps(30); + + SvMemoryStream aStream; + TypeSerializer aSerializer(aStream); + aSerializer.writeGradient(aGradient); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + Gradient aReadGradient; + aSerializer.readGradient(aReadGradient); + CPPUNIT_ASSERT_EQUAL(GradientStyle::Radial, aReadGradient.GetStyle()); + CPPUNIT_ASSERT_EQUAL(Color(0xFF, 0x00, 0x00), aReadGradient.GetStartColor()); + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0x00), aReadGradient.GetEndColor()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(900), aReadGradient.GetAngle()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(5), aReadGradient.GetBorder()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(11), aReadGradient.GetOfsX()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(12), aReadGradient.GetOfsY()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(21), aReadGradient.GetStartIntensity()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(22), aReadGradient.GetEndIntensity()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), aReadGradient.GetSteps()); +} + +void TypeSerializerTest::testGraphic_Vector() +{ + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + aGraphic.makeAvailable(); + BitmapChecksum aChecksum = aGraphic.getVectorGraphicData()->GetChecksum(); + + // Test WriteGraphic - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(290), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("ee55ab6faa73b61b68bc3d5628d95f0d3c528e2a"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } + + // Test WriteGraphic - Normal + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(233), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("c2bed2099ce617f1cc035701de5186f0d43e3064"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(createMagic('s', 'v', 'g', '0'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } + + // Test TypeSerializer - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(290), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("ee55ab6faa73b61b68bc3d5628d95f0d3c528e2a"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } + + // Test TypeSerializer - Normal + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(233), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("c2bed2099ce617f1cc035701de5186f0d43e3064"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(createMagic('s', 'v', 'g', '0'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } +} + +void TypeSerializerTest::testGraphic_Bitmap_NoGfxLink() +{ + Bitmap aBitmap(Size(10, 10), 24); + aBitmap.Erase(COL_LIGHTGRAYBLUE); + BitmapEx aBitmapEx(aBitmap); + Graphic aGraphic(aBitmapEx); + + // Test WriteGraphic + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(383), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da831418499146d51bf245fadf60b9111faa76c2"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); // Magic written with WriteDIBBitmapEx + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aBitmapEx.GetChecksum(), aNewGraphic.GetBitmapExRef().GetChecksum()); + } + + // Test TypeSerializer + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(383), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da831418499146d51bf245fadf60b9111faa76c2"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); // Magic written with WriteDIBBitmapEx + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aBitmapEx.GetChecksum(), aNewGraphic.GetBitmapExRef().GetChecksum()); + } +} + +void TypeSerializerTest::testGraphic_Animation() +{ + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "123_Numbers.gif"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + aGraphic.makeAvailable(); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAnimated()); + + // Test WriteGraphic + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(15167), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("69d0f80832a0aebcbda7ad43ecadf85e99fc1057"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } + + // Test WriteGraphic - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(1582), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da3b9600340fa80a895f2107357e4ab65a9292eb"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } + + // Test TypeSerializer + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(15167), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("69d0f80832a0aebcbda7ad43ecadf85e99fc1057"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } + + // Test TypeSerializer - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(1582), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da3b9600340fa80a895f2107357e4ab65a9292eb"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } +} + +void TypeSerializerTest::testGraphic_GDIMetaFile() +{ + GDIMetaFile aGDIMetaFile; + { + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + pVirtualDev->SetConnectMetaFile(&aGDIMetaFile); + Size aVDSize(10, 10); + pVirtualDev->SetOutputSizePixel(aVDSize); + pVirtualDev->SetBackground(Wallpaper(COL_LIGHTRED)); + pVirtualDev->Erase(); + pVirtualDev->DrawPixel(Point(4, 4)); + } + Graphic aGraphic(aGDIMetaFile); + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aGraphic.GetType()); + + // Test WriteGraphic + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(229), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("144c518e5149d61ab4bc34643df820372405d61d"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + char aIdCharArray[7] = { 0, 0, 0, 0, 0, 0, 0 }; + aMemoryStream.ReadBytes(aIdCharArray, 6); + OString sID(aIdCharArray); + CPPUNIT_ASSERT_EQUAL(OString("VCLMTF"), sID); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aNewGraphic.GetType()); + } + + // Test TypeSerializer + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(229), aMemoryStream.remainingSize()); + std::vector<unsigned char> aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("144c518e5149d61ab4bc34643df820372405d61d"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + char aIdCharArray[7] = { 0, 0, 0, 0, 0, 0, 0 }; + aMemoryStream.ReadBytes(aIdCharArray, 6); + OString sID(aIdCharArray); + CPPUNIT_ASSERT_EQUAL(OString("VCLMTF"), sID); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aNewGraphic.GetType()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(TypeSerializerTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/app/test_IconThemeInfo.cxx b/vcl/qa/cppunit/app/test_IconThemeInfo.cxx new file mode 100644 index 000000000..d2e466d89 --- /dev/null +++ b/vcl/qa/cppunit/app/test_IconThemeInfo.cxx @@ -0,0 +1,116 @@ +/* -*- 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 <stdexcept> + +#include <rtl/ustring.hxx> +#include <vcl/IconThemeInfo.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +using namespace vcl; + +class IconThemeInfoTest : public CppUnit::TestFixture +{ + void + UpperCaseDisplayNameIsReturnedForNonDefaultId(); + + void + ImagesZipIsNotValid(); + + void + ImagesColibreZipIsValid(); + + void + ThemeIdIsDetectedFromFileNameWithUnderscore(); + + void + ExceptionIsThrownWhenIdCannotBeDetermined1(); + + void + ExceptionIsThrownWhenIdCannotBeDetermined2(); + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IconThemeInfoTest); + CPPUNIT_TEST(UpperCaseDisplayNameIsReturnedForNonDefaultId); + CPPUNIT_TEST(ThemeIdIsDetectedFromFileNameWithUnderscore); + CPPUNIT_TEST(ImagesZipIsNotValid); + CPPUNIT_TEST(ImagesColibreZipIsValid); + CPPUNIT_TEST(ExceptionIsThrownWhenIdCannotBeDetermined1); + CPPUNIT_TEST(ExceptionIsThrownWhenIdCannotBeDetermined2); + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +void +IconThemeInfoTest::UpperCaseDisplayNameIsReturnedForNonDefaultId() +{ + OUString const id("katze"); + OUString displayName = vcl::IconThemeInfo::ThemeIdToDisplayName(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("theme id is properly uppercased", OUString("Katze"), displayName); +} + +void +IconThemeInfoTest::ImagesZipIsNotValid() +{ + bool valid = vcl::IconThemeInfo::UrlCanBeParsed("file://images.zip"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("images.zip is not a valid theme name", false, valid); +} + +void +IconThemeInfoTest::ImagesColibreZipIsValid() +{ + OUString const id("file://images_colibre.zip"); + bool valid = vcl::IconThemeInfo::UrlCanBeParsed(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("images_colibre.zip is a valid theme name", true, valid); +} + +void +IconThemeInfoTest::ThemeIdIsDetectedFromFileNameWithUnderscore() +{ + OUString const fname("images_colibre.zip"); + OUString sname = vcl::IconThemeInfo::FileNameToThemeId(fname); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'colibre' theme id is returned for 'images_colibre.zip'", OUString("colibre"), sname); +} + +void +IconThemeInfoTest::ExceptionIsThrownWhenIdCannotBeDetermined1() +{ + bool thrown = false; + OUString const fname("images_colibre"); + try { + vcl::IconThemeInfo::FileNameToThemeId(fname); + } + catch (std::runtime_error&) { + thrown = true; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception was thrown",true, thrown); +} + +void +IconThemeInfoTest::ExceptionIsThrownWhenIdCannotBeDetermined2() +{ + bool thrown = false; + OUString const fname("image_colibre.zip"); + try { + vcl::IconThemeInfo::FileNameToThemeId(fname); + } + catch (std::runtime_error&) { + thrown = true; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception was thrown", true, thrown); +} + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(IconThemeInfoTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/app/test_IconThemeScanner.cxx b/vcl/qa/cppunit/app/test_IconThemeScanner.cxx new file mode 100644 index 000000000..f65e70bc6 --- /dev/null +++ b/vcl/qa/cppunit/app/test_IconThemeScanner.cxx @@ -0,0 +1,82 @@ +/* -*- 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 <stdexcept> + +#include <rtl/ustring.hxx> +#include <IconThemeScanner.hxx> +#include <vcl/IconThemeInfo.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +class IconThemeScannerTest : public CppUnit::TestFixture +{ + void + AddedThemeIsFoundById(); + + void + AddedThemeInfoIsReturned(); + + void + ExceptionIsThrownIfInvalidInfoIsRequested(); + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IconThemeScannerTest); + CPPUNIT_TEST(AddedThemeIsFoundById); + CPPUNIT_TEST(AddedThemeInfoIsReturned); + CPPUNIT_TEST(ExceptionIsThrownIfInvalidInfoIsRequested); + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +void +IconThemeScannerTest::AddedThemeIsFoundById() +{ + vcl::IconThemeScanner scanner; + scanner.AddIconThemeByPath("file:://images_katze.zip"); + OUString id = vcl::IconThemeInfo::FileNameToThemeId("images_katze.zip"); + bool found = scanner.IconThemeIsInstalled(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("icon theme could be added by url", true, found); +} + +void +IconThemeScannerTest::AddedThemeInfoIsReturned() +{ + vcl::IconThemeScanner scanner; + OUString theme("file:://images_katze.zip"); + scanner.AddIconThemeByPath(theme); + OUString id = vcl::IconThemeInfo::FileNameToThemeId("images_katze.zip"); + const vcl::IconThemeInfo& info = scanner.GetIconThemeInfo(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'katze' icon theme is found from id", theme, info.GetUrlToFile()); +} + +void +IconThemeScannerTest::ExceptionIsThrownIfInvalidInfoIsRequested() +{ + vcl::IconThemeScanner scanner; + scanner.AddIconThemeByPath("file:://images_katze.zip"); + bool thrown = false; + try + { + scanner.GetIconThemeInfo("hund"); + } + catch (const std::runtime_error&) + { + thrown = true; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception is thrown if invalid theme info is requested", true, thrown); +} + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(IconThemeScannerTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/app/test_IconThemeSelector.cxx b/vcl/qa/cppunit/app/test_IconThemeSelector.cxx new file mode 100644 index 000000000..69f61c79e --- /dev/null +++ b/vcl/qa/cppunit/app/test_IconThemeSelector.cxx @@ -0,0 +1,183 @@ +/* -*- 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 <IconThemeSelector.hxx> + +#include <vcl/IconThemeInfo.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +class IconThemeSelectorTest : public CppUnit::TestFixture +{ +#ifndef _WIN32 //default theme on Windows is Colibre independently from any desktop environment + void BreezeIsReturnedForKde5Desktop(); + void ElementaryIsReturnedForGnomeDesktop(); + void ThemeIsOverriddenByPreferredTheme(); + void ThemeIsOverriddenByHighContrastMode(); + void NotInstalledThemeDoesNotOverride(); + void InstalledThemeIsFound(); + void FirstThemeIsReturnedIfRequestedThemeIsNotFound(); + void FallbackThemeIsReturnedForEmptyInput(); + void DifferentPreferredThemesAreInequal(); + void DifferentHighContrastModesAreInequal(); + static std::vector<vcl::IconThemeInfo> GetFakeInstalledThemes(); +#endif + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IconThemeSelectorTest); + +#ifndef _WIN32 + CPPUNIT_TEST(BreezeIsReturnedForKde5Desktop); + CPPUNIT_TEST(ElementaryIsReturnedForGnomeDesktop); + CPPUNIT_TEST(ThemeIsOverriddenByPreferredTheme); + CPPUNIT_TEST(ThemeIsOverriddenByHighContrastMode); + CPPUNIT_TEST(NotInstalledThemeDoesNotOverride); + CPPUNIT_TEST(InstalledThemeIsFound); + CPPUNIT_TEST(FirstThemeIsReturnedIfRequestedThemeIsNotFound); + CPPUNIT_TEST(FallbackThemeIsReturnedForEmptyInput); + CPPUNIT_TEST(DifferentPreferredThemesAreInequal); + CPPUNIT_TEST(DifferentHighContrastModesAreInequal); +#endif + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +#ifndef _WIN32 + +/*static*/ std::vector<vcl::IconThemeInfo> +IconThemeSelectorTest::GetFakeInstalledThemes() +{ + std::vector<vcl::IconThemeInfo> r; + vcl::IconThemeInfo a; + a.mThemeId = "breeze"; + r.push_back(a); + a.mThemeId = "elementary"; + r.push_back(a); + a.mThemeId = "colibre"; + r.push_back(a); + a.mThemeId = "sifr"; + r.push_back(a); + return r; +} + +void +IconThemeSelectorTest::BreezeIsReturnedForKde5Desktop() +{ + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + vcl::IconThemeSelector s; + OUString r = s.SelectIconThemeForDesktopEnvironment(themes, "plasma5"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is returned for Plasma 5 desktop", OUString("breeze"), r); +} + +void +IconThemeSelectorTest::ElementaryIsReturnedForGnomeDesktop() +{ + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + vcl::IconThemeSelector s; + OUString r = s.SelectIconThemeForDesktopEnvironment(themes, "gnome"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'elementary' theme is returned for gnome desktop", OUString("elementary"), r); +} + +void +IconThemeSelectorTest::ThemeIsOverriddenByPreferredTheme() +{ + vcl::IconThemeSelector s; + OUString preferred("breeze"); + s.SetPreferredIconTheme(preferred, false); + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconThemeForDesktopEnvironment(themes, "gnome"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'elementary' theme is overridden by breeze", preferred, selected); +} + +void +IconThemeSelectorTest::ThemeIsOverriddenByHighContrastMode() +{ + vcl::IconThemeSelector s; + s.SetUseHighContrastTheme(true); + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "breeze"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is overridden by high contrast mode", + OUString("sifr"), selected); + s.SetUseHighContrastTheme(false); + selected = s.SelectIconTheme(themes, "breeze"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is no longer overridden by high contrast mode", + OUString("breeze"), selected); +} + +void +IconThemeSelectorTest::NotInstalledThemeDoesNotOverride() +{ + vcl::IconThemeSelector s; + s.SetPreferredIconTheme("breeze_foo", false); + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "colibre"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'colibre' theme is not overridden by 'breeze_foo'", OUString("colibre"), selected); +} + +void +IconThemeSelectorTest::InstalledThemeIsFound() +{ + vcl::IconThemeSelector s; + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "colibre"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'colibre' theme is found", OUString("colibre"), selected); +} + +void +IconThemeSelectorTest::FirstThemeIsReturnedIfRequestedThemeIsNotFound() +{ + vcl::IconThemeSelector s; + std::vector<vcl::IconThemeInfo> themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "breeze_foo"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is found", themes.front().GetThemeId(), selected); +} + +void +IconThemeSelectorTest::FallbackThemeIsReturnedForEmptyInput() +{ + vcl::IconThemeSelector s; + OUString selected = s.SelectIconTheme(std::vector<vcl::IconThemeInfo>(), "colibre"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("fallback is returned for empty input", + OUString(vcl::IconThemeSelector::FALLBACK_ICON_THEME_ID), selected); +} + +void +IconThemeSelectorTest::DifferentHighContrastModesAreInequal() +{ + vcl::IconThemeSelector s1; + vcl::IconThemeSelector s2; + s1.SetUseHighContrastTheme(true); + s2.SetUseHighContrastTheme(false); + bool equal = (s1 == s2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Different high contrast modes are detected as inequal", false, equal); +} + +void +IconThemeSelectorTest::DifferentPreferredThemesAreInequal() +{ + vcl::IconThemeSelector s1; + vcl::IconThemeSelector s2; + s1.SetPreferredIconTheme("breeze", false); + s2.SetUseHighContrastTheme(true); + bool equal = (s1 == s2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Different preferred themes are detected as inequal", false, equal); +} + +#endif + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(IconThemeSelectorTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/bitmapcolor.cxx b/vcl/qa/cppunit/bitmapcolor.cxx new file mode 100644 index 000000000..eafa4d138 --- /dev/null +++ b/vcl/qa/cppunit/bitmapcolor.cxx @@ -0,0 +1,262 @@ +/* -*- 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 incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// bootstrap stuff +#include <test/bootstrapfixture.hxx> + +#include <vcl/BitmapColor.hxx> + +namespace +{ +class BitmapColorTest : public test::BootstrapFixture +{ +public: + BitmapColorTest() + : BootstrapFixture(true, false) + { + } + + void defaultConstructor(); + void colorValueConstructor(); + void colorClassConstructor(); + void setValue(); + void invert(); + void getLuminance(); + + CPPUNIT_TEST_SUITE(BitmapColorTest); + CPPUNIT_TEST(defaultConstructor); + CPPUNIT_TEST(colorValueConstructor); + CPPUNIT_TEST(colorClassConstructor); + CPPUNIT_TEST(setValue); + CPPUNIT_TEST(invert); + CPPUNIT_TEST(getLuminance); + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapColorTest::defaultConstructor() +{ + BitmapColor aBmpColor; + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(0), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(0), aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), aBmpColor.GetAlpha()); +} + +void BitmapColorTest::colorValueConstructor() +{ + { + BitmapColor aBmpColor(0, 0, 0); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(0), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(128, 128, 128); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(128), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(128), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(128), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(255, 255, 255); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(255), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(255), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(255), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetAlpha()); + } +} + +void BitmapColorTest::colorClassConstructor() +{ + { + BitmapColor aBmpColor(Color(0, 0, 0)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(0), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(Color(127, 127, 127)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(127), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(127), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(127), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(Color(255, 255, 255)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(255), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(255), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(255), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(0), + aBmpColor.GetAlpha()); + } + + // Transparency / Alpha + { + BitmapColor aBmpColor(Color(255, 128, 64, 0)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast<sal_uInt8>(128), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast<sal_uInt8>(64), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast<sal_uInt8>(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast<sal_uInt8>(255), + aBmpColor.GetAlpha()); + } +} + +void BitmapColorTest::setValue() +{ + BitmapColor aBmpColor; + + aBmpColor.SetRed(127); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(127), aBmpColor.GetRed()); + + aBmpColor.SetGreen(127); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(127), aBmpColor.GetGreen()); + + aBmpColor.SetBlue(127); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(127), aBmpColor.GetBlue()); +} + +void BitmapColorTest::invert() +{ + BitmapColor aBmpColor(255, 255, 255); + BitmapColor aInvertedColor(aBmpColor); + aInvertedColor.Invert(); + + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(0), aInvertedColor.GetRed()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(0), aInvertedColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(0), aInvertedColor.GetBlue()); +} + +void BitmapColorTest::getLuminance() +{ + { + BitmapColor aBmpColor(COL_BLACK); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(0), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_BLUE); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(14), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_GREEN); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(75), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_CYAN); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(90), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_RED); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(38), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_MAGENTA); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(52), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_BROWN); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(113), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_GRAY); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(128), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTGRAY); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(192), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTBLUE); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(28), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTGREEN); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(150), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTCYAN); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(179), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTRED); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(75), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTMAGENTA); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(104), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_YELLOW); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(226), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_WHITE); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(255), aBmpColor.GetLuminance()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapColorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx new file mode 100644 index 000000000..73e3baab9 --- /dev/null +++ b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx @@ -0,0 +1,269 @@ +/* -*- 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 <vcl/virdev.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/svapp.hxx> + +#include <tools/stream.hxx> + +#include <vcl/graphicfilter.hxx> +#include <vcl/filter/PngImageReader.hxx> + +#include <svdata.hxx> +#include <salinst.hxx> + +static OUString const gaDataUrl = "/vcl/qa/cppunit/bitmaprender/data/"; + +class BitmapRenderTest : public test::BootstrapFixture +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + +public: + BitmapRenderTest() + : BootstrapFixture(true, false) + { + } + + void testTdf104141(); + void testTdf113918(); + void testDrawAlphaBitmapEx(); + void testAlphaVirtualDevice(); + void testTdf116888(); + + CPPUNIT_TEST_SUITE(BitmapRenderTest); + CPPUNIT_TEST(testTdf104141); + CPPUNIT_TEST(testTdf113918); + CPPUNIT_TEST(testDrawAlphaBitmapEx); + CPPUNIT_TEST(testAlphaVirtualDevice); + CPPUNIT_TEST(testTdf116888); + + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapRenderTest::testTdf104141() +{ + ScopedVclPtrInstance<VirtualDevice> pVDev; + pVDev->SetOutputSizePixel(Size(400, 400)); + pVDev->SetBackground(Wallpaper(COL_GREEN)); + pVDev->Erase(); + + // Load animated GIF and draw it on green background + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + const OUString aURL(getFullUrl("tdf104141.gif")); + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + BitmapEx aBitmap = aGraphic.GetBitmapEx(); + pVDev->DrawBitmapEx(Point(20, 20), aBitmap); + + // Check drawing results: ensure that it contains transparent + // (greenish) pixels + const Color aColor = pVDev->GetPixel(Point(21, 21)); + CPPUNIT_ASSERT(aColor.GetGreen() > 10 * aColor.GetRed() + && aColor.GetGreen() > 10 * aColor.GetBlue()); +} + +void BitmapRenderTest::testTdf113918() +{ + ScopedVclPtrInstance<VirtualDevice> pVDev; + pVDev->SetOutputSizePixel(Size(2480, 3508)); + pVDev->SetBackground(Wallpaper(COL_GREEN)); + pVDev->Erase(); + + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + const OUString aURL(getFullUrl("tdf113918.png")); + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + BitmapEx aBitmap = aGraphic.GetBitmapEx(); + pVDev->DrawBitmapEx(Point(0, 0), aBitmap); + + // Ensure that image is drawn with white background color from palette + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(21, 21))); + + // Ensure that image is drawn with gray text color from palette + const Color aColor = pVDev->GetPixel(Point(1298, 1368)); + CPPUNIT_ASSERT(aColor.GetGreen() == aColor.GetRed() && aColor.GetGreen() == aColor.GetBlue()); + CPPUNIT_ASSERT(aColor.GetGreen() > 100); +} + +void BitmapRenderTest::testDrawAlphaBitmapEx() +{ + ScopedVclPtrInstance<VirtualDevice> pVDev; + pVDev->SetOutputSizePixel(Size(8, 8)); + pVDev->SetBackground(Wallpaper(COL_WHITE)); + pVDev->Erase(); + + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(0, 0))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(1, 1))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(2, 2))); + + SvFileStream aFileStream(getFullUrl("ImageRGBA.png"), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + // Check backend capabilities, if the backend support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (pBackendCapabilities->mbSupportsBitmap32) + { + CPPUNIT_ASSERT_EQUAL(sal_uInt16(32), aBitmapEx.GetBitmap().GetBitCount()); + } + else + { + CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmapEx.GetBitmap().GetBitCount()); + CPPUNIT_ASSERT_EQUAL(true, aBitmapEx.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), aBitmapEx.GetAlpha().GetBitCount()); + } + + // Check the bitmap has pixels we expect + CPPUNIT_ASSERT_EQUAL(Color(0xFF, 0x00, 0x00, 0x00), aBitmapEx.GetPixelColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0x00), aBitmapEx.GetPixelColor(1, 1)); + CPPUNIT_ASSERT_EQUAL(Color(0x7F, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(2, 2)); + + pVDev->DrawBitmapEx(Point(), aBitmapEx); + + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0xFF), pVDev->GetPixel(Point(0, 0))); + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0x00), pVDev->GetPixel(Point(1, 1))); + +// sometimes on Windows we get rounding error in blending so let's ignore this on Windows for now. +#if !defined(_WIN32) + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x7F, 0xFF, 0x7F), pVDev->GetPixel(Point(2, 2))); +#endif +} + +#ifdef _WIN32 + +namespace +{ +int deltaColor(BitmapColor aColor1, BitmapColor aColor2) +{ + int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed()); + int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen()); + int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue()); + + return std::max(std::max(deltaR, deltaG), deltaB); +} +} + +#endif + +void BitmapRenderTest::testAlphaVirtualDevice() +{ + // Create an alpha virtual device + ScopedVclPtr<VirtualDevice> pAlphaVirtualDevice(VclPtr<VirtualDevice>::Create( + *Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT)); + + // Set it up + pAlphaVirtualDevice->SetOutputSizePixel(Size(4, 4)); + pAlphaVirtualDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + pAlphaVirtualDevice->Erase(); + + // Get a BitmapEx from the VirDev -> Colors should have alpha + BitmapEx aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Height()); + Color aColor = aBitmap.GetPixelColor(1, 1); + CPPUNIT_ASSERT_EQUAL(Color(0xffffffff), aColor); + + // Draw an opaque pixel to the VirDev + pAlphaVirtualDevice->DrawPixel(Point(1, 1), Color(0x0022ff55)); + + aColor = pAlphaVirtualDevice->GetPixel(Point(1, 1)); + // Read back the opaque pixel +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x0022ff55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x0022ff55), aColor); +#endif + + // Read back the BitmapEx and check the opaque pixel + aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Height()); + + aColor = aBitmap.GetPixelColor(1, 1); +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x0022ff55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x0022ff55), aColor); +#endif + + // Draw an semi-transparent pixel + pAlphaVirtualDevice->DrawPixel(Point(0, 0), Color(0x44, 0x22, 0xff, 0x55)); + + aColor = pAlphaVirtualDevice->GetPixel(Point(0, 0)); + // Read back the semi-transparent pixel +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x4422FF55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x4422FF55), aColor); +#endif + + // Read back the BitmapEx and check the semi-transparent pixel + aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Height()); + + aColor = aBitmap.GetPixelColor(0, 0); +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x4422FF55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x4422FF55), aColor); +#endif +} + +void BitmapRenderTest::testTdf116888() +{ + // The image is a 8bit image with a non-grayscale palette. In OpenGL mode + // pdf export of the image was broken, because OpenGLSalBitmap::ReadTexture() + // didn't handle 8bit non-grayscale and moreover OpenGLSalBitmap::AcquireBuffer() + // didn't properly release mpUserBuffer after ReadTexture() failure. + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + const OUString aURL(getFullUrl("tdf116888.gif")); + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + CPPUNIT_ASSERT(!aBitmap.IsEmpty()); + aBitmap.Scale(0.8, 0.8); // This scaling discards mpUserData, + Bitmap::ScopedReadAccess pAccess(aBitmap); // forcing ReadTexture() here. + // Check that there is mpUserBuffer content. + CPPUNIT_ASSERT(pAccess); + const ScanlineFormat eFormat = pAccess->GetScanlineFormat(); + CPPUNIT_ASSERT_EQUAL(ScanlineFormat::N8BitPal, eFormat); + CPPUNIT_ASSERT(!aBitmap.HasGreyPaletteAny()); + // HACK: Some rendering backends change white to #FEFEFE while scaling for some reason. + // That is pretty much white too in practice, so adjust for that. + BitmapColor white(COL_WHITE); + if (pAccess->GetColor(0, 0) == Color(0xfe, 0xfe, 0xfe)) + white = Color(0xfe, 0xfe, 0xfe); + // Check that the image contents are also valid. + CPPUNIT_ASSERT_EQUAL(white, pAccess->GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(white, pAccess->GetColor(0, pAccess->Width() - 1)); + CPPUNIT_ASSERT_EQUAL(white, pAccess->GetColor(pAccess->Height() - 1, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), + pAccess->GetColor(pAccess->Height() - 1, pAccess->Width() - 1)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapRenderTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png b/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png Binary files differnew file mode 100644 index 000000000..7a8399293 --- /dev/null +++ b/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif b/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif Binary files differnew file mode 100644 index 000000000..d6390fdaa --- /dev/null +++ b/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf113918.png b/vcl/qa/cppunit/bitmaprender/data/tdf113918.png Binary files differnew file mode 100644 index 000000000..dd49897d9 --- /dev/null +++ b/vcl/qa/cppunit/bitmaprender/data/tdf113918.png diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif b/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif Binary files differnew file mode 100644 index 000000000..295310949 --- /dev/null +++ b/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif diff --git a/vcl/qa/cppunit/blocklistparsertest.cxx b/vcl/qa/cppunit/blocklistparsertest.cxx new file mode 100644 index 000000000..d62568de6 --- /dev/null +++ b/vcl/qa/cppunit/blocklistparsertest.cxx @@ -0,0 +1,153 @@ +/* -*- 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/types.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <unotest/bootstrapfixturebase.hxx> + +#include <driverblocklist.hxx> + +using namespace DriverBlocklist; + +namespace +{ + +class BlocklistParserTest : public test::BootstrapFixtureBase +{ + void testParse(); + void testEvaluate(); + + CPPUNIT_TEST_SUITE(BlocklistParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testEvaluate); + CPPUNIT_TEST_SUITE_END(); +}; + +void BlocklistParserTest::testParse() +{ + std::vector<DriverInfo> aDriveInfos; + + Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_parse.xml", + aDriveInfos, VersionType::OpenGL); + aBlocklistParser.parse(); + + size_t const n = aDriveInfos.size(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(16), n); + + size_t i = 0; + + for (bool bIsWhitelisted : {true, false}) + { + DriverInfo& aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); // "all" + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_LESS_THAN, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(OpenGLVersion(10,20,30,40), aDriveInfo.mnDriverVersion); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorNVIDIA), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_EQUAL, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorMicrosoft), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(OUString("0xcafe"), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_EXCLUSIVE, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE_START, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_COMPARISON_IGNORED, aDriveInfo.meComparisonOp); + } +} + +void BlocklistParserTest::testEvaluate() +{ + std::vector<DriverInfo> aDriveInfos; + + Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_evaluate.xml", + aDriveInfos, VersionType::OpenGL); + aBlocklistParser.parse(); + + OUString vendorAMD = GetVendorId(VendorAMD); + OUString vendorNVIDIA = GetVendorId(VendorNVIDIA); + OUString vendorIntel = GetVendorId(VendorIntel); + OUString vendorMicrosoft = GetVendorId(VendorMicrosoft); + + // Check OS + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_8)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_10)); + + // Check generic OS + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_10)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_LINUX)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_OSX_10_7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_OSX_10_8)); + + // Check Vendors + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_10)); + + // Check Versions + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.39", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.41", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + + // Check + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "9.17.10.4229", vendorIntel, "all", DRIVER_OS_WINDOWS_7)); + + +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BlocklistParserTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/builder/demo.ui b/vcl/qa/cppunit/builder/demo.ui new file mode 100644 index 000000000..d5784b79f --- /dev/null +++ b/vcl/qa/cppunit/builder/demo.ui @@ -0,0 +1,1960 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="vcl"> + <requires lib="gtk+" version="3.18"/> + <object class="GtkListStore" id="liststore1"> + <columns> + <!-- column-name gchararray1 --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="no">[None]</col> + </row> + <row> + <col id="0" translatable="no">Normal</col> + </row> + </data> + </object> + <object class="GtkListStore" id="liststore2"> + <columns> + <!-- column-name gchararray1 --> + <column type="gchararray"/> + </columns> + <data> + <row> + <col id="0" translatable="no">1</col> + </row> + <row> + <col id="0" translatable="no">2</col> + </row> + <row> + <col id="0" translatable="no">3</col> + </row> + <row> + <col id="0" translatable="no">4</col> + </row> + <row> + <col id="0" translatable="no">5</col> + </row> + <row> + <col id="0" translatable="no">6</col> + </row> + <row> + <col id="0" translatable="no">7</col> + </row> + <row> + <col id="0" translatable="no">8</col> + </row> + <row> + <col id="0" translatable="no">9</col> + </row> + <row> + <col id="0" translatable="no">10</col> + </row> + <row> + <col id="0" translatable="no">1 - 10</col> + </row> + </data> + </object> + <object class="GtkDialog" id="dialog1"> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="cancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="ok"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkNotebook" id="notebook1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">2</property> + <property name="row_homogeneous">True</property> + <property name="column_homogeneous">True</property> + <child> + <object class="GtkLabel" id="labelfoo"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">cell 1.1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">cell 3.3</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">A label that spans three rows</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">3</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkSpinButton" id="spinbutton1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="numeric">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="button4"> + <property name="label" translatable="no">EXPAND</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="no">A tooltip example</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button5"> + <property name="label" translatable="no">FILL</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="button3"> + <property name="label" translatable="no">button</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="radiobutton1"> + <property name="label" translatable="no">radiobutton</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="checkbutton1"> + <property name="label" translatable="no">checkbutton</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">left</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">right</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">center</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="activates_default">True</property> + <property name="text" translatable="no">an edit control</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label9"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Frame Label</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="Tab1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 1</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">10</property> + <child> + <object class="GtkFrame" id="frame2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="column_spacing">5</property> + <property name="row_homogeneous">True</property> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">_Number of title pages</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">NF_PAGE_COUNT</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Place title pages at</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label10"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">pages</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">2</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="NF_PAGE_COUNT"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="numeric">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="NF_PAGE_START"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="numeric">True</property> + <accessibility> + <relation type="labelled-by" target="RB_PAGE_START"/> + </accessibility> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">4</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="RB_USE_EXISTING_PAGES"> + <property name="label" translatable="no">Converting existing pages to title pages</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">RB_INSERT_NEW_PAGES</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">4</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="RB_INSERT_NEW_PAGES"> + <property name="label" translatable="no">Insert new title pages</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">RB_USE_EXISTING_PAGES</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">4</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="RB_DOCUMENT_START"> + <property name="label" translatable="no">Document Start</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">RB_PAGE_START</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + <property name="width">3</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="RB_PAGE_START"> + <property name="label" translatable="no">Page</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">RB_DOCUMENT_START</property> + <accessibility> + <relation type="label-for" target="NF_PAGE_START"/> + </accessibility> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label11"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Make Title Pages</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box7"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkCheckButton" id="CB_RESTART_NUMBERING"> + <property name="label" translatable="no">Reset Page Numbering after title pages</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box8"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkLabel" id="FT_PAGE_COUNT"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Page number</property> + <accessibility> + <relation type="label-for" target="NF_RESTART_NUMBERING"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="NF_RESTART_NUMBERING"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="numeric">True</property> + <accessibility> + <relation type="labelled-by" target="FT_PAGE_COUNT"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="CB_SET_PAGE_NUMBER"> + <property name="label" translatable="no">Set Page Number for first title page</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box9"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkLabel" id="FT_PAGE_PAGES"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Page number</property> + <accessibility> + <relation type="label-for" target="NF_SET_PAGE_NUMBER"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="NF_SET_PAGE_NUMBER"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="numeric">True</property> + <accessibility> + <relation type="labelled-by" target="FT_PAGE_PAGES"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label12"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Page Numbering</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box10"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkComboBox" id="LB_PAGE_PROPERTIES"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="PB_PAGE_PROPERTIES"> + <property name="label" translatable="no">Edit...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label13"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Edit Page Properties</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="Tab2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 2</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box11"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkRadioButton" id="2"> + <property name="label" translatable="no">Line break</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="3"> + <property name="label" translatable="no">Column break</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">2</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="1"> + <property name="label" translatable="no">Page break</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">2</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Style</property> + <property name="mnemonic_widget">5</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="model">liststore1</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="7"> + <property name="label" translatable="no">Change page number</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <accessibility> + <relation type="label-for" target="8"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box12"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkSpinButton" id="8"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <accessibility> + <relation type="labelled-by" target="7"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Type</property> + </object> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="Tab3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 3</property> + </object> + <packing> + <property name="position">2</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box13"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkFrame" id="frame6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box14"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkRadioButton" id="15"> + <property name="label" translatable="no">Optimal</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="16"> + <property name="label" translatable="no">Fit width and height</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">15</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="17"> + <property name="label" translatable="no">Fit width</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">15</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="18"> + <property name="label" translatable="no">100%</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">15</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box15"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkRadioButton" id="19"> + <property name="label" translatable="no">Variable</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">15</property> + <accessibility> + <relation type="label-for" target="20"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="20"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <accessibility> + <relation type="labelled-by" target="19"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="14"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Zoom factor</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame7"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment7"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box16"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkRadioButton" id="22"> + <property name="label" translatable="no">Automatic</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="23"> + <property name="label" translatable="no">Single page</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">22</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box17"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkRadioButton" id="24"> + <property name="label" translatable="no">Columns</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + <property name="group">22</property> + <accessibility> + <relation type="label-for" target="25"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="25"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <accessibility> + <relation type="labelled-by" target="24"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment8"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">10</property> + <child> + <object class="GtkCheckButton" id="26"> + <property name="label" translatable="no">Book mode</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="21"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">View layout</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">3</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 4</property> + </object> + <packing> + <property name="position">3</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box18"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <child> + <object class="GtkFrame" id="frame8"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment9"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkTreeView" id="treeview1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">liststore2</property> + <property name="headers_visible">False</property> + <property name="search_column">0</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection3"/> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Level</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame9"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment10"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkBox" id="box19"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">10</property> + <child> + <object class="GtkBox" id="box20"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="column_spacing">10</property> + <child> + <object class="GtkLabel" id="label16"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Paragraph Style</property> + <property name="mnemonic_widget">combobox2</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label17"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Number</property> + <property name="mnemonic_widget">combobox3</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label18"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Character Style</property> + <property name="mnemonic_widget">combobox4</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label19"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Show sublevels</property> + <property name="mnemonic_widget">spinbutton2</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label20"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Separator</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">5</property> + <property name="width">2</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">6</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">7</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">8</property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment11"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">20</property> + <child> + <object class="GtkLabel" id="label21"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Before</property> + <property name="mnemonic_widget">entry2</property> + <property name="xalign">0</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">6</property> + </packing> + </child> + <child> + <object class="GtkAlignment" id="alignment12"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">20</property> + <child> + <object class="GtkLabel" id="label22"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">After</property> + <property name="mnemonic_widget">entry3</property> + <property name="xalign">0</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">7</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label23"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Start at</property> + <property name="mnemonic_widget">spinbutton3</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">8</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkDrawingArea" id="drawingarea1"> + <property name="width_request">150</property> + <property name="height_request">200</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label24"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Numbering</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">4</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 5</property> + </object> + <packing> + <property name="position">4</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box21"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <child> + <object class="GtkFrame" id="frame10"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment13"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkTreeView" id="treeview2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">liststore2</property> + <property name="headers_visible">False</property> + <property name="search_column">0</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection4"/> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label26"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Level</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame11"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment14"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="left_padding">12</property> + <child> + <object class="GtkGrid" id="grid4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">10</property> + <property name="column_spacing">10</property> + <child> + <object class="GtkLabel" id="label27"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Numbering followed by</property> + <property name="mnemonic_widget">combobox5</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label28"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Numbering Alignment</property> + <property name="mnemonic_widget">combobox6</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label29"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Aligned at</property> + <property name="mnemonic_widget">spinbutton6</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label30"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Indent at</property> + <property name="mnemonic_widget">spinbutton4</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton4"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">4</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label31"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">at</property> + <property name="mnemonic_widget">spinbutton5</property> + <property name="xalign">1</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton5"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkSpinButton" id="spinbutton6"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="combobox6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkDrawingArea" id="drawingarea2"> + <property name="width_request">300</property> + <property name="height_request">150</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">5</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button6"> + <property name="label" translatable="no">Default</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="valign">end</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">5</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label32"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Position and spacing</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="position">5</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label25"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 6</property> + </object> + <packing> + <property name="position">5</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <object class="GtkExpander" id="expander1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="resize_toplevel">True</property> + <child> + <object class="GtkGrid" id="grid5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">200</property> + <property name="column_spacing">400</property> + <child> + <object class="GtkLabel" id="label34"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">label</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label35"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">label</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label36"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">label</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label37"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">label</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label38"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">label</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label39"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">label</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">2</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label40"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">Details</property> + </object> + </child> + </object> + <packing> + <property name="position">6</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="label33"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="no">page 7</property> + </object> + <packing> + <property name="position">6</property> + <property name="tab_fill">False</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-5">ok</action-widget> + </action-widgets> + </object> +</interface> diff --git a/vcl/qa/cppunit/canvasbitmaptest.cxx b/vcl/qa/cppunit/canvasbitmaptest.cxx new file mode 100644 index 000000000..511874a0c --- /dev/null +++ b/vcl/qa/cppunit/canvasbitmaptest.cxx @@ -0,0 +1,773 @@ +/* -*- 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 incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// bootstrap stuff +#include <test/bootstrapfixture.hxx> + +#include <com/sun/star/util/Endianness.hpp> +#include <com/sun/star/rendering/ColorComponentTag.hpp> +#include <com/sun/star/rendering/ColorSpaceType.hpp> +#include <com/sun/star/rendering/RenderingIntent.hpp> +#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp> +#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp> +#include <com/sun/star/rendering/XBitmapPalette.hpp> + +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <sal/log.hxx> + +#include <vcl/canvastools.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/bitmapex.hxx> + +#include <canvasbitmap.hxx> +#include <algorithm> +#include <bitmapwriteaccess.hxx> + +using namespace ::com::sun::star; +using namespace vcl::unotools; + +namespace com::sun::star::rendering +{ + +static bool operator==( const RGBColor& rLHS, const ARGBColor& rRHS ) +{ + return rLHS.Red == rRHS.Red && rLHS.Green == rRHS.Green && rLHS.Blue == rRHS.Blue; +} + +} + +namespace +{ + +class CanvasBitmapTest : public test::BootstrapFixture +{ +public: + CanvasBitmapTest() : BootstrapFixture(true, false) {} + + void runTest(); + + CPPUNIT_TEST_SUITE(CanvasBitmapTest); + CPPUNIT_TEST(runTest); + CPPUNIT_TEST_SUITE_END(); +}; + +bool rangeCheck( const rendering::RGBColor& rColor ) +{ + return rColor.Red < 0.0 || rColor.Red > 1.0 || + rColor.Green < 0.0 || rColor.Green > 1.0 || + rColor.Blue < 0.0 || rColor.Blue > 1.0; +} + +void checkCanvasBitmap( const rtl::Reference<VclCanvasBitmap>& xBmp, + const char* msg, + int nOriginalDepth ) +{ + SAL_INFO("vcl", "Testing " << msg << ", with depth " << nOriginalDepth); + + BitmapEx aContainedBmpEx( xBmp->getBitmapEx() ); + Bitmap aContainedBmp( aContainedBmpEx.GetBitmap() ); + int nDepth = nOriginalDepth; + int extraBpp = 0; + + { + Bitmap::ScopedReadAccess pAcc( aContainedBmp ); + nDepth = pAcc->GetBitCount(); + if( pAcc->GetScanlineFormat() == ScanlineFormat::N32BitTcMask ) + extraBpp = 8; // the format has 8 unused bits + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Original bitmap size not (200,200)", + Size(200,200), aContainedBmp.GetSizePixel()); + + CPPUNIT_ASSERT_MESSAGE( "Original bitmap size via API not (200,200)", + xBmp->getSize().Width == 200 && xBmp->getSize().Height == 200); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "alpha state mismatch", + aContainedBmpEx.IsTransparent(), bool(xBmp->hasAlpha())); + + CPPUNIT_ASSERT_MESSAGE( "getScaledBitmap() failed", + xBmp->getScaledBitmap( geometry::RealSize2D(500,500), false ).is()); + + rendering::IntegerBitmapLayout aLayout; + uno::Sequence<sal_Int8> aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,1,1)); + + const sal_Int32 nExpectedBitsPerPixel( + (aContainedBmpEx.IsTransparent() ? std::max(8,nDepth)+8 : nDepth) + extraBpp); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanlines not 1", + static_cast<sal_Int32>(1), aLayout.ScanLines); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanline bytes mismatch", + static_cast<sal_Int32>((nExpectedBitsPerPixel+7)/8), aLayout.ScanLineBytes); + CPPUNIT_ASSERT_MESSAGE( "# scanline stride mismatch", + aLayout.ScanLineStride == (nExpectedBitsPerPixel+7)/8 || + aLayout.ScanLineStride == -(nExpectedBitsPerPixel+7)/8); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# plane stride not 0", + static_cast<sal_Int32>(0), aLayout.PlaneStride); + + CPPUNIT_ASSERT_MESSAGE( "Color space not there", + aLayout.ColorSpace.is()); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Palette existence does not conform to bitmap", + (nDepth <= 8), aLayout.Palette.is()); + + uno::Sequence<sal_Int8> aPixelData2 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(0,0) ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "getData and getPixel did not return same amount of data", + aPixelData.getLength(), aPixelData2.getLength()); + + aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,200,1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanlines not 1 for getPixel", + static_cast<sal_Int32>(1), aLayout.ScanLines); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanline bytes mismatch for getPixel", + static_cast<sal_Int32>((200*nExpectedBitsPerPixel+7)/8), aLayout.ScanLineBytes); + CPPUNIT_ASSERT_MESSAGE( "# scanline stride mismatch for getPixel", + aLayout.ScanLineStride == (200*nExpectedBitsPerPixel+7)/8 || + aLayout.ScanLineStride == -(200*nExpectedBitsPerPixel+7)/8); + + uno::Sequence< rendering::RGBColor > aRGBColors = xBmp->convertIntegerToRGB( aPixelData ); + uno::Sequence< rendering::ARGBColor > aARGBColors = xBmp->convertIntegerToARGB( aPixelData ); + + const rendering::RGBColor* pRGBStart ( aRGBColors.getConstArray() ); + const rendering::RGBColor* pRGBEnd ( aRGBColors.getConstArray()+aRGBColors.getLength() ); + const rendering::ARGBColor* pARGBStart( aARGBColors.getConstArray() ); + std::pair<const rendering::RGBColor*, + const rendering::ARGBColor*> aRes = std::mismatch( pRGBStart, pRGBEnd, pARGBStart ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "argb and rgb colors are not equal", + pRGBEnd, aRes.first); + + CPPUNIT_ASSERT_MESSAGE( "rgb colors are not within [0,1] range", + std::none_of(pRGBStart,pRGBEnd,&rangeCheck)); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "First pixel is not white", 1.0, pRGBStart[0].Red, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "First pixel is not white", 1.0, pRGBStart[0].Green, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "First pixel is not white", 1.0, pRGBStart[0].Blue, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "Second pixel is not opaque", 1.0, pARGBStart[1].Alpha, 1E-12); + if( aContainedBmpEx.IsTransparent() ) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE( "First pixel is not fully transparent", + 0.0, pARGBStart[0].Alpha); + } + + CPPUNIT_ASSERT_MESSAGE( "Second pixel is not black", + pRGBStart[1].Red == 0.0 && pRGBStart[1].Green == 0.0 && pRGBStart[1].Blue == 0.0); + + if( nOriginalDepth > 8 ) + { + const Color aCol(COL_GREEN); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sixth pixel is not green (red component)", + vcl::unotools::toDoubleColor(aCol.GetRed()), pRGBStart[5].Red); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sixth pixel is not green (green component)", + vcl::unotools::toDoubleColor(aCol.GetGreen()), pRGBStart[5].Green); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sixth pixel is not green (blue component)", + vcl::unotools::toDoubleColor(aCol.GetBlue()), pRGBStart[5].Blue); + } + else if( nDepth <= 8 ) + { + uno::Reference<rendering::XBitmapPalette> xPal = xBmp->getPalette(); + CPPUNIT_ASSERT_MESSAGE( "8bit or less: missing palette", + xPal.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Palette incorrect entry count", + static_cast<sal_Int32>(1 << nOriginalDepth), xPal->getNumberOfEntries()); + uno::Sequence<double> aIndex; + CPPUNIT_ASSERT_MESSAGE( "Palette is not read-only", + !xPal->setIndex(aIndex,true,0)); + CPPUNIT_ASSERT_MESSAGE( "Palette entry 0 is not opaque", + xPal->getIndex(aIndex,0)); + CPPUNIT_ASSERT_MESSAGE( "Palette has no valid color space", + xPal->getColorSpace().is()); + } + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "150th pixel is not white", 1.0, pRGBStart[150].Red, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "150th pixel is not white", 1.0, pRGBStart[150].Green, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "150th pixel is not white", 1.0, pRGBStart[150].Blue, 1E-12); + + if( nOriginalDepth <= 8 ) + return; + + uno::Sequence<rendering::ARGBColor> aARGBColor(1); + uno::Sequence<rendering::RGBColor> aRGBColor(1); + uno::Sequence<sal_Int8> aPixel3, aPixel4; + + const Color aCol(COL_GREEN); + aARGBColor[0].Red = vcl::unotools::toDoubleColor(aCol.GetRed()); + aARGBColor[0].Green = vcl::unotools::toDoubleColor(aCol.GetGreen()); + aARGBColor[0].Blue = vcl::unotools::toDoubleColor(aCol.GetBlue()); + aARGBColor[0].Alpha = 1.0; + + aRGBColor[0].Red = vcl::unotools::toDoubleColor(aCol.GetRed()); + aRGBColor[0].Green = vcl::unotools::toDoubleColor(aCol.GetGreen()); + aRGBColor[0].Blue = vcl::unotools::toDoubleColor(aCol.GetBlue()); + + aPixel3 = xBmp->convertIntegerFromARGB( aARGBColor ); + aPixel4 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(5,0) ); + CPPUNIT_ASSERT_MESSAGE( "Green pixel from bitmap mismatch with manually converted green pixel", + bool(aPixel3 == aPixel4)); + + if( !aContainedBmpEx.IsTransparent() ) + { + aPixel3 = xBmp->convertIntegerFromRGB( aRGBColor ); + CPPUNIT_ASSERT_MESSAGE( "Green pixel from bitmap mismatch with manually RGB-converted green pixel", + bool(aPixel3 == aPixel4)); + } + +} + +class TestBitmap : public cppu::WeakImplHelper< rendering::XIntegerReadOnlyBitmap, + rendering::XBitmapPalette, + rendering::XIntegerBitmapColorSpace > +{ +private: + geometry::IntegerSize2D maSize; + uno::Sequence<sal_Int8> maComponentTags; + uno::Sequence<sal_Int32> maComponentBitCounts; + rendering::IntegerBitmapLayout maLayout; + const sal_Int32 mnBitsPerPixel; + + // XBitmap + virtual geometry::IntegerSize2D SAL_CALL getSize() override { return maSize; } + virtual sal_Bool SAL_CALL hasAlpha( ) override { return mnBitsPerPixel != 8; } + virtual uno::Reference< rendering::XBitmap > SAL_CALL getScaledBitmap( const geometry::RealSize2D&, + sal_Bool ) override { return this; } + + // XIntegerReadOnlyBitmap + virtual uno::Sequence< ::sal_Int8 > SAL_CALL getData( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) override + { + CPPUNIT_ASSERT_MESSAGE( "X1 out of bounds", rect.X1 >= 0 ); + CPPUNIT_ASSERT_MESSAGE( "Y1 out of bounds", rect.Y1 >= 0 ); + CPPUNIT_ASSERT_MESSAGE( "X2 out of bounds", rect.X2 <= maSize.Width ); + CPPUNIT_ASSERT_MESSAGE( "Y2 out of bounds", rect.Y2 <= maSize.Height ); + + bitmapLayout = getMemoryLayout(); + + const sal_Int32 nWidth = rect.X2-rect.X1; + const sal_Int32 nHeight = rect.Y2-rect.Y1; + const sal_Int32 nScanlineLen = (nWidth * mnBitsPerPixel + 7)/8; + uno::Sequence<sal_Int8> aRes( nScanlineLen * nHeight ); + sal_Int8* pOut = aRes.getArray(); + + bitmapLayout.ScanLines = nHeight; + bitmapLayout.ScanLineBytes = + bitmapLayout.ScanLineStride= nScanlineLen; + + if( mnBitsPerPixel == 8 ) + { + for( sal_Int32 y=0; y<nHeight; ++y ) + { + for( sal_Int32 x=0; x<nWidth; ++x ) + pOut[ y*nScanlineLen + x ] = sal_Int8(x); + } + } + else + { + for( sal_Int32 y=0; y<nHeight; ++y ) + { + for( sal_Int32 x=0; x<nWidth; ++x ) + { + pOut[ y*nScanlineLen + 4*x ] = sal_Int8(rect.X1); + pOut[ y*nScanlineLen + 4*x + 1 ] = sal_Int8(rect.Y2); + pOut[ y*nScanlineLen + 4*x + 2 ] = sal_Int8(x); + pOut[ y*nScanlineLen + 4*x + 3 ] = sal_Int8(rect.Y1); + } + } + } + + return aRes; + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL getPixel( rendering::IntegerBitmapLayout&, + const geometry::IntegerPoint2D& ) override + { + CPPUNIT_ASSERT_MESSAGE("getPixel: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + /// @throws uno::RuntimeException + uno::Reference< rendering::XBitmapPalette > getPalette( ) + { + uno::Reference< XBitmapPalette > aRet; + if( mnBitsPerPixel == 8 ) + aRet.set(this); + return aRet; + } + + virtual rendering::IntegerBitmapLayout SAL_CALL getMemoryLayout( ) override + { + rendering::IntegerBitmapLayout aLayout( maLayout ); + + const sal_Int32 nScanlineLen = (maSize.Width * mnBitsPerPixel + 7)/8; + + aLayout.ScanLines = maSize.Height; + aLayout.ScanLineBytes = + aLayout.ScanLineStride= nScanlineLen; + aLayout.Palette = getPalette(); + aLayout.ColorSpace.set( this ); + + return aLayout; + } + + // XBitmapPalette + virtual sal_Int32 SAL_CALL getNumberOfEntries() override + { + CPPUNIT_ASSERT_MESSAGE( "Got palette getNumberOfEntries interface call without handing out palette", + getPalette().is() ); + + return 255; + } + + virtual sal_Bool SAL_CALL getIndex( uno::Sequence< double >& entry, + ::sal_Int32 nIndex ) override + { + CPPUNIT_ASSERT_MESSAGE( "Got palette getIndex interface call without handing out palette", + getPalette().is() ); + CPPUNIT_ASSERT_MESSAGE( "getIndex: index out of range", + nIndex >= 0 && nIndex < 256 ); + entry = colorToStdColorSpaceSequence( + Color(sal_uInt8(nIndex), + sal_uInt8(nIndex), + sal_uInt8(nIndex)) ); + + return true; // no palette transparency here. + } + + virtual sal_Bool SAL_CALL setIndex( const uno::Sequence< double >&, + sal_Bool, + ::sal_Int32 nIndex ) override + { + CPPUNIT_ASSERT_MESSAGE( "Got palette setIndex interface call without handing out palette", + getPalette().is()); + CPPUNIT_ASSERT_MESSAGE( "setIndex: index out of range", + nIndex >= 0 && nIndex < 256); + return false; + } + + struct PaletteColorSpaceHolder: public rtl::StaticWithInit<uno::Reference<rendering::XColorSpace>, + PaletteColorSpaceHolder> + { + uno::Reference<rendering::XColorSpace> operator()() + { + return vcl::unotools::createStandardColorSpace(); + } + }; + + virtual uno::Reference< rendering::XColorSpace > SAL_CALL getColorSpace( ) override + { + // this is the method from XBitmapPalette. Return palette color + // space here + return PaletteColorSpaceHolder::get(); + } + + // XIntegerBitmapColorSpace + virtual ::sal_Int8 SAL_CALL getType( ) override + { + return rendering::ColorSpaceType::RGB; + } + + virtual uno::Sequence< sal_Int8 > SAL_CALL getComponentTags( ) override + { + return maComponentTags; + } + + virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override + { + return rendering::RenderingIntent::PERCEPTUAL; + } + + virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties() override + { + CPPUNIT_ASSERT_MESSAGE("getProperties: method not implemented", false ); + return uno::Sequence< ::beans::PropertyValue >(); + } + + virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >&, + const uno::Reference< rendering::XColorSpace >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertColorSpace: method not implemented", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToRGB: method not implemented", false); + return uno::Sequence< rendering::RGBColor >(); + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToARGB: method not implemented", false); + return uno::Sequence< rendering::ARGBColor >(); + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToPARGB: method not implemented", false); + return uno::Sequence< rendering::ARGBColor >(); + } + + virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromRGB: method not implemented", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromARGB: this method is not expected to be called!", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromPARGB: this method is not expected to be called!", false); + return uno::Sequence< double >(); + } + + virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override + { + return mnBitsPerPixel; + } + + virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override + { + return maComponentBitCounts; + } + + virtual ::sal_Int8 SAL_CALL getEndianness( ) override + { + return util::Endianness::LITTLE; + } + + virtual uno::Sequence< double > SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& , + const uno::Reference< rendering::XColorSpace >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromIntegerColorSpace: method not implemented", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& , + const uno::Reference< rendering::XIntegerBitmapColorSpace >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToIntegerColorSpace: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override + { + const uno::Sequence< rendering::ARGBColor > aTemp( convertIntegerToARGB(deviceColor) ); + uno::Sequence< rendering::RGBColor > aRes( aTemp.getLength() ); + std::transform(aTemp.begin(), aTemp.end(), aRes.begin(), + [](const rendering::ARGBColor& rColor) { + return rendering::RGBColor(rColor.Red, + rColor.Green, + rColor.Blue); + }); + + return aRes; + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override + { + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nBytesPerPixel(mnBitsPerPixel == 8 ? 1 : 4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("number of channels no multiple of pixel element count", + 0, static_cast<int>(nLen%nBytesPerPixel)); + + uno::Sequence< rendering::ARGBColor > aRes( nLen / nBytesPerPixel ); + + if( getPalette().is() ) + { + std::transform(deviceColor.begin(), deviceColor.end(), aRes.begin(), + [](sal_Int8 nIn) { + auto fColor = vcl::unotools::toDoubleColor(nIn); + return rendering::ARGBColor(1.0, fColor, fColor, fColor); + }); + } + else + { + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor( + vcl::unotools::toDoubleColor(deviceColor[i+3]), + vcl::unotools::toDoubleColor(deviceColor[i+0]), + vcl::unotools::toDoubleColor(deviceColor[i+1]), + vcl::unotools::toDoubleColor(deviceColor[i+2])); + } + } + + return aRes; + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( + const uno::Sequence< ::sal_Int8 >& deviceColor) override + { + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nBytesPerPixel(mnBitsPerPixel == 8 ? 1 : 4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("number of channels no multiple of pixel element count", + 0, static_cast<int>(nLen%nBytesPerPixel)); + + uno::Sequence< rendering::ARGBColor > aRes( nLen / nBytesPerPixel ); + + if( getPalette().is() ) + { + std::transform(deviceColor.begin(), deviceColor.end(), aRes.begin(), + [](sal_Int8 nIn) { + auto fColor = vcl::unotools::toDoubleColor(nIn); + return rendering::ARGBColor(1.0, fColor, fColor, fColor); + }); + } + else + { + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + const double fAlpha=vcl::unotools::toDoubleColor(deviceColor[i+3]); + *pOut++ = rendering::ARGBColor( + fAlpha, + fAlpha*vcl::unotools::toDoubleColor(deviceColor[i+0]), + fAlpha*vcl::unotools::toDoubleColor(deviceColor[i+1]), + fAlpha*vcl::unotools::toDoubleColor(deviceColor[i+2])); + } + } + + return aRes; + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( + const uno::Sequence< rendering::RGBColor >&) override + { + CPPUNIT_ASSERT_MESSAGE("convertIntegerFromRGB: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertIntegerFromARGB: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertIntegerFromPARGB: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + +public: + TestBitmap( const geometry::IntegerSize2D& rSize, bool bPalette ) : + maSize(rSize), + maComponentTags(), + maComponentBitCounts(), + maLayout(), + mnBitsPerPixel( bPalette ? 8 : 32 ) + { + if( bPalette ) + { + maComponentTags.realloc(1); + maComponentTags[0] = rendering::ColorComponentTag::INDEX; + + maComponentBitCounts.realloc(1); + maComponentBitCounts[0] = 8; + } + else + { + maComponentTags.realloc(4); + sal_Int8* pTags = maComponentTags.getArray(); + pTags[0] = rendering::ColorComponentTag::RGB_BLUE; + pTags[1] = rendering::ColorComponentTag::RGB_GREEN; + pTags[2] = rendering::ColorComponentTag::RGB_RED; + pTags[3] = rendering::ColorComponentTag::ALPHA; + + maComponentBitCounts.realloc(4); + sal_Int32* pCounts = maComponentBitCounts.getArray(); + pCounts[0] = 8; + pCounts[1] = 8; + pCounts[2] = 8; + pCounts[3] = 8; + } + + maLayout.ScanLines = 0; + maLayout.ScanLineBytes = 0; + maLayout.ScanLineStride = 0; + maLayout.PlaneStride = 0; + maLayout.ColorSpace.clear(); + maLayout.Palette.clear(); + maLayout.IsMsbFirst = false; + } +}; + +void CanvasBitmapTest::runTest() +{ + static const sal_Int8 lcl_depths[]={1,4,8,24}; + + // Testing VclCanvasBitmap wrapper + + for( size_t i=0; i<SAL_N_ELEMENTS(lcl_depths); ++i ) + { + const sal_Int8 nDepth( lcl_depths[i] ); + Bitmap aBitmap(Size(200,200),nDepth); + aBitmap.Erase(COL_WHITE); + { + BitmapScopedWriteAccess pAcc(aBitmap); + if( pAcc.get() ) + { + BitmapColor aBlack(0); + BitmapColor aWhite(0); + if( pAcc->HasPalette() ) + { + aBlack.SetIndex( sal::static_int_cast<sal_Int8>(pAcc->GetBestPaletteIndex(BitmapColor(0,0,0))) ); + aWhite.SetIndex( sal::static_int_cast<sal_Int8>(pAcc->GetBestPaletteIndex(BitmapColor(255,255,255))) ); + } + else + { + aBlack = COL_BLACK; + aWhite = COL_WHITE; + } + pAcc->SetFillColor(COL_GREEN); + pAcc->FillRect(tools::Rectangle(0,0,100,100)); + pAcc->SetPixel(0,0,aWhite); + pAcc->SetPixel(0,1,aBlack); + pAcc->SetPixel(0,2,aWhite); + } + } + + rtl::Reference<VclCanvasBitmap> xBmp( new VclCanvasBitmap(BitmapEx(aBitmap)) ); + + checkCanvasBitmap( xBmp, "single bitmap", nDepth ); + + Bitmap aMask(Size(200,200),1); + aMask.Erase(COL_WHITE); + { + BitmapScopedWriteAccess pAcc(aMask); + if( pAcc.get() ) + { + pAcc->SetFillColor(COL_BLACK); + pAcc->FillRect(tools::Rectangle(0,0,100,100)); + pAcc->SetPixel(0,0,BitmapColor(1)); + pAcc->SetPixel(0,1,BitmapColor(0)); + pAcc->SetPixel(0,2,BitmapColor(1)); + } + } + + xBmp.set( new VclCanvasBitmap(BitmapEx(aBitmap,aMask)) ); + + checkCanvasBitmap( xBmp, "masked bitmap", nDepth ); + + AlphaMask aAlpha(Size(200,200)); + aAlpha.Erase(255); + { + BitmapWriteAccess* pAcc = aAlpha.AcquireWriteAccess(); + if( pAcc ) + { + pAcc->SetFillColor(COL_BLACK); + pAcc->FillRect(tools::Rectangle(0,0,100,100)); + pAcc->SetPixel(0,0,BitmapColor(255)); + pAcc->SetPixel(0,1,BitmapColor(0)); + pAcc->SetPixel(0,2,BitmapColor(255)); + aAlpha.ReleaseAccess(pAcc); + } + } + + xBmp.set( new VclCanvasBitmap(BitmapEx(aBitmap,aAlpha)) ); + + checkCanvasBitmap( xBmp, "alpha bitmap", nDepth ); + } + + // Testing XBitmap import + + uno::Reference< rendering::XIntegerReadOnlyBitmap > xTestBmp( + new TestBitmap( geometry::IntegerSize2D(10,10), true )); + + BitmapEx aBmp = vcl::unotools::bitmapExFromXBitmap(xTestBmp); + CPPUNIT_ASSERT_MESSAGE( "Palette bitmap is transparent", + !aBmp.IsTransparent()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap does not have size (10,10)", + Size(10,10), aBmp.GetSizePixel()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap does not have bitcount of 8", + static_cast<sal_uInt16>(8), aBmp.GetBitCount()); + { + Bitmap aBitmap = aBmp.GetBitmap(); + BitmapReadAccess* pBmpAcc = aBitmap.AcquireReadAccess(); + + CPPUNIT_ASSERT_MESSAGE( "Bitmap has invalid BitmapReadAccess", + pBmpAcc ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect content", + BitmapColor(0), pBmpAcc->GetPixel(0,0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect content", + BitmapColor(2), pBmpAcc->GetPixel(2,2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) incorrect content", + BitmapColor(9), pBmpAcc->GetPixel(2,9)); + + Bitmap::ReleaseAccess(pBmpAcc); + } + + xTestBmp.set( new TestBitmap( geometry::IntegerSize2D(10,10), false )); + + aBmp = vcl::unotools::bitmapExFromXBitmap(xTestBmp); + CPPUNIT_ASSERT_MESSAGE( "Palette bitmap is not transparent", + aBmp.IsTransparent()); + CPPUNIT_ASSERT_MESSAGE( "Palette bitmap has no alpha", + aBmp.IsAlpha()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap does not have size (10,10)", + Size(10,10), aBmp.GetSizePixel()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap has bitcount of 24", + static_cast<sal_uInt16>(24), aBmp.GetBitCount()); + { + Bitmap aBitmap = aBmp.GetBitmap(); + BitmapReadAccess* pBmpAcc = aBitmap.AcquireReadAccess(); + BitmapReadAccess* pAlphaAcc = aBmp.GetAlpha().AcquireReadAccess(); + + CPPUNIT_ASSERT_MESSAGE( "Bitmap has invalid BitmapReadAccess", + pBmpAcc); + CPPUNIT_ASSERT_MESSAGE( "Bitmap has invalid alpha BitmapReadAccess", + pAlphaAcc); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect content", + BitmapColor(0,1,0), pBmpAcc->GetPixel(0,0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect alpha content", + BitmapColor(255), pAlphaAcc->GetPixel(0,0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect content", + BitmapColor(0,3,2), pBmpAcc->GetPixel(2,2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect alpha content", + BitmapColor(253), pAlphaAcc->GetPixel(2,2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) incorrect content", + BitmapColor(0,3,9), pBmpAcc->GetPixel(2,9)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) correct alpha content", + BitmapColor(253), pAlphaAcc->GetPixel(2,9)); + + aBmp.GetAlpha().ReleaseAccess(pAlphaAcc); + Bitmap::ReleaseAccess(pBmpAcc); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(CanvasBitmapTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx new file mode 100644 index 000000000..85a5b3991 --- /dev/null +++ b/vcl/qa/cppunit/complextext.cxx @@ -0,0 +1,170 @@ +/* -*- 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 <ostream> +#include <vector> + +#if HAVE_MORE_FONTS +// must be declared before inclusion of test/bootstrapfixture.hxx +static std::ostream& operator<<(std::ostream& rStream, const std::vector<long>& rVec); +#endif +#include <test/bootstrapfixture.hxx> + +#include <vcl/wrkwin.hxx> +#include <vcl/virdev.hxx> +// workaround MSVC2015 issue with std::unique_ptr +#include <sallayout.hxx> +#include <salgdi.hxx> + +#if HAVE_MORE_FONTS +static std::ostream& operator<<(std::ostream& rStream, const std::vector<long>& rVec) +{ + rStream << "{ "; + for (size_t i = 0; i < rVec.size() - 1; i++) + rStream << rVec[i] << ", "; + rStream << rVec.back(); + rStream << " }"; + return rStream; +} +#endif + +class VclComplexTextTest : public test::BootstrapFixture +{ +public: + VclComplexTextTest() : BootstrapFixture(true, false) {} + + /// Play with font measuring etc. + void testArabic(); + void testKashida(); + void testTdf95650(); // Windows-only issue + + CPPUNIT_TEST_SUITE(VclComplexTextTest); + CPPUNIT_TEST(testArabic); + CPPUNIT_TEST(testKashida); + CPPUNIT_TEST(testTdf95650); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclComplexTextTest::testArabic() +{ +#if HAVE_MORE_FONTS + const unsigned char pOneTwoThreeUTF8[] = { + 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90, + 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8, + 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9, + 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7, + 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00 + }; + OUString aOneTwoThree( reinterpret_cast<char const *>(pOneTwoThreeUTF8), + SAL_N_ELEMENTS( pOneTwoThreeUTF8 ) - 1, + RTL_TEXTENCODING_UTF8 ); + ScopedVclPtrInstance<WorkWindow> pWin(static_cast<vcl::Window *>(nullptr)); + CPPUNIT_ASSERT( pWin ); + + vcl::Font aFont("DejaVu Sans", "Book", Size(0, 12)); + + OutputDevice *pOutDev = pWin.get(); + pOutDev->SetFont( aFont ); + + // absolute character widths AKA text array. + std::vector<long> aRefCharWidths {6, 9, 16, 16, 22, 22, 26, 29, 32, 32, + 36, 40, 49, 53, 56, 63, 63, 66, 72, 72}; + std::vector<long> aCharWidths(aOneTwoThree.getLength(), 0); + long nTextWidth = pOutDev->GetTextArray(aOneTwoThree, aCharWidths.data()); + + CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths); + // this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73 + CPPUNIT_ASSERT_EQUAL(72L, nTextWidth); + CPPUNIT_ASSERT_EQUAL(nTextWidth, aCharWidths.back()); + + // text advance width and line height + CPPUNIT_ASSERT_EQUAL(72L, pOutDev->GetTextWidth(aOneTwoThree)); + CPPUNIT_ASSERT_EQUAL(14L, pOutDev->GetTextHeight()); + + // exact bounding rectangle, not essentially the same as text width/height + tools::Rectangle aBoundRect, aTestRect( 0, 1, 71, 15 ); + pOutDev->GetTextBoundRect(aBoundRect, aOneTwoThree); + CPPUNIT_ASSERT_EQUAL(aTestRect, aBoundRect); + +#if 0 + // FIXME: This seems to be wishful thinking, GetTextRect() does not take + // rotation into account. + + // normal orientation + tools::Rectangle aInput; + tools::Rectangle aRect = pOutDev->GetTextRect( aInput, aOneTwoThree ); + + // now rotate 270 degrees + vcl::Font aRotated( aFont ); + aRotated.SetOrientation( 2700 ); + pOutDev->SetFont( aRotated ); + tools::Rectangle aRectRot = pOutDev->GetTextRect( aInput, aOneTwoThree ); + + // Check that we did do the rotation... + fprintf( stderr, "%ld %ld %ld %ld\n", + aRect.GetWidth(), aRect.GetHeight(), + aRectRot.GetWidth(), aRectRot.GetHeight() ); + CPPUNIT_ASSERT( aRectRot.GetWidth() == aRect.GetHeight() ); + CPPUNIT_ASSERT( aRectRot.GetHeight() == aRect.GetWidth() ); +#endif +#endif +} + +void VclComplexTextTest::testKashida() +{ +#if HAVE_MORE_FONTS + // Cache the glyph list of some Arabic text. + ScopedVclPtrInstance<VirtualDevice> pOutputDevice; + auto aText + = OUString::fromUtf8(u8"ï»Šï»¨ïº»ïº ïºŽï» ï»“ï»®ïº´ï»“ï»ïº ï»Šï»¨ïº»ïº ï»’ï»Ÿïº°ï»³ ïººï» ïº‘. ﺖﺘﻛﻮﻧ ﺎﻟﺩï»ïºïº“ ﺎﻟïºïºŽïº’ﻋﺓ ﻢﻧ ١٥ ﻊﻨﺻïºïº."); + std::unique_ptr<SalLayout> pLayout = pOutputDevice->ImplLayout( + aText, 0, aText.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly); + const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs(); + if (!pGlyphs) + // Failed in some non-interesting ways. + return; + SalLayoutGlyphs aGlyphs = *pGlyphs; + + // Now lay it out using the cached glyph list. + ImplLayoutArgs aLayoutArgs(aText, 0, aText.getLength(), SalLayoutFlags::NONE, + pOutputDevice->GetFont().GetLanguageTag(), nullptr); + pLayout = pOutputDevice->GetGraphics()->GetTextLayout(0); + CPPUNIT_ASSERT(pLayout->LayoutText(aLayoutArgs, &aGlyphs)); + + // Without the accompanying fix in place, this test would have failed with 'assertion failed'. + // The kashida justification flag was lost when going via the glyph cache. + CPPUNIT_ASSERT(aLayoutArgs.mnFlags & SalLayoutFlags::KashidaJustification); +#endif +} + +void VclComplexTextTest::testTdf95650() +{ + const sal_Unicode pTxt[] = { + 0x0131, 0x0302, 0x0504, 0x4E44, 0x3031, 0x3030, 0x3531, 0x2D30, + 0x3037, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E, 0x072E, 0x100A, + 0x0D11, 0x1312, 0x0105, 0x020A, 0x0512, 0x1403, 0x030C, 0x1528, + 0x2931, 0x632E, 0x7074, 0x0D20, 0x0E0A, 0x100A, 0xF00D, 0x0D20, + 0x030A, 0x0C0B, 0x20E0, 0x0A0D + }; + OUString aTxt(pTxt, SAL_N_ELEMENTS(pTxt) - 1); + ScopedVclPtrInstance<WorkWindow> pWin(static_cast<vcl::Window *>(nullptr)); + CPPUNIT_ASSERT(pWin); + + OutputDevice *pOutDev = pWin.get(); + // Check that the following executes without failing assertion + pOutDev->ImplLayout(aTxt, 9, 1, Point(), 0, nullptr, SalLayoutFlags::BiDiRtl); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclComplexTextTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/data/123_Numbers.gif b/vcl/qa/cppunit/data/123_Numbers.gif Binary files differnew file mode 100644 index 000000000..2e47e28cb --- /dev/null +++ b/vcl/qa/cppunit/data/123_Numbers.gif diff --git a/vcl/qa/cppunit/data/Exif1.jpg b/vcl/qa/cppunit/data/Exif1.jpg Binary files differnew file mode 100644 index 000000000..a81425e75 --- /dev/null +++ b/vcl/qa/cppunit/data/Exif1.jpg diff --git a/vcl/qa/cppunit/data/Exif1_090CW.jpg b/vcl/qa/cppunit/data/Exif1_090CW.jpg Binary files differnew file mode 100644 index 000000000..bb8a81a16 --- /dev/null +++ b/vcl/qa/cppunit/data/Exif1_090CW.jpg diff --git a/vcl/qa/cppunit/data/Exif1_180.jpg b/vcl/qa/cppunit/data/Exif1_180.jpg Binary files differnew file mode 100644 index 000000000..b18b70f13 --- /dev/null +++ b/vcl/qa/cppunit/data/Exif1_180.jpg diff --git a/vcl/qa/cppunit/data/Exif1_270CW.jpg b/vcl/qa/cppunit/data/Exif1_270CW.jpg Binary files differnew file mode 100644 index 000000000..f10764114 --- /dev/null +++ b/vcl/qa/cppunit/data/Exif1_270CW.jpg diff --git a/vcl/qa/cppunit/data/SimpleExample.svg b/vcl/qa/cppunit/data/SimpleExample.svg new file mode 100644 index 000000000..6890b5456 --- /dev/null +++ b/vcl/qa/cppunit/data/SimpleExample.svg @@ -0,0 +1,4 @@ +<svg width="50" height="50" version="1.1" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"> + <rect x="0" y="0" width="50" height="50" fill="#aaaaaa"/> + <rect x="5" y="5" width="40" height="40" fill="#ff44aa"/> +</svg> diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.bmp b/vcl/qa/cppunit/data/TypeDetectionExample.bmp Binary files differnew file mode 100644 index 000000000..5197e42a7 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.bmp diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.eps b/vcl/qa/cppunit/data/TypeDetectionExample.eps new file mode 100644 index 000000000..7f0db47bc --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat May 2 14:29:27 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 1 7 8 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 1 7 8 +%%EndPageSetup +q 0 1 7 7 rectclip +1 0 0 -1 0 8 cm q +0.956863 0.831373 0.266667 rg +3.75 0.75 m 5.41 0.75 6.75 2.09 6.75 3.75 c 6.75 5.41 5.41 6.75 3.75 6.75 + c 2.09 6.75 0.75 5.41 0.75 3.75 c 0.75 2.09 2.09 0.75 3.75 0.75 c h +3.75 0.75 m f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.gif b/vcl/qa/cppunit/data/TypeDetectionExample.gif Binary files differnew file mode 100644 index 000000000..b33eb4f90 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.gif diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.jpg b/vcl/qa/cppunit/data/TypeDetectionExample.jpg Binary files differnew file mode 100644 index 000000000..b8436eaa1 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.jpg diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.met b/vcl/qa/cppunit/data/TypeDetectionExample.met Binary files differnew file mode 100644 index 000000000..7635e841f --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.met diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.pcx b/vcl/qa/cppunit/data/TypeDetectionExample.pcx Binary files differnew file mode 100644 index 000000000..639323455 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.pcx diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.pdf b/vcl/qa/cppunit/data/TypeDetectionExample.pdf Binary files differnew file mode 100644 index 000000000..b68bff5e1 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.pdf diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.png b/vcl/qa/cppunit/data/TypeDetectionExample.png Binary files differnew file mode 100644 index 000000000..f73f5fd74 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.png diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.psd b/vcl/qa/cppunit/data/TypeDetectionExample.psd Binary files differnew file mode 100644 index 000000000..8282b14fd --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.psd diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.svg b/vcl/qa/cppunit/data/TypeDetectionExample.svg new file mode 100644 index 000000000..e23e44c23 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.svg @@ -0,0 +1,4 @@ +<svg width="10" height="10" version="1.1" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"> + <rect x="0" y="0" width="10" height="10" fill="#ffffff"/> + <rect x="1" y="1" width="8" height="8" fill="#72d1c8"/> +</svg> diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.svgz b/vcl/qa/cppunit/data/TypeDetectionExample.svgz Binary files differnew file mode 100644 index 000000000..17c1bcc3c --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.svgz diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.tga b/vcl/qa/cppunit/data/TypeDetectionExample.tga Binary files differnew file mode 100644 index 000000000..870c88b10 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.tga diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.tif b/vcl/qa/cppunit/data/TypeDetectionExample.tif Binary files differnew file mode 100644 index 000000000..dc74dc958 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.tif diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.wmf b/vcl/qa/cppunit/data/TypeDetectionExample.wmf Binary files differnew file mode 100644 index 000000000..7ed706928 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.wmf diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.xbm b/vcl/qa/cppunit/data/TypeDetectionExample.xbm new file mode 100644 index 000000000..b40d1a45e --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.xbm @@ -0,0 +1,5 @@ +#define sample_width 10 +#define sample_height 10 +static unsigned char sample_bits[] = { + 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, + 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00 }; diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.xpm b/vcl/qa/cppunit/data/TypeDetectionExample.xpm new file mode 100644 index 000000000..7b9b94359 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.xpm @@ -0,0 +1,15 @@ +/* XPM */ +static char * sample_xpm[] = { +"10 10 2 1", +" c #FFFFFF", +". c #72D1C8", +" ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" "}; diff --git a/vcl/qa/cppunit/data/inch-size.emf b/vcl/qa/cppunit/data/inch-size.emf Binary files differnew file mode 100644 index 000000000..ac5a1b805 --- /dev/null +++ b/vcl/qa/cppunit/data/inch-size.emf diff --git a/vcl/qa/cppunit/data/testBasicMorphology.png b/vcl/qa/cppunit/data/testBasicMorphology.png Binary files differnew file mode 100644 index 000000000..5db565779 --- /dev/null +++ b/vcl/qa/cppunit/data/testBasicMorphology.png diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png Binary files differnew file mode 100644 index 000000000..ba335bab3 --- /dev/null +++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png Binary files differnew file mode 100644 index 000000000..3b10a949a --- /dev/null +++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png Binary files differnew file mode 100644 index 000000000..30d90757e --- /dev/null +++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png Binary files differnew file mode 100644 index 000000000..a506577da --- /dev/null +++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png diff --git a/vcl/qa/cppunit/dndtest.cxx b/vcl/qa/cppunit/dndtest.cxx new file mode 100644 index 000000000..37629239b --- /dev/null +++ b/vcl/qa/cppunit/dndtest.cxx @@ -0,0 +1,311 @@ +/* -*- 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 incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <unotest/filters-test.hxx> +#include <test/bootstrapfixture.hxx> + +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/lstbox.hxx> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> +#include <com/sun/star/datatransfer/dnd/XDragSourceListener.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp> +#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp> +#include <com/sun/star/datatransfer/dnd/XDragGestureListener.hpp> + +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::datatransfer::dnd; + +class MyWin : public WorkWindow +{ +public: + MyWin( vcl::Window* pParent, WinBits nWinStyle ); + + void MouseMove( const MouseEvent& rMEvt ); + void MouseButtonDown( const MouseEvent& rMEvt ); + void MouseButtonUp( const MouseEvent& rMEvt ); + void KeyInput( const KeyEvent& rKEvt ); + void KeyUp( const KeyEvent& rKEvt ); + void Paint( const Rectangle& rRect ); + void Resize(); +}; + +class MyDragAndDropListener: public ::cppu::WeakImplHelper < XDropTargetListener, XDragGestureListener, XDragSourceListener > +{ + vcl::Window * m_pWindow; + +public: + + explicit MyDragAndDropListener( vcl::Window * pWindow ) : m_pWindow( pWindow ) {}; + + virtual void SAL_CALL dragGestureRecognized( const DragGestureEvent& dge ) throw(RuntimeException); + virtual void SAL_CALL drop( const DropTargetDropEvent& dtde ) throw(RuntimeException); + virtual void SAL_CALL dragEnter( const DropTargetDragEnterEvent& dtde ) throw(RuntimeException); + virtual void SAL_CALL dragExit( const DropTargetEvent& dte ) throw(RuntimeException); + virtual void SAL_CALL dragOver( const DropTargetDragEvent& dtde ) throw(RuntimeException); + virtual void SAL_CALL dropActionChanged( const DropTargetDragEvent& dtde ) throw(RuntimeException); + virtual void SAL_CALL dragDropEnd( const DragSourceDropEvent& dsde ) throw(RuntimeException); + virtual void SAL_CALL dragEnter( const DragSourceDragEvent& dsdee ) throw(RuntimeException); + virtual void SAL_CALL dragExit( const DragSourceEvent& dse ) throw(RuntimeException); + virtual void SAL_CALL dragOver( const DragSourceDragEvent& dsde ) throw(RuntimeException); + virtual void SAL_CALL dropActionChanged( const DragSourceDragEvent& dsde ) throw(RuntimeException); + virtual void SAL_CALL disposing( const EventObject& eo ) throw(RuntimeException); +}; + +class MyInfoBox : public InfoBox +{ + +public: + + explicit MyInfoBox( vcl::Window* pParent ); +}; + +class MyListBox : public ListBox +{ + +public: + + explicit MyListBox( vcl::Window* pParent ); +}; + +class StringTransferable : public ::cppu::WeakImplHelper< XTransferable > +{ + const OUString m_aData; + Sequence< DataFlavor > m_aFlavorList; + +public: + explicit StringTransferable( const OUString& rString ) : m_aData( rString ), m_aFlavorList( 1 ) + { + DataFlavor df; + + df.MimeType = "text/plain;charset=utf-16"; + df.DataType = cppu::UnoType<OUString>::get(); + + m_aFlavorList[0] = df; + }; + + virtual Any SAL_CALL getTransferData( const DataFlavor& aFlavor ) throw(UnsupportedFlavorException, IOException, RuntimeException); + virtual Sequence< DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(RuntimeException); + virtual bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException); +}; + +class VclDnDTest : public test::BootstrapFixture +{ +public: + VclDnDTest() : BootstrapFixture(true, false) {} + + /// Play with drag and drop + void testDnD(); + + CPPUNIT_TEST_SUITE(VclDnDTest); + CPPUNIT_TEST(testDnD); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclDnDTest::testDnD() +{ + MyWin aMainWin( NULL, WB_APP | WB_STDWORK ); + aMainWin.SetText( OUString( "Drag And Drop - Workbench" ) ); + aMainWin.Show(); + + // test the clipboard code + Reference< XClipboard > xClipboard = aMainWin.GetClipboard(); + CPPUNIT_ASSERT_MESSAGE("System clipboard not available", + xClipboard.is()); + + MyInfoBox aInfoBox( &aMainWin ); + aInfoBox.Execute(); + + MyListBox aListBox( &aMainWin ); + aListBox.setPosSizePixel( 10, 10, 100, 100 ); + aListBox.InsertEntry( OUString("TestItem")); + aListBox.Show(); +} + +MyWin::MyWin( vcl::Window* pParent, WinBits nWinStyle ) : + WorkWindow( pParent, nWinStyle ) +{ + Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this ); + + Reference< XDropTarget > xDropTarget = GetDropTarget(); + if( xDropTarget.is() ) + { + xDropTarget->addDropTargetListener( xListener ); + xDropTarget->setActive( true ); + } + + Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer(); + if( xRecognizer.is() ) + xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) ); +} + +void MyWin::MouseMove( const MouseEvent& rMEvt ) +{ + WorkWindow::MouseMove( rMEvt ); +} + +void MyWin::MouseButtonDown( const MouseEvent& rMEvt ) +{ + WorkWindow::MouseButtonDown( rMEvt ); +} + +void MyWin::MouseButtonUp( const MouseEvent& rMEvt ) +{ + WorkWindow::MouseButtonUp( rMEvt ); +} + +void MyWin::KeyInput( const KeyEvent& rKEvt ) +{ + WorkWindow::KeyInput( rKEvt ); +} + +void MyWin::KeyUp( const KeyEvent& rKEvt ) +{ + WorkWindow::KeyUp( rKEvt ); +} + +void MyWin::Paint( const Rectangle& rRect ) +{ + WorkWindow::Paint( rRect ); +} + +void MyWin::Resize() +{ + WorkWindow::Resize(); +} + +void SAL_CALL MyDragAndDropListener::dragGestureRecognized( const DragGestureEvent& dge ) throw(RuntimeException) +{ + Reference< XDragSource > xDragSource( dge.DragSource, UNO_QUERY ); + xDragSource->startDrag( dge, -1, 0, 0, new StringTransferable( OUString("TestString") ), this ); +} + +void SAL_CALL MyDragAndDropListener::drop( const DropTargetDropEvent& dtde ) throw(RuntimeException) +{ + dtde.Context->dropComplete( true ); +} + +void SAL_CALL MyDragAndDropListener::dragEnter( const DropTargetDragEnterEvent& dtdee ) throw(RuntimeException) +{ + dtdee.Context->acceptDrag( dtdee.DropAction ); +} + +void SAL_CALL MyDragAndDropListener::dragExit( const DropTargetEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragOver( const DropTargetDragEvent& dtde ) throw(RuntimeException) +{ + dtde.Context->acceptDrag( dtde.DropAction ); +} + +void SAL_CALL MyDragAndDropListener::dropActionChanged( const DropTargetDragEvent& dtde ) throw(RuntimeException) +{ + dtde.Context->acceptDrag( dtde.DropAction ); +} + +void SAL_CALL MyDragAndDropListener::dragDropEnd( const DragSourceDropEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragEnter( const DragSourceDragEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragExit( const DragSourceEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragOver( const DragSourceDragEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dropActionChanged( const DragSourceDragEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::disposing( const EventObject& ) throw(RuntimeException) +{ +} + +MyInfoBox::MyInfoBox( vcl::Window* pParent ) : InfoBox( pParent, + OUString("dragging over this box should result in another window id in the drag log.") ) +{ + Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this ); + + Reference< XDropTarget > xDropTarget = GetDropTarget(); + if( xDropTarget.is() ) + { + xDropTarget->addDropTargetListener( xListener ); + xDropTarget->setActive( true ); + } + + Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer(); + if( xRecognizer.is() ) + xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) ); +}; + +MyListBox::MyListBox( vcl::Window* pParent ) : ListBox( pParent ) +{ + Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this ); + + Reference< XDropTarget > xDropTarget = GetDropTarget(); + if( xDropTarget.is() ) + { + xDropTarget->addDropTargetListener( xListener ); + xDropTarget->setActive( true ); + } + + Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer(); + if( xRecognizer.is() ) + xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) ); +}; + +Any SAL_CALL StringTransferable::getTransferData( const DataFlavor& ) + throw(UnsupportedFlavorException, IOException, RuntimeException) +{ + return makeAny( m_aData ); +} + +Sequence< DataFlavor > SAL_CALL StringTransferable::getTransferDataFlavors( ) + throw(RuntimeException) +{ + return m_aFlavorList; +} + +bool SAL_CALL StringTransferable::isDataFlavorSupported( const DataFlavor& ) + throw(RuntimeException) +{ + return true; +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclDnDTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/errorhandler.cxx b/vcl/qa/cppunit/errorhandler.cxx new file mode 100644 index 000000000..21c672ac5 --- /dev/null +++ b/vcl/qa/cppunit/errorhandler.cxx @@ -0,0 +1,73 @@ +/* -*- 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 <cppunit/TestAssert.h> + +#include <vcl/errinf.hxx> + +class ErrorHandlerTest; + +namespace { + +class MockErrorHandler : private ErrorHandler +{ + friend ErrorHandlerTest; + +protected: + virtual bool CreateString(const ErrorInfo *pErrInfo, OUString &rErrString) const override + { + if (pErrInfo->GetErrorCode().IsDynamic()) + rErrString = "Dynamic error"; + else + rErrString = "Non-dynamic error"; + + return true; + } +}; + +} + +class ErrorHandlerTest : public test::BootstrapFixture +{ +public: + ErrorHandlerTest() : BootstrapFixture(true, false) {} + + void testGetErrorString(); + + CPPUNIT_TEST_SUITE(ErrorHandlerTest); + CPPUNIT_TEST(testGetErrorString); + CPPUNIT_TEST_SUITE_END(); +}; + +void ErrorHandlerTest::testGetErrorString() +{ + MockErrorHandler aErrHdlr; + std::unique_ptr<ErrorInfo> xErrorInfo; + OUString aErrStr; + + CPPUNIT_ASSERT_MESSAGE("GetErrorString(ERRCODE_ABORT, aErrStr) should return false", + !ErrorHandler::GetErrorString(ERRCODE_ABORT, aErrStr)); + // normally protected, but MockErrorHandler is a friend of this class + xErrorInfo = ErrorInfo::GetErrorInfo(ERRCODE_ABORT); + aErrHdlr.CreateString(xErrorInfo.get(), aErrStr); + CPPUNIT_ASSERT_EQUAL_MESSAGE("error message should be non-dynamic", OUString("Non-dynamic error"), aErrStr); + + CPPUNIT_ASSERT_MESSAGE("GetErrorString(ERRCODE_NONE, aErrStr) should return false", + !ErrorHandler::GetErrorString(ERRCODE_NONE, aErrStr)); + xErrorInfo = ErrorInfo::GetErrorInfo(ERRCODE_NONE); + aErrHdlr.CreateString(xErrorInfo.get(), aErrStr); + CPPUNIT_ASSERT_EQUAL_MESSAGE("error message should be non-dynamic", OUString("Non-dynamic error"), aErrStr); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ErrorHandlerTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf b/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf new file mode 100644 index 000000000..73de3117b --- /dev/null +++ b/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf @@ -0,0 +1,55 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R +>> +endobj +2 0 obj << + /Type /Pages + /MediaBox [0 0 200 300] + /Count 1 + /Kids [3 0 R] +>> +endobj +3 0 obj << + /Type /Page + /Parent 2 0 R + /Contents 4 0 R + /Key[<</InnerKey 42>>] +>> +endobj +4 0 obj << + /Length 188 +>> +stream +q +0 0 0 rg +0 290 10 10 re B* +10 150 50 30 re B* +0 0 1 rg +190 290 10 10 re B* +70 232 50 30 re B* +0 1 0 rg +190 0 10 10 re B* +130 150 50 30 re B* +1 0 0 rg +0 0 10 10 re B* +70 67 50 30 re B* +Q +endstream +endobj +xref +0 5 +0000000000 65535 f +0000000015 00000 n +0000000068 00000 n +0000000157 00000 n +0000000251 00000 n +trailer << + /Root 1 0 R + /Size 5 +>> +startxref +491 +%%EOF diff --git a/vcl/qa/cppunit/filter/ipdf/ipdf.cxx b/vcl/qa/cppunit/filter/ipdf/ipdf.cxx new file mode 100644 index 000000000..0f94f3276 --- /dev/null +++ b/vcl/qa/cppunit/filter/ipdf/ipdf.cxx @@ -0,0 +1,73 @@ +/* -*- 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 <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawView.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/security/XCertificate.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/xml/crypto/SEInitializer.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <osl/file.hxx> +#include <unotools/tempfile.hxx> +#include <sfx2/sfxbasemodel.hxx> +#include <svx/svdview.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/objsh.hxx> +#include <vcl/filter/PDFiumLibrary.hxx> +#include <vcl/filter/pdfdocument.hxx> + +using namespace ::com::sun::star; + +namespace +{ +char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/filter/ipdf/data/"; +} + +/// Covers vcl/source/filter/ipdf/ fixes. +class VclFilterIpdfTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +public: + void setUp() override; +}; + +void VclFilterIpdfTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testDictArrayDict) +{ + // Load a file that has markup like this: + // 3 0 obj << + // /Key[<</InnerKey 42>>] + // >> + OUString aSourceURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "dict-array-dict.pdf"; + SvFileStream aFile(aSourceURL, StreamMode::READ); + vcl::filter::PDFDocument aDocument; + CPPUNIT_ASSERT(aDocument.Read(aFile)); + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT(!aPages.empty()); + vcl::filter::PDFObjectElement* pPage = aPages[0]; + auto pKey = dynamic_cast<vcl::filter::PDFArrayElement*>(pPage->Lookup("Key")); + + // Without the accompanying fix in place, this test would have failed, because the value of Key + // was a dictionary element, not an array element. + CPPUNIT_ASSERT(pKey); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/font.cxx b/vcl/qa/cppunit/font.cxx new file mode 100644 index 000000000..e99bf12a5 --- /dev/null +++ b/vcl/qa/cppunit/font.cxx @@ -0,0 +1,161 @@ +/* -*- 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 <cppunit/TestAssert.h> + +#include <vcl/font.hxx> + +class VclFontTest : public test::BootstrapFixture +{ +public: + VclFontTest() : BootstrapFixture(true, false) {} + + void testName(); + void testWeight(); + void testWidthType(); + void testPitch(); + void testItalic(); + void testAlignment(); + void testQuality(); + void testSymbolFlagAndCharSet(); + + CPPUNIT_TEST_SUITE(VclFontTest); + CPPUNIT_TEST(testName); + CPPUNIT_TEST(testWeight); + CPPUNIT_TEST(testWidthType); + CPPUNIT_TEST(testPitch); + CPPUNIT_TEST(testItalic); + CPPUNIT_TEST(testAlignment); + CPPUNIT_TEST(testQuality); + CPPUNIT_TEST(testSymbolFlagAndCharSet); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclFontTest::testName() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_MESSAGE( "Family name should be empty", aFont.GetFamilyName().isEmpty()); + CPPUNIT_ASSERT_MESSAGE( "Style name should be empty", aFont.GetStyleName().isEmpty()); + aFont.SetFamilyName("Test family name"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Family name should not be empty", OUString("Test family name"), aFont.GetFamilyName()); + aFont.SetStyleName("Test style name"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Style name should not be empty", OUString("Test style name"), aFont.GetStyleName()); +} + +void VclFontTest::testWeight() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Weight should be WEIGHT_DONTKNOW", FontWeight::WEIGHT_DONTKNOW, aFont.GetWeight()); + + aFont.SetWeight(FontWeight::WEIGHT_BLACK); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Weight should be WEIGHT_BLACK", FontWeight::WEIGHT_BLACK, aFont.GetWeight()); +} + +void VclFontTest::testWidthType() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font width should be WIDTH_DONTKNOW", FontWidth::WIDTH_DONTKNOW, aFont.GetWidthType()); + + aFont.SetWidthType(FontWidth::WIDTH_EXPANDED); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font width should be EXPANDED", FontWidth::WIDTH_EXPANDED, aFont.GetWidthType()); +} + +void VclFontTest::testItalic() +{ + vcl::Font aFont; + + // shouldn't this be set to ITALIC_DONTKNOW? currently it defaults to ITALIC_NONE + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Italic should be ITALIC_NONE", FontItalic::ITALIC_NONE, aFont.GetItalic()); + + aFont.SetItalic(FontItalic::ITALIC_NORMAL); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Italic should be EXPANDED", FontItalic::ITALIC_NORMAL, aFont.GetItalic()); +} + + +void VclFontTest::testAlignment() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Text alignment should be ALIGN_TOP", TextAlign::ALIGN_TOP, aFont.GetAlignment()); + + aFont.SetAlignment(TextAlign::ALIGN_BASELINE); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Text alignment should be ALIGN_BASELINE", TextAlign::ALIGN_BASELINE, aFont.GetAlignment()); +} + + +void VclFontTest::testPitch() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Pitch should be PITCH_DONTKNOW", FontPitch::PITCH_DONTKNOW, aFont.GetPitch()); + + aFont.SetPitch(FontPitch::PITCH_FIXED); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Pitch should be PITCH_FIXED", FontPitch::PITCH_FIXED, aFont.GetPitch()); +} + +void VclFontTest::testQuality() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL( int(0), aFont.GetQuality() ); + + aFont.SetQuality( 100 ); + CPPUNIT_ASSERT_EQUAL( int(100), aFont.GetQuality() ); + + aFont.IncreaseQualityBy( 50 ); + CPPUNIT_ASSERT_EQUAL( int(150), aFont.GetQuality() ); + + aFont.DecreaseQualityBy( 100 ); + CPPUNIT_ASSERT_EQUAL( int(50), aFont.GetQuality() ); +} + + +void VclFontTest::testSymbolFlagAndCharSet() +{ + // default constructor should set scalable flag to false + vcl::Font aFont; + + CPPUNIT_ASSERT_MESSAGE( "Should not be seen as a symbol font after default constructor called", !aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Character set should be RTL_TEXTENCODING_DONTKNOW after default constructor called", + RTL_TEXTENCODING_DONTKNOW, aFont.GetCharSet() ); + + aFont.SetSymbolFlag(true); + + CPPUNIT_ASSERT_MESSAGE( "Test 1: Symbol font flag should be on", aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 1: Character set should be RTL_TEXTENCODING_SYMBOL", + RTL_TEXTENCODING_SYMBOL, aFont.GetCharSet() ); + + aFont.SetSymbolFlag(false); + + CPPUNIT_ASSERT_MESSAGE( "Test 2: Symbol font flag should be off", !aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 2: Character set should be RTL_TEXTENCODING_DONTKNOW", + RTL_TEXTENCODING_DONTKNOW, aFont.GetCharSet() ); + + aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + + CPPUNIT_ASSERT_MESSAGE( "Test 3: Symbol font flag should be on", aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 3: Character set should be RTL_TEXTENCODING_SYMBOL", + RTL_TEXTENCODING_SYMBOL, aFont.GetCharSet() ); + + aFont.SetCharSet( RTL_TEXTENCODING_UNICODE ); + + CPPUNIT_ASSERT_MESSAGE( "Test 4: Symbol font flag should be off", !aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 4: Character set should be RTL_TEXTENCODING_UNICODE", + RTL_TEXTENCODING_UNICODE, aFont.GetCharSet() ); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFontTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/fontcharmap.cxx b/vcl/qa/cppunit/fontcharmap.cxx new file mode 100644 index 000000000..b9d0d8c21 --- /dev/null +++ b/vcl/qa/cppunit/fontcharmap.cxx @@ -0,0 +1,45 @@ +/* -*- 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 <vcl/fontcharmap.hxx> + +class VclFontCharMapTest : public test::BootstrapFixture +{ +public: + VclFontCharMapTest() : BootstrapFixture(true, false) {} + + void testDefaultFontCharMap(); + + CPPUNIT_TEST_SUITE(VclFontCharMapTest); + CPPUNIT_TEST(testDefaultFontCharMap); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclFontCharMapTest::testDefaultFontCharMap() +{ + FontCharMapRef xfcmap( new FontCharMap() ); // gets default map + + CPPUNIT_ASSERT( xfcmap->IsDefaultMap() ); + + sal_uInt32 nStartBMPPlane = xfcmap->GetFirstChar(); + sal_uInt32 nStartSupBMPPlane = xfcmap->GetNextChar(0xD800); + sal_uInt32 nEndBMPPlane = xfcmap->GetLastChar(); + + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0x0020), nStartBMPPlane); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0xE000), nStartSupBMPPlane); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0xFFF0-1), nEndBMPPlane); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFontCharMapTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/fontmetric.cxx b/vcl/qa/cppunit/fontmetric.cxx new file mode 100644 index 000000000..4a3f476c2 --- /dev/null +++ b/vcl/qa/cppunit/fontmetric.cxx @@ -0,0 +1,138 @@ +/* -*- 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 <cppunit/TestAssert.h> + +#include <vcl/metric.hxx> + +class VclFontMetricTest : public test::BootstrapFixture +{ +public: + VclFontMetricTest() : BootstrapFixture(true, false) {} + + void testFullstopCenteredFlag(); + void testSpacings(); + void testSlant(); + void testBulletOffset(); + void testEqualityOperator(); + + CPPUNIT_TEST_SUITE(VclFontMetricTest); + CPPUNIT_TEST(testFullstopCenteredFlag); + CPPUNIT_TEST(testSpacings); + CPPUNIT_TEST(testSlant); + CPPUNIT_TEST(testBulletOffset); + CPPUNIT_TEST(testEqualityOperator); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclFontMetricTest::testFullstopCenteredFlag() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag should be false after default constructor called", !aFontMetric.IsFullstopCentered() ); + + aFontMetric.SetFullstopCenteredFlag(true); + + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag should be true", aFontMetric.IsFullstopCentered() ); +} + +void VclFontMetricTest::testSpacings() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetAscent() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetDescent() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetExternalLeading() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetInternalLeading() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetLineHeight() ); + + + aFontMetric.SetAscent( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetAscent() ); + + aFontMetric.SetDescent( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetDescent() ); + + aFontMetric.SetExternalLeading( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetExternalLeading() ); + + aFontMetric.SetInternalLeading( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetInternalLeading() ); + + aFontMetric.SetLineHeight( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetLineHeight() ); +} + +void VclFontMetricTest::testSlant() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetSlant() ); + + aFontMetric.SetSlant( 45 ); + CPPUNIT_ASSERT_EQUAL( 45L, aFontMetric.GetSlant() ); +} + +void VclFontMetricTest::testBulletOffset() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetBulletOffset() ); + + aFontMetric.SetBulletOffset( 45 ); + CPPUNIT_ASSERT_EQUAL( 45L, aFontMetric.GetBulletOffset() ); +} + +void VclFontMetricTest::testEqualityOperator() +{ + // default constructor should set scalable flag to false + FontMetric aLhs, aRhs; + + aLhs.SetFullstopCenteredFlag(true); + aRhs.SetFullstopCenteredFlag(true); + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag set same, aLhs == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag set same, aLhs != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetExternalLeading(10); + aRhs.SetExternalLeading(10); + CPPUNIT_ASSERT_MESSAGE( "External leading set same, aLHS == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "External leading set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetInternalLeading(10); + aRhs.SetInternalLeading(10); + CPPUNIT_ASSERT_MESSAGE( "Internal leading set same, aLHS == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "Internal leading set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetAscent( 100 ); + aRhs.SetAscent( 100 ); + CPPUNIT_ASSERT_MESSAGE( "Ascent set same, aLHS == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "Ascent set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetDescent( 100 ); + aRhs.SetDescent( 100 ); + CPPUNIT_ASSERT_MESSAGE( "Descent set same, aLHS == aRhs failed", aLhs.operator ==(aRhs)); + CPPUNIT_ASSERT_MESSAGE( "Descent set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetSlant( 100 ); + aRhs.SetSlant( 100 ); + CPPUNIT_ASSERT_MESSAGE( "Slant set same, aLHS == aRhs failed", aLhs.operator ==(aRhs)); + CPPUNIT_ASSERT_MESSAGE( "Slant set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); +} + + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFontMetricTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/gen/data/tdf121120.png b/vcl/qa/cppunit/gen/data/tdf121120.png Binary files differnew file mode 100644 index 000000000..8e48fba38 --- /dev/null +++ b/vcl/qa/cppunit/gen/data/tdf121120.png diff --git a/vcl/qa/cppunit/gen/gen.cxx b/vcl/qa/cppunit/gen/gen.cxx new file mode 100644 index 000000000..dfcfaa997 --- /dev/null +++ b/vcl/qa/cppunit/gen/gen.cxx @@ -0,0 +1,116 @@ +/* -*- 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 <com/sun/star/frame/Desktop.hpp> + +#include <comphelper/processfactory.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/sfxbasemodel.hxx> +#include <test/unoapi_test.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/virdev.hxx> + +using namespace com::sun::star; + +/// This test uses the gen backend (i.e. intentionally not the svp one, which is the default.) +class GenTest : public UnoApiTest +{ +public: + GenTest() + : UnoApiTest("/vcl/qa/cppunit/gen/data/") + { + } + + virtual void setUp() override + { + UnoApiTest::setUp(); + mxDesktop.set( + frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory()))); + SfxApplication::GetOrCreate(); + }; + + virtual void tearDown() override + { + if (mxComponent.is()) + { + closeDocument(mxComponent); + mxComponent->dispose(); + } + UnoApiTest::tearDown(); + }; + + Bitmap load(const char* pName) + { + OUString aFileURL; + createFileURL(OUString::createFromAscii(pName), aFileURL); + mxComponent = loadFromDesktop(aFileURL, "com.sun.star.drawing.DrawingDocument"); + SfxBaseModel* pModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pModel); + SfxObjectShell* pShell = pModel->GetObjectShell(); + std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile(); + BitmapEx aResultBitmap; + CPPUNIT_ASSERT(xMetaFile->CreateThumbnail(aResultBitmap)); + return aResultBitmap.GetBitmap(); + } + + uno::Reference<lang::XComponent> mxComponent; +}; + +CPPUNIT_TEST_FIXTURE(GenTest, testTdf121120) +{ + Bitmap aBitmap = load("tdf121120.png"); + Bitmap::ScopedReadAccess pAccess(aBitmap); + const Size& rSize = aBitmap.GetSizePixel(); + Color aColor(pAccess->GetPixel(rSize.getHeight() / 2, rSize.getWidth() / 2)); + // Without the accompanying fix in place, this test would have failed with 'Expected: 255; + // Actual : 1'. I.e. center of the preview (which has the background color) was ~black, not + // white. + CPPUNIT_ASSERT_EQUAL(0xff, int(aColor.GetRed())); + CPPUNIT_ASSERT_EQUAL(0xff, int(aColor.GetBlue())); + CPPUNIT_ASSERT_EQUAL(0xff, int(aColor.GetGreen())); +} + +/// Test that drawing a line preview to a bitmap is not lost. +CPPUNIT_TEST_FIXTURE(GenTest, testTdf107966) +{ + // Set up the virtual device: white background. + ScopedVclPtr<VirtualDevice> pVirtualDevice(VclPtr<VirtualDevice>::Create()); + pVirtualDevice->SetLineColor(); + MapMode aMapMode; + aMapMode.SetMapUnit(MapUnit::MapTwip); + pVirtualDevice->SetMapMode(aMapMode); + pVirtualDevice->SetOutputSizePixel(Size(90, 15)); + pVirtualDevice->SetFillColor(Color(255, 255, 255)); + pVirtualDevice->DrawRect(tools::Rectangle(Point(), Size(1350, 225))); + pVirtualDevice->SetFillColor(Color(0, 0, 0)); + AntialiasingFlags nOldAA = pVirtualDevice->GetAntialiasing(); + pVirtualDevice->SetAntialiasing(nOldAA & ~AntialiasingFlags::EnableB2dDraw); + + // Paint a black polygon on it. + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(0, 15)); + aPolygon.append(basegfx::B2DPoint(1350, 15)); + aPolygon.append(basegfx::B2DPoint(1350, 0)); + aPolygon.append(basegfx::B2DPoint(0, 0)); + pVirtualDevice->DrawPolygon(aPolygon); + + // Make sure that the polygon is visible. + Bitmap aBitmap = pVirtualDevice->GetBitmap(Point(), Size(1350, 15)); + Bitmap::ScopedReadAccess pAccess(aBitmap); + Color aPixel(pAccess->GetPixel(0, 0)); + // Without the accompanying fix in place, this test would have failed with 'Expected: 000000; + // Actual: ffffff', i.e. the top left pixel was white, not black. + CPPUNIT_ASSERT_EQUAL(OUString("000000"), aPixel.AsRGBHexString()); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/graphicfilter/data/README b/vcl/qa/cppunit/graphicfilter/data/README new file mode 100644 index 000000000..2cc9fb3cb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/README @@ -0,0 +1,7 @@ +Files with the string 'CVE' in their name are encrypted to avoid +problems with virus checkers on source code download.; use: + +mdecrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to unencrypt +mcrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to create new tests + +to get access to the plain files for manual testing. diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp Binary files differnew file mode 100644 index 000000000..d77db5782 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp Binary files differnew file mode 100644 index 000000000..4cfbdfff8 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp Binary files differnew file mode 100644 index 000000000..289cf8c0e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp Binary files differnew file mode 100644 index 000000000..84ac054db --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp Binary files differnew file mode 100644 index 000000000..a6aed5983 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp Binary files differnew file mode 100644 index 000000000..76aaecf97 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp new file mode 100644 index 000000000..d223dde28 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp @@ -0,0 +1 @@ +î¬.Gx©ŠKØ'seë2Ï~°Œè.G1Ì-”è‚#á›ø1†Y!ðÜÊ¢/ÙDVñ
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp Binary files differnew file mode 100644 index 000000000..b733b2484 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp Binary files differnew file mode 100644 index 000000000..2b58d1035 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp Binary files differnew file mode 100644 index 000000000..cfe7e40f6 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp Binary files differnew file mode 100644 index 000000000..1ca6e0008 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp Binary files differnew file mode 100644 index 000000000..84b6c35c8 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp Binary files differnew file mode 100644 index 000000000..a75d6ebae --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore new file mode 100644 index 000000000..583b009c7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore @@ -0,0 +1 @@ +*.wmf-* diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp Binary files differnew file mode 100644 index 000000000..3815a1c13 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp Binary files differnew file mode 100644 index 000000000..88b11ad57 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf Binary files differnew file mode 100644 index 000000000..a511da43a --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf Binary files differnew file mode 100644 index 000000000..dd57d9102 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf Binary files differnew file mode 100644 index 000000000..8fa6e9377 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf Binary files differnew file mode 100644 index 000000000..6adabec8b --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf Binary files differnew file mode 100644 index 000000000..92da5f05a --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf Binary files differnew file mode 100644 index 000000000..b89db21c2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf Binary files differnew file mode 100644 index 000000000..634fccdc0 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf Binary files differnew file mode 100644 index 000000000..e3baf3bfa --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf Binary files differnew file mode 100644 index 000000000..ef4c6a009 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf Binary files differnew file mode 100644 index 000000000..c71739a50 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf Binary files differnew file mode 100644 index 000000000..746e85e84 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf Binary files differnew file mode 100644 index 000000000..fbd546cb0 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf Binary files differnew file mode 100644 index 000000000..40f24b41d --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf Binary files differnew file mode 100644 index 000000000..dcc2a66f7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf Binary files differnew file mode 100644 index 000000000..b82444a97 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf Binary files differnew file mode 100644 index 000000000..8e67ce5ae --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf Binary files differnew file mode 100644 index 000000000..b17ce7061 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf Binary files differnew file mode 100644 index 000000000..0991bba4f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf Binary files differnew file mode 100644 index 000000000..78d030daa --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf Binary files differnew file mode 100644 index 000000000..fadbb7516 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf Binary files differnew file mode 100644 index 000000000..bbc0285db --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf Binary files differnew file mode 100644 index 000000000..a52213238 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf Binary files differnew file mode 100644 index 000000000..0af6c749b --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif Binary files differnew file mode 100644 index 000000000..7e84566e9 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif new file mode 100644 index 000000000..cbefd0162 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif @@ -0,0 +1 @@ +””&‡VâusØ[eë21oæX
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif new file mode 100644 index 000000000..a8f51b6ef --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif @@ -0,0 +1,2 @@ +””&X©=ŠÜØ¿;ekbÎ~§6à*^1Ì.”Ä„#᛾fLt€wüO zØâjA÷–F®HT©Øî +ÞeŸ€Ô ?AäUõaŒÈ»L*ÖVÉqd¦&ó`©6~[ŠÓ…j™ÜæÏøªÖ`¦µo§D9ëÚ.>4ùÓ
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif Binary files differnew file mode 100644 index 000000000..8f0f4fdb7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif new file mode 100644 index 000000000..d81d3b084 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif @@ -0,0 +1 @@ +””&H©1ŠÎØ'[ek2Ι~Ømé®ß1L-h£a[^¦Î.Þð!7¢/&»VOÊ»·BB^ïuËÃî±³È2k]YnEåG)qâ¿
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif Binary files differnew file mode 100644 index 000000000..26b35e63b --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif Binary files differnew file mode 100644 index 000000000..63426f9d8 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif Binary files differnew file mode 100644 index 000000000..e92a316e4 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif Binary files differnew file mode 100644 index 000000000..190c7b079 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif Binary files differnew file mode 100644 index 000000000..cf4f30c21 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif new file mode 100644 index 000000000..53d2ca01e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif @@ -0,0 +1 @@ +””&t©Š};'[ek2Ι~Ømé®ß1L-h£a[^¦Î.Þð!7¢/&»VOÊ»·BB^ïuËÃî±³È2k]Ynyå°G)‹Ê¿˜ð…‘jkš×Bà:Š’åå¢d#|åµÀu«\#ÑL—®í¢¡µê@Eßý˜
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif Binary files differnew file mode 100644 index 000000000..7cb2a03d5 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif Binary files differnew file mode 100644 index 000000000..cddbdc357 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif Binary files differnew file mode 100644 index 000000000..860f9e1d8 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif Binary files differnew file mode 100644 index 000000000..b7265f807 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif Binary files differnew file mode 100644 index 000000000..47f5d4341 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg Binary files differnew file mode 100644 index 000000000..c03c8529c --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg Binary files differnew file mode 100644 index 000000000..1a24da322 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg Binary files differnew file mode 100644 index 000000000..794ff52e4 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg Binary files differnew file mode 100644 index 000000000..8911646fa --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg Binary files differnew file mode 100644 index 000000000..c5373df43 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg Binary files differnew file mode 100644 index 000000000..33bbe9b5f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg Binary files differnew file mode 100644 index 000000000..e783bd33e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg Binary files differnew file mode 100644 index 000000000..3d9481aca --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg Binary files differnew file mode 100644 index 000000000..5eb27ffb5 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg Binary files differnew file mode 100644 index 000000000..4917f207f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg Binary files differnew file mode 100644 index 000000000..9d26db005 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg Binary files differnew file mode 100644 index 000000000..bc668d3e3 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg Binary files differnew file mode 100644 index 000000000..675881f36 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg Binary files differnew file mode 100644 index 000000000..01e7fe16f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg Binary files differnew file mode 100644 index 000000000..4753ed8db --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg Binary files differnew file mode 100644 index 000000000..c6ee53505 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png new file mode 100644 index 000000000..fa90a296f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png @@ -0,0 +1,3 @@ +Àœë#Mb£Š}ÕÔo7ë2ÎË~X¨á.^TÿwBè„!õ›žf1±°ƒÿ»±sé
‘tšùgšça2bA±Õð‡ÁËHbè—"8àî|†ìeGfS$N0nI€Öªõ +Ôç0"ð—JG°zÀ¤Ü¢(s?d)À"Ëÿ‘GE¢×F¯–9~}–ÇrÕ TÎp?áÅÂ*¿ìò·¥ckµ$E"ŒXï¯8á¾=2±T_3³v¿™#é–á$Hh4«‰JÑKiÝŠJÿ&7r…ú€…Ï=uŠ¯ù69KÙjãûäÎçèÿëWh{‘é½Ï$·
dVÅÜ[îÐЖ™Êy\à%Žº%†Ç¾H®meÛÃÞ+
“Á}€ÀgXI¡2ñ>‰*Ä«õ&ù˜Õú›Í·
)†Ì¸6ÔpU‚TjODhÙ¶1™éù-ÄÔ<WµŒUR±Kø591Òþ¦«M“„? +~˜æ*Nr¡Ìu;µãÀkh©ÉXˆÔà{ÖßÔ¤»' Ów©ìF[—ÛÒKèRÓf§y›‹O¹¨%0´©iháx׃‹€wz¿4dT.¥@ŒXm4¦Þi¤íô÷pçð¬Z¼¾^±ßy‘˜ÝÂЯú`®ºÎ_YŸ¬? …t‹uw4\kÁd¬J~m˜‹gú`<2ìl²Ñn¦ÒãùÞ*ð
òök h*n÷„w7ƒ‘!“YIßP+hK†Ø*Ôž`õ?Ëâç˜ü
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png Binary files differnew file mode 100644 index 000000000..d0644d139 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png Binary files differnew file mode 100644 index 000000000..9b30cc38c --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png Binary files differnew file mode 100644 index 000000000..b9ff67bb8 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png new file mode 100644 index 000000000..592fda10a --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png @@ -0,0 +1 @@ +Àœë#Mb£Š}ÕÔo7ë2Í~\íá._舄Ã{ÜÚß'p|&êFàà¨/û§§‚ô¬
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0951-2.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0951-2.png new file mode 100644 index 000000000..38899f733 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0951-2.png @@ -0,0 +1 @@ +Àœë#Mb£Š}ÕÔo7ë2ΰ~XÍù.^@Jäiè„#åüß+p¨%çHh¢/Ù¦ô‹0!0õ‚
òþõ{åﶌ[¦ÜB…]2ÓŒ*[»@Κâæ}¾{` RötÔ´Ž|}ø·Ï3ëÁ€N=aè‰DúITÇgI‰ã!³…Ò¨C]ËõÍÀ†ûïÚ åˆíEr–GOXÕö°9ò Ì“øˆÏ^Œ;²0/Aî±ìî)¢O²"vg Óº¹jõ”«1•»èá¨{b*[¼›o:Ù–ƒw*^_ˉœöi8˜¨¼d°q?]þ0Û}È´‰
á$õ}Ñê|6Es0”x%mL¤ à-Àm¹÷÷ë:ÓÒÄæ
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-2.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-2.png Binary files differnew file mode 100644 index 000000000..5494ca00e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-2.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/EDB-34720-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/EDB-34720-1.png Binary files differnew file mode 100644 index 000000000..3165f2c5e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/EDB-34720-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png Binary files differnew file mode 100644 index 000000000..db8e7a834 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0951-1.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0951-1.png new file mode 100644 index 000000000..b5e6220dc --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0951-1.png @@ -0,0 +1 @@ +Àœë#Mb£Š}ÕÔo7ë2Ε~Xèë._ÁÍãâè„#åüß+p¨±çHh¢/ÙG%òƒL¹¹Ö69lÂî±µ˜R?Y‘Š’¼¸ÖæôÑ)RÈ€ôAÙólþ7½„*…’[.óïþ{òýH
–Þá‚ÒçZ#á£
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png new file mode 100644 index 000000000..7848d5ad5 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png @@ -0,0 +1 @@ +Àœë#Mb£Š}ÕÔo7ë2Δ~Xéè._ló!©è„#åüß+p¨%çHh¢/ÙG%òƒL¹¹Ö69lÂ˜R?¦nCG³x¥öP¹¢&ŒØÈœîs0ÄÉÈ- C¤Ê99$8ôênœ;GF£Ô¾c
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-IDAT.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-IDAT.png Binary files differnew file mode 100644 index 000000000..b116a92ec --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-IDAT.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png Binary files differnew file mode 100644 index 000000000..cbba93bed --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png Binary files differnew file mode 100644 index 000000000..1c45c7689 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/svm/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-1.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-1.svm Binary files differnew file mode 100644 index 000000000..2fce465f7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-1.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm Binary files differnew file mode 100644 index 000000000..1b3cd1416 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm Binary files differnew file mode 100644 index 000000000..b4afeb09f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm Binary files differnew file mode 100644 index 000000000..c2f14d4a0 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm Binary files differnew file mode 100644 index 000000000..835e7f668 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm Binary files differnew file mode 100644 index 000000000..8d6d94e12 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm Binary files differnew file mode 100644 index 000000000..ad722ea13 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/svm/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/svm/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/pass/leak-1.svm b/vcl/qa/cppunit/graphicfilter/data/svm/pass/leak-1.svm Binary files differnew file mode 100644 index 000000000..14dbea080 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/svm/pass/leak-1.svm diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 Binary files differnew file mode 100644 index 000000000..49d3ddf28 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf Binary files differnew file mode 100644 index 000000000..ac546ce5b --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf Binary files differnew file mode 100644 index 000000000..aab34004e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf new file mode 100644 index 000000000..b68b7403c --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf @@ -0,0 +1 @@ +HUÛ¬.DZ©Š|Ød[eë2Ë~Sïb&[1Ì-kèÀg¥ßÚ"uZJjÞë<í‘êweƒù»·üÿâŠÏÂî±¼
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf Binary files differnew file mode 100644 index 000000000..370abe0e2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1238-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1238-1.wmf Binary files differnew file mode 100644 index 000000000..10da32742 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1238-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1245-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1245-1.wmf Binary files differnew file mode 100644 index 000000000..10da32742 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1245-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-1.wmf Binary files differnew file mode 100644 index 000000000..87319c2d4 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-2.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-2.wmf Binary files differnew file mode 100644 index 000000000..ff20cad78 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-2.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-3.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-3.wmf new file mode 100644 index 000000000..20a70fa67 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-3.wmf @@ -0,0 +1,5 @@ +HUÒ¬BGx©Š}ؘؤ`{3Χ~§é._1Ì,´Ê„"àšžf[Ch!64¢/ÙLV°Ê@H½½¡Îs0=3±¼Èk]ÙiuåC)N¯F—)#™É°‹ðÅÁ÷-hK§DŽz8ôê +Õ~ "
–Þ¤†Ñ‚³‚!>øø¼Šù¯iŸÐHh“‚×®¦cCߨ?j‡‡aC °Ùε +®¨#êBqŒoìb뀜Ûa6œTâ_‰–ljWõ+¦³ o'”P¨eSÑ%^̈«%©'™…æÅ_VÇKpJ62AFéÔÅ<+q‰›³Iˆjbö¶n}
{êgÌÆ"–û!ˆk[3ÀA²Ã+t}s +¢-·Ò>m=÷÷¢~HZ…§(¾®Þ”Òßfß[ÿcŒ ¬36œ§‹Š†_G¯„ߎ\äÉV@BzyâGßd2Înƒ‡‹)|3 ÃŽcz™¼îâD÷‰¿Ýæ2_æ¨&pN‘xø9YÝXDž`ýFh¿4+·õC^§b×Ë?o +@ÖƒˆqÂ
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf new file mode 100644 index 000000000..045f1f45e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf @@ -0,0 +1,3 @@ +ž˜6.Gx©ŠGÓ;>³eë2Î 8Yíà-Ñ1Ì-‘èŠ#ᛞv5."Þ2¢/Ùf_°ÔL½B¡ÎŒÏÄê±´Èi]YowÙ¼(ŽçKP¹ +)W`1a¨%#X„mi×-ã +HŽ‘n<ônÕ~ –ÖáË•©Œ¡Z!>
Ø|xíHf}ÐHœôx;ºëcCa¹?jlG‘CLO9VƵ$˜è#äBq—]a¦Ök
Ý.²w°Åx”}þ†ˆÆùº¤ß c„461ŠJ‘pHŽÑ«!©'f‡æ¥7VÇWpJp2AFvGÍ<7jú
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf Binary files differnew file mode 100644 index 000000000..2ec88066f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf Binary files differnew file mode 100644 index 000000000..02c72ad88 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf Binary files differnew file mode 100644 index 000000000..29c534fdc --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf Binary files differnew file mode 100644 index 000000000..f9a72867c --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf Binary files differnew file mode 100644 index 000000000..e2fac1523 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore new file mode 100644 index 000000000..583b009c7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore @@ -0,0 +1 @@ +*.wmf-* diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf Binary files differnew file mode 100644 index 000000000..e70664e64 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf new file mode 100644 index 000000000..cdb09c6b2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf @@ -0,0 +1 @@ +HUÛ¬.DZ©Š¡üI2ÆwÉ~¤ïé._1Ì-œè„#™žf1.!Þ0¢/Ù¸T¸ÊDH½½¡NÏÂî±¼
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf Binary files differnew file mode 100644 index 000000000..7864da572 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf Binary files differnew file mode 100644 index 000000000..1512a2256 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf Binary files differnew file mode 100644 index 000000000..365a247a7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf Binary files differnew file mode 100644 index 000000000..bfd7e20de --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm new file mode 100644 index 000000000..9d2a43470 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm @@ -0,0 +1,12 @@ +#define?te_width 31 +#define te_height = { + 0x0e, 0x20, 0x02, 0x38, 0x11, 0x70, 0x07, 0x 0x44, + 0x11, 1x2e, 0x3a, 0x44, 0x8e, 0x24, 0x92, 0x38, 0xdf, 0x25, 0xd2,0x7d, + 0x91, 0x24 0x92, 0x44, 0x95: 0x24, 0x92, 0x54, 0xf5, 0x7f, 0xff, 0x57, + 0x95, 0x24, 0x92, 0x54, 0x95, 0x 4,54, 0x95, 0x24, 0x92, 0x54, + 0x95, 0x24,x54, 0x95, 0x24, 0x92, 0x54, 0x95, 0x24, 0x92, 0x54, + 0x95, 0x24, 0x92, 0x54, 0x95, 0x24, 0x92,0x54, 0x95, 0x24, 0x92, 0x54, + 0x95, 0x24,ÏÏÏÏÏÏÏ 0x92, 0x54, 0x95, 0x24, 0x92, 0x54, 0xf5, 0x7f, 0xff, 0x57, + 0x95,0x24, 0x92, 0x54, 0x95, 0x24, 0x92, 0x54, 0, 0x54, 0xf5, 0xd= { + 25, 0xd2, 0x7d, +0x00, 0x7c };
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm new file mode 100644 index 000000000..aad9f0305 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm @@ -0,0 +1,2011 @@ +#define Grafix1_width 485 +#define Grafix1_height 395 +static char Grafix1_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, + 0x07, 0x00, 0x1c, 0xfc, 0x80, 0x81, 0x03, 0x30, 0x70, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x0c, 0xdc, 0x00, 0x70, 0x00, 0x37, 0x07, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x06, 0x00, 0x18, 0xd6, 0x80, 0xc1, 0x02, 0x30, 0x58, 0x00, 0x00, + 0x00, 0xb0, 0x00, 0x0c, 0xd6, 0x00, 0x60, 0x80, 0x35, 0x06, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x06, 0x00, 0x18, 0xc2, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x60, 0x80, 0x00, 0x06, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x06, 0x00, 0x18, 0xc3, 0x00, 0x60, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0x60, 0xc0, 0x00, 0x06, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x58, + 0xf0, 0xe1, 0x63, 0xc1, 0x87, 0x0f, 0x9f, 0xcf, 0xcc, 0xf1, 0xe1, 0x3b, + 0x3e, 0xe0, 0x01, 0x0e, 0x7f, 0xf8, 0x8e, 0xef, 0xe0, 0x63, 0xe6, 0x3b, + 0xe6, 0xe0, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x64, 0x98, 0x99, 0x91, 0x61, 0x66, 0x86, 0x19, 0xc3, 0x9e, 0x61, 0x98, + 0x31, 0x0c, 0x30, 0x03, 0x8c, 0x19, 0x66, 0x0c, 0xc3, 0x98, 0x61, 0xcf, + 0x30, 0x46, 0x98, 0xb1, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x4c, 0x8c, 0x19, 0x31, 0x31, 0x66, 0xc4, 0x18, 0xc3, 0x99, 0x61, + 0x18, 0x31, 0x0c, 0x18, 0x00, 0xd8, 0x18, 0x46, 0x0c, 0xc3, 0x18, 0xe1, + 0xcc, 0x30, 0x26, 0x18, 0x71, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x1c, 0x8c, 0x19, 0x71, 0x30, 0x66, 0xc4, 0x18, 0xc3, 0x98, + 0x61, 0x18, 0x31, 0x0c, 0x18, 0x00, 0x70, 0x18, 0x46, 0x0c, 0xc3, 0x18, + 0x61, 0xcc, 0x30, 0x16, 0x18, 0x31, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x38, 0x8c, 0x99, 0xe1, 0x30, 0x66, 0xc6, 0x18, 0xc3, + 0x98, 0x61, 0x98, 0x31, 0x0c, 0x18, 0x00, 0x70, 0x18, 0x66, 0x0c, 0xc3, + 0x98, 0x61, 0xcc, 0x30, 0x1e, 0x98, 0x31, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x70, 0x8c, 0xf1, 0xc0, 0x31, 0xc6, 0xc3, 0x18, + 0xc3, 0x98, 0x61, 0xf0, 0x30, 0x0c, 0x18, 0x00, 0x70, 0x18, 0x3c, 0x0c, + 0xc3, 0xf0, 0x60, 0xcc, 0x30, 0x36, 0xf0, 0x30, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x64, 0x8c, 0x11, 0x90, 0x31, 0x46, 0xc0, + 0x18, 0xc3, 0x98, 0x61, 0x10, 0x30, 0x0c, 0x18, 0x00, 0xd8, 0x18, 0x04, + 0x0c, 0xc3, 0x10, 0x60, 0xcc, 0x30, 0x66, 0x10, 0x30, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x4c, 0x98, 0xf1, 0x31, 0x61, 0xc6, + 0x87, 0x19, 0xc3, 0x98, 0x61, 0xf0, 0x31, 0x0c, 0x30, 0x03, 0x8c, 0x19, + 0x7c, 0x0c, 0xc3, 0xf0, 0x61, 0xcc, 0x30, 0xc6, 0xf0, 0x31, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x34, 0xf0, 0xf3, 0xd7, 0xc0, + 0xcf, 0x1f, 0xbf, 0xe7, 0xb9, 0xf1, 0xf0, 0x37, 0x1e, 0xe0, 0x01, 0x86, + 0x3f, 0xfc, 0x8d, 0xc7, 0xf0, 0xf7, 0xfc, 0x31, 0xc7, 0xf1, 0x7f, 0x0e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x06, + 0x00, 0x20, 0x18, 0x00, 0x00, 0x80, 0x01, 0x08, 0x36, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x82, 0x0d, 0xc0, 0x08, 0x06, 0x00, 0x30, 0x00, 0x08, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x04, 0x00, 0x60, 0x10, 0x00, 0x00, 0x80, 0x01, 0x18, 0x34, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0d, 0xc0, 0x18, 0x04, 0x00, 0x30, 0x00, 0x18, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x38, 0x02, 0x00, 0xe0, 0x08, 0x00, 0x00, 0xe0, 0x00, 0x38, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x07, 0x70, 0x38, 0x02, 0x00, 0x1c, 0x00, + 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0xf0, 0x01, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x60, 0x00, 0xf0, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x03, 0x30, 0xf0, 0x01, 0x00, 0x0c, + 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x7f, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x55, 0x55, 0x55, 0x55, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xbc, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xab, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x80, 0x7f, 0x44, 0x44, 0x44, 0xc4, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x55, 0x7f, 0x77, 0x77, 0x77, 0x77, 0x77, 0xf7, + 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0xfe, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0xf1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xfa, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xdf, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xfd, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x45, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe3, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xfa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x91, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x45, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x71, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x8b, 0xd8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x89, 0xe8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x22, 0x7a, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0x17, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x89, 0x88, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x22, 0x62, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x11, 0x19, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x88, + 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, + 0xc4, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x22, 0x62, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0xf7, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0xff, 0x11, 0x11, 0x1d, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0x88, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xea, 0x89, 0x88, 0x88, 0xe8, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x23, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x11, 0xd1, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x79, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x8f, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xe4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xc8, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0x7d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x75, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x44, 0x74, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa0, 0xea, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, + 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x17, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x55, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, + 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x80, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x26, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2e, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x80, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x89, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xb8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x44, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0xe2, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x3f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x62, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0xf7, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xaa, 0xaa, 0xaa, 0x0e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x46, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x54, 0x55, 0x55, + 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xa8, + 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xa8, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x8e, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x50, 0x55, 0x55, 0x55, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x23, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x98, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x6c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0xbc, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x16, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x1d, 0x00, 0x00, 0x80, 0xdf, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x44, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0xd7, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x9d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x60, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0xe0, 0xba, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x26, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5f, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xdf, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xb1, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xb2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x60, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0xd1, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa8, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x3a, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x5c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x50, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x03, 0x80, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x80, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x13, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0xc0, 0xa8, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xbc, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x40, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x4f, 0x44, 0x44, + 0x44, 0xc4, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x20, 0x22, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x37, 0x22, + 0x22, 0x22, 0x22, 0x7e, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x51, + 0x11, 0x11, 0x11, 0x11, 0xd1, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x90, + 0x88, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xae, + 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x50, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, + 0x45, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x47, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x05, 0x00, + 0x00, 0x28, 0x22, 0x72, 0x77, 0x77, 0x77, 0x77, 0x77, 0x2f, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x62, 0x77, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x18, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x31, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x13, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xea, + 0x00, 0x00, 0x00, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x8e, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xb8, 0xaa, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xaa, + 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x26, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, + 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0x23, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x12, 0x11, 0x11, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x3d, 0x11, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x54, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0xdc, 0xdd, + 0xdd, 0xdd, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x47, 0x44, 0x44, 0x44, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0xa8, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, + 0xba, 0xaa, 0xaa, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xb2, 0xaa, 0xaa, 0xaa, 0x23, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x89, + 0x88, 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0xdd, + 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xdd, + 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, + 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, + 0x45, 0x44, 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, + 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xbd, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xd8, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, + 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xb2, 0xaa, 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x88, 0x88, 0x88, 0x88, 0xaa, + 0xaa, 0xaa, 0x9a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x22, 0x22, 0x22, + 0x22, 0x76, 0x77, 0x77, 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, + 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, + 0x11, 0x11, 0x19, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, + 0x11, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, + 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xab, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x45, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, 0x77, 0x2f, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x35, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x14, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x8c, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0x8a, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, + 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x37, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x5f, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, + 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, 0xc8, + 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xba, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, + 0xc4, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xa2, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, + 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, + 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0x9d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xde, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x46, 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0x8d, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, + 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xd8, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0x7d, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x26, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xc8, 0xaa, 0x9a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0xc4, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x37, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xe2, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x15, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0x9a, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, + 0x37, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xa8, 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x62, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x37, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, 0x77, + 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x91, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x6a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc6, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x4c, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0x23, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x6a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0x8b, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xde, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xa2, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xd9, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, + 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0x8b, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xbd, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xdd, + 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xd5, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x4c, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x3a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xb2, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x51, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, + 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xe2, 0x77, 0x3f, 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x27, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x91, 0x11, 0xf1, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0x8f, 0x88, 0x88, 0x88, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x5c, 0x44, 0x44, 0x44, 0x45, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x22, 0x22, 0xa2, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x91, 0x11, 0x11, + 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xac, 0xaa, 0xaa, 0x8e, + 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, + 0x74, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, 0x77, + 0x77, 0xf7, 0x27, 0x62, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xf7, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x39, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x19, 0x11, 0x11, 0x11, 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xa8, 0xaa, 0xaa, 0xaa, 0xea, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x4f, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0xf5, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0xdf, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x9d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x46, 0x7c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x27, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0x23, + 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x14, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x3d, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8d, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdf, 0xdd, 0xdd, + 0xdd, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdf, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x5e, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, + 0xaa, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x2a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x38, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x19, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11, + 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x57, 0xbd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xd8, 0xdd, 0xdd, 0xbd, 0x88, 0x88, 0x88, 0x88, 0xf8, 0xdd, 0xdd, + 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x70, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x54, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x47, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xfa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x60, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x1f, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xea, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xe8, 0xab, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x7e, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0xd5, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0x77, 0x77, 0x27, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0x3f, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x7a, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xf3, 0x1f, 0x11, 0x11, + 0x11, 0x11, 0x11, 0xd1, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, + 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, + 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xfa, 0x8f, + 0x88, 0x88, 0x88, 0x88, 0xbe, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x1a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, + 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, + 0xfc, 0xff, 0x7f, 0xe4, 0xff, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x55, 0xd5, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x76, + 0x77, 0x77, 0x77, 0xf7, 0x7f, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x0d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb0, 0xaa, 0xaa, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xac, 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x49, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x31, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x7a, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xa2, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xea, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x42, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0x6a, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x84, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x31, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, + 0x85, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xbd, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0x7d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x08, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, + 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, + 0xaa, 0xaa, 0x0a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xa2, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x08, 0x14, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0x55, 0x55, 0x0d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x4e, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0x0a, 0x20, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x26, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x20, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x55, 0x55, 0x15, 0xc0, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8c, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x80, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0x1a, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2a, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, + 0x00, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, + 0x1a, 0x00, 0x8c, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x9a, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x20, 0x00, 0x58, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x65, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x55, 0x55, 0x35, 0x00, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x37, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x20, 0x00, 0x40, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xaa, 0xaa, 0x2a, 0x00, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x35, 0x00, 0x00, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x62, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x14, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0x89, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x45, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x00, + 0x00, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, 0x23, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, + 0x00, 0x00, 0xc0, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, + 0x6a, 0x00, 0x00, 0x80, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0xb8, 0xaa, + 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x2c, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xaa, 0xaa, 0x26, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x15, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xa0, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xdc, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x46, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, + 0x00, 0x8c, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x4c, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x4c, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0x2a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x60, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x19, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x55, + 0x55, 0x01, 0x00, 0x00, 0x00, 0x80, 0x89, 0x88, 0x88, 0xf8, 0xdd, 0xdd, + 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x54, 0x44, + 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x22, 0x22, 0xaa, + 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, + 0x19, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x88, + 0x88, 0xac, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x45, 0x44, 0x46, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x26, 0x22, 0x77, 0x77, 0x77, 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x91, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xaa, 0xaa, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0xc8, 0xaa, 0xaa, 0xaa, 0x8e, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x75, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x77, 0x77, 0x77, 0x27, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x11, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, + 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xaa, 0xaa, 0xaa, + 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0x44, + 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x7d, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x30, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0xaa, 0xea, 0xab, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x4e, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xac, 0xaa, 0xaa, 0xfa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x71, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x01, 0x00, + 0x00, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xbd, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0x5f, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x45, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xe4, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, + 0x06, 0x00, 0x00, 0x00, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x3e, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, 0xbe, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x00, 0xe0, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0xf1, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x55, + 0x55, 0x55, 0x35, 0x00, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0x1f, 0x00, + 0x00, 0xfc, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0xdd, + 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x4f, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x3e, 0xc0, 0xab, 0xaa, 0xaa, 0xaa, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, + 0xea, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x99, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x58, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x88, 0x88, 0x88, + 0x88, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0x7f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x58, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xaa, 0xaa, + 0xaa, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xaa, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x56, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x55, 0x55, 0x55, 0x3d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xaa, 0xaa, + 0xea, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x7f, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}; diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm Binary files differnew file mode 100644 index 000000000..ca2d777a1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm new file mode 100644 index 000000000..b5eab3e33 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm @@ -0,0 +1,306 @@ +/* XPM */
+static char * example_xpm[] = {
+"150 100 203 2",
+" c #E6DECA",
+". c #E5DDC9",
+"+ c #E4DCC8",
+"@ c #E3DBC7",
+"# c #E3DAC5",
+"$ c #E2D9C4",
+"% c #E1D8C3",
+"& c #E1D7C1",
+"* c #DFD6C1",
+"= c #DFD5BF",
+"- c #DED4BE",
+"; c #DDD3BD",
+"> c #DDD2BB",
+", c #DCD1BA",
+"' c #DBCFB9",
+") c #DACFB8",
+"! c #D9CDB7",
+"~ c #D8CDB6",
+"{ c #D6CAB2",
+"] c #D7CBB3",
+"^ c #D7CCB5",
+"/ c #D5C9B1",
+"( c #D4C8B0",
+"_ c #D3C7AF",
+": c #D3C6AD",
+"< c #D2C5AC",
+"[ c #D1C3AB",
+"} c #D0C2AA",
+"| c #CFC1A9",
+"1 c #CEC0A8",
+"2 c #CDBFA7",
+"3 c #CBBDA5",
+"4 c #CCBEA6",
+"5 c #CABBA2",
+"6 c #C9BAA1",
+"7 c #CBBCA3",
+"8 c #C8B9A0",
+"9 c #C7B89F",
+"0 c #C6B79E",
+"a c #C5B69D",
+"b c #C5B59B",
+"c c #C4B49A",
+"d c #C3B399",
+"e c #C2B298",
+"f c #C1B197",
+"g c #C0B096",
+"h c #BFAF95",
+"i c #BEAE94",
+"j c #BDAD93",
+"k c #BDAC91",
+"l c #BCAB90",
+"m c #BBAA8F",
+"n c #BAA98E",
+"o c #B9A88D",
+"p c #B2A186",
+"q c #B3A287",
+"r c #B8A78C",
+"s c #B6A58A",
+"t c #B2A084",
+"u c #B09E82",
+"v c #AF9D81",
+"w c #B5A489",
+"x c #7F6B4B",
+"y c #5F4E2D",
+"z c #5E4D2C",
+"A c #614F2D",
+"B c #A39175",
+"C c #9D8B6F",
+"D c #978265",
+"E c #927E5E",
+"F c #8C7858",
+"G c #857151",
+"H c #7A6746",
+"I c #776443",
+"J c #887454",
+"K c #E7DFCB",
+"L c #1E1800",
+"M c #161100",
+"N c #221B00",
+"O c #AB997D",
+"P c #9A876A",
+"Q c #948060",
+"R c #8A7656",
+"S c #816D4D",
+"T c #796645",
+"U c #715E3D",
+"V c #685534",
+"W c #584826",
+"X c #725F3E",
+"Y c #B19F83",
+"Z c #E8E0CC",
+"` c #B7A68B",
+" . c #120F00",
+".. c #000000",
+"+. c #AC9A7E",
+"@. c #937F5F",
+"#. c #826E4E",
+"$. c #6F5D3D",
+"%. c #E9E1CD",
+"&. c #AD9B7F",
+"*. c #9B896D",
+"=. c #847050",
+"-. c #7A6848",
+";. c #6A5838",
+">. c #61502F",
+",. c #5B4A29",
+"'. c #746140",
+"). c #AE9C80",
+"!. c #968164",
+"~. c #8E7A5A",
+"{. c #897555",
+"]. c #8B7757",
+"^. c #836F4F",
+"/. c #7D6949",
+"(. c #9F8D71",
+"_. c #907C5C",
+":. c #A9977B",
+"<. c #A08E72",
+"[. c #9A8568",
+"}. c #988366",
+"|. c #A29074",
+"1. c #9B886B",
+"2. c #958161",
+"3. c #695635",
+"4. c #665534",
+"5. c #756241",
+"6. c #9C8A6E",
+"7. c #625130",
+"8. c #766342",
+"9. c #6B5939",
+"0. c #7E6A4A",
+"a. c #6A5736",
+"b. c #786544",
+"c. c #A79579",
+"d. c #998467",
+"e. c #B4A388",
+"f. c #A59377",
+"g. c #493A13",
+"h. c #3A2D00",
+"i. c #413509",
+"j. c #362B00",
+"k. c #6D5B3B",
+"l. c #52431E",
+"m. c #382D00",
+"n. c #282000",
+"o. c #403306",
+"p. c #5D4C2B",
+"q. c #73603F",
+"r. c #4A3B14",
+"s. c #1A1500",
+"t. c #544422",
+"u. c #8F7B5B",
+"v. c #7C6948",
+"w. c #51421D",
+"x. c #3C3000",
+"y. c #534321",
+"z. c #241C00",
+"A. c #3E3202",
+"B. c #655433",
+"C. c #574725",
+"D. c #50411C",
+"E. c #53441F",
+"F. c #6E5C3C",
+"G. c #554523",
+"H. c #4D3F19",
+"I. c #4F3F19",
+"J. c #A49276",
+"K. c #A8967A",
+"L. c #302600",
+"M. c #473911",
+"N. c #0E0B00",
+"O. c #3F3203",
+"P. c #080600",
+"Q. c #42340A",
+"R. c #4B3C15",
+"S. c #43350B",
+"T. c #877353",
+"U. c #5C4B2A",
+"V. c #46370E",
+"W. c #4C3E18",
+"X. c #322700",
+"Y. c #50401A",
+"Z. c #645332",
+"`. c #2A2100",
+" + c #2E2500",
+".+ c #645230",
+"++ c #A69478",
+"@+ c #867252",
+"#+ c #5A4826",
+"$+ c #463810",
+"%+ c #A18F73",
+"&+ c #806C4C",
+"*+ c #403204",
+"=+ c #413407",
+"-+ c #9E8C70",
+";+ c #958263",
+">+ c #AA987C",
+",+ c #5A4928",
+"'+ c #564624",
+")+ c #4C3D16",
+"!+ c #483912",
+"~+ c #6C5A3A",
+"{+ c #8D7959",
+" ",
+" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + + + + + . . . . . . . . . . . . . . . . . . + + + + + + + . . . . . . . . . . . . . . . . . . + + + + + + + + + + + . . . . + . . . . . ",
+" . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . + + + + + + + + . . . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ @ @ @ @ @ @ @ + + + + + + + . . . . . . . . ",
+" . . . . . + . + + + @ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ @ @ @ @ @ # # # # # # # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # # # # # @ @ @ @ + @ + + . + . . . . ",
+" . . . . + . + + + + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # # # # # # # $ $ $ $ $ % % % % $ $ $ $ $ # # # # # # # # # # # $ $ $ $ $ $ % % % $ $ $ $ $ # # # # # # # # # # # $ $ $ $ % % % % % % % % % $ $ % $ # # # @ @ @ + + + . . . . . . ",
+" . . . . . + . + @ + @ @ # # # # $ $ $ $ $ $ $ # # # # # # # # # # # $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ % % % & & & & * * * * * * & & & & % % % $ $ $ $ $ % % % % & & & * * * * * * & & & & % % % $ $ $ $ $ % % % & & & * * * * * = = * * * * & & & % % $ $ # # @ @ + + . + . . . . ",
+" . . . . + + + + @ @ # # $ $ % % % % % % % % % % % % % $ $ $ % % % % % % & & & & & & & & & & & & & & * * * = * = = = = = = = = = * * = * * * & & & & & * * * = * * = = = = = = = = * * = * * * & & & & & * * * = * = = = - - - - - - - - = = * = * * & % % $ # # # @ @ + + . . . . ",
+" . . . . + + @ @ @ # # % % % & & & * * * * * * * * * & & & & & & * * * * = * * * * * * * * * * * * = * = - - ; ; > ; > > , > > > > ; ; - - = = * * * * * = = - - ; ; > ; > > > > ; > ; ; - - = = * * * * * = = - - - ; ; > , ' ' ' ' ' , , > > - - - = * * & & % $ # # @ + + + . . . . ",
+" . . . . + + @ @ # # $ % & & = = * = = = - - - - = = = = = = = = = = = - - - - ; ; ; ; ; ; ; ; ; ; ; ; ; > , ' ' ) ) ) ! ! ! ! ! ! ! ) ' ' , > > ; - - - ; > > , ' ) ) ! ! ! ! ! ! ! ! ) ' ' , > > ; - - ; ; > > , ) ) ) ! ! ! ! ~ ~ ~ ! ! ! ! ) ) ' > ; - = * * & % $ # # @ + + + . . . . ",
+" . . . . + + + # # $ % % & * * = - ; ; ; > > , , > > > ; > ; ; ; ; > ; > , ' ' ) ) ) ) ) ) ) ) ) ) ) ) ) ! ! ! ! ~ ~ { { { { { { { { ] ~ ~ ! ! ) ) ) ) ) ) ' ) ! ! ~ ~ ^ ] { { { { / { { ~ ~ ! ! ) ) ) ) ) ) ) ! ! ) ~ ^ ^ { { / { { / { { / { ] ^ ~ ! ! ) ' ; ; = * * & % $ # # + + + . . . ",
+" . . . + + @ @ # $ % & = * = ; > , ) ) ) ! ! ! ! ! ! ! ! ) ) ) ) ) ! ! ! ) ! ! ~ ~ ^ ^ ^ ^ ^ ^ ~ ~ ~ ^ ^ ] { / { / ( ( _ _ _ ( _ _ : ( ( / { { ] ^ ^ ~ ~ ~ ~ ^ { { { / ( ( _ _ _ _ _ _ ( / / { { ] ^ ^ ~ ~ ~ ~ ^ { { { / ( _ _ _ : _ _ : _ _ _ ( / / { { ~ ! ) ' > - = * & % $ # @ @ + + . . . ",
+" . . . . . @ @ # $ % * * = - ; , ) ! ! ~ ^ ^ { { ] ] { ^ ^ ~ ~ ~ ~ ^ ^ ] { / { { / / ( _ ( _ ( ( ( ( ( ( _ _ _ _ _ < [ [ [ } | | | } [ < < : _ _ ( / / / { / ( ( _ _ _ < [ [ [ } } } } } [ [ : _ _ ( / / / { / ( ( _ _ _ < [ } } 1 | | | | 1 1 } [ < : _ / { ] ~ ! ) > ; * * & % # # @ + + . . ",
+" . . . + + @ @ # % & * * - > ' ) ! ~ { / / / / ( ( ( ( ( / ( ( ( / ( ( _ _ ( _ : [ [ [ [ < < [ [ [ [ [ [ < [ } 1 1 1 2 2 2 3 3 3 3 3 2 2 1 | | [ [ < : _ _ _ _ < < [ 1 | 2 2 2 2 3 3 2 1 2 1 | | [ [ < : _ _ _ _ < < } | 1 1 2 3 3 4 3 3 4 3 3 2 2 | | < < _ ( { ^ ! ) , - * * & $ # # + + + . . . ",
+" . . . + @ # $ $ & * = ; > ' ) ~ { { ( _ _ : < [ [ [ [ [ [ < < < [ [ [ [ [ | | | 1 2 2 2 1 2 2 2 2 1 1 2 2 2 2 3 4 5 5 6 5 6 6 6 6 6 6 5 7 4 2 1 1 | | | | | | 1 2 1 3 3 5 5 5 5 5 6 5 5 7 5 4 2 1 1 | | | | | | 1 2 2 4 5 7 5 5 8 8 6 8 8 6 5 5 5 4 2 2 | [ : ( { ] ! ) , - = * % $ # @ @ . . . ",
+" . . . + + @ # $ % * * - ; ) ! ] { / ( < [ [ | | | 1 1 1 1 1 1 1 1 1 2 2 1 2 3 3 5 5 5 5 5 6 6 5 5 7 5 5 5 5 5 5 8 6 9 0 0 a a 0 0 a 0 0 9 9 8 5 5 7 3 3 4 4 3 4 3 7 5 5 8 9 0 0 0 0 0 0 0 9 6 5 5 5 7 3 3 4 4 3 4 3 7 5 5 6 8 0 0 0 a b a a a 0 9 9 6 7 3 2 1 [ < ( { ] ) ' > = * & % # @ + + + . . . ",
+" . . . @ # $ $ % * = ; ' ! ] { ( _ < | 1 2 2 3 3 3 3 7 7 7 7 3 5 7 5 5 6 5 8 8 9 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 b a c c d c c e c c d c b a 0 9 8 6 8 5 5 5 5 8 6 8 9 0 a b c c d d d c c c a 0 9 8 6 8 5 5 5 5 8 6 8 9 0 a b c d d e e e c c c c 0 9 9 5 7 4 1 } < ( { ~ ) ' ; = * % $ # @ + + . . . ",
+" . . + + + @ $ % & * - , ) ~ { ( : < | 1 3 5 5 5 5 6 8 8 8 8 8 8 9 9 0 0 0 a b a b c c d c c c c d d c c d c c d d f f f g g g g g g g f e d c c c b 0 0 0 0 0 0 a b c c d e e g f g f g e e d c c a b 0 0 0 0 0 0 a b c c d f g g g g g g g g f d c b 0 9 6 5 4 1 | < ( ] ~ ) , = * & $ # @ + + + . . ",
+" . . . + + @ # $ % * = ; ) ~ ] ( : } 1 4 7 5 8 0 9 0 0 a a a b b a b c c c d e d f f f g g g g g g g g g g g g g h h i i i j j j j j j i h h g g e c d c c c b c c d d e g g h h i h h i h g g f f e d c c b c c c c d d e f g h h i i j j i i i g g g c c 0 9 8 5 4 1 < _ / ^ ) , - = * % $ # @ + + . . ",
+" . . . . @ # # % * * ; , ) ^ / _ [ 1 4 7 5 8 0 0 a c c d d d e d f e f f f g g i i i i j j j j j j j j j j j j k j j k l k l l l l l k k j j i i g g f f g e e f g g g h h i j j j k k j j j j i i h g f f g e e f g g g h h j j j j l k l j j j j h h f e b a 9 5 7 2 } : ( ] ! ) ; = * % $ @ @ + . . . ",
+" . . + + @ $ % * * ; ' ! ] ( : } 4 3 5 9 0 b d d e f g g g g g h i i j j j j j j k l m l l l l l m l l l l l m m m m n m m m m m m m m l m k j j i h i h h h i h h i j j k k l l m m l l l k k j j i h i h h h i h h j j k j k l m m m m l l k k j i g f d c a 8 5 3 1 [ ( { ^ ' , - & & % # @ + . . . ",
+" . . + + @ # $ % * = , ' ^ { ( [ | 3 5 8 0 b c e g g i i j j j j k k k l k m m m m m n m n m n m n m m n n m m m m m n n n n n n n n m m m m l k l j j j j j j j j j j k k m l m m m m m m m m l l k j j j j j j j j j j k k l m m m m m m m m m k j i h g e c b 0 5 3 1 } _ ( ] ! , ; = & % $ @ + + . . . ",
+" . . + + @ # $ & & = , ) ^ ( : [ 1 7 5 0 b d e g h i j l k m l l m m m n m m m n n m m n n n o o o n n o o o n o n n n n n o o n n m m n m m m m m m l k k k k k l k l l m m m m m m m m m m m m m l l l l k l k k l k l l m m m m m m m m m m m l k j i h f c c a 9 7 4 | : ( ] ! ' ; = & % # @ + + + . . ",
+" . . + + @ # $ & * - , ) ] ( [ | 2 5 8 0 c e g h j j k m m m n n m n n n n n n n n n n n n n n m n n n m n n n n n m m n m m m m m m m m m m m m m m m m m m l m m l m m m m m m m m m m m m m m m m m m m m m l m m l m m m m m m m m m m m m m l k j j h g d c a 8 5 3 1 [ _ ] ~ ' ; = * % $ # @ + + . . ",
+". . . . @ @ # % * = - ' ~ / ( < 1 4 6 0 b e f g j j l l m m m n n n o n n n m m n m m m m m m m l m m m m m m m m m m l m m m l l m m m m m m m m m m m m m m m m m m m m l m m m m m m m m m m m m m m m m m m m m m m m m l m m l l l l m m l l l k j j h g f d b 0 6 7 1 [ _ / ^ ' , = & & $ @ @ + . . ",
+". . . . + @ $ % * = > ' ~ / ( } 1 7 6 0 c e g h j k l m m n n n n n n m m m m m l l k k k j j j j j j j k k k k k j j j j j j j j j k k k l m m m m m m m m m m m m l m l l l k k k k l l l l m m m m m m m m m m m m l m l k l k k k k k l l k k k j j j i g f d c 0 5 3 1 } : / ^ ) , - * % $ # @ + . . ",
+". . . . + @ # % * = , ' ~ / : } 1 7 8 0 c e g i j k l m m n n m m m m m l k k j j i i h g g g g g g g g g g h h g g g g g g g g h i i j j j k k l m m m m m m m m l k k k j j j j j j j j j k k l l m m m m m m m m l k k k j j j j j j j j j j j j j j i h g g d c 0 9 5 4 | < ( ] ! ' - * & % # @ + . . ",
+". . + + # $ % & = , ' ^ / < | 1 5 9 b c f g i j k l m m m m m l l k j j i h g g g e d d d d c c c c c d d d d d d d c c d d d e e g g g h j j j k l k l l k k k k j j j h h g g g h g h i i j j k k k l l l k k k k j i i h h h g g g h g h h i i j i i h g f d c a 9 6 3 | < _ { ~ ' ; * * % # # + + + . ",
+". . + + # $ & & = , ' ^ ( : | 4 5 9 a c e g i j j k k l l k k j i h h g f e d c c a 0 0 0 0 9 9 9 9 0 0 0 0 0 0 0 0 0 0 0 a a b c c d e g g h i i j j j j j j j i h h g g f e e e e f f g g h i i j j j j j j j j i h g g f f e f e e f f g g g h g h h g g f e c 0 9 5 4 1 [ _ / ^ ) , = & & $ @ @ + . . ",
+". . + @ @ $ % & - , ' ^ ( : 1 2 5 9 a c e g h i j j j j j i i g g f e c b a 0 9 8 5 5 5 5 7 7 7 7 7 7 7 7 5 5 5 5 5 5 5 5 6 8 9 9 0 a c c d e g g g i h h h h g g f e d c c b c b c c c d d e g g g h h h h h h g g f e d c c c b c c c c d e f g g g g g g f d c b 9 8 7 2 | < / ^ ) , - * & $ # @ + + . ",
+". . + @ @ # % & = , ! ] ( < | 4 5 9 a c e f g h i i h h h g f e d b a 0 9 6 5 7 4 2 2 1 1 | | | | | | | | 1 1 1 1 1 1 2 2 4 3 7 5 6 8 0 0 b c c e e f f f f e e d c b a 0 0 0 9 9 0 0 0 a b c c d e f g f f f e e d c c a a 0 0 0 0 0 0 a b c d d e f g g f f d d b 0 6 5 4 | < ( ] ~ ' ; * * % $ # @ + + ",
+". . + + @ @ $ & * - , ! ] ( < | 2 5 8 0 c d e g g g g g f e e c b 0 9 8 5 3 4 1 1 | [ < : : _ _ ( ( ( ( _ _ _ _ : : < < < } } | 1 2 4 7 5 6 9 0 a b c c c c c b b a 0 9 8 6 5 5 5 5 5 5 8 8 9 0 0 a c c c c c c b b 0 0 9 8 8 6 5 5 5 6 8 9 9 a b c d d f f f e d c b 0 8 5 3 1 [ ( / ^ ' , - * & $ # @ + + ",
+". . + + @ @ $ & * - , ! { ( : 1 2 5 8 0 b c d e e f e e d c a 0 8 6 5 3 1 1 } < _ ( ( / { ] ^ ] ] ] ] ] ] ] { { ] { { / ( ( _ : < } | 1 4 3 5 5 8 9 9 0 0 0 0 0 8 8 5 5 7 3 4 2 2 2 2 4 3 7 5 6 6 8 0 0 0 0 0 0 9 8 8 5 5 7 3 3 4 4 3 3 7 5 5 9 0 a b c d d e e d c c a 9 5 7 2 | < / ] ! ' - = * % $ # @ + ",
+". . + + @ # $ & & - , ! ] / : 1 4 5 6 0 a c c d d c c c b 0 9 6 5 3 1 | [ : ( ( ] ^ ~ ! ) ) ' ) ' ' ' ' ) ) ) ' ) ) ! ~ ^ ^ ] { ( ( : [ } 1 2 4 7 7 5 5 5 5 5 5 3 3 2 2 1 1 } | } } | | 1 1 2 4 3 7 5 5 5 5 5 5 5 3 3 2 2 1 | | | | | 1 1 4 7 5 6 0 0 b c d d e d c c a 0 8 5 4 | [ _ / ^ ) , - * & $ $ @ + ",
+". . + + @ # $ & & = , ! ] ( : | 2 7 8 9 a b c c c c a 0 0 8 5 3 2 1 [ : ( / ] ~ ! ' , , > ; ; - - - - - - - ; ; ; > > , , ' ! ! ^ { / ( _ < } } 1 1 1 2 2 2 1 1 1 | } [ < : _ _ ( _ _ : < < } | | 1 2 2 2 2 2 1 1 1 | | [ < : : : : < < } 1 1 3 5 6 9 0 b c c d d d c b 0 8 6 3 2 | < ( ] ! ) ; = * % $ $ @ ",
+". . + + @ # $ % & = , ! { / : | 2 7 5 9 0 a b b a a 0 9 6 5 4 1 } : ( / ] ~ ) ' > - - = * & & & % % % % & & & & * * = = - ; > , ) ! ~ ] { ( _ _ < [ } } } } [ [ < _ _ ( ( / / { { { / / / ( _ : : < [ } } } } } [ < : _ ( ( ( ( ( ( ( ( _ < } 1 4 5 5 9 0 a c c c c c b a 0 6 7 4 | } ( ( ] ) ' - * & % $ # ",
+". . + + @ # $ % & = , ! ] / : | 1 3 5 9 0 0 0 a 0 9 8 5 7 4 1 } : ( { ^ ) ' > - = * & % $ # # # # @ @ # # # # # $ $ % % & * = - ; > ' ! ~ ^ ] / ( ( ( ( ( ( ( ( ( / { ] ^ ^ ~ ~ ~ ~ ~ ^ ] ^ { / ( ( ( ( ( ( ( ( ( ( / { { ] ( ( ( ( ( / ( _ : [ 1 4 5 6 0 0 b c c c c c b 0 9 5 3 1 } < ( ] ^ ) ; = * & $ # ",
+". . + + @ # $ & & = , ! ] / : | 2 5 6 9 0 a a a a 0 9 5 3 1 [ : ( ] ~ ' , - = & % $ # @ @ + + + . . . . + + + + + @ @ # $ $ % & = - ; > , ) ! ~ ^ ] ] ] { ] ] ^ ^ ~ ! ) ' , , ' , ' , , ' ) ! ~ ^ ^ ] ] { { ] ] ^ ^ ~ ! ! | m p q q m 1 { / ( : [ 1 3 5 8 0 0 b c c c c b 0 0 8 5 3 1 } _ ( ^ ) ' ; = * % $ ",
+". . + + @ @ $ & & = , ! ] / : 2 a i m r s q t u v v w b 1 } : ( ] ~ ' > - = % % # @ + . . . . . + + @ # $ % & * = ; > , , ' ' ) ) ) ) ' ' , > , > ; ; - - - - - ; ; > , ' , ' ' ) ) ) ) ' ' , , > ' j x y z A x l ] ^ / ( < | 1 3 5 9 0 a b c c c c b a 8 6 3 2 } [ ( ] ^ ) ; = * % $ ",
+". . + + @ @ $ & * - , ) ] / : 6 t B C D E F G x H I J s 1 < ( / ~ ) , - * % # # + . . K K K K K K K K K K K K K . . + @ # $ % & & * = - ; ; ; > > > ; ; - - = = * * & & & & & * * = = - - ; ; > > > > ; ; - - = , s y L M N A w ^ ) ^ / _ < 1 4 7 6 0 a b c c c c b 0 9 8 7 4 1 [ _ / ] ) , - * & $ ",
+". . + @ @ # % & = , ! ^ / : 0 O P Q R S T U V y W X Y 1 _ ( ] ) , ; * % $ @ + . K K Z Z Z Z Z Z Z Z Z Z Z Z Z Z K K K . . + @ @ # $ % % & & * * * * * * * & & % % $ $ $ $ # $ $ $ $ % % & & * * * * * * * * & & % - ` z ...M y s ) ' ! ] ( : } 1 3 6 9 0 b c c c c c a 0 9 5 3 1 } < ( ] ! ' ; = * & ",
+". . + @ # $ % & = , ) ~ / : 9 +.P @.R #.T $.V z W X Y 1 ( / ~ ' > - & $ # + . K K Z Z %.%.%.%.%.%.%.%.%.%.%.Z Z Z Z K K K . + + @ @ # # $ $ $ $ $ $ $ $ # # # @ @ @ @ + + @ @ @ @ # # # $ $ $ $ $ $ $ $ $ $ # # * r z ...M z s ' > ' ~ { ( [ | 4 5 8 0 a c c c c c c 0 0 6 7 4 1 [ _ ] ^ ' , = * % ",
+". . + + # $ % & = > ' ~ / _ 9 &.*.Q F =.-.X ;.>.,.'.t | ( ] ! , - * % # @ . . K Z Z %.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.Z Z Z K K . . + + + @ @ @ @ @ @ + + + + . . . . . . . . . . . + + + @ @ @ @ @ @ @ @ + + + % o y ...M y ` > - , ! ] ( : } 2 7 6 0 a c c d d c b a 0 8 5 4 1 [ _ ( ] ) , - * & ",
+". . . + # # % & * > ' ~ ] ( 8 ).C !.~.{.].{.^./.H R r [ / ^ ) > - & % # + . K Z Z %.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.Z Z Z Z K K K . . . . . . . . . . . . . . . . . . . . . . . $ n y ...M y r ; - > ) ~ / _ } 1 3 6 9 0 b c c d c d a 0 8 5 3 2 | : / ^ ! ' - * & ",
+". . . . + @ # % & * > , ! ] ( 6 v (.D _.Q :.q q p p r 6 < _ / ^ ! ' = $ # + . . . + + . . Z Z Z K . . . K K . . . . . Z K K K + + @ @ @ . . @ # # # + . . + @ @ @ . K K @ @ @ @ @ + + @ # # # @ . K @ m y ...M y r - = ; ' ^ / < 1 3 5 9 0 b c d d d c c b 0 0 5 3 1 } : / ] ) ' ; = & ",
+". . . . @ @ # % & * > , ~ ] ( 5 Y <.[.@.}.s 9 6 5 7 4 | 1 g ` w s l 2 ; @ + . & [ g l l h 2 & Z * } c j h 9 / ^ b l l l a > Z Z > b m m m c ) ; | e j d [ * + * } d j c _ $ K K Z K , b m m m c ! ; 1 f j e | - + @ m A ...M y r - * - ' ~ _ 5 j q u u q m g d d d c c b 0 0 5 3 1 } : / ^ ! ' ; = & ",
+" . . + + @ # $ & * - , ! ] ( 5 q |.1.2.[.r 9 6 5 7 1 | 0 <.H 3.4.5.6.5 & + % 3 *.X >.7.8.B ( . , k !.I V 9.S (.O 0.7.A 7.^.a a ^.7.A 7.S r o !.I a.T *.0 { j !.b.;.H (.4 @ Z %. a ^.7.A 7.S o r Q 5.3.b.!.j , K + m A ...M A o = & - , ( d c.~.T X I G d.&.l f d c c b 0 0 5 3 1 } : / ] ) ' ; = & ",
+" . . + + @ @ $ % * = , ) ~ / 3 e.f.C !.d.&.s s e.n 8 } 3 O 5.g.h.i.9.:.( $ ( c.4.j.M h.k.t , - n ^.l.m.L n.o.p.q.r.M .L 7.k . . k 7.L .s.t.u.v.w.m.N x.y D :.=.y.m.z.A.B.c.^ K %.. k 7.L .s.C.@.0.D.j.N m.E.G l = Z + m A ...M A o = * - ^ e [.F.G.H.I.E.z $.R J.m e c b c 0 9 5 3 2 | : / ^ ! ' - * & ",
+" . . + + # # % & = > , ! { 4 ` K.(.[.2.2.E F J @.m [ < c }.p.A.L.M.x n ( r H o.N.s.y.d.| $ 5 u.I.s.........z.O.N .... .A l . . l A ...P.x.t.Q.M ....P.m.,.;.R.L ....P.S.T.5 %.. l A ...P.o.U.M.s.......L D.E 3 . . m A ...M A o * * ; 3 C V M.i.V.R.D.t.p.9.J K.j c c a 9 9 5 3 1 [ _ ( ] ' , = & & ",
+" . . . . @ @ $ % & * ; , ! ] 1 o O |.1.2.~.G v.5.=.s } _ [ r =.W.X.X.t.@.p _.Y.M N.Q.S h & > v Z.n.......P.N.N.N....... .A l . . l A ..... .z.s.P.......N.`.m.N P....... +U f . %.. l A .....M +L N.P.......`.V p - + l A ...M A o * * ~ w I M.A.S.y.B.a.>.z .+5.Q q d c 0 9 6 5 2 1 < _ ] ^ ' , = * % ",
+" . . . + + @ # % & & - , ' ^ } l &.++C D _.T.0.8.@+s | _ ( 4 c.9.o.`.m.A #.p.`.P. +4.O ! . < !.W.N...N.h.D.#+D.h.N..... .A l . . l A .....N $+l.V.L ......N M.E.$+N ....s.Z.j . %.. l A ..... .x.w.#+D.m.N...N.I.d._ @ l A ...M A o * = 1 1.W x.A.D.x C C ^.V Z.F.@+:.h a 0 8 5 3 2 } < ( ] ! ' ; = * & ",
+" . . + + @ # $ % & * ; , ! [ i Y :.%+[.@.].#.H J ` [ ( / / c Q C.X.z.x.g.m.N.s.D.2.4 + 9 &+*+P...m.;.*.v *.a.m..... .A l . . l A ...P.$+=.(.^.V.P...P.M.@+%+@+M.P... .>.l . %.. l A .....m.9.6.v 1.3.j...P.=+^.8 # l A ...M A o * - c G g.m.*+z *.j l *.X 4.k.&+(.k 0 9 6 5 4 1 [ _ / ^ ) ' - * & $ ",
+" . . . + @ $ % & & - , ) : g q +.B -+C P ;+_.}.k [ ( / ~ ( s /.$+z.L s. .N.=+v.m & Z . f $. +..N.I.d.4 ; 4 d.I.N... .A l . . l A ... .W O } >+W ... .W O [ O W ... .A l . %.. l A ...N.Y.[.2 ; 3 }.I.N...L.X e # l A ...M A o * ; k '.i.j.*+z D +.O d.X V F./.[.n 0 0 5 3 2 | < _ / ^ ' , - * & % ",
+" . . . + + @ @ $ % & = > ' ( d s v c.c.` i j m i 7 : / ] ~ ! 1 %+y j.s. .N.z.p.J.{ K Z . j 4.L .. .,+Y = K = Y ,+ ... .A l . . l A ... .y o = o y ... .y o = o y ... .A l . %.. l A ... .,.t = K = Y ,+ ...N V i $ l A ...M A o * ; o a.x.j.A.R..+F.X $.4.V $./.!.r 0 6 5 4 1 [ < ( ^ ! ' ; = * & $ ",
+" . . . + + @ # $ % & * ; , ( c r u :.O e 1 | | | < _ / ] ~ ) / q U O.L M N.j.F.r * Z Z . k .+s... .z ` # Z # ` z ... .A l . . l A ... .A m $ m A ... .A m $ m A ... .A l . %.. l A ... .z r # Z # ` z ...s..+j $ l A ...M A o * ; r 4.m.j.A.Q.R.D.'+p..+a.X /.;+o 0 5 5 2 1 [ ( / ^ ) , ; = & % $ ",
+" . . . + + @ $ % & * = , / b o p O &.c | [ < < _ ( / ] ! ) 1 %+A j.L M N.z.p.J.{ K Z . j V N .. .#+v - K = u ,+ ... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A ... .,+Y = K - v #+ ...N V j $ l A ...M A o * ; o 9.A.j.A.R..+F.'.b./.S J ~.-+l 9 5 7 2 | : ( / ^ ' , = * & % # ",
+" . . . @ @ # $ & * = > ] 0 m q +.&.c | | } [ [ _ ( ] ~ ( ` 0.M.`.n.X.L N.=+v.m & Z . e X L...N.H.!.7 - 4 }.I.N... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A ...N.I.}.2 - 7 !.H.N...L.X e # l A ...M A o * - j I Q.j.o.p.2.O v u u v t q o c 6 5 4 2 } : ( { ~ ' , = * & % # ",
+" . . . + @ @ # $ % & * > ] 0 m q &.+.m f h j l g 2 / ] ] b ;+#+h.L.M.p.M.L L D.2.4 + 8 ^.=+P...j.V P v *.;.m..... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A .....m.;.*.v P V j...P.=+^.6 # l A ...M A o * - a {.)+m.o.,.;+n a e o t Y q m b 6 5 3 1 } _ ( ] ^ ' ; = * & $ $ ",
+" . . . + @ @ # $ % & * > ] 0 m q +.++f.<.P ;+_.d.h ( { 1 :.F.S.X.i.F.}.I =+N. +4.O ! : }.I.N...N.m.D.#+w.h.N..... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A ..... .x.w.#+D.m.N... .Y.[._ @ l A ...M A o * = | -+,.A.*+H.q.[.:.f.D {.{.@.++h 6 5 4 2 } : ( { ^ ' , = * & $ # ",
+" . . . @ @ # $ & * = > ] 0 m q +.B *.2.F =.-.{.o : < o @+w.A.x.p.1.f |.z n.N.Q.S i * > t 4.n.......P.N. .N....... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A .....s.j.N .P.......L.;.q - @ m A ...M A o = = ~ r -.r.o.S.D.Z.U '.U F.5.{.c.f 8 5 7 2 } < ( / ^ ' > - & & % # ",
+" . . . + + @ $ % & * = , / b n p >+|.P @.].S T J r } b P .+S.O.I.T.g ! c R r. .s.y.}.1 % 5 _.Y.s.......P. +Q.n..... .A l . . l A ... .A m % m A ... .A m % m A ... .A l . %.. l A ...P.i.>.g.s.......N E.Q 3 @ @ m y ...M y r - = > 4 %+9.g.S.!+H.y.,+7.9.v.D w b 9 5 7 2 1 [ _ / ^ ' , - * & % $ ",
+" . . . + + @ # $ % & * ; ' ( c r Y :.%+[.@.R S T T.r 7 ).H D.i.M.X ).] % ! t $.x.M h.~+Y ' ; n =.w.j.L n.i.7.T W.s. .L 7.k . . l 7.L .L 7.l % l 7.L .L 7.l % l 7.L .L 7.k . %.+ m A ... .'+Q 0.Y.X.N h.t.J j - @ m >.L .N >.o - = > ^ c 6.'.#+D.D.t.z ;.-.Q ).g 0 0 6 5 4 1 } : / ] ! ' ; = * & # ",
+" . . . + + @ @ $ % & = > ' / 9 k s u >+B *.D E F !.l b B &+F.;.I -+5 ; % & 1 (.X A >.5.|.: # ! m 2.5.4.9.^.B &.0.7.A 7.^.b . . b #.7.A 7.#.c $ c #.7.A 7.#.c $ c #.7.A 7.^.b . Z + m A ... .z v s E X V I D j ' @ + # c S >.y >.S g ; - , ! ( c O E /.5.5.0.{+C t i c a 0 8 5 3 2 | < _ / ^ ' , - * & % ",
+" . . . @ @ # % & * - , ! ] < 4 5 0 d g j m n r k 5 4 f r w s m 7 ! * & % ; } i r o k 5 ; + # > 2 f l j 0 ( { c m m m c ' ' c m m m c ) + ) c n m m c ) + ) c m m m c ' K @ m y ... .y r ~ 4 g k f 1 ; @ @ @ @ ~ e r r r g / - ; , ~ ] : 5 j w Y v Y e.l f c c c 0 0 9 5 4 1 } _ / ] ) ' ; = & % ",
+" . . . + + @ # % * = - , ! ] / _ [ 1 1 4 3 3 3 4 4 1 [ < : ( / ^ ) > ; = = * * - = = = & $ $ $ % & & & & % # # % $ $ $ $ + + + + $ $ % % % @ @ # & & & & % @ @ @ $ $ $ $ $ + + . $ n y ... .y r * % * * * & % $ % $ % % - - ; ; , ; , ' ) ^ / _ } 2 5 8 0 b c c c d c c a 0 9 6 3 4 1 [ ( ] ^ ) ; = * & ",
+" . . . + + @ # $ & & = , ' ~ ] ( : [ | 1 4 4 3 4 4 1 1 } < ( / ] ~ ' , ; ; - = * * & & & % % % % % % $ $ $ # # # @ @ @ + + + + + + @ @ @ @ # # # # $ $ $ # # # # @ @ @ + + + + + + % r y ... .z r = $ % % % % % % & & & & * * = = ; > , ) ~ { ( : [ 1 3 5 8 0 a c c d c c c a a 9 6 3 1 } _ ( ] ) , - * & ",
+" . . . + @ # # $ & * - , ) ^ / ( : | 1 4 3 7 5 7 7 3 2 1 } < ( / ] ^ ! ) ' , , > > ; ; ; - - - - = = = * * * & % % % $ $ $ # # $ $ $ $ % % & & & * * * * * & & & % % $ $ # # # # # = r z ... .z s > = = = - - - - - ; ; ; > > , , ) ! ~ ^ / ( : [ 1 4 7 8 0 a c d d e e d d c a 9 8 7 1 } < ( ] ! ' - * * ",
+" . . . . + @ $ % & * ; , ! ] ( : [ | 2 4 7 5 5 5 5 7 4 2 1 } : _ ( { ] ^ ~ ! ) ) ) ' ' ' ' ' ' ' , , , > > ; - - = = * * & & & & * * * = = - - ; ; ; ; ; ; ; - - = * * & & & & & & ; s z ... .z e.! > , , , ' ' ' , ' ' ' ) ) ! ! ^ ^ { ( ( : [ | 2 7 5 9 a b c e f f f f d c c a 9 5 4 1 < _ ] ~ ' ; * * ",
+" . . + + @ # % * = > , ~ { ( : } 1 4 7 5 5 8 8 6 5 5 3 4 1 | [ : _ ( / / { ] ] ] ^ ^ ^ ^ ^ ^ ~ ~ ~ ! ) ) ' , , , > > ; ; ; ; ; ; ; > , , , , ' ' ' ' ' ' ' , , , > ; ; - - - - - ' w y L .N y q ] ! ! ~ ~ ^ ^ ^ ^ ^ ^ ^ ] ] { { / ( ( : < } 1 2 7 5 9 0 b d e f g g g g f e c b 0 6 3 2 } _ ( ] ' , - * ",
+" . . + + @ # $ % & = > ' ~ { _ [ | 1 3 5 8 8 8 9 9 8 6 5 5 3 2 1 | } [ < : : _ _ ( ( ( ( ( ( ( ( ( / / { ] ] ^ ~ ! ! ) ' ' ' ' ' ' ) ) ! ~ ^ ^ ] ] ^ ^ ^ ] ^ ^ ~ ! ) ' , , > > > > ! k x z p.z /.n ( { / / ( ( ( ( ( ( ( ( ( _ : : < [ } } 1 2 4 7 6 9 0 b c d f g g h g g g e c b 0 8 3 1 } : / ^ ) , - * ",
+" . . + + @ # $ & & - , ) ~ { _ [ 1 3 7 6 8 0 0 0 0 0 9 8 6 5 7 7 4 2 1 1 1 | | } } } } } } } [ [ < < : : _ ( ( / / { ] ] ^ ^ ^ ^ ^ ] { / ( / ( ( ( ( ( ( ( ( / / { ] ^ ~ ! ~ ! ! ~ ~ 1 n t Y u r 5 : _ : < [ [ } } } [ } } } | 1 1 1 1 2 4 7 5 5 9 0 a c c e f g g h i h g g e d c a 8 7 2 | < ( ] ! ' ; * ",
+" . . + + @ # $ % * = , ) ~ / _ [ 1 3 5 6 0 0 0 b b b a 0 0 9 8 6 5 5 5 7 7 7 7 3 3 4 3 3 3 4 4 4 2 1 1 1 | } } < : : _ ( ( ( ( ( ( _ : : < [ } | } } } } } } < : : _ ( / / / { { / ( ( [ } } 1 1 | 1 1 1 1 2 4 4 3 3 3 3 3 3 7 3 7 7 5 6 6 9 0 0 a c c e g g h i j j i i h g f d c 0 8 5 4 1 < ( ] ! ' - * ",
+" . . + + @ @ $ % * = , ' ^ / _ [ 2 3 5 8 0 a b c c c c c b b a a 0 0 0 9 9 9 9 9 8 8 9 9 8 8 8 6 5 6 5 5 7 3 4 2 1 1 | } | } } | } | 1 1 1 2 4 4 3 3 3 3 4 4 2 1 1 } [ [ : : _ _ : < [ [ | | 1 2 3 7 5 5 6 6 8 8 9 9 9 9 9 9 0 9 0 0 0 0 a b c c d e f g h i j j j j j i i g f e c a 0 5 4 1 [ ( ] ! ' - * ",
+" . . + + @ @ $ % * = , ) ^ / _ } 2 7 5 8 0 b c d d e e e d d d c c c c c c c b c c c c b b b a b a 0 0 0 9 8 6 5 5 5 3 4 3 4 4 3 4 3 7 5 5 5 6 8 8 8 8 6 8 5 5 7 3 4 2 1 1 | | | | 1 1 2 4 3 5 5 6 9 0 0 0 a a b b c c b c c c c c c d d d e f g g h h i j j j k k j j j j g g e c b 8 5 3 1 [ ( ] ! ' - * ",
+" . . + + @ # $ & * - , ) ^ / : | 1 7 5 9 0 c d e f f g g g g g f f g f g g f g g f f f f f f f f e e d c c b b a 0 0 9 8 6 8 8 6 8 9 9 0 0 0 a b b b b a a 0 0 8 6 5 5 7 3 4 4 4 4 3 7 5 6 8 9 0 a b c c d e f f f g g f g g g g g g h g h i i i j j j k k l l l l l k j j h f f c 0 9 5 4 | [ ( ] ) ' - * ",
+" . . + + @ # $ & & - , ) ^ / : [ 2 7 5 0 0 c e f g g h h h i i h i i i i i i i i i i i i i j i i i h g g f f e d c c c b b b b b b c c d d d e f f e e e d d c c a 0 0 9 6 6 6 6 6 8 8 0 a a c c e f g g g h i i i j j j j j j j j j j j j k k k k l l m m m m l l m k j j g g e c 0 8 7 2 } : / ^ ) ' - * ",
+" . . + + @ # $ % & = , ' ~ / _ [ 1 3 5 9 a c d g g h i j j j j j k k k k l l l l l m m m m l l l k k j j j j i h g g g g f e e f g g g g g h i i i i i h h g g f d d c b a 0 a a 0 b b c c e f g g i j j k k k l l l m m m m m m m m m m m m m m m m m n m m m m m k k j i g f c b 0 6 5 1 | _ ( ^ ) ' - & ",
+" . . + + @ # % * = , , ^ { _ [ 1 4 5 9 a c e g h i j j k l l l m m m m m m m m n m m m m m n m m m m l m l k k j j j i j i i j i j j j k j k k k k k j j j i h g f f e d c d d c d e f g g h i j k k l m m m m n m n n m n n n n o n n n o n n n n n n n n m m m k k i h g e c a 0 5 7 2 [ : / ] ) , - * ",
+" . . . . + @ $ % * * ; ' ~ ] ( < | 2 5 8 0 c d g h j j k l l m m n n n n o o o o o o r o o r r o o o o n m n n m m m l l l k k l l m l m m m m m m m m m m l k j j i i g g g g g g g g h i j k l l m m n n n o o r o r r r r r r r r r o o r r r o o o o m m m m k j j i g f d b 0 8 5 4 | : ( { ! ) , = * ",
+" . . . + @ # # % & * - , ) ^ / _ } 2 5 8 0 b d f g i j l l m m m n o o o o o r r o r r r r r r r o o o o o o o n n m n n n m m n m m n n n n n n n n m m m m l l k j j j i i i i i j j j k k m m m m n o o o r r r r r r r r r r r r o o r o o o n n n m m m m k j j h g g e c a 9 5 3 1 [ : ( ] ! , ; = & ",
+" . . . + + @ # $ & * - > ) ^ / _ < 1 3 5 9 b c e g h j l l m m m n n n o o o o o o o n o n n n n n n n n o n n n n o o o o n n o o o o n o n n n n n n n m m m m l k k k j j j j j k k l l m l m m m m m m n m n m n n n n o o o o n n n m n m m m m m m l k j j h h g f e c 0 9 8 7 2 1 < ( { ^ ) , - * & ",
+" . . + + + @ $ % * = ; ' ! ] ( < | 2 7 8 0 b d f h i j k m m n m m n m m m m m n m m m m m m m m m m m n m n m n n o n o n n o n n n n n n n m n m m m m m m m l l l l l l l l l l l l l l m l m m m m m m m m m m m m m m m m m l m l m l m k k l k k j j j h g g e c b a 9 6 5 4 1 } : ( { ) ) ; = * & ",
+" . . . @ # # % * * - , ' ^ ( : [ 1 3 5 8 0 c d g g j j k k l m l l m l l m k l l k k l l l k k l k l m l m m m m n m m n n m m m m m m m m l l m l l k l l l m l l l m l l l l l l l l m l m l k k l k k j k j k l j j j j j j j j j j j j i j i h h g g f f e c b b 0 9 5 7 4 1 } < ( ] ! ! ' - * * % ",
+" . . . + + @ # $ & * = ; ) ! ^ ( : | 1 3 8 0 b c e g h i j j j j j k k k j i j j i h i h h h g i h i j i j j j j k k k k k k l k k l k j k j j j j j j j j j j k l k l l l l l l l k k k j k j j j i i i i h g g g h g g g h h h h g g g g g g g f e e d c c c b 0 0 9 6 7 4 1 | < < ( { ~ ) ' - = * & $ ",
+" . . . + + + @ # $ * * - , ) ^ { ( [ | 4 5 6 0 b c f f g g i i i h h g g g g f e e e f d d d e d f e g f f g g g g i h i i i i j h g g g g g g g g g g h g h i i j k j k k l m k k j j j j h g g g g f e e e c d c d c c c d d d d d c c c c c b b c a 0 0 9 0 6 6 5 5 4 2 1 | < _ ( { ~ ) ) ; = * & % # ",
+" . . . + + @ # $ & * * ; ' ! ] ( : [ 1 4 5 8 0 a c c d e g g f g e e d d c b a a a 0 0 0 0 0 0 0 a 0 b b c c c d c d e e e e e d d c c c c c c c d c c e g f h g h j j j j j j j j h h g f f d c b b a 0 0 0 0 0 0 9 9 9 9 0 0 0 0 0 9 9 0 8 8 8 9 5 5 6 5 5 7 3 2 1 | | < : _ / { ~ ! ' ; - * * % $ # ",
+" . . . + + + @ # % & * = ; ) ~ ] ( _ } 1 3 5 9 9 a b c c d c c c c c 0 0 0 9 8 8 6 6 5 6 5 5 6 5 6 6 6 8 8 0 0 0 0 0 0 b b 0 0 0 0 0 0 9 9 9 9 9 9 a a b b c e d f g g h h h h g g e e c c b a 0 0 9 6 5 5 6 7 5 5 5 5 5 5 7 7 7 7 7 7 3 3 3 3 3 3 2 2 2 2 1 1 1 [ [ < _ _ / / ^ ~ ! ' ; = * * % $ $ # ",
+" . . + + @ # $ % & * ; ' ) ^ ] ( : } 2 3 5 5 9 0 a 0 0 a 0 0 9 8 6 6 5 5 3 3 3 2 2 2 2 2 2 2 2 2 3 3 3 7 5 5 5 5 6 5 5 6 5 5 5 5 5 5 5 5 5 7 5 5 6 8 9 0 a c c e f g f f g d c c b a 0 9 8 5 5 7 3 4 2 2 2 1 1 1 1 1 1 1 1 1 1 1 | | | 1 1 | 1 } } [ [ [ : : _ ( / / { ^ ! ! ) , ; - * * % $ # @ @ ",
+" . . . + + @ # $ $ & * * ; ' ) ] { ( : } 1 4 5 5 6 9 8 8 9 6 6 5 7 3 3 2 2 | 1 } [ [ [ } } } [ [ } [ } 1 1 | 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 2 2 4 7 5 5 6 9 a a b c c c c b a a 0 8 6 5 7 4 1 | | } [ [ [ < [ : : : : : : : : : : _ _ _ _ _ _ : _ _ ( ( { { { ] ~ ! ! ! ' , ; - * = & % $ # @ @ @ ",
+" . . . + + + @ # % & * = ; ) ! ] { ( : } 1 2 4 7 7 5 5 7 7 4 4 1 1 | [ [ : _ _ ( ( / ( / / ( ( ( _ ( _ _ _ _ : : : : : : : : : : _ _ _ : : < [ [ | | 1 4 3 5 6 8 9 0 0 0 0 9 8 5 5 3 2 1 | | < < _ _ ( / / { / { { { { / / / / / / / { { { { { ] { ^ ~ ~ ! ! ! ! ) ' , ; - = * = * & % $ $ @ @ @ . ",
+" . . . . . + @ # $ % * * - ; ' ! ] / ( < [ | 1 1 2 1 2 1 2 1 | [ [ : _ / / { { ] ^ ^ ~ ~ ~ ~ ~ ^ ^ ^ ] { / { / / { { { { { / / / / / / { / / / _ _ < [ } 1 4 3 7 5 5 5 5 5 5 7 3 4 1 } [ < _ ( / { ] { ~ ~ ! ~ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ) ) ) ' ) ' , > ; ; = = * = * & % $ $ # # @ + . + ",
+" . . . . . @ @ # $ % & * = , ) ! ] { ( _ < < [ | | | [ < [ : ( / { { ^ ! ! ! ) ) ) ' ' ' ' ' ) ' ) ) ) ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ~ { { / _ _ < | | 1 1 4 3 3 4 1 1 | [ < _ ( { / ~ ! ! ! ) ) ' , , > > > > > > > > > > > > > > > > > ; ; ; ; - - - = = = * * & % % $ $ # @ @ @ + . . . ",
+" . . + + + # # $ % & * - , ) ! ~ { / ( ( _ _ < : _ ( _ / { { ~ ! ! ) , > ; - - - = - = - - - ; ; ; ; > > ; > > > > > > ; ; ; ; > > , ' ) ! ! ^ { / ( _ < < [ | | | | [ < < _ ( { { ~ ! ) ' , ; ; ; - - - = = = = = = = = = = = = = = = = = * * * = = * * * & & % % $ $ # # @ @ + @ + . . . ",
+" . . + + + @ # $ & * * - > ' ! ~ ] { { / / / / { { ] ^ ! ! ' ' ; - - * * = * * * * * * * * * = = = * * = = = = = = = * * * = = = - - ; > ' ) ) ~ ] { / ( _ _ _ _ _ _ ( { { ] ~ ! ' , ; - = = * * & * & & & & & & & & & & & & & & & & & & & & % % % % % $ $ $ $ # # # @ @ + @ + . + . . . ",
+" . . . . . + @ @ # $ & * * - ; ' ) ! ! ~ ^ ] ] ^ ~ ! ) ) ' , ; - = * * * % % % % % % % % % % % % % % % & & & & & & & & & & & & & & & * * = - ; , ' ! ! ~ ] { { { { { { ] ~ ! ! ) , ; - * * & & & % % % $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ # # # # # # @ @ @ @ + @ + + . + . . . . ",
+" . . . . . + @ @ # $ & * * = - ; ' ) ) ! ! ! ! ) ' ' > - = = = * & $ $ $ # # # # # # # # # # # # # # # $ $ $ $ $ $ $ $ $ $ $ $ $ % % & * = = = - > , ) ! ) ! ! ! ! ) ) ) , > - = * * & % % # # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + + + + + + + . . . . . . . ",
+" . . . . + @ @ # $ % & * * = - ; ; > > > > ; ; - = = = * & % $ # # @ @ @ @ @ + + + + + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # $ $ % & & * * - ; ; > , ' ' ' ' , > ; ; = * * & % % $ # # @ @ @ + + + + + + + + + + + + + + + + + + + + + + + + + + + . . . . + . . . . . ",
+" . . + . + @ @ $ $ % & & * * = = - - - - = = * * & & % # # # @ @ + + + + . . . . . . . + + + + + + + + + + + + + + + + + + @ @ # # $ % % & * * * = - - ; ; - - = * * * & % % $ # @ @ + + + + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
+" . . . + . + + @ # # $ % % & * * * * * * & * & % % $ $ # @ @ @ + + + . . . . . . . . . . . . . . . . . . . . . . . . . + + + + @ @ # # $ % % & * * = * * * * = * * & % % $ # # @ @ + + + + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "};
diff --git a/vcl/qa/cppunit/graphicfilter/filters-test.cxx b/vcl/qa/cppunit/graphicfilter/filters-test.cxx new file mode 100644 index 000000000..26f743cfa --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/filters-test.cxx @@ -0,0 +1,181 @@ +/* -*- 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 <unotest/filters-test.hxx> +#include <test/bootstrapfixture.hxx> + +#include <comphelper/fileformat.h> + +#include <vcl/graphicfilter.hxx> +#include <tools/stream.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +using namespace ::com::sun::star; + +/* Implementation of Filters test */ + +class VclFiltersTest : + public test::FiltersTest, + public test::BootstrapFixture +{ + std::unique_ptr<GraphicFilter> mpGraphicFilter; +public: + VclFiltersTest() : + BootstrapFixture(true, false), + mpGraphicFilter(new GraphicFilter(false)) + {} + + virtual bool load(const OUString &, + const OUString &rURL, const OUString &, + SfxFilterFlags, SotClipboardFormatId, unsigned int) override; + + void checkExportImport(const OUString& aFilterShortName); + + /** + * Ensure CVEs remain unbroken + */ + void testCVEs(); + + void testScaling(); + void testExportImport(); + + CPPUNIT_TEST_SUITE(VclFiltersTest); + CPPUNIT_TEST(testCVEs); + CPPUNIT_TEST(testScaling); + CPPUNIT_TEST(testExportImport); + CPPUNIT_TEST_SUITE_END(); +}; + +bool VclFiltersTest::load(const OUString &, + const OUString &rURL, const OUString &, + SfxFilterFlags, SotClipboardFormatId, unsigned int) +{ + SvFileStream aFileStream(rURL, StreamMode::READ); + Graphic aGraphic; + bool bRetval(ERRCODE_NONE == mpGraphicFilter->ImportGraphic(aGraphic, rURL, aFileStream)); + + if (!bRetval) + { + // if error occurred, we are done + return bRetval; + } + + // if not and we have an embedded Vector Graphic Data, trigger it's interpretation + // to check for error. Graphic with VectorGraphicData (Svg/Emf/Wmf) load without error + // as long as one of the three types gets detected. Thus, cycles like load/save in + // other format will work (what may be wanted). For the test framework it was indirectly + // intended to trigger an error when load in the sense of deep data interpretation fails, + // so we need to trigger this here + if (aGraphic.getVectorGraphicData()) + { + if (aGraphic.getVectorGraphicData()->getRange().isEmpty()) + { + // invalid file or file with no content + return false; + } + } + + return true; +} + +void VclFiltersTest::testScaling() +{ + for (BmpScaleFlag i = BmpScaleFlag::Default; i <= BmpScaleFlag::BiLinear; i = static_cast<BmpScaleFlag>(static_cast<int>(i) + 1)) + { + Bitmap aBitmap( Size( 413, 409 ), 24 ); + BitmapEx aBitmapEx( aBitmap ); + + fprintf( stderr, "scale with type %d\n", int( i ) ); + CPPUNIT_ASSERT( aBitmapEx.Scale( 0.1937046, 0.193154, i ) ); + Size aAfter( aBitmapEx.GetSizePixel() ); + fprintf( stderr, "size %ld, %ld\n", aAfter.Width(), aAfter.Height() ); + CPPUNIT_ASSERT( labs (aAfter.Height() - aAfter.Width()) <= 1 ); + } +} + +void VclFiltersTest::checkExportImport(const OUString& aFilterShortName) +{ + Bitmap aBitmap( Size( 100, 100 ), 24 ); + aBitmap.Erase(COL_WHITE); + + SvMemoryStream aStream; + aStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + + css::uno::Sequence< css::beans::PropertyValue > aFilterData( 3 ); + aFilterData[ 0 ].Name = "Interlaced"; + aFilterData[ 0 ].Value <<= sal_Int32(0); + aFilterData[ 1 ].Name = "Compression"; + aFilterData[ 1 ].Value <<= sal_Int32(1); + aFilterData[ 2 ].Name = "Quality"; + aFilterData[ 2 ].Value <<= sal_Int32(90); + + sal_uInt16 aFilterType = mpGraphicFilter->GetExportFormatNumberForShortName(aFilterShortName); + mpGraphicFilter->ExportGraphic( aBitmap, OUString(), aStream, aFilterType, &aFilterData ); + + CPPUNIT_ASSERT(aStream.Tell() > 0); + + aStream.Seek( STREAM_SEEK_TO_BEGIN ); + + Graphic aLoadedGraphic; + mpGraphicFilter->ImportGraphic( aLoadedGraphic, OUString(), aStream ); + + BitmapEx aLoadedBitmapEx = aLoadedGraphic.GetBitmapEx(); + Size aSize = aLoadedBitmapEx.GetSizePixel(); + + CPPUNIT_ASSERT_EQUAL(100L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(100L, aSize.Height()); +} + +void VclFiltersTest::testExportImport() +{ + fprintf(stderr, "Check ExportImport JPG\n"); + checkExportImport("jpg"); + fprintf(stderr, "Check ExportImport PNG\n"); + checkExportImport("png"); + fprintf(stderr, "Check ExportImport BMP\n"); + checkExportImport("bmp"); +} + +void VclFiltersTest::testCVEs() +{ +#ifndef DISABLE_CVE_TESTS + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/wmf/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/emf/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/png/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/jpg/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/gif/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/bmp/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/xbm/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/xpm/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/svm/")); +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFiltersTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/jpeg/JpegReaderTest.cxx b/vcl/qa/cppunit/jpeg/JpegReaderTest.cxx new file mode 100644 index 000000000..a5c0d9e95 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/JpegReaderTest.cxx @@ -0,0 +1,167 @@ +/* -*- 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 <unotest/bootstrapfixturebase.hxx> +#include <vcl/graphicfilter.hxx> +#include <bitmapwriteaccess.hxx> +#include <tools/stream.hxx> + +static OUString const gaDataUrl("/vcl/qa/cppunit/jpeg/data/"); + +class JpegReaderTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + + Graphic loadJPG(const OUString& aURL); + +public: + void testReadRGB(); + void testReadGray(); + void testReadCMYK(); + + CPPUNIT_TEST_SUITE(JpegReaderTest); + CPPUNIT_TEST(testReadRGB); + CPPUNIT_TEST(testReadGray); + CPPUNIT_TEST(testReadCMYK); + CPPUNIT_TEST_SUITE_END(); +}; + +static int deltaColor(BitmapColor aColor1, BitmapColor aColor2) +{ + int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed()); + int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen()); + int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue()); + + return std::max(std::max(deltaR, deltaG), deltaB); +} + +static bool checkRect(Bitmap& rBitmap, int aLayerNumber, long nAreaHeight, long nAreaWidth, Color aExpectedColor, int nMaxDelta) +{ + BitmapScopedWriteAccess pAccess(rBitmap); + + long nWidth = std::min(nAreaWidth, pAccess->Width()); + long nHeight = std::min(nAreaHeight, pAccess->Height()); + + long firstX = 0 + aLayerNumber; + long firstY = 0 + aLayerNumber; + + long lastX = nWidth - 1 - aLayerNumber; + long lastY = nHeight - 1 - aLayerNumber; + + int delta; + + for (long y = firstY; y <= lastY; y++) + { + Color aColorFirst = pAccess->GetPixel(y, firstX); + delta = deltaColor(aColorFirst, aExpectedColor); + if (delta > nMaxDelta) + return false; + + Color aColorLast = pAccess->GetPixel(y, lastX); + delta = deltaColor(aColorLast, aExpectedColor); + if (delta > nMaxDelta) + return false; + } + for (long x = firstX; x <= lastX; x++) + { + Color aColorFirst = pAccess->GetPixel(firstY, x); + delta = deltaColor(aColorFirst, aExpectedColor); + if (delta > nMaxDelta) + return false; + + Color aColorLast = pAccess->GetPixel(lastY, x); + delta = deltaColor(aColorLast, aExpectedColor); + if (delta > nMaxDelta) + return false; + } + return true; +} + +static int getNumberOfImageComponents(const Graphic& rGraphic) +{ + GfxLink aLink = rGraphic.GetGfxLink(); + SvMemoryStream aMemoryStream(const_cast<sal_uInt8*>(aLink.GetData()), aLink.GetDataSize(), + StreamMode::READ | StreamMode::WRITE); + GraphicDescriptor aDescriptor(aMemoryStream, nullptr); + CPPUNIT_ASSERT(aDescriptor.Detect(true)); + return aDescriptor.GetNumberOfImageComponents(); +} + +Graphic JpegReaderTest::loadJPG(const OUString& aURL) +{ + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + return aGraphic; +} + +void JpegReaderTest::testReadRGB() +{ + Graphic aGraphic = loadJPG(getFullUrl("JPEGTestRGB.jpeg")); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + Size aSize = aBitmap.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Height()); + + int nMaxDelta = 1; // still acceptable color error + CPPUNIT_ASSERT(checkRect(aBitmap, 0, 8, 8, Color(0xff, 0xff, 0xff), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 1, 8, 8, Color(0xff, 0x00, 0x00), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 2, 8, 8, Color(0x00, 0xff, 0x00), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 3, 8, 8, Color(0x00, 0x00, 0xff), nMaxDelta)); + + CPPUNIT_ASSERT_EQUAL(3, getNumberOfImageComponents(aGraphic)); +} + +void JpegReaderTest::testReadGray() +{ + Graphic aGraphic = loadJPG(getFullUrl("JPEGTestGray.jpeg")); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + Size aSize = aBitmap.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Height()); + + aBitmap.Convert(BmpConversion::N24Bit); // convert to 24bit so we don't need to deal with palette + + int nMaxDelta = 1; + CPPUNIT_ASSERT(checkRect(aBitmap, 0, 8, 8, Color(0xff, 0xff, 0xff), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 1, 8, 8, Color(0x36, 0x36, 0x36), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 2, 8, 8, Color(0xb6, 0xb6, 0xb6), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 3, 8, 8, Color(0x12, 0x12, 0x12), nMaxDelta)); + + CPPUNIT_ASSERT_EQUAL(1, getNumberOfImageComponents(aGraphic)); +} + +void JpegReaderTest::testReadCMYK() +{ + Graphic aGraphic = loadJPG(getFullUrl("JPEGTestCMYK.jpeg")); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + Size aSize = aBitmap.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Height()); + + int maxDelta = 1; + CPPUNIT_ASSERT(checkRect(aBitmap, 0, 8, 8, Color(0xff, 0xff, 0xff), maxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 1, 8, 8, Color(0xff, 0x00, 0x00), maxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 2, 8, 8, Color(0x00, 0xff, 0x00), maxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 3, 8, 8, Color(0x00, 0x00, 0xff), maxDelta)); + + CPPUNIT_ASSERT_EQUAL(4, getNumberOfImageComponents(aGraphic)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(JpegReaderTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/jpeg/JpegWriterTest.cxx b/vcl/qa/cppunit/jpeg/JpegWriterTest.cxx new file mode 100644 index 000000000..b4d9d2460 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/JpegWriterTest.cxx @@ -0,0 +1,105 @@ +/* -*- 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 <unotest/bootstrapfixturebase.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/bitmapaccess.hxx> +#include <tools/stream.hxx> + +static OUString const gaDataUrl("/vcl/qa/cppunit/jpeg/data/"); + +class JpegWriterTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + + BitmapEx load(const OUString& aURL); + BitmapEx roundtripJPG(const BitmapEx& bitmap); + BitmapEx roundtripJPG(const OUString& aURL); + +public: + void testWrite8BitGrayscale(); + void testWrite8BitNonGrayscale(); + + CPPUNIT_TEST_SUITE(JpegWriterTest); + CPPUNIT_TEST(testWrite8BitGrayscale); + CPPUNIT_TEST(testWrite8BitNonGrayscale); + CPPUNIT_TEST_SUITE_END(); +}; + +BitmapEx JpegWriterTest::load(const OUString& aURL) +{ + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + return aGraphic.GetBitmapEx(); +} + +BitmapEx JpegWriterTest::roundtripJPG(const OUString& aURL) { return roundtripJPG(load(aURL)); } + +BitmapEx JpegWriterTest::roundtripJPG(const BitmapEx& bitmap) +{ + SvMemoryStream stream; + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 exportFormatJPG = rFilter.GetExportFormatNumberForShortName(JPG_SHORTNAME); + Graphic aExportGraphic(bitmap); + ErrCode bResult = rFilter.ExportGraphic(aExportGraphic, "memory", stream, exportFormatJPG); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + stream.Seek(0); + Graphic aImportGraphic; + sal_uInt16 importFormatJPG = rFilter.GetImportFormatNumberForShortName(JPG_SHORTNAME); + bResult = rFilter.ImportGraphic(aImportGraphic, "memory", stream, importFormatJPG); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + return aImportGraphic.GetBitmapEx(); +} + +void JpegWriterTest::testWrite8BitGrayscale() +{ + Bitmap bitmap = roundtripJPG(getFullUrl("8BitGrayscale.jpg")).GetBitmap(); + Bitmap::ScopedReadAccess access(bitmap); + const ScanlineFormat format = access->GetScanlineFormat(); + // Check that it's still 8bit grayscale. + CPPUNIT_ASSERT_EQUAL(ScanlineFormat::N8BitPal, format); + CPPUNIT_ASSERT(bitmap.HasGreyPalette8Bit()); + // Check that the content is valid. + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, access->Width() - 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(access->Height() - 1, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), + access->GetColor(access->Height() - 1, access->Width() - 1)); +} + +void JpegWriterTest::testWrite8BitNonGrayscale() +{ + Bitmap bitmap = roundtripJPG(getFullUrl("8BitNonGrayscale.gif")).GetBitmap(); + Bitmap::ScopedReadAccess access(bitmap); + const ScanlineFormat format = access->GetScanlineFormat(); + // Check that it's still 8bit grayscale. + CPPUNIT_ASSERT_EQUAL(ScanlineFormat::N8BitPal, format); + // The original image has grayscale palette, just with entries in a different order. + // Do not check for grayscale 8bit, the roundtrip apparently fixes that. What's important + // is the content. + CPPUNIT_ASSERT(bitmap.HasGreyPaletteAny()); + // CPPUNIT_ASSERT(bitmap.HasGreyPalette8Bit()); + // Check that the content is valid. + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, access->Width() - 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(access->Height() - 1, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), + access->GetColor(access->Height() - 1, access->Width() - 1)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(JpegWriterTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg b/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg Binary files differnew file mode 100644 index 000000000..91541e4a8 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg diff --git a/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif b/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif Binary files differnew file mode 100644 index 000000000..295310949 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg Binary files differnew file mode 100644 index 000000000..81cca025e --- /dev/null +++ b/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg Binary files differnew file mode 100644 index 000000000..014825f42 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg Binary files differnew file mode 100644 index 000000000..3cfe1dda2 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg diff --git a/vcl/qa/cppunit/lifecycle.cxx b/vcl/qa/cppunit/lifecycle.cxx new file mode 100644 index 000000000..a4a3f5d9e --- /dev/null +++ b/vcl/qa/cppunit/lifecycle.cxx @@ -0,0 +1,357 @@ +/* -*- 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 <vcl/wrkwin.hxx> +#include <vcl/edit.hxx> +#include <vcl/toolkit/button.hxx> +#include <vcl/toolkit/combobox.hxx> +#include <vcl/toolkit/dialog.hxx> +#include <vcl/toolkit/field.hxx> +#include <vcl/virdev.hxx> +#include <vcl/tabctrl.hxx> +#include <vcl/layout.hxx> +#include <vcl/scheduler.hxx> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +class LifecycleTest : public test::BootstrapFixture +{ + void testWidgets(vcl::Window *pParent); + +public: + LifecycleTest() : BootstrapFixture(true, false) {} + + void testCast(); + void testVirtualDevice(); + void testMultiDispose(); + void testIsolatedWidgets(); + void testParentedWidgets(); + void testChildDispose(); + void testPostDispose(); + void testFocus(); + void testLeakage(); + void testToolkit(); + + CPPUNIT_TEST_SUITE(LifecycleTest); + CPPUNIT_TEST(testCast); + CPPUNIT_TEST(testVirtualDevice); + CPPUNIT_TEST(testMultiDispose); + CPPUNIT_TEST(testIsolatedWidgets); + CPPUNIT_TEST(testParentedWidgets); + CPPUNIT_TEST(testChildDispose); + CPPUNIT_TEST(testPostDispose); + CPPUNIT_TEST(testFocus); + CPPUNIT_TEST(testLeakage); + CPPUNIT_TEST(testToolkit); + CPPUNIT_TEST_SUITE_END(); +}; + +// A compile time sanity check +void LifecycleTest::testCast() +{ + ScopedVclPtrInstance< PushButton > xButton( nullptr, 0 ); + ScopedVclPtr<vcl::Window> xWindow(xButton); + + ScopedVclPtrInstance< MetricField > xField( nullptr, 0 ); + ScopedVclPtr<SpinField> xSpin(xField); + ScopedVclPtr<Edit> xEdit(xField); + +// the following line should NOT compile +// VclPtr<PushButton> xButton2(xWindow); +} + +void LifecycleTest::testVirtualDevice() +{ + VclPtr<VirtualDevice> pVDev = VclPtr< VirtualDevice >::Create(); + ScopedVclPtrInstance< VirtualDevice > pVDev2; + VclPtrInstance<VirtualDevice> pVDev3; + VclPtrInstance<VirtualDevice> pVDev4(DeviceFormat::BITMASK); + CPPUNIT_ASSERT(!!pVDev && !!pVDev2 && !!pVDev3 && !!pVDev4); + pVDev.disposeAndClear(); + pVDev4.disposeAndClear(); +} + +void LifecycleTest::testMultiDispose() +{ + VclPtrInstance<WorkWindow> xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + xWin->disposeOnce(); + xWin->disposeOnce(); + xWin->disposeOnce(); + CPPUNIT_ASSERT(!xWin->GetWindow(GetWindowType::Parent)); + CPPUNIT_ASSERT(!xWin->GetChild(0)); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0), xWin->GetChildCount()); +} + +void LifecycleTest::testWidgets(vcl::Window *pParent) +{ + { + ScopedVclPtrInstance< PushButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< OKButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< CancelButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< HelpButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + + // Some widgets really insist on adoption. + if (pParent) + { + { + ScopedVclPtrInstance< CheckBox > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< Edit > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< ComboBox > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< RadioButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + } +} + +void LifecycleTest::testIsolatedWidgets() +{ + testWidgets(nullptr); +} + +void LifecycleTest::testParentedWidgets() +{ + ScopedVclPtrInstance<WorkWindow> xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + xWin->Show(); + testWidgets(xWin); +} + +namespace { + +class DisposableChild : public vcl::Window +{ +public: + explicit DisposableChild(vcl::Window *pParent) : vcl::Window(pParent) {} + virtual ~DisposableChild() override + { + disposeOnce(); + } +}; + +} + +void LifecycleTest::testChildDispose() +{ + VclPtrInstance<WorkWindow> xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + VclPtrInstance< DisposableChild > xChild( xWin.get() ); + xWin->Show(); + xChild->disposeOnce(); + xWin->disposeOnce(); +} + +void LifecycleTest::testPostDispose() +{ + VclPtrInstance<WorkWindow> xWin(nullptr, WB_APP|WB_STDWORK); + xWin->disposeOnce(); + + // check selected methods continue to work post-dispose + CPPUNIT_ASSERT(!xWin->GetParent()); + xWin->Show(); + CPPUNIT_ASSERT(!xWin->IsReallyShown()); + CPPUNIT_ASSERT(!xWin->IsEnabled()); + CPPUNIT_ASSERT(!xWin->IsInputEnabled()); + CPPUNIT_ASSERT(!xWin->GetChild(0)); + CPPUNIT_ASSERT(!xWin->GetWindow(GetWindowType::Parent)); +} + +namespace { + +class FocusCrashPostDispose : public TabControl +{ +public: + explicit FocusCrashPostDispose(vcl::Window *pParent) : + TabControl(pParent, 0) + { + } + virtual bool PreNotify( NotifyEvent& ) override + { + return false; + } + virtual bool EventNotify( NotifyEvent& ) override + { + return false; + } + virtual void GetFocus() override + { + CPPUNIT_FAIL("get focus"); + } + virtual void LoseFocus() override + { + CPPUNIT_FAIL("this should never be called"); + } +}; + +} + +void LifecycleTest::testFocus() +{ + ScopedVclPtrInstance<WorkWindow> xWin(nullptr, WB_APP|WB_STDWORK); + ScopedVclPtrInstance< FocusCrashPostDispose > xChild(xWin); + xWin->Show(); + xChild->GrabFocus(); + // process asynchronous ToTop + Scheduler::ProcessTaskScheduling(); + // FIXME: really awful to test focus issues without showing windows. + // CPPUNIT_ASSERT(xChild->HasFocus()); +} + +namespace { + +template <class vcl_type> +class LeakTestClass : public vcl_type +{ + bool &mrDeleted; +public: + template<typename... Arg> + LeakTestClass(bool &bDeleted, Arg &&... arg) : + vcl_type(std::forward<Arg>(arg)...), + mrDeleted(bDeleted) + { + mrDeleted = false; + } + ~LeakTestClass() + { + mrDeleted = true; + } +}; + +class LeakTestObject +{ + bool mbDeleted; + VclPtr<vcl::Window> mxRef; + void *mpRef; + LeakTestObject() + : mbDeleted(false) + , mpRef(nullptr) + { + } +public: + template<typename vcl_type, typename... Arg> static LeakTestObject * + Create(Arg &&... arg) + { + LeakTestObject *pNew = new LeakTestObject(); + pNew->mxRef = VclPtr< LeakTestClass< vcl_type > >::Create( pNew->mbDeleted, + std::forward<Arg>(arg)...); + pNew->mpRef = static_cast<void *>(static_cast<vcl::Window *>(pNew->mxRef)); + return pNew; + } + const VclPtr<vcl::Window>& getRef() const { return mxRef; } + void disposeAndClear() + { + mxRef.disposeAndClear(); + } + void assertDeleted() + { + if (!mbDeleted) + { + OUStringBuffer aMsg = "Type '"; + vcl::Window *pWin = static_cast<vcl::Window *>(mpRef); + aMsg.appendAscii(typeid(*pWin).name()); + aMsg.append("' not freed after dispose"); + CPPUNIT_FAIL(OUStringToOString(aMsg.makeStringAndClear(), + RTL_TEXTENCODING_UTF8).getStr()); + } + } +}; + +} + +void LifecycleTest::testLeakage() +{ + std::vector<LeakTestObject *> aObjects; + + // Create objects + aObjects.push_back(LeakTestObject::Create<WorkWindow>(nullptr, WB_APP|WB_STDWORK)); + VclPtr<vcl::Window> xParent = aObjects.back()->getRef(); + + aObjects.push_back(LeakTestObject::Create<PushButton>(xParent)); + aObjects.push_back(LeakTestObject::Create<OKButton>(xParent)); + aObjects.push_back(LeakTestObject::Create<CancelButton>(xParent)); + aObjects.push_back(LeakTestObject::Create<HelpButton>(xParent)); + aObjects.push_back(LeakTestObject::Create<CheckBox>(xParent)); + aObjects.push_back(LeakTestObject::Create<Edit>(xParent)); + aObjects.push_back(LeakTestObject::Create<ComboBox>(xParent)); + aObjects.push_back(LeakTestObject::Create<RadioButton>(xParent)); + + { // something that looks like a dialog + aObjects.push_back(LeakTestObject::Create<Dialog>(xParent,WB_CLIPCHILDREN|WB_MOVEABLE|WB_3DLOOK|WB_CLOSEABLE|WB_SIZEABLE)); + VclPtr<vcl::Window> xDlgParent = aObjects.back()->getRef(); + aObjects.push_back(LeakTestObject::Create<VclVBox>(xDlgParent)); + VclPtr<vcl::Window> xVBox = aObjects.back()->getRef(); + aObjects.push_back(LeakTestObject::Create<VclVButtonBox>(xVBox)); + } + + aObjects.push_back(LeakTestObject::Create<Dialog>(xParent, "PrintProgressDialog", "vcl/ui/printprogressdialog.ui")); + xParent.clear(); + + for (auto i = aObjects.rbegin(); i != aObjects.rend(); ++i) + (*i)->getRef()->Show(); + + for (auto i = aObjects.rbegin(); i != aObjects.rend(); ++i) + (*i)->disposeAndClear(); + + for (auto i = aObjects.begin(); i != aObjects.end(); ++i) + (*i)->assertDeleted(); + + for (auto i = aObjects.begin(); i != aObjects.end(); ++i) + delete *i; +} + +void LifecycleTest::testToolkit() +{ + LeakTestObject *pVclWin = LeakTestObject::Create<WorkWindow>(nullptr, WB_APP|WB_STDWORK); + css::uno::Reference<css::awt::XWindow> xWindow(pVclWin->getRef()->GetComponentInterface(), css::uno::UNO_QUERY); + CPPUNIT_ASSERT(xWindow.is()); + + // test UNO dispose + css::uno::Reference<css::lang::XComponent> xWinComponent = xWindow; + CPPUNIT_ASSERT(xWinComponent.is()); + CPPUNIT_ASSERT(!pVclWin->getRef()->IsDisposed()); + xWinComponent->dispose(); + CPPUNIT_ASSERT(pVclWin->getRef()->IsDisposed()); + + // test UNO cleanup + xWinComponent.clear(); + xWindow.clear(); + pVclWin->disposeAndClear(); + pVclWin->assertDeleted(); + + delete pVclWin; +} + +CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/mnemonic.cxx b/vcl/qa/cppunit/mnemonic.cxx new file mode 100644 index 000000000..e870e1d29 --- /dev/null +++ b/vcl/qa/cppunit/mnemonic.cxx @@ -0,0 +1,57 @@ +/* -*- 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 <o3tl/cppunittraitshelper.hxx> +#include <test/bootstrapfixture.hxx> +#include <cppunit/TestAssert.h> + +#include <vcl/mnemonic.hxx> + +class VclMnemonicTest : public test::BootstrapFixture +{ +public: + VclMnemonicTest() : BootstrapFixture(true, false) {} + + void testMnemonic(); + + CPPUNIT_TEST_SUITE(VclMnemonicTest); + CPPUNIT_TEST(testMnemonic); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclMnemonicTest::testMnemonic() +{ + MnemonicGenerator aGenerator; + + { + OUString sResult = aGenerator.CreateMnemonic(u"ßa"); + CPPUNIT_ASSERT_EQUAL(u'~', sResult[1]); + } + + { + const sal_Unicode TEST[] = { 0x4E00, 'b' }; + OUString sResult = aGenerator.CreateMnemonic(OUString(TEST, SAL_N_ELEMENTS(TEST))); + CPPUNIT_ASSERT_EQUAL(u'~', sResult[1]); + } + + { + const sal_Unicode TEST[] = { 0x4E00 }; + OUString sResult = aGenerator.CreateMnemonic(OUString(TEST, SAL_N_ELEMENTS(TEST))); + CPPUNIT_ASSERT_EQUAL(OUString("(~C)"), sResult.copy(sResult.getLength() - 4)); + } + +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclMnemonicTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx new file mode 100644 index 000000000..e99a35f67 --- /dev/null +++ b/vcl/qa/cppunit/outdev.cxx @@ -0,0 +1,291 @@ +/* -*- 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 <vcl/print.hxx> +#include <vcl/virdev.hxx> +#include <vcl/window.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <bitmapwriteaccess.hxx> +#include <bufferdevice.hxx> +#include <window.h> + +#include <basegfx/matrix/b2dhommatrix.hxx> + +class VclOutdevTest : public test::BootstrapFixture +{ +public: + VclOutdevTest() : BootstrapFixture(true, false) {} + + void testVirtualDevice(); + void testUseAfterDispose(); + void testPrinterBackgroundColor(); + void testWindowBackgroundColor(); + void testGetReadableFontColorPrinter(); + void testGetReadableFontColorWindow(); + void testDrawTransformedBitmapEx(); + void testDrawTransformedBitmapExFlip(); + void testRTL(); + void testRTLGuard(); + + CPPUNIT_TEST_SUITE(VclOutdevTest); + CPPUNIT_TEST(testVirtualDevice); + CPPUNIT_TEST(testUseAfterDispose); + CPPUNIT_TEST(testPrinterBackgroundColor); + CPPUNIT_TEST(testWindowBackgroundColor); + CPPUNIT_TEST(testGetReadableFontColorPrinter); + CPPUNIT_TEST(testGetReadableFontColorWindow); + CPPUNIT_TEST(testDrawTransformedBitmapEx); + CPPUNIT_TEST(testDrawTransformedBitmapExFlip); + CPPUNIT_TEST(testRTL); + CPPUNIT_TEST(testRTLGuard); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclOutdevTest::testGetReadableFontColorPrinter() +{ + ScopedVclPtrInstance<Printer> pPrinter; + CPPUNIT_ASSERT_EQUAL(pPrinter->GetReadableFontColor(COL_WHITE, COL_WHITE), COL_BLACK); +} + +void VclOutdevTest::testGetReadableFontColorWindow() +{ + ScopedVclPtrInstance<vcl::Window> pWindow(nullptr, WB_APP | WB_STDWORK); + CPPUNIT_ASSERT_EQUAL(pWindow->GetReadableFontColor(COL_WHITE, COL_BLACK), COL_WHITE); + CPPUNIT_ASSERT_EQUAL(pWindow->GetReadableFontColor(COL_WHITE, COL_WHITE), COL_BLACK); + CPPUNIT_ASSERT_EQUAL(pWindow->GetReadableFontColor(COL_BLACK, COL_BLACK), COL_WHITE); +} + +void VclOutdevTest::testPrinterBackgroundColor() +{ + ScopedVclPtrInstance<Printer> pPrinter; + CPPUNIT_ASSERT_EQUAL(pPrinter->GetBackgroundColor(), COL_WHITE); +} + +void VclOutdevTest::testWindowBackgroundColor() +{ + ScopedVclPtrInstance<vcl::Window> pWindow(nullptr, WB_APP | WB_STDWORK); + pWindow->SetBackground(Wallpaper(COL_WHITE)); + CPPUNIT_ASSERT_EQUAL(pWindow->GetBackgroundColor(), COL_WHITE); +} + +void VclOutdevTest::testVirtualDevice() +{ + ScopedVclPtrInstance< VirtualDevice > pVDev; + pVDev->SetOutputSizePixel(Size(32,32)); + pVDev->SetBackground(Wallpaper(COL_WHITE)); + + CPPUNIT_ASSERT_EQUAL(pVDev->GetBackgroundColor(), COL_WHITE); + + pVDev->Erase(); + pVDev->DrawPixel(Point(1,2),COL_BLUE); + pVDev->DrawPixel(Point(31,30),COL_RED); + + Size aSize = pVDev->GetOutputSizePixel(); + CPPUNIT_ASSERT_EQUAL(Size(32,32), aSize); + + Bitmap aBmp = pVDev->GetBitmap(Point(),aSize); + +#if 0 + OUString rFileName("/tmp/foo-unx.png"); + try { + vcl::PNGWriter aWriter( aBmp ); + SvFileStream sOutput( rFileName, StreamMode::WRITE ); + aWriter.Write( sOutput ); + sOutput.Close(); + } catch (...) { + SAL_WARN("vcl", "Error writing png to " << rFileName); + } +#endif + + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(0,0))); +#if !defined _WIN32 //TODO: various failures on Windows tinderboxes + CPPUNIT_ASSERT_EQUAL(COL_BLUE, pVDev->GetPixel(Point(1,2))); + CPPUNIT_ASSERT_EQUAL(COL_RED, pVDev->GetPixel(Point(31,30))); +#endif + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(30,31))); + + // Gotcha: y and x swap for BitmapReadAccess: deep joy. + Bitmap::ScopedReadAccess pAcc(aBmp); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, static_cast<Color>(pAcc->GetPixel(0,0))); +#if !defined _WIN32 //TODO: various failures on Windows tinderboxes + CPPUNIT_ASSERT_EQUAL(COL_BLUE, static_cast<Color>(pAcc->GetPixel(2,1))); + CPPUNIT_ASSERT_EQUAL(COL_RED, static_cast<Color>(pAcc->GetPixel(30,31))); +#endif + CPPUNIT_ASSERT_EQUAL(COL_WHITE, static_cast<Color>(pAcc->GetPixel(31,30))); + +#if 0 + VclPtr<vcl::Window> pWin = VclPtr<WorkWindow>::Create( (vcl::Window *)nullptr ); + CPPUNIT_ASSERT( pWin ); + OutputDevice *pOutDev = pWin.get(); +#endif +} + +void VclOutdevTest::testUseAfterDispose() +{ + // Create a virtual device, enable map mode then dispose it. + ScopedVclPtrInstance<VirtualDevice> pVDev; + + pVDev->EnableMapMode(); + + pVDev->disposeOnce(); + + // Make sure that these don't crash after dispose. + pVDev->GetInverseViewTransformation(); + + pVDev->GetViewTransformation(); +} + +void VclOutdevTest::testDrawTransformedBitmapEx() +{ + // Create a virtual device, and connect a metafile to it. + // Also create a 16x16 bitmap. + ScopedVclPtrInstance<VirtualDevice> pVDev; + Bitmap aBitmap(Size(16, 16), 24); + { + // Fill the top left quarter with black. + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(j, i, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + basegfx::B2DHomMatrix aMatrix; + aMatrix.scale(8, 8); + // Rotate 90 degrees clockwise, so the black part goes to the top right. + aMatrix.rotate(M_PI / 2); + GDIMetaFile aMtf; + aMtf.Record(pVDev.get()); + + // Draw the rotated bitmap on the vdev. + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize()); + MetaAction* pAction = aMtf.GetAction(0); + CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); + auto pBitmapAction = static_cast<MetaBmpExScaleAction*>(pAction); + const BitmapEx& rBitmapEx = pBitmapAction->GetBitmapEx(); + Size aTransformedSize = rBitmapEx.GetSizePixel(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 16x16 + // - Actual : 8x8 + // I.e. the bitmap before scaling was already scaled down, just because it was rotated. + CPPUNIT_ASSERT_EQUAL(Size(16, 16), aTransformedSize); + + aBitmap = rBitmapEx.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + BitmapColor aColor = pAccess->GetPixel(j, i); + Color aExpected = i >= 8 && j < 8 ? COL_BLACK : COL_WHITE; + std::stringstream ss; + ss << "Color is expected to be "; + ss << ((aExpected == COL_WHITE) ? "white" : "black"); + ss << ", is " << aColor.AsRGBHexString(); + ss << " (row " << j << ", col " << i << ")"; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: c[00000000] + // - Actual : c[ffffff00] + // - Color is expected to be black, is ffffff (row 0, col 8) + // i.e. the top right quarter of the image was not fully black, there was a white first + // row. + CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str(), aExpected, Color(aColor)); + } + } +} + +void VclOutdevTest::testDrawTransformedBitmapExFlip() +{ + // Create a virtual device, and connect a metafile to it. + // Also create a 16x16 bitmap. + ScopedVclPtrInstance<VirtualDevice> pVDev; + Bitmap aBitmap(Size(16, 16), 24); + { + // Fill the top left quarter with black. + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(j, i, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + basegfx::B2DHomMatrix aMatrix; + // Negative y scale: bitmap should be upside down, so the black part goes to the bottom left. + aMatrix.scale(8, -8); + // Rotate 90 degrees clockwise, so the black part goes back to the top left. + aMatrix.rotate(M_PI / 2); + GDIMetaFile aMtf; + aMtf.Record(pVDev.get()); + + // Draw the scaled and rotated bitmap on the vdev. + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize()); + MetaAction* pAction = aMtf.GetAction(0); + CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); + auto pBitmapAction = static_cast<MetaBmpExScaleAction*>(pAction); + const BitmapEx& rBitmapEx = pBitmapAction->GetBitmapEx(); + + aBitmap = rBitmapEx.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + int nX = 8 * 0.25; + int nY = 8 * 0.25; + BitmapColor aColor = pAccess->GetPixel(nY, nX); + std::stringstream ss; + ss << "Color is expected to be black, is " << aColor.AsRGBHexString(); + ss << " (row " << nY << ", col " << nX << ")"; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: c[00000000] + // - Actual : c[ffffff00] + // - Color is expected to be black, is ffffff (row 2, col 2) + // i.e. the top left quarter of the image was not black, due to a missing flip. + CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str(), COL_BLACK, Color(aColor)); +} + +void VclOutdevTest::testRTL() +{ + ScopedVclPtrInstance<vcl::Window> pWindow(nullptr, WB_APP | WB_STDWORK); + pWindow->EnableRTL(); + vcl::RenderContext& rRenderContext = *pWindow; + vcl::BufferDevice pBuffer(pWindow, rRenderContext); + + // Without the accompanying fix in place, this test would have failed, because the RTL status + // from pWindow was not propagated to pBuffer. + CPPUNIT_ASSERT(pBuffer->IsRTLEnabled()); +} + +void VclOutdevTest::testRTLGuard() +{ + ScopedVclPtrInstance<vcl::Window> pWindow(nullptr, WB_APP | WB_STDWORK); + pWindow->EnableRTL(); + pWindow->RequestDoubleBuffering(true); + ImplFrameData* pFrameData = pWindow->ImplGetWindowImpl()->mpFrameData; + vcl::PaintBufferGuard aGuard(pFrameData, pWindow); + // Without the accompanying fix in place, this test would have failed, because the RTL status + // from pWindow was not propagated to aGuard. + CPPUNIT_ASSERT(aGuard.GetRenderContext()->IsRTLEnabled()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/pdfexport/data/6m-wide.odg b/vcl/qa/cppunit/pdfexport/data/6m-wide.odg Binary files differnew file mode 100644 index 000000000..49fb9bfff --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/6m-wide.odg diff --git a/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf Binary files differnew file mode 100644 index 000000000..af665fcba --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf diff --git a/vcl/qa/cppunit/pdfexport/data/forcepoint71.key b/vcl/qa/cppunit/pdfexport/data/forcepoint71.key Binary files differnew file mode 100644 index 000000000..716fe5848 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/forcepoint71.key diff --git a/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp b/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp Binary files differnew file mode 100644 index 000000000..b6787aff6 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp diff --git a/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf Binary files differnew file mode 100644 index 000000000..739a80c47 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf diff --git a/vcl/qa/cppunit/pdfexport/data/reduce-image.fodt b/vcl/qa/cppunit/pdfexport/data/reduce-image.fodt new file mode 100644 index 000000000..b5737ae27 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/reduce-image.fodt @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ooo="http://openoffice.org/2004/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:default-style style:family="graphic"> + </style:default-style> + <style:style style:name="Graphics" style:family="graphic"> + </style:style> + </office:styles> + <office:automatic-styles> + <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"> + <style:graphic-properties style:run-through="foreground" style:horizontal-pos="center" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p text:style-name="Standard"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="char" svg:width="0.041cm" svg:height="0.041cm" draw:z-index="0"><draw:image loext:mime-type="image/png"><office:binary-data>iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAAAABmJLR0QA/wD/AP+gvaeTAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5AEVDCUTfvEVdAAAAYhJREFUeNrt3bEJwzAQ + htFckjLreP8Bso5bc2lTpBDG4kfkvQUE5uNUGEnV3TdIufsECBABggARIAgQAYIAESAIEAGC + ABEgCBABggARIAgQAYIAESAIEAGCABEgCBABggARIHx7phZ+vF9D13Id217WXW9dExBbMAgQ + AYIAESAIEAGCABEgCBABIkAQIAIEASJAECAChKnq6hfTR88gsKarz46YgNiCESAIEAGCABEg + CBABwlSx27FStzHxW+oPlgmILRgBggARIAgQAYIAESAIEAGCABEgCBABggARIAgQAYIAESAI + EAGCABEgCBABggARIAgQAYIAESACBAEiQBAgAgQBIkAQIAIEASJAECACBAEiQBAgi4u9mJ56 + oRsTEASIAEGACBABggARIAiQP1LdmR8So39Cjm0v6663rgmILRgEiABBgAgQBIgAQYAIEASI + ABEgCBABggARIAgQAcJUsTMhYAIiQAQIAkSAIEAECAJEgCBABAgCRIAgQAQIAkSAIEAECKd9 + AEYENxB/sygQAAAAAElFTkSuQmCC + </office:binary-data></draw:image></draw:frame></text:p> + </office:text> + </office:body> +</office:document> diff --git a/vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt b/vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt new file mode 100644 index 000000000..99ff22746 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ooo="http://openoffice.org/2004/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:default-style style:family="graphic"> + </style:default-style> + <style:style style:name="Graphics" style:family="graphic"> + </style:style> + </office:styles> + <office:automatic-styles> + <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"> + <style:graphic-properties style:run-through="foreground" style:horizontal-pos="center" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p text:style-name="Standard"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="char" svg:width="0.041cm" svg:height="0.041cm" draw:z-index="0"><draw:image loext:mime-type="image/png"><office:binary-data>iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMklEQVR42mP4//8/AyWYYXAZ + wHSK+z8pbOoaAJIgBWM1gFh/jxqAxwCKYmHgE9KAZSYAhK3Dgc2FxfUAAAAASUVORK5CYII= + </office:binary-data></draw:image></draw:frame></text:p> + </office:text> + </office:body> +</office:document> diff --git a/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt b/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt Binary files differnew file mode 100644 index 000000000..ecd779537 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105093.odp b/vcl/qa/cppunit/pdfexport/data/tdf105093.odp Binary files differnew file mode 100644 index 000000000..82ce29cda --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf105093.odp diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105461.odp b/vcl/qa/cppunit/pdfexport/data/tdf105461.odp Binary files differnew file mode 100644 index 000000000..9c86a3bd7 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf105461.odp diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105954.odt b/vcl/qa/cppunit/pdfexport/data/tdf105954.odt Binary files differnew file mode 100644 index 000000000..ba5c96de6 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf105954.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106059.odt b/vcl/qa/cppunit/pdfexport/data/tdf106059.odt Binary files differnew file mode 100644 index 000000000..a2c180378 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf106059.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106206.odt b/vcl/qa/cppunit/pdfexport/data/tdf106206.odt Binary files differnew file mode 100644 index 000000000..3581157de --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf106206.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106693.odt b/vcl/qa/cppunit/pdfexport/data/tdf106693.odt Binary files differnew file mode 100644 index 000000000..a2c180378 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf106693.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106702.odt b/vcl/qa/cppunit/pdfexport/data/tdf106702.odt Binary files differnew file mode 100644 index 000000000..da3b7e814 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf106702.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt b/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt Binary files differnew file mode 100644 index 000000000..d46c93dff --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106972.odt b/vcl/qa/cppunit/pdfexport/data/tdf106972.odt Binary files differnew file mode 100644 index 000000000..3fa76c49f --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf106972.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107013.odt b/vcl/qa/cppunit/pdfexport/data/tdf107013.odt Binary files differnew file mode 100644 index 000000000..644e65c6d --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf107013.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107018.odt b/vcl/qa/cppunit/pdfexport/data/tdf107018.odt Binary files differnew file mode 100644 index 000000000..3bfc7b2d7 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf107018.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107089.odt b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt Binary files differnew file mode 100644 index 000000000..5aaaab944 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107868.odt b/vcl/qa/cppunit/pdfexport/data/tdf107868.odt Binary files differnew file mode 100644 index 000000000..8309f4b87 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf107868.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf108963.odp b/vcl/qa/cppunit/pdfexport/data/tdf108963.odp Binary files differnew file mode 100644 index 000000000..246c0c72a --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf108963.odp diff --git a/vcl/qa/cppunit/pdfexport/data/tdf109143.odt b/vcl/qa/cppunit/pdfexport/data/tdf109143.odt Binary files differnew file mode 100644 index 000000000..7d9afa378 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf109143.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf113143.odp b/vcl/qa/cppunit/pdfexport/data/tdf113143.odp Binary files differnew file mode 100644 index 000000000..5f8a1b10e --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf113143.odp diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt b/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt Binary files differnew file mode 100644 index 000000000..63fe82946 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt Binary files differnew file mode 100644 index 000000000..c1e1f6d43 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115262.ods b/vcl/qa/cppunit/pdfexport/data/tdf115262.ods Binary files differnew file mode 100644 index 000000000..b401a74ce --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf115262.ods diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115967.odt b/vcl/qa/cppunit/pdfexport/data/tdf115967.odt Binary files differnew file mode 100644 index 000000000..39f4ce178 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf115967.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt b/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt Binary files differnew file mode 100644 index 000000000..caabc4987 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf121615.odt b/vcl/qa/cppunit/pdfexport/data/tdf121615.odt Binary files differnew file mode 100644 index 000000000..7d2a87cf0 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf121615.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf121962.odt b/vcl/qa/cppunit/pdfexport/data/tdf121962.odt Binary files differnew file mode 100644 index 000000000..a831b1136 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf121962.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf128630.odp b/vcl/qa/cppunit/pdfexport/data/tdf128630.odp Binary files differnew file mode 100644 index 000000000..d216504b7 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf128630.odp diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt Binary files differnew file mode 100644 index 000000000..7fecc55c6 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt Binary files differnew file mode 100644 index 000000000..3d7b5e59c --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt Binary files differnew file mode 100644 index 000000000..6db91fe81 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt Binary files differnew file mode 100644 index 000000000..47c370004 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt diff --git a/vcl/qa/cppunit/pdfexport/data/tdf99680.odt b/vcl/qa/cppunit/pdfexport/data/tdf99680.odt Binary files differnew file mode 100644 index 000000000..de12f9baa --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf99680.odt diff --git a/vcl/qa/cppunit/pdfexport/data/toc-link.fodt b/vcl/qa/cppunit/pdfexport/data/toc-link.fodt new file mode 100644 index 000000000..ab29e88a4 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/toc-link.fodt @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text"/> + <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:default-outline-level="1" style:class="text"> + <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm"/> + </style:style> + <style:style style:name="Contents_20_Heading" style:display-name="Contents Heading" style:family="paragraph" style:parent-style-name="Heading" style:class="index"/> + <style:style style:name="Contents_20_1" style:display-name="Contents 1" style:family="paragraph" style:parent-style-name="Index" style:class="index"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false"/> + </style:style> + <style:style style:name="Index_20_Link" style:display-name="Index Link" style:family="text"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="Sect1" style:family="section"/> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.59cm" fo:page-height="27.94cm" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm"/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:table-of-content text:style-name="Sect1" text:protected="true" text:name="Table of Contents"> + <text:table-of-content-source text:outline-level="10"> + <text:index-title-template text:style-name="Contents_20_Heading">Table of Contents</text:index-title-template> + <text:table-of-content-entry-template text:outline-level="1" text:style-name="Contents_20_1"> + <text:index-entry-link-start/> + <text:index-entry-text/> + <text:index-entry-link-end/> + </text:table-of-content-entry-template> + </text:table-of-content-source> + <text:index-body> + <text:index-title text:style-name="Sect1" text:name="Table of Contents_Head"> + <text:p text:style-name="Contents_20_Heading">Table of Contents</text:p> + </text:index-title> + <text:p text:style-name="Contents_20_1"><text:a xlink:type="simple" xlink:href="#__RefHeading_Toc">Heading 1<text:tab/>1</text:a></text:p> + </text:index-body> + </text:table-of-content> + <text:h text:style-name="Heading_20_1" text:outline-level="1"><text:bookmark-start text:name="__RefHeading_Toc"/>Heading 1<text:bookmark-end text:name="__RefHeading_Toc"/></text:h> + </office:text> + </office:body> +</office:document> diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx new file mode 100644 index 000000000..fe402b4ed --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -0,0 +1,2295 @@ +/* -*- 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 <memory> +#include <type_traits> + +#include <config_features.h> + +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/view/XPrintable.hpp> +#include <com/sun/star/text/XDocumentIndexesSupplier.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/io/XOutputStream.hpp> + +#include <comphelper/scopeguard.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <test/bootstrapfixture.hxx> +#include <unotest/macros_test.hxx> +#include <unotools/mediadescriptor.hxx> +#include <unotools/tempfile.hxx> +#include <vcl/filter/pdfdocument.hxx> +#include <tools/zcodec.hxx> +#include <fpdf_edit.h> +#include <fpdf_text.h> +#include <fpdf_doc.h> +#include <fpdfview.h> +#include <vcl/graphicfilter.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <unotools/streamwrap.hxx> + +#include <vcl/filter/PDFiumLibrary.hxx> + +using namespace ::com::sun::star; + +static std::ostream& operator<<(std::ostream& rStrm, const Color& rColor) +{ + rStrm << "Color: R:" << static_cast<int>(rColor.GetRed()) + << " G:" << static_cast<int>(rColor.GetGreen()) + << " B:" << static_cast<int>(rColor.GetBlue()) + << " A:" << static_cast<int>(rColor.GetTransparency()); + return rStrm; +} + +namespace +{ + +struct CloseDocument { + void operator ()(FPDF_DOCUMENT doc) { + if (doc != nullptr) { + FPDF_CloseDocument(doc); + } + } +}; + +using DocumentHolder = + std::unique_ptr<typename std::remove_pointer<FPDF_DOCUMENT>::type, CloseDocument>; + +struct ClosePage { + void operator ()(FPDF_PAGE page) { + if (page != nullptr) { + FPDF_ClosePage(page); + } + } +}; + +using PageHolder = + std::unique_ptr<typename std::remove_pointer<FPDF_PAGE>::type, ClosePage>; + +/// Tests the PDF export filter. +class PdfExportTest : public test::BootstrapFixture, public unotest::MacrosTest +{ + uno::Reference<lang::XComponent> mxComponent; + utl::TempFile maTempFile; + SvMemoryStream maMemory; + // Export the document as PDF, then parse it with PDFium. + DocumentHolder exportAndParse(const OUString& rURL, const utl::MediaDescriptor& rDescriptor); + std::shared_ptr<vcl::pdf::PDFium> mpPDFium; + +public: + PdfExportTest(); + virtual void setUp() override; + virtual void tearDown() override; + void saveAsPDF(const OUString& rFile); + void load(const OUString& rFile, vcl::filter::PDFDocument& rDocument); + /// Tests that a pdf image is roundtripped back to PDF as a vector format. + void testTdf106059(); + /// Tests that text highlight from Impress is not lost. + void testTdf105461(); + void testTdf107868(); + /// Tests that embedded video from Impress is not exported as a linked one. + void testTdf105093(); + /// Tests export of non-PDF images. + void testTdf106206(); + /// Tests export of PDF images without reference XObjects. + void testTdf106693(); + void testForcePoint71(); + void testTdf106972(); + void testTdf106972Pdf17(); + void testSofthyphenPos(); + void testTdf107013(); + void testTdf107018(); + void testTdf107089(); + void testTdf99680(); + void testTdf99680_2(); + void testTdf108963(); + void testTdf118244_radioButtonGroup(); + /// Test writing ToUnicode CMAP for LTR ligatures. + void testTdf115117_1(); + /// Text extracting LTR text with ligatures. + void testTdf115117_1a(); + /// Test writing ToUnicode CMAP for RTL ligatures. + void testTdf115117_2(); + /// Test extracting RTL text with ligatures. + void testTdf115117_2a(); + /// Test writing ToUnicode CMAP for doubly encoded glyphs. + void testTdf66597_1(); + /// Test writing ActualText for RTL many to one glyph to Unicode mapping. + void testTdf66597_2(); + /// Test writing ActualText for LTR many to one glyph to Unicode mapping. + void testTdf66597_3(); + void testTdf109143(); + void testTdf105954(); + void testTdf128630(); + void testTdf106702(); + void testTdf113143(); + void testTdf115262(); + void testTdf121962(); + void testTdf115967(); + void testTdf121615(); + void testTocLink(); + void testPdfImageResourceInlineXObjectRef(); + void testReduceSmallImage(); + void testReduceImage(); + void testLinkWrongPage(); + void testLargePage(); + void testVersion15(); + void testDefaultVersion(); + void testMultiPagePDF(); + + + CPPUNIT_TEST_SUITE(PdfExportTest); + CPPUNIT_TEST(testTdf106059); + CPPUNIT_TEST(testTdf105461); + CPPUNIT_TEST(testTdf107868); + CPPUNIT_TEST(testTdf105093); + CPPUNIT_TEST(testTdf106206); + CPPUNIT_TEST(testTdf106693); + CPPUNIT_TEST(testForcePoint71); + CPPUNIT_TEST(testTdf106972); + CPPUNIT_TEST(testTdf106972Pdf17); + CPPUNIT_TEST(testSofthyphenPos); + CPPUNIT_TEST(testTdf107013); + CPPUNIT_TEST(testTdf107018); + CPPUNIT_TEST(testTdf107089); + CPPUNIT_TEST(testTdf99680); + CPPUNIT_TEST(testTdf99680_2); + CPPUNIT_TEST(testTdf108963); + CPPUNIT_TEST(testTdf118244_radioButtonGroup); + CPPUNIT_TEST(testTdf115117_1); + CPPUNIT_TEST(testTdf115117_1a); + CPPUNIT_TEST(testTdf115117_2); + CPPUNIT_TEST(testTdf115117_2a); + CPPUNIT_TEST(testTdf66597_1); + CPPUNIT_TEST(testTdf66597_2); + CPPUNIT_TEST(testTdf66597_3); + CPPUNIT_TEST(testTdf109143); + CPPUNIT_TEST(testTdf105954); + CPPUNIT_TEST(testTdf128630); + CPPUNIT_TEST(testTdf106702); + CPPUNIT_TEST(testTdf113143); + CPPUNIT_TEST(testTdf115262); + CPPUNIT_TEST(testTdf121962); + CPPUNIT_TEST(testTdf115967); + CPPUNIT_TEST(testTdf121615); + CPPUNIT_TEST(testTocLink); + CPPUNIT_TEST(testPdfImageResourceInlineXObjectRef); + CPPUNIT_TEST(testReduceSmallImage); + CPPUNIT_TEST(testReduceImage); + CPPUNIT_TEST(testLinkWrongPage); + CPPUNIT_TEST(testLargePage); + CPPUNIT_TEST(testVersion15); + CPPUNIT_TEST(testDefaultVersion); + CPPUNIT_TEST(testMultiPagePDF); + CPPUNIT_TEST_SUITE_END(); +}; + +PdfExportTest::PdfExportTest() +{ + maTempFile.EnableKillingFile(); +} + +DocumentHolder PdfExportTest::exportAndParse(const OUString& rURL, const utl::MediaDescriptor& rDescriptor) +{ + // Import the bugdoc and export as PDF. + mxComponent = loadFromDesktop(rURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + xStorable->storeToURL(maTempFile.GetURL(), rDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + return pPdfDocument; +} + +void PdfExportTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); + + mpPDFium = vcl::pdf::PDFiumLibrary::get(); +} + +void PdfExportTest::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/pdfexport/data/"; + +void PdfExportTest::saveAsPDF(const OUString& rFile) +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFile; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); +} + +void PdfExportTest::load(const OUString& rFile, vcl::filter::PDFDocument& rDocument) +{ + saveAsPDF(rFile); + + // Parse the export result. + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(rDocument.Read(aStream)); +} + +void PdfExportTest::testTdf106059() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106059.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + // Explicitly enable the usage of the reference XObject markup. + uno::Sequence<beans::PropertyValue> aFilterData( comphelper::InitPropertySequence({ + {"UseReferenceXObject", uno::Any(true) } + })); + aMediaDescriptor["FilterData"] <<= aFilterData; + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // Assert that the XObject in the page resources dictionary is a reference XObject. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + // The document has one page. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + // The page has one image. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pReferenceXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pReferenceXObject); + // The image is a reference XObject. + // This dictionary key was missing, so the XObject wasn't a reference one. + CPPUNIT_ASSERT(pReferenceXObject->Lookup("Ref")); +} + +void PdfExportTest::testTdf106693() +{ + vcl::filter::PDFDocument aDocument; + load("tdf106693.odt", aDocument); + + // Assert that the XObject in the page resources dictionary is a form XObject. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + // The document has one page. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + // The page has one image. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + // The image is a form XObject. + auto pSubtype = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype->GetValue()); + // This failed: UseReferenceXObject was ignored and Ref was always created. + CPPUNIT_ASSERT(!pXObject->Lookup("Ref")); + + // Assert that the form object refers to an inner form object, not a + // bitmap. + auto pInnerResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pInnerResources); + auto pInnerXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pInnerResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pInnerXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pInnerXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pInnerXObject = pInnerXObjects->LookupObject(pInnerXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pInnerXObject); + auto pInnerSubtype = dynamic_cast<vcl::filter::PDFNameElement*>(pInnerXObject->Lookup("Subtype")); + CPPUNIT_ASSERT(pInnerSubtype); + // This failed: this was Image (bitmap), not Form (vector). + CPPUNIT_ASSERT_EQUAL(OString("Form"), pInnerSubtype->GetValue()); +} + +void PdfExportTest::testTdf105461() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf105461.odp"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Make sure there is a filled rectangle inside. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nYellowPathCount = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH) + continue; + + unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0; + FPDFPageObj_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha); + if (Color(nRed, nGreen, nBlue) == COL_YELLOW) + ++nYellowPathCount; + } + + // This was 0, the page contained no yellow paths. + CPPUNIT_ASSERT_EQUAL(1, nYellowPathCount); +} + +void PdfExportTest::testTdf107868() +{ + // No need to run it on Windows, since it would use GDI printing, and not trigger PDF export + // which is the intent of the test. +// FIXME: Why does this fail on macOS? +#if !defined MACOSX && !defined _WIN32 + + // Import the bugdoc and print to PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf107868.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + uno::Reference<view::XPrintable> xPrintable(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xPrintable.is()); + uno::Sequence<beans::PropertyValue> aOptions(comphelper::InitPropertySequence( + { + {"FileName", uno::makeAny(maTempFile.GetURL())}, + {"Wait", uno::makeAny(true)} + })); + xPrintable->print(aOptions); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + if (!pPdfDocument) + // Printing to PDF failed in a non-interesting way, e.g. CUPS is not + // running, there is no printer defined, etc. + return; + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Make sure there is no filled rectangle inside. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nWhitePathCount = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH) + continue; + + unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0; + FPDFPageObj_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha); + if (Color(nRed, nGreen, nBlue) == COL_WHITE) + ++nWhitePathCount; + } + + // This was 4, the page contained 4 white paths at problematic positions. + CPPUNIT_ASSERT_EQUAL(0, nWhitePathCount); +#endif +} + +void PdfExportTest::testTdf105093() +{ + vcl::filter::PDFDocument aDocument; + load("tdf105093.odp", aDocument); + + // The document has one page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + // Get page annotations. + auto pAnnots = dynamic_cast<vcl::filter::PDFArrayElement*>(aPages[0]->Lookup("Annots")); + CPPUNIT_ASSERT(pAnnots); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pAnnots->GetElements().size()); + auto pAnnotReference = dynamic_cast<vcl::filter::PDFReferenceElement*>(pAnnots->GetElements()[0]); + CPPUNIT_ASSERT(pAnnotReference); + vcl::filter::PDFObjectElement* pAnnot = pAnnotReference->LookupObject(); + CPPUNIT_ASSERT(pAnnot); + CPPUNIT_ASSERT_EQUAL(OString("Annot"), static_cast<vcl::filter::PDFNameElement*>(pAnnot->Lookup("Type"))->GetValue()); + + // Get the Action -> Rendition -> MediaClip -> FileSpec. + auto pAction = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAnnot->Lookup("A")); + CPPUNIT_ASSERT(pAction); + auto pRendition = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pAction->LookupElement("R")); + CPPUNIT_ASSERT(pRendition); + auto pMediaClip = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pRendition->LookupElement("C")); + CPPUNIT_ASSERT(pMediaClip); + auto pFileSpec = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pMediaClip->LookupElement("D")); + CPPUNIT_ASSERT(pFileSpec); + // Make sure the filespec refers to an embedded file. + // This key was missing, the embedded video was handled as a linked one. + CPPUNIT_ASSERT(pFileSpec->LookupElement("EF")); +} + +void PdfExportTest::testTdf106206() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106206.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + // The page has a stream. + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + // Uncompress it. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure there is an image reference there. + OString aImage("/Im"); + auto pStart = static_cast<const char*>(aUncompressed.GetData()); + const char* pEnd = pStart + aUncompressed.GetSize(); + auto it = std::search(pStart, pEnd, aImage.getStr(), aImage.getStr() + aImage.getLength()); + CPPUNIT_ASSERT(it != pEnd); + + // And also that it's not an invalid one. + OString aInvalidImage("/Im0"); + it = std::search(pStart, pEnd, aInvalidImage.getStr(), aInvalidImage.getStr() + aInvalidImage.getLength()); + // This failed, object #0 was referenced. + CPPUNIT_ASSERT(bool(it == pEnd)); +} + +void PdfExportTest::testTdf109143() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf109143.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + // Get access to the only image on the only page. + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Make sure it's re-compressed. + auto pLength = dynamic_cast<vcl::filter::PDFNumberElement*>(pXObject->Lookup("Length")); + CPPUNIT_ASSERT(pLength); + int nLength = pLength->GetValue(); + // This failed: cropped TIFF-in-JPEG wasn't re-compressed, so crop was + // lost. Size was 59416, now is 11827. + CPPUNIT_ASSERT(nLength < 50000); +} + +void PdfExportTest::testTdf106972() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106972.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // Get access to the only form object on the only page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Get access to the only image inside the form object. + auto pFormResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pFormResources); + auto pImages = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pFormResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pImages); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pImages->GetItems().size()); + vcl::filter::PDFObjectElement* pImage = pImages->LookupObject(pImages->GetItems().begin()->first); + CPPUNIT_ASSERT(pImage); + + // Assert resources of the image. + auto pImageResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pImage->Lookup("Resources")); + CPPUNIT_ASSERT(pImageResources); + // This failed: the PDF image had no Font resource. + CPPUNIT_ASSERT(pImageResources->LookupElement("Font")); +} + +void PdfExportTest::testTdf106972Pdf17() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106972-pdf17.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // Get access to the only image on the only page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Assert that we now attempt to preserve the original PDF data, even if + // the original input was PDF >= 1.4. + CPPUNIT_ASSERT(pXObject->Lookup("Resources")); +} + +void PdfExportTest::testSofthyphenPos() +{ + // No need to run it on Windows, since it would use GDI printing, and not trigger PDF export + // which is the intent of the test. +// FIXME: Why does this fail on macOS? +#if !defined MACOSX && !defined _WIN32 + + // Import the bugdoc and print to PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "softhyphen_pdf.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + uno::Reference<view::XPrintable> xPrintable(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xPrintable.is()); + uno::Sequence<beans::PropertyValue> aOptions(comphelper::InitPropertySequence( + { + {"FileName", uno::makeAny(maTempFile.GetURL())}, + {"Wait", uno::makeAny(true)} + })); + xPrintable->print(aOptions); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + if (aFile.bad() || !aMemory.GetSize()) + { + // Printing to PDF failed in a non-interesting way, e.g. CUPS is not + // running, there is no printer defined, etc. + return; + } + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // tdf#96892 incorrect fractional part of font size caused soft-hyphen to + // be positioned inside preceding text (incorrect = 11.1, correct = 11.05) + + // there are 3 texts currently, for line 1, soft-hyphen, line 2 + bool haveText(false); + + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(pPdfPageObject)); + haveText = true; + double const size(FPDFTextObj_GetFontSize(pPdfPageObject)); + CPPUNIT_ASSERT_DOUBLES_EQUAL(11.05, size, 1E-06); + } + + CPPUNIT_ASSERT(haveText); +#endif +} + +void PdfExportTest::testTdf107013() +{ + vcl::filter::PDFDocument aDocument; + load("tdf107013.odt", aDocument); + + // Get access to the only image on the only page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + // This failed, the reference to the image was created, but not the image. + CPPUNIT_ASSERT(pXObject); +} + +void PdfExportTest::testTdf107018() +{ + vcl::filter::PDFDocument aDocument; + load("tdf107018.odt", aDocument); + + // Get access to the only image on the only page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Get access to the form object inside the image. + auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + // Get access to Resources -> Font -> F1 of the form. + auto pFormResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pForm->Lookup("Resources")); + CPPUNIT_ASSERT(pFormResources); + auto pFonts = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pFormResources->LookupElement("Font")); + CPPUNIT_ASSERT(pFonts); + auto pF1Ref = dynamic_cast<vcl::filter::PDFReferenceElement*>(pFonts->LookupElement("F1")); + CPPUNIT_ASSERT(pF1Ref); + vcl::filter::PDFObjectElement* pF1 = pF1Ref->LookupObject(); + CPPUNIT_ASSERT(pF1); + + // Check that Foo -> Bar of the font is of type Pages. + auto pFontFoo = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pF1->Lookup("Foo")); + CPPUNIT_ASSERT(pFontFoo); + auto pBar = dynamic_cast<vcl::filter::PDFReferenceElement*>(pFontFoo->LookupElement("Bar")); + CPPUNIT_ASSERT(pBar); + vcl::filter::PDFObjectElement* pObject = pBar->LookupObject(); + CPPUNIT_ASSERT(pObject); + auto pName = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + CPPUNIT_ASSERT(pName); + // This was "XObject", reference in a nested dictionary wasn't updated when + // copying the page stream of a PDF image. + CPPUNIT_ASSERT_EQUAL(OString("Pages"), pName->GetValue()); +} + +void PdfExportTest::testTdf107089() +{ + vcl::filter::PDFDocument aDocument; + load("tdf107089.odt", aDocument); + + // Get access to the only image on the only page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Get access to the form object inside the image. + auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + // Make sure 'Hello' is part of the form object's stream. + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + OString aHello("Hello"); + auto pStart = static_cast<const char*>(aObjectStream.GetData()); + const char* pEnd = pStart + aObjectStream.GetSize(); + auto it = std::search(pStart, pEnd, aHello.getStr(), aHello.getStr() + aHello.getLength()); + // This failed, 'Hello' was part only a mixed compressed/uncompressed stream, i.e. garbage. + CPPUNIT_ASSERT(it != pEnd); +} + +void PdfExportTest::testTdf99680() +{ + vcl::filter::PDFDocument aDocument; + load("tdf99680.odt", aDocument); + + // The document has one page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + // The page 1 has a stream. + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + + // Uncompress it. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // tdf#130150 See infos in task - short: tdf#99680 was not the + // correct fix, so empty clip regions are valid - allow again in tests + // Make sure there are no empty clipping regions. + // OString aEmptyRegion("0 0 m h W* n"); + // auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength()); + // CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd); + + // Count save graphic state (q) and restore (Q) operators + // and ensure their amount is equal + auto pStart = static_cast<const char*>(aUncompressed.GetData()); + const char* pEnd = pStart + aUncompressed.GetSize(); + size_t nSaveCount = std::count(pStart, pEnd, 'q'); + size_t nRestoreCount = std::count(pStart, pEnd, 'Q'); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount); +} + +void PdfExportTest::testTdf99680_2() +{ + vcl::filter::PDFDocument aDocument; + load("tdf99680-2.odt", aDocument); + + // For each document page + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aPages.size()); + for (size_t nPageNr = 0; nPageNr < aPages.size(); nPageNr++) + { + // Get page contents and stream. + vcl::filter::PDFObjectElement* pContents = aPages[nPageNr]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // tdf#130150 See infos in task - short: tdf#99680 was not the + // correct fix, so empty clip regions are valid - allow again in tests + // Make sure there are no empty clipping regions. + // OString aEmptyRegion("0 0 m h W* n"); + // auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength()); + // CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd); + + // Count save graphic state (q) and restore (Q) operators + // and ensure their amount is equal + auto pStart = static_cast<const char*>(aUncompressed.GetData()); + const char* pEnd = pStart + aUncompressed.GetSize(); + size_t nSaveCount = std::count(pStart, pEnd, 'q'); + size_t nRestoreCount = std::count(pStart, pEnd, 'Q'); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount); + } +} + +void PdfExportTest::testTdf108963() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf108963.odp"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // FIXME: strangely this fails on some Win systems after a pdfium update, expected: 793.7; actual: 793 +#if !defined _WIN32 + // Test page size (28x15.75 cm, was 1/100th mm off, tdf#112690) + // bad: MediaBox[0 0 793.672440944882 446.428346456693] + // good: MediaBox[0 0 793.700787401575 446.456692913386] + const double aWidth = FPDF_GetPageWidth(pPdfPage.get()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(793.7, aWidth, 0.01); + const double aHeight = FPDF_GetPageHeight(pPdfPage.get()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(446.46, aHeight, 0.01); + + // Make sure there is a filled rectangle inside. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nYellowPathCount = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH) + continue; + + unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0; + FPDFPageObj_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha); + if (Color(nRed, nGreen, nBlue) == COL_YELLOW) + { + ++nYellowPathCount; + // The path described a yellow rectangle, but it was not rotated. + int nSegments = FPDFPath_CountSegments(pPdfPageObject); + CPPUNIT_ASSERT_EQUAL(5, nSegments); + FPDF_PATHSEGMENT pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 0); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(pSegment)); + float fX = 0; + float fY = 0; + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(245395, static_cast<int>(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(244261, static_cast<int>(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 1); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(275102, static_cast<int>(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(267618, static_cast<int>(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 2); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(287518, static_cast<int>(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(251829, static_cast<int>(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 3); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(257839, static_cast<int>(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(228472, static_cast<int>(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 4); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(245395, static_cast<int>(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(244261, static_cast<int>(round(fY * 1000))); + CPPUNIT_ASSERT(FPDFPathSegment_GetClose(pSegment)); + } + } + + CPPUNIT_ASSERT_EQUAL(1, nYellowPathCount); +#endif +} + +void PdfExportTest::testTdf118244_radioButtonGroup() +{ + vcl::filter::PDFDocument aDocument; + load("tdf118244_radioButtonGroup.odt", aDocument); + + // The document has one page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + // There are eight radio buttons. + auto pAnnots = dynamic_cast<vcl::filter::PDFArrayElement*>(aPages[0]->Lookup("Annots")); + CPPUNIT_ASSERT(pAnnots); + CPPUNIT_ASSERT_EQUAL_MESSAGE("# of radio buttons",static_cast<size_t>(8), pAnnots->GetElements().size()); + + sal_uInt32 nRadioGroups = 0; + for ( const auto& aElement : aDocument.GetElements() ) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get()); + if ( !pObject ) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("FT")); + if ( pType && pType->GetValue() == "Btn" ) + { + auto pKids = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject->Lookup("Kids")); + if ( pKids ) + { + size_t expectedSize = 2; + ++nRadioGroups; + if ( nRadioGroups == 3 ) + expectedSize = 3; + CPPUNIT_ASSERT_EQUAL(expectedSize, pKids->GetElements().size()); + } + } + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("# of radio groups", sal_uInt32(3), nRadioGroups); +} + +// This requires Carlito font, if it is missing the test will most likely +// fail. +void PdfExportTest::testTdf115117_1() +{ +#if HAVE_MORE_FONTS + vcl::filter::PDFDocument aDocument; + load("tdf115117-1.odt", aDocument); + + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + + // Get access to ToUnicode of the first font + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pToUnicodeRef = dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + // The first values, <01> <02> etc., are glyph ids, they might change order + // if we changed how font subsets are created. + // The second values, <00740069> etc., are Unicode code points in hex, + // <00740069> is U+0074 and U+0069 i.e. "ti" which is a ligature in + // Carlito/Calibri. This test is failing if any of the second values + // changed which means we are not detecting ligatures and writing CMAP + // entries for them correctly. If glyph order in the subset changes then + // the order here will changes and the PDF has to be carefully inspected to + // ensure that the new values are correct before updating the string below. + OString aCmap("9 beginbfchar\n" + "<01> <00740069>\n" + "<02> <0020>\n" + "<03> <0074>\n" + "<04> <0065>\n" + "<05> <0073>\n" + "<06> <00660069>\n" + "<07> <0066006C>\n" + "<08> <006600660069>\n" + "<09> <00660066006C>\n" + "endbfchar"); + auto pStart = static_cast<const char*>(aObjectStream.GetData()); + const char* pEnd = pStart + aObjectStream.GetSize(); + auto it = std::search(pStart, pEnd, aCmap.getStr(), aCmap.getStr() + aCmap.getLength()); + CPPUNIT_ASSERT(it != pEnd); +#endif +} + +// This requires DejaVu Sans font, if it is missing the test will most likely +// fail. +void PdfExportTest::testTdf115117_2() +{ +#if HAVE_MORE_FONTS + // See the comments in testTdf115117_1() for explanation. + + vcl::filter::PDFDocument aDocument; + load("tdf115117-2.odt", aDocument); + + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pToUnicodeRef = dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + OString aCmap("7 beginbfchar\n" + "<01> <06440627>\n" + "<02> <0020>\n" + "<03> <0641>\n" + "<04> <0642>\n" + "<05> <0648>\n" + "<06> <06440627>\n" + "<07> <0628>\n" + "endbfchar"); + auto pStart = static_cast<const char*>(aObjectStream.GetData()); + const char* pEnd = pStart + aObjectStream.GetSize(); + auto it = std::search(pStart, pEnd, aCmap.getStr(), aCmap.getStr() + aCmap.getLength()); + CPPUNIT_ASSERT(it != pEnd); +#endif +} + +void PdfExportTest::testTdf115117_1a() +{ +#if HAVE_MORE_FONTS + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115117-1.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + auto pPdfTextPage = FPDFText_LoadPage(pPdfPage.get()); + CPPUNIT_ASSERT(pPdfTextPage); + + // Extract the text from the page. This pdfium API is a bit higher level + // than we want and might apply heuristic that give false positive, but it + // is a good approximation in addition to the check in testTdf115117_1(). + int nChars = FPDFText_CountChars(pPdfTextPage); + CPPUNIT_ASSERT_EQUAL(44, nChars); + + OUString aExpectedText = "ti ti test ti\r\nti test fi fl ffi ffl test fi"; + std::vector<sal_uInt32> aChars(nChars); + for (int i = 0; i < nChars; i++) + aChars[i] = FPDFText_GetUnicode(pPdfTextPage, i); + OUString aActualText(aChars.data(), aChars.size()); + CPPUNIT_ASSERT_EQUAL(aExpectedText, aActualText); + + FPDFText_ClosePage(pPdfTextPage); +#endif +} + +void PdfExportTest::testTdf115117_2a() +{ +#if HAVE_MORE_FONTS + // See the comments in testTdf115117_1a() for explanation. + + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115117-2.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + auto pPdfTextPage = FPDFText_LoadPage(pPdfPage.get()); + CPPUNIT_ASSERT(pPdfTextPage); + + int nChars = FPDFText_CountChars(pPdfTextPage); + CPPUNIT_ASSERT_EQUAL(13, nChars); + + OUString aExpectedText = u"\u0627\u0644 \u0628\u0627\u0644 \u0648\u0642\u0641 \u0627\u0644"; + std::vector<sal_uInt32> aChars(nChars); + for (int i = 0; i < nChars; i++) + aChars[i] = FPDFText_GetUnicode(pPdfTextPage, i); + OUString aActualText(aChars.data(), aChars.size()); + CPPUNIT_ASSERT_EQUAL(aExpectedText, aActualText); + + FPDFText_ClosePage(pPdfTextPage); +#endif +} + +void PdfExportTest::testTdf66597_1() +{ +#if HAVE_MORE_FONTS + // This requires Amiri font, if it is missing the test will fail. + vcl::filter::PDFDocument aDocument; + load("tdf66597-1.odt", aDocument); + + { + // Get access to ToUnicode of the first font + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pName = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("BaseFont")); + auto aName = pName->GetValue().copy(7); // skip the subset id + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected font name", OString("Amiri-Regular"), aName); + + auto pToUnicodeRef = dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + // The <01> is glyph id, <0020> is code point. + // The document has three characters <space><nbspace><space>, but the font + // reuses the same glyph for space and nbspace so we should have a single + // CMAP entry for the space, and nbspace will be handled with ActualText + // (tested above). + std::string aCmap("1 beginbfchar\n" + "<01> <0020>\n" + "endbfchar"); + std::string aData(static_cast<const char*>(aObjectStream.GetData()), aObjectStream.GetSize()); + auto nPos = aData.find(aCmap); + CPPUNIT_ASSERT(nPos != std::string::npos); + } + + { + auto aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + // Get page contents and stream. + auto pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + auto pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + auto& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure the expected ActualText is present. + std::string aData(static_cast<const char*>(aUncompressed.GetData()), aUncompressed.GetSize()); + + std::string aActualText("/Span<</ActualText<"); + size_t nCount = 0; + size_t nPos = 0; + while ((nPos = aData.find(aActualText, nPos)) != std::string::npos) + { + nCount++; + nPos += aActualText.length(); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("The should be one ActualText entry!", static_cast<size_t>(1), nCount); + + aActualText = "/Span<</ActualText<FEFF00A0>>>"; + nPos = aData.find(aActualText); + CPPUNIT_ASSERT_MESSAGE("ActualText not found!", nPos != std::string::npos); + } +#endif +} + +// This requires Reem Kufi font, if it is missing the test will fail. +void PdfExportTest::testTdf66597_2() +{ +#if HAVE_MORE_FONTS + vcl::filter::PDFDocument aDocument; + load("tdf66597-2.odt", aDocument); + + { + // Get access to ToUnicode of the first font + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pName = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("BaseFont")); + auto aName = pName->GetValue().copy(7); // skip the subset id + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected font name", OString("ReemKufi-Regular"), aName); + + auto pToUnicodeRef = dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + std::string aCmap("8 beginbfchar\n" + "<02> <0632>\n" + "<03> <0020>\n" + "<04> <0648>\n" + "<05> <0647>\n" + "<06> <062F>\n" + "<08> <062C>\n" + "<09> <0628>\n" + "<0B> <0623>\n" + "endbfchar"); + std::string aData(static_cast<const char*>(aObjectStream.GetData()), aObjectStream.GetSize()); + auto nPos = aData.find(aCmap); + CPPUNIT_ASSERT(nPos != std::string::npos); + } + + { + auto aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + // Get page contents and stream. + auto pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + auto pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + auto& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure the expected ActualText is present. + std::string aData(static_cast<const char*>(aUncompressed.GetData()), aUncompressed.GetSize()); + + std::vector<std::string> aCodes({ "0632", "062C", "0628", "0623" }); + std::string aActualText("/Span<</ActualText<"); + size_t nCount = 0; + size_t nPos = 0; + while ((nPos = aData.find(aActualText, nPos)) != std::string::npos) + { + nCount++; + nPos += aActualText.length(); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of ActualText entries does not match!", aCodes.size(), nCount); + + for (const auto& aCode : aCodes) + { + aActualText = "/Span<</ActualText<FEFF" + aCode + ">>>"; + nPos = aData.find(aActualText); + CPPUNIT_ASSERT_MESSAGE("ActualText not found for " + aCode, nPos != std::string::npos); + } + } +#endif +} + +// This requires Gentium Basic font, if it is missing the test will fail. +void PdfExportTest::testTdf66597_3() +{ +#if HAVE_MORE_FONTS + vcl::filter::PDFDocument aDocument; + load("tdf66597-3.odt", aDocument); + + { + // Get access to ToUnicode of the first font + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pName = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("BaseFont")); + auto aName = pName->GetValue().copy(7); // skip the subset id + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected font name", OString("GentiumBasic"), aName); + + auto pToUnicodeRef = dynamic_cast<vcl::filter::PDFReferenceElement*>(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + std::string aCmap("2 beginbfchar\n" + "<01> <1ECB0331030B>\n" + "<05> <0020>\n" + "endbfchar"); + std::string aData(static_cast<const char*>(aObjectStream.GetData()), aObjectStream.GetSize()); + auto nPos = aData.find(aCmap); + CPPUNIT_ASSERT(nPos != std::string::npos); + } + + { + auto aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + // Get page contents and stream. + auto pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + auto pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + auto& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure the expected ActualText is present. + std::string aData(static_cast<const char*>(aUncompressed.GetData()), aUncompressed.GetSize()); + + std::string aActualText("/Span<</ActualText<FEFF1ECB0331030B>>>"); + size_t nCount = 0; + size_t nPos = 0; + while ((nPos = aData.find(aActualText, nPos)) != std::string::npos) + { + nCount++; + nPos += aActualText.length(); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of ActualText entries does not match!", static_cast<size_t>(4), nCount); + } +#endif +} + +void PdfExportTest::testTdf105954() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf105954.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence( + { { "ReduceImageResolution", uno::Any(true) }, + { "MaxImageResolution", uno::Any(static_cast<sal_Int32>(300)) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // There is a single image on the page. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, nPageObjectCount); + + // Check width of the image. + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), /*index=*/0); + FPDF_IMAGEOBJ_METADATA aMeta; + CPPUNIT_ASSERT(FPDFImageObj_GetImageMetadata(pPageObject, pPdfPage.get(), &aMeta)); + // This was 2000, i.e. the 'reduce to 300 DPI' request was ignored. + // This is now around 238 (228 on macOS). + CPPUNIT_ASSERT_LESS(static_cast<unsigned int>(250), aMeta.width); +} + +void PdfExportTest::testTdf128630() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf128630.odp"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); + DocumentHolder pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Assert the aspect ratio of the only bitmap on the page. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(pPageObject); + CPPUNIT_ASSERT(pBitmap); + int nWidth = FPDFBitmap_GetWidth(pBitmap); + int nHeight = FPDFBitmap_GetHeight(pBitmap); + FPDFBitmap_Destroy(pBitmap); + // Without the accompanying fix in place, this test would have failed with: + // assertion failed + // - Expression: nWidth != nHeight + // i.e. the bitmap lost its custom aspect ratio during export. + CPPUNIT_ASSERT(nWidth != nHeight); + } +} + +void PdfExportTest::testTdf106702() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106702.odt"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has two pages. + CPPUNIT_ASSERT_EQUAL(2, FPDF_GetPageCount(pPdfDocument.get())); + + // First page already has the correct image position. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nExpected = 0; + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nExpected = fTop; + break; + } + + // Second page had an incorrect image position. + pPdfPage.reset(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/1)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nActual = 0; + nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nActual = fTop; + break; + } + + // This failed, vertical pos is 818 points, was 1674 (outside visible page + // bounds). + CPPUNIT_ASSERT_EQUAL(nExpected, nActual); +} + +void PdfExportTest::testTdf113143() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf113143.odp"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); + uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence({ + { "ExportNotesPages", uno::Any(true) }, + // ReduceImageResolution is on by default and that hides the bug we + // want to test. + { "ReduceImageResolution", uno::Any(false) }, + // Set a custom PDF version. + { "SelectPdfVersion", uno::makeAny(static_cast<sal_Int32>(16)) }, + })); + aMediaDescriptor["FilterData"] <<= aFilterData; + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has two pages. + CPPUNIT_ASSERT_EQUAL(2, FPDF_GetPageCount(pPdfDocument.get())); + + // First has the original (larger) image. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nLarger = 0; + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nLarger = fRight - fLeft; + break; + } + + // Second page has the scaled (smaller) image. + pPdfPage.reset(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/1)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nSmaller = 0; + nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nSmaller = fRight - fLeft; + break; + } + + // This failed, both were 319, now nSmaller is 169. + CPPUNIT_ASSERT_LESS(nLarger, nSmaller); + + // The following check used to fail in the past, header was "%PDF-1.5": + maMemory.Seek(0); + OString aExpectedHeader("%PDF-1.6"); + OString aHeader(read_uInt8s_ToOString(maMemory, aExpectedHeader.getLength())); + CPPUNIT_ASSERT_EQUAL(aExpectedHeader, aHeader); +} + +void PdfExportTest::testForcePoint71() +{ + // I just care it doesn't crash + saveAsPDF("forcepoint71.key"); +} + +void PdfExportTest::testTdf115262() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115262.ods"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("calc_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + CPPUNIT_ASSERT_EQUAL(8, FPDF_GetPageCount(pPdfDocument.get())); + + // Get the 6th page. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/5)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Look up the position of the first image and the 400th row. + FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(pPdfPage.get()); + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nFirstImageTop = 0; + int nRowTop = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + + if (FPDFPageObj_GetType(pPageObject) == FPDF_PAGEOBJ_IMAGE) + { + nFirstImageTop = fTop; + } + else if (FPDFPageObj_GetType(pPageObject) == FPDF_PAGEOBJ_TEXT) + { + unsigned long nTextSize = FPDFTextObj_GetText(pPageObject, pTextPage, nullptr, 0); + std::vector<sal_Unicode> aText(nTextSize); + FPDFTextObj_GetText(pPageObject, pTextPage, aText.data(), nTextSize); + OUString sText(aText.data(), nTextSize / 2 - 1); + if (sText == "400") + nRowTop = fTop; + } + } + // Make sure that the top of the "400" is below the top of the image (in + // bottom-right-corner-based PDF coordinates). + // This was: expected less than 144, actual is 199. + CPPUNIT_ASSERT_LESS(nFirstImageTop, nRowTop); + FPDFText_ClosePage(pTextPage); +} + +void PdfExportTest::testTdf121962() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf121962.odt"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Get the first page + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(pPdfPage.get()); + + // Make sure the table sum is displayed as "0", not faulty expression. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_TEXT) + continue; + unsigned long nTextSize = FPDFTextObj_GetText(pPageObject, pTextPage, nullptr, 0); + std::vector<sal_Unicode> aText(nTextSize); + FPDFTextObj_GetText(pPageObject, pTextPage, aText.data(), nTextSize); + OUString sText(aText.data(), nTextSize / 2 - 1); + CPPUNIT_ASSERT(sText != "** Expression is faulty **"); + } + + FPDFText_ClosePage(pTextPage); +} + +void PdfExportTest::testTdf115967() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115967.odt"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Get the first page + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(pPdfPage.get()); + + // Make sure the elements inside a formula in a RTL document are exported + // LTR ( m=750abc ) and not RTL ( m=057cba ) + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + OUString sText; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_TEXT) + continue; + unsigned long nTextSize = FPDFTextObj_GetText(pPageObject, pTextPage, nullptr, 2); + std::vector<sal_Unicode> aText(nTextSize); + FPDFTextObj_GetText(pPageObject, pTextPage, aText.data(), nTextSize); + OUString sChar(aText.data(), nTextSize / 2 - 1); + sText += sChar.trim(); + } + CPPUNIT_ASSERT_EQUAL(OUString("m=750abc"), sText); + + FPDFText_ClosePage(pTextPage); +} + +void PdfExportTest::testTdf121615() +{ + vcl::filter::PDFDocument aDocument; + load("tdf121615.odt", aDocument); + + // The document has one page. + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); + + // Get access to the only image on the only page. + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + vcl::filter::PDFStreamElement* pStream = pXObject->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + + // Load the embedded image. + rObjectStream.Seek( 0 ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + sal_uInt16 format; + ErrCode bResult = rFilter.ImportGraphic(aGraphic, OUString( "import" ), rObjectStream, + GRFILTER_FORMAT_DONTKNOW, &format); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + + // The image should be grayscale 8bit JPEG. + sal_uInt16 jpegFormat = rFilter.GetImportFormatNumberForShortName( JPG_SHORTNAME ); + CPPUNIT_ASSERT( jpegFormat != GRFILTER_FORMAT_NOTFOUND ); + CPPUNIT_ASSERT_EQUAL( jpegFormat, format ); + BitmapEx aBitmap = aGraphic.GetBitmapEx(); + CPPUNIT_ASSERT_EQUAL( 200L, aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL( 300L, aBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL( 8, int(aBitmap.GetBitCount())); + // tdf#121615 was caused by broken handling of data width with 8bit color, + // so the test image has some black in the bottomright corner, check it's there + CPPUNIT_ASSERT_EQUAL( COL_WHITE, aBitmap.GetPixelColor( 0, 0 )); + CPPUNIT_ASSERT_EQUAL( COL_WHITE, aBitmap.GetPixelColor( 0, 299 )); + CPPUNIT_ASSERT_EQUAL( COL_WHITE, aBitmap.GetPixelColor( 199, 0 )); + CPPUNIT_ASSERT_EQUAL( COL_BLACK, aBitmap.GetPixelColor( 199, 299 )); +} + +void PdfExportTest::testTocLink() +{ + // Load the Writer document. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "toc-link.fodt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + // Update the ToC. + uno::Reference<text::XDocumentIndexesSupplier> xDocumentIndexesSupplier(mxComponent, + uno::UNO_QUERY); + CPPUNIT_ASSERT(xDocumentIndexesSupplier.is()); + + uno::Reference<util::XRefreshable> xToc( + xDocumentIndexesSupplier->getDocumentIndexes()->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xToc.is()); + + xToc->refresh(); + + // Save as PDF. + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Ensure there is a link on the first page (in the ToC). + int nStartPos = 0; + FPDF_LINK pLinkAnnot = nullptr; + // Without the accompanying fix in place, this test would have failed, as FPDFLink_Enumerate() + // returned false, as the page contained no links. + CPPUNIT_ASSERT(FPDFLink_Enumerate(pPdfPage.get(), &nStartPos, &pLinkAnnot)); +} + +void PdfExportTest::testReduceSmallImage() +{ + // Load the Writer document. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reduce-small-image.fodt"; + mxComponent = loadFromDesktop(aURL); + + // Save as PDF. + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the PDF: get the image. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get())); + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pPageObject)); + + // Make sure we don't scale down a tiny bitmap. + FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(pPageObject); + CPPUNIT_ASSERT(pBitmap); + int nWidth = FPDFBitmap_GetWidth(pBitmap); + int nHeight = FPDFBitmap_GetHeight(pBitmap); + FPDFBitmap_Destroy(pBitmap); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 16 + // - Actual : 6 + // i.e. the image was scaled down to 300 DPI, even if it had tiny size. + CPPUNIT_ASSERT_EQUAL(16, nWidth); + CPPUNIT_ASSERT_EQUAL(16, nHeight); +} + +void PdfExportTest::testReduceImage() +{ + // Load the Writer document. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reduce-image.fodt"; + mxComponent = loadFromDesktop(aURL); + + // Save as PDF. + uno::Reference<css::lang::XMultiServiceFactory> xFactory = getMultiServiceFactory(); + uno::Reference<document::XFilter> xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference<document::XExporter> xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(mxComponent); + + SvFileStream aOutputStream(maTempFile.GetURL(), StreamMode::WRITE); + uno::Reference<io::XOutputStream> xOutputStream(new utl::OStreamWrapper(aOutputStream)); + + uno::Sequence<beans::PropertyValue> aFilterData( + comphelper::InitPropertySequence({ { "ReduceImageResolution", uno::Any(false) } })); + + // This is intentionally in an "unlucky" order, output stream comes before filter data. + uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({ + { "FilterName", uno::Any(OUString("writer_pdf_Export")) }, + { "OutputStream", uno::Any(xOutputStream) }, + { "FilterData", uno::Any(aFilterData) }, + })); + xFilter->filter(aDescriptor); + aOutputStream.Close(); + + // Parse the PDF: get the image. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get())); + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pPageObject)); + + // Make sure we don't scale down a bitmap. + FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(pPageObject); + CPPUNIT_ASSERT(pBitmap); + int nWidth = FPDFBitmap_GetWidth(pBitmap); + int nHeight = FPDFBitmap_GetHeight(pBitmap); + FPDFBitmap_Destroy(pBitmap); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 160 + // - Actual : 6 + // i.e. the image was scaled down even with ReduceImageResolution=false. + CPPUNIT_ASSERT_EQUAL(160, nWidth); + CPPUNIT_ASSERT_EQUAL(160, nHeight); +} + +bool HasLinksOnPage(PageHolder& pPdfPage) +{ + int nStartPos = 0; + FPDF_LINK pLinkAnnot = nullptr; + return FPDFLink_Enumerate(pPdfPage.get(), &nStartPos, &pLinkAnnot); +} + +void PdfExportTest::testLinkWrongPage() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "link-wrong-page.odp"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); + DocumentHolder pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has 2 pages. + CPPUNIT_ASSERT_EQUAL(2, FPDF_GetPageCount(pPdfDocument.get())); + + // First page should have 1 link (2nd slide, 1st was hidden). + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Without the accompanying fix in place, this test would have failed, as the link of the first + // page went to the second page due to the hidden first slide. + CPPUNIT_ASSERT(HasLinksOnPage(pPdfPage)); + + // Second page should have no links (3rd slide). + PageHolder pPdfPage2(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/1)); + CPPUNIT_ASSERT(pPdfPage2.get()); + CPPUNIT_ASSERT(!HasLinksOnPage(pPdfPage2)); +} + +void PdfExportTest::testLargePage() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "6m-wide.odg"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export"); + DocumentHolder pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has 1 page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Check the value (not the unit) of the page size. + FS_SIZEF aSize; + FPDF_GetPageSizeByIndexF(pPdfDocument.get(), 0, &aSize); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 8503.94 + // - Actual : 17007.875 + // i.e. the value for 600 cm was larger than the 14 400 limit set in the spec. + CPPUNIT_ASSERT_DOUBLES_EQUAL(8503.94, static_cast<double>(aSize.width), 0.01); +} + +void PdfExportTest::testPdfImageResourceInlineXObjectRef() +{ + // Create an empty document. + mxComponent = loadFromDesktop("private:factory/swriter"); + CPPUNIT_ASSERT(mxComponent.is()); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + + // Insert the PDF image. + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xGraphicObject( + xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + OUString aURL + = m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf-image-resource-inline-xobject-ref.pdf"; + xGraphicObject->setPropertyValue("GraphicURL", uno::makeAny(aURL)); + uno::Reference<drawing::XShape> xShape(xGraphicObject, uno::UNO_QUERY); + xShape->setSize(awt::Size(1000, 1000)); + uno::Reference<text::XTextContent> xTextContent(xGraphicObject, uno::UNO_QUERY); + xText->insertTextContent(xCursor->getStart(), xTextContent, /*bAbsorb=*/false); + + // Save as PDF. + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Make sure that the page -> form -> form has a child image. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get())); + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pPageObject)); + // 2: white background and the actual object. + CPPUNIT_ASSERT_EQUAL(2, FPDFFormObj_CountObjects(pPageObject)); + FPDF_PAGEOBJECT pFormObject = FPDFFormObj_GetObject(pPageObject, 1); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pFormObject)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the sub-form was missing its image. + CPPUNIT_ASSERT_EQUAL(1, FPDFFormObj_CountObjects(pFormObject)); + + // Check if the inner form object (original page object in the pdf image) has the correct + // rotation. + FPDF_PAGEOBJECT pInnerFormObject = FPDFFormObj_GetObject(pFormObject, 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pInnerFormObject)); + CPPUNIT_ASSERT_EQUAL(1, FPDFFormObj_CountObjects(pInnerFormObject)); + FPDF_PAGEOBJECT pImage = FPDFFormObj_GetObject(pInnerFormObject, 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pImage)); + FS_MATRIX aMatrix; + FPDFFormObj_GetMatrix(pInnerFormObject, &aMatrix); + basegfx::B2DHomMatrix aMat{ aMatrix.a, aMatrix.c, aMatrix.e, aMatrix.b, aMatrix.d, aMatrix.f }; + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate = 0; + double fShearX = 0; + aMat.decompose(aScale, aTranslate, fRotate, fShearX); + int nRotateDeg = basegfx::rad2deg(fRotate); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: -90 + // - Actual : 0 + // i.e. rotation was lost on pdf export. + CPPUNIT_ASSERT_EQUAL(-90, nRotateDeg); +} + +void PdfExportTest::testDefaultVersion() +{ + // Create an empty document. + mxComponent = loadFromDesktop("private:factory/swriter"); + CPPUNIT_ASSERT(mxComponent.is()); + + // Save as PDF. + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + int nFileVersion = 0; + FPDF_GetFileVersion(pPdfDocument.get(), &nFileVersion); + CPPUNIT_ASSERT_EQUAL(16, nFileVersion); +} + +void PdfExportTest::testVersion15() +{ + // Create an empty document. + mxComponent = loadFromDesktop("private:factory/swriter"); + CPPUNIT_ASSERT(mxComponent.is()); + + // Save as PDF. + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence( + { { "SelectPdfVersion", uno::makeAny(static_cast<sal_Int32>(15)) } })); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + aMediaDescriptor["FilterData"] <<= aFilterData; + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + int nFileVersion = 0; + FPDF_GetFileVersion(pPdfDocument.get(), &nFileVersion); + CPPUNIT_ASSERT_EQUAL(15, nFileVersion); +} + +// Check round-trip of importing and exporting the PDF with PDFium filter, +// which imports the PDF document as multiple PDFs as graphic object. +// Each page in the document has one PDF graphic object which content is +// the corresponding page in the PDF. When such a document is exported, +// the PDF graphic gets embedded into the exported PDF document (as a +// Form XObject). +void PdfExportTest::testMultiPagePDF() +{ +// setenv only works on unix based systems +#ifndef _WIN32 + // We need to enable PDFium import (and make sure to disable after the test) + bool bResetEnvVar = false; + if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) + { + bResetEnvVar = true; + setenv("LO_IMPORT_USE_PDFIUM", "1", false); + } + comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { + if (bResetEnvVar) + unsetenv("LO_IMPORT_USE_PDFIUM"); + }); + + // Load the PDF and save as PDF + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aPages.size()); + + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + + auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pXObjects->GetItems().size()); // 3 PDFs as Form XObjects + + std::vector<OString> rIDs; + for (auto const & rPair : pXObjects->GetItems()) { + rIDs.push_back(rPair.first); + } + + // Let's check the embedded PDF pages - just make sure the size differs, + // which should indicate we don't have 3 times the same page. + + { // embedded PDF page 1 + vcl::filter::PDFObjectElement* pXObject1 = pXObjects->LookupObject(rIDs[0]); + CPPUNIT_ASSERT(pXObject1); + CPPUNIT_ASSERT_EQUAL(OString("Im19"), rIDs[0]); + + auto pSubtype1 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject1->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype1); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype1->GetValue()); + + auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject1->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Just check that the size of the page stream is what is expected. + CPPUNIT_ASSERT_EQUAL(sal_uInt64(230), rObjectStream.remainingSize()); + } + + { // embedded PDF page 2 + vcl::filter::PDFObjectElement* pXObject2 = pXObjects->LookupObject(rIDs[1]); + CPPUNIT_ASSERT(pXObject2); + CPPUNIT_ASSERT_EQUAL(OString("Im34"), rIDs[1]); + + auto pSubtype2 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject2->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype2); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype2->GetValue()); + + auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject2->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Just check that the size of the page stream is what is expected + CPPUNIT_ASSERT_EQUAL(sal_uInt64(309), rObjectStream.remainingSize()); + } + + { // embedded PDF page 3 + vcl::filter::PDFObjectElement* pXObject3 = pXObjects->LookupObject(rIDs[2]); + CPPUNIT_ASSERT(pXObject3); + CPPUNIT_ASSERT_EQUAL(OString("Im4"), rIDs[2]); + + auto pSubtype3 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject3->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype3); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype3->GetValue()); + + auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject3->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Just check that the size of the page stream is what is expected + CPPUNIT_ASSERT_EQUAL(sal_uInt64(193), rObjectStream.remainingSize()); + } +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/png/PngFilterTest.cxx b/vcl/qa/cppunit/png/PngFilterTest.cxx new file mode 100644 index 000000000..c304ee9d3 --- /dev/null +++ b/vcl/qa/cppunit/png/PngFilterTest.cxx @@ -0,0 +1,193 @@ +/* -*- 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 incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <test/bootstrapfixture.hxx> +#include <tools/stream.hxx> +#include <vcl/filter/PngImageReader.hxx> +#include <vcl/bitmapaccess.hxx> +#include <vcl/alpha.hxx> + +using namespace css; + +class PngFilterTest : public test::BootstrapFixture +{ + OUString maDataUrl; + + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(maDataUrl) + sFileName; + } + +public: + PngFilterTest() + : BootstrapFixture(true, false) + , maDataUrl("/vcl/qa/cppunit/png/data/") + { + } + + void testPng(); + + CPPUNIT_TEST_SUITE(PngFilterTest); + CPPUNIT_TEST(testPng); + CPPUNIT_TEST_SUITE_END(); +}; + +void PngFilterTest::testPng() +{ + for (const OUString& aFileName : { OUString("rect-1bit-pal.png") }) + { + SvFileStream aFileStream(getFullUrl(aFileName), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + Bitmap aBitmap = aBitmapEx.GetBitmap(); + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height()); + + if (pAccess->GetBitCount() == 24 || pAccess->GetBitCount() == 32) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 2)); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false); + } + } + } + for (const OUString& aFileName : + { OUString("color-rect-8bit-RGB.png"), OUString("color-rect-4bit-pal.png") }) + { + SvFileStream aFileStream(getFullUrl(aFileName), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + Bitmap aBitmap = aBitmapEx.GetBitmap(); + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height()); + if (pAccess->GetBitCount() == 24 || pAccess->GetBitCount() == 32) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2)); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false); + } + } + } + for (const OUString& aFileName : { OUString("alpha-rect-8bit-RGBA.png") }) + { + SvFileStream aFileStream(getFullUrl(aFileName), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + Bitmap aBitmap = aBitmapEx.GetBitmap(); + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height()); + + if (pAccess->GetBitCount() == 24) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2)); + + AlphaMask aAlpha = aBitmapEx.GetAlpha(); + { + AlphaMask::ScopedReadAccess pAlphaAccess(aAlpha); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), pAlphaAccess->GetBitCount()); + CPPUNIT_ASSERT_EQUAL(4L, pAlphaAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAlphaAccess->Height()); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00), + pAlphaAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00), + pAlphaAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00), + pAlphaAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00), + pAlphaAccess->GetPixel(2, 2)); + } + } + else if (pAccess->GetBitCount() == 32) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x40), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0xC0), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0xC0), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x40), pAccess->GetPixel(2, 2)); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false); + } + } + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(PngFilterTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png b/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png Binary files differnew file mode 100644 index 000000000..1e90e1a6c --- /dev/null +++ b/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png diff --git a/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png b/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png Binary files differnew file mode 100644 index 000000000..740eede51 --- /dev/null +++ b/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png diff --git a/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png b/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png Binary files differnew file mode 100644 index 000000000..727859d8a --- /dev/null +++ b/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png diff --git a/vcl/qa/cppunit/png/data/rect-1bit-pal.png b/vcl/qa/cppunit/png/data/rect-1bit-pal.png Binary files differnew file mode 100644 index 000000000..cf7ac3e7c --- /dev/null +++ b/vcl/qa/cppunit/png/data/rect-1bit-pal.png diff --git a/vcl/qa/cppunit/svm/data/arc.svm b/vcl/qa/cppunit/svm/data/arc.svm Binary files differnew file mode 100644 index 000000000..5d443a704 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/arc.svm diff --git a/vcl/qa/cppunit/svm/data/bitmapexs.svm b/vcl/qa/cppunit/svm/data/bitmapexs.svm Binary files differnew file mode 100644 index 000000000..f6860bdff --- /dev/null +++ b/vcl/qa/cppunit/svm/data/bitmapexs.svm diff --git a/vcl/qa/cppunit/svm/data/bitmaps.svm b/vcl/qa/cppunit/svm/data/bitmaps.svm Binary files differnew file mode 100644 index 000000000..bf42f1bae --- /dev/null +++ b/vcl/qa/cppunit/svm/data/bitmaps.svm diff --git a/vcl/qa/cppunit/svm/data/chord.svm b/vcl/qa/cppunit/svm/data/chord.svm Binary files differnew file mode 100644 index 000000000..7c7136eed --- /dev/null +++ b/vcl/qa/cppunit/svm/data/chord.svm diff --git a/vcl/qa/cppunit/svm/data/clipregion.svm b/vcl/qa/cppunit/svm/data/clipregion.svm Binary files differnew file mode 100644 index 000000000..aa0d277fe --- /dev/null +++ b/vcl/qa/cppunit/svm/data/clipregion.svm diff --git a/vcl/qa/cppunit/svm/data/ellipse.svm b/vcl/qa/cppunit/svm/data/ellipse.svm Binary files differnew file mode 100644 index 000000000..369e4292c --- /dev/null +++ b/vcl/qa/cppunit/svm/data/ellipse.svm diff --git a/vcl/qa/cppunit/svm/data/fillcolor.svm b/vcl/qa/cppunit/svm/data/fillcolor.svm Binary files differnew file mode 100644 index 000000000..8e1a826c4 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/fillcolor.svm diff --git a/vcl/qa/cppunit/svm/data/gradient.svm b/vcl/qa/cppunit/svm/data/gradient.svm Binary files differnew file mode 100644 index 000000000..68811e065 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/gradient.svm diff --git a/vcl/qa/cppunit/svm/data/hatch.svm b/vcl/qa/cppunit/svm/data/hatch.svm Binary files differnew file mode 100644 index 000000000..4e6bdf638 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/hatch.svm diff --git a/vcl/qa/cppunit/svm/data/line.svm b/vcl/qa/cppunit/svm/data/line.svm Binary files differnew file mode 100644 index 000000000..67441ec92 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/line.svm diff --git a/vcl/qa/cppunit/svm/data/linecolor.svm b/vcl/qa/cppunit/svm/data/linecolor.svm Binary files differnew file mode 100644 index 000000000..2cba7f734 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/linecolor.svm diff --git a/vcl/qa/cppunit/svm/data/masks.svm b/vcl/qa/cppunit/svm/data/masks.svm Binary files differnew file mode 100644 index 000000000..b9e777930 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/masks.svm diff --git a/vcl/qa/cppunit/svm/data/overlinecolor.svm b/vcl/qa/cppunit/svm/data/overlinecolor.svm Binary files differnew file mode 100644 index 000000000..10cd773fb --- /dev/null +++ b/vcl/qa/cppunit/svm/data/overlinecolor.svm diff --git a/vcl/qa/cppunit/svm/data/pie.svm b/vcl/qa/cppunit/svm/data/pie.svm Binary files differnew file mode 100644 index 000000000..1eaf67447 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/pie.svm diff --git a/vcl/qa/cppunit/svm/data/pixel.svm b/vcl/qa/cppunit/svm/data/pixel.svm Binary files differnew file mode 100644 index 000000000..dc15ab8f0 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/pixel.svm diff --git a/vcl/qa/cppunit/svm/data/point.svm b/vcl/qa/cppunit/svm/data/point.svm Binary files differnew file mode 100644 index 000000000..5b5c3731b --- /dev/null +++ b/vcl/qa/cppunit/svm/data/point.svm diff --git a/vcl/qa/cppunit/svm/data/polygon.svm b/vcl/qa/cppunit/svm/data/polygon.svm Binary files differnew file mode 100644 index 000000000..162ccfd9c --- /dev/null +++ b/vcl/qa/cppunit/svm/data/polygon.svm diff --git a/vcl/qa/cppunit/svm/data/polyline.svm b/vcl/qa/cppunit/svm/data/polyline.svm Binary files differnew file mode 100644 index 000000000..9139da371 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/polyline.svm diff --git a/vcl/qa/cppunit/svm/data/polypolygon.svm b/vcl/qa/cppunit/svm/data/polypolygon.svm Binary files differnew file mode 100644 index 000000000..ea01bd14a --- /dev/null +++ b/vcl/qa/cppunit/svm/data/polypolygon.svm diff --git a/vcl/qa/cppunit/svm/data/pushpop.svm b/vcl/qa/cppunit/svm/data/pushpop.svm Binary files differnew file mode 100644 index 000000000..d5ab6e80a --- /dev/null +++ b/vcl/qa/cppunit/svm/data/pushpop.svm diff --git a/vcl/qa/cppunit/svm/data/rasterop.svm b/vcl/qa/cppunit/svm/data/rasterop.svm Binary files differnew file mode 100644 index 000000000..ac9f796c2 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/rasterop.svm diff --git a/vcl/qa/cppunit/svm/data/rect.svm b/vcl/qa/cppunit/svm/data/rect.svm Binary files differnew file mode 100644 index 000000000..8c398b572 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/rect.svm diff --git a/vcl/qa/cppunit/svm/data/roundrect.svm b/vcl/qa/cppunit/svm/data/roundrect.svm Binary files differnew file mode 100644 index 000000000..aa0ca3e29 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/roundrect.svm diff --git a/vcl/qa/cppunit/svm/data/strecthtext.svm b/vcl/qa/cppunit/svm/data/strecthtext.svm Binary files differnew file mode 100644 index 000000000..f6dcb5fba --- /dev/null +++ b/vcl/qa/cppunit/svm/data/strecthtext.svm diff --git a/vcl/qa/cppunit/svm/data/text.svm b/vcl/qa/cppunit/svm/data/text.svm Binary files differnew file mode 100644 index 000000000..37da7f598 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/text.svm diff --git a/vcl/qa/cppunit/svm/data/textalign.svm b/vcl/qa/cppunit/svm/data/textalign.svm Binary files differnew file mode 100644 index 000000000..091c49876 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textalign.svm diff --git a/vcl/qa/cppunit/svm/data/textarray.svm b/vcl/qa/cppunit/svm/data/textarray.svm Binary files differnew file mode 100644 index 000000000..7863b03ce --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textarray.svm diff --git a/vcl/qa/cppunit/svm/data/textcolor.svm b/vcl/qa/cppunit/svm/data/textcolor.svm Binary files differnew file mode 100644 index 000000000..f55b3ccd7 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textcolor.svm diff --git a/vcl/qa/cppunit/svm/data/textfillecolor.svm b/vcl/qa/cppunit/svm/data/textfillecolor.svm Binary files differnew file mode 100644 index 000000000..52a4f29f3 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textfillecolor.svm diff --git a/vcl/qa/cppunit/svm/data/textline.svm b/vcl/qa/cppunit/svm/data/textline.svm Binary files differnew file mode 100644 index 000000000..1d8517823 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textline.svm diff --git a/vcl/qa/cppunit/svm/data/textlinecolor.svm b/vcl/qa/cppunit/svm/data/textlinecolor.svm Binary files differnew file mode 100644 index 000000000..786dfc465 --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textlinecolor.svm diff --git a/vcl/qa/cppunit/svm/data/textrectangle.svm b/vcl/qa/cppunit/svm/data/textrectangle.svm Binary files differnew file mode 100644 index 000000000..62c424d6a --- /dev/null +++ b/vcl/qa/cppunit/svm/data/textrectangle.svm diff --git a/vcl/qa/cppunit/svm/data/transparent.svm b/vcl/qa/cppunit/svm/data/transparent.svm Binary files differnew file mode 100644 index 000000000..40864b90a --- /dev/null +++ b/vcl/qa/cppunit/svm/data/transparent.svm diff --git a/vcl/qa/cppunit/svm/data/wallpaper.svm b/vcl/qa/cppunit/svm/data/wallpaper.svm Binary files differnew file mode 100644 index 000000000..8fca8c31f --- /dev/null +++ b/vcl/qa/cppunit/svm/data/wallpaper.svm diff --git a/vcl/qa/cppunit/svm/svmtest.cxx b/vcl/qa/cppunit/svm/svmtest.cxx new file mode 100644 index 000000000..413c3b7f6 --- /dev/null +++ b/vcl/qa/cppunit/svm/svmtest.cxx @@ -0,0 +1,1684 @@ +/* -*- 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 <test/xmltesttools.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/gradient.hxx> +#include <vcl/hatch.hxx> +#include <vcl/lineinfo.hxx> +#include <vcl/virdev.hxx> +#include <bitmapwriteaccess.hxx> +#include <vcl/pngwrite.hxx> + +#include <config_features.h> +#if HAVE_FEATURE_OPENGL +#include <vcl/opengl/OpenGLHelper.hxx> +#endif +#include <vcl/skia/SkiaHelper.hxx> + +using namespace css; + +class SvmTest : public test::BootstrapFixture, public XmlTestTools +{ + OUString maDataUrl; + + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(maDataUrl) + sFileName; + } + + void checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtualDev, const GDIMetaFile& rMetaFile); + + // write GDI Metafile to a file in data directory + // only use this for new tests to create the svm file + void writeToFile(GDIMetaFile& rMetaFile, OUString const & rName); + + GDIMetaFile writeAndReadStream(GDIMetaFile& rMetaFile, OUString const & rName = OUString()); + + GDIMetaFile readFile(const OUString& sName); + + xmlDocUniquePtr dumpMeta(const GDIMetaFile& rMetaFile); + + void checkVirtualDevice(const xmlDocUniquePtr& pDoc); + void checkErase(const xmlDocUniquePtr& pDoc); + + void checkPixel(const GDIMetaFile& rMetaFile); + void testPixel(); + + void checkPoint(const GDIMetaFile& rMetaFile); + void testPoint(); + + void checkLine(const GDIMetaFile& rMetaFile); + void testLine(); + + void checkRect(const GDIMetaFile& rMetaFile); + void testRect(); + + void checkRoundRect(const GDIMetaFile& rMetaFile); + void testRoundRect(); + + void checkEllipse(const GDIMetaFile& rMetaFile); + void testEllipse(); + + void checkArc(const GDIMetaFile& rMetaFile); + void testArc(); + + void checkPie(const GDIMetaFile& rMetaFile); + void testPie(); + + void checkChord(const GDIMetaFile& rMetaFile); + void testChord(); + + void checkPolyLine(const GDIMetaFile& rMetaFile); + void testPolyLine(); + + void checkPolygon(const GDIMetaFile& rMetaFile); + void testPolygon(); + + void checkPolyPolygon(const GDIMetaFile& rMetaFile); + void testPolyPolygon(); + + void checkText(const GDIMetaFile& rMetaFile); + void testText(); + + void checkTextArray(const GDIMetaFile& rMetaFile); + void testTextArray(); + + void checkStrechText(const GDIMetaFile& rMetaFile); + void testStrechText(); + + void checkTextRect(const GDIMetaFile& rMetaFile); + void testTextRect(); + + void checkTextLine(const GDIMetaFile& rMetaFile); + void testTextLine(); + + void checkBitmaps(const GDIMetaFile& rMetaFile); + void testBitmaps(); + + void checkBitmapExs(const GDIMetaFile& rMetaFile); + void testBitmapExs(); + + void checkMasks(const GDIMetaFile& rMetaFile); + void testMasks(); + + void checkGradient(const GDIMetaFile& rMetaFile); + void testGradient(); + + //void checkGradientEx(const GDIMetaFile& rMetaFile); + void testGradientEx(); + + void checkHatch(const GDIMetaFile& rMetaFile); + void testHatch(); + + void checkWallpaper(const GDIMetaFile& rMetaFile); + void testWallpaper(); + + void checkClipRegion(const GDIMetaFile& rMetaFile); + void testClipRegion(); + + //void checkIntersectRectClipRegion(const GDIMetaFile& rMetaFile); + void testIntersectRectClipRegion(); + + //void checkIntersectRegionClipRegion(const GDIMetaFile& rMetaFile); + void testIntersectRegionClipRegion(); + + //void checkMoveClipRegion(const GDIMetaFile& rMetaFile); + void testMoveClipRegion(); + + void checkLineColor(const GDIMetaFile& rMetaFile); + void testLineColor(); + + void checkFillColor(const GDIMetaFile& rMetaFile); + void testFillColor(); + + void checkTextColor(const GDIMetaFile& rMetaFile); + void testTextColor(); + + void checkTextFillColor(const GDIMetaFile& rMetaFile); + void testTextFillColor(); + + void checkTextLineColor(const GDIMetaFile& rMetaFile); + void testTextLineColor(); + + void checkOverLineColor(const GDIMetaFile& rMetaFile); + void testOverLineColor(); + + void checkTextAlign(const GDIMetaFile& rMetaFile); + void testTextAlign(); + + //void checkMapMode(const GDIMetaFile& rMetaFile); + void testMapMode(); + + //void checkFont(const GDIMetaFile& rMetaFile); + void testFont(); + + void checkPushPop(const GDIMetaFile& rMetaFile); + void testPushPop(); + + void checkRasterOp(const GDIMetaFile& rMetaFile); + void testRasterOp(); + + void checkTransparent(const GDIMetaFile& rMetaFile); + void testTransparent(); + + //void checkFloatTransparent(const GDIMetaFile& rMetaFile); + void testFloatTransparent(); + + //void checkEPS(const GDIMetaFile& rMetaFile); + void testEPS(); + + //void checkRefPoint(const GDIMetaFile& rMetaFile); + void testRefPoint(); + + //void checkComment(const GDIMetaFile& rMetaFile); + void testComment(); + + //void checkLayoutMode(const GDIMetaFile& rMetaFile); + void testLayoutMode(); + + //void checkTextLanguage(const GDIMetaFile& rMetaFile); + void testTextLanguage(); + +public: + SvmTest() + : BootstrapFixture(true, false) + , maDataUrl("/vcl/qa/cppunit/svm/data/") + {} + + CPPUNIT_TEST_SUITE(SvmTest); + CPPUNIT_TEST(testPixel); + CPPUNIT_TEST(testPoint); + CPPUNIT_TEST(testLine); + CPPUNIT_TEST(testRect); + CPPUNIT_TEST(testRoundRect); + CPPUNIT_TEST(testEllipse); + CPPUNIT_TEST(testArc); + CPPUNIT_TEST(testPie); + CPPUNIT_TEST(testChord); + CPPUNIT_TEST(testPolyLine); + CPPUNIT_TEST(testPolygon); + CPPUNIT_TEST(testPolyPolygon); + CPPUNIT_TEST(testText); + CPPUNIT_TEST(testTextArray); + CPPUNIT_TEST(testStrechText); + CPPUNIT_TEST(testTextRect); + CPPUNIT_TEST(testTextLine); + CPPUNIT_TEST(testBitmaps); // BMP, BMPSCALE, BMPSCALEPART + CPPUNIT_TEST(testBitmapExs); // BMPEX, BMPEXSCALE, BMPEXSCALEPART + CPPUNIT_TEST(testMasks); // MASK, MASKSCALE, MASKSCALEPART + CPPUNIT_TEST(testGradient); + CPPUNIT_TEST(testGradientEx); + CPPUNIT_TEST(testHatch); + CPPUNIT_TEST(testWallpaper); + CPPUNIT_TEST(testClipRegion); + CPPUNIT_TEST(testIntersectRectClipRegion); + CPPUNIT_TEST(testIntersectRegionClipRegion); + CPPUNIT_TEST(testMoveClipRegion); + CPPUNIT_TEST(testLineColor); + CPPUNIT_TEST(testFillColor); + CPPUNIT_TEST(testTextColor); + CPPUNIT_TEST(testTextFillColor); + CPPUNIT_TEST(testTextLineColor); + CPPUNIT_TEST(testOverLineColor); + CPPUNIT_TEST(testTextAlign); + CPPUNIT_TEST(testMapMode); + CPPUNIT_TEST(testFont); + CPPUNIT_TEST(testPushPop); + CPPUNIT_TEST(testRasterOp); + CPPUNIT_TEST(testTransparent); + CPPUNIT_TEST(testFloatTransparent); + CPPUNIT_TEST(testEPS); + CPPUNIT_TEST(testRefPoint); + CPPUNIT_TEST(testComment); + CPPUNIT_TEST(testLayoutMode); + CPPUNIT_TEST(testTextLanguage); + + CPPUNIT_TEST_SUITE_END(); +}; + +static void setupBaseVirtualDevice(VirtualDevice& rDevice, GDIMetaFile& rMeta) +{ + rDevice.SetConnectMetaFile(&rMeta); + Size aVDSize(10, 10); + rDevice.SetOutputSizePixel(aVDSize); + rDevice.SetBackground(Wallpaper(COL_LIGHTRED)); + rDevice.Erase(); +} + +void SvmTest::checkRendering(ScopedVclPtrInstance<VirtualDevice> const & pVirtualDev, const GDIMetaFile& rMetaFile) +{ + BitmapEx aSourceBitmapEx = pVirtualDev->GetBitmapEx(Point(), Size(10, 10)); + ScopedVclPtrInstance<VirtualDevice> pVirtualDevResult; + const_cast<GDIMetaFile&>(rMetaFile).Play(pVirtualDevResult.get()); + BitmapEx aResultBitmapEx = pVirtualDev->GetBitmapEx(Point(), Size(10, 10)); + + const bool bWriteCompareBitmap = false; + + if (bWriteCompareBitmap) + { + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + + { + SvFileStream aStream(aTempFile.GetURL() + ".source.png", StreamMode::WRITE | StreamMode::TRUNC); + vcl::PNGWriter aPNGWriter(aSourceBitmapEx); + aPNGWriter.Write(aStream); + } + { + SvFileStream aStream(aTempFile.GetURL() + ".result.png", StreamMode::WRITE | StreamMode::TRUNC); + vcl::PNGWriter aPNGWriter(aResultBitmapEx); + aPNGWriter.Write(aStream); + } + } + CPPUNIT_ASSERT_EQUAL(aSourceBitmapEx.GetChecksum(), aResultBitmapEx.GetChecksum()); +} + +static GDIMetaFile readMetafile(const OUString& rUrl) +{ + GDIMetaFile aResultMetafile; + SvFileStream aFileStream(rUrl, StreamMode::READ); + aFileStream.Seek(STREAM_SEEK_TO_BEGIN); + aResultMetafile.Read(aFileStream); + return aResultMetafile; +} + +static void writeMetaFile(GDIMetaFile& rInputMetafile, const OUString& rUrl) +{ + SvFileStream aFileStream(rUrl, StreamMode::WRITE); + aFileStream.Seek(STREAM_SEEK_TO_BEGIN); + rInputMetafile.Write(aFileStream); + aFileStream.Close(); +} + +void SvmTest::writeToFile(GDIMetaFile& rMetaFile, OUString const & rName) +{ + if (rName.isEmpty()) + return; + OUString sFilePath = getFullUrl(rName); + writeMetaFile(rMetaFile, sFilePath); +} + +GDIMetaFile SvmTest::writeAndReadStream(GDIMetaFile& rMetaFile, OUString const & rName) +{ + if (!rName.isEmpty()) + writeToFile(rMetaFile, rName); + + SvMemoryStream aStream; + rMetaFile.Write(aStream); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + GDIMetaFile aResultMetafile; + aResultMetafile.Read(aStream); + return aResultMetafile; +} + +GDIMetaFile SvmTest::readFile(const OUString& sName) +{ + OUString sFilePath = getFullUrl(sName); + return readMetafile(sFilePath); +} + +xmlDocUniquePtr SvmTest::dumpMeta(const GDIMetaFile& rMetaFile) +{ + MetafileXmlDump dumper; + xmlDocUniquePtr pDoc = dumpAndParse(dumper, rMetaFile); + CPPUNIT_ASSERT (pDoc); + + checkVirtualDevice(pDoc); + checkErase(pDoc); + + return pDoc; +} + +void SvmTest::checkVirtualDevice(const xmlDocUniquePtr& pDoc) +{ + assertXPath(pDoc, "/metafile/linecolor[1]", "color", "#000000"); + assertXPath(pDoc, "/metafile/fillcolor[1]", "color", "#ffffff"); + + assertXPathAttrs(pDoc, "/metafile/rect[1]", { + {"left", "0"}, {"top", "0"}, + {"right", "9"}, {"bottom", "9"} + }); + + assertXPath(pDoc, "/metafile/linecolor[2]", "color", "#000000"); + assertXPath(pDoc, "/metafile/fillcolor[2]", "color", "#ffffff"); +} + +void SvmTest::checkErase(const xmlDocUniquePtr& pDoc) +{ + assertXPath(pDoc, "/metafile/linecolor[3]", "color", "#000000"); + assertXPath(pDoc, "/metafile/fillcolor[3]", "color", "#ff0000"); + + assertXPathAttrs(pDoc, "/metafile/rect[2]", { + {"left", "0"}, {"top", "0"}, + {"right", "9"}, {"bottom", "9"} + }); +} + +void SvmTest::checkPixel(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/pixel[1]", { + {"x", "8"}, {"y", "1"}, {"color", "#008000"}, + }); + + assertXPathAttrs(pDoc, "/metafile/pixel[2]", { + {"x", "1"}, {"y", "8"}, {"color", "#000080"}, + }); +} + +void SvmTest::testPixel() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawPixel(Point(8, 1), COL_GREEN); + pVirtualDev->DrawPixel(Point(1, 8), COL_BLUE); + + checkPixel(writeAndReadStream(aGDIMetaFile)); + checkPixel(readFile("pixel.svm")); +} + +void SvmTest::checkPoint(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/point[1]", { + {"x", "4"}, {"y", "4"} + }); +} + +void SvmTest::testPoint() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawPixel(Point(4, 4)); + + checkPoint(writeAndReadStream(aGDIMetaFile)); + checkPoint(readFile("point.svm")); +} + +void SvmTest::checkLine(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/line[1]", { + {"startx", "1"}, {"starty", "1"}, + {"endx", "8"}, {"endy", "8"}, + }); + + assertXPathAttrs(pDoc, "/metafile/line[1]", { + {"style", "solid"}, {"width", "0"}, + {"dashlen", "0"}, {"dashcount", "0"}, + {"dotlen", "0"}, {"dotcount", "0"}, + {"distance", "0"}, + {"join", "round"}, {"cap", "butt"} + }); + + assertXPathAttrs(pDoc, "/metafile/line[2]", { + {"startx", "1"}, {"starty", "8"}, + {"endx", "8"}, {"endy", "1"}, + }); + + assertXPathAttrs(pDoc, "/metafile/line[2]", { + {"style", "dash"}, {"width", "7"}, + {"dashlen", "5"}, {"dashcount", "4"}, + {"dotlen", "3"}, {"dotcount", "2"}, + {"distance", "1"}, + {"join", "miter"}, {"cap", "round"} + }); +} + +void SvmTest::testLine() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawLine(Point(1, 1), Point(8, 8)); + LineInfo aLineInfo(LineStyle::Dash, 7); + aLineInfo.SetDashLen(5); + aLineInfo.SetDashCount(4); + aLineInfo.SetDotLen(3); + aLineInfo.SetDotCount(2); + aLineInfo.SetDistance(1); + aLineInfo.SetLineJoin(basegfx::B2DLineJoin::Miter); + aLineInfo.SetLineCap(css::drawing::LineCap_ROUND); + pVirtualDev->DrawLine(Point(1, 8), Point(8, 1), aLineInfo); + + checkLine(writeAndReadStream(aGDIMetaFile)); + checkLine(readFile("line.svm")); +} + +void SvmTest::checkRect(const GDIMetaFile& rMetaFile) +{ + + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/rect[3]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + }); +} + +void SvmTest::testRect() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawRect(tools::Rectangle(Point(1, 2), Size(4, 4))); + + checkRect(writeAndReadStream(aGDIMetaFile)); + checkRect(readFile("rect.svm")); +} + +void SvmTest::checkRoundRect(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/roundrect[1]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + {"horizontalround", "1"}, {"verticalround", "2"} + }); +} + +void SvmTest::testRoundRect() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawRect(tools::Rectangle(Point(1, 2), Size(4, 4)), 1, 2); + + checkRoundRect(writeAndReadStream(aGDIMetaFile)); + checkRoundRect(readFile("roundrect.svm")); +} + +void SvmTest::checkEllipse(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/ellipse[1]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + }); +} + +void SvmTest::testEllipse() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawEllipse(tools::Rectangle(Point(1, 2), Size(4, 4))); + + checkEllipse(writeAndReadStream(aGDIMetaFile)); + checkEllipse(readFile("ellipse.svm")); +} + +void SvmTest::checkArc(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/arc[1]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + + {"startx", "10"}, {"starty", "11"}, + {"endx", "12"}, {"endy", "13"}, + }); +} + +void SvmTest::testArc() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawArc(tools::Rectangle(Point(1, 2), Size(4, 4)), Point(10, 11), Point(12, 13)); + + checkArc(writeAndReadStream(aGDIMetaFile)); + checkArc(readFile("arc.svm")); +} + +void SvmTest::checkPie(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/pie[1]", { + {"left", "11"}, {"top", "12"}, + {"right", "14"}, {"bottom", "15"}, + + {"startx", "20"}, {"starty", "21"}, + {"endx", "22"}, {"endy", "23"}, + }); +} + +void SvmTest::testPie() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawPie(tools::Rectangle(Point(11, 12), Size(4, 4)), Point(20, 21), Point(22, 23)); + + checkPie(writeAndReadStream(aGDIMetaFile)); + checkPie(readFile("pie.svm")); +} + +void SvmTest::checkChord(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/chord[1]", { + {"left", "21"}, {"top", "22"}, + {"right", "24"}, {"bottom", "25"}, + + {"startx", "30"}, {"starty", "31"}, + {"endx", "32"}, {"endy", "33"}, + }); +} + +void SvmTest::testChord() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawChord(tools::Rectangle(Point(21, 22), Size(4, 4)), Point(30, 31), Point(32, 33)); + + checkChord(writeAndReadStream(aGDIMetaFile)); + checkChord(readFile("chord.svm")); +} + +void SvmTest::checkPolyLine(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/polyline[1]", { + {"style", "solid"}, {"width", "0"}, + {"dashlen", "0"}, {"dashcount", "0"}, + {"dotlen", "0"}, {"dotcount", "0"}, + {"distance", "0"}, + {"join", "round"}, {"cap", "butt"} + }); + + assertXPathAttrs(pDoc, "/metafile/polyline[1]/point[1]", {{"x", "1"}, {"y", "8"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[1]/point[2]", {{"x", "2"}, {"y", "7"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[1]/point[3]", {{"x", "3"}, {"y", "6"}}); + + assertXPathAttrs(pDoc, "/metafile/polyline[2]", { + {"style", "dash"}, {"width", "7"}, + {"dashlen", "5"}, {"dashcount", "4"}, + {"dotlen", "3"}, {"dotcount", "2"}, + {"distance", "1"}, + {"join", "miter"}, {"cap", "round"} + }); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[1]", {{"x", "8"}, {"y", "1"}, {"flags", "normal"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[2]", {{"x", "7"}, {"y", "2"}, {"flags", "control"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[3]", {{"x", "6"}, {"y", "3"}, {"flags", "smooth"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[4]", {{"x", "5"}, {"y", "4"}, {"flags", "symmetric"}}); +} + +void SvmTest::testPolyLine() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + pVirtualDev->DrawPolyLine(aPolygon); + + tools::Polygon aPolygonWithControl(4); + aPolygonWithControl.SetPoint(Point(8, 1), 0); + aPolygonWithControl.SetPoint(Point(7, 2), 1); + aPolygonWithControl.SetPoint(Point(6, 3), 2); + aPolygonWithControl.SetPoint(Point(5, 4), 3); + + aPolygonWithControl.SetFlags(0, PolyFlags::Normal); + aPolygonWithControl.SetFlags(1, PolyFlags::Control); + aPolygonWithControl.SetFlags(2, PolyFlags::Smooth); + aPolygonWithControl.SetFlags(3, PolyFlags::Symmetric); + + LineInfo aLineInfo(LineStyle::Dash, 7); + aLineInfo.SetDashLen(5); + aLineInfo.SetDashCount(4); + aLineInfo.SetDotLen(3); + aLineInfo.SetDotCount(2); + aLineInfo.SetDistance(1); + aLineInfo.SetLineJoin(basegfx::B2DLineJoin::Miter); + aLineInfo.SetLineCap(css::drawing::LineCap_ROUND); + + pVirtualDev->DrawPolyLine(aPolygonWithControl, aLineInfo); + + checkPolyLine(writeAndReadStream(aGDIMetaFile)); + checkPolyLine(readFile("polyline.svm")); +} + +void SvmTest::checkPolygon(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/polygon[1]/point[1]", {{"x", "1"}, {"y", "8"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[1]/point[2]", {{"x", "2"}, {"y", "7"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[1]/point[3]", {{"x", "3"}, {"y", "6"}}); + + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[1]", {{"x", "8"}, {"y", "1"}, {"flags", "normal"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[2]", {{"x", "7"}, {"y", "2"}, {"flags", "control"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[3]", {{"x", "6"}, {"y", "3"}, {"flags", "smooth"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[4]", {{"x", "5"}, {"y", "4"}, {"flags", "symmetric"}}); +} + +void SvmTest::testPolygon() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + pVirtualDev->DrawPolygon(aPolygon); + + tools::Polygon aPolygonWithControl(4); + aPolygonWithControl.SetPoint(Point(8, 1), 0); + aPolygonWithControl.SetPoint(Point(7, 2), 1); + aPolygonWithControl.SetPoint(Point(6, 3), 2); + aPolygonWithControl.SetPoint(Point(5, 4), 3); + + aPolygonWithControl.SetFlags(0, PolyFlags::Normal); + aPolygonWithControl.SetFlags(1, PolyFlags::Control); + aPolygonWithControl.SetFlags(2, PolyFlags::Smooth); + aPolygonWithControl.SetFlags(3, PolyFlags::Symmetric); + + pVirtualDev->DrawPolygon(aPolygonWithControl); + + checkPolygon(writeAndReadStream(aGDIMetaFile)); + checkPolygon(readFile("polygon.svm")); +} + +void SvmTest::checkPolyPolygon(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[1]/point[1]", {{"x", "1"}, {"y", "8"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[1]/point[2]", {{"x", "2"}, {"y", "7"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[1]/point[3]", {{"x", "3"}, {"y", "6"}}); + + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[1]", {{"x", "8"}, {"y", "1"}, {"flags", "normal"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[2]", {{"x", "7"}, {"y", "2"}, {"flags", "control"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[3]", {{"x", "6"}, {"y", "3"}, {"flags", "smooth"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[4]", {{"x", "5"}, {"y", "4"}, {"flags", "symmetric"}}); +} + +void SvmTest::testPolyPolygon() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + tools::Polygon aPolygonWithControl(4); + aPolygonWithControl.SetPoint(Point(8, 1), 0); + aPolygonWithControl.SetPoint(Point(7, 2), 1); + aPolygonWithControl.SetPoint(Point(6, 3), 2); + aPolygonWithControl.SetPoint(Point(5, 4), 3); + + aPolygonWithControl.SetFlags(0, PolyFlags::Normal); + aPolygonWithControl.SetFlags(1, PolyFlags::Control); + aPolygonWithControl.SetFlags(2, PolyFlags::Smooth); + aPolygonWithControl.SetFlags(3, PolyFlags::Symmetric); + + tools::PolyPolygon aPolyPolygon(2); + aPolyPolygon.Insert(aPolygon); + aPolyPolygon.Insert(aPolygonWithControl); + + pVirtualDev->DrawPolyPolygon(aPolyPolygon); + + checkPolyPolygon(writeAndReadStream(aGDIMetaFile)); + checkPolyPolygon(readFile("polypolygon.svm")); +} + +void SvmTest::checkText(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/text[1]", { + {"x", "4"}, {"y", "6"}, {"index", "1"}, {"length", "2"}, + }); + + assertXPathContent(pDoc, "/metafile/text[1]/textcontent", "xABC"); +} + +void SvmTest::testText() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawText(Point(4,6), "xABC", 1, 2); + + checkText(writeAndReadStream(aGDIMetaFile)); + checkText(readFile("text.svm")); +} + +void SvmTest::checkTextArray(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textarray[1]", { + {"x", "4"}, {"y", "6"}, {"index", "1"}, {"length", "4"}, + }); + assertXPathContent(pDoc, "/metafile/textarray[1]/dxarray", "15 20 25 "); + assertXPathContent(pDoc, "/metafile/textarray[1]/text", "123456"); +} + +void SvmTest::testTextArray() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + long const aDX[] = { 10, 15, 20, 25, 30, 35 }; + pVirtualDev->DrawTextArray(Point(4,6), "123456", aDX, 1, 4); + + checkTextArray(writeAndReadStream(aGDIMetaFile)); + checkTextArray(readFile("textarray.svm")); +} + +void SvmTest::checkStrechText(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/stretchtext[1]", { + {"x", "4"}, {"y", "6"}, {"index", "1"}, {"length", "4"}, {"width", "10"} + }); + + assertXPathContent(pDoc, "/metafile/stretchtext[1]/textcontent", "123456"); +} + +void SvmTest::testStrechText() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + pVirtualDev->DrawStretchText(Point(4,6), 10, "123456", 1, 4); + + checkStrechText(writeAndReadStream(aGDIMetaFile)); + checkStrechText(readFile("strecthtext.svm")); +} + +void SvmTest::checkTextRect(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textrect[1]", { + {"left", "0"}, {"top", "0"}, {"right", "4"}, {"bottom", "4"} + }); + assertXPathContent(pDoc, "/metafile/textrect[1]/textcontent", "123456"); + assertXPathContent(pDoc, "/metafile/textrect[1]/style", "Center"); +} + +void SvmTest::testTextRect() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + pVirtualDev->DrawText(tools::Rectangle(Point(0,0), Size(5,5)), "123456", DrawTextFlags::Center); + + checkTextRect(writeAndReadStream(aGDIMetaFile)); + checkTextRect(readFile("textrectangle.svm")); +} + +void SvmTest::checkTextLine(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textline[1]", { + {"x", "4"}, {"y", "6"}, {"width", "10"}, + {"strikeout", "single"}, {"underline", "single"}, {"overline", "single"} + }); +} + +void SvmTest::testTextLine() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + pVirtualDev->DrawTextLine(Point(4,6), 10, STRIKEOUT_SINGLE, LINESTYLE_SINGLE, LINESTYLE_SINGLE); + + checkTextLine(writeAndReadStream(aGDIMetaFile)); + checkTextLine(readFile("textline.svm")); +} + +void SvmTest::checkBitmaps(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + if (SkiaHelper::isVCLSkiaEnabled()) + return; // TODO SKIA using CRCs is broken (the idea of it) + + OUString crc1 = "b8dee5da"; + OUString crc2 = "281fc589"; + OUString crc3 = "5e01ddcc"; +#if HAVE_FEATURE_OPENGL + if (OpenGLHelper::isVCLOpenGLEnabled()) + { + // OpenGL uses a different scaling algorithm and also a different RGB order. + crc1 = "5e01ddcc"; + crc2 = "281fc589"; + crc3 = "b8dee5da"; + } +#endif + + assertXPathAttrs(pDoc, "/metafile/bmp[1]", {{"x", "1"}, {"y", "2"}, {"crc", crc1}}); + assertXPathAttrs(pDoc, "/metafile/bmpscale[1]", { + {"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"}, {"crc", crc2} + }); + assertXPathAttrs(pDoc, "/metafile/bmpscalepart[1]", { + {"destx", "1"}, {"desty", "2"}, {"destwidth", "3"}, {"destheight", "4"}, + {"srcx", "2"}, {"srcy", "1"}, {"srcwidth", "4"}, {"srcheight", "3"}, + {"crc", crc3} + }); +} + +void SvmTest::testBitmaps() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + Bitmap aBitmap1(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap1); + pAccess->Erase(COL_RED); + } + Bitmap aBitmap2(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap2); + pAccess->Erase(COL_GREEN); + } + Bitmap aBitmap3(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap3); + pAccess->Erase(COL_BLUE); + } + pVirtualDev->DrawBitmap(Point(1, 2), aBitmap1); + pVirtualDev->DrawBitmap(Point(1, 2), Size(3, 4), aBitmap2); + pVirtualDev->DrawBitmap(Point(1, 2), Size(3, 4), Point(2, 1), Size(4, 3), aBitmap3); + + { + GDIMetaFile aReloadedGDIMetaFile = writeAndReadStream(aGDIMetaFile); + checkBitmaps(aReloadedGDIMetaFile); + checkRendering(pVirtualDev, aReloadedGDIMetaFile); + } + { + GDIMetaFile aFileGDIMetaFile = readFile("bitmaps.svm"); + checkBitmaps(aFileGDIMetaFile); + checkRendering(pVirtualDev, aFileGDIMetaFile); + } +} + +void SvmTest::checkBitmapExs(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + if (SkiaHelper::isVCLSkiaEnabled()) + return; // TODO SKIA using CRCs is broken (the idea of it) + + std::vector<OUString> aExpectedCRC; + +#if HAVE_FEATURE_OPENGL + if (OpenGLHelper::isVCLOpenGLEnabled()) + { + aExpectedCRC.insert(aExpectedCRC.end(), + { + "08feb5d3", + "281fc589", + "b8dee5da", + "4df0e464", + "7d3a8da3", + "1426653b", + "4fd547df", + "71efc447", + }); + } + else +#endif + { + aExpectedCRC.insert(aExpectedCRC.end(), + { + "d8377d4f", + "281fc589", + "5e01ddcc", + "4df0e464", + "34434a50", + "d1736327", + "b37875c2", + "a85d44b8", + }); + } + + assertXPathAttrs(pDoc, "/metafile/bmpex[1]", { + {"x", "1"}, {"y", "1"}, {"crc", aExpectedCRC[0]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpexscale[1]", { + {"x", "5"}, {"y", "0"}, {"width", "2"}, {"height", "3"}, + {"crc", aExpectedCRC[1]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpexscalepart[1]", { + {"destx", "7"}, {"desty", "1"}, {"destwidth", "2"}, {"destheight", "2"}, + {"srcx", "0"}, {"srcy", "0"}, {"srcwidth", "3"}, {"srcheight", "4"}, + {"crc", aExpectedCRC[2]}, {"transparenttype", "bitmap"} + }); + +#ifndef MACOSX + assertXPathAttrs(pDoc, "/metafile/bmpex[2]", { + {"x", "6"}, {"y", "6"}, {"crc", aExpectedCRC[3]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[3]", { + {"x", "0"}, {"y", "6"}, {"crc", aExpectedCRC[4]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[4]", { + {"x", "2"}, {"y", "6"}, {"crc", aExpectedCRC[5]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[5]", { + {"x", "0"}, {"y", "8"}, {"crc", aExpectedCRC[6]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[6]", { + {"x", "2"}, {"y", "8"}, {"crc", aExpectedCRC[7]}, {"transparenttype", "bitmap"} + }); +#endif +} + +void SvmTest::testBitmapExs() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + // DrawBitmapEx + { + Bitmap aBitmap(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_YELLOW); + } + + pVirtualDev->DrawBitmapEx(Point(1, 1), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - Scale + { + Bitmap aBitmap(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_GREEN); + } + pVirtualDev->DrawBitmapEx(Point(5, 0), Size(2, 3), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - Scale - Part + { + Bitmap aBitmap(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_BLUE); + } + pVirtualDev->DrawBitmapEx(Point(7, 1), Size(2, 2), Point(0, 0), Size(3, 4), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 50% transparent + { + Bitmap aBitmap(Size(4, 4), 24); + AlphaMask aAlpha(Size(4, 4)); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + + AlphaScopedWriteAccess pAlphaAccess(aAlpha); + pAlphaAccess->Erase(Color(128, 128, 128)); + } + pVirtualDev->DrawBitmapEx(Point(6, 6), BitmapEx(aBitmap, aAlpha)); + } + + // DrawBitmapEx - 1-bit + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N1BitThreshold); + pVirtualDev->DrawBitmapEx(Point(0, 6), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 4-bit + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N4BitColors); + pVirtualDev->DrawBitmapEx(Point(2, 6), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 8-bit Color + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N8BitColors); + pVirtualDev->DrawBitmapEx(Point(0, 8), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 8-bit Grey + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N8BitGreys); + pVirtualDev->DrawBitmapEx(Point(2, 8), BitmapEx(aBitmap, COL_WHITE)); + } + + { + GDIMetaFile aReloadedGDIMetaFile = writeAndReadStream(aGDIMetaFile); + checkBitmapExs(aReloadedGDIMetaFile); + checkRendering(pVirtualDev, aReloadedGDIMetaFile); + } + { + GDIMetaFile aFileGDIMetaFile = readFile("bitmapexs.svm"); + checkBitmapExs(aFileGDIMetaFile); + checkRendering(pVirtualDev, aFileGDIMetaFile); + } +} + +void SvmTest::checkMasks(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/mask[1]", { + {"x", "1"}, {"y", "2"}, + {"color", "#000000"} + }); + assertXPathAttrs(pDoc, "/metafile/maskscale[1]", { + {"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"}, + {"color", "#000000"} + }); + assertXPathAttrs(pDoc, "/metafile/maskscalepart[1]", { + {"destx", "1"}, {"desty", "2"}, {"destwidth", "3"}, {"destheight", "4"}, + {"srcx", "2"}, {"srcy", "1"}, {"srcwidth", "4"}, {"srcheight", "3"}, + {"color", "#ff0000"} + }); +} + +// TODO: Masks are kind-of special - we don't persist the color attribute (it is +// always #000000) of the meta-action (which is wrong), but rely on alpha to do +// the right thing. +void SvmTest::testMasks() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + Bitmap aBitmap1(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap1); + pAccess->Erase(COL_RED); + } + Bitmap aBitmap2(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap2); + pAccess->Erase(COL_GREEN); + } + Bitmap aBitmap3(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap3); + pAccess->Erase(COL_BLUE); + } + + pVirtualDev->DrawMask(Point(1, 2), aBitmap1, COL_LIGHTRED); + pVirtualDev->DrawMask(Point(1, 2), Size(3, 4), aBitmap2, COL_LIGHTRED); + pVirtualDev->DrawMask(Point(1, 2), Size(3, 4), Point(2, 1), Size(4, 3), aBitmap3, COL_LIGHTRED, MetaActionType::MASKSCALEPART); + + checkMasks(writeAndReadStream(aGDIMetaFile)); + checkMasks(readFile("masks.svm")); +} + +void SvmTest::checkGradient(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/gradient[1]", { + {"style", "Linear"}, + {"startcolor", "#ffffff"}, + {"endcolor", "#000000"}, + {"angle", "0"}, + {"border", "0"}, + {"offsetx", "50"}, + {"offsety", "50"}, + {"startintensity", "100"}, + {"endintensity", "100"}, + {"steps", "0"}, + }); + assertXPathAttrs(pDoc, "/metafile/gradient[1]/rectangle", { + {"left", "1"}, + {"top", "2"}, + {"right", "4"}, + {"bottom", "6"}, + }); + + assertXPathAttrs(pDoc, "/metafile/gradient[2]", { + {"style", "Radial"}, + {"startcolor", "#ff0000"}, + {"endcolor", "#00ff00"}, + {"angle", "55"}, + {"border", "10"}, + {"offsetx", "22"}, + {"offsety", "24"}, + {"startintensity", "4"}, + {"endintensity", "14"}, + {"steps", "64"}, + }); + assertXPathAttrs(pDoc, "/metafile/gradient[2]/rectangle", { + {"left", "3"}, + {"top", "4"}, + {"right", "3"}, + {"bottom", "5"}, + }); +} + +void SvmTest::testGradient() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Rectangle aRectangle(Point(1, 2), Size(4,5)); + + Gradient aGradient(GradientStyle::Linear, COL_WHITE, COL_BLACK); + pVirtualDev->DrawGradient(aRectangle, aGradient); + + tools::Rectangle aRectangle2(Point(3, 4), Size(1,2)); + + Gradient aGradient2; + aGradient2.SetStyle(GradientStyle::Radial); + aGradient2.SetStartColor(COL_LIGHTRED); + aGradient2.SetEndColor(COL_LIGHTGREEN); + aGradient2.SetAngle(55); + aGradient2.SetBorder(10); + aGradient2.SetOfsX(22); + aGradient2.SetOfsY(24); + aGradient2.SetStartIntensity(4); + aGradient2.SetEndIntensity(14); + aGradient2.SetSteps(64); + pVirtualDev->DrawGradient(aRectangle2, aGradient2); + + checkGradient(writeAndReadStream(aGDIMetaFile)); + checkGradient(readFile("gradient.svm")); +} + +void SvmTest::testGradientEx() +{} + +void SvmTest::checkHatch(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/hatch[1]/polygon/point[1]", { + {"x", "1"}, {"y", "8"}, + }); + assertXPathAttrs(pDoc, "/metafile/hatch[1]/polygon/point[2]", { + {"x", "2"}, {"y", "7"}, + }); + assertXPathAttrs(pDoc, "/metafile/hatch[1]/polygon/point[3]", { + {"x", "3"}, {"y", "6"}, + }); + + assertXPathAttrs(pDoc, "/metafile/hatch[1]/hatch", { + {"style", "Single"}, + {"color", "#ffff00"}, + {"distance", "15"}, + {"angle", "900"}, + }); +} + +void SvmTest::testHatch() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + tools::PolyPolygon aPolyPolygon(1); + aPolyPolygon.Insert(aPolygon); + + Hatch aHatch(HatchStyle::Single, COL_YELLOW, 15, 900); + + pVirtualDev->DrawHatch(aPolyPolygon, aHatch); + + checkHatch(writeAndReadStream(aGDIMetaFile)); + checkHatch(readFile("hatch.svm")); +} + +void SvmTest::checkWallpaper(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + // Funny enough - we don't serialize the rectangle of the wallpaper so it's always EMPTY + assertXPathAttrs(pDoc, "/metafile/wallpaper[1]", + { + {"left", "0"}, + {"top", "0"}, + {"right", "empty"}, + {"bottom", "empty"}, + }); + + assertXPathAttrs(pDoc, "/metafile/wallpaper[1]/wallpaper", + { + {"color", "#00ff00"}, + {"style", "Tile"}, + {"fixed", "true"}, + {"scrollable", "true"}, + }); +} + +void SvmTest::testWallpaper() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + Wallpaper aWallpaper(COL_LIGHTGREEN); + pVirtualDev->DrawWallpaper(tools::Rectangle(Point(1, 1), Size(3, 3)), aWallpaper); + + checkWallpaper(writeAndReadStream(aGDIMetaFile)); + checkWallpaper(readFile("wallpaper.svm")); +} + +void SvmTest::checkClipRegion(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/clipregion[1]", { + {"left", "2"}, + {"top", "2"}, + {"right", "5"}, + {"bottom", "5"}, + }); +} + +void SvmTest::testClipRegion() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + vcl::Region aRegion(tools::Rectangle(Point(2, 2), Size(4, 4))); + + // TODO + // explicit Region(const tools::Polygon& rPolygon); + // explicit Region(const tools::PolyPolygon& rPolyPoly); + // explicit Region(const basegfx::B2DPolyPolygon&); + pVirtualDev->SetClipRegion(aRegion); + + checkClipRegion(writeAndReadStream(aGDIMetaFile)); + checkClipRegion(readFile("clipregion.svm")); +} + +void SvmTest::testIntersectRectClipRegion() +{} +void SvmTest::testIntersectRegionClipRegion() +{} +void SvmTest::testMoveClipRegion() +{} + +void SvmTest::checkLineColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push/linecolor[1]", { + {"color", "#654321"}, + }); +} + +void SvmTest::testLineColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->Push(); + pVirtualDev->SetLineColor(Color(0x654321)); + pVirtualDev->Pop(); + + checkLineColor(writeAndReadStream(aGDIMetaFile)); + checkLineColor(readFile("linecolor.svm")); +} + +void SvmTest::checkFillColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push/fillcolor[1]", { + {"color", "#456789"}, + }); +} + +void SvmTest::testFillColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->Push(); + pVirtualDev->SetFillColor(Color(0x456789)); + pVirtualDev->Pop(); + + checkFillColor(writeAndReadStream(aGDIMetaFile)); + checkFillColor(readFile("fillcolor.svm")); +} + +void SvmTest::checkTextColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textcolor[1]", { + {"color", "#123456"}, + }); +} + +void SvmTest::testTextColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextColor(Color(0x123456)); + + checkTextColor(writeAndReadStream(aGDIMetaFile)); + checkTextColor(readFile("textcolor.svm")); +} + +void SvmTest::checkTextFillColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textfillcolor[1]", { + {"color", "#234567"}, + }); +} + +void SvmTest::testTextFillColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextFillColor(Color(0x234567)); + + checkTextFillColor(writeAndReadStream(aGDIMetaFile)); + checkTextFillColor(readFile("textfillecolor.svm")); +} + +void SvmTest::checkTextLineColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textlinecolor[1]", { + {"color", "#345678"}, + }); +} + +void SvmTest::testTextLineColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextLineColor(Color(0x345678)); + + checkTextLineColor(writeAndReadStream(aGDIMetaFile)); + checkTextLineColor(readFile("textlinecolor.svm")); +} + +void SvmTest::checkOverLineColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push/overlinecolor[1]", { + {"color", "#345678"}, + }); +} + +void SvmTest::testOverLineColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->Push(); + pVirtualDev->SetOverlineColor(Color(0x345678)); + pVirtualDev->Pop(); + + checkOverLineColor(writeAndReadStream(aGDIMetaFile)); + checkOverLineColor(readFile("overlinecolor.svm")); +} + +void SvmTest::checkTextAlign(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textalign[1]", { + {"align", "bottom"}, + }); +} + +void SvmTest::testTextAlign() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextAlign(TextAlign::ALIGN_BOTTOM); + + checkTextAlign(writeAndReadStream(aGDIMetaFile)); + checkTextAlign(readFile("textalign.svm")); +} + +void SvmTest::testMapMode() +{} +void SvmTest::testFont() +{} + +void SvmTest::checkPushPop(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push[1]", {{"flags", "PushAll"}}); + assertXPathAttrs(pDoc, "/metafile/push[1]/linecolor[1]", {{"color", "#800000"}}); + assertXPathAttrs(pDoc, "/metafile/push[1]/line[1]", { + {"startx", "4"}, {"starty", "4"}, + {"endx", "6"}, {"endy", "6"}, + }); + assertXPathAttrs(pDoc, "/metafile/push[1]/push[1]", {{"flags", "PushLineColor, PushFillColor"}}); + assertXPathAttrs(pDoc, "/metafile/push[1]/push[1]/line[1]", { + {"startx", "5"}, {"starty", "5"}, + {"endx", "7"}, {"endy", "7"}, + }); +} + +void SvmTest::testPushPop() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(COL_YELLOW); + pVirtualDev->Push(); + pVirtualDev->SetLineColor(COL_RED); + pVirtualDev->DrawLine(Point(4,4), Point(6,6)); + pVirtualDev->Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR); + pVirtualDev->SetLineColor(COL_LIGHTRED); + pVirtualDev->DrawLine(Point(5,5), Point(7,7)); + pVirtualDev->Pop(); + pVirtualDev->Pop(); + pVirtualDev->DrawLine(Point(1,1), Point(8,8)); + + checkPushPop(writeAndReadStream(aGDIMetaFile)); + checkPushPop(readFile("pushpop.svm")); +} + +void SvmTest::checkRasterOp(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/rasterop[1]", { + {"operation", "xor"}, + }); +} + +void SvmTest::testRasterOp() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetRasterOp(RasterOp::Xor); + + checkRasterOp(writeAndReadStream(aGDIMetaFile)); + checkRasterOp(readFile("rasterop.svm")); +} + +void SvmTest::checkTransparent(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/transparent[1]", { + {"transparence", "50"}, + }); + + assertXPathAttrs(pDoc, "/metafile/transparent[1]/polygon/point[1]", { + {"x", "1"}, {"y", "8"}, + }); + assertXPathAttrs(pDoc, "/metafile/transparent[1]/polygon/point[2]", { + {"x", "2"}, {"y", "7"}, + }); + assertXPathAttrs(pDoc, "/metafile/transparent[1]/polygon/point[3]", { + {"x", "3"}, {"y", "6"}, + }); +} + +void SvmTest::testTransparent() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance<VirtualDevice> pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + tools::PolyPolygon aPolyPolygon(1); + aPolyPolygon.Insert(aPolygon); + + pVirtualDev->DrawTransparent(aPolygon, 50); + + CPPUNIT_ASSERT(aGDIMetaFile.HasTransparentActions()); + checkTransparent(writeAndReadStream(aGDIMetaFile)); + checkTransparent(readFile("transparent.svm")); +} + +void SvmTest::testFloatTransparent() +{} + +void SvmTest::testEPS() +{} + +void SvmTest::testRefPoint() +{} + +void SvmTest::testComment() +{} + +void SvmTest::testLayoutMode() +{} + +void SvmTest::testTextLanguage() +{} + +CPPUNIT_TEST_SUITE_REGISTRATION(SvmTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/test_blocklist_evaluate.xml b/vcl/qa/cppunit/test_blocklist_evaluate.xml new file mode 100644 index 000000000..d7b72d6d8 --- /dev/null +++ b/vcl/qa/cppunit/test_blocklist_evaluate.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +* 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/. +--> + +<!-- + entry attributes: + os - "all", "7", "8", "8_1", "10", "windows", "linux", "osx_10_5", "osx_10_6", "osx_10_7", "osx_10_8", "osx" + vendor - "all", "intel", "amd", "nvidia", "microsoft" + compare - "less", "less_equal", "greater", "greater_equal", "equal", "not_equal", "between_exclusive", "between_inclusive", "between_inclusive_start" + version + minVersion + maxVersion +--> + +<root> + <whitelist> + </whitelist> + <blacklist> + + <entry os="all" vendor="amd" compare="less" version="10.20.30.40"> + <device id="all"/> + </entry> + + <entry os="all" vendor="microsoft" compare="equal" version="10.20.30.40"> + <device id="all"/> + </entry> + + <entry os="all" vendor="intel" compare="less" version="10.18.14.4264"> + <device id="all"/> + </entry> + + <entry os="osx" vendor="microsoft" compare="equal" version="10.20.30.50"> + <device id="all"/> + </entry> + + <entry os="linux" vendor="microsoft" compare="equal" version="10.20.30.50"> + <device id="all"/> + </entry> + + </blacklist> +</root> diff --git a/vcl/qa/cppunit/test_blocklist_parse.xml b/vcl/qa/cppunit/test_blocklist_parse.xml new file mode 100644 index 000000000..f9af4cb54 --- /dev/null +++ b/vcl/qa/cppunit/test_blocklist_parse.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +* 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/. +--> + +<root> + <whitelist> + <entry os="all" vendor="all" compare="less" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="7" vendor="nvidia" compare="equal" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="8" vendor="microsoft" compare="not_equal" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="8" vendor="0xcafe" compare="not_equal" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="8_1" compare="between_exclusive" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="10" compare="between_inclusive" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="all" compare="between_inclusive_start" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="all"> + <device id="all"/> + </entry> + </whitelist> + <blacklist> + <entry os="all" vendor="all" compare="less" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="7" vendor="nvidia" compare="equal" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="8" vendor="microsoft" compare="not_equal" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="8" vendor="0xcafe" compare="not_equal" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="8_1" compare="between_exclusive" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="10" compare="between_inclusive" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="all" compare="between_inclusive_start" version="10.20.30.40"> + <device id="all"/> + </entry> + <entry os="all"> + <device id="all"/> + </entry> + </blacklist> +</root> diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx new file mode 100644 index 000000000..4071cd0fd --- /dev/null +++ b/vcl/qa/cppunit/timer.cxx @@ -0,0 +1,566 @@ +/* -*- 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/. + */ +/* + * Timers are evil beasts across platforms... + */ + +#include <test/bootstrapfixture.hxx> + +#include <osl/thread.hxx> +#include <chrono> + +#include <vcl/timer.hxx> +#include <vcl/idle.hxx> +#include <vcl/svapp.hxx> +#include <vcl/scheduler.hxx> +#include <svdata.hxx> +#include <salinst.hxx> + +// #define TEST_WATCHDOG + +// Enables timer tests that appear to provoke windows under load unduly. +//#define TEST_TIMERPRECISION + +namespace { + +/// Avoid our timer tests just wedging the build if they fail. +class WatchDog : public osl::Thread +{ + sal_Int32 mnSeconds; +public: + explicit WatchDog(sal_Int32 nSeconds) : + Thread(), + mnSeconds( nSeconds ) + { + create(); + } + virtual void SAL_CALL run() override + { + osl::Thread::wait( std::chrono::seconds(mnSeconds) ); + fprintf(stderr, "ERROR: WatchDog timer thread expired, failing the test!\n"); + fflush(stderr); + CPPUNIT_ASSERT_MESSAGE("watchdog triggered", false); + } +}; + +} + +static WatchDog * aWatchDog = new WatchDog( 120 ); // random high number in secs + +class TimerTest : public test::BootstrapFixture +{ +public: + TimerTest() : BootstrapFixture(true, false) {} + + void testIdle(); + void testIdleMainloop(); +#ifdef TEST_WATCHDOG + void testWatchdog(); +#endif + void testDurations(); +#ifdef TEST_TIMERPRECISION + void testAutoTimer(); + void testMultiAutoTimers(); +#endif + void testAutoTimerStop(); + void testNestedTimer(); + void testSlowTimerCallback(); + void testTriggerIdleFromIdle(); + void testInvokedReStart(); + void testPriority(); + void testRoundRobin(); + + CPPUNIT_TEST_SUITE(TimerTest); + CPPUNIT_TEST(testIdle); + CPPUNIT_TEST(testIdleMainloop); +#ifdef TEST_WATCHDOG + CPPUNIT_TEST(testWatchdog); +#endif + CPPUNIT_TEST(testDurations); +#ifdef TEST_TIMERPRECISION + CPPUNIT_TEST(testAutoTimer); + CPPUNIT_TEST(testMultiAutoTimers); +#endif + CPPUNIT_TEST(testAutoTimerStop); + CPPUNIT_TEST(testNestedTimer); + CPPUNIT_TEST(testSlowTimerCallback); + CPPUNIT_TEST(testTriggerIdleFromIdle); + CPPUNIT_TEST(testInvokedReStart); + CPPUNIT_TEST(testPriority); + CPPUNIT_TEST(testRoundRobin); + + CPPUNIT_TEST_SUITE_END(); +}; + +#ifdef TEST_WATCHDOG +void TimerTest::testWatchdog() +{ + // out-wait the watchdog. + osl::Thread::wait( std::chrono::seconds(12) ); +} +#endif + +namespace { + +class IdleBool : public Idle +{ + bool &mrBool; +public: + explicit IdleBool( bool &rBool ) : + Idle( "IdleBool" ), mrBool( rBool ) + { + SetPriority( TaskPriority::LOWEST ); + Start(); + mrBool = false; + } + virtual void Invoke() override + { + mrBool = true; + Application::EndYield(); + } +}; + +} + +void TimerTest::testIdle() +{ + bool bTriggered = false; + IdleBool aTest( bTriggered ); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered); +} + +void TimerTest::testIdleMainloop() +{ + bool bTriggered = false; + IdleBool aTest( bTriggered ); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle bDone + while (!bTriggered) + { + ImplSVData* pSVData = ImplGetSVData(); + + // can't test this via Application::Yield since this + // also processes all tasks directly via the scheduler. + pSVData->maAppData.mnDispatchLevel++; + pSVData->mpDefInst->DoYield(true, false); + pSVData->maAppData.mnDispatchLevel--; + } + CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered); +} + +namespace { + +class TimerBool : public Timer +{ + bool &mrBool; +public: + TimerBool( sal_uLong nMS, bool &rBool ) : + Timer( "TimerBool" ), mrBool( rBool ) + { + SetTimeout( nMS ); + Start(); + mrBool = false; + } + virtual void Invoke() override + { + mrBool = true; + Application::EndYield(); + } +}; + +} + +void TimerTest::testDurations() +{ + static const sal_uLong aDurations[] = { 0, 1, 500, 1000 }; + for (size_t i = 0; i < SAL_N_ELEMENTS( aDurations ); i++) + { + bool bDone = false; + TimerBool aTimer( aDurations[i], bDone ); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle bDone + while( !bDone ) + { + Application::Yield(); + } + } +} + +namespace { + +class AutoTimerCount : public AutoTimer +{ + sal_Int32 &mrCount; + const sal_Int32 mnMaxCount; + +public: + AutoTimerCount( sal_uLong nMS, sal_Int32 &rCount, + const sal_Int32 nMaxCount = -1 ) + : AutoTimer( "AutoTimerCount" ) + , mrCount( rCount ) + , mnMaxCount( nMaxCount ) + { + SetTimeout( nMS ); + Start(); + mrCount = 0; + } + + virtual void Invoke() override + { + ++mrCount; + CPPUNIT_ASSERT( mnMaxCount < 0 || mrCount <= mnMaxCount ); + if ( mrCount == mnMaxCount ) + Stop(); + } +}; + +} + +#ifdef TEST_TIMERPRECISION + +void TimerTest::testAutoTimer() +{ + const sal_Int32 nDurationMs = 30; + const sal_Int32 nEventsCount = 5; + const double exp = (nDurationMs * nEventsCount); + + sal_Int32 nCount = 0; + std::ostringstream msg; + + // Repeat when we have random latencies. + // This is expected on non-realtime OSes. + for (int i = 0; i < 10; ++i) + { + const auto start = std::chrono::high_resolution_clock::now(); + nCount = 0; + AutoTimerCount aCount(nDurationMs, nCount); + while (nCount < nEventsCount) { + Application::Yield(); + } + + const auto end = std::chrono::high_resolution_clock::now(); + double dur = std::chrono::duration<double, std::milli>(end - start).count(); + + msg << std::setprecision(2) << std::fixed + << "periodic multi-timer - dur: " + << dur << " (" << exp << ") ms." << std::endl; + + // +/- 20% should be reasonable enough a margin. + if (dur >= (exp * 0.8) && dur <= (exp * 1.2)) + { + // Success. + return; + } + } + + CPPUNIT_FAIL(msg.str().c_str()); +} + +void TimerTest::testMultiAutoTimers() +{ + // The behavior of the timers change drastically + // when multiple timers are present. + // The worst, in my tests, is when two + // timers with 1ms period exist with a + // third of much longer period. + + const sal_Int32 nDurationMsX = 5; + const sal_Int32 nDurationMsY = 10; + const sal_Int32 nDurationMs = 40; + const sal_Int32 nEventsCount = 5; + const double exp = (nDurationMs * nEventsCount); + const double expX = (exp / nDurationMsX); + const double expY = (exp / nDurationMsY); + + sal_Int32 nCountX = 0; + sal_Int32 nCountY = 0; + sal_Int32 nCount = 0; + std::ostringstream msg; + + // Repeat when we have random latencies. + // This is expected on non-realtime OSes. + for (int i = 0; i < 10; ++i) + { + nCountX = 0; + nCountY = 0; + nCount = 0; + + const auto start = std::chrono::high_resolution_clock::now(); + AutoTimerCount aCountX(nDurationMsX, nCountX); + AutoTimerCount aCountY(nDurationMsY, nCountY); + + AutoTimerCount aCount(nDurationMs, nCount); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle nCount + while (nCount < nEventsCount) { + Application::Yield(); + } + + const auto end = std::chrono::high_resolution_clock::now(); + double dur = std::chrono::duration<double, std::milli>(end - start).count(); + + msg << std::setprecision(2) << std::fixed << "periodic multi-timer - dur: " + << dur << " (" << exp << ") ms, nCount: " << nCount + << " (" << nEventsCount << "), nCountX: " << nCountX + << " (" << expX << "), nCountY: " << nCountY + << " (" << expY << ")." << std::endl; + + // +/- 20% should be reasonable enough a margin. + if (dur >= (exp * 0.8) && dur <= (exp * 1.2) && + nCountX >= (expX * 0.8) && nCountX <= (expX * 1.2) && + nCountY >= (expY * 0.8) && nCountY <= (expY * 1.2)) + { + // Success. + return; + } + } + + CPPUNIT_FAIL(msg.str().c_str()); +} +#endif // TEST_TIMERPRECISION + +void TimerTest::testAutoTimerStop() +{ + sal_Int32 nTimerCount = 0; + const sal_Int32 nMaxCount = 5; + AutoTimerCount aAutoTimer( 0, nTimerCount, nMaxCount ); + // coverity[loop_top] - Application::Yield allows the timer to fire and increment TimerCount + while (nMaxCount != nTimerCount) + Application::Yield(); + CPPUNIT_ASSERT( !aAutoTimer.IsActive() ); + CPPUNIT_ASSERT( !Application::Reschedule() ); +} + +namespace { + +class YieldTimer : public Timer +{ +public: + explicit YieldTimer( sal_uLong nMS ) : Timer( "YieldTimer" ) + { + SetTimeout( nMS ); + Start(); + } + virtual void Invoke() override + { + for (int i = 0; i < 100; i++) + Application::Yield(); + } +}; + +} + +void TimerTest::testNestedTimer() +{ + sal_Int32 nCount = 0; + YieldTimer aCount(5); + AutoTimerCount aCountUp( 3, nCount ); + // coverity[loop_top] - Application::Yield allows the timer to fire and increment nCount + while (nCount < 20) + Application::Yield(); +} + +namespace { + +class SlowCallbackTimer : public Timer +{ + bool &mbSlow; +public: + SlowCallbackTimer( sal_uLong nMS, bool &bBeenSlow ) : + Timer( "SlowCallbackTimer" ), mbSlow( bBeenSlow ) + { + SetTimeout( nMS ); + Start(); + mbSlow = false; + } + virtual void Invoke() override + { + osl::Thread::wait( std::chrono::seconds(1) ); + mbSlow = true; + } +}; + +} + +void TimerTest::testSlowTimerCallback() +{ + bool bBeenSlow = false; + sal_Int32 nCount = 0; + AutoTimerCount aHighFreq(1, nCount); + SlowCallbackTimer aSlow(250, bBeenSlow); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle bBeenSlow + while (!bBeenSlow) + Application::Yield(); + // coverity[loop_top] - Application::Yield allows the timer to fire and increment nCount + while (nCount < 200) + Application::Yield(); +} + +namespace { + +class TriggerIdleFromIdle : public Idle +{ + bool* mpTriggered; + TriggerIdleFromIdle* mpOther; +public: + explicit TriggerIdleFromIdle( bool* pTriggered, TriggerIdleFromIdle* pOther ) : + Idle( "TriggerIdleFromIdle" ), mpTriggered(pTriggered), mpOther(pOther) + { + } + virtual void Invoke() override + { + Start(); + if (mpOther) + mpOther->Start(); + Application::Yield(); + if (mpTriggered) + *mpTriggered = true; + } +}; + +} + +void TimerTest::testTriggerIdleFromIdle() +{ + bool bTriggered1 = false; + bool bTriggered2 = false; + TriggerIdleFromIdle aTest2( &bTriggered2, nullptr ); + TriggerIdleFromIdle aTest1( &bTriggered1, &aTest2 ); + aTest1.Start(); + Application::Yield(); + CPPUNIT_ASSERT_MESSAGE("idle not triggered", bTriggered1); + CPPUNIT_ASSERT_MESSAGE("idle not triggered", bTriggered2); +} + +namespace { + +class IdleInvokedReStart : public Idle +{ + sal_Int32 &mrCount; +public: + IdleInvokedReStart( sal_Int32 &rCount ) + : Idle( "IdleInvokedReStart" ), mrCount( rCount ) + { + Start(); + } + virtual void Invoke() override + { + mrCount++; + if ( mrCount < 2 ) + Start(); + } +}; + +} + +void TimerTest::testInvokedReStart() +{ + sal_Int32 nCount = 0; + IdleInvokedReStart aIdle( nCount ); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL( sal_Int32(2), nCount ); +} + +namespace { + +class IdleSerializer : public Idle +{ + sal_uInt32 mnPosition; + sal_uInt32 &mrProcesed; +public: + IdleSerializer(const char *pDebugName, TaskPriority ePrio, + sal_uInt32 nPosition, sal_uInt32 &rProcesed) + : Idle( pDebugName ) + , mnPosition( nPosition ) + , mrProcesed( rProcesed ) + { + SetPriority(ePrio); + Start(); + } + virtual void Invoke() override + { + ++mrProcesed; + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Ignored prio", mnPosition, mrProcesed ); + } +}; + +} + +void TimerTest::testPriority() +{ + // scope, so tasks are deleted + { + // Start: 1st Idle low, 2nd high + sal_uInt32 nProcessed = 0; + IdleSerializer aLowPrioIdle("IdleSerializer LowPrio", + TaskPriority::LOWEST, 2, nProcessed); + IdleSerializer aHighPrioIdle("IdleSerializer HighPrio", + TaskPriority::HIGHEST, 1, nProcessed); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed ); + } + + { + // Start: 1st Idle high, 2nd low + sal_uInt32 nProcessed = 0; + IdleSerializer aHighPrioIdle("IdleSerializer HighPrio", + TaskPriority::HIGHEST, 1, nProcessed); + IdleSerializer aLowPrioIdle("IdleSerializer LowPrio", + TaskPriority::LOWEST, 2, nProcessed); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed ); + } +} + +namespace { + +class TestAutoIdleRR : public AutoIdle +{ + sal_uInt32 &mrCount; + + DECL_LINK( IdleRRHdl, Timer *, void ); + +public: + TestAutoIdleRR( sal_uInt32 &rCount, + const char *pDebugName ) + : AutoIdle( pDebugName ) + , mrCount( rCount ) + { + CPPUNIT_ASSERT_EQUAL( sal_uInt32(0), mrCount ); + SetInvokeHandler( LINK( this, TestAutoIdleRR, IdleRRHdl ) ); + Start(); + } +}; + +} + +IMPL_LINK_NOARG(TestAutoIdleRR, IdleRRHdl, Timer *, void) +{ + ++mrCount; + if ( mrCount == 3 ) + Stop(); +} + +void TimerTest::testRoundRobin() +{ + sal_uInt32 nCount1 = 0, nCount2 = 0; + TestAutoIdleRR aIdle1( nCount1, "TestAutoIdleRR aIdle1" ), + aIdle2( nCount2, "TestAutoIdleRR aIdle2" ); + while ( Application::Reschedule() ) + { + CPPUNIT_ASSERT( nCount1 == nCount2 || nCount1 - 1 == nCount2 ); + CPPUNIT_ASSERT( nCount1 <= 3 ); + CPPUNIT_ASSERT( nCount2 <= 3 ); + } + CPPUNIT_ASSERT( 3 == nCount1 && 3 == nCount2 ); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx b/vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx new file mode 100644 index 000000000..d5d0167b7 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx @@ -0,0 +1,132 @@ +/* -*- 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/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <unotest/bootstrapfixturebase.hxx> + +#include <widgetdraw/WidgetDefinitionReader.hxx> + +namespace +{ +static OUString const gaDataUrl("/vcl/qa/cppunit/widgetdraw/data/"); + +class WidgetDefinitionReaderTest : public test::BootstrapFixtureBase +{ +private: + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + +public: + void testRead(); + void testReadSettings(); + + CPPUNIT_TEST_SUITE(WidgetDefinitionReaderTest); + CPPUNIT_TEST(testRead); + CPPUNIT_TEST(testReadSettings); + CPPUNIT_TEST_SUITE_END(); +}; + +void WidgetDefinitionReaderTest::testReadSettings() +{ + { + vcl::WidgetDefinition aDefinition; + vcl::WidgetDefinitionReader aReader(getFullUrl("definitionSettings1.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + CPPUNIT_ASSERT_EQUAL(OString(""), aDefinition.mpSettings->msCenteredTabs); + } + + { + vcl::WidgetDefinition aDefinition; + vcl::WidgetDefinitionReader aReader(getFullUrl("definitionSettings2.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + CPPUNIT_ASSERT_EQUAL(OString("true"), aDefinition.mpSettings->msCenteredTabs); + } + + { + vcl::WidgetDefinition aDefinition; + vcl::WidgetDefinitionReader aReader(getFullUrl("definitionSettings3.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + CPPUNIT_ASSERT_EQUAL(OString("true"), aDefinition.mpSettings->msNoActiveTabTextRaise); + CPPUNIT_ASSERT_EQUAL(OString("false"), aDefinition.mpSettings->msCenteredTabs); + CPPUNIT_ASSERT_EQUAL(OString("0"), aDefinition.mpSettings->msListBoxEntryMargin); + CPPUNIT_ASSERT_EQUAL(OString("10"), aDefinition.mpSettings->msDefaultFontSize); + CPPUNIT_ASSERT_EQUAL(OString("16"), aDefinition.mpSettings->msTitleHeight); + CPPUNIT_ASSERT_EQUAL(OString("12"), aDefinition.mpSettings->msFloatTitleHeight); + CPPUNIT_ASSERT_EQUAL(OString("15"), + aDefinition.mpSettings->msListBoxPreviewDefaultLogicWidth); + CPPUNIT_ASSERT_EQUAL(OString("7"), + aDefinition.mpSettings->msListBoxPreviewDefaultLogicHeight); + } +} + +void WidgetDefinitionReaderTest::testRead() +{ + vcl::WidgetDefinition aDefinition; + + vcl::WidgetDefinitionReader aReader(getFullUrl("definition1.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + + CPPUNIT_ASSERT_EQUAL(OUString("123456"), aDefinition.mpStyle->maFaceColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("234567"), aDefinition.mpStyle->maCheckedColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("345678"), aDefinition.mpStyle->maLightColor.AsRGBHexString()); + + CPPUNIT_ASSERT_EQUAL(OUString("ffffff"), + aDefinition.mpStyle->maVisitedLinkColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("ffffff"), aDefinition.mpStyle->maToolTextColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("ffffff"), aDefinition.mpStyle->maFontColor.AsRGBHexString()); + + // Pushbutton + { + ControlState eState + = ControlState::DEFAULT | ControlState::ENABLED | ControlState::ROLLOVER; + std::vector<std::shared_ptr<vcl::WidgetDefinitionState>> aStates + = aDefinition.getDefinition(ControlType::Pushbutton, ControlPart::Entire) + ->getStates(ControlType::Pushbutton, ControlPart::Entire, eState, + PushButtonValue()); + + CPPUNIT_ASSERT_EQUAL(size_t(2), aStates.size()); + + CPPUNIT_ASSERT_EQUAL(size_t(2), aStates[0]->mpWidgetDrawActions.size()); + CPPUNIT_ASSERT_EQUAL(vcl::WidgetDrawActionType::RECTANGLE, + aStates[0]->mpWidgetDrawActions[0]->maType); + CPPUNIT_ASSERT_EQUAL(vcl::WidgetDrawActionType::LINE, + aStates[0]->mpWidgetDrawActions[1]->maType); + } + + // Radiobutton + { + std::vector<std::shared_ptr<vcl::WidgetDefinitionState>> aStates + = aDefinition.getDefinition(ControlType::Radiobutton, ControlPart::Entire) + ->getStates(ControlType::Radiobutton, ControlPart::Entire, ControlState::NONE, + ImplControlValue(ButtonValue::On)); + CPPUNIT_ASSERT_EQUAL(size_t(1), aStates.size()); + CPPUNIT_ASSERT_EQUAL(size_t(2), aStates[0]->mpWidgetDrawActions.size()); + } + + { + std::vector<std::shared_ptr<vcl::WidgetDefinitionState>> aStates + = aDefinition.getDefinition(ControlType::Radiobutton, ControlPart::Entire) + ->getStates(ControlType::Radiobutton, ControlPart::Entire, ControlState::NONE, + ImplControlValue(ButtonValue::Off)); + CPPUNIT_ASSERT_EQUAL(size_t(1), aStates.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), aStates[0]->mpWidgetDrawActions.size()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(WidgetDefinitionReaderTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/widgetdraw/data/definition1.xml b/vcl/qa/cppunit/widgetdraw/data/definition1.xml new file mode 100644 index 000000000..041e8fc24 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definition1.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widgets> + <style> + <faceColor value="#123456"/> + <checkedColor value="#234567"/> + <lightColor value="#345678"/> + <lightBorderColor value="#FFFFFF"/> + <shadowColor value="#FFFFFF"/> + <darkShadowColor value="#FFFFFF"/> + <buttonTextColor value="#FFFFFF"/> + <buttonRolloverTextColor value="#FFFFFF"/> + <radioCheckTextColor value="#FFFFFF"/> + <groupTextColor value="#FFFFFF"/> + <labelTextColor value="#FFFFFF"/> + <windowColor value="#FFFFFF"/> + <windowTextColor value="#FFFFFF"/> + <dialogColor value="#FFFFFF"/> + <dialogTextColor value="#FFFFFF"/> + <workspaceColor value="#FFFFFF"/> + <monoColor value="#FFFFFF"/> + <fieldColor value="#FFFFFF"/> + <fieldTextColor value="#FFFFFF"/> + <fieldRolloverTextColor value="#FFFFFF"/> + <activeColor value="#FFFFFF"/> + <activeTextColor value="#FFFFFF"/> + <activeBorderColor value="#FFFFFF"/> + <deactiveColor value="#FFFFFF"/> + <deactiveTextColor value="#FFFFFF"/> + <deactiveBorderColor value="#FFFFFF"/> + <menuColor value="#FFFFFF"/> + <menuBarColor value="#FFFFFF"/> + <menuBarRolloverColor value="#FFFFFF"/> + <menuBorderColor value="#FFFFFF"/> + <menuTextColor value="#FFFFFF"/> + <menuBarTextColor value="#FFFFFF"/> + <menuBarRolloverTextColor value="#FFFFFF"/> + <menuBarHighlightTextColor value="#FFFFFF"/> + <menuHighlightColor value="#FFFFFF"/> + <menuHighlightTextColor value="#FFFFFF"/> + <highlightColor value="#FFFFFF"/> + <highlightTextColor value="#FFFFFF"/> + <activeTabColor value="#FFFFFF"/> + <inactiveTabColor value="#FFFFFF"/> + <tabTextColor value="#FFFFFF"/> + <tabRolloverTextColor value="#FFFFFF"/> + <tabHighlightTextColor value="#FFFFFF"/> + <disableColor value="#FFFFFF"/> + <helpColor value="#FFFFFF"/> + <helpTextColor value="#FFFFFF"/> + <linkColor value="#FFFFFF"/> + <visitedLinkColor value="#FFFFFF"/> + <toolTextColor value="#FFFFFF"/> + <fontColor value="#FFFFFF"/> + </style> + <pushbutton> + <part value="Entire"> + <state enabled="any" focused="any" pressed="any" rollover="any" default="any" selected="any" button-value="any"> + <rect stroke="#808080" fill="#FFFFFF" stroke-width="1.0" rx="5" ry="5" margin="1"/> + <line stroke="#808080" fill="#808080" stroke-width="1.0"/> + </state> + <state enabled="true" focused="any" pressed="any" rollover="true" default="true" selected="any" button-value="any"> + <rect stroke="#808080" fill="#808080" stroke-width="1.0" rx="5" ry="5" margin="1"/> + </state> + </part> + <part value="Focus"> + <state enabled="any" focused="any" pressed="any" rollover="any" default="any" selected="any" button-value="any"> + <rect stroke="#808080" fill="#FFFFFF" stroke-width="1.0" rx="5" ry="5" margin="1"/> + </state> + </part> + </pushbutton> + <radiobutton> + <part value="Entire"> + <state enabled="any" focused="any" pressed="any" rollover="any" default="any" selected="any" button-value="false"> + <rect stroke="#007AFF" fill="#FFFFFF" stroke-width="1" margin="0"/> + </state> + <state enabled="any" focused="any" pressed="any" rollover="any" default="any" selected="any" button-value="true"> + <rect stroke="#007AFF" fill="#FFFFFF" stroke-width="1" margin="0"/> + <rect stroke="#007AFF" fill="#007AFF" stroke-width="1" margin="3"/> + </state> + </part> + </radiobutton> +</widgets> diff --git a/vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml b/vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml new file mode 100644 index 000000000..9ca7f894f --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widgets> + <settings> + </settings> +</widgets> diff --git a/vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml b/vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml new file mode 100644 index 000000000..0d6d6e111 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widgets> + <settings> + <centeredTabs value="true"/> + </settings> +</widgets> diff --git a/vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml b/vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml new file mode 100644 index 000000000..9ad88dd54 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widgets> + <settings> + <noActiveTabTextRaise value="true"/> + <centeredTabs value="false"/> + <listBoxEntryMargin value="0"/> + <defaultFontSize value="10"/> + <titleHeight value="16"/> + <floatTitleHeight value="12"/> + <listBoxPreviewDefaultLogicWidth value="15"/> + <listBoxPreviewDefaultLogicHeight value="7"/> + </settings> +</widgets> |