bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / ww8par4.cxx
blob7aa31b67d17de1787fbf5e4f82116337576c6446
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 "writerhelper.hxx"
22 #include <com/sun/star/embed/XClassifiedObject.hpp>
23 #include <com/sun/star/embed/Aspects.hpp>
25 #include <algorithm>
26 #include <functional>
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 <svx/unoapi.hxx>
35 #include <sot/exchange.hxx>
36 #include <swtypes.hxx>
37 #include <fmtanchr.hxx>
38 #include <fmtcntnt.hxx>
39 #include <dcontact.hxx>
40 #include <frmfmt.hxx>
41 #include <pam.hxx>
42 #include <ndgrf.hxx>
43 #include <docsh.hxx> // fuer Ole-Node
44 #include <mdiexp.hxx> // Progress
45 #include <redline.hxx>
46 #include <fltshell.hxx>
47 #include <unodraw.hxx>
48 #include <shellio.hxx>
49 #include <ndole.hxx>
51 #include <vcl/graphicfilter.hxx>
52 #include <vcl/wmf.hxx>
54 #include "ww8scan.hxx"
55 #include "ww8par.hxx"
56 #include "ww8par2.hxx" // WWFlyPara::BoxUpWidth()
58 struct OLE_MFP
60 sal_Int16 mm; // 0x6 int
61 sal_Int16 xExt; // 0x8 int in 1/100 mm
62 sal_Int16 yExt; // 0xa int in 1/100 mm
63 sal_Int16 hMF; // 0xc int
66 using namespace ::com::sun::star;
68 static bool SwWw8ReadScaling(long& rX, long& rY, SvStorageRef& rSrc1)
70 // Skalierungsfaktoren holen:
71 // Informationen in PIC-Stream ( durch ausprobieren )
72 // 0x0 (l)cb
73 // 0x08 .. 0x0a Flags ??
74 // 0x08 Inh: 1 / 0
75 // 0x09 Inh: 0,8,0x18
76 // 0x0a Inh: immer 8, MAP_ANISOTROPIC ???
77 // 0x0b Inh: immer 0
78 // 0x0c, 0x10 Originalgroesse x,y in 1/100 mm
79 // 0x14, 0x16 Originalgroesse x,y in tw
80 // 0x2c, 0x30 Skalierung x,y in Promille
81 // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
83 SvStorageStreamRef xSrc3 = rSrc1->OpenSotStream( OUString("\3PIC"),
84 STREAM_STD_READ | STREAM_NOCREATE);
85 SvStorageStream* pS = xSrc3;
86 pS->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
87 pS->Seek( STREAM_SEEK_TO_END );
89 OSL_ENSURE( pS->Tell() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
91 sal_Int32 nOrgWidth,
92 nOrgHeight,
93 nScaleX,
94 nScaleY,
95 nCropLeft,
96 nCropTop,
97 nCropRight,
98 nCropBottom;
99 pS->Seek( 0x14 );
100 *pS >> nOrgWidth // Original Size in 1/100 mm
101 >> nOrgHeight;
102 pS->Seek( 0x2c );
103 *pS >> nScaleX // Scaling in Promille
104 >> nScaleY
105 >> nCropLeft // Cropping in 1/100 mm
106 >> nCropTop
107 >> nCropRight
108 >> nCropBottom;
110 rX = nOrgWidth - nCropLeft - nCropRight;
111 rY = nOrgHeight - nCropTop - nCropBottom;
112 if (10 > nScaleX || 65536 < nScaleX || 10 > nScaleY || 65536 < nScaleY)
114 OSL_ENSURE( !pS, "+OLE-Scalinginformation in PIC-Stream wrong" );
115 return false;
117 else
119 rX = (rX * nScaleX) / 1000;
120 rY = (rY * nScaleY) / 1000;
122 return true;
125 static bool SwWw6ReadMetaStream(GDIMetaFile& rWMF, OLE_MFP* pMfp,
126 SvStorageRef& rSrc1)
128 SvStorageStreamRef xSrc2 = rSrc1->OpenSotStream( OUString("\3META"),
129 STREAM_STD_READ | STREAM_NOCREATE);
130 SvStorageStream* pSt = xSrc2;
131 pSt->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
132 sal_uLong nRead = pSt->Read( pMfp, sizeof(*pMfp ) );
133 // Mini-Placable-Header lesen
134 if (nRead != sizeof(*pMfp))
135 return false;
137 #if defined OSL_BIGENDIAN
138 pMfp->mm = OSL_SWAPWORD( pMfp->mm );
139 pMfp->xExt = OSL_SWAPWORD( pMfp->xExt );
140 pMfp->yExt = OSL_SWAPWORD( pMfp->yExt );
141 #endif // OSL_BIGENDIAN
143 if( pMfp->mm == 94 || pMfp->mm == 99 )
145 OSL_ENSURE( !pSt, "+OLE: Falscher Metafile-Typ" );
146 return false;
148 if( pMfp->mm != 8 )
150 OSL_ENSURE( !pSt, "+OLE: Falscher Metafile-Typ ( nicht Anisotropic )" );
152 if( !pMfp->xExt || !pMfp->yExt )
154 OSL_ENSURE( !pSt, "+OLE: Groesse von 0 ???" );
155 return false;
157 bool bOk = ReadWindowMetafile( *pSt, rWMF, NULL ) ? true : false; // WMF lesen
158 // *pSt >> aWMF geht nicht ohne placable Header
159 if (!bOk || pSt->GetError() || rWMF.GetActionSize() == 0)
161 OSL_ENSURE( !pSt, "+OLE: Konnte Metafile nicht lesen" );
162 return false;
165 rWMF.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
168 // MetaFile auf neue Groesse skalieren und
169 // neue Groesse am MetaFile setzen
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, SvStorageRef& rSrc1)
183 // 03-META-Stream nicht da. Vielleicht ein 03-PICT ?
184 SvStorageStreamRef xSrc4 = rSrc1->OpenSotStream(OUString("\3PICT"));
185 SvStorageStream* pStp = xSrc4;
186 pStp->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
187 sal_uInt8 aTestA[10]; // Ist der 01Ole-Stream ueberhaupt vorhanden
188 sal_uLong nReadTst = pStp->Read( aTestA, sizeof( aTestA ) );
189 if (nReadTst != sizeof(aTestA))
190 return false;
192 pStp->Seek( STREAM_SEEK_TO_BEGIN );
194 // Mac-Pict steht im 03PICT-StorageStream allerdings ohne die ersten 512
195 // Bytes, die bei einem MAC-PICT egal sind ( werden nicht ausgewertet )
196 return SwWW8ImplReader::GetPictGrafFromStream(rGraph, *pStp);
199 SwFlyFrmFmt* SwWW8ImplReader::InsertOle(SdrOle2Obj &rObject,
200 const SfxItemSet &rFlySet, const SfxItemSet &rGrfSet)
202 SfxObjectShell *pPersist = rDoc.GetPersist();
203 OSL_ENSURE(pPersist, "No persist, cannot insert objects correctly");
204 if (!pPersist)
205 return 0;
207 SwFlyFrmFmt *pRet = 0;
209 SfxItemSet *pMathFlySet = 0;
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))
217 StarMath sets it own fixed size, so its counter productive to use the
218 size word says it is. i.e. Don't attempt to override its size.
220 pMathFlySet = new SfxItemSet(rFlySet);
221 pMathFlySet->ClearItem(RES_FRM_SIZE);
226 Take complete responsibility of the object away from SdrOle2Obj and to
227 me here locally. This utility class now owns the object.
230 // TODO/MBA: is the object inserted multiple times here? Testing!
231 // And is it a problem that we now use the same naming scheme as in the other apps?
232 sw::hack::DrawingOLEAdaptor aOLEObj(rObject, *pPersist);
233 OUString sNewName;
234 bool bSuccess = aOLEObj.TransferToDoc(sNewName);
236 OSL_ENSURE(bSuccess, "Insert OLE failed");
237 if (bSuccess)
239 const SfxItemSet *pFlySet = pMathFlySet ? pMathFlySet : &rFlySet;
240 pRet = rDoc.InsertOLE(*pPaM, sNewName, rObject.GetAspect(), pFlySet, &rGrfSet, 0);
242 delete pMathFlySet;
243 return pRet;
246 SwFrmFmt* SwWW8ImplReader::ImportOle(const Graphic* pGrf,
247 const SfxItemSet* pFlySet, const SfxItemSet *pGrfSet, const Rectangle& aVisArea )
249 ::SetProgressState(nProgress, mpDocShell); // Update
250 SwFrmFmt* pFmt = 0;
252 GrafikCtor();
254 Graphic aGraph;
255 SdrObject* pRet = ImportOleBase(aGraph, pGrf, pFlySet, aVisArea );
257 // create flyset
258 SfxItemSet* pTempSet = 0;
259 if( !pFlySet )
261 pTempSet = new SfxItemSet( rDoc.GetAttrPool(), RES_FRMATR_BEGIN,
262 RES_FRMATR_END-1);
264 pFlySet = pTempSet;
266 // Abstand/Umrandung raus
267 if (!mbNewDoc)
268 Reader::ResetFrmFmtAttrs( *pTempSet );
270 SwFmtAnchor aAnchor( FLY_AS_CHAR );
271 aAnchor.SetAnchor( pPaM->GetPoint() );
272 pTempSet->Put( aAnchor );
274 const Size aSizeTwip = OutputDevice::LogicToLogic(
275 aGraph.GetPrefSize(), aGraph.GetPrefMapMode(), MAP_TWIP );
277 pTempSet->Put( SwFmtFrmSize( ATT_FIX_SIZE, aSizeTwip.Width(),
278 aSizeTwip.Height() ) );
279 pTempSet->Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
281 if( pSFlyPara )
283 // OLE im Rahmen ? ok, Rahmen auf Bildgroesse vergroessern (
284 // nur wenn Auto-Breite )
285 pSFlyPara->BoxUpWidth( aSizeTwip.Width() );
289 if (pRet) // Ole-Object wurde eingefuegt
291 if (pRet->ISA(SdrOle2Obj))
293 pFmt = InsertOle(*((SdrOle2Obj*)pRet), *pFlySet, *pGrfSet);
294 SdrObject::Free( pRet ); // das brauchen wir nicht mehr
296 else
297 pFmt = rDoc.Insert(*pPaM, *pRet, pFlySet, NULL);
299 else if (
300 GRAPHIC_GDIMETAFILE == aGraph.GetType() ||
301 GRAPHIC_BITMAP == aGraph.GetType()
304 pFmt = rDoc.Insert(*pPaM, aEmptyStr, aEmptyStr, &aGraph, pFlySet,
305 pGrfSet, NULL);
307 delete pTempSet;
308 return pFmt;
311 bool SwWW8ImplReader::ImportOleWMF(SvStorageRef xSrc1,GDIMetaFile &rWMF,
312 long &rX,long &rY)
314 bool bOk = false;
315 OLE_MFP aMfp;
316 if( SwWw6ReadMetaStream( rWMF, &aMfp, xSrc1 ) )
319 take scaling factor as found in PIC and apply it to graphic.
321 SwWw8ReadScaling( rX, rY, xSrc1 );
322 Size aFinalSize, aOrigSize;
323 aFinalSize.Width() = rX;
324 aFinalSize.Height() = rY;
325 aFinalSize = OutputDevice::LogicToLogic(
326 aFinalSize, MAP_TWIP, rWMF.GetPrefMapMode() );
327 aOrigSize = rWMF.GetPrefSize();
328 Fraction aScaleX(aFinalSize.Width(),aOrigSize.Width());
329 Fraction aScaleY(aFinalSize.Height(),aOrigSize.Height());
330 rWMF.Scale( aScaleX, aScaleY );
331 bOk = true;
333 return bOk;
336 SdrObject* SwWW8ImplReader::ImportOleBase( Graphic& rGraph,
337 const Graphic* pGrf, const SfxItemSet* pFlySet, const Rectangle& aVisArea )
339 SdrObject* pRet = 0;
340 OSL_ENSURE( pStg, "ohne storage geht hier fast gar nichts!" );
342 ::SetProgressState( nProgress, rDoc.GetDocShell() ); // Update
344 long nX=0, nY=0; // nX, nY is graphic size
345 bool bOleOk = true;
347 String aSrcStgName = OUString('_');
348 // ergibt Name "_4711"
349 aSrcStgName += OUString::number( nObjLocFc );
351 SvStorageRef xSrc0 = pStg->OpenSotStorage(OUString(SL::aObjectPool));
352 SvStorageRef xSrc1 = xSrc0->OpenSotStorage( aSrcStgName,
353 STREAM_READWRITE| STREAM_SHARE_DENYALL );
356 if (pGrf)
358 rGraph = *pGrf;
359 const Size aSizeTwip = OutputDevice::LogicToLogic(
360 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MAP_TWIP );
361 nX = aSizeTwip.Width();
362 nY = aSizeTwip.Height();
364 else
366 GDIMetaFile aWMF;
368 if (ImportOleWMF(xSrc1,aWMF,nX,nY))
369 rGraph = Graphic( aWMF );
370 else if( SwWw6ReadMacPICTStream( rGraph, xSrc1 ) )
372 // 03-META-Stream nicht da. Vielleicht ein 03-PICT ?
373 const Size aSizeTwip = OutputDevice::LogicToLogic(
374 rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MAP_TWIP );
375 nX = aSizeTwip.Width();
376 nY = aSizeTwip.Height();
377 // PICT: kein WMF da -> Grafik statt OLE
378 bOleOk = false;
380 } // StorageStreams wieder zu
383 Rectangle aRect(0, 0, nX, nY);
385 if (pFlySet)
387 if (const SwFmtFrmSize* pSize =
388 (const SwFmtFrmSize*)pFlySet->GetItem(RES_FRM_SIZE, false))
390 aRect.SetSize(pSize->GetSize());
394 if (!(bIsHeader || bIsFooter))
396 //Can't put them in headers/footers :-(
397 uno::Reference< drawing::XShape > xRef;
398 OSL_ENSURE(pFormImpl, "Impossible");
399 if (pFormImpl && pFormImpl->ReadOCXStream(xSrc1, &xRef, false))
401 pRet = GetSdrObjectFromXShape(xRef);
402 OSL_ENSURE(pRet, "Impossible");
403 if (pRet)
404 pRet->SetLogicRect(aRect);
405 return pRet;
409 if (GRAPHIC_GDIMETAFILE == rGraph.GetType() ||
410 GRAPHIC_BITMAP == rGraph.GetType())
412 ::SetProgressState(nProgress, mpDocShell); // Update
414 if (bOleOk)
416 sal_uLong nOldPos = pDataStream->Tell();
417 pDataStream->Seek(STREAM_SEEK_TO_END);
418 SvStream *pTmpData = 0;
419 if (nObjLocFc < pDataStream->Tell())
421 pTmpData = pDataStream;
422 pTmpData->Seek( nObjLocFc );
425 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
428 SvStorageStreamRef xObjInfoSrc = xSrc1->OpenSotStream(OUString("\3ObjInfo"),
429 STREAM_STD_READ | STREAM_NOCREATE );
430 if ( xObjInfoSrc.Is() && !xObjInfoSrc->GetError() )
432 sal_uInt8 nByte = 0;
433 *xObjInfoSrc >> nByte;
434 if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
435 nAspect = embed::Aspects::MSOLE_ICON;
439 ErrCode nError = ERRCODE_NONE;
440 pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
441 aSrcStgName, xSrc0, mpDocShell->GetStorage(), rGraph, aRect, aVisArea, pTmpData, nError,
442 SwMSDffManager::GetFilterFlags(), nAspect );
443 pDataStream->Seek( nOldPos );
446 return pRet;
449 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream& rStrm,
450 sal_Int32 nTblPos, sal_Int32 nTblSiz, SwDoc& rDocOut )
452 ::std::vector<String> aAuthorNames;
453 WW8ReadSTTBF( !bVer67, rStrm, nTblPos, nTblSiz, bVer67 ? 2 : 0,
454 eStructCharSet, aAuthorNames );
456 sal_uInt16 nCount = static_cast< sal_uInt16 >(aAuthorNames.size());
457 for( sal_uInt16 nAuthor = 0; nAuthor < nCount; ++nAuthor )
459 // Store author in doc
460 sal_uInt16 nSWId = rDocOut.InsertRedlineAuthor(aAuthorNames[nAuthor]);
461 // Store matchpair
462 m_aAuthorInfos[nAuthor] = nSWId;
467 Revision Marks ( == Redlining )
469 // insert or delete content (change char attributes resp.)
470 void SwWW8ImplReader::Read_CRevisionMark(RedlineType_t eType,
471 const sal_uInt8* pData, short nLen )
473 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
474 // pointing to the very same char position as our SprmCFRMark[Del]
475 if (!pPlcxMan)
476 return;
477 const sal_uInt8* pSprmCIbstRMark;
478 const sal_uInt8* pSprmCDttmRMark;
479 if( nsRedlineType_t::REDLINE_FORMAT == eType )
481 pSprmCIbstRMark = pData+1;
482 pSprmCDttmRMark = pData+3;
484 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" varient of HasCharSprm and take the last one as the true one.
491 std::vector<const sal_uInt8 *> aResult;
492 bool bIns = (nsRedlineType_t::REDLINE_INSERT == eType);
493 if( bVer67 )
495 pPlcxMan->HasCharSprm(69, aResult);
496 pSprmCIbstRMark = aResult.empty() ? 0 : aResult.back();
497 aResult.clear();
498 pPlcxMan->HasCharSprm(70, aResult);
499 pSprmCDttmRMark = aResult.empty() ? 0 : aResult.back();
501 else
503 pPlcxMan->HasCharSprm( bIns ? 0x4804 : 0x4863, aResult);
504 pSprmCIbstRMark = aResult.empty() ? 0 : aResult.back();
505 aResult.clear();
506 pPlcxMan->HasCharSprm( bIns ? 0x6805 : 0x6864, aResult);
507 pSprmCDttmRMark = aResult.empty() ? 0 : aResult.back();
511 if (nLen < 0)
512 mpRedlineStack->close(*pPaM->GetPoint(), eType, pTableDesc );
513 else
515 // start of new revision mark, if not there default to first entry
516 sal_uInt16 nWWAutNo = pSprmCIbstRMark ? SVBT16ToShort(pSprmCIbstRMark) : 0;
517 sal_uInt32 nWWDate = pSprmCDttmRMark ? SVBT32ToUInt32(pSprmCDttmRMark): 0;
518 DateTime aStamp(msfilter::util::DTTM2DateTime(nWWDate));
519 sal_uInt16 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( nsRedlineType_t::REDLINE_INSERT, pData, nLen );
531 // delete old content
532 void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16 , const sal_uInt8* pData, short nLen)
534 Read_CRevisionMark( nsRedlineType_t::REDLINE_DELETE, pData, nLen );
537 // change properties of content ( == char formating)
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( nsRedlineType_t::REDLINE_FORMAT, pData, nLen );
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */