1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ww8par4.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
35 #include "writerhelper.hxx"
36 #include <com/sun/star/embed/XClassifiedObject.hpp>
38 #ifndef __SGI_STL_ALGORITHM
41 #ifndef __SGI_STL_FUNCTIONAL
44 #include <osl/endian.h>
45 #include <sot/storage.hxx>
46 #include <com/sun/star/drawing/XShape.hpp>
47 #include <hintids.hxx>
48 #include <svx/svdoole2.hxx>
49 #include <svx/msdffimp.hxx>
50 #include <svx/impgrf.hxx>
51 #include <svx/unoapi.hxx>
52 #include <svx/msocximex.hxx>
54 #include <sot/exchange.hxx>
55 #include <swtypes.hxx>
56 #include <fmtanchr.hxx>
57 #include <fmtcntnt.hxx>
58 #include <dcontact.hxx>
63 #include <docsh.hxx> // fuer Ole-Node
65 #include <mdiexp.hxx> // Progress
66 #include <redline.hxx>
67 #include <fltshell.hxx>
68 #include <unodraw.hxx>
69 #include <shellio.hxx>
73 #include "ww8scan.hxx"
75 #include "ww8par2.hxx" // WWFlyPara::BoxUpWidth()
80 INT16 xExt
; // 0x8 int in 1/100 mm
81 INT16 yExt
; // 0xa int in 1/100 mm
85 using namespace ::com::sun::star
;
87 // SV_IMPL_OP_PTRARR_SORT(WW8AuthorInfos, WW8AuthorInfo_Ptr)
88 SV_IMPL_OP_PTRARR_SORT(WW8OleMaps
, WW8OleMap_Ptr
)
90 static bool SwWw8ReadScaling(long& rX
, long& rY
, SvStorageRef
& rSrc1
)
92 // Skalierungsfaktoren holen:
93 // Informationen in PIC-Stream ( durch ausprobieren )
95 // 0x08 .. 0x0a Flags ??
98 // 0x0a Inh: immer 8, MAP_ANISOTROPIC ???
100 // 0x0c, 0x10 Originalgroesse x,y in 1/100 mm
101 // 0x14, 0x16 Originalgroesse x,y in tw
102 // 0x2c, 0x30 Skalierung x,y in Promille
103 // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
105 SvStorageStreamRef xSrc3
= rSrc1
->OpenSotStream( CREATE_CONST_ASC( "\3PIC" ),
106 STREAM_STD_READ
| STREAM_NOCREATE
);
107 SvStorageStream
* pS
= xSrc3
;
108 pS
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
109 pS
->Seek( STREAM_SEEK_TO_END
);
111 ASSERT( pS
->Tell() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
122 *pS
>> nOrgWidth
// Original Size in 1/100 mm
125 *pS
>> nScaleX
// Scaling in Promille
127 >> nCropLeft
// Cropping in 1/100 mm
132 rX
= nOrgWidth
- nCropLeft
- nCropRight
;
133 rY
= nOrgHeight
- nCropTop
- nCropBottom
;
134 if (10 > nScaleX
|| 65536 < nScaleX
|| 10 > nScaleY
|| 65536 < nScaleY
)
136 ASSERT( !pS
, "+OLE-Scalinginformation in PIC-Stream wrong" );
141 rX
= (rX
* nScaleX
) / 1000;
142 rY
= (rY
* nScaleY
) / 1000;
147 static bool SwWw6ReadMetaStream(GDIMetaFile
& rWMF
, OLE_MFP
* pMfp
,
150 SvStorageStreamRef xSrc2
= rSrc1
->OpenSotStream( CREATE_CONST_ASC("\3META"),
151 STREAM_STD_READ
| STREAM_NOCREATE
);
152 SvStorageStream
* pSt
= xSrc2
;
153 pSt
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
154 ULONG nRead
= pSt
->Read( pMfp
, sizeof(*pMfp
) );
155 // Mini-Placable-Header lesen
156 if (nRead
!= sizeof(*pMfp
))
159 #if defined OSL_BIGENDIAN
160 pMfp
->mm
= SWAPSHORT( pMfp
->mm
);
161 pMfp
->xExt
= SWAPSHORT( pMfp
->xExt
);
162 pMfp
->yExt
= SWAPSHORT( pMfp
->yExt
);
163 #endif // OSL_BIGENDIAN
165 if( pMfp
->mm
== 94 || pMfp
->mm
== 99 )
167 ASSERT( !pSt
, "+OLE: Falscher Metafile-Typ" );
172 ASSERT( !pSt
, "+OLE: Falscher Metafile-Typ ( nicht Anisotropic )" );
174 if( !pMfp
->xExt
|| !pMfp
->yExt
)
176 ASSERT( !pSt
, "+OLE: Groesse von 0 ???" );
179 bool bOk
= ReadWindowMetafile( *pSt
, rWMF
, NULL
) ? true : false; // WMF lesen
180 // *pSt >> aWMF geht nicht ohne placable Header
181 if (!bOk
|| pSt
->GetError() || rWMF
.GetActionCount() == 0)
183 ASSERT( !pSt
, "+OLE: Konnte Metafile nicht lesen" );
187 rWMF
.SetPrefMapMode( MapMode( MAP_100TH_MM
) );
190 // MetaFile auf neue Groesse skalieren und
191 // neue Groesse am MetaFile setzen
192 Size
aOldSiz( rWMF
.GetPrefSize() );
193 Size
aNewSiz( pMfp
->xExt
, pMfp
->yExt
);
194 Fraction
aFracX( aNewSiz
.Width(), aOldSiz
.Width() );
195 Fraction
aFracY( aNewSiz
.Height(), aOldSiz
.Height() );
197 rWMF
.Scale( aFracX
, aFracY
);
198 rWMF
.SetPrefSize( aNewSiz
);
203 static bool SwWw6ReadMacPICTStream(Graphic
& rGraph
, SvStorageRef
& rSrc1
)
205 // 03-META-Stream nicht da. Vielleicht ein 03-PICT ?
206 SvStorageStreamRef xSrc4
= rSrc1
->OpenSotStream( CREATE_CONST_ASC( "\3PICT" ));
207 SvStorageStream
* pStp
= xSrc4
;
208 pStp
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
209 BYTE aTestA
[10]; // Ist der 01Ole-Stream ueberhaupt vorhanden
210 ULONG nReadTst
= pStp
->Read( aTestA
, sizeof( aTestA
) );
211 if (nReadTst
!= sizeof(aTestA
))
214 pStp
->Seek( STREAM_SEEK_TO_BEGIN
);
217 SvStream
*pDbg
= sw::hack::CreateDebuggingStream(CREATE_CONST_ASC(".pct"));
218 pDbg
->Seek(0x200); //Prepend extra 0x200 of zeros to make this a valid PICT
219 sw::hack::DumpStream(*pStp
, *pDbg
);
223 // Mac-Pict steht im 03PICT-StorageStream allerdings ohne die ersten 512
224 // Bytes, die bei einem MAC-PICT egal sind ( werden nicht ausgewertet )
225 return SwWW8ImplReader::GetPictGrafFromStream(rGraph
, *pStp
);
228 SwFlyFrmFmt
* SwWW8ImplReader::InsertOle(SdrOle2Obj
&rObject
,
229 const SfxItemSet
&rFlySet
, const SfxItemSet
&rGrfSet
)
231 SfxObjectShell
*pPersist
= rDoc
.GetPersist();
232 ASSERT(pPersist
, "No persist, cannot insert objects correctly");
236 SwFlyFrmFmt
*pRet
= 0;
238 SfxItemSet
*pMathFlySet
= 0;
239 uno::Reference
< embed::XClassifiedObject
> xClass( rObject
.GetObjRef(), uno::UNO_QUERY
);
242 SvGlobalName
aClassName( xClass
->getClassID() );
243 if (SotExchange::IsMath(aClassName
))
246 StarMath sets it own fixed size, so its counter productive to use the
247 size word says it is. i.e. Don't attempt to override its size.
249 pMathFlySet
= new SfxItemSet(rFlySet
);
250 pMathFlySet
->ClearItem(RES_FRM_SIZE
);
255 Take complete responsibility of the object away from SdrOle2Obj and to
256 me here locally. This utility class now owns the object.
259 // TODO/MBA: is the object inserted multiple times here? Testing!
260 // And is it a problem that we now use the same naming scheme as in the other apps?
261 sw::hack::DrawingOLEAdaptor
aOLEObj(rObject
, *pPersist
);
262 ::rtl::OUString sNewName
;
263 bool bSuccess
= aOLEObj
.TransferToDoc(sNewName
);
265 ASSERT(bSuccess
, "Insert OLE failed");
268 const SfxItemSet
*pFlySet
= pMathFlySet
? pMathFlySet
: &rFlySet
;
269 pRet
= rDoc
.InsertOLE(*pPaM
, sNewName
, rObject
.GetAspect(), pFlySet
, &rGrfSet
, 0);
275 SwFrmFmt
* SwWW8ImplReader::ImportOle(const Graphic
* pGrf
,
276 const SfxItemSet
* pFlySet
, const SfxItemSet
*pGrfSet
, const Rectangle
& aVisArea
)
278 ::SetProgressState(nProgress
, mpDocShell
); // Update
284 SdrObject
* pRet
= ImportOleBase(aGraph
, pGrf
, pFlySet
, aVisArea
);
287 SfxItemSet
* pTempSet
= 0;
290 pTempSet
= new SfxItemSet( rDoc
.GetAttrPool(), RES_FRMATR_BEGIN
,
295 // Abstand/Umrandung raus
297 Reader::ResetFrmFmtAttrs( *pTempSet
);
299 SwFmtAnchor
aAnchor( FLY_IN_CNTNT
);
300 aAnchor
.SetAnchor( pPaM
->GetPoint() );
301 pTempSet
->Put( aAnchor
);
303 const Size aSizeTwip
= OutputDevice::LogicToLogic(
304 aGraph
.GetPrefSize(), aGraph
.GetPrefMapMode(), MAP_TWIP
);
306 pTempSet
->Put( SwFmtFrmSize( ATT_FIX_SIZE
, aSizeTwip
.Width(),
307 aSizeTwip
.Height() ) );
308 pTempSet
->Put( SwFmtVertOrient( 0, text::VertOrientation::TOP
, text::RelOrientation::FRAME
));
312 // OLE im Rahmen ? ok, Rahmen auf Bildgroesse vergroessern (
313 // nur wenn Auto-Breite )
314 pSFlyPara
->BoxUpWidth( aSizeTwip
.Width() );
318 if (pRet
) // Ole-Object wurde eingefuegt
320 if (pRet
->ISA(SdrOle2Obj
))
322 pFmt
= InsertOle(*((SdrOle2Obj
*)pRet
), *pFlySet
, *pGrfSet
);
323 SdrObject::Free( pRet
); // das brauchen wir nicht mehr
326 pFmt
= rDoc
.Insert(*pPaM
, *pRet
, pFlySet
, NULL
);
329 GRAPHIC_GDIMETAFILE
== aGraph
.GetType() ||
330 GRAPHIC_BITMAP
== aGraph
.GetType()
333 pFmt
= rDoc
.Insert(*pPaM
, aEmptyStr
, aEmptyStr
, &aGraph
, pFlySet
,
340 bool SwWW8ImplReader::ImportOleWMF(SvStorageRef xSrc1
,GDIMetaFile
&rWMF
,
345 if( SwWw6ReadMetaStream( rWMF
, &aMfp
, xSrc1
) )
348 take scaling factor as found in PIC and apply it to graphic.
350 SwWw8ReadScaling( rX
, rY
, xSrc1
);
351 Size aFinalSize
, aOrigSize
;
352 aFinalSize
.Width() = rX
;
353 aFinalSize
.Height() = rY
;
354 aFinalSize
= OutputDevice::LogicToLogic(
355 aFinalSize
, MAP_TWIP
, rWMF
.GetPrefMapMode() );
356 aOrigSize
= rWMF
.GetPrefSize();
357 Fraction
aScaleX(aFinalSize
.Width(),aOrigSize
.Width());
358 Fraction
aScaleY(aFinalSize
.Height(),aOrigSize
.Height());
359 rWMF
.Scale( aScaleX
, aScaleY
);
365 SdrObject
* SwWW8ImplReader::ImportOleBase( Graphic
& rGraph
,
366 const Graphic
* pGrf
, const SfxItemSet
* pFlySet
, const Rectangle
& aVisArea
)
369 ASSERT( pStg
, "ohne storage geht hier fast gar nichts!" );
371 ::SetProgressState( nProgress
, rDoc
.GetDocShell() ); // Update
373 long nX
=0, nY
=0; // nX, nY is graphic size
376 String aSrcStgName
= '_';
377 // ergibt Name "_4711"
378 aSrcStgName
+= String::CreateFromInt32( nObjLocFc
);
380 SvStorageRef xSrc0
= pStg
->OpenSotStorage(CREATE_CONST_ASC(SL::aObjectPool
));
381 SvStorageRef xSrc1
= xSrc0
->OpenSotStorage( aSrcStgName
,
382 STREAM_READWRITE
| STREAM_SHARE_DENYALL
);
388 const Size aSizeTwip
= OutputDevice::LogicToLogic(
389 rGraph
.GetPrefSize(), rGraph
.GetPrefMapMode(), MAP_TWIP
);
390 nX
= aSizeTwip
.Width();
391 nY
= aSizeTwip
.Height();
397 if (ImportOleWMF(xSrc1
,aWMF
,nX
,nY
))
398 rGraph
= Graphic( aWMF
);
399 else if( SwWw6ReadMacPICTStream( rGraph
, xSrc1
) )
401 // 03-META-Stream nicht da. Vielleicht ein 03-PICT ?
402 const Size aSizeTwip
= OutputDevice::LogicToLogic(
403 rGraph
.GetPrefSize(), rGraph
.GetPrefMapMode(), MAP_TWIP
);
404 nX
= aSizeTwip
.Width();
405 nY
= aSizeTwip
.Height();
406 // PICT: kein WMF da -> Grafik statt OLE
409 } // StorageStreams wieder zu
412 Rectangle
aRect(0, 0, nX
, nY
);
416 if (const SwFmtFrmSize
* pSize
=
417 (const SwFmtFrmSize
*)pFlySet
->GetItem(RES_FRM_SIZE
, false))
419 aRect
.SetSize(pSize
->GetSize());
423 if (!(bIsHeader
|| bIsFooter
))
425 //Can't put them in headers/footers :-(
426 uno::Reference
< drawing::XShape
> xRef
;
427 ASSERT(pFormImpl
, "Impossible");
428 if (pFormImpl
&& pFormImpl
->ReadOCXStream(xSrc1
, &xRef
, false))
430 pRet
= GetSdrObjectFromXShape(xRef
);
431 ASSERT(pRet
, "Impossible");
433 pRet
->SetLogicRect(aRect
);
438 if (GRAPHIC_GDIMETAFILE
== rGraph
.GetType() ||
439 GRAPHIC_BITMAP
== rGraph
.GetType())
441 ::SetProgressState(nProgress
, mpDocShell
); // Update
445 ULONG nOldPos
= pDataStream
->Tell();
446 pDataStream
->Seek(STREAM_SEEK_TO_END
);
447 SvStream
*pTmpData
= 0;
448 if (nObjLocFc
< pDataStream
->Tell())
450 pTmpData
= pDataStream
;
451 pTmpData
->Seek( nObjLocFc
);
454 sal_Int64 nAspect
= embed::Aspects::MSOLE_CONTENT
;
457 SvStorageStreamRef xObjInfoSrc
= xSrc1
->OpenSotStream( CREATE_CONST_ASC( "\3ObjInfo" ),
458 STREAM_STD_READ
| STREAM_NOCREATE
);
459 if ( xObjInfoSrc
.Is() && !xObjInfoSrc
->GetError() )
462 *xObjInfoSrc
>> nByte
;
463 if ( ( nByte
>> 4 ) & embed::Aspects::MSOLE_ICON
)
464 nAspect
= embed::Aspects::MSOLE_ICON
;
468 ErrCode nError
= ERRCODE_NONE
;
469 pRet
= SvxMSDffManager::CreateSdrOLEFromStorage(
470 aSrcStgName
, xSrc0
, mpDocShell
->GetStorage(), rGraph
, aRect
, aVisArea
, pTmpData
, nError
,
471 SwMSDffManager::GetFilterFlags(), nAspect
);
472 pDataStream
->Seek( nOldPos
);
478 void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream
& rStrm
,
479 INT32 nTblPos
, INT32 nTblSiz
, SwDoc
& rDocOut
)
481 ::std::vector
<String
> aAuthorNames
;
482 WW8ReadSTTBF( !bVer67
, rStrm
, nTblPos
, nTblSiz
, bVer67
? 2 : 0,
483 eStructCharSet
, aAuthorNames
);
485 USHORT nCount
= static_cast< USHORT
>(aAuthorNames
.size());
486 for( USHORT nAuthor
= 0; nAuthor
< nCount
; ++nAuthor
)
488 // Store author in doc
489 USHORT nSWId
= rDocOut
.InsertRedlineAuthor(aAuthorNames
[nAuthor
]);
492 pAuthorInfos
= new sw::util::AuthorInfos
;
493 sw::util::AuthorInfo
* pAutorInfo
= new sw::util::AuthorInfo( nAuthor
, nSWId
);
494 if( 0 == pAuthorInfos
->Insert( pAutorInfo
) )
500 Revision Marks ( == Redlining )
502 // insert or delete content (change char attributes resp.)
503 void SwWW8ImplReader::Read_CRevisionMark(RedlineType_t eType
,
504 const BYTE
* pData
, short nLen
)
506 // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
507 // pointing to the very same char position as our SprmCFRMark[Del]
510 const BYTE
* pSprmCIbstRMark
;
511 const BYTE
* pSprmCDttmRMark
;
512 if( nsRedlineType_t::REDLINE_FORMAT
== eType
)
514 pSprmCIbstRMark
= pData
+1;
515 pSprmCDttmRMark
= pData
+3;
521 It is possible to have a number of date stamps for the created time
522 of the change, (possibly a word bug) so we must use the "get a full
523 list" varient of HasCharSprm and take the last one as the true one.
525 std::vector
<const BYTE
*> aResult
;
526 bool bIns
= (nsRedlineType_t::REDLINE_INSERT
== eType
);
529 pPlcxMan
->HasCharSprm(69, aResult
);
530 pSprmCIbstRMark
= aResult
.empty() ? 0 : aResult
.back();
532 pPlcxMan
->HasCharSprm(70, aResult
);
533 pSprmCDttmRMark
= aResult
.empty() ? 0 : aResult
.back();
537 pPlcxMan
->HasCharSprm( bIns
? 0x4804 : 0x4863, aResult
);
538 pSprmCIbstRMark
= aResult
.empty() ? 0 : aResult
.back();
540 pPlcxMan
->HasCharSprm( bIns
? 0x6805 : 0x6864, aResult
);
541 pSprmCDttmRMark
= aResult
.empty() ? 0 : aResult
.back();
546 mpRedlineStack
->close(*pPaM
->GetPoint(), eType
, pTableDesc
);
549 // start of new revision mark, if not there default to first entry
550 USHORT nWWAutNo
= pSprmCIbstRMark
? SVBT16ToShort( pSprmCIbstRMark
) : 0;
551 sw::util::AuthorInfo
aEntry(nWWAutNo
);
553 if (pAuthorInfos
&& pAuthorInfos
->Seek_Entry(&aEntry
, &nPos
))
555 if (const sw::util::AuthorInfo
* pAuthor
= pAuthorInfos
->GetObject(nPos
))
557 UINT32 nWWDate
= pSprmCDttmRMark
? SVBT32ToUInt32(pSprmCDttmRMark
): 0;
558 DateTime
aStamp(sw::ms::DTTM2DateTime(nWWDate
));
559 USHORT nAutorNo
= pAuthor
->nOurId
;
560 SwFltRedline
aNewAttr(eType
, nAutorNo
, aStamp
);
568 // insert new content
569 void SwWW8ImplReader::Read_CFRMark(USHORT
, const BYTE
* pData
, short nLen
)
571 Read_CRevisionMark( nsRedlineType_t::REDLINE_INSERT
, pData
, nLen
);
574 // delete old content
575 void SwWW8ImplReader::Read_CFRMarkDel(USHORT
, const BYTE
* pData
, short nLen
)
577 Read_CRevisionMark( nsRedlineType_t::REDLINE_DELETE
, pData
, nLen
);
580 // change properties of content ( == char formating)
581 void SwWW8ImplReader::Read_CPropRMark(USHORT
, const BYTE
* pData
, short nLen
)
583 // complex (len is always 7)
584 // 1 byte - chp.fPropRMark
585 // 2 bytes - chp.ibstPropRMark
586 // 4 bytes - chp.dttmPropRMark;
587 Read_CRevisionMark( nsRedlineType_t::REDLINE_FORMAT
, pData
, nLen
);
590 /* vi:set tabstop=4 shiftwidth=4 expandtab: */