WMF tdf#142625 Refactor Bitmap records, to better handle missing features

Change-Id: If3334158e6e0ef9bc3aa33656ad0ee45cf460dbb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116827
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 2ad512d..d949240 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -696,25 +696,25 @@ void Test::TestStretchDIBWMF()
    xmlDocUniquePtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer<Primitive2DContainer>(aSequence));
    CPPUNIT_ASSERT (pDocument);

    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "xy11", "12065");
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "xy12", "0");
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
                "xy13", "3598");
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "xy13", "0");
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "xy21", "0");
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "xy22", "12065");
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
                "xy23", "3598");
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "xy23", "0");

    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "height", "10");
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "width", "10");
#if !defined(MACOSX) // TODO DIB display needs to be fixed for macOS
    assertXPath(pDocument, "/primitive2D/metafile/transform/bitmap",
    assertXPath(pDocument, "/primitive2D/metafile/transform/mask/bitmap",
                "checksum", "275245357");
#endif
}
diff --git a/emfio/source/reader/wmfreader.cxx b/emfio/source/reader/wmfreader.cxx
index 73d059a..65c2cff 100644
--- a/emfio/source/reader/wmfreader.cxx
+++ b/emfio/source/reader/wmfreader.cxx
@@ -803,14 +803,14 @@ namespace emfio

            case W_META_BITBLT:
            {
                // 0-3   : nRasterOperation                      #93454#
                // 0-3   : nRasterOperation        #93454#
                // 4-5   : y offset of source bitmap
                // 6-7   : x offset of source bitmap
                // 8-9   : used height of source bitmap
                // 10-11 : used width  of source bitmap
                // 8-9   : height of source and destination bitmap
                // 10-11 : width  of source and destination bitmap
                // 12-13 : destination position y (in pixel)
                // 14-15 : destination position x (in pixel)
                // 16-17 : don't know
                // 16-17 : bitmap type
                // 18-19 : Width Bitmap in Pixel
                // 20-21 : Height Bitmap in Pixel
                // 22-23 : bytes per scanline
@@ -818,26 +818,31 @@ namespace emfio
                // 25    : bitcount

                sal_uInt32  nRasterOperation = 0;
                sal_uInt16  nYSrc = 0, nXSrc = 0, nSye = 0, nSxe = 0, nBitmapType = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0;
                sal_Int16   nYSrc = 0, nXSrc = 0, nSye = 0, nSxe = 0, nBitmapType = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0;
                sal_uInt8   nPlanes, nBitCount;
                const bool bNoSourceBitmap = ( nRecordSize == ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 );

                mpInputStream->ReadUInt32( nRasterOperation );
                SAL_WARN("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec);
                if ( nRecordSize == ( ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 ) )
                SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec << ", No source bitmap: " << bNoSourceBitmap);

                mpInputStream->ReadInt16( nYSrc ).ReadInt16( nXSrc );
                if ( bNoSourceBitmap )
                    mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)
                mpInputStream->ReadInt16( nSye ).ReadInt16( nSxe );
                Point aPoint( ReadYX() ); // The upper-left corner of the destination rectangle.
                mpInputStream->ReadInt16( nBitmapType ).ReadInt16( nWidth ).ReadInt16( nHeight ).ReadInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount );

                SAL_INFO("emfio", "\t\t Bitmap type:" << nBitmapType << " Width:" << nWidth << " Height:" << nHeight << " WidthBytes:" << nBytesPerScan << " Planes: " << static_cast< sal_uInt16 >( nPlanes ) << " BitCount: " << static_cast< sal_uInt16 >( nBitCount ) );
                if ( bNoSourceBitmap )
                {
                    SAL_WARN("emfio", "\t\t TODO The unsupported Bitmap record (without embedded source Bitmap). Please fill a bug.");
                    break;
                }
                mpInputStream->ReadUInt16( nYSrc ).ReadUInt16( nXSrc ).ReadUInt16( nSye ).ReadUInt16( nSxe );
                Point aPoint( ReadYX() ); // The upper-left corner of the destination rectangle.
                mpInputStream->ReadUInt16( nBitmapType ).ReadUInt16( nWidth ).ReadUInt16( nHeight ).ReadUInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount );

                SAL_INFO("emfio", "\t\t Bitmap type:" << nBitmapType << " Width:" << nWidth << " Height:" << nHeight << " WidthBytes:" << nBytesPerScan);
                bool bOk = nWidth && nHeight && nBytesPerScan > 0 && nPlanes == 1 && nBitCount == 1;
                if (bOk)
                {
                    // must be enough data to fulfil the request
                    bOk = nBytesPerScan <= mpInputStream->remainingSize() / nHeight;
                    bOk = o3tl::make_unsigned( nBytesPerScan ) <= mpInputStream->remainingSize() / nHeight;
                }
                if (bOk)
                {
@@ -884,18 +889,13 @@ namespace emfio
            case W_META_STRETCHDIB:
            {
                sal_uInt32  nRasterOperation = 0;
                sal_Int16   nYSrc = 0, nXSrc = 0, nSrcHeight = 0, nSrcWidth = 0;
                sal_uInt16  nColorUsage = 0;
                sal_Int16   nSrcHeight = 0, nSrcWidth = 0, nYSrc = 0, nXSrc = 0;
                Bitmap      aBmp;
                const bool bNoSourceBitmap = ( nFunc != W_META_STRETCHDIB ) && ( nRecordSize == ( ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 ) );

                mpInputStream->ReadUInt32( nRasterOperation );
                SAL_WARN("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec);

                if ( nRecordSize == ( ( static_cast< sal_uInt32 >( nFunc ) >> 8 ) + 3 ) )
                {
                    SAL_WARN("emfio", "\t\t TODO The unsupported Bitmap record (without embedded source Bitmap). Please fill a bug.");
                    break;
                }
                SAL_INFO("emfio", "\t\t Raster operation: 0x" << std::hex << nRasterOperation << std::dec << ", No source bitmap: " << bNoSourceBitmap);
                if( nFunc == W_META_STRETCHDIB )
                    mpInputStream->ReadUInt16( nColorUsage );

@@ -909,19 +909,19 @@ namespace emfio
                // nYSrc and nXSrc is the offset of the first pixel
                mpInputStream->ReadInt16( nYSrc ).ReadInt16( nXSrc );

                // TODO Add META_STRETCHBLT support, which is defined by Bitmap16 Object
                if( nFunc == W_META_DIBBITBLT ||
                    nFunc == W_META_DIBSTRETCHBLT ||
                    nFunc == W_META_STRETCHDIB )
                {
                    if ( nRasterOperation == PATCOPY )
                        mpInputStream->ReadUInt16( nColorUsage );    // i don't know anything of this parameter, so it's called nUsage
                                            // DrawRect( Rectangle( ReadYX(), aDestSize ), false );
                    if ( bNoSourceBitmap )
                        mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)

                    Size aDestSize( ReadYXExt() );
                    if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
                    {
                        tools::Rectangle aDestRect( ReadYX(), aDestSize );
                        if ( nRasterOperation != PATCOPY )
                        if ( !bNoSourceBitmap )
                        {
                            // tdf#142625 Read the DIBHeader and check if bitmap is supported
                            // If bitmap is not supported don't run ReadDIB, as it will interrupt image processing
@@ -1943,7 +1943,6 @@ namespace emfio
                        if( nFunction == W_META_STRETCHDIB )
                            pStm->ReadUInt16( nColorUsage );

                        // nSye and nSxe is the number of pixels that has to been used
                        if( nFunction == W_META_DIBSTRETCHBLT ||
                            nFunction == W_META_STRETCHBLT ||
                            nFunction == W_META_STRETCHDIB )
@@ -1955,20 +1954,16 @@ namespace emfio
                        // nYSrc and nXSrc is the offset of the first pixel
                        pStm->ReadInt16( nYSrc ).ReadInt16( nXSrc );

                        if( nFunction == W_META_DIBBITBLT ||
                            nFunction == W_META_DIBSTRETCHBLT )
                        {
                            if ( nRasterOperation == PATCOPY )
                                pStm->ReadUInt16( nColorUsage );    // i don't know anything of this parameter, so it's called nUsage
                                                    // DrawRect( Rectangle( ReadYX(), aDestSize ), false );
                        const bool bNoSourceBitmap = ( nFunction != W_META_STRETCHDIB ) && ( nRSize == ( ( static_cast< sal_uInt32 >( nFunction ) >> 8 ) + 3 ) );
                        if ( bNoSourceBitmap )
                            mpInputStream->SeekRel( 2 ); // Skip Reserved 2 bytes (it must be ignored)

                            Size aDestSize( ReadYXExt() );
                            if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
                            {
                                tools::Rectangle aDestRect( ReadYX(), aDestSize );
                                GetWinExtMax( aDestRect, aBound, nMapMode );
                                bBoundsDetermined = true;
                            }
                        Size aDestSize( ReadYXExt() );
                        if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
                        {
                            tools::Rectangle aDestRect( ReadYX(), aDestSize );
                            GetWinExtMax( aDestRect, aBound, nMapMode );
                            bBoundsDetermined = true;
                        }
                    }
                    break;