summaryrefslogtreecommitdiffstats
path: root/vcl/source/gdi/TypeSerializer.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /vcl/source/gdi/TypeSerializer.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/gdi/TypeSerializer.cxx')
-rw-r--r--vcl/source/gdi/TypeSerializer.cxx486
1 files changed, 486 insertions, 0 deletions
diff --git a/vcl/source/gdi/TypeSerializer.cxx b/vcl/source/gdi/TypeSerializer.cxx
new file mode 100644
index 000000000..cad183128
--- /dev/null
+++ b/vcl/source/gdi/TypeSerializer.cxx
@@ -0,0 +1,486 @@
+/* -*- 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 <vcl/TypeSerializer.hxx>
+#include <tools/vcompat.hxx>
+#include <tools/fract.hxx>
+#include <sal/log.hxx>
+#include <comphelper/fileformat.h>
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/dibtools.hxx>
+
+TypeSerializer::TypeSerializer(SvStream& rStream)
+ : GenericTypeSerializer(rStream)
+{
+}
+
+void TypeSerializer::readGradient(Gradient& rGradient)
+{
+ VersionCompatRead aCompat(mrStream);
+
+ sal_uInt16 nStyle = 0;
+ Color aStartColor;
+ Color aEndColor;
+ sal_uInt16 nAngle = 0;
+ sal_uInt16 nBorder = 0;
+ sal_uInt16 nOffsetX = 0;
+ sal_uInt16 nOffsetY = 0;
+ sal_uInt16 nIntensityStart = 0;
+ sal_uInt16 nIntensityEnd = 0;
+ sal_uInt16 nStepCount = 0;
+
+ mrStream.ReadUInt16(nStyle);
+ readColor(aStartColor);
+ readColor(aEndColor);
+ mrStream.ReadUInt16(nAngle);
+ mrStream.ReadUInt16(nBorder);
+ mrStream.ReadUInt16(nOffsetX);
+ mrStream.ReadUInt16(nOffsetY);
+ mrStream.ReadUInt16(nIntensityStart);
+ mrStream.ReadUInt16(nIntensityEnd);
+ mrStream.ReadUInt16(nStepCount);
+
+ rGradient.SetStyle(static_cast<GradientStyle>(nStyle));
+ rGradient.SetStartColor(aStartColor);
+ rGradient.SetEndColor(aEndColor);
+ if (nAngle > 3600)
+ {
+ SAL_WARN("vcl", "angle out of range " << nAngle);
+ nAngle = 0;
+ }
+ rGradient.SetAngle(Degree10(nAngle));
+ rGradient.SetBorder(nBorder);
+ rGradient.SetOfsX(nOffsetX);
+ rGradient.SetOfsY(nOffsetY);
+ rGradient.SetStartIntensity(nIntensityStart);
+ rGradient.SetEndIntensity(nIntensityEnd);
+ rGradient.SetSteps(nStepCount);
+}
+
+void TypeSerializer::writeGradient(const Gradient& rGradient)
+{
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(rGradient.GetStyle()));
+ writeColor(rGradient.GetStartColor());
+ writeColor(rGradient.GetEndColor());
+ mrStream.WriteUInt16(rGradient.GetAngle().get());
+ mrStream.WriteUInt16(rGradient.GetBorder());
+ mrStream.WriteUInt16(rGradient.GetOfsX());
+ mrStream.WriteUInt16(rGradient.GetOfsY());
+ mrStream.WriteUInt16(rGradient.GetStartIntensity());
+ mrStream.WriteUInt16(rGradient.GetEndIntensity());
+ mrStream.WriteUInt16(rGradient.GetSteps());
+}
+
+void TypeSerializer::readGfxLink(GfxLink& rGfxLink)
+{
+ sal_uInt16 nType = 0;
+ sal_uInt32 nDataSize = 0;
+ sal_uInt32 nUserId = 0;
+
+ Size aSize;
+ MapMode aMapMode;
+ bool bMapAndSizeValid = false;
+
+ {
+ VersionCompatRead aCompat(mrStream);
+
+ // Version 1
+ mrStream.ReadUInt16(nType);
+ mrStream.ReadUInt32(nDataSize);
+ mrStream.ReadUInt32(nUserId);
+
+ if (aCompat.GetVersion() >= 2)
+ {
+ readSize(aSize);
+ readMapMode(aMapMode);
+ bMapAndSizeValid = true;
+ }
+ }
+
+ auto nRemainingData = mrStream.remainingSize();
+ if (nDataSize > nRemainingData)
+ {
+ SAL_WARN("vcl", "graphic link stream is smaller than requested size");
+ nDataSize = nRemainingData;
+ }
+
+ std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nDataSize]);
+ mrStream.ReadBytes(pBuffer.get(), nDataSize);
+
+ rGfxLink = GfxLink(std::move(pBuffer), nDataSize, static_cast<GfxLinkType>(nType));
+ rGfxLink.SetUserId(nUserId);
+
+ if (bMapAndSizeValid)
+ {
+ rGfxLink.SetPrefSize(aSize);
+ rGfxLink.SetPrefMapMode(aMapMode);
+ }
+}
+
+void TypeSerializer::writeGfxLink(const GfxLink& rGfxLink)
+{
+ {
+ VersionCompatWrite aCompat(mrStream, 2);
+
+ // Version 1
+ mrStream.WriteUInt16(sal_uInt16(rGfxLink.GetType()));
+ mrStream.WriteUInt32(rGfxLink.GetDataSize());
+ mrStream.WriteUInt32(rGfxLink.GetUserId());
+
+ // Version 2
+ writeSize(rGfxLink.GetPrefSize());
+ writeMapMode(rGfxLink.GetPrefMapMode());
+ }
+
+ if (rGfxLink.GetDataSize())
+ {
+ if (rGfxLink.GetData())
+ mrStream.WriteBytes(rGfxLink.GetData(), rGfxLink.GetDataSize());
+ }
+}
+
+namespace
+{
+#define NATIVE_FORMAT_50 COMPAT_FORMAT('N', 'A', 'T', '5')
+
+} // end anonymous namespace
+
+void TypeSerializer::readGraphic(Graphic& rGraphic)
+{
+ if (mrStream.GetError())
+ return;
+
+ const sal_uInt64 nInitialStreamPosition = mrStream.Tell();
+ sal_uInt32 nType;
+
+ // if there is no more data, avoid further expensive
+ // reading which will create VDevs and other stuff, just to
+ // read nothing.
+ if (mrStream.remainingSize() < 4)
+ return;
+
+ // read Id
+ mrStream.ReadUInt32(nType);
+
+ if (NATIVE_FORMAT_50 == nType)
+ {
+ Graphic aGraphic;
+ GfxLink aLink;
+
+ // read compat info, destructor writes stuff into the header
+ {
+ VersionCompatRead aCompat(mrStream);
+ }
+
+ readGfxLink(aLink);
+
+ if (!mrStream.GetError() && aLink.LoadNative(aGraphic))
+ {
+ if (aLink.IsPrefMapModeValid())
+ aGraphic.SetPrefMapMode(aLink.GetPrefMapMode());
+
+ if (aLink.IsPrefSizeValid())
+ aGraphic.SetPrefSize(aLink.GetPrefSize());
+ }
+ else
+ {
+ mrStream.Seek(nInitialStreamPosition);
+ mrStream.SetError(ERRCODE_IO_WRONGFORMAT);
+ }
+ rGraphic = aGraphic;
+ }
+ else
+ {
+ BitmapEx aBitmapEx;
+ const SvStreamEndian nOldFormat = mrStream.GetEndian();
+
+ mrStream.SeekRel(-4);
+ mrStream.SetEndian(SvStreamEndian::LITTLE);
+ ReadDIBBitmapEx(aBitmapEx, mrStream);
+
+ if (!mrStream.GetError())
+ {
+ sal_uInt32 nMagic1 = 0;
+ sal_uInt32 nMagic2 = 0;
+ if (mrStream.remainingSize() >= 8)
+ {
+ sal_uInt64 nBeginPosition = mrStream.Tell();
+ mrStream.ReadUInt32(nMagic1);
+ mrStream.ReadUInt32(nMagic2);
+ mrStream.Seek(nBeginPosition);
+ }
+ if (!mrStream.GetError())
+ {
+ if (nMagic1 == 0x5344414e && nMagic2 == 0x494d4931)
+ {
+ Animation aAnimation;
+ ReadAnimation(mrStream, aAnimation);
+
+ // #108077# manually set loaded BmpEx to Animation
+ // (which skips loading its BmpEx if already done)
+ aAnimation.SetBitmapEx(aBitmapEx);
+ rGraphic = Graphic(aAnimation);
+ }
+ else
+ {
+ rGraphic = Graphic(aBitmapEx);
+ }
+ }
+ else
+ {
+ mrStream.ResetError();
+ }
+ }
+ else
+ {
+ GDIMetaFile aMetaFile;
+
+ mrStream.Seek(nInitialStreamPosition);
+ mrStream.ResetError();
+ SvmReader aReader(mrStream);
+ aReader.Read(aMetaFile);
+
+ if (!mrStream.GetError())
+ {
+ rGraphic = Graphic(aMetaFile);
+ }
+ else
+ {
+ ErrCode nOriginalError = mrStream.GetErrorCode();
+ // try to stream in Svg defining data (length, byte array and evtl. path)
+ // See below (operator<<) for more information
+ sal_uInt32 nMagic;
+ mrStream.Seek(nInitialStreamPosition);
+ mrStream.ResetError();
+ mrStream.ReadUInt32(nMagic);
+
+ if (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic
+ || constPdfMagic == nMagic)
+ {
+ sal_uInt32 nLength = 0;
+ mrStream.ReadUInt32(nLength);
+
+ if (nLength)
+ {
+ auto rData = std::make_unique<std::vector<sal_uInt8>>(nLength);
+ mrStream.ReadBytes(rData->data(), rData->size());
+ BinaryDataContainer aDataContainer(std::move(rData));
+
+ if (!mrStream.GetError())
+ {
+ VectorGraphicDataType aDataType(VectorGraphicDataType::Svg);
+
+ switch (nMagic)
+ {
+ case constWmfMagic:
+ aDataType = VectorGraphicDataType::Wmf;
+ break;
+ case constEmfMagic:
+ aDataType = VectorGraphicDataType::Emf;
+ break;
+ case constPdfMagic:
+ aDataType = VectorGraphicDataType::Pdf;
+ break;
+ }
+
+ auto aVectorGraphicDataPtr
+ = std::make_shared<VectorGraphicData>(aDataContainer, aDataType);
+ rGraphic = Graphic(aVectorGraphicDataPtr);
+ }
+ }
+ }
+ else
+ {
+ mrStream.SetError(nOriginalError);
+ }
+
+ mrStream.Seek(nInitialStreamPosition);
+ }
+ }
+ mrStream.SetEndian(nOldFormat);
+ }
+}
+
+void TypeSerializer::writeGraphic(const Graphic& rGraphic)
+{
+ Graphic aGraphic(rGraphic);
+
+ if (!aGraphic.makeAvailable())
+ return;
+
+ auto pGfxLink = aGraphic.GetSharedGfxLink();
+
+ if (mrStream.GetVersion() >= SOFFICE_FILEFORMAT_50
+ && (mrStream.GetCompressMode() & SvStreamCompressFlags::NATIVE) && pGfxLink
+ && pGfxLink->IsNative())
+ {
+ // native format
+ mrStream.WriteUInt32(NATIVE_FORMAT_50);
+
+ // write compat info, destructor writes stuff into the header
+ {
+ VersionCompatWrite aCompat(mrStream, 1);
+ }
+ pGfxLink->SetPrefMapMode(aGraphic.GetPrefMapMode());
+ pGfxLink->SetPrefSize(aGraphic.GetPrefSize());
+ writeGfxLink(*pGfxLink);
+ }
+ else
+ {
+ // own format
+ const SvStreamEndian nOldFormat = mrStream.GetEndian();
+ mrStream.SetEndian(SvStreamEndian::LITTLE);
+
+ switch (aGraphic.GetType())
+ {
+ case GraphicType::NONE:
+ case GraphicType::Default:
+ break;
+
+ case GraphicType::Bitmap:
+ {
+ auto pVectorGraphicData = aGraphic.getVectorGraphicData();
+ if (pVectorGraphicData)
+ {
+ // stream out Vector Graphic defining data (length, byte array and evtl. path)
+ // this is used e.g. in swapping out graphic data and in transporting it over UNO API
+ // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
+ // no problem to extend it; only used at runtime
+ switch (pVectorGraphicData->getType())
+ {
+ case VectorGraphicDataType::Wmf:
+ {
+ mrStream.WriteUInt32(constWmfMagic);
+ break;
+ }
+ case VectorGraphicDataType::Emf:
+ {
+ mrStream.WriteUInt32(constEmfMagic);
+ break;
+ }
+ case VectorGraphicDataType::Svg:
+ {
+ mrStream.WriteUInt32(constSvgMagic);
+ break;
+ }
+ case VectorGraphicDataType::Pdf:
+ {
+ mrStream.WriteUInt32(constPdfMagic);
+ break;
+ }
+ }
+
+ sal_uInt32 nSize = pVectorGraphicData->getBinaryDataContainer().getSize();
+ mrStream.WriteUInt32(nSize);
+ mrStream.WriteBytes(pVectorGraphicData->getBinaryDataContainer().getData(),
+ nSize);
+ // For backwards compatibility, used to serialize path
+ mrStream.WriteUniOrByteString(u"", mrStream.GetStreamCharSet());
+ }
+ else if (aGraphic.IsAnimated())
+ {
+ WriteAnimation(mrStream, aGraphic.GetAnimation());
+ }
+ else
+ {
+ WriteDIBBitmapEx(aGraphic.GetBitmapEx(), mrStream);
+ }
+ }
+ break;
+
+ default:
+ {
+ if (aGraphic.IsSupportedGraphic())
+ {
+ if (!mrStream.GetError())
+ {
+ SvmWriter aWriter(mrStream);
+ aWriter.Write(rGraphic.GetGDIMetaFile());
+ }
+ }
+ }
+ break;
+ }
+ mrStream.SetEndian(nOldFormat);
+ }
+}
+
+bool TooLargeScaleForMapMode(const Fraction& rScale, int nDPI)
+{
+ // ImplLogicToPixel will multiply its values by this numerator * dpi and then double that
+ // result before dividing
+ if (rScale.GetNumerator() > std::numeric_limits<sal_Int32>::max() / nDPI / 2)
+ return true;
+ if (rScale.GetNumerator() < std::numeric_limits<sal_Int32>::min() / nDPI / 2)
+ return true;
+ return false;
+}
+
+static bool UselessScaleForMapMode(const Fraction& rScale)
+{
+ if (!rScale.IsValid())
+ return true;
+ if (TooLargeScaleForMapMode(rScale, 96))
+ return true;
+ if (static_cast<double>(rScale) < 0.0)
+ return true;
+ return false;
+}
+
+void TypeSerializer::readMapMode(MapMode& rMapMode)
+{
+ VersionCompatRead aCompat(mrStream);
+ sal_uInt16 nTmp16(0);
+ Point aOrigin;
+ Fraction aScaleX;
+ Fraction aScaleY;
+ bool bSimple(true);
+
+ mrStream.ReadUInt16(nTmp16);
+ MapUnit eUnit = static_cast<MapUnit>(nTmp16);
+ readPoint(aOrigin);
+ readFraction(aScaleX);
+ readFraction(aScaleY);
+ mrStream.ReadCharAsBool(bSimple);
+
+ const bool bBogus = UselessScaleForMapMode(aScaleX) || UselessScaleForMapMode(aScaleY);
+ SAL_WARN_IF(bBogus, "vcl", "invalid scale");
+
+ if (bSimple || bBogus)
+ rMapMode = MapMode(eUnit);
+ else
+ rMapMode = MapMode(eUnit, aOrigin, aScaleX, aScaleY);
+}
+
+void TypeSerializer::writeMapMode(MapMode const& rMapMode)
+{
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ mrStream.WriteUInt16(sal_uInt16(rMapMode.GetMapUnit()));
+ writePoint(rMapMode.GetOrigin());
+ writeFraction(rMapMode.GetScaleX());
+ writeFraction(rMapMode.GetScaleY());
+ mrStream.WriteBool(rMapMode.IsSimple());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */