/* -*- 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 .
*/
// Special case for animations if (rImpGraphic.mpAnimationContainer)
{
mpAnimationContainer = std::make_shared<AnimationContainer>(rImpGraphic.mpAnimationContainer->maAnimation);
maCachedBitmap = mpAnimationContainer->maAnimation.GetBitmapEx();
}
}
if (pSizeHint)
{
maSwapInfo.maPrefSize = *pSizeHint;
maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM);
}
GraphicDescriptor aDescriptor(aMemoryStream, nullptr); if (aDescriptor.Detect(true))
{ if (!pSizeHint)
{ // If we have logic size, work with that, as later pixel -> logic // conversion will work with the output device DPI, not the graphic // DPI.
Size aLogSize = aDescriptor.GetSize_100TH_MM(); if (aDescriptor.GetPreferredLogSize() && aDescriptor.GetPreferredMapMode())
{
maSwapInfo.maPrefSize = *aDescriptor.GetPreferredLogSize();
maSwapInfo.maPrefMapMode = *aDescriptor.GetPreferredMapMode();
} elseif (aLogSize.getWidth() && aLogSize.getHeight())
{
maSwapInfo.maPrefSize = aLogSize;
maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM);
} else
{
maSwapInfo.maPrefSize = aDescriptor.GetSizePixel();
maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel);
}
}
if (maVectorGraphicData)
maSwapInfo.mnPageIndex = maVectorGraphicData->getPageIndex();
// tdf#167007 Add animated graphic to cache when prepared // For some reason, after an animation has been swapped out by // MemoryManager::loopAndReduceMemory(), the animation repeatedly // creates a new ImpGraphic instance, swaps it in, but it never // gets registered in the cache. Since it is not in the cache, new // ImpGraphic instances get deleted almost immediately after they // are created. // So prevent immediate deletion by ensuring that animated // ImpGraphic instances are registered when they are prepared. if (maSwapInfo.mbIsAnimated)
registerIntoManager();
}
// calculate pixel size. Normally, it's the same as aDrawSize, but may // need to be extended when hairlines are on the right or bottom edge
Size aPixelSize(aDrawSize);
if(GraphicType::GdiMetafile == getType())
{ // tdf#126319 Removed correction based on hairline-at-the-extremes of // the metafile. The task shows that this is no longer sufficient since // less hairlines get used in general - what is good, but breaks that // old fix. Anyways, hairlines are a left-over from non-AA times // when it was not possible to paint lines taller than one pixel. // This might need to be corrected further using primitives and // the possibility to get better-quality ranges for correction. For // now, always add that one pixel.
aPixelSize.setWidth(aPixelSize.getWidth() + 1);
aPixelSize.setHeight(aPixelSize.getHeight() + 1);
}
// use maBitmapEx as local buffer for rendered metafile const_cast<ImpGraphic*>(this)->maCachedBitmap = aVDev->GetBitmapEx( Point(), aVDev->GetOutputSizePixel() );
}
}
// use maBitmapEx as local buffer for rendered metafile const_cast<ImpGraphic*>(this)->maCachedBitmap = BitmapEx(getBitmap(rParameters), aMonoMask.getBitmap(rParameters));
}
if (mpBitmapContainer) return mpBitmapContainer->getBitmapExRef(); else return maCachedBitmap;
}
const GDIMetaFile& ImpGraphic::getGDIMetaFile() const
{
ensureAvailable(); if (!maMetaFile.GetActionSize()
&& maVectorGraphicData
&& (VectorGraphicDataType::Emf == maVectorGraphicData->getType()
|| VectorGraphicDataType::Wmf == maVectorGraphicData->getType()))
{ // If we have a Emf/Wmf VectorGraphic object, we // need a way to get the Metafile data out of the primitive // representation. Use a strict virtual hook (MetafileAccessor) // to access the MetafilePrimitive2D directly. Also see comments in // XEmfParser about this. const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > aSequence(maVectorGraphicData->getPrimitive2DSequence());
if (1 == aSequence.size())
{ // try to cast to MetafileAccessor implementation const css::uno::Reference< css::graphic::XPrimitive2D >& xReference(aSequence[0]); auto pUnoPrimitive = static_cast< const drawinglayer::primitive2d::UnoPrimitive2D* >(xReference.get()); if (pUnoPrimitive)
{ const MetafileAccessor* pMetafileAccessor = dynamic_cast< const MetafileAccessor* >(pUnoPrimitive->getBasePrimitive2D().get());
if (pMetafileAccessor)
{ // it is a MetafileAccessor implementation, get Metafile
pMetafileAccessor->accessMetafile(const_cast< ImpGraphic* >(this)->maMetaFile);
}
}
}
}
if (GraphicType::Bitmap == meType && !maMetaFile.GetActionSize())
{ if (maVectorGraphicData)
updateBitmapFromVectorGraphic();
// #i119735# // Use the local maMetaFile as container for a metafile-representation // of the bitmap graphic. This will be done only once, thus be buffered. // I checked all usages of maMetaFile, it is only used when type is not // GraphicType::Bitmap. In operator= it will get copied, thus buffering will // survive copying (change this if not wanted)
ImpGraphic* pThat = const_cast< ImpGraphic* >(this);
// #123983# directly create a metafile with the same PrefSize and PrefMapMode // the bitmap has, this will be an always correct metafile if (aBitmapEx.IsAlpha())
{
pThat->maMetaFile.AddAction(new MetaBmpExScaleAction(Point(), aBitmapEx.GetPrefSize(), aBitmapEx));
} else
{
pThat->maMetaFile.AddAction(new MetaBmpScaleAction(Point(), aBitmapEx.GetPrefSize(), aBitmapEx.GetBitmap()));
}
if (isSwappedOut())
{
aSize = maSwapInfo.maPrefSize;
} else
{ switch (meType)
{ case GraphicType::Bitmap:
{ if (maVectorGraphicData)
{ if (maCachedBitmap.IsEmpty())
{ if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight())
{ // svg not yet buffered in maBitmapEx, return size derived from range const basegfx::B2DRange& rRange = maVectorGraphicData->getRange();
#ifdef MACOSX // tdf#157680 scale down estimated size of embedded PDF // For some unknown reason, the embedded PDF sizes // are 20x larger than expected. This only occurs on // macOS so possibly there is some special conversion // from MapUnit::MapPoint to MapUnit::MapTwip elsewhere // in the code. if (maVectorGraphicData->getType() == VectorGraphicDataType::Pdf)
aSize = Size(basegfx::fround(rRange.getWidth() / 20.0f), basegfx::fround(rRange.getHeight() / 20.0f)); else #endif
aSize = Size(basegfx::fround<tools::Long>(rRange.getWidth()), basegfx::fround<tools::Long>(rRange.getHeight()));
} else
{
aSize = maExPrefSize;
}
} else
{
aSize = maCachedBitmap.GetPrefSize();
case GraphicType::GdiMetafile:
{
aSize = maMetaFile.GetPrefSize();
} break;
case GraphicType::NONE: case GraphicType::Default: break;
}
}
return aSize;
}
void ImpGraphic::setValuesForPrefSize(const Size& rPrefSize)
{ switch (meType)
{ case GraphicType::Bitmap:
{ // used when importing a writer FlyFrame with SVG as graphic, added conversion // to allow setting the PrefSize at the BitmapEx to hold it if (maVectorGraphicData)
{
maExPrefSize = rPrefSize;
maCachedBitmap.SetPrefSize(rPrefSize);
} // #108077# Push through pref size to animation object, // will be lost on copy otherwise elseif (mpAnimationContainer)
{ const_cast<BitmapEx&>(mpAnimationContainer->maAnimation.GetBitmapEx()).SetPrefSize(rPrefSize);
maCachedBitmap.SetPrefSize(rPrefSize);
} elseif (mpBitmapContainer)
{
mpBitmapContainer->maBitmapEx.SetPrefSize(rPrefSize);
}
} break;
case GraphicType::GdiMetafile:
{ if (isSupportedGraphic())
maMetaFile.SetPrefSize(rPrefSize);
} break;
case GraphicType::NONE: case GraphicType::Default: break;
}
}
if (isSwappedOut())
{
aMapMode = maSwapInfo.maPrefMapMode;
} else
{ switch (meType)
{ case GraphicType::Bitmap:
{ if (maVectorGraphicData)
{ if (maCachedBitmap.IsEmpty())
{ // svg not yet buffered in maBitmapEx, return default PrefMapMode
aMapMode = MapMode(MapUnit::Map100thMM);
} else
{ const Size aSize = maCachedBitmap.GetPrefSize(); if (aSize.Width() && aSize.Height())
aMapMode = maCachedBitmap.GetPrefMapMode();
}
} elseif (mpBitmapContainer)
{
aMapMode = mpBitmapContainer->getPrefMapMode();
} elseif (mpAnimationContainer)
{
aMapMode = mpAnimationContainer->getPrefMapMode();
}
} break;
case GraphicType::GdiMetafile:
{ return maMetaFile.GetPrefMapMode();
} break;
case GraphicType::NONE: case GraphicType::Default: break;
}
}
return aMapMode;
}
void ImpGraphic::setValuesForPrefMapMod(const MapMode& rPrefMapMode)
{ switch (meType)
{ case GraphicType::Bitmap:
{ if (maVectorGraphicData)
{ // ignore for Vector Graphic Data. If this is really used (except the grfcache) // it can be extended by using maBitmapEx as buffer for updateBitmapFromVectorGraphic()
}
// #108077# Push through pref mapmode to animation object, // will be lost on copy otherwise elseif (mpAnimationContainer)
{ const_cast<BitmapEx&>(mpAnimationContainer->maAnimation.GetBitmapEx()).SetPrefMapMode(rPrefMapMode);
maCachedBitmap.SetPrefMapMode(rPrefMapMode);
} elseif (mpBitmapContainer)
{
mpBitmapContainer->maBitmapEx.SetPrefMapMode(rPrefMapMode);
}
} break;
case GraphicType::GdiMetafile:
{
maMetaFile.SetPrefMapMode(rPrefMapMode);
} break;
case GraphicType::NONE: case GraphicType::Default: break;
}
}
case GraphicType::Bitmap:
{ if (maVectorGraphicData)
{
rStream.WriteInt32(sal_Int32(GraphicContentType::Vector)); // 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 (maVectorGraphicData->getType())
{ case VectorGraphicDataType::Wmf:
{
rStream.WriteUInt32(constWmfMagic); break;
} case VectorGraphicDataType::Emf:
{
rStream.WriteUInt32(constEmfMagic); break;
} case VectorGraphicDataType::Svg:
{
rStream.WriteUInt32(constSvgMagic); break;
} case VectorGraphicDataType::Pdf:
{
rStream.WriteUInt32(constPdfMagic); break;
}
}
if (isSwappedOut())
{ auto pThis = const_cast<ImpGraphic*>(this);
pThis->registerIntoManager();
bResult = pThis->swapIn();
}
resetLastUsed(); return bResult;
}
void ImpGraphic::updateFromLoadedGraphic(const ImpGraphic* pGraphic)
{ if (mbPrepared)
{
GraphicExternalLink aLink = maGraphicExternalLink;
Size aPrefSize = maSwapInfo.maPrefSize;
MapMode aPrefMapMode = maSwapInfo.maPrefMapMode;
*this = *pGraphic; if (aPrefSize.getWidth() && aPrefSize.getHeight() && aPrefMapMode == getPrefMapMode())
{ // Use custom preferred size if it was set when the graphic was still unloaded. // Only set the size in case the unloaded and loaded unit matches.
setPrefSize(aPrefSize);
}
maGraphicExternalLink = std::move(aLink);
} else
{ // Move over only graphic content
mpAnimationContainer.reset();
case GraphicContentType::Vector:
{ // try to stream in Svg defining data (length, byte array and evtl. path) // See below (operator<<) for more information
sal_uInt32 nMagic;
rStream.ReadUInt32(nMagic);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.