xref: /core/sc/source/filter/excel/xiescher.cxx (revision 047eb23bb416d9ce63a8b0748b077f7302b1399a)
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 <xiescher.hxx>
21 
22 #include <com/sun/star/beans/NamedValue.hpp>
23 #include <com/sun/star/container/XIndexContainer.hpp>
24 #include <com/sun/star/container/XNameContainer.hpp>
25 #include <com/sun/star/embed/Aspects.hpp>
26 #include <com/sun/star/embed/XEmbeddedObject.hpp>
27 #include <com/sun/star/embed/XEmbedPersist.hpp>
28 #include <com/sun/star/awt/PushButtonType.hpp>
29 #include <com/sun/star/awt/ScrollBarOrientation.hpp>
30 #include <com/sun/star/awt/VisualEffect.hpp>
31 #include <com/sun/star/style/VerticalAlignment.hpp>
32 #include <com/sun/star/drawing/XControlShape.hpp>
33 #include <com/sun/star/form/XForm.hpp>
34 #include <com/sun/star/form/XFormsSupplier.hpp>
35 #include <com/sun/star/form/binding/XBindableValue.hpp>
36 #include <com/sun/star/form/binding/XValueBinding.hpp>
37 #include <com/sun/star/form/binding/XListEntrySink.hpp>
38 #include <com/sun/star/form/binding/XListEntrySource.hpp>
39 #include <com/sun/star/script/ScriptEventDescriptor.hpp>
40 #include <com/sun/star/script/XEventAttacherManager.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 
44 #include <sfx2/objsh.hxx>
45 #include <officecfg/Office/Common.hxx>
46 #include <unotools/moduleoptions.hxx>
47 #include <comphelper/configuration.hxx>
48 #include <vcl/dibtools.hxx>
49 #include <vcl/gdimtf.hxx>
50 #include <vcl/outdev.hxx>
51 #include <vcl/wmf.hxx>
52 #include <comphelper/classids.hxx>
53 #include <comphelper/documentinfo.hxx>
54 #include <o3tl/safeint.hxx>
55 #include <toolkit/helper/vclunohelper.hxx>
56 #include <basegfx/point/b2dpoint.hxx>
57 #include <basegfx/polygon/b2dpolygon.hxx>
58 #include <sal/log.hxx>
59 
60 #include <svx/svdopath.hxx>
61 #include <svx/svdocirc.hxx>
62 #include <svx/svdoedge.hxx>
63 #include <svx/svdogrp.hxx>
64 #include <svx/svdoashp.hxx>
65 #include <svx/svdograf.hxx>
66 #include <svx/svdoole2.hxx>
67 #include <svx/svdouno.hxx>
68 #include <svx/svdpage.hxx>
69 #include <editeng/editobj.hxx>
70 #include <editeng/outliner.hxx>
71 #include <editeng/outlobj.hxx>
72 #include <svx/svditer.hxx>
73 #include <editeng/writingmodeitem.hxx>
74 #include <svx/xlnclit.hxx>
75 #include <svx/xlndsit.hxx>
76 #include <svx/xlnedcit.hxx>
77 #include <svx/xlnedit.hxx>
78 #include <svx/xlnedwit.hxx>
79 #include <svx/xlnstcit.hxx>
80 #include <svx/xlnstit.hxx>
81 #include <svx/xlnstwit.hxx>
82 #include <svx/xlnwtit.hxx>
83 #include <svx/sdasitm.hxx>
84 #include <svx/sdshcitm.hxx>
85 #include <svx/sdshitm.hxx>
86 #include <svx/sdsxyitm.hxx>
87 #include <svx/sdtagitm.hxx>
88 #include <svx/sdtditm.hxx>
89 
90 #include <editeng/eeitem.hxx>
91 #include <svx/xflclit.hxx>
92 #include <sal/macros.h>
93 #include <editeng/adjustitem.hxx>
94 #include <svx/xfillit0.hxx>
95 #include <svx/xlineit0.hxx>
96 #include <svx/xlinjoit.hxx>
97 #include <svx/xlntrit.hxx>
98 #include <svx/xbtmpit.hxx>
99 #include <svx/xbitmap.hxx>
100 #include <svtools/embedhlp.hxx>
101 #include <sot/storage.hxx>
102 
103 #include <document.hxx>
104 #include <drwlayer.hxx>
105 #include <docsh.hxx>
106 #include <userdat.hxx>
107 #include <unonames.hxx>
108 #include <convuno.hxx>
109 #include <postit.hxx>
110 #include <globstr.hrc>
111 #include <scresid.hxx>
112 
113 #include <fprogressbar.hxx>
114 #include <xltracer.hxx>
115 #include <xistream.hxx>
116 #include <xihelper.hxx>
117 #include <xiformula.hxx>
118 #include <xilink.hxx>
119 #include <xistyle.hxx>
120 #include <xipage.hxx>
121 #include <xichart.hxx>
122 #include <xicontent.hxx>
123 #include <scextopt.hxx>
124 
125 #include <namebuff.hxx>
126 #include <sfx2/docfile.hxx>
127 #include <memory>
128 #include <numeric>
129 #include <string_view>
130 #include <utility>
131 
132 using namespace com::sun::star;
133 using ::com::sun::star::uno::Any;
134 using ::com::sun::star::beans::XPropertySet;
135 using ::com::sun::star::uno::Exception;
136 using ::com::sun::star::uno::Reference;
137 using ::com::sun::star::uno::Sequence;
138 using ::com::sun::star::uno::UNO_QUERY;
139 using ::com::sun::star::uno::UNO_QUERY_THROW;
140 using ::com::sun::star::uno::UNO_SET_THROW;
141 using ::com::sun::star::beans::NamedValue;
142 using ::com::sun::star::container::XIndexContainer;
143 using ::com::sun::star::container::XNameContainer;
144 using ::com::sun::star::frame::XModel;
145 using ::com::sun::star::awt::XControlModel;
146 using ::com::sun::star::embed::XEmbeddedObject;
147 using ::com::sun::star::embed::XEmbedPersist;
148 using ::com::sun::star::drawing::XControlShape;
149 using ::com::sun::star::drawing::XShape;
150 using ::com::sun::star::form::XFormComponent;
151 using ::com::sun::star::form::XFormsSupplier;
152 using ::com::sun::star::form::binding::XBindableValue;
153 using ::com::sun::star::form::binding::XValueBinding;
154 using ::com::sun::star::form::binding::XListEntrySink;
155 using ::com::sun::star::form::binding::XListEntrySource;
156 using ::com::sun::star::script::ScriptEventDescriptor;
157 using ::com::sun::star::script::XEventAttacherManager;
158 using ::com::sun::star::table::CellAddress;
159 using ::com::sun::star::table::CellRangeAddress;
160 
161 // Drawing objects ============================================================
162 
XclImpDrawObjBase(const XclImpRoot & rRoot)163 XclImpDrawObjBase::XclImpDrawObjBase( const XclImpRoot& rRoot ) :
164     XclImpRoot( rRoot ),
165     mnObjId( EXC_OBJ_INVALID_ID ),
166     mnTab( 0 ),
167     mnObjType( EXC_OBJTYPE_UNKNOWN ),
168     mnDffShapeId( 0 ),
169     mnDffFlags( ShapeFlag::NONE ),
170     mbHasAnchor( false ),
171     mbHidden( false ),
172     mbVisible( true ),
173     mbPrintable( true ),
174     mbAreaObj( false ),
175     mbAutoMargin( true ),
176     mbSimpleMacro( true ),
177     mbProcessSdr( true ),
178     mbInsertSdr( true ),
179     mbCustomDff( false ),
180     mbNotifyMacroEventRead( false )
181 {
182 }
183 
~XclImpDrawObjBase()184 XclImpDrawObjBase::~XclImpDrawObjBase()
185 {
186 }
187 
ReadObj3(const XclImpRoot & rRoot,XclImpStream & rStrm)188 XclImpDrawObjRef XclImpDrawObjBase::ReadObj3( const XclImpRoot& rRoot, XclImpStream& rStrm )
189 {
190     XclImpDrawObjRef xDrawObj;
191 
192     if( rStrm.GetRecLeft() >= 30 )
193     {
194         sal_uInt16 nObjType;
195         rStrm.Ignore( 4 );
196         nObjType = rStrm.ReaduInt16();
197         switch( nObjType )
198         {
199             case EXC_OBJTYPE_GROUP:         xDrawObj= std::make_shared<XclImpGroupObj>( rRoot );          break;
200             case EXC_OBJTYPE_LINE:          xDrawObj= std::make_shared<XclImpLineObj>( rRoot );           break;
201             case EXC_OBJTYPE_RECTANGLE:     xDrawObj= std::make_shared<XclImpRectObj>( rRoot );           break;
202             case EXC_OBJTYPE_OVAL:          xDrawObj= std::make_shared<XclImpOvalObj>( rRoot );           break;
203             case EXC_OBJTYPE_ARC:           xDrawObj= std::make_shared<XclImpArcObj>( rRoot );            break;
204             case EXC_OBJTYPE_CHART:         xDrawObj= std::make_shared<XclImpChartObj>( rRoot );          break;
205             case EXC_OBJTYPE_TEXT:          xDrawObj= std::make_shared<XclImpTextObj>( rRoot );           break;
206             case EXC_OBJTYPE_BUTTON:        xDrawObj= std::make_shared<XclImpButtonObj>( rRoot );         break;
207             case EXC_OBJTYPE_PICTURE:       xDrawObj= std::make_shared<XclImpPictureObj>( rRoot );        break;
208             default:
209                 SAL_WARN("sc.filter",  "XclImpDrawObjBase::ReadObj3 - unknown object type 0x" << std::hex << nObjType );
210                 rRoot.GetTracer().TraceUnsupportedObjects();
211         }
212     }
213 
214     if (!xDrawObj)
215     {
216         xDrawObj = std::make_shared<XclImpPhObj>(rRoot);
217     }
218 
219     xDrawObj->mnTab = rRoot.GetCurrScTab();
220     xDrawObj->ImplReadObj3( rStrm );
221     return xDrawObj;
222 }
223 
ReadObj4(const XclImpRoot & rRoot,XclImpStream & rStrm)224 XclImpDrawObjRef XclImpDrawObjBase::ReadObj4( const XclImpRoot& rRoot, XclImpStream& rStrm )
225 {
226     XclImpDrawObjRef xDrawObj;
227 
228     if( rStrm.GetRecLeft() >= 30 )
229     {
230         sal_uInt16 nObjType;
231         rStrm.Ignore( 4 );
232         nObjType = rStrm.ReaduInt16();
233         switch( nObjType )
234         {
235             case EXC_OBJTYPE_GROUP:         xDrawObj = std::make_shared<XclImpGroupObj>( rRoot );          break;
236             case EXC_OBJTYPE_LINE:          xDrawObj = std::make_shared<XclImpLineObj>( rRoot );           break;
237             case EXC_OBJTYPE_RECTANGLE:     xDrawObj = std::make_shared<XclImpRectObj>( rRoot );           break;
238             case EXC_OBJTYPE_OVAL:          xDrawObj = std::make_shared<XclImpOvalObj>( rRoot );           break;
239             case EXC_OBJTYPE_ARC:           xDrawObj = std::make_shared<XclImpArcObj>( rRoot );            break;
240             case EXC_OBJTYPE_CHART:         xDrawObj = std::make_shared<XclImpChartObj>( rRoot );          break;
241             case EXC_OBJTYPE_TEXT:          xDrawObj = std::make_shared<XclImpTextObj>( rRoot );           break;
242             case EXC_OBJTYPE_BUTTON:        xDrawObj = std::make_shared<XclImpButtonObj>( rRoot );         break;
243             case EXC_OBJTYPE_PICTURE:       xDrawObj = std::make_shared<XclImpPictureObj>( rRoot );        break;
244             case EXC_OBJTYPE_POLYGON:       xDrawObj = std::make_shared<XclImpPolygonObj>( rRoot );        break;
245             default:
246                 SAL_WARN("sc.filter",  "XclImpDrawObjBase::ReadObj4 - unknown object type 0x" << std::hex << nObjType );
247                 rRoot.GetTracer().TraceUnsupportedObjects();
248         }
249     }
250 
251     if (!xDrawObj)
252     {
253         xDrawObj = std::make_shared<XclImpPhObj>(rRoot);
254     }
255 
256     xDrawObj->mnTab = rRoot.GetCurrScTab();
257     xDrawObj->ImplReadObj4( rStrm );
258     return xDrawObj;
259 }
260 
ReadObj5(const XclImpRoot & rRoot,XclImpStream & rStrm)261 XclImpDrawObjRef XclImpDrawObjBase::ReadObj5( const XclImpRoot& rRoot, XclImpStream& rStrm )
262 {
263     XclImpDrawObjRef xDrawObj;
264 
265     if( rStrm.GetRecLeft() >= 34 )
266     {
267         sal_uInt16 nObjType(EXC_OBJTYPE_UNKNOWN);
268         rStrm.Ignore( 4 );
269         nObjType = rStrm.ReaduInt16();
270         switch( nObjType )
271         {
272             case EXC_OBJTYPE_GROUP:         xDrawObj = std::make_shared<XclImpGroupObj>( rRoot );          break;
273             case EXC_OBJTYPE_LINE:          xDrawObj = std::make_shared<XclImpLineObj>( rRoot );           break;
274             case EXC_OBJTYPE_RECTANGLE:     xDrawObj = std::make_shared<XclImpRectObj>( rRoot );           break;
275             case EXC_OBJTYPE_OVAL:          xDrawObj = std::make_shared<XclImpOvalObj>( rRoot );           break;
276             case EXC_OBJTYPE_ARC:           xDrawObj = std::make_shared<XclImpArcObj>( rRoot );            break;
277             case EXC_OBJTYPE_CHART:         xDrawObj = std::make_shared<XclImpChartObj>( rRoot );          break;
278             case EXC_OBJTYPE_TEXT:          xDrawObj = std::make_shared<XclImpTextObj>( rRoot );           break;
279             case EXC_OBJTYPE_BUTTON:        xDrawObj = std::make_shared<XclImpButtonObj>( rRoot );         break;
280             case EXC_OBJTYPE_PICTURE:       xDrawObj = std::make_shared<XclImpPictureObj>( rRoot );        break;
281             case EXC_OBJTYPE_POLYGON:       xDrawObj = std::make_shared<XclImpPolygonObj>( rRoot );        break;
282             case EXC_OBJTYPE_CHECKBOX:      xDrawObj = std::make_shared<XclImpCheckBoxObj>( rRoot );       break;
283             case EXC_OBJTYPE_OPTIONBUTTON:  xDrawObj = std::make_shared<XclImpOptionButtonObj>( rRoot );   break;
284             case EXC_OBJTYPE_EDIT:          xDrawObj = std::make_shared<XclImpEditObj>( rRoot );           break;
285             case EXC_OBJTYPE_LABEL:         xDrawObj = std::make_shared<XclImpLabelObj>( rRoot );          break;
286             case EXC_OBJTYPE_DIALOG:        xDrawObj = std::make_shared<XclImpDialogObj>( rRoot );         break;
287             case EXC_OBJTYPE_SPIN:          xDrawObj = std::make_shared<XclImpSpinButtonObj>( rRoot );     break;
288             case EXC_OBJTYPE_SCROLLBAR:     xDrawObj = std::make_shared<XclImpScrollBarObj>( rRoot );      break;
289             case EXC_OBJTYPE_LISTBOX:       xDrawObj = std::make_shared<XclImpListBoxObj>( rRoot );        break;
290             case EXC_OBJTYPE_GROUPBOX:      xDrawObj = std::make_shared<XclImpGroupBoxObj>( rRoot );       break;
291             case EXC_OBJTYPE_DROPDOWN:      xDrawObj = std::make_shared<XclImpDropDownObj>( rRoot );       break;
292             default:
293                 SAL_WARN("sc.filter",  "XclImpDrawObjBase::ReadObj5 - unknown object type 0x" << std::hex << nObjType );
294                 rRoot.GetTracer().TraceUnsupportedObjects();
295                 xDrawObj = std::make_shared<XclImpPhObj>( rRoot );
296         }
297     }
298 
299     OSL_ENSURE(xDrawObj, "object import failed");
300 
301     if (xDrawObj)
302     {
303         xDrawObj->mnTab = rRoot.GetCurrScTab();
304         xDrawObj->ImplReadObj5( rStrm );
305     }
306     return xDrawObj;
307 }
308 
ReadObj8(const XclImpRoot & rRoot,XclImpStream & rStrm)309 XclImpDrawObjRef XclImpDrawObjBase::ReadObj8( const XclImpRoot& rRoot, XclImpStream& rStrm )
310 {
311     XclImpDrawObjRef xDrawObj;
312 
313     if( rStrm.GetRecLeft() >= 10 )
314     {
315         sal_uInt16 nSubRecId(0), nSubRecSize(0), nObjType(0);
316         nSubRecId = rStrm.ReaduInt16();
317         nSubRecSize = rStrm.ReaduInt16();
318         nObjType = rStrm.ReaduInt16();
319         OSL_ENSURE( nSubRecId == EXC_ID_OBJCMO, "XclImpDrawObjBase::ReadObj8 - OBJCMO subrecord expected" );
320         if( (nSubRecId == EXC_ID_OBJCMO) && (nSubRecSize >= 6) )
321         {
322             switch( nObjType )
323             {
324                 // in BIFF8, all simple objects support text
325                 case EXC_OBJTYPE_LINE:
326                 case EXC_OBJTYPE_ARC:
327                     xDrawObj = std::make_shared<XclImpTextObj>( rRoot );
328                     // lines and arcs may be 2-dimensional
329                     xDrawObj->SetAreaObj( false );
330                 break;
331 
332                 // in BIFF8, all simple objects support text
333                 case EXC_OBJTYPE_RECTANGLE:
334                 case EXC_OBJTYPE_OVAL:
335                 case EXC_OBJTYPE_POLYGON:
336                 case EXC_OBJTYPE_DRAWING:
337                 case EXC_OBJTYPE_TEXT:
338                     xDrawObj = std::make_shared<XclImpTextObj>( rRoot );
339                 break;
340 
341                 case EXC_OBJTYPE_GROUP:         xDrawObj = std::make_shared<XclImpGroupObj>( rRoot );          break;
342                 case EXC_OBJTYPE_CHART:         xDrawObj = std::make_shared<XclImpChartObj>( rRoot );          break;
343                 case EXC_OBJTYPE_BUTTON:        xDrawObj = std::make_shared<XclImpButtonObj>( rRoot );         break;
344                 case EXC_OBJTYPE_PICTURE:       xDrawObj = std::make_shared<XclImpPictureObj>( rRoot );        break;
345                 case EXC_OBJTYPE_CHECKBOX:      xDrawObj = std::make_shared<XclImpCheckBoxObj>( rRoot );       break;
346                 case EXC_OBJTYPE_OPTIONBUTTON:  xDrawObj = std::make_shared<XclImpOptionButtonObj>( rRoot );   break;
347                 case EXC_OBJTYPE_EDIT:          xDrawObj = std::make_shared<XclImpEditObj>( rRoot );           break;
348                 case EXC_OBJTYPE_LABEL:         xDrawObj = std::make_shared<XclImpLabelObj>( rRoot );          break;
349                 case EXC_OBJTYPE_DIALOG:        xDrawObj = std::make_shared<XclImpDialogObj>( rRoot );         break;
350                 case EXC_OBJTYPE_SPIN:          xDrawObj = std::make_shared<XclImpSpinButtonObj>( rRoot );     break;
351                 case EXC_OBJTYPE_SCROLLBAR:     xDrawObj = std::make_shared<XclImpScrollBarObj>( rRoot );      break;
352                 case EXC_OBJTYPE_LISTBOX:       xDrawObj = std::make_shared<XclImpListBoxObj>( rRoot );        break;
353                 case EXC_OBJTYPE_GROUPBOX:      xDrawObj = std::make_shared<XclImpGroupBoxObj>( rRoot );       break;
354                 case EXC_OBJTYPE_DROPDOWN:      xDrawObj = std::make_shared<XclImpDropDownObj>( rRoot );       break;
355                 case EXC_OBJTYPE_NOTE:          xDrawObj = std::make_shared<XclImpNoteObj>( rRoot );           break;
356 
357                 default:
358                     SAL_WARN("sc.filter",  "XclImpDrawObjBase::ReadObj8 - unknown object type 0x" << std::hex << nObjType );
359                     rRoot.GetTracer().TraceUnsupportedObjects();
360             }
361         }
362     }
363 
364     if (!xDrawObj) //ensure placeholder for unknown or broken records
365     {
366         SAL_WARN( "sc.filter", "XclImpDrawObjBase::ReadObj8 import failed, substituting placeholder");
367         xDrawObj = std::make_shared<XclImpPhObj>( rRoot );
368     }
369 
370     xDrawObj->mnTab = rRoot.GetCurrScTab();
371     xDrawObj->ImplReadObj8( rStrm );
372     return xDrawObj;
373 }
374 
SetAnchor(const XclObjAnchor & rAnchor)375 void XclImpDrawObjBase::SetAnchor( const XclObjAnchor& rAnchor )
376 {
377     maAnchor = rAnchor;
378     mbHasAnchor = true;
379 }
380 
GetDffRect() const381 const tools::Rectangle& XclImpDrawObjBase::GetDffRect() const
382 {
383     return maDffRect;
384 }
385 
SetDffData(const DffObjData & rDffObjData,const OUString & rObjName,const OUString & rHyperlink,bool bVisible,bool bAutoMargin)386 void XclImpDrawObjBase::SetDffData(
387     const DffObjData& rDffObjData, const OUString& rObjName, const OUString& rHyperlink,
388     bool bVisible, bool bAutoMargin )
389 {
390     mnDffShapeId = rDffObjData.nShapeId;
391     mnDffFlags = rDffObjData.nSpFlags;
392     maObjName = rObjName;
393     maHyperlink = rHyperlink;
394     mbVisible = bVisible;
395     mbAutoMargin = bAutoMargin;
396     maDffRect = rDffObjData.aChildAnchor;
397 }
398 
GetObjName() const399 OUString XclImpDrawObjBase::GetObjName() const
400 {
401     /*  #i51348# Always return a non-empty name. Create English
402         default names depending on the object type. This is not implemented as
403         virtual functions in derived classes, as class type and object type may
404         not match. */
405     return maObjName.isEmpty() ? GetObjectManager().GetDefaultObjName(*this) : maObjName;
406 }
407 
GetAnchor() const408 const XclObjAnchor* XclImpDrawObjBase::GetAnchor() const
409 {
410     return mbHasAnchor ? &maAnchor : nullptr;
411 }
412 
IsValidSize(const tools::Rectangle & rAnchorRect) const413 bool XclImpDrawObjBase::IsValidSize( const tools::Rectangle& rAnchorRect ) const
414 {
415     // XclObjAnchor rounds up the width, width of 3 is the result of an Excel width of 0
416     return mbAreaObj ?
417         ((rAnchorRect.GetWidth() > 3) && (rAnchorRect.GetHeight() > 1)) :
418         ((rAnchorRect.GetWidth() > 3) || (rAnchorRect.GetHeight() > 1));
419 }
420 
GetUsedArea(SCTAB nScTab) const421 ScRange XclImpDrawObjBase::GetUsedArea( SCTAB nScTab ) const
422 {
423     ScRange aScUsedArea( ScAddress::INITIALIZE_INVALID );
424     // #i44077# object inserted -> update used area for OLE object import
425     if( mbHasAnchor && GetAddressConverter().ConvertRange( aScUsedArea, maAnchor, nScTab, nScTab, false ) )
426     {
427         // reduce range, if object ends directly on borders between two columns or rows
428         if( (maAnchor.mnRX == 0) && (aScUsedArea.aStart.Col() < aScUsedArea.aEnd.Col()) )
429             aScUsedArea.aEnd.IncCol( -1 );
430         if( (maAnchor.mnBY == 0) && (aScUsedArea.aStart.Row() < aScUsedArea.aEnd.Row()) )
431             aScUsedArea.aEnd.IncRow( -1 );
432     }
433     return aScUsedArea;
434 }
435 
GetProgressSize() const436 std::size_t XclImpDrawObjBase::GetProgressSize() const
437 {
438     return DoGetProgressSize();
439 }
440 
CreateSdrObject(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect,bool bIsDff) const441 rtl::Reference<SdrObject> XclImpDrawObjBase::CreateSdrObject( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect, bool bIsDff ) const
442 {
443     rtl::Reference<SdrObject> xSdrObj;
444     if( bIsDff && !mbCustomDff )
445     {
446         rDffConv.Progress( GetProgressSize() );
447     }
448     else
449     {
450         xSdrObj = DoCreateSdrObj( rDffConv, rAnchorRect );
451 
452         //added for exporting OCX control
453         /*  mnObjType value set should be as below table:
454                     0x0000      Group               0x0001      Line
455                     0x0002      Rectangle           0x0003      Oval
456                     0x0004      Arc                 0x0005      Chart
457                     0x0006      Text                    0x0009      Polygon
458                 +-----------------------------------------------------+
459         OCX ==>|    0x0008      Picture                                     |
460                 +-----------------------------------------------------+
461                 |   0x0007      Button                                      |
462                 |   0x000B      Checkbox            0x000C      Radio button    |
463                 |   0x000D      Edit box                0x000E      Label       |
464         TBX ==> |   0x000F      Dialog box          0x0010      Spin control    |
465                 |   0x0011      Scrollbar               0x0012      List            |
466                 |   0x0013      Group box           0x0014      Dropdown list   |
467                 +-----------------------------------------------------+
468                     0x0019      Note                0x001E      OfficeArt object
469         */
470         if( xSdrObj && xSdrObj->IsUnoObj() &&
471             ( (mnObjType < 25 && mnObjType > 10) || mnObjType == 7 || mnObjType == 8 ) )
472         {
473             SdrUnoObj* pSdrUnoObj = dynamic_cast< SdrUnoObj* >( xSdrObj.get() );
474             if( pSdrUnoObj != nullptr )
475             {
476                 const Reference< XControlModel >& xCtrlModel = pSdrUnoObj->GetUnoControlModel();
477                 Reference< XPropertySet > xPropSet(xCtrlModel,UNO_QUERY);
478                 static constexpr OUString sPropertyName(u"ControlTypeinMSO"_ustr);
479 
480                 enum { eCreateFromOffice = 0, eCreateFromMSTBXControl, eCreateFromMSOCXControl };
481 
482                 if( mnObjType == 7 || (mnObjType < 25 && mnObjType > 10) )//TBX
483                 {
484                     try
485                     {
486                         //Need summary type for export. Detail type(checkbox, button ...) has been contained by mnObjType
487                         const sal_Int16 nTBXControlType = eCreateFromMSTBXControl ;
488                         xPropSet->setPropertyValue(sPropertyName, Any(nTBXControlType));
489                     }
490                     catch(const Exception&)
491                     {
492                         SAL_WARN("sc.filter", "XclImpDrawObjBase::CreateSdrObject, this control can't be set the property ControlTypeinMSO!");
493                     }
494                 }
495                 if( mnObjType == 8 )//OCX
496                 {
497                     //Need summary type for export
498                     static constexpr OUStringLiteral sObjIdPropertyName(u"ObjIDinMSO");
499                     const XclImpPictureObj* const pObj = dynamic_cast< const XclImpPictureObj* const >(this);
500                     if( pObj != nullptr && pObj->IsOcxControl() )
501                     {
502                         try
503                         {
504                             const sal_Int16 nOCXControlType =  eCreateFromMSOCXControl;
505                             xPropSet->setPropertyValue(sPropertyName, Any(nOCXControlType));
506                             //Detail type(checkbox, button ...)
507                             xPropSet->setPropertyValue(sObjIdPropertyName, Any(sal_uInt16(mnObjId)));
508                         }
509                         catch(const Exception&)
510                         {
511                             SAL_WARN("sc.filter", "XclImpDrawObjBase::CreateSdrObject, this control can't be set the property ObjIDinMSO!");
512                         }
513                     }
514                 }
515 
516             }
517         }
518     }
519     return xSdrObj;
520 }
521 
NotifyMacroEventRead()522 void XclImpDrawObjBase::NotifyMacroEventRead()
523 {
524     if (mbNotifyMacroEventRead)
525         return;
526     ScDocShell* pDocShell = GetDocShell();
527     if (!pDocShell)
528         return;
529     comphelper::DocumentInfo::notifyMacroEventRead(pDocShell->GetModel());
530     mbNotifyMacroEventRead = true;
531 }
532 
PreProcessSdrObject(XclImpDffConverter & rDffConv,SdrObject & rSdrObj)533 void XclImpDrawObjBase::PreProcessSdrObject( XclImpDffConverter& rDffConv, SdrObject& rSdrObj )
534 {
535     // default: front layer, derived classes may have to set other layer in DoPreProcessSdrObj()
536     rSdrObj.NbcSetLayer( SC_LAYER_FRONT );
537 
538     // set object name (GetObjName() will always return a non-empty name)
539     rSdrObj.SetName( GetObjName() );
540 
541     // #i39167# full width for all objects regardless of horizontal alignment
542     rSdrObj.SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) );
543 
544     // automatic text margin
545     if( mbAutoMargin )
546     {
547         sal_Int32 nMargin = rDffConv.GetDefaultTextMargin();
548         rSdrObj.SetMergedItem( makeSdrTextLeftDistItem( nMargin ) );
549         rSdrObj.SetMergedItem( makeSdrTextRightDistItem( nMargin ) );
550         rSdrObj.SetMergedItem( makeSdrTextUpperDistItem( nMargin ) );
551         rSdrObj.SetMergedItem( makeSdrTextLowerDistItem( nMargin ) );
552     }
553 
554     // macro and hyperlink
555     // removed oracle/sun check for mbSimpleMacro ( no idea what its for )
556     if (!maMacroName.isEmpty())
557     {
558         if( ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( &rSdrObj, true ) )
559         {
560             OUString sMacro = XclTools::GetSbMacroUrl(maMacroName, GetDocShell());
561             if (!sMacro.isEmpty())
562                 NotifyMacroEventRead();
563             pInfo->SetMacro(sMacro);
564         }
565     }
566     if (!maHyperlink.isEmpty())
567         rSdrObj.setHyperlink(maHyperlink);
568 
569     // call virtual function for object type specific processing
570     DoPreProcessSdrObj( rDffConv, rSdrObj );
571 }
572 
PostProcessSdrObject(XclImpDffConverter & rDffConv,SdrObject & rSdrObj) const573 void XclImpDrawObjBase::PostProcessSdrObject( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
574 {
575     // call virtual function for object type specific processing
576     DoPostProcessSdrObj( rDffConv, rSdrObj );
577 }
578 
579 // protected ------------------------------------------------------------------
580 
ReadName5(XclImpStream & rStrm,sal_uInt16 nNameLen)581 void XclImpDrawObjBase::ReadName5( XclImpStream& rStrm, sal_uInt16 nNameLen )
582 {
583     maObjName.clear();
584     if( nNameLen > 0 )
585     {
586         // name length field is repeated before the name
587         maObjName = rStrm.ReadByteString( false );
588         // skip padding byte for word boundaries
589         if( rStrm.GetRecPos() & 1 ) rStrm.Ignore( 1 );
590     }
591 }
592 
ReadMacro3(XclImpStream & rStrm,sal_uInt16 nMacroSize)593 void XclImpDrawObjBase::ReadMacro3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
594 {
595     maMacroName.clear();
596     rStrm.Ignore( nMacroSize );
597     // skip padding byte for word boundaries, not contained in nMacroSize
598     if( rStrm.GetRecPos() & 1 ) rStrm.Ignore( 1 );
599 }
600 
ReadMacro4(XclImpStream & rStrm,sal_uInt16 nMacroSize)601 void XclImpDrawObjBase::ReadMacro4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
602 {
603     maMacroName.clear();
604     rStrm.Ignore( nMacroSize );
605 }
606 
ReadMacro5(XclImpStream & rStrm,sal_uInt16 nMacroSize)607 void XclImpDrawObjBase::ReadMacro5( XclImpStream& rStrm, sal_uInt16 nMacroSize )
608 {
609     maMacroName.clear();
610     rStrm.Ignore( nMacroSize );
611 }
612 
ReadMacro8(XclImpStream & rStrm)613 void XclImpDrawObjBase::ReadMacro8( XclImpStream& rStrm )
614 {
615     maMacroName.clear();
616     if( rStrm.GetRecLeft() <= 6 )
617         return;
618 
619     // macro is stored in a tNameXR token containing a link to a defined name
620     sal_uInt16 nFmlaSize;
621     nFmlaSize = rStrm.ReaduInt16();
622     rStrm.Ignore( 4 );
623     OSL_ENSURE( nFmlaSize == 7, "XclImpDrawObjBase::ReadMacro - unexpected formula size" );
624     if( nFmlaSize == 7 )
625     {
626         sal_uInt8 nTokenId;
627         sal_uInt16 nExtSheet, nExtName;
628         nTokenId = rStrm.ReaduInt8();
629         nExtSheet = rStrm.ReaduInt16();
630         nExtName = rStrm.ReaduInt16();
631         OSL_ENSURE( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ),
632             "XclImpDrawObjBase::ReadMacro - tNameXR token expected" );
633         if( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ) )
634             maMacroName = GetLinkManager().GetMacroName( nExtSheet, nExtName );
635     }
636 }
637 
ConvertLineStyle(SdrObject & rSdrObj,const XclObjLineData & rLineData) const638 void XclImpDrawObjBase::ConvertLineStyle( SdrObject& rSdrObj, const XclObjLineData& rLineData ) const
639 {
640     if( rLineData.IsAuto() )
641     {
642         XclObjLineData aAutoData;
643         aAutoData.mnAuto = 0;
644         ConvertLineStyle( rSdrObj, aAutoData );
645     }
646     else
647     {
648         tools::Long nLineWidth = 35 * ::std::min( rLineData.mnWidth, EXC_OBJ_LINE_THICK );
649         rSdrObj.SetMergedItem( XLineWidthItem( nLineWidth ) );
650         rSdrObj.SetMergedItem( XLineColorItem( OUString(), GetPalette().GetColor( rLineData.mnColorIdx ) ) );
651         rSdrObj.SetMergedItem( XLineJointItem( css::drawing::LineJoint_MITER ) );
652 
653         sal_uLong nDotLen = ::std::max< sal_uLong >( 70 * rLineData.mnWidth, 35 );
654         sal_uLong nDashLen = 3 * nDotLen;
655         sal_uLong nDist = 2 * nDotLen;
656 
657         switch( rLineData.mnStyle )
658         {
659             default:
660             case EXC_OBJ_LINE_SOLID:
661                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_SOLID ) );
662             break;
663             case EXC_OBJ_LINE_DASH:
664                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_DASH ) );
665                 rSdrObj.SetMergedItem( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECT, 0, nDotLen, 1, nDashLen, nDist ) ) );
666             break;
667             case EXC_OBJ_LINE_DOT:
668                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_DASH ) );
669                 rSdrObj.SetMergedItem( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECT, 1, nDotLen, 0, nDashLen, nDist ) ) );
670             break;
671             case EXC_OBJ_LINE_DASHDOT:
672                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_DASH ) );
673                 rSdrObj.SetMergedItem( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECT, 1, nDotLen, 1, nDashLen, nDist ) ) );
674             break;
675             case EXC_OBJ_LINE_DASHDOTDOT:
676                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_DASH ) );
677                 rSdrObj.SetMergedItem( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECT, 2, nDotLen, 1, nDashLen, nDist ) ) );
678             break;
679             case EXC_OBJ_LINE_MEDTRANS:
680                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_SOLID ) );
681                 rSdrObj.SetMergedItem( XLineTransparenceItem( 50 ) );
682             break;
683             case EXC_OBJ_LINE_DARKTRANS:
684                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_SOLID ) );
685                 rSdrObj.SetMergedItem( XLineTransparenceItem( 25 ) );
686             break;
687             case EXC_OBJ_LINE_LIGHTTRANS:
688                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_SOLID ) );
689                 rSdrObj.SetMergedItem( XLineTransparenceItem( 75 ) );
690             break;
691             case EXC_OBJ_LINE_NONE:
692                 rSdrObj.SetMergedItem( XLineStyleItem( drawing::LineStyle_NONE ) );
693             break;
694         }
695     }
696 }
697 
ConvertFillStyle(SdrObject & rSdrObj,const XclObjFillData & rFillData) const698 void XclImpDrawObjBase::ConvertFillStyle( SdrObject& rSdrObj, const XclObjFillData& rFillData ) const
699 {
700     if( rFillData.IsAuto() )
701     {
702         XclObjFillData aAutoData;
703         aAutoData.mnAuto = 0;
704         ConvertFillStyle( rSdrObj, aAutoData );
705     }
706     else if( rFillData.mnPattern == EXC_PATT_NONE )
707     {
708         rSdrObj.SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
709     }
710     else
711     {
712         Color aPattColor = GetPalette().GetColor( rFillData.mnPattColorIdx );
713         Color aBackColor = GetPalette().GetColor( rFillData.mnBackColorIdx );
714         if( (rFillData.mnPattern == EXC_PATT_SOLID) || (aPattColor == aBackColor) )
715         {
716             rSdrObj.SetMergedItem( XFillStyleItem( drawing::FillStyle_SOLID ) );
717             rSdrObj.SetMergedItem( XFillColorItem( OUString(), aPattColor ) );
718         }
719         else
720         {
721             static const sal_uInt8 sppnPatterns[][ 8 ] =
722             {
723                 { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 },
724                 { 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD },
725                 { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 },
726                 { 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 },
727                 { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC },
728                 { 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99 },
729                 { 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x33, 0x99 },
730                 { 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33 },
731                 { 0xCC, 0xFF, 0x33, 0xFF, 0xCC, 0xFF, 0x33, 0xFF },
732                 { 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 },
733                 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 },
734                 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 },
735                 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 },
736                 { 0xFF, 0x11, 0x11, 0x11, 0xFF, 0x11, 0x11, 0x11 },
737                 { 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11 },
738                 { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
739                 { 0x80, 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00 }
740             };
741             const sal_uInt8* const pnPattern = sppnPatterns[std::min<size_t>(rFillData.mnPattern - 2, SAL_N_ELEMENTS(sppnPatterns) - 1)];
742             // create 2-colored 8x8 DIB
743             SvMemoryStream aMemStrm;
744             aMemStrm.WriteUInt32( 12 ).WriteInt16( 8 ).WriteInt16( 8 ).WriteUInt16( 1 ).WriteUInt16( 1 );
745             aMemStrm.WriteUChar( 0xFF ).WriteUChar( 0xFF ).WriteUChar( 0xFF );
746             aMemStrm.WriteUChar( 0x00 ).WriteUChar( 0x00 ).WriteUChar( 0x00 );
747             for( size_t nIdx = 0; nIdx < 8; ++nIdx )
748                 aMemStrm.WriteUInt32( pnPattern[ nIdx ] ); // 32-bit little-endian
749             aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
750             Bitmap aBitmap;
751             (void)ReadDIB(aBitmap, aMemStrm, false);
752 
753             XOBitmap aXOBitmap( aBitmap );
754             aXOBitmap.Bitmap2Array();
755             if( aXOBitmap.GetBackgroundColor() == COL_BLACK )
756                 ::std::swap( aPattColor, aBackColor );
757             aXOBitmap.SetPixelColor( aPattColor );
758             aXOBitmap.SetBackgroundColor( aBackColor );
759             aXOBitmap.Array2Bitmap();
760             aBitmap = aXOBitmap.GetBitmap();
761 
762             rSdrObj.SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
763             rSdrObj.SetMergedItem(XFillBitmapItem(OUString(), Graphic(BitmapEx(aBitmap))));
764         }
765     }
766 }
767 
ConvertFrameStyle(SdrObject & rSdrObj,sal_uInt16 nFrameFlags) const768 void XclImpDrawObjBase::ConvertFrameStyle( SdrObject& rSdrObj, sal_uInt16 nFrameFlags ) const
769 {
770     if( ::get_flag( nFrameFlags, EXC_OBJ_FRAME_SHADOW ) )
771     {
772         rSdrObj.SetMergedItem( makeSdrShadowItem( true ) );
773         rSdrObj.SetMergedItem( makeSdrShadowXDistItem( 35 ) );
774         rSdrObj.SetMergedItem( makeSdrShadowYDistItem( 35 ) );
775         rSdrObj.SetMergedItem( makeSdrShadowColorItem( GetPalette().GetColor( EXC_COLOR_WINDOWTEXT ) ) );
776     }
777 }
778 
GetSolidLineColor(const XclObjLineData & rLineData) const779 Color XclImpDrawObjBase::GetSolidLineColor( const XclObjLineData& rLineData ) const
780 {
781     Color aColor( COL_TRANSPARENT );
782     if( rLineData.IsAuto() )
783     {
784         XclObjLineData aAutoData;
785         aAutoData.mnAuto = 0;
786         aColor = GetSolidLineColor( aAutoData );
787     }
788     else if( rLineData.mnStyle != EXC_OBJ_LINE_NONE )
789     {
790         aColor = GetPalette().GetColor( rLineData.mnColorIdx );
791     }
792     return aColor;
793 }
794 
GetSolidFillColor(const XclObjFillData & rFillData) const795 Color XclImpDrawObjBase::GetSolidFillColor( const XclObjFillData& rFillData ) const
796 {
797     Color aColor( COL_TRANSPARENT );
798     if( rFillData.IsAuto() )
799     {
800         XclObjFillData aAutoData;
801         aAutoData.mnAuto = 0;
802         aColor = GetSolidFillColor( aAutoData );
803     }
804     else if( rFillData.mnPattern != EXC_PATT_NONE )
805     {
806         Color aPattColor = GetPalette().GetColor( rFillData.mnPattColorIdx );
807         Color aBackColor = GetPalette().GetColor( rFillData.mnBackColorIdx );
808         aColor = XclTools::GetPatternColor( aPattColor, aBackColor, rFillData.mnPattern );
809     }
810     return aColor;
811 }
812 
DoReadObj3(XclImpStream &,sal_uInt16)813 void XclImpDrawObjBase::DoReadObj3( XclImpStream&, sal_uInt16 )
814 {
815 }
816 
DoReadObj4(XclImpStream &,sal_uInt16)817 void XclImpDrawObjBase::DoReadObj4( XclImpStream&, sal_uInt16 )
818 {
819 }
820 
DoReadObj5(XclImpStream &,sal_uInt16,sal_uInt16)821 void XclImpDrawObjBase::DoReadObj5( XclImpStream&, sal_uInt16, sal_uInt16 )
822 {
823 }
824 
DoReadObj8SubRec(XclImpStream &,sal_uInt16,sal_uInt16)825 void XclImpDrawObjBase::DoReadObj8SubRec( XclImpStream&, sal_uInt16, sal_uInt16 )
826 {
827 }
828 
DoGetProgressSize() const829 std::size_t XclImpDrawObjBase::DoGetProgressSize() const
830 {
831     return 1;
832 }
833 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle &) const834 rtl::Reference<SdrObject> XclImpDrawObjBase::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& ) const
835 {
836     rDffConv.Progress( GetProgressSize() );
837     return nullptr;
838 }
839 
DoPreProcessSdrObj(XclImpDffConverter &,SdrObject &) const840 void XclImpDrawObjBase::DoPreProcessSdrObj( XclImpDffConverter&, SdrObject& ) const
841 {
842     // trace if object is not printable
843     if( !IsPrintable() )
844         GetTracer().TraceObjectNotPrintable();
845 }
846 
DoPostProcessSdrObj(XclImpDffConverter &,SdrObject &) const847 void XclImpDrawObjBase::DoPostProcessSdrObj( XclImpDffConverter&, SdrObject& ) const
848 {
849 }
850 
ImplReadObj3(XclImpStream & rStrm)851 void XclImpDrawObjBase::ImplReadObj3( XclImpStream& rStrm )
852 {
853     // back to offset 4 (ignore object count field)
854     rStrm.Seek( 4 );
855 
856     sal_uInt16 nObjFlags, nMacroSize;
857     mnObjType = rStrm.ReaduInt16();
858     mnObjId = rStrm.ReaduInt16();
859     nObjFlags = rStrm.ReaduInt16();
860     rStrm >> maAnchor;
861     nMacroSize = rStrm.ReaduInt16();
862     rStrm.Ignore( 2 );
863 
864     mbHasAnchor = true;
865     mbHidden = ::get_flag( nObjFlags, EXC_OBJ_HIDDEN );
866     mbVisible = ::get_flag( nObjFlags, EXC_OBJ_VISIBLE );
867     DoReadObj3( rStrm, nMacroSize );
868 }
869 
ImplReadObj4(XclImpStream & rStrm)870 void XclImpDrawObjBase::ImplReadObj4( XclImpStream& rStrm )
871 {
872     // back to offset 4 (ignore object count field)
873     rStrm.Seek( 4 );
874 
875     sal_uInt16 nObjFlags, nMacroSize;
876     mnObjType = rStrm.ReaduInt16();
877     mnObjId = rStrm.ReaduInt16();
878     nObjFlags = rStrm.ReaduInt16();
879     rStrm >> maAnchor;
880     nMacroSize = rStrm.ReaduInt16();
881     rStrm.Ignore( 2 );
882 
883     mbHasAnchor = true;
884     mbHidden = ::get_flag( nObjFlags, EXC_OBJ_HIDDEN );
885     mbVisible = ::get_flag( nObjFlags, EXC_OBJ_VISIBLE );
886     mbPrintable = ::get_flag( nObjFlags, EXC_OBJ_PRINTABLE );
887     DoReadObj4( rStrm, nMacroSize );
888 }
889 
ImplReadObj5(XclImpStream & rStrm)890 void XclImpDrawObjBase::ImplReadObj5( XclImpStream& rStrm )
891 {
892     // back to offset 4 (ignore object count field)
893     rStrm.Seek( 4 );
894 
895     sal_uInt16 nObjFlags, nMacroSize, nNameLen;
896     mnObjType = rStrm.ReaduInt16();
897     mnObjId = rStrm.ReaduInt16();
898     nObjFlags = rStrm.ReaduInt16();
899     rStrm >> maAnchor;
900     nMacroSize = rStrm.ReaduInt16();
901     rStrm.Ignore( 2 );
902     nNameLen = rStrm.ReaduInt16();
903     rStrm.Ignore( 2 );
904 
905     mbHasAnchor = true;
906     mbHidden = ::get_flag( nObjFlags, EXC_OBJ_HIDDEN );
907     mbVisible = ::get_flag( nObjFlags, EXC_OBJ_VISIBLE );
908     mbPrintable = ::get_flag( nObjFlags, EXC_OBJ_PRINTABLE );
909     DoReadObj5( rStrm, nNameLen, nMacroSize );
910 }
911 
ImplReadObj8(XclImpStream & rStrm)912 void XclImpDrawObjBase::ImplReadObj8( XclImpStream& rStrm )
913 {
914     // back to beginning
915     rStrm.Seek( EXC_REC_SEEK_TO_BEGIN );
916 
917     bool bLoop = true;
918     while (bLoop)
919     {
920         if (rStrm.GetRecLeft() < 4)
921             break;
922 
923         sal_uInt16 nSubRecId = rStrm.ReaduInt16();
924         sal_uInt16 nSubRecSize = rStrm.ReaduInt16();
925         rStrm.PushPosition();
926         // sometimes the last subrecord has an invalid length (OBJLBSDATA) -> min()
927         nSubRecSize = static_cast< sal_uInt16 >( ::std::min< std::size_t >( nSubRecSize, rStrm.GetRecLeft() ) );
928 
929         switch( nSubRecId )
930         {
931             case EXC_ID_OBJCMO:
932                 OSL_ENSURE( rStrm.GetRecPos() == 4, "XclImpDrawObjBase::ImplReadObj8 - unexpected OBJCMO subrecord" );
933                 if( (rStrm.GetRecPos() == 4) && (nSubRecSize >= 6) )
934                 {
935                     sal_uInt16 nObjFlags;
936                     mnObjType = rStrm.ReaduInt16();
937                     mnObjId = rStrm.ReaduInt16(  );
938                     nObjFlags = rStrm.ReaduInt16(  );
939                     mbPrintable = ::get_flag( nObjFlags, EXC_OBJCMO_PRINTABLE );
940                 }
941             break;
942             case EXC_ID_OBJMACRO:
943                 ReadMacro8( rStrm );
944             break;
945             case EXC_ID_OBJEND:
946                 bLoop = false;
947             break;
948             default:
949                 DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
950         }
951 
952         rStrm.PopPosition();
953         rStrm.Ignore( nSubRecSize );
954     }
955 
956     /*  Call DoReadObj8SubRec() with EXC_ID_OBJEND for further stream
957         processing (e.g. charts), even if the OBJEND subrecord is missing. */
958     DoReadObj8SubRec( rStrm, EXC_ID_OBJEND, 0 );
959 
960     /*  Pictures that Excel reads from BIFF5 and writes to BIFF8 still have the
961         IMGDATA record following the OBJ record (but they use the image data
962         stored in DFF). The IMGDATA record may be continued by several CONTINUE
963         records. But the last CONTINUE record may be in fact an MSODRAWING
964         record that contains the DFF data of the next drawing object! So we
965         have to skip just enough CONTINUE records to look at the next
966         MSODRAWING/CONTINUE record. */
967     if( !((rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord()) )
968         return;
969 
970     rStrm.Ignore( 4 );
971     sal_uInt32 nDataSize = rStrm.ReaduInt32();
972     nDataSize -= rStrm.GetRecLeft();
973     // skip following CONTINUE records until IMGDATA ends
974     while (true)
975     {
976         if (!nDataSize)
977             break;
978         if (rStrm.GetNextRecId() != EXC_ID_CONT)
979             break;
980         if (!rStrm.StartNextRecord())
981             break;
982         OSL_ENSURE( nDataSize >= rStrm.GetRecLeft(), "XclImpDrawObjBase::ImplReadObj8 - CONTINUE too long" );
983         nDataSize -= ::std::min< sal_uInt32 >( rStrm.GetRecLeft(), nDataSize );
984     }
985     OSL_ENSURE( nDataSize == 0, "XclImpDrawObjBase::ImplReadObj8 - missing CONTINUE records" );
986     // next record may be MSODRAWING or CONTINUE or anything else
987 }
988 
InsertGrouped(XclImpDrawObjRef const & xDrawObj)989 void XclImpDrawObjVector::InsertGrouped( XclImpDrawObjRef const & xDrawObj )
990 {
991     if( !mObjs.empty() )
992         if( XclImpGroupObj* pGroupObj = dynamic_cast< XclImpGroupObj* >( mObjs.back().get() ) )
993             if( pGroupObj->TryInsert( xDrawObj ) )
994                 return;
995     mObjs.push_back( xDrawObj );
996 }
997 
GetProgressSize() const998 std::size_t XclImpDrawObjVector::GetProgressSize() const
999 {
1000     return std::accumulate(mObjs.begin(), mObjs.end(), std::size_t(0),
1001         [](const std::size_t& rSum, const XclImpDrawObjRef& rxObj) { return rSum + rxObj->GetProgressSize(); });
1002 }
1003 
XclImpPhObj(const XclImpRoot & rRoot)1004 XclImpPhObj::XclImpPhObj( const XclImpRoot& rRoot ) :
1005     XclImpDrawObjBase( rRoot )
1006 {
1007     SetProcessSdrObj( false );
1008 }
1009 
XclImpGroupObj(const XclImpRoot & rRoot)1010 XclImpGroupObj::XclImpGroupObj( const XclImpRoot& rRoot ) :
1011     XclImpDrawObjBase( rRoot ),
1012     mnFirstUngrouped( 0 )
1013 {
1014 }
1015 
TryInsert(XclImpDrawObjRef const & xDrawObj)1016 bool XclImpGroupObj::TryInsert( XclImpDrawObjRef const & xDrawObj )
1017 {
1018     if( xDrawObj->GetObjId() == mnFirstUngrouped )
1019         return false;
1020     // insert into own list or into nested group
1021     maChildren.InsertGrouped( xDrawObj );
1022     return true;
1023 }
1024 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)1025 void XclImpGroupObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1026 {
1027     rStrm.Ignore( 4 );
1028     mnFirstUngrouped = rStrm.ReaduInt16();
1029     rStrm.Ignore( 16 );
1030     ReadMacro3( rStrm, nMacroSize );
1031 }
1032 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1033 void XclImpGroupObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1034 {
1035     rStrm.Ignore( 4 );
1036     mnFirstUngrouped = rStrm.ReaduInt16();
1037     rStrm.Ignore( 16 );
1038     ReadMacro4( rStrm, nMacroSize );
1039 }
1040 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1041 void XclImpGroupObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1042 {
1043     rStrm.Ignore( 4 );
1044     mnFirstUngrouped = rStrm.ReaduInt16();
1045     rStrm.Ignore( 16 );
1046     ReadName5( rStrm, nNameLen );
1047     ReadMacro5( rStrm, nMacroSize );
1048 }
1049 
DoGetProgressSize() const1050 std::size_t XclImpGroupObj::DoGetProgressSize() const
1051 {
1052     return XclImpDrawObjBase::DoGetProgressSize() + maChildren.GetProgressSize();
1053 }
1054 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle &) const1055 rtl::Reference<SdrObject> XclImpGroupObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& /*rAnchorRect*/ ) const
1056 {
1057     rtl::Reference<SdrObjGroup> xSdrObj(
1058         new SdrObjGroup(
1059             *GetDoc().GetDrawLayer()));
1060     // child objects in BIFF2-BIFF5 have absolute size, not needed to pass own anchor rectangle
1061     SdrObjList& rObjList = *xSdrObj->GetSubList();  // SdrObjGroup always returns existing sublist
1062     for( const auto& rxChild : maChildren )
1063         rDffConv.ProcessObject( rObjList, *rxChild );
1064     rDffConv.Progress();
1065     return xSdrObj;
1066 }
1067 
XclImpLineObj(const XclImpRoot & rRoot)1068 XclImpLineObj::XclImpLineObj( const XclImpRoot& rRoot ) :
1069     XclImpDrawObjBase( rRoot ),
1070     mnArrows( 0 ),
1071     mnStartPoint( EXC_OBJ_LINE_TL )
1072 {
1073     SetAreaObj( false );
1074 }
1075 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)1076 void XclImpLineObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1077 {
1078     rStrm >> maLineData;
1079     mnArrows = rStrm.ReaduInt16();
1080     mnStartPoint = rStrm.ReaduInt8();
1081     rStrm.Ignore( 1 );
1082     ReadMacro3( rStrm, nMacroSize );
1083 }
1084 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1085 void XclImpLineObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1086 {
1087     rStrm >> maLineData;
1088     mnArrows = rStrm.ReaduInt16();
1089     mnStartPoint = rStrm.ReaduInt8();
1090     rStrm.Ignore( 1 );
1091     ReadMacro4( rStrm, nMacroSize );
1092 }
1093 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1094 void XclImpLineObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1095 {
1096     rStrm >> maLineData;
1097     mnArrows = rStrm.ReaduInt16();
1098     mnStartPoint = rStrm.ReaduInt8();
1099     rStrm.Ignore( 1 );
1100     ReadName5( rStrm, nNameLen );
1101     ReadMacro5( rStrm, nMacroSize );
1102 }
1103 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1104 rtl::Reference<SdrObject> XclImpLineObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1105 {
1106     ::basegfx::B2DPolygon aB2DPolygon;
1107     switch( mnStartPoint )
1108     {
1109         default:
1110         case EXC_OBJ_LINE_TL:
1111             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Top() ) );
1112             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Bottom() ) );
1113         break;
1114         case EXC_OBJ_LINE_TR:
1115             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Top() ) );
1116             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Bottom() ) );
1117         break;
1118         case EXC_OBJ_LINE_BR:
1119             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Bottom() ) );
1120             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Top() ) );
1121         break;
1122         case EXC_OBJ_LINE_BL:
1123             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Left(), rAnchorRect.Bottom() ) );
1124             aB2DPolygon.append( ::basegfx::B2DPoint( rAnchorRect.Right(), rAnchorRect.Top() ) );
1125         break;
1126     }
1127     rtl::Reference<SdrObject> xSdrObj(
1128         new SdrPathObj(
1129             *GetDoc().GetDrawLayer(),
1130             SdrObjKind::Line,
1131             ::basegfx::B2DPolyPolygon(aB2DPolygon)));
1132     ConvertLineStyle( *xSdrObj, maLineData );
1133 
1134     // line ends
1135     sal_uInt8 nArrowType = ::extract_value< sal_uInt8 >( mnArrows, 0, 4 );
1136     bool bLineStart = false;
1137     bool bLineEnd = false;
1138     bool bFilled = false;
1139     switch( nArrowType )
1140     {
1141         case EXC_OBJ_ARROW_OPEN:        bLineStart = false; bLineEnd = true;  bFilled = false;  break;
1142         case EXC_OBJ_ARROW_OPENBOTH:    bLineStart = true;  bLineEnd = true;  bFilled = false;  break;
1143         case EXC_OBJ_ARROW_FILLED:      bLineStart = false; bLineEnd = true;  bFilled = true;   break;
1144         case EXC_OBJ_ARROW_FILLEDBOTH:  bLineStart = true;  bLineEnd = true;  bFilled = true;   break;
1145     }
1146     if( bLineStart || bLineEnd )
1147     {
1148         sal_uInt8 nArrowWidth = ::extract_value< sal_uInt8 >( mnArrows, 4, 4 );
1149         double fArrowWidth = 3.0;
1150         switch( nArrowWidth )
1151         {
1152             case EXC_OBJ_ARROW_NARROW:  fArrowWidth = 2.0;  break;
1153             case EXC_OBJ_ARROW_MEDIUM:  fArrowWidth = 3.0;  break;
1154             case EXC_OBJ_ARROW_WIDE:    fArrowWidth = 5.0;  break;
1155         }
1156 
1157         sal_uInt8 nArrowLength = ::extract_value< sal_uInt8 >( mnArrows, 8, 4 );
1158         double fArrowLength = 3.0;
1159         switch( nArrowLength )
1160         {
1161             case EXC_OBJ_ARROW_NARROW:  fArrowLength = 2.5; break;
1162             case EXC_OBJ_ARROW_MEDIUM:  fArrowLength = 3.5; break;
1163             case EXC_OBJ_ARROW_WIDE:    fArrowLength = 6.0; break;
1164         }
1165 
1166         ::basegfx::B2DPolygon aArrowPoly;
1167 #define EXC_ARROW_POINT( x, y ) ::basegfx::B2DPoint( fArrowWidth * (x), fArrowLength * (y) )
1168         if( bFilled )
1169         {
1170             aArrowPoly.append( EXC_ARROW_POINT(   0, 100 ) );
1171             aArrowPoly.append( EXC_ARROW_POINT(  50,   0 ) );
1172             aArrowPoly.append( EXC_ARROW_POINT( 100, 100 ) );
1173         }
1174         else
1175         {
1176             sal_uInt8 nLineWidth = ::limit_cast< sal_uInt8 >( maLineData.mnWidth, EXC_OBJ_LINE_THIN, EXC_OBJ_LINE_THICK );
1177             aArrowPoly.append( EXC_ARROW_POINT( 50, 0 ) );
1178             aArrowPoly.append( EXC_ARROW_POINT( 100, 100 - 3 * nLineWidth ) );
1179             aArrowPoly.append( EXC_ARROW_POINT( 100 - 5 * nLineWidth, 100 ) );
1180             aArrowPoly.append( EXC_ARROW_POINT( 50, 12 * nLineWidth ) );
1181             aArrowPoly.append( EXC_ARROW_POINT( 5 * nLineWidth, 100 ) );
1182             aArrowPoly.append( EXC_ARROW_POINT( 0, 100 - 3 * nLineWidth ) );
1183         }
1184 #undef EXC_ARROW_POINT
1185 
1186         tools::Long nWidth = static_cast< tools::Long >( 125 * fArrowWidth );
1187         if( bLineStart )
1188         {
1189             xSdrObj->SetMergedItem( XLineStartItem( OUString(), basegfx::B2DPolyPolygon(aArrowPoly) ) );
1190             xSdrObj->SetMergedItem( XLineStartWidthItem( nWidth ) );
1191             xSdrObj->SetMergedItem( XLineStartCenterItem( false ) );
1192         }
1193         if( bLineEnd )
1194         {
1195             xSdrObj->SetMergedItem( XLineEndItem( OUString(), basegfx::B2DPolyPolygon(aArrowPoly) ) );
1196             xSdrObj->SetMergedItem( XLineEndWidthItem( nWidth ) );
1197             xSdrObj->SetMergedItem( XLineEndCenterItem( false ) );
1198         }
1199     }
1200     rDffConv.Progress();
1201     return xSdrObj;
1202 }
1203 
XclImpRectObj(const XclImpRoot & rRoot)1204 XclImpRectObj::XclImpRectObj( const XclImpRoot& rRoot ) :
1205     XclImpDrawObjBase( rRoot ),
1206     mnFrameFlags( 0 )
1207 {
1208     SetAreaObj( true );
1209 }
1210 
ReadFrameData(XclImpStream & rStrm)1211 void XclImpRectObj::ReadFrameData( XclImpStream& rStrm )
1212 {
1213     rStrm >> maFillData >> maLineData;
1214     mnFrameFlags = rStrm.ReaduInt16();
1215 }
1216 
ConvertRectStyle(SdrObject & rSdrObj) const1217 void XclImpRectObj::ConvertRectStyle( SdrObject& rSdrObj ) const
1218 {
1219     ConvertLineStyle( rSdrObj, maLineData );
1220     ConvertFillStyle( rSdrObj, maFillData );
1221     ConvertFrameStyle( rSdrObj, mnFrameFlags );
1222 }
1223 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)1224 void XclImpRectObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1225 {
1226     ReadFrameData( rStrm );
1227     ReadMacro3( rStrm, nMacroSize );
1228 }
1229 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1230 void XclImpRectObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1231 {
1232     ReadFrameData( rStrm );
1233     ReadMacro4( rStrm, nMacroSize );
1234 }
1235 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1236 void XclImpRectObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1237 {
1238     ReadFrameData( rStrm );
1239     ReadName5( rStrm, nNameLen );
1240     ReadMacro5( rStrm, nMacroSize );
1241 }
1242 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1243 rtl::Reference<SdrObject> XclImpRectObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1244 {
1245     rtl::Reference<SdrObject> xSdrObj(
1246         new SdrRectObj(
1247             *GetDoc().GetDrawLayer(),
1248             rAnchorRect));
1249     ConvertRectStyle( *xSdrObj );
1250     rDffConv.Progress();
1251     return xSdrObj;
1252 }
1253 
XclImpOvalObj(const XclImpRoot & rRoot)1254 XclImpOvalObj::XclImpOvalObj( const XclImpRoot& rRoot ) :
1255     XclImpRectObj( rRoot )
1256 {
1257 }
1258 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1259 rtl::Reference<SdrObject> XclImpOvalObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1260 {
1261     rtl::Reference<SdrObject> xSdrObj(
1262         new SdrCircObj(
1263             *GetDoc().GetDrawLayer(),
1264             SdrCircKind::Full,
1265             rAnchorRect));
1266     ConvertRectStyle( *xSdrObj );
1267     rDffConv.Progress();
1268     return xSdrObj;
1269 }
1270 
XclImpArcObj(const XclImpRoot & rRoot)1271 XclImpArcObj::XclImpArcObj( const XclImpRoot& rRoot ) :
1272     XclImpDrawObjBase( rRoot ),
1273     mnQuadrant( EXC_OBJ_ARC_TR )
1274 {
1275     SetAreaObj( false );    // arc may be 2-dimensional
1276 }
1277 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)1278 void XclImpArcObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1279 {
1280     rStrm >> maFillData >> maLineData;
1281     mnQuadrant = rStrm.ReaduInt8();
1282     rStrm.Ignore( 1 );
1283     ReadMacro3( rStrm, nMacroSize );
1284 }
1285 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1286 void XclImpArcObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1287 {
1288     rStrm >> maFillData >> maLineData;
1289     mnQuadrant  = rStrm.ReaduInt8();
1290     rStrm.Ignore( 1 );
1291     ReadMacro4( rStrm, nMacroSize );
1292 }
1293 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1294 void XclImpArcObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1295 {
1296     rStrm >> maFillData >> maLineData;
1297     mnQuadrant = rStrm.ReaduInt8();
1298     rStrm.Ignore( 1 );
1299     ReadName5( rStrm, nNameLen );
1300     ReadMacro5( rStrm, nMacroSize );
1301 }
1302 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1303 rtl::Reference<SdrObject> XclImpArcObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1304 {
1305     tools::Rectangle aNewRect = rAnchorRect;
1306     Degree100 nStartAngle;
1307     Degree100 nEndAngle;
1308     switch( mnQuadrant )
1309     {
1310         default:
1311         case EXC_OBJ_ARC_TR:
1312             nStartAngle = 0_deg100;
1313             nEndAngle = 9000_deg100;
1314             aNewRect.AdjustLeft( -(rAnchorRect.GetWidth()) );
1315             aNewRect.AdjustBottom(rAnchorRect.GetHeight() );
1316         break;
1317         case EXC_OBJ_ARC_TL:
1318             nStartAngle = 9000_deg100;
1319             nEndAngle = 18000_deg100;
1320             aNewRect.AdjustRight(rAnchorRect.GetWidth() );
1321             aNewRect.AdjustBottom(rAnchorRect.GetHeight() );
1322         break;
1323         case EXC_OBJ_ARC_BL:
1324             nStartAngle = 18000_deg100;
1325             nEndAngle = 27000_deg100;
1326             aNewRect.AdjustRight(rAnchorRect.GetWidth() );
1327             aNewRect.AdjustTop( -(rAnchorRect.GetHeight()) );
1328         break;
1329         case EXC_OBJ_ARC_BR:
1330             nStartAngle = 27000_deg100;
1331             nEndAngle = 0_deg100;
1332             aNewRect.AdjustLeft( -(rAnchorRect.GetWidth()) );
1333             aNewRect.AdjustTop( -(rAnchorRect.GetHeight()) );
1334         break;
1335     }
1336     SdrCircKind eObjKind = maFillData.IsFilled() ? SdrCircKind::Section : SdrCircKind::Arc;
1337     rtl::Reference<SdrObject> xSdrObj(
1338         new SdrCircObj(
1339             *GetDoc().GetDrawLayer(),
1340             eObjKind,
1341             aNewRect,
1342             nStartAngle,
1343             nEndAngle));
1344     ConvertFillStyle( *xSdrObj, maFillData );
1345     ConvertLineStyle( *xSdrObj, maLineData );
1346     rDffConv.Progress();
1347     return xSdrObj;
1348 }
1349 
XclImpPolygonObj(const XclImpRoot & rRoot)1350 XclImpPolygonObj::XclImpPolygonObj( const XclImpRoot& rRoot ) :
1351     XclImpRectObj( rRoot ),
1352     mnPolyFlags( 0 ),
1353     mnPointCount( 0 )
1354 {
1355     SetAreaObj( false );    // polygon may be 2-dimensional
1356 }
1357 
ReadCoordList(XclImpStream & rStrm)1358 void XclImpPolygonObj::ReadCoordList( XclImpStream& rStrm )
1359 {
1360     if( (rStrm.GetNextRecId() == EXC_ID_COORDLIST) && rStrm.StartNextRecord() )
1361     {
1362         OSL_ENSURE( rStrm.GetRecLeft() / 4 == mnPointCount, "XclImpPolygonObj::ReadCoordList - wrong polygon point count" );
1363         while (true)
1364         {
1365             if (rStrm.GetRecLeft() < 4)
1366                 break;
1367             sal_uInt16 nX = rStrm.ReaduInt16();
1368             sal_uInt16 nY = rStrm.ReaduInt16();
1369             maCoords.emplace_back( nX, nY );
1370         }
1371     }
1372 }
1373 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1374 void XclImpPolygonObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1375 {
1376     ReadFrameData( rStrm );
1377     mnPolyFlags = rStrm.ReaduInt16();
1378     rStrm.Ignore( 10 );
1379     mnPointCount = rStrm.ReaduInt16();
1380     rStrm.Ignore( 8 );
1381     ReadMacro4( rStrm, nMacroSize );
1382     ReadCoordList( rStrm );
1383 }
1384 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1385 void XclImpPolygonObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1386 {
1387     ReadFrameData( rStrm );
1388     mnPolyFlags = rStrm.ReaduInt16();
1389     rStrm.Ignore( 10 );
1390     mnPointCount = rStrm.ReaduInt16();
1391     rStrm.Ignore( 8 );
1392     ReadName5( rStrm, nNameLen );
1393     ReadMacro5( rStrm, nMacroSize );
1394     ReadCoordList( rStrm );
1395 }
1396 
1397 namespace {
1398 
lclGetPolyPoint(const tools::Rectangle & rAnchorRect,const Point & rPoint)1399 ::basegfx::B2DPoint lclGetPolyPoint( const tools::Rectangle& rAnchorRect, const Point& rPoint )
1400 {
1401     return ::basegfx::B2DPoint(
1402         rAnchorRect.Left() + static_cast< sal_Int32 >( ::std::min< double >( rPoint.X(), 16384.0 ) / 16384.0 * rAnchorRect.GetWidth() + 0.5 ),
1403         rAnchorRect.Top() + static_cast< sal_Int32 >( ::std::min< double >( rPoint.Y(), 16384.0 ) / 16384.0 * rAnchorRect.GetHeight() + 0.5 ) );
1404 }
1405 
1406 } // namespace
1407 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1408 rtl::Reference<SdrObject> XclImpPolygonObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1409 {
1410     rtl::Reference<SdrObject> xSdrObj;
1411     if( maCoords.size() >= 2 )
1412     {
1413         // create the polygon
1414         ::basegfx::B2DPolygon aB2DPolygon;
1415         for( const auto& rCoord : maCoords )
1416             aB2DPolygon.append( lclGetPolyPoint( rAnchorRect, rCoord ) );
1417         // close polygon if specified
1418         if( ::get_flag( mnPolyFlags, EXC_OBJ_POLY_CLOSED ) && (maCoords.front() != maCoords.back()) )
1419             aB2DPolygon.append( lclGetPolyPoint( rAnchorRect, maCoords.front() ) );
1420         // create the SdrObject
1421         SdrObjKind eObjKind = maFillData.IsFilled() ? SdrObjKind::PathPoly : SdrObjKind::PathPolyLine;
1422         xSdrObj =
1423             new SdrPathObj(
1424                 *GetDoc().GetDrawLayer(),
1425                 eObjKind,
1426                 ::basegfx::B2DPolyPolygon(aB2DPolygon));
1427         ConvertRectStyle( *xSdrObj );
1428     }
1429     rDffConv.Progress();
1430     return xSdrObj;
1431 }
1432 
ReadByteString(XclImpStream & rStrm)1433 void XclImpObjTextData::ReadByteString( XclImpStream& rStrm )
1434 {
1435     mxString.reset();
1436     if( maData.mnTextLen > 0 )
1437     {
1438         mxString = std::make_shared<XclImpString>( rStrm.ReadRawByteString( maData.mnTextLen ) );
1439         // skip padding byte for word boundaries
1440         if( rStrm.GetRecPos() & 1 ) rStrm.Ignore( 1 );
1441     }
1442 }
1443 
ReadFormats(XclImpStream & rStrm)1444 void XclImpObjTextData::ReadFormats( XclImpStream& rStrm )
1445 {
1446     if( mxString )
1447         mxString->ReadObjFormats( rStrm, maData.mnFormatSize );
1448     else
1449         rStrm.Ignore( maData.mnFormatSize );
1450 }
1451 
XclImpTextObj(const XclImpRoot & rRoot)1452 XclImpTextObj::XclImpTextObj( const XclImpRoot& rRoot ) :
1453     XclImpRectObj( rRoot )
1454 {
1455 }
1456 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)1457 void XclImpTextObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1458 {
1459     ReadFrameData( rStrm );
1460     maTextData.maData.ReadObj3( rStrm );
1461     ReadMacro3( rStrm, nMacroSize );
1462     maTextData.ReadByteString( rStrm );
1463     maTextData.ReadFormats( rStrm );
1464 }
1465 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1466 void XclImpTextObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1467 {
1468     ReadFrameData( rStrm );
1469     maTextData.maData.ReadObj3( rStrm );
1470     ReadMacro4( rStrm, nMacroSize );
1471     maTextData.ReadByteString( rStrm );
1472     maTextData.ReadFormats( rStrm );
1473 }
1474 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1475 void XclImpTextObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1476 {
1477     ReadFrameData( rStrm );
1478     maTextData.maData.ReadObj5( rStrm );
1479     ReadName5( rStrm, nNameLen );
1480     ReadMacro5( rStrm, nMacroSize );
1481     maTextData.ReadByteString( rStrm );
1482     rStrm.Ignore( maTextData.maData.mnLinkSize );   // ignore text link formula
1483     maTextData.ReadFormats( rStrm );
1484 }
1485 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1486 rtl::Reference<SdrObject> XclImpTextObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1487 {
1488     rtl::Reference<SdrObjCustomShape> xSdrObj(
1489         new SdrObjCustomShape(
1490             *GetDoc().GetDrawLayer()));
1491     xSdrObj->NbcSetSnapRect( rAnchorRect );
1492     OUString aRectType = u"rectangle"_ustr;
1493     xSdrObj->MergeDefaultAttributes( &aRectType );
1494     ConvertRectStyle( *xSdrObj );
1495     bool bAutoSize = ::get_flag( maTextData.maData.mnFlags, EXC_OBJ_TEXT_AUTOSIZE );
1496     xSdrObj->SetMergedItem( makeSdrTextAutoGrowWidthItem( bAutoSize ) );
1497     xSdrObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bAutoSize ) );
1498     xSdrObj->SetMergedItem( makeSdrTextWordWrapItem( true ) );
1499     rDffConv.Progress();
1500     return xSdrObj;
1501 }
1502 
DoPreProcessSdrObj(XclImpDffConverter & rDffConv,SdrObject & rSdrObj) const1503 void XclImpTextObj::DoPreProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
1504 {
1505     // set text data
1506     if( SdrTextObj* pTextObj = DynCastSdrTextObj( &rSdrObj ) )
1507     {
1508         if( maTextData.mxString )
1509         {
1510             if( maTextData.mxString->IsRich() )
1511             {
1512                 if (maTextData.mxString->GetText().getLength() > 1024 && comphelper::IsFuzzing())
1513                 {
1514                     SAL_WARN("sc.filter", "truncating slow long rich text for fuzzing performance");
1515                     maTextData.mxString->SetText(maTextData.mxString->GetText().copy(0, 1024));
1516                 }
1517 
1518                 // rich text
1519                 std::unique_ptr< EditTextObject > xEditObj(
1520                     XclImpStringHelper::CreateTextObject( GetRoot(), *maTextData.mxString ) );
1521                 OutlinerParaObject aOutlineObj(std::move(xEditObj));
1522                 aOutlineObj.SetOutlinerMode( OutlinerMode::TextObject );
1523                 pTextObj->NbcSetOutlinerParaObject( std::move(aOutlineObj) );
1524             }
1525             else
1526             {
1527                 // plain text
1528                 pTextObj->NbcSetText( maTextData.mxString->GetText() );
1529             }
1530 
1531             /*  #i96858# Do not apply any formatting if there is no text.
1532                 SdrObjCustomShape::SetVerticalWriting (initiated from
1533                 SetMergedItem) calls SdrTextObj::ForceOutlinerParaObject which
1534                 ensures that we can erroneously write a ClientTextbox record
1535                 (with no content) while exporting to XLS, which can cause a
1536                 corrupted exported document. */
1537 
1538             SvxAdjust eHorAlign = SvxAdjust::Left;
1539             SdrTextVertAdjust eVerAlign = SDRTEXTVERTADJUST_TOP;
1540 
1541             // orientation (this is only a fake, drawing does not support real text orientation)
1542             namespace csst = css::text;
1543             csst::WritingMode eWriteMode = csst::WritingMode_LR_TB;
1544             switch( maTextData.maData.mnOrient )
1545             {
1546                 default:
1547                 case EXC_OBJ_ORIENT_NONE:
1548                 {
1549                     eWriteMode = csst::WritingMode_LR_TB;
1550                     switch( maTextData.maData.GetHorAlign() )
1551                     {
1552                         case EXC_OBJ_HOR_LEFT:      eHorAlign = SvxAdjust::Left;    break;
1553                         case EXC_OBJ_HOR_CENTER:    eHorAlign = SvxAdjust::Center;  break;
1554                         case EXC_OBJ_HOR_RIGHT:     eHorAlign = SvxAdjust::Right;   break;
1555                         case EXC_OBJ_HOR_JUSTIFY:   eHorAlign = SvxAdjust::Block;   break;
1556                     }
1557                     switch( maTextData.maData.GetVerAlign() )
1558                     {
1559                         case EXC_OBJ_VER_TOP:       eVerAlign = SDRTEXTVERTADJUST_TOP;      break;
1560                         case EXC_OBJ_VER_CENTER:    eVerAlign = SDRTEXTVERTADJUST_CENTER;   break;
1561                         case EXC_OBJ_VER_BOTTOM:    eVerAlign = SDRTEXTVERTADJUST_BOTTOM;   break;
1562                         case EXC_OBJ_VER_JUSTIFY:   eVerAlign = SDRTEXTVERTADJUST_BLOCK;    break;
1563                     }
1564                 }
1565                 break;
1566 
1567                 case EXC_OBJ_ORIENT_90CCW:
1568                 {
1569                     if( SdrObjCustomShape* pObjCustomShape = dynamic_cast< SdrObjCustomShape* >( &rSdrObj ) )
1570                     {
1571                         css::beans::PropertyValue aTextRotateAngle;
1572                         aTextRotateAngle.Name = "TextRotateAngle";
1573                         aTextRotateAngle.Value <<= 180.0;
1574                         SdrCustomShapeGeometryItem aGeometryItem(pObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
1575                         aGeometryItem.SetPropertyValue( aTextRotateAngle );
1576                         pObjCustomShape->SetMergedItem( aGeometryItem );
1577                     }
1578                     eWriteMode = csst::WritingMode_TB_RL;
1579                     switch( maTextData.maData.GetHorAlign() )
1580                     {
1581                         case EXC_OBJ_HOR_LEFT:      eVerAlign = SDRTEXTVERTADJUST_TOP;      break;
1582                         case EXC_OBJ_HOR_CENTER:    eVerAlign = SDRTEXTVERTADJUST_CENTER;   break;
1583                         case EXC_OBJ_HOR_RIGHT:     eVerAlign = SDRTEXTVERTADJUST_BOTTOM;   break;
1584                         case EXC_OBJ_HOR_JUSTIFY:   eVerAlign = SDRTEXTVERTADJUST_BLOCK;    break;
1585                     }
1586                     MSO_Anchor eTextAnchor = static_cast<MSO_Anchor>(rDffConv.GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop ));
1587                     switch( eTextAnchor )
1588                     {
1589                         case mso_anchorTopCentered :
1590                         case mso_anchorMiddleCentered :
1591                         case mso_anchorBottomCentered :
1592                         {
1593                             eHorAlign = SvxAdjust::Center;
1594                         }
1595                         break;
1596 
1597                         default:
1598                         {
1599                             switch( maTextData.maData.GetVerAlign() )
1600                             {
1601                                 case EXC_OBJ_VER_TOP:       eHorAlign = SvxAdjust::Right;   break;
1602                                 case EXC_OBJ_VER_CENTER:    eHorAlign = SvxAdjust::Center;  break;
1603                                 case EXC_OBJ_VER_BOTTOM:    eHorAlign = SvxAdjust::Left;    break;
1604                                 case EXC_OBJ_VER_JUSTIFY:   eHorAlign = SvxAdjust::Block;   break;
1605                             }
1606                         }
1607                     }
1608                 }
1609                 break;
1610 
1611                 case EXC_OBJ_ORIENT_STACKED:
1612                 {
1613                     // sj: STACKED is not supported, maybe it can be optimized here a bit
1614                     [[fallthrough]];
1615                 }
1616                 case EXC_OBJ_ORIENT_90CW:
1617                 {
1618                     eWriteMode = csst::WritingMode_TB_RL;
1619                     switch( maTextData.maData.GetHorAlign() )
1620                     {
1621                         case EXC_OBJ_HOR_LEFT:      eVerAlign = SDRTEXTVERTADJUST_BOTTOM;   break;
1622                         case EXC_OBJ_HOR_CENTER:    eVerAlign = SDRTEXTVERTADJUST_CENTER;   break;
1623                         case EXC_OBJ_HOR_RIGHT:     eVerAlign = SDRTEXTVERTADJUST_TOP;      break;
1624                         case EXC_OBJ_HOR_JUSTIFY:   eVerAlign = SDRTEXTVERTADJUST_BLOCK;    break;
1625                     }
1626                     MSO_Anchor eTextAnchor = static_cast<MSO_Anchor>(rDffConv.GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop ));
1627                     switch ( eTextAnchor )
1628                     {
1629                         case mso_anchorTopCentered :
1630                         case mso_anchorMiddleCentered :
1631                         case mso_anchorBottomCentered :
1632                         {
1633                             eHorAlign = SvxAdjust::Center;
1634                         }
1635                         break;
1636 
1637                         default:
1638                         {
1639                             switch( maTextData.maData.GetVerAlign() )
1640                             {
1641                                 case EXC_OBJ_VER_TOP:       eHorAlign = SvxAdjust::Left;   break;
1642                                 case EXC_OBJ_VER_CENTER:    eHorAlign = SvxAdjust::Center;  break;
1643                                 case EXC_OBJ_VER_BOTTOM:    eHorAlign = SvxAdjust::Right;   break;
1644                                 case EXC_OBJ_VER_JUSTIFY:   eHorAlign = SvxAdjust::Block;   break;
1645                             }
1646                         }
1647                     }
1648                 }
1649                 break;
1650             }
1651             rSdrObj.SetMergedItem( SvxAdjustItem( eHorAlign, EE_PARA_JUST ) );
1652             rSdrObj.SetMergedItem( SdrTextVertAdjustItem( eVerAlign ) );
1653             rSdrObj.SetMergedItem( SvxWritingModeItem( eWriteMode, SDRATTR_TEXTDIRECTION ) );
1654         }
1655     }
1656     // base class processing
1657     XclImpRectObj::DoPreProcessSdrObj( rDffConv, rSdrObj );
1658 }
1659 
XclImpChartObj(const XclImpRoot & rRoot,bool bOwnTab)1660 XclImpChartObj::XclImpChartObj( const XclImpRoot& rRoot, bool bOwnTab ) :
1661     XclImpRectObj( rRoot ),
1662     mbOwnTab( bOwnTab )
1663 {
1664     SetSimpleMacro( false );
1665     SetCustomDffObj( true );
1666 }
1667 
ReadChartSubStream(XclImpStream & rStrm)1668 void XclImpChartObj::ReadChartSubStream( XclImpStream& rStrm )
1669 {
1670     /*  If chart is read from a chartsheet (mbOwnTab == true), the BOF record
1671         has already been read. If chart is embedded as object, the next record
1672         has to be the BOF record. */
1673     if( mbOwnTab )
1674     {
1675         /*  #i109800# The input stream may point somewhere inside the chart
1676             substream and not exactly to the leading BOF record. To read this
1677             record correctly in the following, the stream has to rewind it, so
1678             that the next call to StartNextRecord() will find it correctly. */
1679         if( rStrm.GetRecId() != EXC_ID5_BOF )
1680             rStrm.RewindRecord();
1681     }
1682     else
1683     {
1684         if( (rStrm.GetNextRecId() == EXC_ID5_BOF) && rStrm.StartNextRecord() )
1685         {
1686             sal_uInt16 nBofType;
1687             rStrm.Seek( 2 );
1688             nBofType = rStrm.ReaduInt16();
1689             SAL_WARN_IF( nBofType != EXC_BOF_CHART, "sc.filter", "XclImpChartObj::ReadChartSubStream - no chart BOF record" );
1690         }
1691         else
1692         {
1693             SAL_INFO("sc.filter", "XclImpChartObj::ReadChartSubStream - missing chart substream");
1694             return;
1695         }
1696     }
1697 
1698     // read chart, even if BOF record contains wrong substream identifier
1699     mxChart = std::make_shared<XclImpChart>( GetRoot(), mbOwnTab );
1700     mxChart->ReadChartSubStream( rStrm );
1701     if( mbOwnTab )
1702         FinalizeTabChart();
1703 }
1704 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)1705 void XclImpChartObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1706 {
1707     // read OBJ record and the following chart substream
1708     ReadFrameData( rStrm );
1709     rStrm.Ignore( 18 );
1710     ReadMacro3( rStrm, nMacroSize );
1711     // set frame format from OBJ record, it is used if chart itself is transparent
1712     if( mxChart )
1713         mxChart->UpdateObjFrame( maLineData, maFillData );
1714 }
1715 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)1716 void XclImpChartObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
1717 {
1718     // read OBJ record and the following chart substream
1719     ReadFrameData( rStrm );
1720     rStrm.Ignore( 18 );
1721     ReadMacro4( rStrm, nMacroSize );
1722     // set frame format from OBJ record, it is used if chart itself is transparent
1723     if( mxChart )
1724         mxChart->UpdateObjFrame( maLineData, maFillData );
1725 }
1726 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)1727 void XclImpChartObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1728 {
1729     // read OBJ record and the following chart substream
1730     ReadFrameData( rStrm );
1731     rStrm.Ignore( 18 );
1732     ReadName5( rStrm, nNameLen );
1733     ReadMacro5( rStrm, nMacroSize );
1734     ReadChartSubStream( rStrm );
1735     // set frame format from OBJ record, it is used if chart itself is transparent
1736     if( mxChart )
1737         mxChart->UpdateObjFrame( maLineData, maFillData );
1738 }
1739 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16)1740 void XclImpChartObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 /*nSubRecSize*/ )
1741 {
1742     // read the following chart substream
1743     if( nSubRecId == EXC_ID_OBJEND )
1744     {
1745         // enable CONTINUE handling for the entire chart substream
1746         rStrm.ResetRecord( true );
1747         ReadChartSubStream( rStrm );
1748         /*  disable CONTINUE handling again to be able to read
1749             following CONTINUE records as MSODRAWING records. */
1750         rStrm.ResetRecord( false );
1751     }
1752 }
1753 
DoGetProgressSize() const1754 std::size_t XclImpChartObj::DoGetProgressSize() const
1755 {
1756     return mxChart ? mxChart->GetProgressSize() : 1;
1757 }
1758 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const1759 rtl::Reference<SdrObject> XclImpChartObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
1760 {
1761     rtl::Reference<SdrObject> xSdrObj;
1762     ScDocShell* pDocShell = GetDocShell();
1763     if( rDffConv.SupportsOleObjects() && SvtModuleOptions().IsChartInstalled() && pDocShell && mxChart && !mxChart->IsPivotChart() )
1764     {
1765         // create embedded chart object
1766         OUString aEmbObjName;
1767         OUString sBaseURL(GetRoot().GetMedium().GetBaseURL());
1768         Reference< XEmbeddedObject > xEmbObj = pDocShell->GetEmbeddedObjectContainer().
1769                 CreateEmbeddedObject( SvGlobalName( SO3_SCH_CLASSID ).GetByteSequence(), aEmbObjName, &sBaseURL );
1770 
1771         if (!xEmbObj)
1772             return xSdrObj;
1773 
1774         /*  Set the size to the embedded object, this prevents that font sizes
1775             of text objects are changed in the chart when the object is
1776             inserted into the draw page. */
1777         sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
1778         MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xEmbObj->getMapUnit( nAspect ) );
1779         Size aSize( OutputDevice::LogicToLogic( rAnchorRect.GetSize(), MapMode( MapUnit::Map100thMM ), MapMode( aUnit ) ) );
1780         css::awt::Size aAwtSize( aSize.Width(), aSize.Height() );
1781         xEmbObj->setVisualAreaSize( nAspect, aAwtSize );
1782 
1783         // #i121334# This call will change the chart's default background fill from white to transparent.
1784         // Add here again if this is wanted (see task description for details)
1785         // ChartHelper::AdaptDefaultsForChart( xEmbObj );
1786 
1787         // create the container OLE object
1788         xSdrObj =
1789             new SdrOle2Obj(
1790                 *GetDoc().GetDrawLayer(),
1791                 svt::EmbeddedObjectRef(xEmbObj, nAspect),
1792                 aEmbObjName,
1793                 rAnchorRect);
1794     }
1795 
1796     return xSdrObj;
1797 }
1798 
DoPostProcessSdrObj(XclImpDffConverter & rDffConv,SdrObject & rSdrObj) const1799 void XclImpChartObj::DoPostProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
1800 {
1801     const SdrOle2Obj* pSdrOleObj = dynamic_cast< const SdrOle2Obj* >( &rSdrObj );
1802     if( !(mxChart && pSdrOleObj) )
1803         return;
1804 
1805     const Reference< XEmbeddedObject >& xEmbObj = pSdrOleObj->GetObjRef();
1806     if( xEmbObj.is() && ::svt::EmbeddedObjectRef::TryRunningState( xEmbObj ) ) try
1807     {
1808         Reference< XEmbedPersist > xPersist( xEmbObj, UNO_QUERY_THROW );
1809         Reference< XModel > xModel( xEmbObj->getComponent(), UNO_QUERY_THROW );
1810         mxChart->Convert( xModel, rDffConv, xPersist->getEntryName(), rSdrObj.GetLogicRect() );
1811     }
1812     catch( const Exception& )
1813     {
1814     }
1815 }
1816 
FinalizeTabChart()1817 void XclImpChartObj::FinalizeTabChart()
1818 {
1819     /*  #i44077# Calculate and store DFF anchor for sheet charts.
1820         Needed to get used area if this chart is inserted as OLE object. */
1821     OSL_ENSURE( mbOwnTab, "XclImpChartObj::FinalizeTabChart - not allowed for embedded chart objects" );
1822 
1823     // set uninitialized page to landscape
1824     if( !GetPageSettings().GetPageData().mbValid )
1825         GetPageSettings().SetPaperSize( EXC_PAPERSIZE_DEFAULT, false );
1826 
1827     // calculate size of the chart object
1828     const XclPageData& rPageData = GetPageSettings().GetPageData();
1829     Size aPaperSize = rPageData.GetScPaperSize();
1830 
1831     tools::Long nWidth = XclTools::GetHmmFromTwips( aPaperSize.Width() );
1832     tools::Long nHeight = XclTools::GetHmmFromTwips( aPaperSize.Height() );
1833 
1834     // subtract page margins, give some more extra space
1835     nWidth -= o3tl::saturating_add(XclTools::GetHmmFromInch(rPageData.mfLeftMargin + rPageData.mfRightMargin), static_cast<sal_Int32>(2000));
1836     nHeight -= o3tl::saturating_add(XclTools::GetHmmFromInch(rPageData.mfTopMargin + rPageData.mfBottomMargin), static_cast<sal_Int32>(1000));
1837 
1838     // print column/row headers?
1839     if( rPageData.mbPrintHeadings )
1840     {
1841         nWidth -= 2000;
1842         nHeight -= 1000;
1843     }
1844 
1845     // create the object anchor
1846     XclObjAnchor aAnchor;
1847     aAnchor.SetRect( GetRoot(), GetCurrScTab(), tools::Rectangle( 1000, 500, nWidth, nHeight ), MapUnit::Map100thMM );
1848     SetAnchor( aAnchor );
1849 }
1850 
XclImpNoteObj(const XclImpRoot & rRoot)1851 XclImpNoteObj::XclImpNoteObj( const XclImpRoot& rRoot ) :
1852     XclImpTextObj( rRoot ),
1853     maScPos( ScAddress::INITIALIZE_INVALID ),
1854     mnNoteFlags( 0 )
1855 {
1856     SetSimpleMacro( false );
1857     // caption object will be created manually
1858     SetInsertSdrObj( false );
1859 }
1860 
SetNoteData(const ScAddress & rScPos,sal_uInt16 nNoteFlags)1861 void XclImpNoteObj::SetNoteData( const ScAddress& rScPos, sal_uInt16 nNoteFlags )
1862 {
1863     maScPos = rScPos;
1864     mnNoteFlags = nNoteFlags;
1865 }
1866 
DoPreProcessSdrObj(XclImpDffConverter & rDffConv,SdrObject & rSdrObj) const1867 void XclImpNoteObj::DoPreProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
1868 {
1869     // create formatted text
1870     XclImpTextObj::DoPreProcessSdrObj( rDffConv, rSdrObj );
1871     OutlinerParaObject* pOutlinerObj = rSdrObj.GetOutlinerParaObject();
1872     if( maScPos.IsValid() && pOutlinerObj )
1873     {
1874         // create cell note with all data from drawing object
1875         ScNoteUtil::CreateNoteFromObjectData(
1876             GetDoc(), maScPos,
1877             rSdrObj.GetMergedItemSet(),
1878             OUString(), *pOutlinerObj,
1879             rSdrObj.GetLogicRect(),
1880             ::get_flag( mnNoteFlags, EXC_NOTE_VISIBLE ) );
1881     }
1882 }
1883 
XclImpControlHelper(const XclImpRoot & rRoot,XclCtrlBindMode eBindMode)1884 XclImpControlHelper::XclImpControlHelper( const XclImpRoot& rRoot, XclCtrlBindMode eBindMode ) :
1885     mrRoot( rRoot ),
1886     meBindMode( eBindMode )
1887 {
1888 }
1889 
~XclImpControlHelper()1890 XclImpControlHelper::~XclImpControlHelper()
1891 {
1892 }
1893 
CreateSdrObjectFromShape(const Reference<XShape> & rxShape,const tools::Rectangle & rAnchorRect) const1894 rtl::Reference<SdrObject> XclImpControlHelper::CreateSdrObjectFromShape(
1895         const Reference< XShape >& rxShape, const tools::Rectangle& rAnchorRect ) const
1896 {
1897     mxShape = rxShape;
1898     rtl::Reference<SdrObject> xSdrObj( SdrObject::getSdrObjectFromXShape( rxShape ) );
1899     if( xSdrObj )
1900     {
1901         xSdrObj->NbcSetSnapRect( rAnchorRect );
1902         // #i30543# insert into control layer
1903         xSdrObj->NbcSetLayer( SC_LAYER_CONTROLS );
1904     }
1905     return xSdrObj;
1906 }
1907 
ApplySheetLinkProps() const1908 void XclImpControlHelper::ApplySheetLinkProps() const
1909 {
1910 
1911     Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( mxShape );
1912     if( !xCtrlModel.is() )
1913         return;
1914 
1915    // sheet links
1916     ScDocShell* pDocShell = mrRoot.GetDocShell();
1917     if(!pDocShell)
1918         return;
1919 
1920     ScModelObj* pModelObj = pDocShell->GetModel();
1921     if( !pModelObj )
1922         return;
1923 
1924     // cell link
1925     if( mxCellLink ) try
1926     {
1927         Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY_THROW );
1928 
1929         // create argument sequence for createInstanceWithArguments()
1930         CellAddress aApiAddress;
1931         ScUnoConversion::FillApiAddress( aApiAddress, *mxCellLink );
1932 
1933         NamedValue aValue;
1934         aValue.Name = SC_UNONAME_BOUNDCELL;
1935         aValue.Value <<= aApiAddress;
1936 
1937         Sequence< Any > aArgs{ Any(aValue) };
1938 
1939         // create the CellValueBinding instance and set at the control model
1940         OUString aServiceName;
1941         switch( meBindMode )
1942         {
1943             case EXC_CTRL_BINDCONTENT:  aServiceName = SC_SERVICENAME_VALBIND;       break;
1944             case EXC_CTRL_BINDPOSITION: aServiceName = SC_SERVICENAME_LISTCELLBIND;  break;
1945         }
1946         Reference< XValueBinding > xBinding(
1947             pModelObj->createInstanceWithArguments( aServiceName, aArgs ), UNO_QUERY_THROW );
1948         xBindable->setValueBinding( xBinding );
1949     }
1950     catch( const Exception& )
1951     {
1952     }
1953 
1954     // source range
1955     if( !mxSrcRange )
1956         return;
1957 
1958     try
1959     {
1960         Reference< XListEntrySink > xEntrySink( xCtrlModel, UNO_QUERY_THROW );
1961 
1962         // create argument sequence for createInstanceWithArguments()
1963         CellRangeAddress aApiRange;
1964         ScUnoConversion::FillApiRange( aApiRange, *mxSrcRange );
1965 
1966         NamedValue aValue;
1967         aValue.Name = SC_UNONAME_CELLRANGE;
1968         aValue.Value <<= aApiRange;
1969 
1970         Sequence< Any > aArgs{ Any(aValue) };
1971 
1972         // create the EntrySource instance and set at the control model
1973         Reference< XListEntrySource > xEntrySource( pModelObj->createInstanceWithArguments(
1974             SC_SERVICENAME_LISTSOURCE, aArgs ), UNO_QUERY_THROW );
1975         xEntrySink->setListEntrySource( xEntrySource );
1976     }
1977     catch( const Exception& )
1978     {
1979     }
1980 }
1981 
ProcessControl(const XclImpDrawObjBase & rDrawObj) const1982 void XclImpControlHelper::ProcessControl( const XclImpDrawObjBase& rDrawObj ) const
1983 {
1984     Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( mxShape );
1985     if( !xCtrlModel.is() )
1986         return;
1987 
1988     ApplySheetLinkProps();
1989 
1990     ScfPropertySet aPropSet( xCtrlModel );
1991 
1992     // #i51348# set object name at control model
1993     aPropSet.SetStringProperty( u"Name"_ustr, rDrawObj.GetObjName() );
1994 
1995     // control visible and printable?
1996     aPropSet.SetBoolProperty( u"EnableVisible"_ustr, rDrawObj.IsVisible() );
1997     aPropSet.SetBoolProperty( u"Printable"_ustr, rDrawObj.IsPrintable() );
1998 
1999     // virtual call for type specific processing
2000     DoProcessControl( aPropSet );
2001 }
2002 
ReadCellLinkFormula(XclImpStream & rStrm,bool bWithBoundSize)2003 void XclImpControlHelper::ReadCellLinkFormula( XclImpStream& rStrm, bool bWithBoundSize )
2004 {
2005     ScRangeList aScRanges;
2006     ReadRangeList( aScRanges, rStrm, bWithBoundSize );
2007     // Use first cell of first range
2008     if ( !aScRanges.empty() )
2009     {
2010         const ScRange & rScRange = aScRanges.front();
2011         mxCellLink = std::make_shared<ScAddress>( rScRange.aStart );
2012     }
2013 }
2014 
ReadSourceRangeFormula(XclImpStream & rStrm,bool bWithBoundSize)2015 void XclImpControlHelper::ReadSourceRangeFormula( XclImpStream& rStrm, bool bWithBoundSize )
2016 {
2017     ScRangeList aScRanges;
2018     ReadRangeList( aScRanges, rStrm, bWithBoundSize );
2019     // Use first range
2020     if ( !aScRanges.empty() )
2021     {
2022         const ScRange & rScRange = aScRanges.front();
2023         mxSrcRange = std::make_shared<ScRange>( rScRange );
2024     }
2025 }
2026 
DoProcessControl(ScfPropertySet &) const2027 void XclImpControlHelper::DoProcessControl( ScfPropertySet& ) const
2028 {
2029 }
2030 
ReadRangeList(ScRangeList & rScRanges,XclImpStream & rStrm)2031 void XclImpControlHelper::ReadRangeList( ScRangeList& rScRanges, XclImpStream& rStrm )
2032 {
2033     XclTokenArray aXclTokArr;
2034     sal_uInt16 nSize = XclTokenArray::ReadSize(rStrm);
2035     rStrm.Ignore( 4 );
2036     aXclTokArr.ReadArray(nSize, rStrm);
2037     mrRoot.GetFormulaCompiler().CreateRangeList( rScRanges, EXC_FMLATYPE_CONTROL, aXclTokArr, rStrm );
2038 }
2039 
ReadRangeList(ScRangeList & rScRanges,XclImpStream & rStrm,bool bWithBoundSize)2040 void XclImpControlHelper::ReadRangeList( ScRangeList& rScRanges, XclImpStream& rStrm, bool bWithBoundSize )
2041 {
2042     if( bWithBoundSize )
2043     {
2044         sal_uInt16 nSize;
2045         nSize = rStrm.ReaduInt16();
2046         if( nSize > 0 )
2047         {
2048             rStrm.PushPosition();
2049             ReadRangeList( rScRanges, rStrm );
2050             rStrm.PopPosition();
2051             rStrm.Ignore( nSize );
2052         }
2053     }
2054     else
2055     {
2056         ReadRangeList( rScRanges, rStrm );
2057     }
2058 }
2059 
XclImpTbxObjBase(const XclImpRoot & rRoot)2060 XclImpTbxObjBase::XclImpTbxObjBase( const XclImpRoot& rRoot ) :
2061     XclImpTextObj( rRoot ),
2062     XclImpControlHelper( rRoot, EXC_CTRL_BINDPOSITION )
2063 {
2064     SetSimpleMacro( false );
2065     SetCustomDffObj( true );
2066 }
2067 
2068 namespace {
2069 
lclExtractColor(sal_uInt8 & rnColorIdx,const DffPropSet & rDffPropSet,sal_uInt32 nPropId)2070 void lclExtractColor( sal_uInt8& rnColorIdx, const DffPropSet& rDffPropSet, sal_uInt32 nPropId )
2071 {
2072     if( rDffPropSet.IsProperty( nPropId ) )
2073     {
2074         sal_uInt32 nColor = rDffPropSet.GetPropertyValue( nPropId, 0 );
2075         if( (nColor & 0xFF000000) == 0x08000000 )
2076             rnColorIdx = ::extract_value< sal_uInt8 >( nColor, 0, 8 );
2077     }
2078 }
2079 
2080 } // namespace
2081 
SetDffProperties(const DffPropSet & rDffPropSet)2082 void XclImpTbxObjBase::SetDffProperties( const DffPropSet& rDffPropSet )
2083 {
2084     maFillData.mnPattern = rDffPropSet.GetPropertyBool( DFF_Prop_fFilled ) ? EXC_PATT_SOLID : EXC_PATT_NONE;
2085     lclExtractColor( maFillData.mnBackColorIdx, rDffPropSet, DFF_Prop_fillBackColor );
2086     lclExtractColor( maFillData.mnPattColorIdx, rDffPropSet, DFF_Prop_fillColor );
2087     ::set_flag( maFillData.mnAuto, EXC_OBJ_LINE_AUTO, false );
2088 
2089     maLineData.mnStyle = rDffPropSet.GetPropertyBool( DFF_Prop_fLine ) ? EXC_OBJ_LINE_SOLID : EXC_OBJ_LINE_NONE;
2090     lclExtractColor( maLineData.mnColorIdx, rDffPropSet, DFF_Prop_lineColor );
2091     ::set_flag( maLineData.mnAuto, EXC_OBJ_FILL_AUTO, false );
2092 }
2093 
SetStringProperty(const OUString & sName,const OUString & sVal)2094 void XclImpControlHelper::SetStringProperty(const OUString& sName, const OUString& sVal)
2095 {
2096     Reference<XControlModel> xCtrlModel = XclControlHelper::GetControlModel(mxShape);
2097     if (!xCtrlModel.is())
2098         return;
2099 
2100     ScfPropertySet aProps(xCtrlModel);
2101     aProps.SetStringProperty(sName, sVal);
2102 }
2103 
FillMacroDescriptor(ScriptEventDescriptor & rDescriptor) const2104 bool XclImpTbxObjBase::FillMacroDescriptor( ScriptEventDescriptor& rDescriptor ) const
2105 {
2106     return XclControlHelper::FillMacroDescriptor( rDescriptor, DoGetEventType(), GetMacroName(), GetDocShell() );
2107 }
2108 
ConvertFont(ScfPropertySet & rPropSet) const2109 void XclImpTbxObjBase::ConvertFont( ScfPropertySet& rPropSet ) const
2110 {
2111     if( maTextData.mxString )
2112     {
2113         const XclFormatRunVec& rFormatRuns = maTextData.mxString->GetFormats();
2114         if( rFormatRuns.empty() )
2115             GetFontBuffer().WriteDefaultCtrlFontProperties( rPropSet );
2116         else
2117             GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL, rFormatRuns.front().mnFontIdx );
2118     }
2119 }
2120 
ConvertLabel(ScfPropertySet & rPropSet) const2121 void XclImpTbxObjBase::ConvertLabel( ScfPropertySet& rPropSet ) const
2122 {
2123     if( maTextData.mxString )
2124     {
2125         OUString aLabel = maTextData.mxString->GetText();
2126         if( maTextData.maData.mnShortcut > 0 )
2127         {
2128             sal_Int32 nPos = aLabel.indexOf( static_cast< sal_Unicode >( maTextData.maData.mnShortcut ) );
2129             if( nPos != -1 )
2130                 aLabel = aLabel.replaceAt( nPos, 0, u"~" );
2131         }
2132         rPropSet.SetStringProperty( u"Label"_ustr, aLabel );
2133 
2134         //Excel Alt text <==> Aoo description
2135         //For TBX control, if user does not operate alt text, alt text will be set label text as default value in Excel.
2136         //In this case, DFF_Prop_wzDescription will not be set in excel file.
2137         //So In the end of SvxMSDffManager::ImportShape, description will not be set. But actually in excel,
2138         //the alt text is the label value. So here set description as label text first which is called before ImportShape.
2139         Reference< css::beans::XPropertySet > xPropset( mxShape, UNO_QUERY );
2140         try{
2141         if(xPropset.is())
2142             xPropset->setPropertyValue( u"Description"_ustr, Any(aLabel) );
2143         }catch( ... )
2144         {
2145             SAL_WARN("sc.filter", "Can't set a default text for TBX Control ");
2146         }
2147     }
2148     ConvertFont( rPropSet );
2149 }
2150 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const2151 rtl::Reference<SdrObject> XclImpTbxObjBase::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
2152 {
2153     rtl::Reference<SdrObject> xSdrObj( rDffConv.CreateSdrObject( *this, rAnchorRect ) );
2154     rDffConv.Progress();
2155     return xSdrObj;
2156 }
2157 
DoPreProcessSdrObj(XclImpDffConverter &,SdrObject &) const2158 void XclImpTbxObjBase::DoPreProcessSdrObj( XclImpDffConverter& /*rDffConv*/, SdrObject& /*rSdrObj*/ ) const
2159 {
2160     // do not call DoPreProcessSdrObj() from base class (to skip text processing)
2161     ProcessControl( *this );
2162 }
2163 
XclImpButtonObj(const XclImpRoot & rRoot)2164 XclImpButtonObj::XclImpButtonObj( const XclImpRoot& rRoot ) :
2165     XclImpTbxObjBase( rRoot )
2166 {
2167 }
2168 
DoProcessControl(ScfPropertySet & rPropSet) const2169 void XclImpButtonObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2170 {
2171     // label and text formatting
2172     ConvertLabel( rPropSet );
2173 
2174     /*  Horizontal text alignment. For unknown reason, the property type is a
2175         simple sal_Int16 and not a com.sun.star.style.HorizontalAlignment. */
2176     sal_Int16 nHorAlign = 1;
2177     switch( maTextData.maData.GetHorAlign() )
2178     {
2179         case EXC_OBJ_HOR_LEFT:      nHorAlign = 0;  break;
2180         case EXC_OBJ_HOR_CENTER:    nHorAlign = 1;  break;
2181         case EXC_OBJ_HOR_RIGHT:     nHorAlign = 2;  break;
2182     }
2183     rPropSet.SetProperty( u"Align"_ustr, nHorAlign );
2184 
2185     // vertical text alignment
2186     namespace csss = css::style;
2187     csss::VerticalAlignment eVerAlign = csss::VerticalAlignment_MIDDLE;
2188     switch( maTextData.maData.GetVerAlign() )
2189     {
2190         case EXC_OBJ_VER_TOP:       eVerAlign = csss::VerticalAlignment_TOP;    break;
2191         case EXC_OBJ_VER_CENTER:    eVerAlign = csss::VerticalAlignment_MIDDLE; break;
2192         case EXC_OBJ_VER_BOTTOM:    eVerAlign = csss::VerticalAlignment_BOTTOM; break;
2193     }
2194     rPropSet.SetProperty( u"VerticalAlign"_ustr, eVerAlign );
2195 
2196     // always wrap text automatically
2197     rPropSet.SetBoolProperty( u"MultiLine"_ustr, true );
2198 
2199     // default button
2200     bool bDefButton = ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_DEFAULT );
2201     rPropSet.SetBoolProperty( u"DefaultButton"_ustr, bDefButton );
2202 
2203     // button type (flags cannot be combined in OOo)
2204     namespace cssa = css::awt;
2205     cssa::PushButtonType eButtonType = cssa::PushButtonType_STANDARD;
2206     if( ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_CLOSE ) )
2207         eButtonType = cssa::PushButtonType_OK;
2208     else if( ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_CANCEL ) )
2209         eButtonType = cssa::PushButtonType_CANCEL;
2210     else if( ::get_flag( maTextData.maData.mnButtonFlags, EXC_OBJ_BUTTON_HELP ) )
2211         eButtonType = cssa::PushButtonType_HELP;
2212     // property type is short, not enum
2213     rPropSet.SetProperty( u"PushButtonType"_ustr, sal_Int16( eButtonType ) );
2214 }
2215 
DoGetServiceName() const2216 OUString XclImpButtonObj::DoGetServiceName() const
2217 {
2218     return u"com.sun.star.form.component.CommandButton"_ustr;
2219 }
2220 
DoGetEventType() const2221 XclTbxEventType XclImpButtonObj::DoGetEventType() const
2222 {
2223     return EXC_TBX_EVENT_ACTION;
2224 }
2225 
XclImpCheckBoxObj(const XclImpRoot & rRoot)2226 XclImpCheckBoxObj::XclImpCheckBoxObj( const XclImpRoot& rRoot ) :
2227     XclImpTbxObjBase( rRoot ),
2228     mnState( EXC_OBJ_CHECKBOX_UNCHECKED ),
2229     mnCheckBoxFlags( 0 )
2230 {
2231 }
2232 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2233 void XclImpCheckBoxObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2234 {
2235     ReadFrameData( rStrm );
2236     rStrm.Ignore( 10 );
2237     maTextData.maData.mnFlags = rStrm.ReaduInt16();
2238     rStrm.Ignore( 20 );
2239     ReadName5( rStrm, nNameLen );
2240     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2241     ReadCellLinkFormula( rStrm, true );
2242     maTextData.maData.mnTextLen = rStrm.ReaduInt16();
2243     maTextData.ReadByteString( rStrm );
2244     mnState = rStrm.ReaduInt16();
2245     maTextData.maData.mnShortcut = rStrm.ReaduInt16();
2246     maTextData.maData.mnShortcutEA = rStrm.ReaduInt16();
2247     mnCheckBoxFlags = rStrm.ReaduInt16();
2248 }
2249 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2250 void XclImpCheckBoxObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2251 {
2252     switch( nSubRecId )
2253     {
2254         case EXC_ID_OBJCBLS:
2255             // do not read EXC_ID_OBJCBLSDATA, not written by OOo Excel export
2256             mnState = rStrm.ReaduInt16();
2257             rStrm.Ignore( 4 );
2258             maTextData.maData.mnShortcut = rStrm.ReaduInt16();
2259             maTextData.maData.mnShortcutEA = rStrm.ReaduInt16();
2260             mnCheckBoxFlags = rStrm.ReaduInt16();
2261         break;
2262         case EXC_ID_OBJCBLSFMLA:
2263             ReadCellLinkFormula( rStrm, false );
2264         break;
2265         default:
2266             XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2267     }
2268 }
2269 
DoProcessControl(ScfPropertySet & rPropSet) const2270 void XclImpCheckBoxObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2271 {
2272     // label and text formatting
2273     ConvertLabel( rPropSet );
2274 
2275     // state
2276     bool bSupportsTristate = GetObjType() == EXC_OBJTYPE_CHECKBOX;
2277     sal_Int16 nApiState = 0;
2278     switch( mnState )
2279     {
2280         case EXC_OBJ_CHECKBOX_UNCHECKED:    nApiState = 0;                          break;
2281         case EXC_OBJ_CHECKBOX_CHECKED:      nApiState = 1;                          break;
2282         case EXC_OBJ_CHECKBOX_TRISTATE:     nApiState = bSupportsTristate ? 2 : 1;  break;
2283     }
2284     if( bSupportsTristate )
2285         rPropSet.SetBoolProperty( u"TriState"_ustr, nApiState == 2 );
2286     rPropSet.SetProperty( u"DefaultState"_ustr, nApiState );
2287 
2288     // box style
2289     namespace AwtVisualEffect = css::awt::VisualEffect;
2290     sal_Int16 nEffect = ::get_flagvalue( mnCheckBoxFlags, EXC_OBJ_CHECKBOX_FLAT, AwtVisualEffect::FLAT, AwtVisualEffect::LOOK3D );
2291     rPropSet.SetProperty( u"VisualEffect"_ustr, nEffect );
2292 
2293     // do not wrap text automatically
2294     rPropSet.SetBoolProperty( u"MultiLine"_ustr, false );
2295 
2296     // #i40279# always centered vertically
2297     namespace csss = css::style;
2298     rPropSet.SetProperty( u"VerticalAlign"_ustr, csss::VerticalAlignment_MIDDLE );
2299 
2300     // background color
2301     if( maFillData.IsFilled() )
2302     {
2303         sal_Int32 nColor = static_cast< sal_Int32 >( GetSolidFillColor( maFillData ) );
2304         rPropSet.SetProperty( u"BackgroundColor"_ustr, nColor );
2305     }
2306 }
2307 
DoGetServiceName() const2308 OUString XclImpCheckBoxObj::DoGetServiceName() const
2309 {
2310     return u"com.sun.star.form.component.CheckBox"_ustr;
2311 }
2312 
DoGetEventType() const2313 XclTbxEventType XclImpCheckBoxObj::DoGetEventType() const
2314 {
2315     return EXC_TBX_EVENT_ACTION;
2316 }
2317 
XclImpOptionButtonObj(const XclImpRoot & rRoot)2318 XclImpOptionButtonObj::XclImpOptionButtonObj( const XclImpRoot& rRoot ) :
2319     XclImpCheckBoxObj( rRoot ),
2320     mnNextInGroup( 0 ),
2321     mnFirstInGroup( 1 )
2322 {
2323 }
2324 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2325 void XclImpOptionButtonObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2326 {
2327     ReadFrameData( rStrm );
2328     rStrm.Ignore( 10 );
2329     maTextData.maData.mnFlags = rStrm.ReaduInt16();
2330     rStrm.Ignore( 32 );
2331     ReadName5( rStrm, nNameLen );
2332     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2333     ReadCellLinkFormula( rStrm, true );
2334     maTextData.maData.mnTextLen = rStrm.ReaduInt16();
2335     maTextData.ReadByteString( rStrm );
2336     mnState = rStrm.ReaduInt16();
2337     maTextData.maData.mnShortcut = rStrm.ReaduInt16();
2338     maTextData.maData.mnShortcutEA = rStrm.ReaduInt16();
2339     mnCheckBoxFlags = rStrm.ReaduInt16();
2340     mnNextInGroup = rStrm.ReaduInt16();
2341     mnFirstInGroup = rStrm.ReaduInt16();
2342 }
2343 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2344 void XclImpOptionButtonObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2345 {
2346     switch( nSubRecId )
2347     {
2348         case EXC_ID_OBJRBODATA:
2349             mnNextInGroup = rStrm.ReaduInt16();
2350             mnFirstInGroup = rStrm.ReaduInt16();
2351         break;
2352         default:
2353             XclImpCheckBoxObj::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2354     }
2355 }
2356 
DoProcessControl(ScfPropertySet & rPropSet) const2357 void XclImpOptionButtonObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2358 {
2359     XclImpCheckBoxObj::DoProcessControl( rPropSet );
2360     // TODO: grouping
2361     XclImpOptionButtonObj* pTbxObj = dynamic_cast< XclImpOptionButtonObj* >( GetObjectManager().GetSheetDrawing( GetTab() ).FindDrawObj( mnNextInGroup ).get() );
2362     if ( pTbxObj && pTbxObj->mnFirstInGroup )
2363     {
2364         // Group has terminated
2365         // traverse each RadioButton in group and
2366         //     a) apply the groupname
2367         //     b) propagate the linked cell from the lead radiobutton
2368         //     c) apply the correct Ref value
2369         XclImpOptionButtonObj* pLeader = pTbxObj;
2370 
2371         sal_Int32 nRefVal = 1;
2372         do
2373         {
2374 
2375             Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( pTbxObj->mxShape );
2376             if ( xCtrlModel.is() )
2377             {
2378                 ScfPropertySet aProps( xCtrlModel );
2379                 OUString sGroupName = OUString::number( pLeader->GetDffShapeId() );
2380 
2381                 aProps.SetStringProperty( u"GroupName"_ustr, sGroupName );
2382                 aProps.SetStringProperty( u"RefValue"_ustr, OUString::number( nRefVal++ ) );
2383                 if ( pLeader->HasCellLink() && !pTbxObj->HasCellLink() )
2384                 {
2385                     // propagate cell link info
2386                     pTbxObj->mxCellLink = std::make_shared<ScAddress>( *pLeader->mxCellLink );
2387                     pTbxObj->ApplySheetLinkProps();
2388                 }
2389                 pTbxObj = dynamic_cast< XclImpOptionButtonObj* >( GetObjectManager().GetSheetDrawing( GetTab() ).FindDrawObj( pTbxObj->mnNextInGroup ).get() );
2390             }
2391             else
2392                 pTbxObj = nullptr;
2393         } while ( pTbxObj && ( pTbxObj->mnFirstInGroup != 1 ) );
2394     }
2395     else
2396     {
2397         // not the leader? try and find it
2398     }
2399 }
2400 
DoGetServiceName() const2401 OUString XclImpOptionButtonObj::DoGetServiceName() const
2402 {
2403     return u"com.sun.star.form.component.RadioButton"_ustr;
2404 }
2405 
DoGetEventType() const2406 XclTbxEventType XclImpOptionButtonObj::DoGetEventType() const
2407 {
2408     return EXC_TBX_EVENT_ACTION;
2409 }
2410 
IsInGroup() const2411 bool XclImpOptionButtonObj::IsInGroup() const
2412 {
2413     return mnNextInGroup;
2414 }
2415 
XclImpLabelObj(const XclImpRoot & rRoot)2416 XclImpLabelObj::XclImpLabelObj( const XclImpRoot& rRoot ) :
2417     XclImpTbxObjBase( rRoot )
2418 {
2419 }
2420 
DoProcessControl(ScfPropertySet & rPropSet) const2421 void XclImpLabelObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2422 {
2423     // label and text formatting
2424     ConvertLabel( rPropSet );
2425 
2426     // text alignment (always top/left aligned)
2427     rPropSet.SetProperty( u"Align"_ustr, sal_Int16( 0 ) );
2428     namespace csss = css::style;
2429     rPropSet.SetProperty( u"VerticalAlign"_ustr, csss::VerticalAlignment_TOP );
2430 
2431     // always wrap text automatically
2432     rPropSet.SetBoolProperty( u"MultiLine"_ustr, true );
2433 }
2434 
DoGetServiceName() const2435 OUString XclImpLabelObj::DoGetServiceName() const
2436 {
2437     return u"com.sun.star.form.component.FixedText"_ustr;
2438 }
2439 
DoGetEventType() const2440 XclTbxEventType XclImpLabelObj::DoGetEventType() const
2441 {
2442     return EXC_TBX_EVENT_MOUSE;
2443 }
2444 
XclImpGroupBoxObj(const XclImpRoot & rRoot)2445 XclImpGroupBoxObj::XclImpGroupBoxObj( const XclImpRoot& rRoot ) :
2446     XclImpTbxObjBase( rRoot ),
2447     mnGroupBoxFlags( 0 )
2448 {
2449 }
2450 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2451 void XclImpGroupBoxObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2452 {
2453     ReadFrameData( rStrm );
2454     rStrm.Ignore( 10 );
2455     maTextData.maData.mnFlags = rStrm.ReaduInt16();
2456     rStrm.Ignore( 26 );
2457     ReadName5( rStrm, nNameLen );
2458     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2459     maTextData.maData.mnTextLen = rStrm.ReaduInt16();
2460     maTextData.ReadByteString( rStrm );
2461     maTextData.maData.mnShortcut = rStrm.ReaduInt16();
2462     maTextData.maData.mnShortcutEA = rStrm.ReaduInt16(  );
2463     mnGroupBoxFlags = rStrm.ReaduInt16();
2464 }
2465 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2466 void XclImpGroupBoxObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2467 {
2468     switch( nSubRecId )
2469     {
2470         case EXC_ID_OBJGBODATA:
2471             maTextData.maData.mnShortcut = rStrm.ReaduInt16();
2472             maTextData.maData.mnShortcutEA = rStrm.ReaduInt16();
2473             mnGroupBoxFlags = rStrm.ReaduInt16();
2474         break;
2475         default:
2476             XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2477     }
2478 }
2479 
DoProcessControl(ScfPropertySet & rPropSet) const2480 void XclImpGroupBoxObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2481 {
2482     // label and text formatting
2483     ConvertLabel( rPropSet );
2484 }
2485 
DoGetServiceName() const2486 OUString XclImpGroupBoxObj::DoGetServiceName() const
2487 {
2488     return u"com.sun.star.form.component.GroupBox"_ustr;
2489 }
2490 
DoGetEventType() const2491 XclTbxEventType XclImpGroupBoxObj::DoGetEventType() const
2492 {
2493     return EXC_TBX_EVENT_MOUSE;
2494 }
2495 
XclImpDialogObj(const XclImpRoot & rRoot)2496 XclImpDialogObj::XclImpDialogObj( const XclImpRoot& rRoot ) :
2497     XclImpTbxObjBase( rRoot )
2498 {
2499 }
2500 
DoProcessControl(ScfPropertySet & rPropSet) const2501 void XclImpDialogObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2502 {
2503     // label and text formatting
2504     ConvertLabel( rPropSet );
2505 }
2506 
DoGetServiceName() const2507 OUString XclImpDialogObj::DoGetServiceName() const
2508 {
2509     // dialog frame faked by a groupbox
2510     return u"com.sun.star.form.component.GroupBox"_ustr;
2511 }
2512 
DoGetEventType() const2513 XclTbxEventType XclImpDialogObj::DoGetEventType() const
2514 {
2515     return EXC_TBX_EVENT_MOUSE;
2516 }
2517 
XclImpEditObj(const XclImpRoot & rRoot)2518 XclImpEditObj::XclImpEditObj( const XclImpRoot& rRoot ) :
2519     XclImpTbxObjBase( rRoot ),
2520     mnContentType( EXC_OBJ_EDIT_TEXT ),
2521     mnMultiLine( 0 ),
2522     mnScrollBar( 0 ),
2523     mnListBoxObjId( 0 )
2524 {
2525 }
2526 
IsNumeric() const2527 bool XclImpEditObj::IsNumeric() const
2528 {
2529     return (mnContentType == EXC_OBJ_EDIT_INTEGER) || (mnContentType == EXC_OBJ_EDIT_DOUBLE);
2530 }
2531 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2532 void XclImpEditObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2533 {
2534     ReadFrameData( rStrm );
2535     rStrm.Ignore( 10 );
2536     maTextData.maData.mnFlags = rStrm.ReaduInt16();
2537     rStrm.Ignore( 14 );
2538     ReadName5( rStrm, nNameLen );
2539     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2540     maTextData.maData.mnTextLen = rStrm.ReaduInt16();
2541     maTextData.ReadByteString( rStrm );
2542     mnContentType = rStrm.ReaduInt16();
2543     mnMultiLine = rStrm.ReaduInt16();
2544     mnScrollBar = rStrm.ReaduInt16();
2545     mnListBoxObjId = rStrm.ReaduInt16();
2546 }
2547 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2548 void XclImpEditObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2549 {
2550     switch( nSubRecId )
2551     {
2552         case EXC_ID_OBJEDODATA:
2553             mnContentType = rStrm.ReaduInt16();
2554             mnMultiLine = rStrm.ReaduInt16();
2555             mnScrollBar = rStrm.ReaduInt16();
2556             mnListBoxObjId = rStrm.ReaduInt16();
2557         break;
2558         default:
2559             XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2560     }
2561 }
2562 
DoProcessControl(ScfPropertySet & rPropSet) const2563 void XclImpEditObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2564 {
2565     if( maTextData.mxString )
2566     {
2567         OUString aText = maTextData.mxString->GetText();
2568         if( IsNumeric() )
2569         {
2570             // TODO: OUString::toDouble() does not handle local decimal separator
2571             rPropSet.SetProperty( u"DefaultValue"_ustr, aText.toDouble() );
2572             rPropSet.SetBoolProperty( u"Spin"_ustr, mnScrollBar != 0 );
2573         }
2574         else
2575         {
2576             rPropSet.SetProperty( u"DefaultText"_ustr, aText );
2577             rPropSet.SetBoolProperty( u"MultiLine"_ustr, mnMultiLine != 0 );
2578             rPropSet.SetBoolProperty( u"VScroll"_ustr, mnScrollBar != 0 );
2579         }
2580     }
2581     ConvertFont( rPropSet );
2582 }
2583 
DoGetServiceName() const2584 OUString XclImpEditObj::DoGetServiceName() const
2585 {
2586     return IsNumeric() ?
2587         u"com.sun.star.form.component.NumericField"_ustr :
2588         u"com.sun.star.form.component.TextField"_ustr;
2589 }
2590 
DoGetEventType() const2591 XclTbxEventType XclImpEditObj::DoGetEventType() const
2592 {
2593     return EXC_TBX_EVENT_TEXT;
2594 }
2595 
XclImpTbxObjScrollableBase(const XclImpRoot & rRoot)2596 XclImpTbxObjScrollableBase::XclImpTbxObjScrollableBase( const XclImpRoot& rRoot ) :
2597     XclImpTbxObjBase( rRoot ),
2598     mnValue( 0 ),
2599     mnMin( 0 ),
2600     mnMax( 100 ),
2601     mnStep( 1 ),
2602     mnPageStep( 10 ),
2603     mnOrient( 0 ),
2604     mnThumbWidth( 1 ),
2605     mnScrollFlags( 0 )
2606 {
2607 }
2608 
ReadSbs(XclImpStream & rStrm)2609 void XclImpTbxObjScrollableBase::ReadSbs( XclImpStream& rStrm )
2610 {
2611     rStrm.Ignore( 4 );
2612     mnValue = rStrm.ReaduInt16();
2613     mnMin = rStrm.ReaduInt16();
2614     mnMax = rStrm.ReaduInt16();
2615     mnStep = rStrm.ReaduInt16();
2616     mnPageStep = rStrm.ReaduInt16();
2617     mnOrient = rStrm.ReaduInt16();
2618     mnThumbWidth = rStrm.ReaduInt16();
2619     mnScrollFlags = rStrm.ReaduInt16();
2620 }
2621 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2622 void XclImpTbxObjScrollableBase::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2623 {
2624     switch( nSubRecId )
2625     {
2626         case EXC_ID_OBJSBS:
2627             ReadSbs( rStrm );
2628         break;
2629         case EXC_ID_OBJSBSFMLA:
2630             ReadCellLinkFormula( rStrm, false );
2631         break;
2632         default:
2633             XclImpTbxObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2634     }
2635 }
2636 
XclImpSpinButtonObj(const XclImpRoot & rRoot)2637 XclImpSpinButtonObj::XclImpSpinButtonObj( const XclImpRoot& rRoot ) :
2638     XclImpTbxObjScrollableBase( rRoot )
2639 {
2640 }
2641 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2642 void XclImpSpinButtonObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2643 {
2644     ReadFrameData( rStrm );
2645     ReadSbs( rStrm );
2646     ReadName5( rStrm, nNameLen );
2647     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2648     ReadCellLinkFormula( rStrm, true );
2649 }
2650 
DoProcessControl(ScfPropertySet & rPropSet) const2651 void XclImpSpinButtonObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2652 {
2653     // Calc's "Border" property is not the 3D/flat style effect in Excel (#i34712#)
2654     rPropSet.SetProperty( u"Border"_ustr, css::awt::VisualEffect::NONE );
2655     rPropSet.SetProperty< sal_Int32 >( u"DefaultSpinValue"_ustr, mnValue );
2656     rPropSet.SetProperty< sal_Int32 >( u"SpinValueMin"_ustr, mnMin );
2657     rPropSet.SetProperty< sal_Int32 >( u"SpinValueMax"_ustr, mnMax );
2658     rPropSet.SetProperty< sal_Int32 >( u"SpinIncrement"_ustr, mnStep );
2659 
2660     // Excel spin buttons always vertical
2661     rPropSet.SetProperty( u"Orientation"_ustr, css::awt::ScrollBarOrientation::VERTICAL );
2662 }
2663 
DoGetServiceName() const2664 OUString XclImpSpinButtonObj::DoGetServiceName() const
2665 {
2666     return u"com.sun.star.form.component.SpinButton"_ustr;
2667 }
2668 
DoGetEventType() const2669 XclTbxEventType XclImpSpinButtonObj::DoGetEventType() const
2670 {
2671     return EXC_TBX_EVENT_VALUE;
2672 }
2673 
XclImpScrollBarObj(const XclImpRoot & rRoot)2674 XclImpScrollBarObj::XclImpScrollBarObj( const XclImpRoot& rRoot ) :
2675     XclImpTbxObjScrollableBase( rRoot )
2676 {
2677 }
2678 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2679 void XclImpScrollBarObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2680 {
2681     ReadFrameData( rStrm );
2682     ReadSbs( rStrm );
2683     ReadName5( rStrm, nNameLen );
2684     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2685     ReadCellLinkFormula( rStrm, true );
2686 }
2687 
DoProcessControl(ScfPropertySet & rPropSet) const2688 void XclImpScrollBarObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2689 {
2690     // Calc's "Border" property is not the 3D/flat style effect in Excel (#i34712#)
2691     rPropSet.SetProperty( u"Border"_ustr, css::awt::VisualEffect::NONE );
2692     rPropSet.SetProperty< sal_Int32 >( u"DefaultScrollValue"_ustr, mnValue );
2693     rPropSet.SetProperty< sal_Int32 >( u"ScrollValueMin"_ustr, mnMin );
2694     rPropSet.SetProperty< sal_Int32 >( u"ScrollValueMax"_ustr, mnMax );
2695     rPropSet.SetProperty< sal_Int32 >( u"LineIncrement"_ustr, mnStep );
2696     rPropSet.SetProperty< sal_Int32 >( u"BlockIncrement"_ustr, mnPageStep );
2697     rPropSet.SetProperty( u"VisibleSize"_ustr, ::std::min< sal_Int32 >( mnPageStep, 1 ) );
2698 
2699     namespace AwtScrollOrient = css::awt::ScrollBarOrientation;
2700     sal_Int32 nApiOrient = ::get_flagvalue( mnOrient, EXC_OBJ_SCROLLBAR_HOR, AwtScrollOrient::HORIZONTAL, AwtScrollOrient::VERTICAL );
2701     rPropSet.SetProperty( u"Orientation"_ustr, nApiOrient );
2702 }
2703 
DoGetServiceName() const2704 OUString XclImpScrollBarObj::DoGetServiceName() const
2705 {
2706     return u"com.sun.star.form.component.ScrollBar"_ustr;
2707 }
2708 
DoGetEventType() const2709 XclTbxEventType XclImpScrollBarObj::DoGetEventType() const
2710 {
2711     return EXC_TBX_EVENT_VALUE;
2712 }
2713 
XclImpTbxObjListBase(const XclImpRoot & rRoot)2714 XclImpTbxObjListBase::XclImpTbxObjListBase( const XclImpRoot& rRoot ) :
2715     XclImpTbxObjScrollableBase( rRoot ),
2716     mnEntryCount( 0 ),
2717     mnSelEntry( 0 ),
2718     mnListFlags( 0 ),
2719     mnEditObjId( 0 ),
2720     mbHasDefFontIdx( false )
2721 {
2722 }
2723 
ReadLbsData(XclImpStream & rStrm)2724 void XclImpTbxObjListBase::ReadLbsData( XclImpStream& rStrm )
2725 {
2726     ReadSourceRangeFormula( rStrm, true );
2727     mnEntryCount = rStrm.ReaduInt16();
2728     mnSelEntry = rStrm.ReaduInt16();
2729     mnListFlags = rStrm.ReaduInt16();
2730     mnEditObjId = rStrm.ReaduInt16();
2731 }
2732 
SetBoxFormatting(ScfPropertySet & rPropSet) const2733 void XclImpTbxObjListBase::SetBoxFormatting( ScfPropertySet& rPropSet ) const
2734 {
2735     // border style
2736     namespace AwtVisualEffect = css::awt::VisualEffect;
2737     sal_Int16 nApiBorder = ::get_flagvalue( mnListFlags, EXC_OBJ_LISTBOX_FLAT, AwtVisualEffect::FLAT, AwtVisualEffect::LOOK3D );
2738     rPropSet.SetProperty( u"Border"_ustr, nApiBorder );
2739 
2740     // font formatting
2741     if( mbHasDefFontIdx )
2742         GetFontBuffer().WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL, maTextData.maData.mnDefFontIdx );
2743     else
2744         GetFontBuffer().WriteDefaultCtrlFontProperties( rPropSet );
2745 }
2746 
XclImpListBoxObj(const XclImpRoot & rRoot)2747 XclImpListBoxObj::XclImpListBoxObj( const XclImpRoot& rRoot ) :
2748     XclImpTbxObjListBase( rRoot )
2749 {
2750 }
2751 
ReadFullLbsData(XclImpStream & rStrm,std::size_t nRecLeft)2752 void XclImpListBoxObj::ReadFullLbsData( XclImpStream& rStrm, std::size_t nRecLeft )
2753 {
2754     std::size_t nRecEnd = rStrm.GetRecPos() + nRecLeft;
2755     ReadLbsData( rStrm );
2756     OSL_ENSURE( (rStrm.GetRecPos() == nRecEnd) || (rStrm.GetRecPos() + mnEntryCount == nRecEnd),
2757         "XclImpListBoxObj::ReadFullLbsData - invalid size of OBJLBSDATA record" );
2758     while (rStrm.IsValid())
2759     {
2760         if (rStrm.GetRecPos() >= nRecEnd)
2761             break;
2762         maSelection.push_back( rStrm.ReaduInt8() );
2763     }
2764 }
2765 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2766 void XclImpListBoxObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2767 {
2768     ReadFrameData( rStrm );
2769     ReadSbs( rStrm );
2770     rStrm.Ignore( 18 );
2771     maTextData.maData.mnDefFontIdx = rStrm.ReaduInt16();
2772     rStrm.Ignore( 4 );
2773     ReadName5( rStrm, nNameLen );
2774     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2775     ReadCellLinkFormula( rStrm, true );
2776     ReadFullLbsData( rStrm, rStrm.GetRecLeft() );
2777     mbHasDefFontIdx = true;
2778 }
2779 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2780 void XclImpListBoxObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2781 {
2782     switch( nSubRecId )
2783     {
2784         case EXC_ID_OBJLBSDATA:
2785             ReadFullLbsData( rStrm, nSubRecSize );
2786         break;
2787         default:
2788             XclImpTbxObjListBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2789     }
2790 }
2791 
DoProcessControl(ScfPropertySet & rPropSet) const2792 void XclImpListBoxObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2793 {
2794     // listbox formatting
2795     SetBoxFormatting( rPropSet );
2796 
2797     // selection type
2798     sal_uInt8 nSelType = ::extract_value< sal_uInt8 >( mnListFlags, 4, 2 );
2799     bool bMultiSel = nSelType != EXC_OBJ_LISTBOX_SINGLE;
2800     rPropSet.SetBoolProperty( u"MultiSelection"_ustr, bMultiSel );
2801 
2802     // selection (do not set, if listbox is linked to a cell)
2803     if( HasCellLink() )
2804         return;
2805 
2806     ScfInt16Vec aSelVec;
2807 
2808     // multi selection: API expects sequence of list entry indexes
2809     if( bMultiSel )
2810     {
2811         sal_Int16 nIndex = 0;
2812         for( const auto& rItem : maSelection )
2813         {
2814             if( rItem != 0 )
2815                 aSelVec.push_back( nIndex );
2816             ++nIndex;
2817         }
2818     }
2819     // single selection: mnSelEntry is one-based, API expects zero-based
2820     else if( mnSelEntry > 0 )
2821         aSelVec.push_back( static_cast< sal_Int16 >( mnSelEntry - 1 ) );
2822 
2823     if( !aSelVec.empty() )
2824     {
2825         Sequence<sal_Int16> aSelSeq(aSelVec.data(), static_cast<sal_Int32>(aSelVec.size()));
2826         rPropSet.SetProperty( u"DefaultSelection"_ustr, aSelSeq );
2827     }
2828 }
2829 
DoGetServiceName() const2830 OUString XclImpListBoxObj::DoGetServiceName() const
2831 {
2832     return u"com.sun.star.form.component.ListBox"_ustr;
2833 }
2834 
DoGetEventType() const2835 XclTbxEventType XclImpListBoxObj::DoGetEventType() const
2836 {
2837     return EXC_TBX_EVENT_CHANGE;
2838 }
2839 
XclImpDropDownObj(const XclImpRoot & rRoot)2840 XclImpDropDownObj::XclImpDropDownObj( const XclImpRoot& rRoot ) :
2841     XclImpTbxObjListBase( rRoot ),
2842     mnLeft( 0 ),
2843     mnTop( 0 ),
2844     mnRight( 0 ),
2845     mnBottom( 0 ),
2846     mnDropDownFlags( 0 ),
2847     mnLineCount( 0 ),
2848     mnMinWidth( 0 )
2849 {
2850 }
2851 
GetDropDownType() const2852 sal_uInt16 XclImpDropDownObj::GetDropDownType() const
2853 {
2854     return ::extract_value< sal_uInt8 >( mnDropDownFlags, 0, 2 );
2855 }
2856 
ReadFullLbsData(XclImpStream & rStrm)2857 void XclImpDropDownObj::ReadFullLbsData( XclImpStream& rStrm )
2858 {
2859     ReadLbsData( rStrm );
2860     mnDropDownFlags = rStrm.ReaduInt16();
2861     mnLineCount = rStrm.ReaduInt16();
2862     mnMinWidth = rStrm.ReaduInt16();
2863     maTextData.maData.mnTextLen = rStrm.ReaduInt16();
2864     maTextData.ReadByteString( rStrm );
2865     // dropdowns of auto-filters have 'simple' style, they don't have a text area
2866     if( GetDropDownType() == EXC_OBJ_DROPDOWN_SIMPLE )
2867         SetProcessSdrObj( false );
2868 }
2869 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16)2870 void XclImpDropDownObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 /*nMacroSize*/ )
2871 {
2872     ReadFrameData( rStrm );
2873     ReadSbs( rStrm );
2874     rStrm.Ignore( 18 );
2875     maTextData.maData.mnDefFontIdx = rStrm.ReaduInt16();
2876     rStrm.Ignore( 14 );
2877     mnLeft = rStrm.ReaduInt16();
2878     mnTop = rStrm.ReaduInt16();
2879     mnRight = rStrm.ReaduInt16();
2880     mnBottom = rStrm.ReaduInt16();
2881     rStrm.Ignore( 4 );
2882     ReadName5( rStrm, nNameLen );
2883     ReadMacro5( rStrm, rStrm.ReaduInt16() );   // first macro size invalid and unused
2884     ReadCellLinkFormula( rStrm, true );
2885     ReadFullLbsData( rStrm );
2886     mbHasDefFontIdx = true;
2887 }
2888 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)2889 void XclImpDropDownObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
2890 {
2891     switch( nSubRecId )
2892     {
2893         case EXC_ID_OBJLBSDATA:
2894             ReadFullLbsData( rStrm );
2895         break;
2896         default:
2897             XclImpTbxObjListBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
2898     }
2899 }
2900 
DoProcessControl(ScfPropertySet & rPropSet) const2901 void XclImpDropDownObj::DoProcessControl( ScfPropertySet& rPropSet ) const
2902 {
2903     // dropdown listbox formatting
2904     SetBoxFormatting( rPropSet );
2905     // enable dropdown button
2906     rPropSet.SetBoolProperty( u"Dropdown"_ustr, true );
2907     // dropdown line count
2908     rPropSet.SetProperty( u"LineCount"_ustr, mnLineCount );
2909 
2910     if( GetDropDownType() == EXC_OBJ_DROPDOWN_COMBOBOX )
2911     {
2912         // text of editable combobox
2913         if( maTextData.mxString )
2914             rPropSet.SetStringProperty( u"DefaultText"_ustr, maTextData.mxString->GetText() );
2915     }
2916     else
2917     {
2918         // selection (do not set, if dropdown is linked to a cell)
2919         if( !HasCellLink() && (mnSelEntry > 0) )
2920         {
2921             Sequence< sal_Int16 > aSelSeq{ o3tl::narrowing<sal_Int16>(mnSelEntry - 1) };
2922             rPropSet.SetProperty( u"DefaultSelection"_ustr, aSelSeq );
2923         }
2924     }
2925 }
2926 
DoGetServiceName() const2927 OUString XclImpDropDownObj::DoGetServiceName() const
2928 {
2929     return (GetDropDownType() == EXC_OBJ_DROPDOWN_COMBOBOX) ?
2930         u"com.sun.star.form.component.ComboBox"_ustr :
2931         u"com.sun.star.form.component.ListBox"_ustr;
2932 }
2933 
DoGetEventType() const2934 XclTbxEventType XclImpDropDownObj::DoGetEventType() const
2935 {
2936     return (GetDropDownType() == EXC_OBJ_DROPDOWN_COMBOBOX) ? EXC_TBX_EVENT_TEXT : EXC_TBX_EVENT_CHANGE;
2937 }
2938 
XclImpPictureObj(const XclImpRoot & rRoot)2939 XclImpPictureObj::XclImpPictureObj( const XclImpRoot& rRoot ) :
2940     XclImpRectObj( rRoot ),
2941     XclImpControlHelper( rRoot, EXC_CTRL_BINDCONTENT ),
2942     mnStorageId( 0 ),
2943     mnCtlsStrmPos( 0 ),
2944     mnCtlsStrmSize( 0 ),
2945     mbEmbedded( false ),
2946     mbLinked( false ),
2947     mbSymbol( false ),
2948     mbControl( false ),
2949     mbUseCtlsStrm( false )
2950 {
2951     SetAreaObj( true );
2952     SetSimpleMacro( true );
2953     SetCustomDffObj( true );
2954 }
2955 
GetOleStorageName() const2956 OUString XclImpPictureObj::GetOleStorageName() const
2957 {
2958     OUStringBuffer aStrgName;
2959     if( (mbEmbedded || mbLinked) && !mbControl && (mnStorageId > 0) )
2960     {
2961         aStrgName = mbEmbedded ? std::u16string_view(u"" EXC_STORAGE_OLE_EMBEDDED) : std::u16string_view(u"" EXC_STORAGE_OLE_LINKED);
2962         static const char spcHexChars[] = "0123456789ABCDEF";
2963         for( sal_uInt8 nIndex = 32; nIndex > 0; nIndex -= 4 )
2964             aStrgName.append(OUStringChar( spcHexChars[ ::extract_value< sal_uInt8 >( mnStorageId, nIndex - 4, 4 ) ] ));
2965     }
2966     return aStrgName.makeStringAndClear();
2967 }
2968 
DoReadObj3(XclImpStream & rStrm,sal_uInt16 nMacroSize)2969 void XclImpPictureObj::DoReadObj3( XclImpStream& rStrm, sal_uInt16 nMacroSize )
2970 {
2971     sal_uInt16 nLinkSize;
2972     ReadFrameData( rStrm );
2973     rStrm.Ignore( 6 );
2974     nLinkSize = rStrm.ReaduInt16();
2975     rStrm.Ignore( 2 );
2976     ReadFlags3( rStrm );
2977     ReadMacro3( rStrm, nMacroSize );
2978     ReadPictFmla( rStrm, nLinkSize );
2979 
2980     if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
2981         maGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
2982 }
2983 
DoReadObj4(XclImpStream & rStrm,sal_uInt16 nMacroSize)2984 void XclImpPictureObj::DoReadObj4( XclImpStream& rStrm, sal_uInt16 nMacroSize )
2985 {
2986     sal_uInt16 nLinkSize;
2987     ReadFrameData( rStrm );
2988     rStrm.Ignore( 6 );
2989     nLinkSize = rStrm.ReaduInt16();
2990     rStrm.Ignore( 2 );
2991     ReadFlags3( rStrm );
2992     ReadMacro4( rStrm, nMacroSize );
2993     ReadPictFmla( rStrm, nLinkSize );
2994 
2995     if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
2996         maGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
2997 }
2998 
DoReadObj5(XclImpStream & rStrm,sal_uInt16 nNameLen,sal_uInt16 nMacroSize)2999 void XclImpPictureObj::DoReadObj5( XclImpStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
3000 {
3001     sal_uInt16 nLinkSize;
3002     ReadFrameData( rStrm );
3003     rStrm.Ignore( 6 );
3004     nLinkSize = rStrm.ReaduInt16();
3005     rStrm.Ignore( 2 );
3006     ReadFlags3( rStrm );
3007     rStrm.Ignore( 4 );
3008     ReadName5( rStrm, nNameLen );
3009     ReadMacro5( rStrm, nMacroSize );
3010     ReadPictFmla( rStrm, nLinkSize );
3011 
3012     if( (rStrm.GetNextRecId() == EXC_ID3_IMGDATA) && rStrm.StartNextRecord() )
3013     {
3014         // page background is stored as hidden picture with name "__BkgndObj"
3015         if ( IsHidden() && (GetObjName() == "__BkgndObj") )
3016             GetPageSettings().ReadImgData( rStrm );
3017         else
3018             maGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
3019     }
3020 }
3021 
DoReadObj8SubRec(XclImpStream & rStrm,sal_uInt16 nSubRecId,sal_uInt16 nSubRecSize)3022 void XclImpPictureObj::DoReadObj8SubRec( XclImpStream& rStrm, sal_uInt16 nSubRecId, sal_uInt16 nSubRecSize )
3023 {
3024     switch( nSubRecId )
3025     {
3026         case EXC_ID_OBJFLAGS:
3027             ReadFlags8( rStrm );
3028         break;
3029         case EXC_ID_OBJPICTFMLA:
3030             ReadPictFmla( rStrm, rStrm.ReaduInt16() );
3031         break;
3032         default:
3033             XclImpDrawObjBase::DoReadObj8SubRec( rStrm, nSubRecId, nSubRecSize );
3034     }
3035 }
3036 
DoCreateSdrObj(XclImpDffConverter & rDffConv,const tools::Rectangle & rAnchorRect) const3037 rtl::Reference<SdrObject> XclImpPictureObj::DoCreateSdrObj( XclImpDffConverter& rDffConv, const tools::Rectangle& rAnchorRect ) const
3038 {
3039     // try to create an OLE object or form control
3040     rtl::Reference<SdrObject> xSdrObj( rDffConv.CreateSdrObject( *this, rAnchorRect ) );
3041 
3042     // insert a graphic replacement for unsupported ole object ( if none already
3043     // exists ) Hmm ok, it's possibly that there has been some imported
3044     // graphic at a base level  but unlikely, normally controls have a valid
3045     // preview in the IMGDATA record ( see below )
3046     // It might be possible to push such an imported graphic up to this
3047     // XclImpPictureObj instance but there are so many layers of indirection I
3048     // don't see an easy way. This way at least ensures that we can
3049     // avoid a 'blank' shape that can result from a failed control import
3050     if ( !xSdrObj && IsOcxControl() && maGraphic.GetType() == GraphicType::NONE )
3051     {
3052         const_cast< XclImpPictureObj* >( this )->maGraphic =
3053                 SdrOle2Obj::GetEmptyOLEReplacementGraphic();
3054     }
3055     // no OLE - create a plain picture from IMGDATA record data
3056     if( !xSdrObj && (maGraphic.GetType() != GraphicType::NONE) )
3057     {
3058         xSdrObj =
3059             new SdrGrafObj(
3060                 *GetDoc().GetDrawLayer(),
3061                 maGraphic,
3062                 rAnchorRect);
3063         ConvertRectStyle( *xSdrObj );
3064     }
3065 
3066     rDffConv.Progress();
3067     return xSdrObj;
3068 }
3069 
GetObjName() const3070 OUString XclImpPictureObj::GetObjName() const
3071 {
3072     if( IsOcxControl() )
3073     {
3074         OUString sName( GetObjectManager().GetOleNameOverride( GetTab(), GetObjId() ) );
3075         if (!sName.isEmpty())
3076             return sName;
3077     }
3078     return XclImpDrawObjBase::GetObjName();
3079 }
3080 
DoPreProcessSdrObj(XclImpDffConverter & rDffConv,SdrObject & rSdrObj) const3081 void XclImpPictureObj::DoPreProcessSdrObj( XclImpDffConverter& rDffConv, SdrObject& rSdrObj ) const
3082 {
3083     if( IsOcxControl() )
3084     {
3085         // do not call XclImpRectObj::DoPreProcessSdrObj(), it would trace missing "printable" feature
3086         ProcessControl( *this );
3087     }
3088     else if( mbEmbedded || mbLinked )
3089     {
3090         // trace missing "printable" feature
3091         XclImpRectObj::DoPreProcessSdrObj( rDffConv, rSdrObj );
3092 
3093         SfxObjectShell* pDocShell = GetDocShell();
3094         SdrOle2Obj* pOleSdrObj = dynamic_cast< SdrOle2Obj* >( &rSdrObj );
3095         if( pOleSdrObj && pDocShell )
3096         {
3097             comphelper::EmbeddedObjectContainer& rEmbObjCont = pDocShell->GetEmbeddedObjectContainer();
3098             Reference< XEmbeddedObject > xEmbObj = pOleSdrObj->GetObjRef();
3099             OUString aOldName( pOleSdrObj->GetPersistName() );
3100 
3101             /*  The object persistence should be already in the storage, but
3102                 the object still might not be inserted into the container. */
3103             if( rEmbObjCont.HasEmbeddedObject( aOldName ) )
3104             {
3105                 if( !rEmbObjCont.HasEmbeddedObject( xEmbObj ) )
3106                     // filter code is allowed to call the following method
3107                     rEmbObjCont.AddEmbeddedObject( xEmbObj, aOldName );
3108             }
3109             else
3110             {
3111                 /*  If the object is still not in container it must be inserted
3112                     there, the name must be generated in this case. */
3113                 OUString aNewName;
3114                 rEmbObjCont.InsertEmbeddedObject( xEmbObj, aNewName );
3115                 if( aOldName != aNewName )
3116                     // SetPersistName, not SetName
3117                     pOleSdrObj->SetPersistName( aNewName );
3118             }
3119         }
3120     }
3121 }
3122 
ReadFlags3(XclImpStream & rStrm)3123 void XclImpPictureObj::ReadFlags3( XclImpStream& rStrm )
3124 {
3125     sal_uInt16 nFlags;
3126     nFlags = rStrm.ReaduInt16();
3127     mbSymbol = ::get_flag( nFlags, EXC_OBJ_PIC_SYMBOL );
3128 }
3129 
ReadFlags8(XclImpStream & rStrm)3130 void XclImpPictureObj::ReadFlags8( XclImpStream& rStrm )
3131 {
3132     sal_uInt16 nFlags;
3133     nFlags = rStrm.ReaduInt16();
3134     mbSymbol      = ::get_flag( nFlags, EXC_OBJ_PIC_SYMBOL );
3135     mbControl     = ::get_flag( nFlags, EXC_OBJ_PIC_CONTROL );
3136     mbUseCtlsStrm = ::get_flag( nFlags, EXC_OBJ_PIC_CTLSSTREAM );
3137     OSL_ENSURE( mbControl || !mbUseCtlsStrm, "XclImpPictureObj::ReadFlags8 - CTLS stream for controls only" );
3138     SetProcessSdrObj( mbControl || !mbUseCtlsStrm );
3139 }
3140 
ReadPictFmla(XclImpStream & rStrm,sal_uInt16 nLinkSize)3141 void XclImpPictureObj::ReadPictFmla( XclImpStream& rStrm, sal_uInt16 nLinkSize )
3142 {
3143     std::size_t nLinkEnd = rStrm.GetRecPos() + nLinkSize;
3144     if( nLinkSize >= 6 )
3145     {
3146         sal_uInt16 nFmlaSize;
3147         nFmlaSize = rStrm.ReaduInt16();
3148         OSL_ENSURE( nFmlaSize > 0, "XclImpPictureObj::ReadPictFmla - missing link formula" );
3149         // BIFF3/BIFF4 do not support storages, nothing to do here
3150         if( (nFmlaSize > 0) && (GetBiff() >= EXC_BIFF5) )
3151         {
3152             rStrm.Ignore( 4 );
3153             sal_uInt8 nToken;
3154             nToken = rStrm.ReaduInt8();
3155 
3156             // different processing for linked vs. embedded OLE objects
3157             if( nToken == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ) )
3158             {
3159                 mbLinked = true;
3160                 switch( GetBiff() )
3161                 {
3162                     case EXC_BIFF5:
3163                     {
3164                         sal_Int16 nRefIdx;
3165                         sal_uInt16 nNameIdx;
3166                         nRefIdx = rStrm.ReadInt16();
3167                         rStrm.Ignore( 8 );
3168                         nNameIdx = rStrm.ReaduInt16();
3169                         rStrm.Ignore( 12 );
3170                         const ExtName* pExtName = GetOldRoot().pExtNameBuff->GetNameByIndex( nRefIdx, nNameIdx );
3171                         if( pExtName && pExtName->IsOLE() )
3172                             mnStorageId = pExtName->nStorageId;
3173                     }
3174                     break;
3175                     case EXC_BIFF8:
3176                     {
3177                         sal_uInt16 nXti, nExtName;
3178                         nXti = rStrm.ReaduInt16();
3179                         nExtName = rStrm.ReaduInt16();
3180                         const XclImpExtName* pExtName = GetLinkManager().GetExternName( nXti, nExtName );
3181                         if( pExtName && (pExtName->GetType() == xlExtOLE) )
3182                             mnStorageId = pExtName->GetStorageId();
3183                     }
3184                     break;
3185                     default:
3186                         DBG_ERROR_BIFF();
3187                 }
3188             }
3189             else if( nToken == XclTokenArrayHelper::GetTokenId( EXC_TOKID_TBL, EXC_TOKCLASS_NONE ) )
3190             {
3191                 mbEmbedded = true;
3192                 OSL_ENSURE( nFmlaSize == 5, "XclImpPictureObj::ReadPictFmla - unexpected formula size" );
3193                 rStrm.Ignore( nFmlaSize - 1 );      // token ID already read
3194                 if( nFmlaSize & 1 )
3195                     rStrm.Ignore( 1 );              // padding byte
3196 
3197                 // a class name may follow inside the picture link
3198                 if( rStrm.GetRecPos() + 2 <= nLinkEnd )
3199                 {
3200                     sal_uInt16 nLen = rStrm.ReaduInt16();
3201                     if( nLen > 0 )
3202                         maClassName = (GetBiff() == EXC_BIFF8) ? rStrm.ReadUniString( nLen ) : rStrm.ReadRawByteString( nLen );
3203                 }
3204             }
3205             // else: ignore other formulas, e.g. pictures linked to cell ranges
3206         }
3207     }
3208 
3209     // seek behind picture link data
3210     rStrm.Seek( nLinkEnd );
3211 
3212     // read additional data for embedded OLE objects following the picture link
3213     if( IsOcxControl() )
3214     {
3215         // #i26521# form controls to be ignored
3216         if( maClassName == "Forms.HTML:Hidden.1"  )
3217         {
3218             SetProcessSdrObj( false );
3219             return;
3220         }
3221 
3222         if( rStrm.GetRecLeft() <= 8 ) return;
3223 
3224         // position and size of control data in 'Ctls' stream
3225         mnCtlsStrmPos = static_cast< std::size_t >( rStrm.ReaduInt32() );
3226         mnCtlsStrmSize = static_cast< std::size_t >( rStrm.ReaduInt32() );
3227 
3228         if( rStrm.GetRecLeft() <= 8 ) return;
3229 
3230         // additional string (16-bit characters), e.g. for progress bar control
3231         sal_uInt32 nAddStrSize;
3232         nAddStrSize = rStrm.ReaduInt32();
3233         OSL_ENSURE( rStrm.GetRecLeft() >= nAddStrSize + 4, "XclImpPictureObj::ReadPictFmla - missing data" );
3234         if( rStrm.GetRecLeft() >= nAddStrSize + 4 )
3235         {
3236             rStrm.Ignore( nAddStrSize );
3237             // cell link and source range
3238             ReadCellLinkFormula( rStrm, true );
3239             ReadSourceRangeFormula( rStrm, true );
3240         }
3241     }
3242     else if( mbEmbedded && (rStrm.GetRecLeft() >= 4) )
3243     {
3244         mnStorageId = rStrm.ReaduInt32();
3245     }
3246 }
3247 
3248 // DFF stream conversion ======================================================
3249 
InsertSdrObjectInfo(SdrObject & rSdrObj,sal_uInt32 nDffShapeId,ShapeFlag nDffFlags)3250 void XclImpSolverContainer::InsertSdrObjectInfo( SdrObject& rSdrObj, sal_uInt32 nDffShapeId, ShapeFlag nDffFlags )
3251 {
3252     if( nDffShapeId > 0 )
3253     {
3254         maSdrInfoMap[ nDffShapeId ].Set( &rSdrObj, nDffFlags );
3255         maSdrObjMap[ &rSdrObj ] = nDffShapeId;
3256     }
3257 }
3258 
RemoveSdrObjectInfo(SdrObject & rSdrObj)3259 void XclImpSolverContainer::RemoveSdrObjectInfo( SdrObject& rSdrObj )
3260 {
3261     // remove info of passed object from the maps
3262     XclImpSdrObjMap::iterator aIt = maSdrObjMap.find( &rSdrObj );
3263     if( aIt != maSdrObjMap.end() )
3264     {
3265         maSdrInfoMap.erase( aIt->second );
3266         maSdrObjMap.erase( aIt );
3267     }
3268 
3269     // remove info of all child objects of a group object
3270     if( SdrObjGroup* pGroupObj = dynamic_cast< SdrObjGroup* >( &rSdrObj ) )
3271     {
3272         if( SdrObjList* pSubList = pGroupObj->GetSubList() )
3273         {
3274             // iterate flat over the list because this function already works recursively
3275             SdrObjListIter aObjIt( pSubList, SdrIterMode::Flat );
3276             for( SdrObject* pChildObj = aObjIt.Next(); pChildObj; pChildObj = aObjIt.Next() )
3277                 RemoveSdrObjectInfo( *pChildObj );
3278         }
3279     }
3280 }
3281 
UpdateConnectorRules()3282 void XclImpSolverContainer::UpdateConnectorRules()
3283 {
3284     for (auto const & pRule : aCList)
3285     {
3286         UpdateConnection( pRule->nShapeA, pRule->pAObj, &pRule->nSpFlagsA );
3287         UpdateConnection( pRule->nShapeB, pRule->pBObj, &pRule->nSpFlagsB );
3288         UpdateConnection( pRule->nShapeC, pRule->pCObj );
3289     }
3290 }
3291 
RemoveConnectorRules()3292 void XclImpSolverContainer::RemoveConnectorRules()
3293 {
3294     aCList.clear();
3295     maSdrInfoMap.clear();
3296     maSdrObjMap.clear();
3297 }
3298 
UpdateConnection(sal_uInt32 nDffShapeId,SdrObject * & rpSdrObj,ShapeFlag * pnDffFlags)3299 void XclImpSolverContainer::UpdateConnection( sal_uInt32 nDffShapeId, SdrObject*& rpSdrObj, ShapeFlag* pnDffFlags )
3300 {
3301     XclImpSdrInfoMap::const_iterator aIt = maSdrInfoMap.find( nDffShapeId );
3302     if( aIt != maSdrInfoMap.end() )
3303     {
3304         rpSdrObj = aIt->second.mpSdrObj;
3305         if( pnDffFlags )
3306             *pnDffFlags = aIt->second.mnDffFlags;
3307     }
3308 }
3309 
XclImpSimpleDffConverter(const XclImpRoot & rRoot,SvStream & rDffStrm)3310 XclImpSimpleDffConverter::XclImpSimpleDffConverter( const XclImpRoot& rRoot, SvStream& rDffStrm ) :
3311     SvxMSDffManager( rDffStrm, rRoot.GetBasePath(), 0, nullptr, rRoot.GetDoc().GetDrawLayer(), 1440, COL_DEFAULT, nullptr ),
3312     XclImpRoot( rRoot )
3313 {
3314     SetSvxMSDffSettings( SVXMSDFF_SETTINGS_CROP_BITMAPS | SVXMSDFF_SETTINGS_IMPORT_EXCEL );
3315 }
3316 
~XclImpSimpleDffConverter()3317 XclImpSimpleDffConverter::~XclImpSimpleDffConverter()
3318 {
3319 }
3320 
GetColorFromPalette(sal_uInt16 nIndex,Color & rColor) const3321 bool XclImpSimpleDffConverter::GetColorFromPalette( sal_uInt16 nIndex, Color& rColor ) const
3322 {
3323     Color nColor = GetPalette().GetColor( nIndex );
3324 
3325     if( nColor == COL_AUTO )
3326         return false;
3327 
3328     rColor = nColor;
3329     return true;
3330 }
3331 
XclImpDffConvData(XclImpDrawing & rDrawing,SdrModel & rSdrModel,SdrPage & rSdrPage)3332 XclImpDffConverter::XclImpDffConvData::XclImpDffConvData(
3333         XclImpDrawing& rDrawing, SdrModel& rSdrModel, SdrPage& rSdrPage ) :
3334     mrDrawing( rDrawing ),
3335     mrSdrModel( rSdrModel ),
3336     mrSdrPage( rSdrPage ),
3337     mnLastCtrlIndex( -1 ),
3338     mbHasCtrlForm( false )
3339 {
3340 }
3341 
3342 constexpr OUString gaStdFormName( u"Standard"_ustr ); /// Standard name of control forms.
3343 
XclImpDffConverter(const XclImpRoot & rRoot,SvStream & rDffStrm)3344 XclImpDffConverter::XclImpDffConverter( const XclImpRoot& rRoot, SvStream& rDffStrm ) :
3345     XclImpSimpleDffConverter( rRoot, rDffStrm ),
3346     oox::ole::MSConvertOCXControls( rRoot.GetDocShell()->GetModel() ),
3347     mnOleImpFlags( 0 ),
3348     mbNotifyMacroEventRead(false)
3349 {
3350     if( officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::get() )
3351         mnOleImpFlags |= OLE_MATHTYPE_2_STARMATH;
3352     if( officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::get() )
3353         mnOleImpFlags |= OLE_WINWORD_2_STARWRITER;
3354     if( officecfg::Office::Common::Filter::Microsoft::Import::PowerPointToImpress::get() )
3355         mnOleImpFlags |= OLE_POWERPOINT_2_STARIMPRESS;
3356 
3357     // try to open the 'Ctls' storage stream containing OCX control properties
3358     mxCtlsStrm = OpenStream( EXC_STREAM_CTLS );
3359 
3360     // default text margin (convert EMU to drawing layer units)
3361     mnDefTextMargin = EXC_OBJ_TEXT_MARGIN;
3362     ScaleEmu( mnDefTextMargin );
3363 }
3364 
~XclImpDffConverter()3365 XclImpDffConverter::~XclImpDffConverter()
3366 {
3367 }
3368 
GetOleNameOverride(SCTAB nTab,sal_uInt16 nObjId)3369 OUString XclImpObjectManager::GetOleNameOverride( SCTAB nTab, sal_uInt16 nObjId )
3370 {
3371     OUString sOleName;
3372     OUString sCodeName = GetExtDocOptions().GetCodeName( nTab );
3373 
3374     if (mxOleCtrlNameOverride.is() && mxOleCtrlNameOverride->hasByName(sCodeName))
3375     {
3376         Reference< XIndexContainer > xIdToOleName;
3377         mxOleCtrlNameOverride->getByName( sCodeName ) >>= xIdToOleName;
3378         xIdToOleName->getByIndex( nObjId ) >>= sOleName;
3379     }
3380 
3381     return sOleName;
3382 }
3383 
StartProgressBar(std::size_t nProgressSize)3384 void XclImpDffConverter::StartProgressBar( std::size_t nProgressSize )
3385 {
3386     mxProgress = std::make_shared<ScfProgressBar>( GetDocShell(), STR_PROGRESS_CALCULATING );
3387     mxProgress->AddSegment( nProgressSize );
3388     mxProgress->Activate();
3389 }
3390 
Progress(std::size_t nDelta)3391 void XclImpDffConverter::Progress( std::size_t nDelta )
3392 {
3393     OSL_ENSURE( mxProgress, "XclImpDffConverter::Progress - invalid call, no progress bar" );
3394     mxProgress->Progress( nDelta );
3395 }
3396 
InitializeDrawing(XclImpDrawing & rDrawing,SdrModel & rSdrModel,SdrPage & rSdrPage)3397 void XclImpDffConverter::InitializeDrawing( XclImpDrawing& rDrawing, SdrModel& rSdrModel, SdrPage& rSdrPage )
3398 {
3399     XclImpDffConvDataRef xConvData = std::make_shared<XclImpDffConvData>( rDrawing, rSdrModel, rSdrPage );
3400     maDataStack.push_back( xConvData );
3401     SetModel( &xConvData->mrSdrModel, 1440 );
3402 }
3403 
ProcessObject(SdrObjList & rObjList,XclImpDrawObjBase & rDrawObj)3404 void XclImpDffConverter::ProcessObject( SdrObjList& rObjList, XclImpDrawObjBase& rDrawObj )
3405 {
3406     if( !rDrawObj.IsProcessSdrObj() )
3407         return;
3408 
3409     const XclObjAnchor* pAnchor = rDrawObj.GetAnchor();
3410     if(!pAnchor)
3411         return;
3412 
3413     tools::Rectangle aAnchorRect = GetConvData().mrDrawing.CalcAnchorRect( *pAnchor, false );
3414     if( rDrawObj.IsValidSize( aAnchorRect ) )
3415     {
3416         // CreateSdrObject() recursively creates embedded child objects
3417         rtl::Reference<SdrObject> xSdrObj( rDrawObj.CreateSdrObject( *this, aAnchorRect, false ) );
3418         if( xSdrObj )
3419             rDrawObj.PreProcessSdrObject( *this, *xSdrObj );
3420         // call InsertSdrObject() also, if SdrObject is missing
3421         InsertSdrObject( rObjList, rDrawObj, xSdrObj.get() );
3422     }
3423 }
3424 
ProcessDrawing(const XclImpDrawObjVector & rDrawObjs)3425 void XclImpDffConverter::ProcessDrawing( const XclImpDrawObjVector& rDrawObjs )
3426 {
3427     SdrPage& rSdrPage = GetConvData().mrSdrPage;
3428     for( const auto& rxDrawObj : rDrawObjs )
3429         ProcessObject( rSdrPage, *rxDrawObj );
3430 }
3431 
ProcessDrawing(SvStream & rDffStrm)3432 void XclImpDffConverter::ProcessDrawing( SvStream& rDffStrm )
3433 {
3434     if( rDffStrm.TellEnd() > 0 )
3435     {
3436         rDffStrm.Seek( STREAM_SEEK_TO_BEGIN );
3437         DffRecordHeader aHeader;
3438         ReadDffRecordHeader( rDffStrm, aHeader );
3439         OSL_ENSURE( aHeader.nRecType == DFF_msofbtDgContainer, "XclImpDffConverter::ProcessDrawing - unexpected record" );
3440         if( aHeader.nRecType == DFF_msofbtDgContainer )
3441             ProcessDgContainer( rDffStrm, aHeader );
3442     }
3443 }
3444 
FinalizeDrawing()3445 void XclImpDffConverter::FinalizeDrawing()
3446 {
3447     OSL_ENSURE( !maDataStack.empty(), "XclImpDffConverter::FinalizeDrawing - no drawing manager on stack" );
3448     maDataStack.pop_back();
3449     // restore previous model at core DFF converter
3450     if( !maDataStack.empty() )
3451         SetModel( &maDataStack.back()->mrSdrModel, 1440 );
3452 }
3453 
NotifyMacroEventRead()3454 void XclImpDffConverter::NotifyMacroEventRead()
3455 {
3456     if (mbNotifyMacroEventRead)
3457         return;
3458     comphelper::DocumentInfo::notifyMacroEventRead(mxModel);
3459     mbNotifyMacroEventRead = true;
3460 }
3461 
CreateSdrObject(const XclImpTbxObjBase & rTbxObj,const tools::Rectangle & rAnchorRect)3462 rtl::Reference<SdrObject> XclImpDffConverter::CreateSdrObject( const XclImpTbxObjBase& rTbxObj, const tools::Rectangle& rAnchorRect )
3463 {
3464     rtl::Reference<SdrObject> xSdrObj;
3465 
3466     OUString aServiceName = rTbxObj.GetServiceName();
3467     if( SupportsOleObjects() && !aServiceName.isEmpty() ) try
3468     {
3469         // create the form control from scratch
3470         Reference< XFormComponent > xFormComp( ScfApiHelper::CreateInstance( GetDocShell(), aServiceName ), UNO_QUERY_THROW );
3471         // set controls form, needed in virtual function InsertControl()
3472         InitControlForm();
3473         // try to insert the control into the form
3474         css::awt::Size aDummySize;
3475         Reference< XShape > xShape;
3476         XclImpDffConvData& rConvData = GetConvData();
3477         if( rConvData.mxCtrlForm.is() && InsertControl( xFormComp, aDummySize, &xShape, true ) )
3478         {
3479             xSdrObj = rTbxObj.CreateSdrObjectFromShape( xShape, rAnchorRect );
3480             // try to attach a macro to the control
3481             ScriptEventDescriptor aDescriptor;
3482             if( (rConvData.mnLastCtrlIndex >= 0) && rTbxObj.FillMacroDescriptor( aDescriptor ) )
3483             {
3484                 NotifyMacroEventRead();
3485                 Reference< XEventAttacherManager > xEventMgr( rConvData.mxCtrlForm, UNO_QUERY_THROW );
3486                 xEventMgr->registerScriptEvent( rConvData.mnLastCtrlIndex, aDescriptor );
3487             }
3488         }
3489     }
3490     catch( const Exception& )
3491     {
3492     }
3493 
3494     return xSdrObj;
3495 }
3496 
CreateSdrObject(const XclImpPictureObj & rPicObj,const tools::Rectangle & rAnchorRect)3497 rtl::Reference<SdrObject> XclImpDffConverter::CreateSdrObject( const XclImpPictureObj& rPicObj, const tools::Rectangle& rAnchorRect )
3498 {
3499     rtl::Reference<SdrObject> xSdrObj;
3500 
3501     if( SupportsOleObjects() )
3502     {
3503         if( rPicObj.IsOcxControl() )
3504         {
3505             if( mxCtlsStrm.is() ) try
3506             {
3507                 /*  set controls form, needed in virtual function InsertControl()
3508                     called from ReadOCXExcelKludgeStream() */
3509                 InitControlForm();
3510 
3511                 // read from mxCtlsStrm into xShape, insert the control model into the form
3512                 Reference< XShape > xShape;
3513                 if( GetConvData().mxCtrlForm.is() )
3514                 {
3515                      Reference< XFormComponent >  xFComp;
3516                      ReadOCXCtlsStream( mxCtlsStrm, xFComp, rPicObj.GetCtlsStreamPos(),  rPicObj.GetCtlsStreamSize() );
3517                      // recreate the method formerly known as ReadOCXExcelKludgeStream()
3518                      if ( xFComp.is() )
3519                      {
3520                          css::awt::Size aSz;  // not used in import
3521                          ScfPropertySet aPropSet( xFComp );
3522                          aPropSet.SetStringProperty( u"Name"_ustr, rPicObj.GetObjName() );
3523                          InsertControl( xFComp, aSz,&xShape,true);
3524                          xSdrObj = rPicObj.CreateSdrObjectFromShape( xShape, rAnchorRect );
3525                      }
3526                 }
3527             }
3528             catch( const Exception& )
3529             {
3530             }
3531         }
3532         else
3533         {
3534             SfxObjectShell* pDocShell = GetDocShell();
3535             rtl::Reference<SotStorage> xSrcStrg = GetRootStorage();
3536             OUString aStrgName = rPicObj.GetOleStorageName();
3537             if( pDocShell && xSrcStrg.is() && (!aStrgName.isEmpty()) )
3538             {
3539                 // first try to resolve graphic from DFF storage
3540                 Graphic aGraphic;
3541                 tools::Rectangle aVisArea;
3542                 if( !GetBLIP( GetPropertyValue( DFF_Prop_pib, 0 ), aGraphic, &aVisArea ) )
3543                 {
3544                     // if not found, use graphic from object (imported from IMGDATA record)
3545                     aGraphic = rPicObj.GetGraphic();
3546                 }
3547                 if( aGraphic.GetType() != GraphicType::NONE )
3548                 {
3549                     ErrCode nError = ERRCODE_NONE;
3550                     namespace cssea = css::embed::Aspects;
3551                     sal_Int64 nAspects = rPicObj.IsSymbol() ? cssea::MSOLE_ICON : cssea::MSOLE_CONTENT;
3552                     xSdrObj =
3553                         CreateSdrOLEFromStorage(
3554                             GetConvData().mrSdrModel,
3555                             aStrgName,
3556                             xSrcStrg,
3557                             pDocShell->GetStorage(),
3558                             aGraphic,
3559                             rAnchorRect,
3560                             aVisArea,
3561                             nullptr,
3562                             nError,
3563                             mnOleImpFlags,
3564                             nAspects,
3565                             GetRoot().GetMedium().GetBaseURL());
3566                 }
3567             }
3568         }
3569     }
3570 
3571     return xSdrObj;
3572 }
3573 
SupportsOleObjects() const3574 bool XclImpDffConverter::SupportsOleObjects() const
3575 {
3576     return GetConvData().mrDrawing.SupportsOleObjects();
3577 }
3578 
3579 // virtual functions ----------------------------------------------------------
3580 
ProcessClientAnchor2(SvStream & rDffStrm,DffRecordHeader & rHeader,DffObjData & rObjData)3581 void XclImpDffConverter::ProcessClientAnchor2( SvStream& rDffStrm,
3582         DffRecordHeader& rHeader, DffObjData& rObjData )
3583 {
3584     // find the OBJ record data related to the processed shape
3585     XclImpDffConvData& rConvData = GetConvData();
3586     XclImpDrawObjBase* pDrawObj = rConvData.mrDrawing.FindDrawObj( rObjData.rSpHd ).get();
3587     if(!pDrawObj)
3588         return;
3589 
3590     OSL_ENSURE( rHeader.nRecType == DFF_msofbtClientAnchor, "XclImpDffConverter::ProcessClientAnchor2 - no client anchor record" );
3591     XclObjAnchor aAnchor;
3592     rHeader.SeekToContent( rDffStrm );
3593     sal_uInt8 nFlags(0);
3594     rDffStrm.ReadUChar( nFlags );
3595     rDffStrm.SeekRel( 1 );  // flags
3596     rDffStrm >> aAnchor;    // anchor format equal to BIFF5 OBJ records
3597 
3598     if (!rDffStrm.good())
3599     {
3600         SAL_WARN("sc.filter", "ProcessClientAnchor2 short read");
3601         return;
3602     }
3603 
3604     pDrawObj->SetAnchor( aAnchor );
3605     rObjData.aChildAnchor = rConvData.mrDrawing.CalcAnchorRect( aAnchor, true );
3606     rObjData.bChildAnchor = true;
3607     // page anchoring is the best approximation we have if mbMove
3608     // is set
3609     rObjData.bPageAnchor = ( nFlags & 0x1 );
3610 }
3611 
3612 namespace {
3613 
3614 struct XclImpDrawObjClientData : public SvxMSDffClientData
3615 {
3616     const XclImpDrawObjBase* m_pTopLevelObj;
3617 
XclImpDrawObjClientData__anon00bc00ab0511::XclImpDrawObjClientData3618     XclImpDrawObjClientData()
3619         : m_pTopLevelObj(nullptr)
3620     {
3621     }
NotifyFreeObj__anon00bc00ab0511::XclImpDrawObjClientData3622     virtual void NotifyFreeObj(SdrObject*) override {}
3623 };
3624 
3625 }
3626 
ProcessObj(SvStream & rDffStrm,DffObjData & rDffObjData,SvxMSDffClientData & rClientData,tools::Rectangle &,SdrObject * pOldSdrObj)3627 rtl::Reference<SdrObject> XclImpDffConverter::ProcessObj( SvStream& rDffStrm, DffObjData& rDffObjData,
3628         SvxMSDffClientData& rClientData, tools::Rectangle& /*rTextRect*/, SdrObject* pOldSdrObj )
3629 {
3630     XclImpDffConvData& rConvData = GetConvData();
3631 
3632     /*  pOldSdrObj passes a generated SdrObject. This function owns this object
3633         and can modify it. The function has either to return it back to caller
3634         or to delete it by itself. */
3635     rtl::Reference<SdrObject> xSdrObj( pOldSdrObj );
3636 
3637     // find the OBJ record data related to the processed shape
3638     XclImpDrawObjRef xDrawObj = rConvData.mrDrawing.FindDrawObj( rDffObjData.rSpHd );
3639     const tools::Rectangle& rAnchorRect = rDffObjData.aChildAnchor;
3640 
3641     // Do not process the global page group shape
3642     bool bGlobalPageGroup( rDffObjData.nSpFlags & ShapeFlag::Patriarch );
3643     if( !xDrawObj || !xDrawObj->IsProcessSdrObj() || bGlobalPageGroup )
3644         return nullptr;   // simply return, xSdrObj will be destroyed
3645 
3646     /*  Pass pointer to top-level object back to caller. If the processed
3647         object is embedded in a group, the pointer is already set to the
3648         top-level parent object. */
3649     XclImpDrawObjClientData& rDrawObjClientData = static_cast<XclImpDrawObjClientData&>(rClientData);
3650     const bool bIsTopLevel = !rDrawObjClientData.m_pTopLevelObj;
3651     if (bIsTopLevel )
3652         rDrawObjClientData.m_pTopLevelObj = xDrawObj.get();
3653 
3654     // connectors don't have to be area objects
3655     if( dynamic_cast< SdrEdgeObj* >( xSdrObj.get() ) )
3656         xDrawObj->SetAreaObj( false );
3657 
3658     /*  Check for valid size for all objects. Needed to ignore lots of invisible
3659         phantom objects from deleted rows or columns (for performance reasons).
3660         #i30816# Include objects embedded in groups.
3661         #i58780# Ignore group shapes, size is not initialized. */
3662     bool bEmbeddedGroup = !bIsTopLevel && dynamic_cast< SdrObjGroup* >( xSdrObj.get() );
3663     if( !bEmbeddedGroup && !xDrawObj->IsValidSize( rAnchorRect ) )
3664         return nullptr;   // simply return, xSdrObj will be destroyed
3665 
3666     // set shape information from DFF stream
3667     OUString aObjName = GetPropertyString( DFF_Prop_wzName, rDffStrm );
3668     OUString aHyperlink = ReadHlinkProperty( rDffStrm );
3669     bool bVisible = !GetPropertyBool( DFF_Prop_fHidden );
3670     bool bAutoMargin = GetPropertyBool( DFF_Prop_AutoTextMargin );
3671     xDrawObj->SetDffData( rDffObjData, aObjName, aHyperlink, bVisible, bAutoMargin );
3672 
3673     /*  Connect textbox data (string, alignment, text orientation) to object.
3674         don't ask for a text-ID, DFF export doesn't set one. */
3675     if( XclImpTextObj* pTextObj = dynamic_cast< XclImpTextObj* >( xDrawObj.get() ) )
3676         if( const XclImpObjTextData* pTextData = rConvData.mrDrawing.FindTextData( rDffObjData.rSpHd ) )
3677             pTextObj->SetTextData( *pTextData );
3678 
3679     // copy line and fill formatting of TBX form controls from DFF properties
3680     if( XclImpTbxObjBase* pTbxObj = dynamic_cast< XclImpTbxObjBase* >( xDrawObj.get() ) )
3681         pTbxObj->SetDffProperties( *this );
3682 
3683     // try to create a custom SdrObject that overwrites the passed object
3684     rtl::Reference<SdrObject> xNewSdrObj( xDrawObj->CreateSdrObject( *this, rAnchorRect, true ) );
3685     if( xNewSdrObj )
3686         xSdrObj = std::move( xNewSdrObj );
3687 
3688     // process the SdrObject
3689     if( xSdrObj )
3690     {
3691         // filled without color -> set system window color
3692         if( GetPropertyBool( DFF_Prop_fFilled ) && !IsProperty( DFF_Prop_fillColor ) )
3693             xSdrObj->SetMergedItem( XFillColorItem( OUString(), GetPalette().GetColor( EXC_COLOR_WINDOWBACK ) ) );
3694 
3695         // additional processing on the SdrObject
3696         xDrawObj->PreProcessSdrObject( *this, *xSdrObj );
3697 
3698         /*  If the SdrObject will not be inserted into the draw page, delete it
3699             here. Happens e.g. for notes: The PreProcessSdrObject() call above
3700             has inserted the note into the document, and the SdrObject is not
3701             needed anymore. */
3702         if( !xDrawObj->IsInsertSdrObj() )
3703             xSdrObj.clear();
3704     }
3705 
3706     if( xSdrObj )
3707     {
3708         /*  Store the relation between shape ID and SdrObject for connectors.
3709             Must be done here (and not in InsertSdrObject() function),
3710             otherwise all SdrObjects embedded in groups would be lost. */
3711         rConvData.maSolverCont.InsertSdrObjectInfo( *xSdrObj, xDrawObj->GetDffShapeId(), xDrawObj->GetDffFlags() );
3712 
3713         /*  If the drawing object is embedded in a group object, call
3714             PostProcessSdrObject() here. For top-level objects this will be
3715             done automatically in InsertSdrObject() but grouped shapes are
3716             inserted into their groups somewhere in the SvxMSDffManager base
3717             class without chance of notification. Unfortunately, now this is
3718             called before the object is really inserted into its group object,
3719             but that should not have any effect for grouped objects. */
3720         if( !bIsTopLevel )
3721             xDrawObj->PostProcessSdrObject( *this, *xSdrObj );
3722     }
3723 
3724     return xSdrObj;
3725 }
3726 
FinalizeObj(DffObjData & rDffObjData,SdrObject * pOldSdrObj)3727 SdrObject* XclImpDffConverter::FinalizeObj(DffObjData& rDffObjData, SdrObject* pOldSdrObj )
3728 {
3729     XclImpDffConvData& rConvData = GetConvData();
3730 
3731     /*  pOldSdrObj passes a generated SdrObject. This function owns this object
3732         and can modify it. The function has either to return it back to caller
3733         or to delete it by itself. */
3734     rtl::Reference<SdrObject> xSdrObj( pOldSdrObj );
3735 
3736     // find the OBJ record data related to the processed shape
3737     XclImpDrawObjRef xDrawObj = rConvData.mrDrawing.FindDrawObj( rDffObjData.rSpHd );
3738 
3739     if( xSdrObj && xDrawObj )
3740     {
3741         // cell anchoring
3742         if ( !rDffObjData.bPageAnchor )
3743             ScDrawLayer::SetCellAnchoredFromPosition( *xSdrObj,  GetDoc(), xDrawObj->GetTab(), false );
3744     }
3745 
3746     return xSdrObj.get();
3747 }
3748 
InsertControl(const Reference<XFormComponent> & rxFormComp,const css::awt::Size &,Reference<XShape> * pxShape,bool)3749 bool XclImpDffConverter::InsertControl( const Reference< XFormComponent >& rxFormComp,
3750         const css::awt::Size& /*rSize*/, Reference< XShape >* pxShape,
3751         bool /*bFloatingCtrl*/ )
3752 {
3753     if( GetDocShell() ) try
3754     {
3755         XclImpDffConvData& rConvData = GetConvData();
3756         Reference< XIndexContainer > xFormIC( rConvData.mxCtrlForm, UNO_QUERY_THROW );
3757         Reference< XControlModel > xCtrlModel( rxFormComp, UNO_QUERY_THROW );
3758 
3759         // create the control shape
3760         Reference< XShape > xShape( ScfApiHelper::CreateInstance( GetDocShell(), u"com.sun.star.drawing.ControlShape"_ustr ), UNO_QUERY_THROW );
3761         Reference< XControlShape > xCtrlShape( xShape, UNO_QUERY_THROW );
3762 
3763         // insert the new control into the form
3764         sal_Int32 nNewIndex = xFormIC->getCount();
3765         xFormIC->insertByIndex( nNewIndex, Any( rxFormComp ) );
3766         // on success: store new index of the control for later use (macro events)
3767         rConvData.mnLastCtrlIndex = nNewIndex;
3768 
3769         // set control model at control shape and pass back shape to caller
3770         xCtrlShape->setControl( xCtrlModel );
3771         if( pxShape ) *pxShape = std::move(xShape);
3772         return true;
3773     }
3774     catch( const Exception& )
3775     {
3776         OSL_FAIL( "XclImpDffConverter::InsertControl - cannot create form control" );
3777     }
3778 
3779     return false;
3780 }
3781 
3782 // private --------------------------------------------------------------------
3783 
GetConvData()3784 XclImpDffConverter::XclImpDffConvData& XclImpDffConverter::GetConvData()
3785 {
3786     OSL_ENSURE( !maDataStack.empty(), "XclImpDffConverter::GetConvData - no drawing manager on stack" );
3787     return *maDataStack.back();
3788 }
3789 
GetConvData() const3790 const XclImpDffConverter::XclImpDffConvData& XclImpDffConverter::GetConvData() const
3791 {
3792     OSL_ENSURE( !maDataStack.empty(), "XclImpDffConverter::GetConvData - no drawing manager on stack" );
3793     return *maDataStack.back();
3794 }
3795 
ReadHlinkProperty(SvStream & rDffStrm) const3796 OUString XclImpDffConverter::ReadHlinkProperty( SvStream& rDffStrm ) const
3797 {
3798     /*  Reads hyperlink data from a complex DFF property. Contents of this
3799         property are equal to the HLINK record, import of this record is
3800         implemented in class XclImpHyperlink. This function has to create an
3801         instance of the XclImpStream class to be able to reuse the
3802         functionality of XclImpHyperlink. */
3803     OUString aString;
3804     sal_uInt32 nBufferSize = GetPropertyValue( DFF_Prop_pihlShape, 0 );
3805     if( (0 < nBufferSize) && (nBufferSize <= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape, rDffStrm ) )
3806     {
3807         // create a faked BIFF record that can be read by XclImpStream class
3808         SvMemoryStream aMemStream;
3809         aMemStream.WriteUInt16( 0 ).WriteUInt16( nBufferSize );
3810 
3811         // copy from DFF stream to memory stream
3812         ::std::vector< sal_uInt8 > aBuffer( nBufferSize );
3813         sal_uInt8* pnData = aBuffer.data();
3814         if (rDffStrm.ReadBytes(pnData, nBufferSize) == nBufferSize)
3815         {
3816             aMemStream.WriteBytes(pnData, nBufferSize);
3817 
3818             // create BIFF import stream to be able to use XclImpHyperlink class
3819             XclImpStream aXclStrm( aMemStream, GetRoot() );
3820             if( aXclStrm.StartNextRecord() )
3821                 aString = XclImpHyperlink::ReadEmbeddedData( aXclStrm );
3822         }
3823     }
3824     return aString;
3825 }
3826 
ProcessDgContainer(SvStream & rDffStrm,const DffRecordHeader & rDgHeader)3827 bool XclImpDffConverter::ProcessDgContainer( SvStream& rDffStrm, const DffRecordHeader& rDgHeader )
3828 {
3829     std::size_t nEndPos = rDgHeader.GetRecEndFilePos();
3830     bool isBreak(false);
3831     while (!isBreak && rDffStrm.good() && rDffStrm.Tell() < nEndPos)
3832     {
3833         DffRecordHeader aHeader;
3834         ReadDffRecordHeader( rDffStrm, aHeader );
3835         switch( aHeader.nRecType )
3836         {
3837             case DFF_msofbtSolverContainer:
3838                 isBreak = !ProcessSolverContainer( rDffStrm, aHeader );
3839             break;
3840             case DFF_msofbtSpgrContainer:
3841                 isBreak = !ProcessShGrContainer( rDffStrm, aHeader );
3842             break;
3843             default:
3844                 isBreak = !aHeader.SeekToEndOfRecord( rDffStrm );
3845         }
3846     }
3847     // seek to end of drawing page container
3848     isBreak = !rDgHeader.SeekToEndOfRecord( rDffStrm );
3849 
3850     // #i12638# #i37900# connector rules
3851     XclImpSolverContainer& rSolverCont = GetConvData().maSolverCont;
3852     rSolverCont.UpdateConnectorRules();
3853     SolveSolver( rSolverCont );
3854     rSolverCont.RemoveConnectorRules();
3855     return !isBreak;
3856 }
3857 
ProcessShGrContainer(SvStream & rDffStrm,const DffRecordHeader & rShGrHeader)3858 bool XclImpDffConverter::ProcessShGrContainer( SvStream& rDffStrm, const DffRecordHeader& rShGrHeader )
3859 {
3860     std::size_t nEndPos = rShGrHeader.GetRecEndFilePos();
3861     bool isBreak(false);
3862     while (!isBreak && rDffStrm.good() && rDffStrm.Tell() < nEndPos)
3863     {
3864         DffRecordHeader aHeader;
3865         ReadDffRecordHeader( rDffStrm, aHeader );
3866         switch( aHeader.nRecType )
3867         {
3868             case DFF_msofbtSpgrContainer:
3869             case DFF_msofbtSpContainer:
3870                 isBreak = !ProcessShContainer( rDffStrm, aHeader );
3871             break;
3872             default:
3873                 isBreak = !aHeader.SeekToEndOfRecord( rDffStrm );
3874         }
3875     }
3876     // seek to end of shape group container
3877     return rShGrHeader.SeekToEndOfRecord( rDffStrm ) && !isBreak;
3878 }
3879 
ProcessSolverContainer(SvStream & rDffStrm,const DffRecordHeader & rSolverHeader)3880 bool XclImpDffConverter::ProcessSolverContainer( SvStream& rDffStrm, const DffRecordHeader& rSolverHeader )
3881 {
3882     // solver container wants to read the solver container header again
3883     rSolverHeader.SeekToBegOfRecord( rDffStrm );
3884     // read the entire solver container
3885     ReadSvxMSDffSolverContainer( rDffStrm, GetConvData().maSolverCont );
3886     // seek to end of solver container
3887     return rSolverHeader.SeekToEndOfRecord( rDffStrm );
3888 }
3889 
ProcessShContainer(SvStream & rDffStrm,const DffRecordHeader & rShHeader)3890 bool XclImpDffConverter::ProcessShContainer( SvStream& rDffStrm, const DffRecordHeader& rShHeader )
3891 {
3892     rShHeader.SeekToBegOfRecord( rDffStrm );
3893     tools::Rectangle aDummy;
3894     XclImpDrawObjClientData aDrawObjClientData;
3895     /*  The call to ImportObj() creates and returns a new SdrObject for the
3896         processed shape. We take ownership of the returned object here. If the
3897         shape is a group object, all embedded objects are created recursively,
3898         and the returned group object contains them all. ImportObj() calls the
3899         virtual functions ProcessClientAnchor2() and ProcessObj() and writes
3900         the pointer to the related draw object data (OBJ record) into aDrawObjClientData. */
3901     rtl::Reference<SdrObject> xSdrObj( ImportObj( rDffStrm, aDrawObjClientData, aDummy, aDummy, /*nCalledByGroup*/0, /*pShapeId*/nullptr ) );
3902     if (aDrawObjClientData.m_pTopLevelObj && xSdrObj )
3903         InsertSdrObject( GetConvData().mrSdrPage, *aDrawObjClientData.m_pTopLevelObj, xSdrObj.get() );
3904     return rShHeader.SeekToEndOfRecord( rDffStrm );
3905 }
3906 
InsertSdrObject(SdrObjList & rObjList,const XclImpDrawObjBase & rDrawObj,SdrObject * pSdrObj)3907 void XclImpDffConverter::InsertSdrObject( SdrObjList& rObjList, const XclImpDrawObjBase& rDrawObj, SdrObject* pSdrObj )
3908 {
3909     XclImpDffConvData& rConvData = GetConvData();
3910     /*  Take ownership of the passed object. If insertion fails (e.g. rDrawObj
3911         states to skip insertion), the object is automatically deleted. */
3912     rtl::Reference<SdrObject> xSdrObj( pSdrObj );
3913     if( xSdrObj && rDrawObj.IsInsertSdrObj() )
3914     {
3915         rObjList.NbcInsertObject( xSdrObj.get() );
3916         // callback to drawing manager for e.g. tracking of used sheet area
3917         rConvData.mrDrawing.OnObjectInserted( rDrawObj );
3918         // callback to drawing object for post processing (use pSdrObj, xSdrObj already released)
3919         rDrawObj.PostProcessSdrObject( *this, *pSdrObj );
3920     }
3921     /*  SdrObject still here? Insertion failed, remove data from shape ID map.
3922         The SdrObject will be destructed then. */
3923     if( xSdrObj )
3924         rConvData.maSolverCont.RemoveSdrObjectInfo( *xSdrObj );
3925 }
3926 
InitControlForm()3927 void XclImpDffConverter::InitControlForm()
3928 {
3929     XclImpDffConvData& rConvData = GetConvData();
3930     if( rConvData.mbHasCtrlForm )
3931         return;
3932 
3933     rConvData.mbHasCtrlForm = true;
3934     if( !SupportsOleObjects() )
3935         return;
3936 
3937     try
3938     {
3939         Reference< XFormsSupplier > xFormsSupplier( rConvData.mrSdrPage.getUnoPage(), UNO_QUERY_THROW );
3940         Reference< XNameContainer > xFormsNC( xFormsSupplier->getForms(), UNO_SET_THROW );
3941         // find or create the Standard form used to insert the imported controls
3942         if( xFormsNC->hasByName( gaStdFormName ) )
3943         {
3944             xFormsNC->getByName( gaStdFormName ) >>= rConvData.mxCtrlForm;
3945         }
3946         else if( SfxObjectShell* pDocShell = GetDocShell() )
3947         {
3948             rConvData.mxCtrlForm.set( ScfApiHelper::CreateInstance( pDocShell, u"com.sun.star.form.component.Form"_ustr ), UNO_QUERY_THROW );
3949             xFormsNC->insertByName( gaStdFormName, Any( rConvData.mxCtrlForm ) );
3950         }
3951     }
3952     catch( const Exception& )
3953     {
3954     }
3955 }
3956 
3957 // Drawing manager ============================================================
3958 
XclImpDrawing(const XclImpRoot & rRoot,bool bOleObjects)3959 XclImpDrawing::XclImpDrawing( const XclImpRoot& rRoot, bool bOleObjects ) :
3960     XclImpRoot( rRoot ),
3961     mbOleObjs( bOleObjects )
3962 {
3963 }
3964 
~XclImpDrawing()3965 XclImpDrawing::~XclImpDrawing()
3966 {
3967 }
3968 
ReadImgData(const XclImpRoot & rRoot,XclImpStream & rStrm)3969 Graphic XclImpDrawing::ReadImgData( const XclImpRoot& rRoot, XclImpStream& rStrm )
3970 {
3971     Graphic aGraphic;
3972     sal_uInt16 nFormat = rStrm.ReaduInt16();
3973     rStrm.Ignore( 2 );//nEnv
3974     sal_uInt32 nDataSize = rStrm.ReaduInt32();
3975     if( nDataSize <= rStrm.GetRecLeft() )
3976     {
3977         switch( nFormat )
3978         {
3979             case EXC_IMGDATA_WMF:   ReadWmf( aGraphic, rStrm );  break;
3980             case EXC_IMGDATA_BMP:   ReadBmp( aGraphic, rRoot, rStrm );  break;
3981             default:    OSL_FAIL( "XclImpDrawing::ReadImgData - unknown image format" );
3982         }
3983     }
3984     return aGraphic;
3985 }
3986 
ReadObj(XclImpStream & rStrm)3987 void XclImpDrawing::ReadObj( XclImpStream& rStrm )
3988 {
3989     XclImpDrawObjRef xDrawObj;
3990 
3991     /*  #i61786# In BIFF8 streams, OBJ records may occur without MSODRAWING
3992         records. In this case, the OBJ records are in BIFF5 format. Do a sanity
3993         check here that there is no DFF data loaded before. */
3994     OSL_ENSURE( maDffStrm.Tell() == 0, "XclImpDrawing::ReadObj - unexpected DFF stream data, OBJ will be ignored" );
3995     if( maDffStrm.Tell() == 0 ) switch( GetBiff() )
3996     {
3997         case EXC_BIFF3:
3998             xDrawObj = XclImpDrawObjBase::ReadObj3( GetRoot(), rStrm );
3999         break;
4000         case EXC_BIFF4:
4001             xDrawObj = XclImpDrawObjBase::ReadObj4( GetRoot(), rStrm );
4002         break;
4003         case EXC_BIFF5:
4004         case EXC_BIFF8:
4005             xDrawObj = XclImpDrawObjBase::ReadObj5( GetRoot(), rStrm );
4006         break;
4007         default:
4008             DBG_ERROR_BIFF();
4009     }
4010 
4011     if( xDrawObj )
4012     {
4013         // insert into maRawObjs or into the last open group object
4014         maRawObjs.InsertGrouped( xDrawObj );
4015         // to be able to find objects by ID
4016         maObjMapId[ xDrawObj->GetObjId() ] = xDrawObj;
4017     }
4018 }
4019 
ReadMsoDrawing(XclImpStream & rStrm)4020 void XclImpDrawing::ReadMsoDrawing( XclImpStream& rStrm )
4021 {
4022     OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
4023     // disable internal CONTINUE handling
4024     rStrm.ResetRecord( false );
4025     // read leading MSODRAWING record
4026     ReadDffRecord( rStrm );
4027 
4028     // read following drawing records, but do not start following unrelated record
4029     bool bLoop = true;
4030     while( bLoop ) switch( rStrm.GetNextRecId() )
4031     {
4032         case EXC_ID_MSODRAWING:
4033         case EXC_ID_MSODRAWINGSEL:
4034         case EXC_ID_CONT:
4035             rStrm.StartNextRecord();
4036             ReadDffRecord( rStrm );
4037         break;
4038         case EXC_ID_OBJ:
4039             rStrm.StartNextRecord();
4040             ReadObj8( rStrm );
4041         break;
4042         case EXC_ID_TXO:
4043             rStrm.StartNextRecord();
4044             ReadTxo( rStrm );
4045         break;
4046         default:
4047             bLoop = false;
4048     }
4049 
4050     // re-enable internal CONTINUE handling
4051     rStrm.ResetRecord( true );
4052 }
4053 
FindDrawObj(const DffRecordHeader & rHeader) const4054 XclImpDrawObjRef XclImpDrawing::FindDrawObj( const DffRecordHeader& rHeader ) const
4055 {
4056     /*  maObjMap stores objects by position of the client data (OBJ record) in
4057         the DFF stream, which is always behind shape start position of the
4058         passed header. The function upper_bound() finds the first element in
4059         the map whose key is greater than the start position of the header. Its
4060         end position is used to test whether the found object is really related
4061         to the shape. */
4062     XclImpDrawObjRef xDrawObj;
4063     XclImpObjMap::const_iterator aIt = maObjMap.upper_bound( rHeader.GetRecBegFilePos() );
4064     if( (aIt != maObjMap.end()) && (aIt->first <= rHeader.GetRecEndFilePos()) )
4065         xDrawObj = aIt->second;
4066     return xDrawObj;
4067 }
4068 
FindDrawObj(sal_uInt16 nObjId) const4069 XclImpDrawObjRef XclImpDrawing::FindDrawObj( sal_uInt16 nObjId ) const
4070 {
4071     XclImpDrawObjRef xDrawObj;
4072     XclImpObjMapById::const_iterator aIt = maObjMapId.find( nObjId );
4073     if( aIt != maObjMapId.end() )
4074         xDrawObj = aIt->second;
4075     return xDrawObj;
4076 }
4077 
FindTextData(const DffRecordHeader & rHeader) const4078 const XclImpObjTextData* XclImpDrawing::FindTextData( const DffRecordHeader& rHeader ) const
4079 {
4080     /*  maTextMap stores textbox data by position of the client data (TXO
4081         record) in the DFF stream, which is always behind shape start position
4082         of the passed header. The function upper_bound() finds the first
4083         element in the map whose key is greater than the start position of the
4084         header. Its end position is used to test whether the found object is
4085         really related to the shape. */
4086     XclImpObjTextMap::const_iterator aIt = maTextMap.upper_bound( rHeader.GetRecBegFilePos() );
4087     if( (aIt != maTextMap.end()) && (aIt->first <= rHeader.GetRecEndFilePos()) )
4088         return aIt->second.get();
4089     return nullptr;
4090 }
4091 
ApplyGroupBoxes()4092 void XclImpDrawing::ApplyGroupBoxes()
4093 {
4094     // sorted: smallest to largest - looking for smallest contained-in GroupBox
4095     // multimap: allows duplicate key values - may have identical areas.
4096     std::multimap<double, XclImpDrawObjRef> aGroupBoxAreaMap;
4097     for (auto& rGroupBox : maObjMapId)
4098     {
4099         if (rGroupBox.second->GetObjType() != EXC_OBJTYPE_GROUPBOX)
4100             continue;
4101         const tools::Rectangle& rRect = rGroupBox.second->GetDffRect();
4102         const double fArea = double(rRect.GetWidth()) * rRect.GetHeight();
4103         aGroupBoxAreaMap.insert(std::pair<double, XclImpDrawObjRef>(fArea, rGroupBox.second));
4104     }
4105 
4106     for (auto& rGroupedObj : maObjMapId)
4107     {
4108         auto pRadioButton = dynamic_cast<XclImpOptionButtonObj*>(rGroupedObj.second.get());
4109         if (!pRadioButton || pRadioButton->IsInGroup())
4110             continue;
4111 
4112         OUString sGroupName(u"autoGroup_"_ustr);
4113         for (auto& rGroupBox : aGroupBoxAreaMap)
4114         {
4115             assert(pRadioButton->GetTab() == rGroupBox.second->GetTab() && "impossible right?");
4116             if (!rGroupBox.second->GetDffRect().Contains(pRadioButton->GetDffRect()))
4117                 continue;
4118 
4119             sGroupName = rGroupBox.second->GetObjName();
4120             if (sGroupName.isEmpty())
4121                 sGroupName += "autoGroup_" + OUString::number(rGroupBox.second->GetObjId());
4122             // I ASSUME the smallest box wins in MS Word. (otherwise first? last?)
4123             break;
4124         }
4125         pRadioButton->SetStringProperty(u"GroupName"_ustr, sGroupName);
4126     }
4127 }
4128 
SetSkipObj(sal_uInt16 nObjId)4129 void XclImpDrawing::SetSkipObj( sal_uInt16 nObjId )
4130 {
4131     maSkipObjs.push_back( nObjId );
4132 }
4133 
GetProgressSize() const4134 std::size_t XclImpDrawing::GetProgressSize() const
4135 {
4136     return std::accumulate(maObjMap.begin(), maObjMap.end(), maRawObjs.GetProgressSize(),
4137         [](const std::size_t& rSum, const XclImpObjMap::value_type& rEntry) { return rSum + rEntry.second->GetProgressSize(); });
4138 }
4139 
ImplConvertObjects(XclImpDffConverter & rDffConv,SdrModel & rSdrModel,SdrPage & rSdrPage)4140 void XclImpDrawing::ImplConvertObjects( XclImpDffConverter& rDffConv, SdrModel& rSdrModel, SdrPage& rSdrPage )
4141 {
4142     //rhbz#636521, disable undo during conversion. faster, smaller and stops
4143     //temp objects being inserted into the undo list
4144     bool bOrigUndoStatus = rSdrModel.IsUndoEnabled();
4145     rSdrModel.EnableUndo(false);
4146     // register this drawing manager at the passed (global) DFF manager
4147     rDffConv.InitializeDrawing( *this, rSdrModel, rSdrPage );
4148     // process list of objects to be skipped
4149     for( const auto& rSkipObj : maSkipObjs )
4150         if( XclImpDrawObjBase* pDrawObj = FindDrawObj( rSkipObj ).get() )
4151             pDrawObj->SetProcessSdrObj( false );
4152     // process drawing objects without DFF data
4153     rDffConv.ProcessDrawing( maRawObjs );
4154     // process all objects in the DFF stream
4155     rDffConv.ProcessDrawing( maDffStrm );
4156     // assign groups based on being contained in the same GroupBox/sheet
4157     ApplyGroupBoxes();
4158     // unregister this drawing manager at the passed (global) DFF manager
4159     rDffConv.FinalizeDrawing();
4160     rSdrModel.EnableUndo(bOrigUndoStatus);
4161 }
4162 
4163 // protected ------------------------------------------------------------------
4164 
AppendRawObject(const XclImpDrawObjRef & rxDrawObj)4165 void XclImpDrawing::AppendRawObject( const XclImpDrawObjRef& rxDrawObj )
4166 {
4167     OSL_ENSURE( rxDrawObj, "XclImpDrawing::AppendRawObject - unexpected empty reference" );
4168     maRawObjs.push_back( rxDrawObj );
4169 }
4170 
4171 // private --------------------------------------------------------------------
4172 
ReadWmf(Graphic & rGraphic,XclImpStream & rStrm)4173 void XclImpDrawing::ReadWmf( Graphic& rGraphic, XclImpStream& rStrm ) // static helper
4174 {
4175     // extract graphic data from IMGDATA and following CONTINUE records
4176     rStrm.Ignore( 8 );
4177     SvMemoryStream aMemStrm;
4178     rStrm.CopyToStream( aMemStrm, rStrm.GetRecLeft() );
4179     aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
4180     // import the graphic from memory stream
4181     GDIMetaFile aGDIMetaFile;
4182     if( ::ReadWindowMetafile( aMemStrm, aGDIMetaFile ) )
4183         rGraphic = aGDIMetaFile;
4184 }
4185 
ReadBmp(Graphic & rGraphic,const XclImpRoot & rRoot,XclImpStream & rStrm)4186 void XclImpDrawing::ReadBmp( Graphic& rGraphic, const XclImpRoot& rRoot, XclImpStream& rStrm ) // static helper
4187 {
4188     // extract graphic data from IMGDATA and following CONTINUE records
4189     SvMemoryStream aMemStrm;
4190 
4191     /*  Excel 3 and 4 seem to write broken BMP data. Usually they write a
4192         DIBCOREHEADER (12 bytes) containing width, height, planes = 1, and
4193         pixel depth = 32 bit. After that, 3 unused bytes are added before the
4194         actual pixel data. This does even confuse Excel 5 and later, which
4195         cannot read the image data correctly. */
4196     if( rRoot.GetBiff() <= EXC_BIFF4 )
4197     {
4198         rStrm.PushPosition();
4199         sal_uInt32 nHdrSize;
4200         sal_uInt16 nWidth, nHeight, nPlanes, nDepth;
4201         nHdrSize = rStrm.ReaduInt32();
4202         nWidth = rStrm.ReaduInt16();
4203         nHeight = rStrm.ReaduInt16();
4204         nPlanes = rStrm.ReaduInt16();
4205         nDepth = rStrm.ReaduInt16();
4206         if( (nHdrSize == 12) && (nPlanes == 1) && (nDepth == 32) )
4207         {
4208             rStrm.Ignore( 3 );
4209             aMemStrm.SetEndian( SvStreamEndian::LITTLE );
4210             aMemStrm.WriteUInt32( nHdrSize ).WriteUInt16( nWidth ).WriteUInt16( nHeight ).WriteUInt16( nPlanes ).WriteUInt16( nDepth );
4211             rStrm.CopyToStream( aMemStrm, rStrm.GetRecLeft() );
4212         }
4213         rStrm.PopPosition();
4214     }
4215 
4216     // no special handling above -> just copy the remaining record data
4217     if( aMemStrm.Tell() == 0 )
4218         rStrm.CopyToStream( aMemStrm, rStrm.GetRecLeft() );
4219 
4220     // import the graphic from memory stream
4221     aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
4222     Bitmap aBitmap;
4223     if( ReadDIB(aBitmap, aMemStrm, false) )   // read DIB without file header
4224         rGraphic = BitmapEx(aBitmap);
4225 }
4226 
ReadDffRecord(XclImpStream & rStrm)4227 void XclImpDrawing::ReadDffRecord( XclImpStream& rStrm )
4228 {
4229     maDffStrm.Seek( STREAM_SEEK_TO_END );
4230     rStrm.CopyRecordToStream( maDffStrm );
4231 }
4232 
ReadObj8(XclImpStream & rStrm)4233 void XclImpDrawing::ReadObj8( XclImpStream& rStrm )
4234 {
4235     XclImpDrawObjRef xDrawObj = XclImpDrawObjBase::ReadObj8( GetRoot(), rStrm );
4236     // store the new object in the internal containers
4237     maObjMap[ maDffStrm.Tell() ] = xDrawObj;
4238     maObjMapId[ xDrawObj->GetObjId() ] = xDrawObj;
4239 }
4240 
ReadTxo(XclImpStream & rStrm)4241 void XclImpDrawing::ReadTxo( XclImpStream& rStrm )
4242 {
4243     XclImpObjTextRef xTextData = std::make_shared<XclImpObjTextData>();
4244     maTextMap[ maDffStrm.Tell() ] = xTextData;
4245 
4246     // 1) read the TXO record
4247     xTextData->maData.ReadTxo8( rStrm );
4248 
4249     // 2) first CONTINUE with string
4250     xTextData->mxString.reset();
4251     bool bValid = true;
4252     if( xTextData->maData.mnTextLen > 0 )
4253     {
4254         bValid = (rStrm.GetNextRecId() == EXC_ID_CONT) && rStrm.StartNextRecord();
4255         OSL_ENSURE( bValid, "XclImpDrawing::ReadTxo - missing CONTINUE record" );
4256         if( bValid )
4257             xTextData->mxString = std::make_shared<XclImpString>( rStrm.ReadUniString( xTextData->maData.mnTextLen ) );
4258     }
4259 
4260     // 3) second CONTINUE with formatting runs
4261     if( xTextData->maData.mnFormatSize > 0 )
4262     {
4263         bValid = (rStrm.GetNextRecId() == EXC_ID_CONT) && rStrm.StartNextRecord();
4264         OSL_ENSURE( bValid, "XclImpDrawing::ReadTxo - missing CONTINUE record" );
4265         if( bValid )
4266             xTextData->ReadFormats( rStrm );
4267     }
4268 }
4269 
XclImpSheetDrawing(const XclImpRoot & rRoot,SCTAB nScTab)4270 XclImpSheetDrawing::XclImpSheetDrawing( const XclImpRoot& rRoot, SCTAB nScTab ) :
4271     XclImpDrawing( rRoot, true ),
4272     maScUsedArea( ScAddress::INITIALIZE_INVALID )
4273 {
4274     maScUsedArea.aStart.SetTab( nScTab );
4275     maScUsedArea.aEnd.SetTab( nScTab );
4276 }
4277 
ReadNote(XclImpStream & rStrm)4278 void XclImpSheetDrawing::ReadNote( XclImpStream& rStrm )
4279 {
4280     switch( GetBiff() )
4281     {
4282         case EXC_BIFF2:
4283         case EXC_BIFF3:
4284         case EXC_BIFF4:
4285         case EXC_BIFF5:
4286             ReadNote3( rStrm );
4287         break;
4288         case EXC_BIFF8:
4289             ReadNote8( rStrm );
4290         break;
4291         default:
4292             DBG_ERROR_BIFF();
4293     }
4294 }
4295 
ReadTabChart(XclImpStream & rStrm)4296 void XclImpSheetDrawing::ReadTabChart( XclImpStream& rStrm )
4297 {
4298     OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF5 );
4299     auto xChartObj = std::make_shared<XclImpChartObj>( GetRoot(), true );
4300     xChartObj->ReadChartSubStream( rStrm );
4301     // insert the chart as raw object without connected DFF data
4302     AppendRawObject( xChartObj );
4303 }
4304 
ConvertObjects(XclImpDffConverter & rDffConv)4305 void XclImpSheetDrawing::ConvertObjects( XclImpDffConverter& rDffConv )
4306 {
4307     if( SdrModel* pSdrModel = GetDoc().GetDrawLayer() )
4308         if( SdrPage* pSdrPage = GetSdrPage( maScUsedArea.aStart.Tab() ) )
4309             ImplConvertObjects( rDffConv, *pSdrModel, *pSdrPage );
4310 }
4311 
CalcAnchorRect(const XclObjAnchor & rAnchor,bool) const4312 tools::Rectangle XclImpSheetDrawing::CalcAnchorRect( const XclObjAnchor& rAnchor, bool /*bDffAnchor*/ ) const
4313 {
4314     return rAnchor.GetRect( GetRoot(), maScUsedArea.aStart.Tab(), MapUnit::Map100thMM );
4315 }
4316 
OnObjectInserted(const XclImpDrawObjBase & rDrawObj)4317 void XclImpSheetDrawing::OnObjectInserted( const XclImpDrawObjBase& rDrawObj )
4318 {
4319     ScRange aScObjArea = rDrawObj.GetUsedArea( maScUsedArea.aStart.Tab() );
4320     if( aScObjArea.IsValid() )
4321         maScUsedArea.ExtendTo( aScObjArea );
4322 }
4323 
4324 // private --------------------------------------------------------------------
4325 
ReadNote3(XclImpStream & rStrm)4326 void XclImpSheetDrawing::ReadNote3( XclImpStream& rStrm )
4327 {
4328     XclAddress aXclPos;
4329     rStrm >> aXclPos;
4330     sal_uInt16 nTotalLen = rStrm.ReaduInt16();
4331 
4332     ScAddress aScNotePos( ScAddress::UNINITIALIZED );
4333     if( !GetAddressConverter().ConvertAddress( aScNotePos, aXclPos, maScUsedArea.aStart.Tab(), true ) )
4334         return;
4335 
4336     sal_uInt16 nPartLen = ::std::min( nTotalLen, static_cast< sal_uInt16 >( rStrm.GetRecLeft() ) );
4337     OUStringBuffer aNoteText(rStrm.ReadRawByteString( nPartLen ));
4338     nTotalLen = nTotalLen - nPartLen;
4339     while (true)
4340     {
4341         if (!nTotalLen)
4342             break;
4343         if (rStrm.GetNextRecId() != EXC_ID_NOTE)
4344             break;
4345         if (!rStrm.StartNextRecord())
4346             break;
4347         rStrm >> aXclPos;
4348         nPartLen = rStrm.ReaduInt16();
4349         OSL_ENSURE( aXclPos.mnRow == 0xFFFF, "XclImpObjectManager::ReadNote3 - missing continuation NOTE record" );
4350         if( aXclPos.mnRow == 0xFFFF )
4351         {
4352             OSL_ENSURE( nPartLen <= nTotalLen, "XclImpObjectManager::ReadNote3 - string too long" );
4353             aNoteText.append(rStrm.ReadRawByteString( nPartLen ));
4354             nTotalLen = nTotalLen - ::std::min( nTotalLen, nPartLen );
4355         }
4356         else
4357         {
4358             // seems to be a new note, record already started -> load the note
4359             rStrm.Seek( EXC_REC_SEEK_TO_BEGIN );
4360             ReadNote( rStrm );
4361             nTotalLen = 0;
4362         }
4363     }
4364     ScNoteUtil::CreateNoteFromString( GetDoc(), aScNotePos, aNoteText.makeStringAndClear(), false, false );
4365 }
4366 
ReadNote8(XclImpStream & rStrm)4367 void XclImpSheetDrawing::ReadNote8( XclImpStream& rStrm )
4368 {
4369     XclAddress aXclPos;
4370     sal_uInt16 nFlags, nObjId;
4371     rStrm >> aXclPos;
4372     nFlags = rStrm.ReaduInt16();
4373     nObjId = rStrm.ReaduInt16();
4374 
4375     ScAddress aScNotePos( ScAddress::UNINITIALIZED );
4376     if( GetAddressConverter().ConvertAddress( aScNotePos, aXclPos, maScUsedArea.aStart.Tab(), true ) )
4377         if( nObjId != EXC_OBJ_INVALID_ID )
4378             if( XclImpNoteObj* pNoteObj = dynamic_cast< XclImpNoteObj* >( FindDrawObj( nObjId ).get() ) )
4379                 pNoteObj->SetNoteData( aScNotePos, nFlags );
4380 }
4381 
4382 // The object manager =========================================================
4383 
XclImpObjectManager(const XclImpRoot & rRoot)4384 XclImpObjectManager::XclImpObjectManager( const XclImpRoot& rRoot ) :
4385     XclImpRoot( rRoot )
4386 {
4387     maDefObjNames[ EXC_OBJTYPE_GROUP ]          = "Group";
4388     maDefObjNames[ EXC_OBJTYPE_LINE ]           = ScResId( STR_SHAPE_LINE );
4389     maDefObjNames[ EXC_OBJTYPE_RECTANGLE ]      = ScResId( STR_SHAPE_RECTANGLE );
4390     maDefObjNames[ EXC_OBJTYPE_OVAL ]           = ScResId( STR_SHAPE_OVAL );
4391     maDefObjNames[ EXC_OBJTYPE_ARC ]            = "Arc";
4392     maDefObjNames[ EXC_OBJTYPE_CHART ]          = "Chart";
4393     maDefObjNames[ EXC_OBJTYPE_TEXT ]           = "Text";
4394     maDefObjNames[ EXC_OBJTYPE_BUTTON ]         =  ScResId( STR_FORM_BUTTON );
4395     maDefObjNames[ EXC_OBJTYPE_PICTURE ]        = "Picture";
4396     maDefObjNames[ EXC_OBJTYPE_POLYGON ]        = "Freeform";
4397     maDefObjNames[ EXC_OBJTYPE_CHECKBOX ]       = ScResId( STR_FORM_CHECKBOX );
4398     maDefObjNames[ EXC_OBJTYPE_OPTIONBUTTON ]   = ScResId( STR_FORM_OPTIONBUTTON );
4399     maDefObjNames[ EXC_OBJTYPE_EDIT ]           = "Edit Box";
4400     maDefObjNames[ EXC_OBJTYPE_LABEL ]          = ScResId( STR_FORM_LABEL );
4401     maDefObjNames[ EXC_OBJTYPE_DIALOG ]         = "Dialog Frame";
4402     maDefObjNames[ EXC_OBJTYPE_SPIN ]           = ScResId( STR_FORM_SPINNER );
4403     maDefObjNames[ EXC_OBJTYPE_SCROLLBAR ]      = ScResId( STR_FORM_SCROLLBAR );
4404     maDefObjNames[ EXC_OBJTYPE_LISTBOX ]        = ScResId( STR_FORM_LISTBOX );
4405     maDefObjNames[ EXC_OBJTYPE_GROUPBOX ]       = ScResId( STR_FORM_GROUPBOX );
4406     maDefObjNames[ EXC_OBJTYPE_DROPDOWN ]       = ScResId( STR_FORM_DROPDOWN );
4407     maDefObjNames[ EXC_OBJTYPE_NOTE ]           = "Comment";
4408     maDefObjNames[ EXC_OBJTYPE_DRAWING ]        = ScResId( STR_SHAPE_AUTOSHAPE );
4409 }
4410 
~XclImpObjectManager()4411 XclImpObjectManager::~XclImpObjectManager()
4412 {
4413 }
4414 
ReadMsoDrawingGroup(XclImpStream & rStrm)4415 void XclImpObjectManager::ReadMsoDrawingGroup( XclImpStream& rStrm )
4416 {
4417     OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
4418     // Excel continues this record with MSODRAWINGGROUP and CONTINUE records, hmm.
4419     rStrm.ResetRecord( true, EXC_ID_MSODRAWINGGROUP );
4420     maDggStrm.Seek( STREAM_SEEK_TO_END );
4421     rStrm.CopyRecordToStream( maDggStrm );
4422 }
4423 
GetSheetDrawing(SCTAB nScTab)4424 XclImpSheetDrawing& XclImpObjectManager::GetSheetDrawing( SCTAB nScTab )
4425 {
4426     XclImpSheetDrawingRef& rxDrawing = maSheetDrawings[ nScTab ];
4427     if( !rxDrawing )
4428         rxDrawing = std::make_shared<XclImpSheetDrawing>( GetRoot(), nScTab );
4429     return *rxDrawing;
4430 }
4431 
ConvertObjects()4432 void XclImpObjectManager::ConvertObjects()
4433 {
4434     // do nothing if the document does not contain a drawing layer
4435     if( !GetDoc().GetDrawLayer() )
4436         return;
4437 
4438     // get total progress bar size for all sheet drawing managers
4439     std::size_t nProgressSize = std::accumulate(maSheetDrawings.begin(), maSheetDrawings.end(), std::size_t(0),
4440         [](const std::size_t& rSum, const XclImpSheetDrawingMap::value_type& rEntry) { return rSum + rEntry.second->GetProgressSize(); });
4441     // nothing to do if progress bar is zero (no objects present)
4442     if( nProgressSize == 0 )
4443         return;
4444 
4445     XclImpDffConverter aDffConv( GetRoot(), maDggStrm );
4446     aDffConv.StartProgressBar( nProgressSize );
4447     for( auto& rEntry : maSheetDrawings )
4448         rEntry.second->ConvertObjects( aDffConv );
4449 
4450     // #i112436# don't call ScChartListenerCollection::SetDirty here,
4451     // instead use InterpretDirtyCells in ScDocument::CalcAfterLoad.
4452 }
4453 
GetDefaultObjName(const XclImpDrawObjBase & rDrawObj) const4454 OUString XclImpObjectManager::GetDefaultObjName( const XclImpDrawObjBase& rDrawObj ) const
4455 {
4456     OUString aDefName;
4457     DefObjNameMap::const_iterator aIt = maDefObjNames.find( rDrawObj.GetObjType() );
4458     if( aIt != maDefObjNames.end() )
4459         aDefName = aIt->second;
4460     return aDefName + " " + OUString::number(static_cast<sal_Int32>(rDrawObj.GetObjId()));
4461 }
4462 
GetUsedArea(SCTAB nScTab) const4463 ScRange XclImpObjectManager::GetUsedArea( SCTAB nScTab ) const
4464 {
4465     XclImpSheetDrawingMap::const_iterator aIt = maSheetDrawings.find( nScTab );
4466     if( aIt != maSheetDrawings.end() )
4467         return aIt->second->GetUsedArea();
4468     return ScRange( ScAddress::INITIALIZE_INVALID );
4469 }
4470 
4471 // DFF property set helper ====================================================
4472 
XclImpDffPropSet(const XclImpRoot & rRoot)4473 XclImpDffPropSet::XclImpDffPropSet( const XclImpRoot& rRoot ) :
4474     XclImpRoot( rRoot ),
4475     maDffConv( rRoot, maDummyStrm )
4476 {
4477 }
4478 
Read(XclImpStream & rStrm)4479 void XclImpDffPropSet::Read( XclImpStream& rStrm )
4480 {
4481     sal_uInt32 nPropSetSize;
4482 
4483     rStrm.PushPosition();
4484     rStrm.Ignore( 4 );
4485     nPropSetSize = rStrm.ReaduInt32();
4486     rStrm.PopPosition();
4487 
4488     mxMemStrm.reset( new SvMemoryStream );
4489     rStrm.CopyToStream( *mxMemStrm, 8 + nPropSetSize );
4490     mxMemStrm->Seek( STREAM_SEEK_TO_BEGIN );
4491     maDffConv.ReadPropSet( *mxMemStrm, nullptr );
4492 }
4493 
GetPropertyValue(sal_uInt16 nPropId) const4494 sal_uInt32 XclImpDffPropSet::GetPropertyValue( sal_uInt16 nPropId ) const
4495 {
4496     return maDffConv.GetPropertyValue( nPropId, 0 );
4497 }
4498 
FillToItemSet(SfxItemSet & rItemSet) const4499 void XclImpDffPropSet::FillToItemSet( SfxItemSet& rItemSet ) const
4500 {
4501     if( mxMemStrm )
4502         maDffConv.ApplyAttributes( *mxMemStrm, rItemSet );
4503 }
4504 
operator >>(XclImpStream & rStrm,XclImpDffPropSet & rPropSet)4505 XclImpStream& operator>>( XclImpStream& rStrm, XclImpDffPropSet& rPropSet )
4506 {
4507     rPropSet.Read( rStrm );
4508     return rStrm;
4509 }
4510 
4511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4512