summaryrefslogtreecommitdiffstats
path: root/vcl/qa/cppunit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /vcl/qa/cppunit
parentInitial commit. (diff)
downloadlibreoffice-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')
-rw-r--r--vcl/qa/cppunit/BackendTest.cxx599
-rw-r--r--vcl/qa/cppunit/BitmapExTest.cxx113
-rw-r--r--vcl/qa/cppunit/BitmapFilterTest.cxx216
-rw-r--r--vcl/qa/cppunit/BitmapProcessorTest.cxx90
-rw-r--r--vcl/qa/cppunit/BitmapScaleTest.cxx293
-rw-r--r--vcl/qa/cppunit/BitmapTest.cxx660
-rw-r--r--vcl/qa/cppunit/FontFeatureTest.cxx336
-rw-r--r--vcl/qa/cppunit/GraphicDescriptorTest.cxx103
-rw-r--r--vcl/qa/cppunit/GraphicFormatDetectorTest.cxx416
-rw-r--r--vcl/qa/cppunit/GraphicNativeMetadataTest.cxx101
-rw-r--r--vcl/qa/cppunit/GraphicTest.cxx435
-rw-r--r--vcl/qa/cppunit/ScanlineToolsTest.cxx224
-rw-r--r--vcl/qa/cppunit/TypeSerializerTest.cxx502
-rw-r--r--vcl/qa/cppunit/app/test_IconThemeInfo.cxx116
-rw-r--r--vcl/qa/cppunit/app/test_IconThemeScanner.cxx82
-rw-r--r--vcl/qa/cppunit/app/test_IconThemeSelector.cxx183
-rw-r--r--vcl/qa/cppunit/bitmapcolor.cxx262
-rw-r--r--vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx269
-rw-r--r--vcl/qa/cppunit/bitmaprender/data/ImageRGBA.pngbin0 -> 106 bytes
-rw-r--r--vcl/qa/cppunit/bitmaprender/data/tdf104141.gifbin0 -> 12205 bytes
-rw-r--r--vcl/qa/cppunit/bitmaprender/data/tdf113918.pngbin0 -> 20043 bytes
-rw-r--r--vcl/qa/cppunit/bitmaprender/data/tdf116888.gifbin0 -> 1875 bytes
-rw-r--r--vcl/qa/cppunit/blocklistparsertest.cxx153
-rw-r--r--vcl/qa/cppunit/builder/demo.ui1960
-rw-r--r--vcl/qa/cppunit/canvasbitmaptest.cxx773
-rw-r--r--vcl/qa/cppunit/complextext.cxx170
-rw-r--r--vcl/qa/cppunit/data/123_Numbers.gifbin0 -> 1515 bytes
-rw-r--r--vcl/qa/cppunit/data/Exif1.jpgbin0 -> 759 bytes
-rw-r--r--vcl/qa/cppunit/data/Exif1_090CW.jpgbin0 -> 771 bytes
-rw-r--r--vcl/qa/cppunit/data/Exif1_180.jpgbin0 -> 771 bytes
-rw-r--r--vcl/qa/cppunit/data/Exif1_270CW.jpgbin0 -> 771 bytes
-rw-r--r--vcl/qa/cppunit/data/SimpleExample.svg4
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.bmpbin0 -> 442 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.eps82
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.gifbin0 -> 50 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.jpgbin0 -> 992 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.metbin0 -> 629 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.pcxbin0 -> 284 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.pdfbin0 -> 962 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.pngbin0 -> 94 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.psdbin0 -> 1338 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.svg4
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.svgzbin0 -> 166 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.tgabin0 -> 148 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.tifbin0 -> 603 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.wmfbin0 -> 290 bytes
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.xbm5
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.xpm15
-rw-r--r--vcl/qa/cppunit/data/inch-size.emfbin0 -> 28322 bytes
-rw-r--r--vcl/qa/cppunit/data/testBasicMorphology.pngbin0 -> 226 bytes
-rw-r--r--vcl/qa/cppunit/data/testBasicMorphologyDilated1.pngbin0 -> 219 bytes
-rw-r--r--vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.pngbin0 -> 224 bytes
-rw-r--r--vcl/qa/cppunit/data/testBasicMorphologyDilated2.pngbin0 -> 174 bytes
-rw-r--r--vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.pngbin0 -> 178 bytes
-rw-r--r--vcl/qa/cppunit/dndtest.cxx311
-rw-r--r--vcl/qa/cppunit/errorhandler.cxx73
-rw-r--r--vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf55
-rw-r--r--vcl/qa/cppunit/filter/ipdf/ipdf.cxx73
-rw-r--r--vcl/qa/cppunit/font.cxx161
-rw-r--r--vcl/qa/cppunit/fontcharmap.cxx45
-rw-r--r--vcl/qa/cppunit/fontmetric.cxx138
-rw-r--r--vcl/qa/cppunit/gen/data/tdf121120.pngbin0 -> 3196 bytes
-rw-r--r--vcl/qa/cppunit/gen/gen.cxx116
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/README7
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmpbin0 -> 313 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmpbin0 -> 43218 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmpbin0 -> 21424 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmpbin0 -> 8585 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmpbin0 -> 8620 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmpbin0 -> 93078 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmpbin0 -> 2616 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmpbin0 -> 2222 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmpbin0 -> 73470 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmpbin0 -> 1038 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmpbin0 -> 632 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmpbin0 -> 110 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmpbin0 -> 5000 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmpbin0 -> 18862 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emfbin0 -> 576 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emfbin0 -> 3524 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emfbin0 -> 1075 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emfbin0 -> 3848 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emfbin0 -> 456 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emfbin0 -> 24229 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emfbin0 -> 2225 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emfbin0 -> 7057 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emfbin0 -> 8700 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emfbin0 -> 3380 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emfbin0 -> 3524 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emfbin0 -> 1040240 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emfbin0 -> 3872 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emfbin0 -> 3792 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emfbin0 -> 3792 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emfbin0 -> 3792 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emfbin0 -> 3792 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emfbin0 -> 42756 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emfbin0 -> 42756 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emfbin0 -> 25160 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emfbin0 -> 7068 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emfbin0 -> 133136 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emfbin0 -> 7068 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gifbin0 -> 328 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif2
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gifbin0 -> 1190 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gifbin0 -> 3080 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gifbin0 -> 47778 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gifbin0 -> 2382 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gifbin0 -> 10998 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gifbin0 -> 2876 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gifbin0 -> 275 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gifbin0 -> 35 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gifbin0 -> 111 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gifbin0 -> 257 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gifbin0 -> 47778 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpgbin0 -> 31214 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpgbin0 -> 31129 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpgbin0 -> 31214 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpgbin0 -> 31214 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpgbin0 -> 31214 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpgbin0 -> 12000000 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpgbin0 -> 443 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpgbin0 -> 4098 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpgbin0 -> 1674 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpgbin0 -> 2634 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpgbin0 -> 4098 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpgbin0 -> 8903 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpgbin0 -> 504 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpgbin0 -> 8559 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpgbin0 -> 24253 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpgbin0 -> 276 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png3
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.pngbin0 -> 346 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.pngbin0 -> 2495 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.pngbin0 -> 18470 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0951-2.png1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-2.pngbin0 -> 383 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/EDB-34720-1.pngbin0 -> 5000 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.pngbin0 -> 260 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0951-1.png1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-IDAT.pngbin0 -> 260 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/black.pngbin0 -> 175 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.pngbin0 -> 5312 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-1.svmbin0 -> 152 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svmbin0 -> 110 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svmbin0 -> 142 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svmbin0 -> 532 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svmbin0 -> 162 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svmbin0 -> 79 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svmbin0 -> 816777 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/svm/pass/leak-1.svmbin0 -> 856 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676bin0 -> 684 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmfbin0 -> 218 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmfbin0 -> 12178 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmfbin0 -> 68 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1238-1.wmfbin0 -> 382 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1245-1.wmfbin0 -> 382 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-1.wmfbin0 -> 675 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-2.wmfbin0 -> 375 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-3.wmf5
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf3
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmfbin0 -> 1916 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmfbin0 -> 54196 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmfbin0 -> 4197 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmfbin0 -> 16064 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmfbin0 -> 5082 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmfbin0 -> 684 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmfbin0 -> 238 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmfbin0 -> 4192 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmfbin0 -> 2142 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmfbin0 -> 13801 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm12
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm2011
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpmbin0 -> 645514 bytes
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm306
-rw-r--r--vcl/qa/cppunit/graphicfilter/filters-test.cxx181
-rw-r--r--vcl/qa/cppunit/jpeg/JpegReaderTest.cxx167
-rw-r--r--vcl/qa/cppunit/jpeg/JpegWriterTest.cxx105
-rw-r--r--vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpgbin0 -> 1384 bytes
-rw-r--r--vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gifbin0 -> 1875 bytes
-rw-r--r--vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpegbin0 -> 405 bytes
-rw-r--r--vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpegbin0 -> 196 bytes
-rw-r--r--vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpegbin0 -> 619 bytes
-rw-r--r--vcl/qa/cppunit/lifecycle.cxx357
-rw-r--r--vcl/qa/cppunit/mnemonic.cxx57
-rw-r--r--vcl/qa/cppunit/outdev.cxx291
-rw-r--r--vcl/qa/cppunit/pdfexport/data/6m-wide.odgbin0 -> 9146 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdfbin0 -> 17693 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/forcepoint71.keybin0 -> 114022 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/link-wrong-page.odpbin0 -> 12293 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdfbin0 -> 1372 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/reduce-image.fodt29
-rw-r--r--vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt21
-rw-r--r--vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odtbin0 -> 9071 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf105093.odpbin0 -> 211126 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf105461.odpbin0 -> 10320 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf105954.odtbin0 -> 74147 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf106059.odtbin0 -> 13585 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf106206.odtbin0 -> 74641 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf106693.odtbin0 -> 13585 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf106702.odtbin0 -> 42158 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odtbin0 -> 21561 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf106972.odtbin0 -> 21376 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf107013.odtbin0 -> 19823 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf107018.odtbin0 -> 15787 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf107089.odtbin0 -> 20171 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf107868.odtbin0 -> 10567 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf108963.odpbin0 -> 10369 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf109143.odtbin0 -> 68155 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf113143.odpbin0 -> 100637 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf115117-1.odtbin0 -> 8566 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf115117-2.odtbin0 -> 8629 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf115262.odsbin0 -> 27638 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf115967.odtbin0 -> 12091 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odtbin0 -> 12847 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf121615.odtbin0 -> 10188 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf121962.odtbin0 -> 14974 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf128630.odpbin0 -> 17558 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf66597-1.odtbin0 -> 8154 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf66597-2.odtbin0 -> 8265 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf66597-3.odtbin0 -> 8251 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf99680-2.odtbin0 -> 215797 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/tdf99680.odtbin0 -> 30257 bytes
-rw-r--r--vcl/qa/cppunit/pdfexport/data/toc-link.fodt45
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport.cxx2295
-rw-r--r--vcl/qa/cppunit/png/PngFilterTest.cxx193
-rw-r--r--vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.pngbin0 -> 158 bytes
-rw-r--r--vcl/qa/cppunit/png/data/color-rect-4bit-pal.pngbin0 -> 104 bytes
-rw-r--r--vcl/qa/cppunit/png/data/color-rect-8bit-RGB.pngbin0 -> 90 bytes
-rw-r--r--vcl/qa/cppunit/png/data/rect-1bit-pal.pngbin0 -> 89 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/arc.svmbin0 -> 279 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/bitmapexs.svmbin0 -> 3773 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/bitmaps.svmbin0 -> 599 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/chord.svmbin0 -> 279 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/clipregion.svmbin0 -> 255 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/ellipse.svmbin0 -> 263 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/fillcolor.svmbin0 -> 244 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/gradient.svmbin0 -> 15497 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/hatch.svmbin0 -> 271 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/line.svmbin0 -> 325 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/linecolor.svmbin0 -> 244 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/masks.svmbin0 -> 603 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/overlinecolor.svmbin0 -> 244 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/pie.svmbin0 -> 279 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/pixel.svmbin0 -> 253 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/point.svmbin0 -> 229 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/polygon.svmbin0 -> 336 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/polyline.svmbin0 -> 400 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/polypolygon.svmbin0 -> 332 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/pushpop.svmbin0 -> 456 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/rasterop.svmbin0 -> 223 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/rect.svmbin0 -> 263 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/roundrect.svmbin0 -> 271 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/strecthtext.svmbin0 -> 259 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/text.svmbin0 -> 249 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textalign.svmbin0 -> 223 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textarray.svmbin0 -> 275 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textcolor.svmbin0 -> 225 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textfillecolor.svmbin0 -> 226 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textline.svmbin0 -> 245 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textlinecolor.svmbin0 -> 226 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/textrectangle.svmbin0 -> 261 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/transparent.svmbin0 -> 251 bytes
-rw-r--r--vcl/qa/cppunit/svm/data/wallpaper.svmbin0 -> 323 bytes
-rw-r--r--vcl/qa/cppunit/svm/svmtest.cxx1684
-rw-r--r--vcl/qa/cppunit/test_blocklist_evaluate.xml46
-rw-r--r--vcl/qa/cppunit/test_blocklist_parse.xml63
-rw-r--r--vcl/qa/cppunit/timer.cxx566
-rw-r--r--vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx132
-rw-r--r--vcl/qa/cppunit/widgetdraw/data/definition1.xml82
-rw-r--r--vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml5
-rw-r--r--vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml6
-rw-r--r--vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml13
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
new file mode 100644
index 000000000..7a8399293
--- /dev/null
+++ b/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png
Binary files differ
diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif b/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif
new file mode 100644
index 000000000..d6390fdaa
--- /dev/null
+++ b/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif
Binary files differ
diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf113918.png b/vcl/qa/cppunit/bitmaprender/data/tdf113918.png
new file mode 100644
index 000000000..dd49897d9
--- /dev/null
+++ b/vcl/qa/cppunit/bitmaprender/data/tdf113918.png
Binary files differ
diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif b/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif
new file mode 100644
index 000000000..295310949
--- /dev/null
+++ b/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif
Binary files differ
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
new file mode 100644
index 000000000..2e47e28cb
--- /dev/null
+++ b/vcl/qa/cppunit/data/123_Numbers.gif
Binary files differ
diff --git a/vcl/qa/cppunit/data/Exif1.jpg b/vcl/qa/cppunit/data/Exif1.jpg
new file mode 100644
index 000000000..a81425e75
--- /dev/null
+++ b/vcl/qa/cppunit/data/Exif1.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/data/Exif1_090CW.jpg b/vcl/qa/cppunit/data/Exif1_090CW.jpg
new file mode 100644
index 000000000..bb8a81a16
--- /dev/null
+++ b/vcl/qa/cppunit/data/Exif1_090CW.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/data/Exif1_180.jpg b/vcl/qa/cppunit/data/Exif1_180.jpg
new file mode 100644
index 000000000..b18b70f13
--- /dev/null
+++ b/vcl/qa/cppunit/data/Exif1_180.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/data/Exif1_270CW.jpg b/vcl/qa/cppunit/data/Exif1_270CW.jpg
new file mode 100644
index 000000000..f10764114
--- /dev/null
+++ b/vcl/qa/cppunit/data/Exif1_270CW.jpg
Binary files differ
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
new file mode 100644
index 000000000..5197e42a7
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.bmp
Binary files differ
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
new file mode 100644
index 000000000..b33eb4f90
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.gif
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.jpg b/vcl/qa/cppunit/data/TypeDetectionExample.jpg
new file mode 100644
index 000000000..b8436eaa1
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.met b/vcl/qa/cppunit/data/TypeDetectionExample.met
new file mode 100644
index 000000000..7635e841f
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.met
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.pcx b/vcl/qa/cppunit/data/TypeDetectionExample.pcx
new file mode 100644
index 000000000..639323455
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.pcx
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.pdf b/vcl/qa/cppunit/data/TypeDetectionExample.pdf
new file mode 100644
index 000000000..b68bff5e1
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.pdf
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.png b/vcl/qa/cppunit/data/TypeDetectionExample.png
new file mode 100644
index 000000000..f73f5fd74
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.png
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.psd b/vcl/qa/cppunit/data/TypeDetectionExample.psd
new file mode 100644
index 000000000..8282b14fd
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.psd
Binary files differ
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
new file mode 100644
index 000000000..17c1bcc3c
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.svgz
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.tga b/vcl/qa/cppunit/data/TypeDetectionExample.tga
new file mode 100644
index 000000000..870c88b10
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.tga
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.tif b/vcl/qa/cppunit/data/TypeDetectionExample.tif
new file mode 100644
index 000000000..dc74dc958
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.tif
Binary files differ
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.wmf b/vcl/qa/cppunit/data/TypeDetectionExample.wmf
new file mode 100644
index 000000000..7ed706928
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.wmf
Binary files differ
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
new file mode 100644
index 000000000..ac5a1b805
--- /dev/null
+++ b/vcl/qa/cppunit/data/inch-size.emf
Binary files differ
diff --git a/vcl/qa/cppunit/data/testBasicMorphology.png b/vcl/qa/cppunit/data/testBasicMorphology.png
new file mode 100644
index 000000000..5db565779
--- /dev/null
+++ b/vcl/qa/cppunit/data/testBasicMorphology.png
Binary files differ
diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png
new file mode 100644
index 000000000..ba335bab3
--- /dev/null
+++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png
Binary files differ
diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png
new file mode 100644
index 000000000..3b10a949a
--- /dev/null
+++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png
Binary files differ
diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png
new file mode 100644
index 000000000..30d90757e
--- /dev/null
+++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png
Binary files differ
diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png
new file mode 100644
index 000000000..a506577da
--- /dev/null
+++ b/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png
Binary files differ
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
new file mode 100644
index 000000000..8e48fba38
--- /dev/null
+++ b/vcl/qa/cppunit/gen/data/tdf121120.png
Binary files differ
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
new file mode 100644
index 000000000..d77db5782
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..4cfbdfff8
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..289cf8c0e
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..84ac054db
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..a6aed5983
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp
Binary files differ
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
new file mode 100644
index 000000000..76aaecf97
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..b733b2484
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..2b58d1035
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..cfe7e40f6
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp
Binary files differ
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
new file mode 100644
index 000000000..1ca6e0008
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp
new file mode 100644
index 000000000..84b6c35c8
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp
new file mode 100644
index 000000000..a75d6ebae
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp
Binary files differ
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
new file mode 100644
index 000000000..3815a1c13
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..88b11ad57
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp
Binary files differ
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
new file mode 100644
index 000000000..a511da43a
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf
Binary files differ
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
new file mode 100644
index 000000000..dd57d9102
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf
Binary files differ
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
new file mode 100644
index 000000000..8fa6e9377
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf
new file mode 100644
index 000000000..6adabec8b
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf
new file mode 100644
index 000000000..92da5f05a
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf
new file mode 100644
index 000000000..b89db21c2
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf
new file mode 100644
index 000000000..634fccdc0
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf
new file mode 100644
index 000000000..e3baf3bfa
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf
Binary files differ
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
new file mode 100644
index 000000000..ef4c6a009
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf
Binary files differ
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
new file mode 100644
index 000000000..c71739a50
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf
Binary files differ
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
new file mode 100644
index 000000000..746e85e84
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf
Binary files differ
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
new file mode 100644
index 000000000..fbd546cb0
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf
Binary files differ
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
new file mode 100644
index 000000000..40f24b41d
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf
Binary files differ
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
new file mode 100644
index 000000000..dcc2a66f7
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf
Binary files differ
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
new file mode 100644
index 000000000..b82444a97
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf
Binary files differ
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
new file mode 100644
index 000000000..8e67ce5ae
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf
Binary files differ
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
new file mode 100644
index 000000000..b17ce7061
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf
Binary files differ
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
new file mode 100644
index 000000000..0991bba4f
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf
Binary files differ
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
new file mode 100644
index 000000000..78d030daa
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf
Binary files differ
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
new file mode 100644
index 000000000..fadbb7516
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf
new file mode 100644
index 000000000..bbc0285db
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf
new file mode 100644
index 000000000..a52213238
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf
new file mode 100644
index 000000000..0af6c749b
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf
Binary files differ
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
new file mode 100644
index 000000000..7e84566e9
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif
Binary files differ
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
new file mode 100644
index 000000000..8f0f4fdb7
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif
Binary files differ
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
new file mode 100644
index 000000000..26b35e63b
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif
Binary files differ
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
new file mode 100644
index 000000000..63426f9d8
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif
Binary files differ
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
new file mode 100644
index 000000000..e92a316e4
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif
Binary files differ
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
new file mode 100644
index 000000000..190c7b079
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif
Binary files differ
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
new file mode 100644
index 000000000..cf4f30c21
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif
Binary files differ
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
new file mode 100644
index 000000000..7cb2a03d5
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif
Binary files differ
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
new file mode 100644
index 000000000..cddbdc357
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif
new file mode 100644
index 000000000..860f9e1d8
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif
new file mode 100644
index 000000000..b7265f807
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif
Binary files differ
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
new file mode 100644
index 000000000..47f5d4341
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif
Binary files differ
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
new file mode 100644
index 000000000..c03c8529c
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg
Binary files differ
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
new file mode 100644
index 000000000..1a24da322
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg
Binary files differ
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
new file mode 100644
index 000000000..794ff52e4
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg
Binary files differ
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
new file mode 100644
index 000000000..8911646fa
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg
Binary files differ
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
new file mode 100644
index 000000000..c5373df43
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg
Binary files differ
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
new file mode 100644
index 000000000..33bbe9b5f
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg
new file mode 100644
index 000000000..e783bd33e
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg
Binary files differ
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
new file mode 100644
index 000000000..3d9481aca
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg
Binary files differ
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
new file mode 100644
index 000000000..5eb27ffb5
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg
Binary files differ
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
new file mode 100644
index 000000000..4917f207f
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg
Binary files differ
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
new file mode 100644
index 000000000..9d26db005
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg
Binary files differ
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
new file mode 100644
index 000000000..bc668d3e3
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg
Binary files differ
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
new file mode 100644
index 000000000..675881f36
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg
Binary files differ
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
new file mode 100644
index 000000000..01e7fe16f
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg
Binary files differ
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
new file mode 100644
index 000000000..4753ed8db
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg
new file mode 100644
index 000000000..c6ee53505
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg
Binary files differ
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àî|†ìeGf­S$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
new file mode 100644
index 000000000..d0644d139
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png
Binary files differ
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
new file mode 100644
index 000000000..9b30cc38c
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png
Binary files differ
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
new file mode 100644
index 000000000..b9ff67bb8
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png
Binary files differ
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
new file mode 100644
index 000000000..5494ca00e
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-2.png
Binary files differ
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
new file mode 100644
index 000000000..3165f2c5e
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/EDB-34720-1.png
Binary files differ
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
new file mode 100644
index 000000000..db8e7a834
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png
Binary files differ
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
new file mode 100644
index 000000000..b116a92ec
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-IDAT.png
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png
new file mode 100644
index 000000000..cbba93bed
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png
new file mode 100644
index 000000000..1c45c7689
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png
Binary files differ
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
new file mode 100644
index 000000000..2fce465f7
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-1.svm
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm
new file mode 100644
index 000000000..1b3cd1416
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm
new file mode 100644
index 000000000..b4afeb09f
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm
new file mode 100644
index 000000000..c2f14d4a0
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm
new file mode 100644
index 000000000..835e7f668
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm
new file mode 100644
index 000000000..8d6d94e12
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm b/vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm
new file mode 100644
index 000000000..ad722ea13
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm
Binary files differ
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
new file mode 100644
index 000000000..14dbea080
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/svm/pass/leak-1.svm
Binary files differ
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
new file mode 100644
index 000000000..49d3ddf28
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676
Binary files differ
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
new file mode 100644
index 000000000..ac546ce5b
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..aab34004e
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..370abe0e2
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf
Binary files differ
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
new file mode 100644
index 000000000..10da32742
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1238-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..10da32742
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1245-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..87319c2d4
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..ff20cad78
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-2.wmf
Binary files differ
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
new file mode 100644
index 000000000..2ec88066f
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf
new file mode 100644
index 000000000..02c72ad88
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf
new file mode 100644
index 000000000..29c534fdc
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf
new file mode 100644
index 000000000..f9a72867c
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf
new file mode 100644
index 000000000..e2fac1523
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..e70664e64
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..7864da572
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf
Binary files differ
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
new file mode 100644
index 000000000..1512a2256
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf
new file mode 100644
index 000000000..365a247a7
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf
Binary files differ
diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf
new file mode 100644
index 000000000..bfd7e20de
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf
Binary files differ
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
new file mode 100644
index 000000000..ca2d777a1
--- /dev/null
+++ b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm
Binary files differ
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
new file mode 100644
index 000000000..91541e4a8
--- /dev/null
+++ b/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg
Binary files differ
diff --git a/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif b/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif
new file mode 100644
index 000000000..295310949
--- /dev/null
+++ b/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif
Binary files differ
diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg
new file mode 100644
index 000000000..81cca025e
--- /dev/null
+++ b/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg
Binary files differ
diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg
new file mode 100644
index 000000000..014825f42
--- /dev/null
+++ b/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg
Binary files differ
diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg
new file mode 100644
index 000000000..3cfe1dda2
--- /dev/null
+++ b/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg
Binary files differ
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
new file mode 100644
index 000000000..49fb9bfff
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/6m-wide.odg
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf
new file mode 100644
index 000000000..af665fcba
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/forcepoint71.key b/vcl/qa/cppunit/pdfexport/data/forcepoint71.key
new file mode 100644
index 000000000..716fe5848
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/forcepoint71.key
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp b/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp
new file mode 100644
index 000000000..b6787aff6
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp
Binary files differ
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
new file mode 100644
index 000000000..739a80c47
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf
Binary files differ
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
new file mode 100644
index 000000000..ecd779537
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105093.odp b/vcl/qa/cppunit/pdfexport/data/tdf105093.odp
new file mode 100644
index 000000000..82ce29cda
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf105093.odp
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105461.odp b/vcl/qa/cppunit/pdfexport/data/tdf105461.odp
new file mode 100644
index 000000000..9c86a3bd7
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf105461.odp
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105954.odt b/vcl/qa/cppunit/pdfexport/data/tdf105954.odt
new file mode 100644
index 000000000..ba5c96de6
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf105954.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106059.odt b/vcl/qa/cppunit/pdfexport/data/tdf106059.odt
new file mode 100644
index 000000000..a2c180378
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf106059.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106206.odt b/vcl/qa/cppunit/pdfexport/data/tdf106206.odt
new file mode 100644
index 000000000..3581157de
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf106206.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106693.odt b/vcl/qa/cppunit/pdfexport/data/tdf106693.odt
new file mode 100644
index 000000000..a2c180378
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf106693.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106702.odt b/vcl/qa/cppunit/pdfexport/data/tdf106702.odt
new file mode 100644
index 000000000..da3b7e814
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf106702.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt b/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt
new file mode 100644
index 000000000..d46c93dff
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106972.odt b/vcl/qa/cppunit/pdfexport/data/tdf106972.odt
new file mode 100644
index 000000000..3fa76c49f
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf106972.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107013.odt b/vcl/qa/cppunit/pdfexport/data/tdf107013.odt
new file mode 100644
index 000000000..644e65c6d
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf107013.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107018.odt b/vcl/qa/cppunit/pdfexport/data/tdf107018.odt
new file mode 100644
index 000000000..3bfc7b2d7
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf107018.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107089.odt b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt
new file mode 100644
index 000000000..5aaaab944
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107868.odt b/vcl/qa/cppunit/pdfexport/data/tdf107868.odt
new file mode 100644
index 000000000..8309f4b87
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf107868.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf108963.odp b/vcl/qa/cppunit/pdfexport/data/tdf108963.odp
new file mode 100644
index 000000000..246c0c72a
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf108963.odp
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf109143.odt b/vcl/qa/cppunit/pdfexport/data/tdf109143.odt
new file mode 100644
index 000000000..7d9afa378
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf109143.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf113143.odp b/vcl/qa/cppunit/pdfexport/data/tdf113143.odp
new file mode 100644
index 000000000..5f8a1b10e
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf113143.odp
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt b/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt
new file mode 100644
index 000000000..63fe82946
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt
new file mode 100644
index 000000000..c1e1f6d43
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115262.ods b/vcl/qa/cppunit/pdfexport/data/tdf115262.ods
new file mode 100644
index 000000000..b401a74ce
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf115262.ods
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115967.odt b/vcl/qa/cppunit/pdfexport/data/tdf115967.odt
new file mode 100644
index 000000000..39f4ce178
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf115967.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt b/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt
new file mode 100644
index 000000000..caabc4987
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf121615.odt b/vcl/qa/cppunit/pdfexport/data/tdf121615.odt
new file mode 100644
index 000000000..7d2a87cf0
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf121615.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf121962.odt b/vcl/qa/cppunit/pdfexport/data/tdf121962.odt
new file mode 100644
index 000000000..a831b1136
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf121962.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf128630.odp b/vcl/qa/cppunit/pdfexport/data/tdf128630.odp
new file mode 100644
index 000000000..d216504b7
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf128630.odp
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt
new file mode 100644
index 000000000..7fecc55c6
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt
new file mode 100644
index 000000000..3d7b5e59c
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt
new file mode 100644
index 000000000..6db91fe81
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt
new file mode 100644
index 000000000..47c370004
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt
Binary files differ
diff --git a/vcl/qa/cppunit/pdfexport/data/tdf99680.odt b/vcl/qa/cppunit/pdfexport/data/tdf99680.odt
new file mode 100644
index 000000000..de12f9baa
--- /dev/null
+++ b/vcl/qa/cppunit/pdfexport/data/tdf99680.odt
Binary files differ
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
new file mode 100644
index 000000000..1e90e1a6c
--- /dev/null
+++ b/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png
Binary files differ
diff --git a/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png b/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png
new file mode 100644
index 000000000..740eede51
--- /dev/null
+++ b/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png
Binary files differ
diff --git a/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png b/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png
new file mode 100644
index 000000000..727859d8a
--- /dev/null
+++ b/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png
Binary files differ
diff --git a/vcl/qa/cppunit/png/data/rect-1bit-pal.png b/vcl/qa/cppunit/png/data/rect-1bit-pal.png
new file mode 100644
index 000000000..cf7ac3e7c
--- /dev/null
+++ b/vcl/qa/cppunit/png/data/rect-1bit-pal.png
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/arc.svm b/vcl/qa/cppunit/svm/data/arc.svm
new file mode 100644
index 000000000..5d443a704
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/arc.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/bitmapexs.svm b/vcl/qa/cppunit/svm/data/bitmapexs.svm
new file mode 100644
index 000000000..f6860bdff
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/bitmapexs.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/bitmaps.svm b/vcl/qa/cppunit/svm/data/bitmaps.svm
new file mode 100644
index 000000000..bf42f1bae
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/bitmaps.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/chord.svm b/vcl/qa/cppunit/svm/data/chord.svm
new file mode 100644
index 000000000..7c7136eed
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/chord.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/clipregion.svm b/vcl/qa/cppunit/svm/data/clipregion.svm
new file mode 100644
index 000000000..aa0d277fe
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/clipregion.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/ellipse.svm b/vcl/qa/cppunit/svm/data/ellipse.svm
new file mode 100644
index 000000000..369e4292c
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/ellipse.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/fillcolor.svm b/vcl/qa/cppunit/svm/data/fillcolor.svm
new file mode 100644
index 000000000..8e1a826c4
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/fillcolor.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/gradient.svm b/vcl/qa/cppunit/svm/data/gradient.svm
new file mode 100644
index 000000000..68811e065
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/gradient.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/hatch.svm b/vcl/qa/cppunit/svm/data/hatch.svm
new file mode 100644
index 000000000..4e6bdf638
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/hatch.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/line.svm b/vcl/qa/cppunit/svm/data/line.svm
new file mode 100644
index 000000000..67441ec92
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/line.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/linecolor.svm b/vcl/qa/cppunit/svm/data/linecolor.svm
new file mode 100644
index 000000000..2cba7f734
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/linecolor.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/masks.svm b/vcl/qa/cppunit/svm/data/masks.svm
new file mode 100644
index 000000000..b9e777930
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/masks.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/overlinecolor.svm b/vcl/qa/cppunit/svm/data/overlinecolor.svm
new file mode 100644
index 000000000..10cd773fb
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/overlinecolor.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/pie.svm b/vcl/qa/cppunit/svm/data/pie.svm
new file mode 100644
index 000000000..1eaf67447
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/pie.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/pixel.svm b/vcl/qa/cppunit/svm/data/pixel.svm
new file mode 100644
index 000000000..dc15ab8f0
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/pixel.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/point.svm b/vcl/qa/cppunit/svm/data/point.svm
new file mode 100644
index 000000000..5b5c3731b
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/point.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/polygon.svm b/vcl/qa/cppunit/svm/data/polygon.svm
new file mode 100644
index 000000000..162ccfd9c
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/polygon.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/polyline.svm b/vcl/qa/cppunit/svm/data/polyline.svm
new file mode 100644
index 000000000..9139da371
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/polyline.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/polypolygon.svm b/vcl/qa/cppunit/svm/data/polypolygon.svm
new file mode 100644
index 000000000..ea01bd14a
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/polypolygon.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/pushpop.svm b/vcl/qa/cppunit/svm/data/pushpop.svm
new file mode 100644
index 000000000..d5ab6e80a
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/pushpop.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/rasterop.svm b/vcl/qa/cppunit/svm/data/rasterop.svm
new file mode 100644
index 000000000..ac9f796c2
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/rasterop.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/rect.svm b/vcl/qa/cppunit/svm/data/rect.svm
new file mode 100644
index 000000000..8c398b572
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/rect.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/roundrect.svm b/vcl/qa/cppunit/svm/data/roundrect.svm
new file mode 100644
index 000000000..aa0ca3e29
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/roundrect.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/strecthtext.svm b/vcl/qa/cppunit/svm/data/strecthtext.svm
new file mode 100644
index 000000000..f6dcb5fba
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/strecthtext.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/text.svm b/vcl/qa/cppunit/svm/data/text.svm
new file mode 100644
index 000000000..37da7f598
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/text.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textalign.svm b/vcl/qa/cppunit/svm/data/textalign.svm
new file mode 100644
index 000000000..091c49876
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textalign.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textarray.svm b/vcl/qa/cppunit/svm/data/textarray.svm
new file mode 100644
index 000000000..7863b03ce
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textarray.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textcolor.svm b/vcl/qa/cppunit/svm/data/textcolor.svm
new file mode 100644
index 000000000..f55b3ccd7
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textcolor.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textfillecolor.svm b/vcl/qa/cppunit/svm/data/textfillecolor.svm
new file mode 100644
index 000000000..52a4f29f3
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textfillecolor.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textline.svm b/vcl/qa/cppunit/svm/data/textline.svm
new file mode 100644
index 000000000..1d8517823
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textline.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textlinecolor.svm b/vcl/qa/cppunit/svm/data/textlinecolor.svm
new file mode 100644
index 000000000..786dfc465
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textlinecolor.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/textrectangle.svm b/vcl/qa/cppunit/svm/data/textrectangle.svm
new file mode 100644
index 000000000..62c424d6a
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/textrectangle.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/transparent.svm b/vcl/qa/cppunit/svm/data/transparent.svm
new file mode 100644
index 000000000..40864b90a
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/transparent.svm
Binary files differ
diff --git a/vcl/qa/cppunit/svm/data/wallpaper.svm b/vcl/qa/cppunit/svm/data/wallpaper.svm
new file mode 100644
index 000000000..8fca8c31f
--- /dev/null
+++ b/vcl/qa/cppunit/svm/data/wallpaper.svm
Binary files differ
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>