nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / filter / ww8 / ww8par4.cxx
blob1c5bc2a09b6cac1cf4cf1d805fd8f6e48e750662
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 <svx/unoapi.hxx>
35 #include <sal/log.hxx>
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 );
86 pS->Seek( STREAM_SEEK_TO_END );
88 OSL_ENSURE( pS->Tell() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
90 sal_Int32 nOrgWidth,
91 nOrgHeight,
92 nScaleX,
93 nScaleY,
94 nCropLeft,
95 nCropTop,
96 nCropRight,
97 nCropBottom;
98 pS->Seek( 0x14 );
99 pS->ReadInt32( nOrgWidth ) // Original Size in 1/100 mm
100 .ReadInt32( nOrgHeight );
101 pS->Seek( 0x2c );
102 pS->ReadInt32( nScaleX ) // Scaling in Promille
103 .ReadInt32( nScaleY )
104 .ReadInt32( nCropLeft ) // Cropping in 1/100 mm
105 .ReadInt32( nCropTop )
106 .ReadInt32( nCropRight )
107 .ReadInt32( nCropBottom );
109 rX = nOrgWidth - nCropLeft - nCropRight;
110 rY = nOrgHeight - nCropTop - nCropBottom;
111 if (10 > nScaleX || 65536 < nScaleX || 10 > nScaleY || 65536 < nScaleY)
113 OSL_ENSURE( !pS, "+OLE-scaling information in PIC-stream wrong" );
114 return false;
116 else
118 rX = (rX * nScaleX) / 1000;
119 rY = (rY * nScaleY) / 1000;
121 return true;
124 static bool SwWw6ReadMetaStream(GDIMetaFile& rWMF, OLE_MFP* pMfp,
125 tools::SvRef<SotStorage> const & rSrc1)
127 tools::SvRef<SotStorageStream> xSrc2 = rSrc1->OpenSotStream( "\3META",
128 StreamMode::STD_READ );
129 SotStorageStream* pSt = xSrc2.get();
130 pSt->SetEndian( SvStreamEndian::LITTLE );
131 size_t const nRead = pSt->ReadBytes(pMfp, sizeof(*pMfp));
132 // read mini-placable-header
133 if (nRead != sizeof(*pMfp))
134 return false;
136 #if defined OSL_BIGENDIAN
137 pMfp->mm = OSL_SWAPWORD( pMfp->mm );
138 pMfp->xExt = OSL_SWAPWORD( pMfp->xExt );
139 pMfp->yExt = OSL_SWAPWORD( pMfp->yExt );
140 #endif // OSL_BIGENDIAN
142 if( pMfp->mm == 94 || pMfp->mm == 99 )
144 SAL_WARN("sw.ww8", "+OLE: wrong metafile type");
145 return false;
147 if( pMfp->mm != 8 )
149 SAL_WARN("sw.ww8", "OLE: wrong mMetafile type (not anisotropic)");
151 if( !pMfp->xExt || !pMfp->yExt )
153 SAL_WARN("sw.ww8", "+OLE: size of 0?");
154 return false;
156 bool bOk = ReadWindowMetafile( *pSt, rWMF ); // read WMF
157 // *pSt >> aWMF doesn't work without the placable header
158 if (!bOk || pSt->GetError() || rWMF.GetActionSize() == 0)
160 SAL_WARN("sw.ww8", "+OLE: could not read the metafile");
161 return false;
164 rWMF.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
166 // Scale MetaFile to new size and save new size to MetaFile
167 Size aOldSiz( rWMF.GetPrefSize() );
168 Size aNewSiz( pMfp->xExt, pMfp->yExt );
169 Fraction aFracX( aNewSiz.Width(), aOldSiz.Width() );
170 Fraction aFracY( aNewSiz.Height(), aOldSiz.Height() );
172 rWMF.Scale( aFracX, aFracY );
173 rWMF.SetPrefSize( aNewSiz );
175 return true;
178 static bool SwWw6ReadMacPICTStream(Graphic& rGraph, tools::SvRef<SotStorage> const & rSrc1)
180 // 03-META-stream does not exist. Maybe a 03-PICT?
181 tools::SvRef<SotStorageStream> xSrc4 = rSrc1->OpenSotStream("\3PICT");
182 SotStorageStream* pStp = xSrc4.get();
183 pStp->SetEndian( SvStreamEndian::LITTLE );
184 sal_uInt8 aTestA[10]; // Does the 01Ole-stream even exist?
185 size_t const nReadTst = pStp->ReadBytes(aTestA, sizeof(aTestA));
186 if (nReadTst != sizeof(aTestA))
187 return false;
189 pStp->Seek( STREAM_SEEK_TO_BEGIN );
191 // Mac-Pict is in the 03PICT-StorageStream but without the first 512 Bytes
192 // which are not relevant in a MAC-PICT (they are not evaluated)
193 return SwWW8ImplReader::GetPictGrafFromStream(rGraph, *pStp);
196 SwFlyFrameFormat* SwWW8ImplReader::InsertOle(SdrOle2Obj &rObject,
197 const SfxItemSet &rFlySet, const SfxItemSet *rGrfSet)
199 SfxObjectShell *pPersist = m_rDoc.GetPersist();
200 OSL_ENSURE(pPersist, "No persist, cannot insert objects correctly");
201 if (!pPersist)
202 return nullptr;
204 SwFlyFrameFormat *pRet = nullptr;
206 std::unique_ptr<SfxItemSet> pMathFlySet;
207 uno::Reference < embed::XClassifiedObject > xClass = rObject.GetObjRef();
208 if( xClass.is() )
210 SvGlobalName aClassName( xClass->getClassID() );
211 if (SotExchange::IsMath(aClassName))
213 // StarMath sets it own fixed size, so its counter productive to use
214 // the size Word says it is. i.e. Don't attempt to override its size.
215 pMathFlySet.reset(new SfxItemSet(rFlySet));
216 pMathFlySet->ClearItem(RES_FRM_SIZE);
221 Take complete responsibility of the object away from SdrOle2Obj and to
222 me here locally. This utility class now owns the object.
225 // TODO/MBA: is the object inserted multiple times here? Testing!
226 // And is it a problem that we now use the same naming scheme as in the other apps?
227 sw::hack::DrawingOLEAdaptor aOLEObj(rObject, *pPersist);
228 OUString sNewName;
229 bool bSuccess = aOLEObj.TransferToDoc(sNewName);
231 OSL_ENSURE(bSuccess, "Insert OLE failed");
232 if (bSuccess)
234 const SfxItemSet *pFlySet = pMathFlySet ? pMathFlySet.get() : &rFlySet;
235 pRet = m_rDoc.getIDocumentContentOperations().InsertOLE(*m_pPaM, sNewName, rObject.GetAspect(), pFlySet, rGrfSet);
237 return pRet;
240 SwFrameFormat* SwWW8ImplReader::ImportOle(const Graphic* pGrf,
241 const SfxItemSet* pFlySet, const SfxItemSet *pGrfSet, const tools::Rectangle& aVisArea )
243 ::SetProgressState(m_nProgress, m_pDocShell); // Update
244 SwFrameFormat* pFormat = nullptr;
246 GrafikCtor();
248 Graphic aGraph;
249 SdrObject* pRet = ImportOleBase(aGraph, pGrf, pFlySet, aVisArea );
251 // create flyset
252 std::unique_ptr<SfxItemSet> pTempSet;
253 if( !pFlySet )
255 pTempSet.reset( new SfxItemSet( m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN,
256 RES_FRMATR_END-1>{}) );
258 pFlySet = pTempSet.get();
260 // Remove distance/borders
261 Reader::ResetFrameFormatAttrs( *pTempSet );
263 SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR );
264 aAnchor.SetAnchor( m_pPaM->GetPoint() );
265 pTempSet->Put( aAnchor );
267 const Size aSizeTwip = OutputDevice::LogicToLogic(
268 aGraph.GetPrefSize(), aGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
270 pTempSet->Put( SwFormatFrameSize( SwFrameSize::Fixed, aSizeTwip.Width(),
271 aSizeTwip.Height() ) );
272 pTempSet->Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
274 if (m_xSFlyPara)
276 // Resize the frame to the picture size if there is an OLE object
277 // in the frame (only if auto-width)
278 m_xSFlyPara->BoxUpWidth(aSizeTwip.Width());
282 if (pRet) // OLE object was inserted
284 if (SdrOle2Obj *pOleObj = dynamic_cast<SdrOle2Obj*>(pRet))
286 pFormat = InsertOle(*pOleObj, *pFlySet, pGrfSet);
287 SdrObject::Free(pRet); // we don't need this anymore
289 else
290 pFormat = m_rDoc.getIDocumentContentOperations().InsertDrawObj(*m_pPaM, *pRet, *pFlySet );
292 else if (
293 GraphicType::GdiMetafile == aGraph.GetType() ||
294 GraphicType::Bitmap == aGraph.GetType()
297 pFormat = m_rDoc.getIDocumentContentOperations().InsertGraphic(
298 *m_pPaM, OUString(), OUString(), &aGraph, pFlySet,
299 pGrfSet, nullptr);
301 return pFormat;
304 bool SwWW8ImplReader::ImportOleWMF(const tools::SvRef<SotStorage>& xSrc1, GDIMetaFile& rWMF,
305 tools::Long& rX, tools::Long& rY)
307 bool bOk = false;
308 OLE_MFP aMfp;
309 if( SwWw6ReadMetaStream( rWMF, &aMfp, xSrc1 ) )
311 // take scaling factor as found in PIC and apply it to graphic.
312 SwWw8ReadScaling( rX, rY, xSrc1 );
313 Size aFinalSize, aOrigSize;
314 aFinalSize.setWidth( rX );
315 aFinalSize.setHeight( rY );
316 aFinalSize = OutputDevice::LogicToLogic(
317 aFinalSize, MapMode(MapUnit::MapTwip), rWMF.GetPrefMapMode() );
318 aOrigSize = rWMF.GetPrefSize();
319 Fraction aScaleX(aFinalSize.Width(),aOrigSize.Width());
320 Fraction aScaleY(aFinalSize.Height(),aOrigSize.Height());
321 rWMF.Scale( aScaleX, aScaleY );
322 bOk = true;
324 return bOk;
327 SdrObject* SwWW8ImplReader::ImportOleBase( Graphic& rGraph,
328 const Graphic* pGrf, const SfxItemSet* pFlySet, const tools::Rectangle& aVisArea )
330 if (!m_pStg)
332 SAL_WARN("sw.ww8", "no storage for ole objects");
333 return nullptr;
336 ::SetProgressState( m_nProgress, m_rDoc.GetDocShell() ); // Update
338 tools::Long nX=0, nY=0; // nX, nY is graphic size
339 bool bOleOk = true;
341 // results in the name "_4711"
342 OUString aSrcStgName = "_" + OUString::number( m_nObjLocFc );
344 tools::SvRef<SotStorage> xSrc0 = m_pStg->OpenSotStorage(SL::aObjectPool);
345 tools::SvRef<SotStorage> xSrc1 = xSrc0->OpenSotStorage( aSrcStgName );
347 if (pGrf)
349 rGraph = *pGrf;
350 const Size aSizeTwip = OutputDevice::LogicToLogic(
351 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
352 nX = aSizeTwip.Width();
353 nY = aSizeTwip.Height();
355 else
357 GDIMetaFile aWMF;
359 if (ImportOleWMF(xSrc1,aWMF,nX,nY))
360 rGraph = Graphic( aWMF );
361 else if( SwWw6ReadMacPICTStream( rGraph, xSrc1 ) )
363 // 03-META stream is not available. Maybe it's a 03-PICT?
364 const Size aSizeTwip = OutputDevice::LogicToLogic(
365 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
366 nX = aSizeTwip.Width();
367 nY = aSizeTwip.Height();
368 // PICT: no WMF available -> Graphic instead of OLE
369 bOleOk = false;
371 } // StorageStreams closed again
373 tools::Rectangle aRect(0, 0, nX, nY);
375 if (pFlySet)
377 if (const SwFormatFrameSize* pSize = pFlySet->GetItem<SwFormatFrameSize>(RES_FRM_SIZE, false))
379 aRect.SetSize(pSize->GetSize());
383 SdrObject* pRet = nullptr;
385 if (!(m_bIsHeader || m_bIsFooter))
387 //Can't put them in headers/footers :-(
388 uno::Reference< drawing::XShape > xRef;
389 OSL_ENSURE(m_xFormImpl, "Impossible");
390 if (m_xFormImpl && m_xFormImpl->ReadOCXStream(xSrc1, &xRef))
392 pRet = GetSdrObjectFromXShape(xRef);
393 OSL_ENSURE(pRet, "Impossible");
394 if (pRet)
395 pRet->SetLogicRect(aRect);
396 return pRet;
400 if (GraphicType::GdiMetafile == rGraph.GetType() ||
401 GraphicType::Bitmap == rGraph.GetType())
403 ::SetProgressState(m_nProgress, m_pDocShell); // Update
405 if (bOleOk)
407 sal_uLong nOldPos = m_pDataStream->Tell();
408 m_pDataStream->Seek(STREAM_SEEK_TO_END);
409 SvStream *pTmpData = nullptr;
410 if (m_nObjLocFc < m_pDataStream->Tell())
412 pTmpData = m_pDataStream;
413 pTmpData->Seek( m_nObjLocFc );
416 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
419 tools::SvRef<SotStorageStream> xObjInfoSrc = xSrc1->OpenSotStream("\3ObjInfo",
420 StreamMode::STD_READ );
421 if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
423 sal_uInt8 nByte = 0;
424 xObjInfoSrc->ReadUChar( nByte );
425 if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
426 nAspect = embed::Aspects::MSOLE_ICON;
430 ErrCode nError = ERRCODE_NONE;
431 GrafikCtor();
433 pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
434 *m_pDrawModel,
435 aSrcStgName,
436 xSrc0,
437 m_pDocShell->GetStorage(),
438 rGraph,
439 aRect,
440 aVisArea,
441 pTmpData,
442 nError,
443 SwMSDffManager::GetFilterFlags(),
444 nAspect,
445 GetBaseURL());
446 m_pDataStream->Seek( nOldPos );
449 return pRet;
452 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream& rStrm,
453 sal_Int32 nTablePos, sal_Int32 nTableSiz, SwDoc& rDocOut )
455 std::vector<OUString> aAuthorNames;
456 WW8ReadSTTBF( !m_bVer67, rStrm, nTablePos, nTableSiz, m_bVer67 ? 2 : 0,
457 m_eStructCharSet, aAuthorNames );
459 sal_uInt16 nCount = static_cast< sal_uInt16 >(aAuthorNames.size());
460 for( sal_uInt16 nAuthor = 0; nAuthor < nCount; ++nAuthor )
462 // Store author in doc
463 std::size_t nSWId = rDocOut.getIDocumentRedlineAccess().InsertRedlineAuthor(aAuthorNames[nAuthor]);
464 // Store matchpair
465 m_aAuthorInfos[nAuthor] = nSWId;
470 Revision Marks ( == Redlining )
472 // insert or delete content (change char attributes resp.)
473 void SwWW8ImplReader::Read_CRevisionMark(RedlineType eType,
474 const sal_uInt8* pData, short nLen )
476 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
477 // pointing to the very same char position as our SprmCFRMark[Del]
478 if (!m_xPlcxMan)
479 return;
480 const sal_uInt8* pSprmCIbstRMark;
481 const sal_uInt8* pSprmCDttmRMark;
482 if( RedlineType::Format == eType )
484 pSprmCIbstRMark = nLen >= 3 ? pData+1 : nullptr;
485 pSprmCDttmRMark = nLen >= 7 ? pData+3 : nullptr;
487 else
489 /* It is possible to have a number of date stamps for the created time
490 * of the change, (possibly a word bug) so we must use the "get a full
491 * list" variant of HasCharSprm and take the last one as the true one.
493 std::vector<SprmResult> aResult;
494 bool bIns = (RedlineType::Insert == eType);
495 if( m_bVer67 )
497 m_xPlcxMan->HasCharSprm(69, aResult);
498 pSprmCIbstRMark = (aResult.empty() || aResult.back().nRemainingData < 2) ? nullptr : aResult.back().pSprm;
499 aResult.clear();
500 m_xPlcxMan->HasCharSprm(70, aResult);
501 pSprmCDttmRMark = (aResult.empty() || aResult.back().nRemainingData < 4) ? nullptr : aResult.back().pSprm;
503 else
505 m_xPlcxMan->HasCharSprm( bIns ? 0x4804 : 0x4863, aResult);
506 pSprmCIbstRMark = (aResult.empty() || aResult.back().nRemainingData < 2) ? nullptr : aResult.back().pSprm;
507 aResult.clear();
508 m_xPlcxMan->HasCharSprm( bIns ? 0x6805 : NS_sprm::CDttmRMarkDel::val, aResult);
509 pSprmCDttmRMark = (aResult.empty() || aResult.back().nRemainingData < 4) ? nullptr : aResult.back().pSprm;
513 if (nLen < 0)
514 m_xRedlineStack->close(*m_pPaM->GetPoint(), eType, m_xTableDesc.get());
515 else
517 // start of new revision mark, if not there default to first entry
518 sal_uInt16 nWWAutNo = pSprmCIbstRMark ? SVBT16ToUInt16(pSprmCIbstRMark) : 0;
519 sal_uInt32 nWWDate = pSprmCDttmRMark ? SVBT32ToUInt32(pSprmCDttmRMark): 0;
520 DateTime aStamp(msfilter::util::DTTM2DateTime(nWWDate));
521 std::size_t nAuthorNo = m_aAuthorInfos[nWWAutNo];
522 SwFltRedline aNewAttr(eType, nAuthorNo, aStamp);
523 NewAttr(aNewAttr);
527 // insert new content
528 void SwWW8ImplReader::Read_CFRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
530 Read_CRevisionMark( RedlineType::Insert, pData, nLen );
533 // delete old content
534 void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16 , const sal_uInt8* pData, short nLen)
536 Read_CRevisionMark( RedlineType::Delete, pData, nLen );
539 // change properties of content ( == char formatting)
540 void SwWW8ImplReader::Read_CPropRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
542 // complex (len is always 7)
543 // 1 byte - chp.fPropRMark
544 // 2 bytes - chp.ibstPropRMark
545 // 4 bytes - chp.dttmPropRMark;
546 Read_CRevisionMark( RedlineType::Format, pData, nLen );
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */