summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2021-02-01 21:03:39 +0100
committerMichael Stahl <michael.stahl@allotropia.de>2021-02-03 11:14:02 +0100
commitf3244248e151c345fdbb07185e041142a044a017 (patch)
tree92931d5361f29c3032fda1d59414221c4926e964
parent01f2379603de09ba1b5e979166e4b5d60a90c1d5 (diff)
tdf#139869 vcl: fix lazy-loading of BMP images with logic size
Regression from commit 7b355669c6ddeab2e6cec692d6afdff41c61d0fb (Function to load graphic swapped out (loaded on demand), 2018-04-14), the code assumes that the map mode and size of a graphic is the same when the image is not yet loaded and when it's loaded already. This was not the case for the BMP import, where ImplReadDIBBody() produced a map mode with scaling and MapUnit::MapMM as the map unit, while GraphicDescriptor assumed that the logic size is always MapUnit::Map100thMM. This resulted in SwNoTextNode::HasContour() using one map mode when the contour polygon is imported and an other one was used while renderin, effectively hiding the image. Fix the problem by extending GraphicDescriptor, so a format detector can opt in to provide its own map mode and size according to that map mode, this way the detector and the BMP import will create matching map modes and sizes, resulting in a visible image in the bugdoc. (cherry picked from commit ddc0714c40c6ea85336431a88b523f3e5c63a3f8) Change-Id: I71e786a4601c63f58da2e6ab9d7681ec6dd7b806 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110320 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
-rw-r--r--include/vcl/graphicfilter.hxx15
-rw-r--r--vcl/qa/cppunit/GraphicDescriptorTest.cxx28
-rw-r--r--vcl/qa/cppunit/data/graphic-descriptor-mapmode.bmpbin0 -> 4922 bytes
-rw-r--r--vcl/source/filter/graphicfilter2.cxx17
-rw-r--r--vcl/source/gdi/impgraph.cxx7
5 files changed, 65 insertions, 2 deletions
diff --git a/include/vcl/graphicfilter.hxx b/include/vcl/graphicfilter.hxx
index 35728237dc7a..bd108a4f49b9 100644
--- a/include/vcl/graphicfilter.hxx
+++ b/include/vcl/graphicfilter.hxx
@@ -27,6 +27,7 @@
#include <o3tl/typed_flags_set.hxx>
#include <memory>
+#include <optional>
namespace com::sun::star::beans { struct PropertyValue; }
namespace com::sun::star::uno { template <class E> class Sequence; }
@@ -139,6 +140,8 @@ class VCL_DLLPUBLIC GraphicDescriptor final
OUString aPathExt;
Size aPixSize;
Size aLogSize;
+ std::optional<Size> maPreferredLogSize;
+ std::optional<MapMode> maPreferredMapMode;
sal_uInt16 nBitsPerPixel;
sal_uInt16 nPlanes;
GraphicFileFormat nFormat;
@@ -209,6 +212,18 @@ public:
/** @return the logical graphic size in 1/100mm or 0 size */
const Size& GetSize_100TH_MM() const { return aLogSize; }
+ /**
+ * Returns the logic size, according to the map mode available via GetPreferredMapMode(). Prefer
+ * this size over GetSize_100TH_MM().
+ */
+ std::optional<Size> GetPreferredLogSize() const { return maPreferredLogSize; }
+
+ /**
+ * If available, this returns the map mode the graphic prefers, which may be other than pixel or
+ * 100th mm. Prefer this map mode over just assuming MapUnit::Map100thMM.
+ */
+ std::optional<MapMode> GetPreferredMapMode() const { return maPreferredMapMode; }
+
/** @return bits/pixel or 0 **/
sal_uInt16 GetBitsPerPixel() const { return nBitsPerPixel; }
diff --git a/vcl/qa/cppunit/GraphicDescriptorTest.cxx b/vcl/qa/cppunit/GraphicDescriptorTest.cxx
index 13f51262c233..cb6c6d25d80a 100644
--- a/vcl/qa/cppunit/GraphicDescriptorTest.cxx
+++ b/vcl/qa/cppunit/GraphicDescriptorTest.cxx
@@ -7,6 +7,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+#include <unotest/bootstrapfixturebase.hxx>
+
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
@@ -21,16 +23,22 @@ using namespace css;
namespace
{
-class GraphicDescriptorTest : public CppUnit::TestFixture
+class GraphicDescriptorTest : public test::BootstrapFixtureBase
{
+ OUString getFullUrl(std::u16string_view sFileName)
+ {
+ return m_directories.getURLFromSrc(u"/vcl/qa/cppunit/data/") + sFileName;
+ }
void testDetectPNG();
void testDetectJPG();
void testDetectGIF();
+ void testDetectBMP();
CPPUNIT_TEST_SUITE(GraphicDescriptorTest);
CPPUNIT_TEST(testDetectPNG);
CPPUNIT_TEST(testDetectJPG);
CPPUNIT_TEST(testDetectGIF);
+ CPPUNIT_TEST(testDetectBMP);
CPPUNIT_TEST_SUITE_END();
};
@@ -96,6 +104,24 @@ void GraphicDescriptorTest::testDetectGIF()
CPPUNIT_ASSERT_EQUAL(tools::Long(100), aDescriptor.GetSizePixel().Height());
}
+void GraphicDescriptorTest::testDetectBMP()
+{
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+ SvFileStream aFileStream(getFullUrl(u"graphic-descriptor-mapmode.bmp"), StreamMode::READ);
+
+ Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aFileStream);
+
+ CPPUNIT_ASSERT(!aGraphic.isAvailable());
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2 (MapUnit::MapMM)
+ // - Actual : 0 (MapUnit::Map100thMM)
+ // i.e. lazy load and load created different map modes, breaking the contour polygon code in
+ // Writer.
+ CPPUNIT_ASSERT_EQUAL(MapUnit::MapMM, aGraphic.GetPrefMapMode().GetMapUnit());
+ aGraphic.makeAvailable();
+ CPPUNIT_ASSERT_EQUAL(MapUnit::MapMM, aGraphic.GetPrefMapMode().GetMapUnit());
+}
+
} // namespace
CPPUNIT_TEST_SUITE_REGISTRATION(GraphicDescriptorTest);
diff --git a/vcl/qa/cppunit/data/graphic-descriptor-mapmode.bmp b/vcl/qa/cppunit/data/graphic-descriptor-mapmode.bmp
new file mode 100644
index 000000000000..f65c10ea2bfb
--- /dev/null
+++ b/vcl/qa/cppunit/data/graphic-descriptor-mapmode.bmp
Binary files differ
diff --git a/vcl/source/filter/graphicfilter2.cxx b/vcl/source/filter/graphicfilter2.cxx
index 3d71a6b3b96a..ebebf829a33f 100644
--- a/vcl/source/filter/graphicfilter2.cxx
+++ b/vcl/source/filter/graphicfilter2.cxx
@@ -156,13 +156,21 @@ bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, bool bExtendedInfo )
// logical width
rStm.SeekRel( 4 );
rStm.ReadUInt32( nTemp32 );
+ sal_uInt32 nXPelsPerMeter = 0;
if ( nTemp32 )
+ {
aLogSize.setWidth( ( aPixSize.Width() * 100000 ) / nTemp32 );
+ nXPelsPerMeter = nTemp32;
+ }
// logical height
rStm.ReadUInt32( nTemp32 );
+ sal_uInt32 nYPelsPerMeter = 0;
if ( nTemp32 )
+ {
aLogSize.setHeight( ( aPixSize.Height() * 100000 ) / nTemp32 );
+ nYPelsPerMeter = nTemp32;
+ }
// further validation, check for rational values
if ( ( nBitsPerPixel > 24 ) || ( nCompression > 3 ) )
@@ -170,6 +178,15 @@ bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, bool bExtendedInfo )
nFormat = GraphicFileFormat::NOT;
bRet = false;
}
+
+ if (bRet && nXPelsPerMeter && nYPelsPerMeter)
+ {
+ maPreferredMapMode
+ = MapMode(MapUnit::MapMM, Point(), Fraction(1000, nXPelsPerMeter),
+ Fraction(1000, nYPelsPerMeter));
+
+ maPreferredLogSize = Size(aPixSize.getWidth(), aPixSize.getHeight());
+ }
}
}
rStm.Seek( nStmPos );
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index 6bb3489c2562..1d3e25418b5f 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -420,7 +420,12 @@ void ImpGraphic::ImplSetPrepared(bool bAnimated, const Size* pSizeHint)
// conversion will work with the output device DPI, not the graphic
// DPI.
Size aLogSize = aDescriptor.GetSize_100TH_MM();
- if (aLogSize.getWidth() && aLogSize.getHeight())
+ if (aDescriptor.GetPreferredLogSize() && aDescriptor.GetPreferredMapMode())
+ {
+ maSwapInfo.maPrefSize = *aDescriptor.GetPreferredLogSize();
+ maSwapInfo.maPrefMapMode = *aDescriptor.GetPreferredMapMode();
+ }
+ else if (aLogSize.getWidth() && aLogSize.getHeight())
{
maSwapInfo.maPrefSize = aLogSize;
maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM);