Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / filter / ww8 / ww8par4.cxx
blob46bfa7325d68915ce4cff583743c30df4a950d92
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <doc.hxx>
21 #include <IDocumentContentOperations.hxx>
22 #include "writerhelper.hxx"
23 #include <com/sun/star/embed/XClassifiedObject.hpp>
24 #include <com/sun/star/embed/Aspects.hpp>
26 #include <cstddef>
27 #include <osl/endian.h>
28 #include <sot/storage.hxx>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <hintids.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <filter/msfilter/msdffimp.hxx>
33 #include "sprmids.hxx"
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
37 #include <sot/exchange.hxx>
38 #include <fmtanchr.hxx>
39 #include <frmfmt.hxx>
40 #include <pam.hxx>
41 #include <docsh.hxx>
42 #include <mdiexp.hxx>
43 #include <fltshell.hxx>
44 #include <shellio.hxx>
46 #include <vcl/wmf.hxx>
47 #include <vcl/gdimtf.hxx>
49 #include "ww8scan.hxx"
50 #include "ww8par.hxx"
51 #include "ww8par2.hxx"
53 namespace {
55 struct OLE_MFP
57 sal_Int16 mm; // 0x6 int
58 sal_Int16 xExt; // 0x8 int in 1/100 mm
59 sal_Int16 yExt; // 0xa int in 1/100 mm
60 sal_Int16 hMF; // 0xc int
65 using namespace ::com::sun::star;
67 static bool SwWw8ReadScaling(tools::Long& rX, tools::Long& rY, tools::SvRef<SotStorage> const & rSrc1)
69 // Getting the scaling factor:
70 // Information in the PIC-stream (by trying out)
71 // 0x0 (l)cb
72 // 0x08 .. 0x0a Flags ??
73 // 0x08 contains: 1 / 0
74 // 0x09 contains: 0,8,0x18
75 // 0x0a contains: always 8, MAP_ANISOTROPIC ???
76 // 0x0b contains: always 0
77 // 0x0c, 0x10 original size x,y in 1/100 mm
78 // 0x14, 0x16 original size x,y in tw
79 // 0x2c, 0x30 scaling x,y in per thousand
80 // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
82 tools::SvRef<SotStorageStream> xSrc3 = rSrc1->OpenSotStream( "\3PIC",
83 StreamMode::STD_READ );
84 SotStorageStream* pS = xSrc3.get();
85 pS->SetEndian( SvStreamEndian::LITTLE );
87 OSL_ENSURE( pS->TellEnd() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
89 sal_Int32 nOrgWidth,
90 nOrgHeight,
91 nScaleX,
92 nScaleY,
93 nCropLeft,
94 nCropTop,
95 nCropRight,
96 nCropBottom;
97 pS->Seek( 0x14 );
98 pS->ReadInt32( nOrgWidth ) // Original Size in 1/100 mm
99 .ReadInt32( nOrgHeight );
100 pS->Seek( 0x2c );
101 pS->ReadInt32( nScaleX ) // Scaling in Promille
102 .ReadInt32( nScaleY )
103 .ReadInt32( nCropLeft ) // Cropping in 1/100 mm
104 .ReadInt32( nCropTop )
105 .ReadInt32( nCropRight )
106 .ReadInt32( nCropBottom );
108 rX = nOrgWidth - nCropLeft - nCropRight;
109 rY = nOrgHeight - nCropTop - nCropBottom;
110 if (10 > nScaleX || 65536 < nScaleX || 10 > nScaleY || 65536 < nScaleY)
112 OSL_ENSURE( !pS, "+OLE-scaling information in PIC-stream wrong" );
113 return false;
115 else
117 rX = (rX * nScaleX) / 1000;
118 rY = (rY * nScaleY) / 1000;
120 return true;
123 static bool SwWw6ReadMetaStream(GDIMetaFile& rWMF, OLE_MFP* pMfp,
124 tools::SvRef<SotStorage> const & rSrc1)
126 tools::SvRef<SotStorageStream> xSrc2 = rSrc1->OpenSotStream( "\3META",
127 StreamMode::STD_READ );
128 SotStorageStream* pSt = xSrc2.get();
129 pSt->SetEndian( SvStreamEndian::LITTLE );
130 size_t const nRead = pSt->ReadBytes(pMfp, sizeof(*pMfp));
131 // read mini-placable-header
132 if (nRead != sizeof(*pMfp))
133 return false;
135 #if defined OSL_BIGENDIAN
136 pMfp->mm = OSL_SWAPWORD( pMfp->mm );
137 pMfp->xExt = OSL_SWAPWORD( pMfp->xExt );
138 pMfp->yExt = OSL_SWAPWORD( pMfp->yExt );
139 #endif // OSL_BIGENDIAN
141 if( pMfp->mm == 94 || pMfp->mm == 99 )
143 SAL_WARN("sw.ww8", "+OLE: wrong metafile type");
144 return false;
146 if( pMfp->mm != 8 )
148 SAL_WARN("sw.ww8", "OLE: wrong mMetafile type (not anisotropic)");
150 if( !pMfp->xExt || !pMfp->yExt )
152 SAL_WARN("sw.ww8", "+OLE: size of 0?");
153 return false;
155 bool bOk = ReadWindowMetafile( *pSt, rWMF ); // read WMF
156 // *pSt >> aWMF doesn't work without the placable header
157 if (!bOk || pSt->GetError() || rWMF.GetActionSize() == 0)
159 SAL_WARN("sw.ww8", "+OLE: could not read the metafile");
160 return false;
163 rWMF.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
165 // Scale MetaFile to new size and save new size to MetaFile
166 Size aOldSiz( rWMF.GetPrefSize() );
167 Size aNewSiz( pMfp->xExt, pMfp->yExt );
168 Fraction aFracX( aNewSiz.Width(), aOldSiz.Width() );
169 Fraction aFracY( aNewSiz.Height(), aOldSiz.Height() );
171 rWMF.Scale( aFracX, aFracY );
172 rWMF.SetPrefSize( aNewSiz );
174 return true;
177 static bool SwWw6ReadMacPICTStream(Graphic& rGraph, tools::SvRef<SotStorage> const & rSrc1)
179 // 03-META-stream does not exist. Maybe a 03-PICT?
180 tools::SvRef<SotStorageStream> xSrc4 = rSrc1->OpenSotStream("\3PICT");
181 SotStorageStream* pStp = xSrc4.get();
182 pStp->SetEndian( SvStreamEndian::LITTLE );
183 sal_uInt8 aTestA[10]; // Does the 01Ole-stream even exist?
184 size_t const nReadTst = pStp->ReadBytes(aTestA, sizeof(aTestA));
185 if (nReadTst != sizeof(aTestA))
186 return false;
188 pStp->Seek( STREAM_SEEK_TO_BEGIN );
190 // Mac-Pict is in the 03PICT-StorageStream but without the first 512 Bytes
191 // which are not relevant in a MAC-PICT (they are not evaluated)
192 return SwWW8ImplReader::GetPictGrafFromStream(rGraph, *pStp);
195 SwFlyFrameFormat* SwWW8ImplReader::InsertOle(SdrOle2Obj &rObject,
196 const SfxItemSet &rFlySet, const SfxItemSet *rGrfSet)
198 SfxObjectShell *pPersist = m_rDoc.GetPersist();
199 OSL_ENSURE(pPersist, "No persist, cannot insert objects correctly");
200 if (!pPersist)
201 return nullptr;
203 SwFlyFrameFormat *pRet = nullptr;
205 std::optional<SfxItemSet> pMathFlySet;
206 uno::Reference < embed::XClassifiedObject > xClass = rObject.GetObjRef();
207 if( xClass.is() )
209 SvGlobalName aClassName( xClass->getClassID() );
210 if (SotExchange::IsMath(aClassName))
212 // StarMath sets it own fixed size, so its counter productive to use
213 // the size Word says it is. i.e. Don't attempt to override its size.
214 pMathFlySet.emplace(rFlySet);
215 pMathFlySet->ClearItem(RES_FRM_SIZE);
220 Take complete responsibility of the object away from SdrOle2Obj and to
221 me here locally. This utility class now owns the object.
224 // TODO/MBA: is the object inserted multiple times here? Testing!
225 // And is it a problem that we now use the same naming scheme as in the other apps?
226 sw::hack::DrawingOLEAdaptor aOLEObj(rObject, *pPersist);
227 OUString sNewName;
228 bool bSuccess = aOLEObj.TransferToDoc(sNewName);
230 OSL_ENSURE(bSuccess, "Insert OLE failed");
231 if (bSuccess)
233 const SfxItemSet *pFlySet = pMathFlySet ? &*pMathFlySet : &rFlySet;
234 pRet = m_rDoc.getIDocumentContentOperations().InsertOLE(*m_pPaM, sNewName, rObject.GetAspect(), pFlySet, rGrfSet);
236 return pRet;
239 SwFrameFormat* SwWW8ImplReader::ImportOle(const Graphic* pGrf,
240 const SfxItemSet* pFlySet, const SfxItemSet *pGrfSet, const tools::Rectangle& aVisArea )
242 ::SetProgressState(m_nProgress, m_pDocShell); // Update
243 SwFrameFormat* pFormat = nullptr;
245 GraphicCtor();
247 Graphic aGraph;
248 rtl::Reference<SdrObject> pRet = ImportOleBase(aGraph, pGrf, pFlySet, aVisArea );
250 // create flyset
251 std::optional<SfxItemSet> pTempSet;
252 if( !pFlySet )
254 pTempSet.emplace( m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN,
255 RES_FRMATR_END-1> );
257 pFlySet = &*pTempSet;
259 // Remove distance/borders
260 Reader::ResetFrameFormatAttrs( *pTempSet );
262 SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR );
263 aAnchor.SetAnchor( m_pPaM->GetPoint() );
264 pTempSet->Put( aAnchor );
266 const Size aSizeTwip = OutputDevice::LogicToLogic(
267 aGraph.GetPrefSize(), aGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
269 pTempSet->Put( SwFormatFrameSize( SwFrameSize::Fixed, aSizeTwip.Width(),
270 aSizeTwip.Height() ) );
271 pTempSet->Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
273 if (m_xSFlyPara)
275 // Resize the frame to the picture size if there is an OLE object
276 // in the frame (only if auto-width)
277 m_xSFlyPara->BoxUpWidth(aSizeTwip.Width());
281 if (pRet) // OLE object was inserted
283 if (SdrOle2Obj *pOleObj = dynamic_cast<SdrOle2Obj*>(pRet.get()))
285 pFormat = InsertOle(*pOleObj, *pFlySet, pGrfSet);
286 pRet.clear(); // we don't need this anymore
288 else
289 pFormat = m_rDoc.getIDocumentContentOperations().InsertDrawObj(*m_pPaM, *pRet, *pFlySet );
291 else if (
292 GraphicType::GdiMetafile == aGraph.GetType() ||
293 GraphicType::Bitmap == aGraph.GetType()
296 pFormat = m_rDoc.getIDocumentContentOperations().InsertGraphic(
297 *m_pPaM, OUString(), OUString(), &aGraph, pFlySet,
298 pGrfSet, nullptr);
300 return pFormat;
303 bool SwWW8ImplReader::ImportOleWMF(const tools::SvRef<SotStorage>& xSrc1, GDIMetaFile& rWMF,
304 tools::Long& rX, tools::Long& rY)
306 bool bOk = false;
307 OLE_MFP aMfp;
308 if( SwWw6ReadMetaStream( rWMF, &aMfp, xSrc1 ) )
310 // take scaling factor as found in PIC and apply it to graphic.
311 SwWw8ReadScaling( rX, rY, xSrc1 );
312 Size aFinalSize, aOrigSize;
313 aFinalSize.setWidth( rX );
314 aFinalSize.setHeight( rY );
315 aFinalSize = OutputDevice::LogicToLogic(
316 aFinalSize, MapMode(MapUnit::MapTwip), rWMF.GetPrefMapMode() );
317 aOrigSize = rWMF.GetPrefSize();
318 Fraction aScaleX(aFinalSize.Width(),aOrigSize.Width());
319 Fraction aScaleY(aFinalSize.Height(),aOrigSize.Height());
320 rWMF.Scale( aScaleX, aScaleY );
321 bOk = true;
323 return bOk;
326 rtl::Reference<SdrObject> SwWW8ImplReader::ImportOleBase( Graphic& rGraph,
327 const Graphic* pGrf, const SfxItemSet* pFlySet, const tools::Rectangle& aVisArea )
329 if (!m_pStg)
331 SAL_WARN("sw.ww8", "no storage for ole objects");
332 return nullptr;
335 ::SetProgressState( m_nProgress, m_rDoc.GetDocShell() ); // Update
337 tools::Long nX=0, nY=0; // nX, nY is graphic size
338 bool bOleOk = true;
340 // results in the name "_4711"
341 OUString aSrcStgName = "_" + OUString::number( m_nObjLocFc );
343 tools::SvRef<SotStorage> xSrc0 = m_pStg->OpenSotStorage(SL::aObjectPool);
344 tools::SvRef<SotStorage> xSrc1 = xSrc0->OpenSotStorage( aSrcStgName );
346 if (pGrf)
348 rGraph = *pGrf;
349 const Size aSizeTwip = OutputDevice::LogicToLogic(
350 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
351 nX = aSizeTwip.Width();
352 nY = aSizeTwip.Height();
354 else
356 GDIMetaFile aWMF;
358 if (ImportOleWMF(xSrc1,aWMF,nX,nY))
359 rGraph = Graphic( aWMF );
360 else if( SwWw6ReadMacPICTStream( rGraph, xSrc1 ) )
362 // 03-META stream is not available. Maybe it's a 03-PICT?
363 const Size aSizeTwip = OutputDevice::LogicToLogic(
364 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
365 nX = aSizeTwip.Width();
366 nY = aSizeTwip.Height();
367 // PICT: no WMF available -> Graphic instead of OLE
368 bOleOk = false;
370 } // StorageStreams closed again
372 tools::Rectangle aRect(0, 0, nX, nY);
374 if (pFlySet)
376 if (const SwFormatFrameSize* pSize = pFlySet->GetItem<SwFormatFrameSize>(RES_FRM_SIZE, false))
378 aRect.SetSize(pSize->GetSize());
382 rtl::Reference<SdrObject> pRet;
384 if (!(m_bIsHeader || m_bIsFooter))
386 //Can't put them in headers/footers :-(
387 uno::Reference< drawing::XShape > xRef;
388 OSL_ENSURE(m_xFormImpl, "Impossible");
389 if (m_xFormImpl && m_xFormImpl->ReadOCXStream(xSrc1, &xRef))
391 pRet = SdrObject::getSdrObjectFromXShape(xRef);
392 OSL_ENSURE(pRet, "Impossible");
393 if (pRet)
394 pRet->SetLogicRect(aRect);
395 return pRet;
399 if (GraphicType::GdiMetafile == rGraph.GetType() ||
400 GraphicType::Bitmap == rGraph.GetType())
402 ::SetProgressState(m_nProgress, m_pDocShell); // Update
404 if (bOleOk)
406 sal_uInt64 nOldPos = m_pDataStream->Tell();
407 SvStream *pTmpData = nullptr;
408 if (m_nObjLocFc < m_pDataStream->TellEnd())
410 pTmpData = m_pDataStream;
411 pTmpData->Seek( m_nObjLocFc );
414 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
417 tools::SvRef<SotStorageStream> xObjInfoSrc = xSrc1->OpenSotStream("\3ObjInfo",
418 StreamMode::STD_READ );
419 if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
421 sal_uInt8 nByte = 0;
422 xObjInfoSrc->ReadUChar( nByte );
423 if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
424 nAspect = embed::Aspects::MSOLE_ICON;
428 ErrCode nError = ERRCODE_NONE;
429 GraphicCtor();
431 pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
432 *m_pDrawModel,
433 aSrcStgName,
434 xSrc0,
435 m_pDocShell->GetStorage(),
436 rGraph,
437 aRect,
438 aVisArea,
439 pTmpData,
440 nError,
441 SwMSDffManager::GetFilterFlags(),
442 nAspect,
443 GetBaseURL());
444 m_pDataStream->Seek( nOldPos );
447 return pRet;
450 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream& rStrm,
451 sal_Int32 nTablePos, sal_Int32 nTableSiz, SwDoc& rDocOut )
453 std::vector<OUString> aAuthorNames;
454 WW8ReadSTTBF( !m_bVer67, rStrm, nTablePos, nTableSiz, m_bVer67 ? 2 : 0,
455 m_eStructCharSet, aAuthorNames );
457 sal_uInt16 nCount = static_cast< sal_uInt16 >(aAuthorNames.size());
458 for( sal_uInt16 nAuthor = 0; nAuthor < nCount; ++nAuthor )
460 // Store author in doc
461 std::size_t nSWId = rDocOut.getIDocumentRedlineAccess().InsertRedlineAuthor(aAuthorNames[nAuthor]);
462 // Store matchpair
463 m_aAuthorInfos[nAuthor] = nSWId;
468 Revision Marks ( == Redlining )
470 // insert or delete content (change char attributes resp.)
471 void SwWW8ImplReader::Read_CRevisionMark(RedlineType eType,
472 const sal_uInt8* pData, short nLen )
474 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
475 // pointing to the very same char position as our SprmCFRMark[Del]
476 if (!m_xPlcxMan)
477 return;
478 const sal_uInt8* pSprmCIbstRMark;
479 const sal_uInt8* pSprmCDttmRMark;
480 if( RedlineType::Format == eType )
482 pSprmCIbstRMark = nLen >= 3 ? pData+1 : nullptr;
483 pSprmCDttmRMark = nLen >= 7 ? pData+3 : nullptr;
485 else
487 /* It is possible to have a number of date stamps for the created time
488 * of the change, (possibly a word bug) so we must use the "get a full
489 * list" variant of HasCharSprm and take the last one as the true one.
491 std::vector<SprmResult> aResult;
492 bool bIns = (RedlineType::Insert == eType);
493 if( m_bVer67 )
495 m_xPlcxMan->HasCharSprm(69, aResult);
496 pSprmCIbstRMark = (aResult.empty() || aResult.back().nRemainingData < 2) ? nullptr : aResult.back().pSprm;
497 aResult.clear();
498 m_xPlcxMan->HasCharSprm(70, aResult);
499 pSprmCDttmRMark = (aResult.empty() || aResult.back().nRemainingData < 4) ? nullptr : aResult.back().pSprm;
501 else
503 m_xPlcxMan->HasCharSprm( bIns ? 0x4804 : 0x4863, aResult);
504 pSprmCIbstRMark = (aResult.empty() || aResult.back().nRemainingData < 2) ? nullptr : aResult.back().pSprm;
505 aResult.clear();
506 m_xPlcxMan->HasCharSprm( bIns ? 0x6805 : NS_sprm::CDttmRMarkDel::val, aResult);
507 pSprmCDttmRMark = (aResult.empty() || aResult.back().nRemainingData < 4) ? nullptr : aResult.back().pSprm;
511 if (nLen < 0)
512 m_xRedlineStack->close(*m_pPaM->GetPoint(), eType, m_xTableDesc.get());
513 else
515 // start of new revision mark, if not there default to first entry
516 sal_uInt16 nWWAutNo = pSprmCIbstRMark ? SVBT16ToUInt16(pSprmCIbstRMark) : 0;
517 sal_uInt32 nWWDate = pSprmCDttmRMark ? SVBT32ToUInt32(pSprmCDttmRMark): 0;
518 DateTime aStamp(msfilter::util::DTTM2DateTime(nWWDate));
519 std::size_t nAuthorNo = m_aAuthorInfos[nWWAutNo];
520 SwFltRedline aNewAttr(eType, nAuthorNo, aStamp);
521 NewAttr(aNewAttr);
525 // insert new content
526 void SwWW8ImplReader::Read_CFRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
528 Read_CRevisionMark( RedlineType::Insert, pData, nLen );
531 // delete old content
532 void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16 , const sal_uInt8* pData, short nLen)
534 Read_CRevisionMark( RedlineType::Delete, pData, nLen );
537 // change properties of content ( == char formatting)
538 void SwWW8ImplReader::Read_CPropRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
540 // complex (len is always 7)
541 // 1 byte - chp.fPropRMark
542 // 2 bytes - chp.ibstPropRMark
543 // 4 bytes - chp.dttmPropRMark;
544 Read_CRevisionMark( RedlineType::Format, pData, nLen );
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */