build fix
[LibreOffice.git] / sw / source / filter / ww8 / ww8par4.cxx
blob05edf9a87fc321d9b4bc11409ef4706e29a7fa95
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 <algorithm>
27 #include <functional>
28 #include <osl/endian.h>
29 #include <sot/storage.hxx>
30 #include <com/sun/star/drawing/XShape.hpp>
31 #include <hintids.hxx>
32 #include <svx/svdoole2.hxx>
33 #include <filter/msfilter/msdffimp.hxx>
34 #include <sprmids.hxx>
35 #include <svx/unoapi.hxx>
37 #include <sot/exchange.hxx>
38 #include <swtypes.hxx>
39 #include <fmtanchr.hxx>
40 #include <fmtcntnt.hxx>
41 #include <dcontact.hxx>
42 #include <frmfmt.hxx>
43 #include <pam.hxx>
44 #include <ndgrf.hxx>
45 #include <docsh.hxx>
46 #include <mdiexp.hxx>
47 #include <redline.hxx>
48 #include <fltshell.hxx>
49 #include <unodraw.hxx>
50 #include <shellio.hxx>
51 #include <ndole.hxx>
53 #include <vcl/graphicfilter.hxx>
54 #include <vcl/wmf.hxx>
56 #include "ww8scan.hxx"
57 #include "ww8par.hxx"
58 #include "ww8par2.hxx"
60 struct OLE_MFP
62 sal_Int16 mm; // 0x6 int
63 sal_Int16 xExt; // 0x8 int in 1/100 mm
64 sal_Int16 yExt; // 0xa int in 1/100 mm
65 sal_Int16 hMF; // 0xc int
68 using namespace ::com::sun::star;
70 static bool SwWw8ReadScaling(long& rX, long& rY, tools::SvRef<SotStorage>& rSrc1)
72 // Getting the scaling factor:
73 // Information in the PIC-stream (by trying out)
74 // 0x0 (l)cb
75 // 0x08 .. 0x0a Flags ??
76 // 0x08 contains: 1 / 0
77 // 0x09 contains: 0,8,0x18
78 // 0x0a contains: always 8, MAP_ANISOTROPIC ???
79 // 0x0b contains: always 0
80 // 0x0c, 0x10 original size x,y in 1/100 mm
81 // 0x14, 0x16 original size x,y in tw
82 // 0x2c, 0x30 scaling x,y in per thousand
83 // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
85 tools::SvRef<SotStorageStream> xSrc3 = rSrc1->OpenSotStream( "\3PIC",
86 StreamMode::STD_READ );
87 SotStorageStream* pS = xSrc3.get();
88 pS->SetEndian( SvStreamEndian::LITTLE );
89 pS->Seek( STREAM_SEEK_TO_END );
91 OSL_ENSURE( pS->Tell() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
93 sal_Int32 nOrgWidth,
94 nOrgHeight,
95 nScaleX,
96 nScaleY,
97 nCropLeft,
98 nCropTop,
99 nCropRight,
100 nCropBottom;
101 pS->Seek( 0x14 );
102 pS->ReadInt32( nOrgWidth ) // Original Size in 1/100 mm
103 .ReadInt32( nOrgHeight );
104 pS->Seek( 0x2c );
105 pS->ReadInt32( nScaleX ) // Scaling in Promille
106 .ReadInt32( nScaleY )
107 .ReadInt32( nCropLeft ) // Cropping in 1/100 mm
108 .ReadInt32( nCropTop )
109 .ReadInt32( nCropRight )
110 .ReadInt32( nCropBottom );
112 rX = nOrgWidth - nCropLeft - nCropRight;
113 rY = nOrgHeight - nCropTop - nCropBottom;
114 if (10 > nScaleX || 65536 < nScaleX || 10 > nScaleY || 65536 < nScaleY)
116 OSL_ENSURE( !pS, "+OLE-scaling information in PIC-stream wrong" );
117 return false;
119 else
121 rX = (rX * nScaleX) / 1000;
122 rY = (rY * nScaleY) / 1000;
124 return true;
127 static bool SwWw6ReadMetaStream(GDIMetaFile& rWMF, OLE_MFP* pMfp,
128 tools::SvRef<SotStorage>& rSrc1)
130 tools::SvRef<SotStorageStream> xSrc2 = rSrc1->OpenSotStream( "\3META",
131 StreamMode::STD_READ );
132 SotStorageStream* pSt = xSrc2.get();
133 pSt->SetEndian( SvStreamEndian::LITTLE );
134 size_t const nRead = pSt->ReadBytes(pMfp, sizeof(*pMfp));
135 // read mini-placable-header
136 if (nRead != sizeof(*pMfp))
137 return false;
139 #if defined OSL_BIGENDIAN
140 pMfp->mm = OSL_SWAPWORD( pMfp->mm );
141 pMfp->xExt = OSL_SWAPWORD( pMfp->xExt );
142 pMfp->yExt = OSL_SWAPWORD( pMfp->yExt );
143 #endif // OSL_BIGENDIAN
145 if( pMfp->mm == 94 || pMfp->mm == 99 )
147 SAL_WARN("sw.ww8", "+OLE: wrong metafile type");
148 return false;
150 if( pMfp->mm != 8 )
152 SAL_WARN("sw.ww8", "OLE: wrong mMetafile type (not anisotropic)");
154 if( !pMfp->xExt || !pMfp->yExt )
156 SAL_WARN("sw.ww8", "+OLE: size of 0?");
157 return false;
159 bool bOk = ReadWindowMetafile( *pSt, rWMF ); // read WMF
160 // *pSt >> aWMF doesn't work without the placable header
161 if (!bOk || pSt->GetError() || rWMF.GetActionSize() == 0)
163 SAL_WARN("sw.ww8", "+OLE: could not read the metafile");
164 return false;
167 rWMF.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
169 // Scale MetaFile to new size and save new size to MetaFile
170 Size aOldSiz( rWMF.GetPrefSize() );
171 Size aNewSiz( pMfp->xExt, pMfp->yExt );
172 Fraction aFracX( aNewSiz.Width(), aOldSiz.Width() );
173 Fraction aFracY( aNewSiz.Height(), aOldSiz.Height() );
175 rWMF.Scale( aFracX, aFracY );
176 rWMF.SetPrefSize( aNewSiz );
178 return true;
181 static bool SwWw6ReadMacPICTStream(Graphic& rGraph, tools::SvRef<SotStorage>& rSrc1)
183 // 03-META-stream does not exist. Maybe a 03-PICT?
184 tools::SvRef<SotStorageStream> xSrc4 = rSrc1->OpenSotStream("\3PICT");
185 SotStorageStream* pStp = xSrc4.get();
186 pStp->SetEndian( SvStreamEndian::LITTLE );
187 sal_uInt8 aTestA[10]; // Does the 01Ole-stream even exist?
188 size_t const nReadTst = pStp->ReadBytes(aTestA, sizeof(aTestA));
189 if (nReadTst != sizeof(aTestA))
190 return false;
192 pStp->Seek( STREAM_SEEK_TO_BEGIN );
194 // Mac-Pict is in the 03PICT-StorageStream but without the first 512 Bytes
195 // which are not relevant in a MAC-PICT (they are not evaluated)
196 return SwWW8ImplReader::GetPictGrafFromStream(rGraph, *pStp);
199 SwFlyFrameFormat* SwWW8ImplReader::InsertOle(SdrOle2Obj &rObject,
200 const SfxItemSet &rFlySet, const SfxItemSet *rGrfSet)
202 SfxObjectShell *pPersist = m_rDoc.GetPersist();
203 OSL_ENSURE(pPersist, "No persist, cannot insert objects correctly");
204 if (!pPersist)
205 return nullptr;
207 SwFlyFrameFormat *pRet = nullptr;
209 SfxItemSet *pMathFlySet = nullptr;
210 uno::Reference < embed::XClassifiedObject > xClass( rObject.GetObjRef(), uno::UNO_QUERY );
211 if( xClass.is() )
213 SvGlobalName aClassName( xClass->getClassID() );
214 if (SotExchange::IsMath(aClassName))
216 // StarMath sets it own fixed size, so its counter productive to use
217 // the size word says it is. i.e. Don't attempt to override its size.
218 pMathFlySet = new SfxItemSet(rFlySet);
219 pMathFlySet->ClearItem(RES_FRM_SIZE);
224 Take complete responsibility of the object away from SdrOle2Obj and to
225 me here locally. This utility class now owns the object.
228 // TODO/MBA: is the object inserted multiple times here? Testing!
229 // And is it a problem that we now use the same naming scheme as in the other apps?
230 sw::hack::DrawingOLEAdaptor aOLEObj(rObject, *pPersist);
231 OUString sNewName;
232 bool bSuccess = aOLEObj.TransferToDoc(sNewName);
234 OSL_ENSURE(bSuccess, "Insert OLE failed");
235 if (bSuccess)
237 const SfxItemSet *pFlySet = pMathFlySet ? pMathFlySet : &rFlySet;
238 pRet = m_rDoc.getIDocumentContentOperations().InsertOLE(*m_pPaM, sNewName, rObject.GetAspect(), pFlySet, rGrfSet);
240 delete pMathFlySet;
241 return pRet;
244 SwFrameFormat* SwWW8ImplReader::ImportOle(const Graphic* pGrf,
245 const SfxItemSet* pFlySet, const SfxItemSet *pGrfSet, const Rectangle& aVisArea )
247 ::SetProgressState(m_nProgress, m_pDocShell); // Update
248 SwFrameFormat* pFormat = nullptr;
250 GrafikCtor();
252 Graphic aGraph;
253 SdrObject* pRet = ImportOleBase(aGraph, pGrf, pFlySet, aVisArea );
255 // create flyset
256 SfxItemSet* pTempSet = nullptr;
257 if( !pFlySet )
259 pTempSet = new SfxItemSet( m_rDoc.GetAttrPool(), RES_FRMATR_BEGIN,
260 RES_FRMATR_END-1);
262 pFlySet = pTempSet;
264 // Remove distance/borders
265 if (!m_bNewDoc)
266 Reader::ResetFrameFormatAttrs( *pTempSet );
268 SwFormatAnchor aAnchor( FLY_AS_CHAR );
269 aAnchor.SetAnchor( m_pPaM->GetPoint() );
270 pTempSet->Put( aAnchor );
272 const Size aSizeTwip = OutputDevice::LogicToLogic(
273 aGraph.GetPrefSize(), aGraph.GetPrefMapMode(), MapUnit::MapTwip );
275 pTempSet->Put( SwFormatFrameSize( ATT_FIX_SIZE, aSizeTwip.Width(),
276 aSizeTwip.Height() ) );
277 pTempSet->Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
279 if( m_pSFlyPara )
281 // Resize the frame to the picture size if there is an OLE object
282 // in the frame (only if auto-width)
283 m_pSFlyPara->BoxUpWidth( aSizeTwip.Width() );
287 if (pRet) // OLE object was inserted
289 if (dynamic_cast< const SdrOle2Obj *>( pRet ) != nullptr)
291 pFormat = InsertOle(*static_cast<SdrOle2Obj*>(pRet), *pFlySet, pGrfSet);
292 SdrObject::Free( pRet ); // we don't need this anymore
294 else
295 pFormat = m_rDoc.getIDocumentContentOperations().InsertDrawObj(*m_pPaM, *pRet, *pFlySet );
297 else if (
298 GraphicType::GdiMetafile == aGraph.GetType() ||
299 GraphicType::Bitmap == aGraph.GetType()
302 pFormat = m_rDoc.getIDocumentContentOperations().Insert(*m_pPaM, OUString(), OUString(), &aGraph, pFlySet,
303 pGrfSet, nullptr);
305 delete pTempSet;
306 return pFormat;
309 bool SwWW8ImplReader::ImportOleWMF(tools::SvRef<SotStorage> xSrc1,GDIMetaFile &rWMF,
310 long &rX,long &rY)
312 bool bOk = false;
313 OLE_MFP aMfp;
314 if( SwWw6ReadMetaStream( rWMF, &aMfp, xSrc1 ) )
316 // take scaling factor as found in PIC and apply it to graphic.
317 SwWw8ReadScaling( rX, rY, xSrc1 );
318 Size aFinalSize, aOrigSize;
319 aFinalSize.Width() = rX;
320 aFinalSize.Height() = rY;
321 aFinalSize = OutputDevice::LogicToLogic(
322 aFinalSize, MapUnit::MapTwip, rWMF.GetPrefMapMode() );
323 aOrigSize = rWMF.GetPrefSize();
324 Fraction aScaleX(aFinalSize.Width(),aOrigSize.Width());
325 Fraction aScaleY(aFinalSize.Height(),aOrigSize.Height());
326 rWMF.Scale( aScaleX, aScaleY );
327 bOk = true;
329 return bOk;
332 SdrObject* SwWW8ImplReader::ImportOleBase( Graphic& rGraph,
333 const Graphic* pGrf, const SfxItemSet* pFlySet, const Rectangle& aVisArea )
335 if (!m_pStg)
337 SAL_WARN("sw.ww8", "no storage for ole objects");
338 return nullptr;
341 ::SetProgressState( m_nProgress, m_rDoc.GetDocShell() ); // Update
343 long nX=0, nY=0; // nX, nY is graphic size
344 bool bOleOk = true;
346 OUString aSrcStgName('_');
347 // results in the name "_4711"
348 aSrcStgName += OUString::number( m_nObjLocFc );
350 tools::SvRef<SotStorage> xSrc0 = m_pStg->OpenSotStorage(OUString(SL::aObjectPool));
351 tools::SvRef<SotStorage> xSrc1 = xSrc0->OpenSotStorage( aSrcStgName );
353 if (pGrf)
355 rGraph = *pGrf;
356 const Size aSizeTwip = OutputDevice::LogicToLogic(
357 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapUnit::MapTwip );
358 nX = aSizeTwip.Width();
359 nY = aSizeTwip.Height();
361 else
363 GDIMetaFile aWMF;
365 if (ImportOleWMF(xSrc1,aWMF,nX,nY))
366 rGraph = Graphic( aWMF );
367 else if( SwWw6ReadMacPICTStream( rGraph, xSrc1 ) )
369 // 03-META stream is not available. Maybe it's a 03-PICT?
370 const Size aSizeTwip = OutputDevice::LogicToLogic(
371 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapUnit::MapTwip );
372 nX = aSizeTwip.Width();
373 nY = aSizeTwip.Height();
374 // PICT: no WMF available -> Graphic instead of OLE
375 bOleOk = false;
377 } // StorageStreams closed again
379 Rectangle aRect(0, 0, nX, nY);
381 if (pFlySet)
383 if (const SwFormatFrameSize* pSize =
384 static_cast<const SwFormatFrameSize*>(pFlySet->GetItem(RES_FRM_SIZE, false)))
386 aRect.SetSize(pSize->GetSize());
390 SdrObject* pRet = nullptr;
392 if (!(m_bIsHeader || m_bIsFooter))
394 //Can't put them in headers/footers :-(
395 uno::Reference< drawing::XShape > xRef;
396 OSL_ENSURE(m_pFormImpl, "Impossible");
397 if (m_pFormImpl && m_pFormImpl->ReadOCXStream(xSrc1, &xRef))
399 pRet = GetSdrObjectFromXShape(xRef);
400 OSL_ENSURE(pRet, "Impossible");
401 if (pRet)
402 pRet->SetLogicRect(aRect);
403 return pRet;
407 if (GraphicType::GdiMetafile == rGraph.GetType() ||
408 GraphicType::Bitmap == rGraph.GetType())
410 ::SetProgressState(m_nProgress, m_pDocShell); // Update
412 if (bOleOk)
414 sal_uLong nOldPos = m_pDataStream->Tell();
415 m_pDataStream->Seek(STREAM_SEEK_TO_END);
416 SvStream *pTmpData = nullptr;
417 if (m_nObjLocFc < m_pDataStream->Tell())
419 pTmpData = m_pDataStream;
420 pTmpData->Seek( m_nObjLocFc );
423 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
426 tools::SvRef<SotStorageStream> xObjInfoSrc = xSrc1->OpenSotStream("\3ObjInfo",
427 StreamMode::STD_READ );
428 if ( xObjInfoSrc.Is() && !xObjInfoSrc->GetError() )
430 sal_uInt8 nByte = 0;
431 xObjInfoSrc->ReadUChar( nByte );
432 if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
433 nAspect = embed::Aspects::MSOLE_ICON;
437 ErrCode nError = ERRCODE_NONE;
438 pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
439 aSrcStgName, xSrc0, m_pDocShell->GetStorage(), rGraph, aRect, aVisArea, pTmpData, nError,
440 SwMSDffManager::GetFilterFlags(), nAspect, GetBaseURL());
441 m_pDataStream->Seek( nOldPos );
444 return pRet;
447 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream& rStrm,
448 sal_Int32 nTablePos, sal_Int32 nTableSiz, SwDoc& rDocOut )
450 std::vector<OUString> aAuthorNames;
451 WW8ReadSTTBF( !m_bVer67, rStrm, nTablePos, nTableSiz, m_bVer67 ? 2 : 0,
452 m_eStructCharSet, aAuthorNames );
454 sal_uInt16 nCount = static_cast< sal_uInt16 >(aAuthorNames.size());
455 for( sal_uInt16 nAuthor = 0; nAuthor < nCount; ++nAuthor )
457 // Store author in doc
458 sal_uInt16 nSWId = rDocOut.getIDocumentRedlineAccess().InsertRedlineAuthor(aAuthorNames[nAuthor]);
459 // Store matchpair
460 m_aAuthorInfos[nAuthor] = nSWId;
465 Revision Marks ( == Redlining )
467 // insert or delete content (change char attributes resp.)
468 void SwWW8ImplReader::Read_CRevisionMark(RedlineType_t eType,
469 const sal_uInt8* pData, short nLen )
471 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
472 // pointing to the very same char position as our SprmCFRMark[Del]
473 if (!m_pPlcxMan)
474 return;
475 const sal_uInt8* pSprmCIbstRMark;
476 const sal_uInt8* pSprmCDttmRMark;
477 if( nsRedlineType_t::REDLINE_FORMAT == eType )
479 pSprmCIbstRMark = nLen >= 3 ? pData+1 : nullptr;
480 pSprmCDttmRMark = nLen >= 7 ? pData+3 : nullptr;
482 else
484 /* It is possible to have a number of date stamps for the created time
485 * of the change, (possibly a word bug) so we must use the "get a full
486 * list" variant of HasCharSprm and take the last one as the true one.
488 std::vector<const sal_uInt8 *> aResult;
489 bool bIns = (nsRedlineType_t::REDLINE_INSERT == eType);
490 if( m_bVer67 )
492 m_pPlcxMan->HasCharSprm(69, aResult);
493 pSprmCIbstRMark = aResult.empty() ? nullptr : aResult.back();
494 aResult.clear();
495 m_pPlcxMan->HasCharSprm(70, aResult);
496 pSprmCDttmRMark = aResult.empty() ? nullptr : aResult.back();
498 else
500 m_pPlcxMan->HasCharSprm( bIns ? 0x4804 : 0x4863, aResult);
501 pSprmCIbstRMark = aResult.empty() ? nullptr : aResult.back();
502 aResult.clear();
503 m_pPlcxMan->HasCharSprm( bIns ? 0x6805 : NS_sprm::LN_CDttmRMarkDel, aResult);
504 pSprmCDttmRMark = aResult.empty() ? nullptr : aResult.back();
508 if (nLen < 0)
509 m_pRedlineStack->close(*m_pPaM->GetPoint(), eType, m_pTableDesc );
510 else
512 // start of new revision mark, if not there default to first entry
513 sal_uInt16 nWWAutNo = pSprmCIbstRMark ? SVBT16ToShort(pSprmCIbstRMark) : 0;
514 sal_uInt32 nWWDate = pSprmCDttmRMark ? SVBT32ToUInt32(pSprmCDttmRMark): 0;
515 DateTime aStamp(msfilter::util::DTTM2DateTime(nWWDate));
516 sal_uInt16 nAuthorNo = m_aAuthorInfos[nWWAutNo];
517 SwFltRedline aNewAttr(eType, nAuthorNo, aStamp);
518 NewAttr(aNewAttr);
522 // insert new content
523 void SwWW8ImplReader::Read_CFRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
525 Read_CRevisionMark( nsRedlineType_t::REDLINE_INSERT, pData, nLen );
528 // delete old content
529 void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16 , const sal_uInt8* pData, short nLen)
531 Read_CRevisionMark( nsRedlineType_t::REDLINE_DELETE, pData, nLen );
534 // change properties of content ( == char formatting)
535 void SwWW8ImplReader::Read_CPropRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
537 // complex (len is always 7)
538 // 1 byte - chp.fPropRMark
539 // 2 bytes - chp.ibstPropRMark
540 // 4 bytes - chp.dttmPropRMark;
541 Read_CRevisionMark( nsRedlineType_t::REDLINE_FORMAT, pData, nLen );
544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */