LibreOffice Module sw (master) 1
wrtww8gr.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <memory>
21#include <com/sun/star/embed/XEmbedPersist.hpp>
22#include <com/sun/star/embed/Aspects.hpp>
23#include <com/sun/star/embed/ElementModes.hpp>
24#include <sal/log.hxx>
25#include <vcl/graphicfilter.hxx>
26#include <vcl/gdimtf.hxx>
27#include <svl/itemiter.hxx>
29
30#include <svtools/embedhlp.hxx>
31
32#include <hintids.hxx>
33#include <editeng/boxitem.hxx>
34#include <editeng/shaditem.hxx>
36#include <editeng/fhgtitem.hxx>
37#include <svx/svdoole2.hxx>
38
40#include <fmtanchr.hxx>
41#include <ndgrf.hxx>
42#include <frmfmt.hxx>
43#include <grfatr.hxx>
44#include <ndole.hxx>
45#include <fmtfsize.hxx>
46#include <fmtornt.hxx>
47
48#include "sprmids.hxx"
49
50#include <doc.hxx>
51#include "writerhelper.hxx"
52#include "writerwordglue.hxx"
53#include "ww8struc.hxx"
54#include "wrtww8.hxx"
55#include "ww8par.hxx"
56#include "escher.hxx"
57//Added for i120568
59#include <fmturl.hxx>
60
62#include <drawdoc.hxx>
63#include <o3tl/string_view.hxx>
64
65using namespace ::com::sun::star;
66
67// TODO:
68// 5. convert the MapModes that Widows can't handle
69
70// OutGrf () is called for every GrfNode in the document. A PicLocFc-Sprm
71// will be inserted, which contains a magic number instead of an address.
72// The GrfNode-Ptr is saved in Graf-Class (used later for output of
73// the graphic and patching of the PicLocFc attributes)
74
75void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
76{
77 SAL_INFO("sw", "WW8Export::OutputGrfNode( const SwGrfNode& )" );
78 OSL_ENSURE( m_pParentFrame, "frame not set!" );
79 if ( m_pParentFrame )
80 {
82 m_pFib->m_fHasPic = true;
83 }
84}
85
87 const tools::SvRef<SotStorage>& xObjStg,
88 OUString const& rStorageName, SwOLENode* pOLENd)
89{
90 bool bGraphicNeeded = false;
91 SfxItemIter aIter( rSet );
92 for (auto pItem = aIter.GetCurItem(); !bGraphicNeeded && pItem; pItem = aIter.NextItem())
93 {
94 switch (pItem->Which())
95 {
96 /*
97 For an inline object these properties are irrelevant because they
98 will be the same as the defaults that msword applies in their
99 absence, so if that is all that there is for these inline objects
100 then if there turns out to be enough information in the object
101 itself to regenerate the correct size and preview of the object
102 then we will not need to provide an additional graphics preview in
103 the data stream, which can save a lot of disk space.
104 */
105 case RES_FRM_SIZE:
106 case RES_CNTNT:
107 case RES_VERT_ORIENT:
108 case RES_ANCHOR:
109 break;
110 default:
111 bGraphicNeeded = true;
112 }
113 }
114
115 /*
116 Now we must see if the object contains a preview itself which is equal to
117 the preview that we are currently using. If the graphics are equal then we
118 don't need to store another preview
119 */
120 GDIMetaFile aWMF;
121 tools::Long nX=0,nY=0;
122 if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
123 {
124 // bGraphicNeeded set to true is right / fixes #i51670#.
125 bGraphicNeeded = true;
126 tools::Rectangle aRect( Point(), Size( nX, nY ) );
127 Graphic aGraph(aWMF);
128
129 ErrCode nErr = ERRCODE_NONE;
130 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
131 if ( pOLENd )
132 nAspect = pOLENd->GetAspect();
135 rStorageName,
136 xObjStg,
138 aGraph,
139 aRect,
141 nullptr,
142 nErr,
143 0,
144 nAspect,
146
147 if (pRet)
148 {
149 uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
150 if ( xObj.is() )
151 {
152 std::unique_ptr<SvStream> pGraphicStream;
154 try
155 {
156 uno::Reference< embed::XEmbedPersist > xPersist(
157 xObj,
158 uno::UNO_QUERY_THROW );
159
160 // it makes no sense to search the object in the container by reference since the object was created
161 // outside of the container and was not inserted there, only the name makes sense
162 pGraphicStream =
163 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
164 }
165 catch( const uno::Exception& )
166 {}
167
168 OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
169 if ( pGraphicStream && !pGraphicStream->GetError() )
170 {
171 Graphic aGr1;
173 if( rGF.ImportGraphic( aGr1, u"", *pGraphicStream ) == ERRCODE_NONE )
174 {
175 Graphic aGr2;
176 pGraphicStream =
177 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
178 if( pGraphicStream && rGF.ImportGraphic( aGr2, u"", *pGraphicStream ) == ERRCODE_NONE )
179 {
180 if ( aGr1 == aGr2 )
181 bGraphicNeeded = false;
182 }
183 }
184 }
185 }
186 }
187 }
188 else
189 bGraphicNeeded = true;
190 return bGraphicNeeded;
191}
192
193void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
194{
195 SAL_INFO("sw", "WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
196 sal_uInt8 *pSpecOLE;
197 sal_uInt8 *pDataAdr;
198 short nSize;
199 static sal_uInt8 aSpecOLE_WW8[] = {
200 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
201 0x0a, 0x08, 1, // sprmCFOLE2
202 0x56, 0x08, 1 // sprmCFObj
203 };
204
205 pSpecOLE = aSpecOLE_WW8;
206 nSize = sizeof( aSpecOLE_WW8 );
207 pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
208
210
211 if( !xObjStg.is() )
212 return;
213
214 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
215 if( !xObj.is() )
216 return;
217
218 const embed::XEmbeddedObject *pObj = xObj.get();
219 //Don't want to use pointer ids, as is traditional, because we need
220 //to put this into a 32bit value, and on 64bit the bottom bits
221 //might collide and two unrelated ole objects end up considered the
222 //same. Don't want to simply start at 0 which is a special value
223 sal_Int32 nPictureId = SAL_MAX_INT32 - m_aOleMap.size();
224 WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
225 std::pair<WW8OleMap::iterator, bool> aRes = m_aOleMap.insert(entry);
226 bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
227 nPictureId = aRes.first->second;
228 Set_UInt32(pDataAdr, nPictureId);
229 OUString sStorageName = "_" + OUString::number( nPictureId );
230 tools::SvRef<SotStorage> xOleStg = xObjStg->OpenSotStorage( sStorageName );
231 if( !xOleStg.is() )
232 return;
233
234 /*
235 If this object storage has been written already don't
236 waste time rewriting it
237 */
238 if (bIsNotDuplicate)
239 {
240 sal_Int64 nAspect = rOLENode.GetAspect();
241 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
242 m_oOLEExp->ExportOLEObject( aObjRef, *xOleStg );
243 if ( nAspect == embed::Aspects::MSOLE_ICON )
244 {
245 OUString aObjInfo( "\3ObjInfo" );
246 if ( !xOleStg->IsStream( aObjInfo ) )
247 {
248 const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
249 tools::SvRef<SotStorageStream> rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
250 if ( rObjInfoStream.is() && !rObjInfoStream->GetError() )
251 {
252 rObjInfoStream->WriteBytes(pObjInfoData, sizeof(pObjInfoData));
253 xOleStg->Commit();
254 }
255 }
256 }
257 }
258
259 // write as embedded field - the other things will be done
260 // in the escher export
261 OUString sServer = FieldString(ww::eEMBED) + xOleStg->GetUserName() + " ";
262
263 OutputField(nullptr, ww::eEMBED, sServer, FieldFlags::Start |
265
266 m_pChpPlc->AppendFkpEntry( Strm().Tell(),
267 nSize, pSpecOLE );
268
269 bool bEndCR = true;
270 /*
271 In the word filter we only need a preview image for
272 floating images, and then only (the usual case) if the
273 object doesn't contain enough information to reconstruct
274 what we need.
275
276 We don't need a graphic for inline objects, so we don't
277 even need the overhead of a graphic in that case.
278 */
279 bool bGraphicNeeded = false;
280
281 if (m_pParentFrame)
282 {
283 bGraphicNeeded = true;
284
286 {
287 const SwAttrSet& rSet =
289 bEndCR = false;
290 bGraphicNeeded = TestOleNeedsGraphic(rSet,
291 xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
292 }
293 }
294
295 if (!bGraphicNeeded)
296 WriteChar(0x1);
297 else
298 {
299 /*
300 ##897##
301 We need to insert the graphic representation of
302 this object for the inline case, otherwise word
303 has no place to find the dimensions of the ole
304 object, and will not be able to draw it
305 */
307 }
308
309 OutputField(nullptr, ww::eEMBED, OUString(),
311
312 if (bEndCR) //No newline in inline case
313 WriteCR();
314}
315
316void WW8Export::OutputLinkedOLE( const OUString& rOleId )
317{
318 uno::Reference< embed::XStorage > xDocStg = m_rDoc.GetDocStorage();
319 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
320 tools::SvRef<SotStorage> xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, StreamMode::READ );
321
323
324 if( !(xObjStg.is() && xObjSrc.is()) )
325 return;
326
327 tools::SvRef<SotStorage> xOleDst = xObjStg->OpenSotStorage( rOleId );
328 if ( xOleDst.is() )
329 xObjSrc->CopyTo( xOleDst.get() );
330
331 if ( xOleDst->GetError( ) )
332 return;
333
334 xOleDst->Commit();
335
336 // Output the cPicLocation attribute
337 std::unique_ptr<ww::bytes> pBuf( new ww::bytes );
339 SwWW8Writer::InsUInt32( *pBuf, o3tl::toInt32(rOleId.subView( 1 )) );
340
342 pBuf->push_back( 1 );
343
345 pBuf->push_back( 1 );
346
348 pBuf->push_back( 1 );
349
350 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
351}
352
353void WW8Export::OutGrf(const ww8::Frame &rFrame)
354{
355 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
356 //will be exported to ensure the fidelity
357 const SwFormatURL& rURL = rFrame.GetFrameFormat().GetAttrSet().GetURL();
358 bool bURLStarted = false;
359 if( !rURL.GetURL().isEmpty() && rFrame.GetWriterType() == ww8::Frame::eGraphic)
360 {
361 bURLStarted = true;
362 m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
363 }
364
365 // Store the graphic settings in GrfNode so they may be written-out later
366 m_pGrf->Insert(rFrame);
367
368 m_pChpPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
369 m_pO->clear();
370
371 // #i29408#
372 // linked, as-character anchored graphics have to be exported as fields.
373 const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
374 ? rFrame.GetContent()->GetGrfNode() : nullptr;
375 if ( pGrfNd && pGrfNd->IsLinkedFile() )
376 {
377 OUString sStr;
378 pGrfNd->GetFileFilterNms(&sStr, nullptr);
379 sStr = FieldString(ww::eINCLUDEPICTURE) + " \"" + sStr + "\" \\d";
380
381 OutputField( nullptr, ww::eINCLUDEPICTURE, sStr,
383 }
384
385 WriteChar( char(1) ); // paste graphic symbols in the main text
386
387 sal_uInt8 aArr[ 18 ];
388 sal_uInt8* pArr = aArr;
389
390 const SwFrameFormat &rFlyFormat = rFrame.GetFrameFormat();
391 const RndStdIds eAn = rFlyFormat.GetAttrSet().GetAnchor(false).GetAnchorId();
392 if (eAn == RndStdIds::FLY_AS_CHAR)
393 {
394 sal_Int16 eVert = rFlyFormat.GetVertOrient().GetVertOrient();
395 if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
396 {
397 bool bVert = false;
398 //The default for word in vertical text mode is to center,
399 //otherwise a sub/super script hack is employed
400 if (auto pTextNd = dynamic_cast< const SwContentNode *>( m_pOutFormatNode ) )
401 {
402 SwPosition aPos(*pTextNd);
403 bVert = m_rDoc.IsInVerticalText(aPos);
404 }
405 if (!bVert)
406 {
407 SwTwips nHeight = rFlyFormat.GetFrameSize().GetHeight();
408 nHeight/=20; //nHeight was in twips, want it in half points, but
409 //then half of total height.
410 tools::Long nFontHeight = GetItem(RES_CHRATR_FONTSIZE).GetHeight();
411 nHeight-=nFontHeight/20;
412
414 Set_UInt16( pArr, - static_cast<sal_Int16>(nHeight));
415 }
416 }
417 }
418
419 // sprmCFSpec
420 Set_UInt16( pArr, 0x855 );
421 Set_UInt8( pArr, 1 );
422
423 // sprmCPicLocation
425 Set_UInt32( pArr, GRF_MAGIC_321 );
426
427 // vary Magic, so that different graphic attributes will not be merged
428 static sal_uInt8 nAttrMagicIdx = 0;
429 --pArr;
430 Set_UInt8( pArr, nAttrMagicIdx++ );
431 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
432
433 // #i75464#
434 // Check, if graphic isn't exported as-character anchored.
435 // Otherwise, an additional paragraph is exported for a graphic, which is
436 // forced to be treated as inline, because it's anchored inside another frame.
437 if ( !rFrame.IsInline() &&
438 ( (eAn == RndStdIds::FLY_AT_PARA) ||
439 (eAn == RndStdIds::FLY_AT_PAGE) ) )
440 {
441 WriteChar( char(0x0d) ); // close the surrounding frame with CR
442
443 static sal_uInt8 nSty[2] = { 0, 0 };
444 m_pO->insert( m_pO->end(), nSty, nSty+2 ); // Style #0
445 bool bOldGrf = m_bOutGrf;
446 m_bOutGrf = true;
447
448 OutputFormat( rFrame.GetFrameFormat(), false, false, true ); // Fly-Attrs
449
450 m_bOutGrf = bOldGrf;
451 m_pPapPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
452 m_pO->clear();
453 }
454 // #i29408#
455 // linked, as-character anchored graphics have to be exported as fields.
456 else if ( pGrfNd && pGrfNd->IsLinkedFile() )
457 {
458 OutputField( nullptr, ww::eINCLUDEPICTURE, OUString(), FieldFlags::Close );
459 }
460 //Added for i120568,the hyperlink info within a graphic whose anchor type is
461 //"As character" will be exported to ensure the fidelity
462 if( bURLStarted )
463 m_pAttrOutput->EndURL(false);
464}
465
467{
468 const Size aSize( rFly.GetLayoutSize() );
469 const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
470 const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
471 maDetails.emplace_back(rFly, nWidth, nHeight);
472}
473
475 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
476{
477 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
478 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
479
480 // write Crop-Attribute content in Header ( if available )
481 const SwCropGrf* pCropItem;
482 if (pAttrSet && (pCropItem
483 = pAttrSet->GetItemIfSet(RES_GRFATR_CROPGRF, false)))
484 {
485 nCropL = static_cast<sal_Int16>(pCropItem->GetLeft());
486 nCropR = static_cast<sal_Int16>(pCropItem->GetRight());
487 nCropT = static_cast<sal_Int16>(pCropItem->GetTop());
488 nCropB = static_cast<sal_Int16>(pCropItem->GetBottom());
489 nXSizeAdd = nXSizeAdd - static_cast<sal_Int16>( pCropItem->GetLeft() + pCropItem->GetRight() );
490 nYSizeAdd = nYSizeAdd - static_cast<sal_Int16>( pCropItem->GetTop() + pCropItem->GetBottom() );
491 }
492
493 Size aGrTwipSz(rFly.GetSize());
494 sal_uInt16 nHdrLen = 0x44;
495
496 sal_uInt8 aArr[ 0x44 ] = { 0 };
497
498 sal_uInt8* pArr = aArr + 0x2E; // Do borders first
499
500 const SwAttrSet& rAttrSet = rFly.GetFrameFormat().GetAttrSet();
501 if (const SvxBoxItem* pBox = rAttrSet.GetItemIfSet(RES_BOX, false))
502 {
503 bool bShadow = false; // Shadow ?
504 if (const SvxShadowItem* pSI = rAttrSet.GetItem<SvxShadowItem>(RES_SHADOW))
505 {
506 bShadow = (pSI->GetLocation() != SvxShadowLocation::NONE) &&
507 (pSI->GetWidth() != 0);
508 }
509
510 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
511 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
512 for(const SvxBoxItemLine & i : aLnArr)
513 {
514 const ::editeng::SvxBorderLine* pLn = pBox->GetLine( i );
515 WW8_BRC aBrc;
516 if (pLn)
517 {
519 pBox->GetDistance( i ), bShadow );
521 aBrc90.cv()));
522 aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
523 aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
524 }
525
526 // use importer logic to determine how large the exported
527 // border will really be in word and adjust accordingly
528 short nSpacing;
529 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
530 switch (i)
531 {
532 case SvxBoxItemLine::TOP:
533 case SvxBoxItemLine::BOTTOM:
534 nHeight -= bShadow ? nThick*2 : nThick;
535 nHeight = nHeight - nSpacing;
536 break;
537 case SvxBoxItemLine::LEFT:
538 case SvxBoxItemLine::RIGHT:
539 default:
540 nWidth -= bShadow ? nThick*2 : nThick;
541 nWidth = nWidth - nSpacing;
542 break;
543 }
544 memcpy( pArr, &aBrc.aBits1, 2);
545 pArr+=2;
546
547 memcpy( pArr, &aBrc.aBits2, 2);
548 pArr+=2;
549 }
550 }
551
552 pArr = aArr + 4; // skip lcb
553 Set_UInt16( pArr, nHdrLen ); // set cbHeader
554
555 Set_UInt16( pArr, mm ); // set mm
556
557 /*
558 Just in case our original size is too big to fit inside a ushort we can
559 substitute the final size and lose on retaining the scaling factor but
560 still keep the correct display size anyway.
561 */
562 const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
563 aGrTwipSz.IsEmpty();
564 if ( bIsSubstitutedSize )
565 {
566 aGrTwipSz.setWidth( nWidth );
567 aGrTwipSz.setHeight( nHeight );
568 }
569 using namespace sw::types;
570 // set xExt & yExt
571 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
572 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
573 pArr += 16;
574 // skip hMF & rcWinMF
575 // set dxaGoal & dyaGoal
576 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
577 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
578
579 if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
580 {
581 if ( !bIsSubstitutedSize )
582 {
583 const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
584 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
585 }
586 else
587 {
588 Set_UInt16( pArr, 1000 );
589 }
590 }
591 else
592 {
593 pArr += 2;
594 }
595
596 if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
597 {
598 if ( !bIsSubstitutedSize )
599 {
600 const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
601 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
602 }
603 else
604 {
605 Set_UInt16( pArr, 1000 );
606 }
607 }
608 else
609 {
610 pArr += 2;
611 }
612
613 if ( !bIsSubstitutedSize )
614 {
615 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
616 Set_UInt16( pArr, nCropT ); // set dyaCropTop
617 Set_UInt16( pArr, nCropR ); // set dxaCropRight
618 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
619 }
620
621 rStrm.WriteBytes(aArr, nHdrLen);
622}
623
625 const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
626{
627 if (rGrfNd.IsLinkedFile()) // Linked File
628 {
629 OUString aFileN;
630 rGrfNd.GetFileFilterNms( &aFileN, nullptr );
631
632 sal_uInt16 const mm = 94; // 94 = BMP, GIF
633
634 WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
635 rGrfNd.GetpSwAttrSet());
636 rStrm.WriteUChar( aFileN.getLength() ); // write Pascal-String
637 SwWW8Writer::WriteString8(rStrm, aFileN, false,
638 RTL_TEXTENCODING_MS_1252);
639 }
640 else // Embedded File or DDE or something like that
641 {
642 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
643 rGrfNd.GetpSwAttrSet());
644 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
645 aInlineEscher.WriteGrfFlyFrame(rFly.GetFrameFormat(), 0x401);
646 aInlineEscher.WritePictures();
647 }
648}
649//For i120928,export graphic info of bullet
651 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
652{
653 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
654
655 Size aGrTwipSz(rGrf.GetPrefSize());
656 sal_uInt16 nHdrLen = 0x44;
657
658 sal_uInt8 aArr[ 0x44 ] = { 0 };
659
660 sal_uInt8* pArr = aArr + 0x2E; //Do borders first
661
662 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
663 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
664 for(const SvxBoxItemLine & i : aLnArr)
665 {
666 WW8_BRC aBrc;
667
668 short nSpacing;
669 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
670 switch (i)
671 {
672 case SvxBoxItemLine::TOP:
673 case SvxBoxItemLine::BOTTOM:
674 nHeight -= nThick;
675 nHeight = nHeight - nSpacing;
676 break;
677 case SvxBoxItemLine::LEFT:
678 case SvxBoxItemLine::RIGHT:
679 default:
680 nWidth -= nThick;
681 nWidth = nWidth - nSpacing;
682 break;
683 }
684 memcpy( pArr, &aBrc.aBits1, 2);
685 pArr+=2;
686
687 memcpy(pArr, &aBrc.aBits2, 2);
688 pArr+=2;
689 }
690
691 pArr = aArr + 4; //skip lcb
692 Set_UInt16( pArr, nHdrLen ); // set cbHeader
693
694 Set_UInt16( pArr, mm ); // set mm
695
696 if ( (convertTwipToMm100(aGrTwipSz.Width()) > USHRT_MAX ) || ( convertTwipToMm100(aGrTwipSz.Height()) > USHRT_MAX )
697 || aGrTwipSz.IsEmpty() )
698 {
699 aGrTwipSz.setWidth( nWidth );
700 aGrTwipSz.setHeight( nHeight );
701 }
702 using namespace sw::types;
703 // set xExt & yExt
704 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
705 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
706 pArr += 16;
707 // skip hMF & rcWinMF
708 // set dxaGoal & dyaGoal
709 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
710 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
711
712 if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
713 {
714 double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
715 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
716 }
717 else
718 pArr += 2;
719
720 if( aGrTwipSz.Height() + nYSizeAdd ) // set my
721 {
722 double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
723 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
724 }
725 else
726 pArr += 2;
727
728 Set_UInt16( pArr, 0 ); // set dxaCropLeft
729 Set_UInt16( pArr, 0 ); // set dyaCropTop
730 Set_UInt16( pArr, 0 ); // set dxaCropRight
731 Set_UInt16( pArr, 0 ); // set dyaCropBottom
732
733 rStrm.WriteBytes(aArr, nHdrLen);
734}
735
736void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
737{
738 WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
739 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
740 aInlineEscher.WriteGrfBullet(rGrf);
741 aInlineEscher.WritePictures();
742}
743
745{
746 sal_uInt16 nWidth = rItem.mnWid;
747 sal_uInt16 nHeight = rItem.mnHei;
748 sal_uInt32 nPos = rStrm.Tell(); // store start of graphic
749
750 const ww8::Frame &rFly = rItem.maFly;
751 switch (rFly.GetWriterType())
752 {
754 {
755 const SwNode *pNode = rItem.maFly.GetContent();
756 const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : nullptr;
757 OSL_ENSURE(pNd, "Impossible");
758 if (pNd)
759 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
760 }
761 break;
762 //For i120928,add branch to export graphic of bullet
764 {
765 if (rItem.maFly.HasGraphic())
766 {
767 const Graphic& rGrf = rItem.maFly.GetGraphic();
768 WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
769 }
770 }
771 break;
772
773 case ww8::Frame::eOle:
774 {
775 const SwNode *pNode = rItem.maFly.GetContent();
776 const SwOLENode *pNd = pNode ? pNode->GetOLENode() : nullptr;
777 OSL_ENSURE(pNd, "Impossible");
778 if (pNd)
779 {
780#ifdef OLE_PREVIEW_AS_EMF
781 //Convert this ole2 preview in ww8+ to an EMF for better unicode
782 //support (note that at this moment this breaks StarSymbol
783 //using graphics because I need to embed starsymbol in exported
784 //documents.
785 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
786 pNd->GetpSwAttrSet());
787 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
788 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrameFormat(), 0x401);
789 aInlineEscher.WritePictures();
790#else
791 // cast away const
792 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
793 SwOLEObj& rSObj= pOleNd->GetOLEObj();
794
795 // TODO/LATER: do we need to load object?
796 Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
797
798 //TODO/LATER: do we really want to use GDIMetafile?!
799 GDIMetaFile aMtf;
800 if ( pGr )
801 aMtf = pGr->GetGDIMetaFile();
802
803 Size aS(aMtf.GetPrefSize());
804 aMtf.WindStart();
806 Size(2880, 2880));
807
808 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
809 pNd->GetpSwAttrSet());
811 delete pGr;
812#endif
813 }
814 }
815 break;
819 /*
820 #i3958# We only export an empty dummy picture frame here, this is
821 what word does the escher export should contain an anchored to
822 character element which is drawn over this dummy and the whole
823 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
824 it's what word does.
825 */
826 {
827 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
828 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
829 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrameFormat(), 0x401);
830 }
831 break;
832 default:
833 OSL_ENSURE(false, "Some inline export not implemented");
834 break;
835 }
836
837 sal_uInt32 nPos2 = rStrm.Tell(); // store the end
838 rStrm.Seek( nPos );
839 rStrm.WriteUInt32(nPos2 - nPos); // patch graphic length in the header
840 rStrm.Seek( nPos2 ); // restore Pos
841}
842
843// SwWW8WrGrf::Write() is called after the text.
844// It writes out all the graphics and remembers the file locations of the graphics,
845// so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
846// The search in the attributes for the Magic sal_uLong and patching
847// happens when writing the attributes. Class SwWW8WrGrf provides with
848// GetFPos() sequentially the positions
850{
852 auto aEnd = maDetails.end();
853 for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
854 {
855 sal_uInt32 nPos = rStrm.Tell(); // align to 4 Bytes
856 if( nPos & 0x3 )
857 SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
858
859 auto aIter2 = std::find(maDetails.begin(), aIter, *aIter);
860 if (aIter2 != aIter)
861 {
862 aIter->mnPos = aIter2->mnPos;
863 }
864 else
865 {
866 aIter->mnPos = rStrm.Tell();
867 WriteGraphicNode(rStrm, *aIter);
868 }
869 }
870}
871
872/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr auto convertTwipToMm100(N n)
SvxBoxItemLine
static OutputDevice * GetDefaultDevice()
void WindStart()
const Size & GetPrefSize() const
void Play(GDIMetaFile &rMtf)
sal_uInt16 mnWid
Definition: wrtww8.hxx:1394
ww8::Frame maFly
Definition: wrtww8.hxx:1392
sal_uInt16 mnHei
Definition: wrtww8.hxx:1395
static GraphicFilter & GetGraphicFilter()
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
Size GetPrefSize() const
const GDIMetaFile & GetGDIMetaFile() const
virtual SwDrawModel * GetOrCreateDrawModel()=0
const sw::BroadcastingModify * m_pOutFormatNode
Definition: wrtww8.hxx:539
std::unique_ptr< SwWW8WrGrf > m_pGrf
Definition: wrtww8.hxx:537
const SfxPoolItem & GetItem(sal_uInt16 nWhich) const
Definition: wrtww8.cxx:784
std::optional< SvxMSExportOLEObjects > m_oOLEExp
Definition: wrtww8.hxx:475
WW8OleMap m_aOleMap
Definition: wrtww8.hxx:477
const ww8::Frame * m_pParentFrame
Definition: wrtww8.hxx:520
void OutputFormat(const SwFormat &rFormat, bool bPapFormat, bool bChpFormat, bool bFlyFormat=false)
Output attributes.
Definition: ww8atr.cxx:887
std::unique_ptr< WW8_WrPlcPn > m_pPapPlc
Definition: wrtww8.hxx:500
std::unique_ptr< WW8_WrPlcPn > m_pChpPlc
Definition: wrtww8.hxx:501
SwDoc & m_rDoc
Definition: wrtww8.hxx:576
const SfxPoolItem * GetCurItem() const
const SfxPoolItem * NextItem()
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
bool IsEmpty() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
static SotStorage * OpenOLEStorage(css::uno::Reference< css::embed::XStorage > const &xStorage, OUString const &rEleName, StreamMode=StreamMode::STD_READWRITE)
SotStorage * OpenSotStorage(const OUString &rEleName, StreamMode=StreamMode::STD_READWRITE, bool transacted=true)
SotStorage & GetStorage() const
Definition: shellio.hxx:494
sal_uInt64 Tell() const
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & WriteUChar(unsigned char nChar)
SvStream & WriteUInt32(sal_uInt32 nUInt32)
sal_uInt64 Seek(sal_uInt64 nPos)
sal_Int32 GetTop() const
sal_Int32 GetRight() const
sal_Int32 GetLeft() const
sal_Int32 GetBottom() const
static rtl::Reference< SdrOle2Obj > CreateSdrOLEFromStorage(SdrModel &rSdrModel, const OUString &rStorageName, tools::SvRef< SotStorage > const &rSrcStorage, const css::uno::Reference< css::embed::XStorage > &xDestStg, const Graphic &rGraf, const tools::Rectangle &rBoundRect, const tools::Rectangle &rVisArea, SvStream *pDataStrrm, ErrCode &rError, sal_uInt32 nConvertFlags, sal_Int64 nAspect, OUString const &rBaseURL)
tools::Long GetHeight() const
const SwFormatURL & GetURL(bool=true) const
Definition: fmturl.hxx:74
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:85
virtual void WritePictures()
Definition: wrtw8esh.cxx:2160
sal_Int32 WriteOLEFlyFrame(const SwFrameFormat &rFormat, sal_uInt32 nShapeId)
Definition: wrtw8esh.cxx:1775
void WriteEmptyFlyFrame(const SwFrameFormat &rFormat, sal_uInt32 nShapeId)
Definition: wrtw8esh.cxx:1530
sal_Int32 WriteGrfFlyFrame(const SwFrameFormat &rFormat, sal_uInt32 nShapeId)
Definition: wrtw8esh.cxx:1601
void WriteGrfBullet(const Graphic &)
Definition: wrtw8esh.cxx:1564
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:493
css::uno::Reference< css::embed::XStorage > GetDocStorage()
Definition: docnew.cxx:644
bool IsInVerticalText(const SwPosition &rPos) const
Definition: doclay.cxx:1693
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
Definition: doc.cxx:169
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:67
SfxPoolItem subclass that wraps a URL.
Definition: fmturl.hxx:33
const OUString & GetTargetFrameName() const
Definition: fmturl.hxx:64
const OUString & GetURL() const
Definition: fmturl.hxx:65
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:57
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:113
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
Style of a layout element.
Definition: frmfmt.hxx:72
bool IsLinkedFile() const
Definition: ndgrf.hxx:160
bool GetFileFilterNms(OUString *pFileNm, OUString *pFilterNm) const
Definition: ndgrf.cxx:470
Base class of the Writer document model elements.
Definition: node.hxx:98
SwGrfNode * GetGrfNode()
Definition: ndgrf.hxx:150
SwDoc & GetDoc()
Definition: node.hxx:233
SwOLENode * GetOLENode()
Inline methods from Node.hxx.
Definition: ndole.hxx:165
sal_Int64 GetAspect() const
Definition: ndole.hxx:140
const SwOLEObj & GetOLEObj() const
Definition: ndole.hxx:116
css::uno::Reference< css::embed::XEmbeddedObject > const & GetOleRef()
Definition: ndole.cxx:1012
static bool ImportOleWMF(const tools::SvRef< SotStorage > &xSrc1, GDIMetaFile &rWMF, tools::Long &rX, tools::Long &rY)
Definition: ww8par4.cxx:303
void WriteGraphicNode(SvStream &rStrm, const GraphicDetails &rItem)
Definition: wrtww8gr.cxx:744
void WriteGrfForBullet(SvStream &rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
Definition: wrtww8gr.cxx:736
void WriteGrfFromGrfNode(SvStream &rStrm, const SwGrfNode &rNd, const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
Definition: wrtww8gr.cxx:624
WW8Export & m_rWrt
for access to the variables
Definition: wrtww8.hxx:1415
static void WritePICBulletFHeader(SvStream &rStrm, const Graphic &rGrf, sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
Definition: wrtww8gr.cxx:650
void Write()
Definition: wrtww8gr.cxx:849
static void WritePICFHeader(SvStream &rStrm, const ww8::Frame &rFly, sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet *pAttrSet=nullptr)
Definition: wrtww8gr.cxx:474
std::vector< GraphicDetails > maDetails
Definition: wrtww8.hxx:1417
void Insert(const ww8::Frame &rFly)
Definition: wrtww8gr.cxx:466
static void InsUInt32(ww::bytes &rO, sal_uInt32 n)
Definition: wrtww8.cxx:1719
static void WriteString8(SvStream &rStrm, std::u16string_view rStr, bool bAddZero, rtl_TextEncoding eCodeSet)
Definition: wrtww8.cxx:1769
static void FillCount(SvStream &rStrm, sal_uLong nCount)
Definition: wrtww8.cxx:935
static void InsUInt16(ww::bytes &rO, sal_uInt16 n)
Definition: wrtww8.cxx:1711
SvStream & Strm() const
Definition: wrtww8.hxx:1189
virtual void OutputField(const SwField *pField, ww::eField eFieldType, const OUString &rFieldCmd, FieldFlags nMode=FieldFlags::All) override
Write the field.
Definition: ww8atr.cxx:1881
std::unique_ptr< WW8AttributeOutput > m_pAttrOutput
Converting attributes to stream data.
Definition: wrtww8.hxx:1013
virtual void OutputGrfNode(const SwGrfNode &) override
Output SwGrfNode.
Definition: wrtww8gr.cxx:75
void OutGrf(const ww8::Frame &rFrame)
Definition: wrtww8gr.cxx:353
SwWW8Writer * m_pWriter
Pointer to the writer.
Definition: wrtww8.hxx:1012
virtual void OutputOLENode(const SwOLENode &) override
Output SwOLENode.
Definition: wrtww8gr.cxx:193
void WriteChar(sal_Unicode c) override
Definition: wrtww8.cxx:1875
bool TestOleNeedsGraphic(const SwAttrSet &rSet, tools::SvRef< SotStorage > const &xOleStg, const tools::SvRef< SotStorage > &xObjStg, OUString const &rStorageName, SwOLENode *pOLENd)
Definition: wrtww8gr.cxx:86
SvStream * m_pDataStrm
Streams for WW97 Export.
Definition: wrtww8.hxx:1001
static WW8_BRCVer9 TranslateBorderLine(const ::editeng::SvxBorderLine &pLine, sal_uInt16 nDist, bool bShadow)
Definition: ww8atr.cxx:4584
std::unique_ptr< WW8Fib > m_pFib
File Information Block.
Definition: wrtww8.hxx:1003
virtual void OutputLinkedOLE(const OUString &) override
Definition: wrtww8gr.cxx:316
SwWW8Writer & GetWriter() const
Definition: wrtww8.hxx:1188
std::unique_ptr< ww::bytes > m_pO
Buffer.
Definition: wrtww8.hxx:999
virtual void WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner=ww8::WW8TableNodeInfoInner::Pointer_t()) override
Definition: wrtww8.cxx:1865
const OUString & GetBaseURL() const
Definition: shellio.hxx:443
css::uno::Reference< css::io::XInputStream > GetGraphicStream(const css::uno::Reference< css::embed::XEmbeddedObject > &, OUString *pMediaType=nullptr)
T * get() const
bool is() const
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
Make exporting a Writer Frame easy.
const Size & GetSize() const
The Size of the contained element.
bool HasGraphic() const
const Size & GetLayoutSize() const
The layout size of the contained element.
const Graphic & GetGraphic() const
WriterSource GetWriterType() const
Get the type of frame that this wraps.
const SwFrameFormat & GetFrameFormat() const
Get the writer SwFrameFormat that this object describes.
const SwNode * GetContent() const
Get the first node of content in the frame.
bool IsInline() const
Is this frame inline (as character)
float u
#define ERRCODE_NONE
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_FONTSIZE(8)
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
constexpr TypedWhichId< SvxShadowItem > RES_SHADOW(113)
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(108)
constexpr TypedWhichId< SwFormatAnchor > RES_ANCHOR(110)
constexpr TypedWhichId< SvxBoxItem > RES_BOX(112)
constexpr TypedWhichId< SwCropGrf > RES_GRFATR_CROPGRF(142)
constexpr TypedWhichId< SwFormatContent > RES_CNTNT(101)
sal_uInt16 nPos
#define SAL_INFO(area, stream)
constexpr OUStringLiteral aObjectPool
Definition: ww8scan.hxx:45
int i
void SvStream & rStrm
::Color BGRToRGB(sal_uInt32 nColour)
sal_uInt8 TransColToIco(const Color &rCol)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
const SvxPageUsage aArr[]
long Long
eINCLUDEPICTURE
std::vector< sal_uInt8 > bytes
Definition: types.hxx:29
static SfxItemSet & rSet
static constexpr sal_uInt16 val
Definition: sprmids.hxx:278
Marks a position in the document model.
Definition: pam.hxx:38
bool fShadow() const
Definition: ww8struc.hxx:329
sal_uInt8 brcType() const
Definition: ww8struc.hxx:325
bool fFrame() const
Definition: ww8struc.hxx:331
sal_uInt8 dptLineWidth() const
Definition: ww8struc.hxx:323
sal_uInt32 cv() const
Definition: ww8struc.hxx:321
sal_uInt8 dptSpace() const
Definition: ww8struc.hxx:327
SVBT16 aBits2
Definition: ww8struc.hxx:264
SVBT16 aBits1
Definition: ww8struc.hxx:263
short DetermineBorderProperties(short *pSpace) const
Definition: ww8scan.cxx:1364
RndStdIds
tools::Long SwTwips
Definition: swtypes.hxx:51
unsigned char sal_uInt8
#define SAL_MAX_INT32
VCL_DLLPUBLIC bool WriteWindowMetafileBits(SvStream &rStream, const GDIMetaFile &rMTF)
static sal_uInt8 nAttrMagicIdx
Definition: wrtww8.cxx:1602
#define GRF_MAGIC_321
Definition: wrtww8.hxx:138
OUString FieldString(ww::eField eIndex)
Definition: ww8atr.cxx:2799
void Set_UInt32(sal_uInt8 *&p, sal_uInt32 n)
Definition: ww8struc.hxx:53
void Set_UInt8(sal_uInt8 *&p, sal_uInt8 n)
Definition: ww8struc.hxx:41
void Set_UInt16(sal_uInt8 *&p, sal_uInt16 n)
Definition: ww8struc.hxx:47